A web server for monitoring and controlling a MakerBot Replicator over the USB host and ethernet.

Dependencies:   IAP NTPClient RTC mbed-rtos mbed Socket lwip-sys lwip BurstSPI

Fork of LPC1768_Mini-DK by Frank Vannieuwkerke

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers telnetd.cpp Source File

telnetd.cpp

00001 // Copyright (c) 2013, jake (at) allaboutjake (dot) com
00002 // All rights reserved.
00003 // 
00004 // Redistribution and use in source and binary forms, with or without
00005 // modification, are permitted provided that the following conditions are met:
00006 //     * Redistributions of source code must retain the above copyright
00007 //       notice, this list of conditions and the following disclaimer.
00008 //     * Redistributions in binary form must reproduce the above copyright
00009 //       notice, this list of conditions and the following disclaimer in the
00010 //       documentation and/or other materials provided with the distribution.
00011 //     * The name of the author and/or copyright holder nor the
00012 //       names of its contributors may be used to endorse or promote products
00013 //       derived from this software without specific prior written permission.
00014 // 
00015 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00016 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00017 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00018 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, AUTHOR, OR ANY CONTRIBUTORS
00019 // BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
00020 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
00021 // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
00022 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00023 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
00024 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00025 
00026 // DESCRIPTION OF FILE:
00027 //
00028 // This file contains a simple telnet server on port 7654.   The main function is
00029 // "telnet_server_task" which is intended to be run in a thread after the 
00030 // network (EthernetInterface) bas been configured.
00031 #include "mbed.h"
00032 #include "main.h"
00033 #include "telnetd.h"
00034 #include "EthernetInterface.h"
00035 #include "SimpleSocket.h"
00036 #include "readline.h"
00037 #include "settings.h"
00038 
00039 int readline_password(ClientSocket* socket, char* buffer, int max_length);
00040 
00041 // Network server task: setup and listen for network connections
00042 void telnet_server_task(void const*) {
00043     // This thread assumes that the EthernetInterface is connected with an IP address.
00044     static int TELNET_PORT = 7654;
00045 
00046     //Use SimpleSocket library to setup a server socket
00047     ServerSocket serverSocket(TELNET_PORT);
00048     
00049     while (1) {
00050         ClientSocket socket = serverSocket.accept();    
00051     
00052         //Create buffer to hold the command prompt input and filename
00053         char promptBuffer[MAX_PROMPT_BUFFER_SIZE];
00054         
00055         char* token = getAuthenticationToken();
00056         if (token != NULL) { 
00057             int authLen = readline_password(&socket, promptBuffer, MAX_PROMPT_BUFFER_SIZE);            
00058             if (memcmp(promptBuffer, token, authLen) != 0) {
00059                 socket.printf("Authentication failed\r\n");
00060                 socket.close();
00061                 continue;
00062             }
00063         }
00064         
00065         //Main loop
00066         while (1) {
00067             // Print the prompt        
00068             socket.printf("> ");
00069         
00070             // Get the command
00071             int cmdLength = readline(&socket, promptBuffer, MAX_PROMPT_BUFFER_SIZE);
00072                 
00073             if (cmdLength > 0) {
00074                 switch(promptBuffer[0]) {
00075                     case 'A':
00076                     case 'a': 
00077                     {
00078                         int tokenLength = cmdLength - 2;
00079                         if (tokenLength > 1) {
00080                             setAuthenticationToken(promptBuffer+2, tokenLength);
00081                             char* token = getAuthenticationToken();
00082                             socket.printf("Authentication set to: %s\r\n", token);                            
00083                         } else {
00084                             socket.printf("Command usage: A <username>:<password> - set authentication username/password\r\n");
00085                         }
00086                         break;
00087                     }
00088                         
00089                     case 'B':
00090                     case 'b':
00091                         //BUILD command - make sure there's a space between cmd and filename
00092                         if (cmdLength > 1 && promptBuffer[1]==' ') {
00093                             int fileNameLength = cmdLength - 2;
00094                             //make sure the filename is at least 5 characters (minimally "?.X3G")
00095                             if (fileNameLength >= 5) {
00096                                 // Check for X3G extension.
00097                                 if (memcmp(promptBuffer+cmdLength-4, ".X3G", 4)==0 ||
00098                                     memcmp(promptBuffer+cmdLength-4, ".x3g", 4)==0) {
00099                                     // Copy filename into filename buffer
00100                                     char filename[13];
00101                                     strncpy(filename, promptBuffer+2, cmdLength-2);
00102                                     filename[cmdLength-2]='\0';//terminate
00103                                 
00104                                     //Print the message to the display and the serial console
00105                                     DISPLAY("Printing filename: '%s'\r\n", filename);
00106                                     socket.printf("Printing filename: '%s'\r\n", filename);
00107                                 
00108                                     //Send command to bot to print
00109                                     if (bot) {
00110                                         bot->playbackCapture(filename);
00111                                     } else {                                   
00112                                         socket.printf("Error: connection to Makerbot not established.\r\n");                                    
00113                                     }
00114                                 } else {
00115                                     socket.printf("Error: filename doesn't end with X3G\r\n");
00116                                 }
00117                             } else {
00118                                 socket.printf("Error: filename must be 5-12 characters long\r\n");
00119                             }
00120                         } else {
00121                             socket.printf("Command usage: B <filename.X3G> - begin build (8.3 filename)\r\n");
00122                             
00123                         }
00124                         break;
00125                     case 'C':
00126                     case 'c':
00127                         if (bot) {
00128                             bot->abortImmediately();
00129                             socket.printf("Cancelling build.\r\n");
00130                         } else {
00131                             socket.printf("Error: connection to Makerbot not established.\r\n");                                    
00132                         }
00133                         break;
00134                     
00135                     case 'P':
00136                     case 'p':
00137                         if (bot) {
00138                             Makerbot::MakerbotBuildState state = bot->getBuildState();
00139                             if (state.build_state == Makerbot::BUILD_STATE_ERROR) {
00140                                 socket.printf("Error: unable to determine build state.  Sending pause/resume command in the blind.\r\n");
00141                                 bot->pauseResume();
00142                             } else if (state.build_state == Makerbot::BUILD_RUNNING) {
00143                                 bot->pauseResume();
00144                                 socket.printf("Pausing build.\r\n");
00145                             } else {
00146                                 socket.printf("Error: Not currently building, cannot pause\r\n");
00147                             }
00148                         } else {
00149                             socket.printf("Error: connection to Makerbot not established.\r\n");                                    
00150                         }
00151                         break;
00152 
00153                     case 'R':
00154                     case 'r':
00155                         if (bot) {
00156                             Makerbot::MakerbotBuildState state = bot->getBuildState();
00157                             if (state.build_state == Makerbot::BUILD_STATE_ERROR) {
00158                                 socket.printf("Error: unable to determine build state.  Sending pause/resume command in the blind.\r\n");
00159                                 bot->pauseResume();
00160                             } else if (state.build_state == Makerbot::BUILD_PAUSED) {
00161                                 bot->pauseResume();
00162                                 socket.printf("Pausing build.\r\n");
00163                             } else {
00164                                 socket.printf("Error: Not currently paused.  Cannot resume.\r\n");
00165                             }
00166                         } else {
00167                             socket.printf("Error: connection to Makerbot not established.\r\n");                                    
00168                         }
00169                         break;
00170 
00171                     case 'S':
00172                     case 's':
00173                         if (bot) {
00174                             Makerbot::MakerbotBuildState state = bot->getBuildState();
00175                             socket.printf("Build State: %s\r\n", Makerbot::humanReadableBuildState(state));
00176                             socket.printf("\tElapsed build time: %d:%02d\r\n", state.hours, state.minutes);
00177                             socket.printf("\tLine #: %ld\r\n", state.line);
00178                             
00179                             for (int x=0; x<bot->getToolCount(); x++) {                            
00180                                 socket.printf("\tTool %d: %dºc/%dºc\r\n", x, bot->getToolTemperature(x), bot->getToolSetPoint(x));
00181                             }
00182                             socket.printf("\tPlatform %dºc/%dºc\r\n", bot->getPlatformTemperature(0), bot->getPlatformSetPoint(0));
00183 
00184                         }
00185                         break;
00186                     
00187                     case 'Q':
00188                     case 'q':
00189                         socket.printf("Logging out\r\n");
00190                         socket.close();                        
00191                         break;
00192                         
00193                     case 'v':
00194                     case 'V': 
00195                         if (bot) {
00196                             char* bot_name = bot->getMachineName();   
00197                             socket.printf("Machine name: %s\r\n", bot_name);
00198     
00199                             float version = bot->getMakerbotVersion();
00200                             socket.printf("Makerbot version: %0.1f\r\n", version);
00201                             socket.printf("Local firmware version: %s\r\n", FIRMWARE_VERSION);                            
00202                         } else {
00203                             socket.printf("Error: connection to Makerbot not established.\r\n");
00204                         }
00205                         break;
00206                     default:      
00207                         socket.printf("unknown command\r\n");                          
00208                 }
00209             }                          
00210             Thread::wait(100);        
00211 
00212             // Go back around and wait for a new connection if we've disconnected
00213             if (!socket.connected())
00214                 break;
00215         }
00216     }
00217     // never gets here
00218     //EthernetInterface::disconnect();  
00219 }
00220 
00221 //Readline routine customized to return a "username:password" style string
00222 int readline_password(ClientSocket* socket, char* buffer, int max_length) {
00223    int curPos = 0;
00224    int usernamePasswordStep = 0;
00225    socket->printf("user: ");
00226    
00227    while (1) {
00228         int c;
00229         
00230         //Wait for a character
00231         while ((c=socket->read()) < 0) {
00232             if (!socket->connected()) return -1;
00233             Thread::yield();
00234         }
00235             
00236         switch (c) {
00237             case '\r':
00238                 continue;
00239                                     
00240             case '\b':
00241                 if (curPos > 0) curPos--;
00242                 break; 
00243                 
00244             default:
00245                 buffer[curPos]= (char)(c & 0xFF);
00246                 curPos++;
00247                 if (curPos < max_length)
00248                     break;
00249                     
00250                 //FALLTHROUGH
00251             case '\n':
00252                 if (usernamePasswordStep==0) {
00253                     socket->printf("password: ");
00254                     buffer[curPos] = ':';
00255                     curPos++;
00256                     usernamePasswordStep++;
00257                     break;
00258                 } else {
00259                     socket->printf("\r\n");
00260                     buffer[curPos]=0x00;  //string terminator
00261                     return curPos;
00262                 }
00263         }
00264     } 
00265     
00266 }