DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
src/hardware/serialport/softmodem.cpp
00001 /*
00002  *  Copyright (C) 2002-2013  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 
00020 #include "dosbox.h"
00021 
00022 #if C_MODEM
00023 
00024 #include <string.h>
00025 #include <stdlib.h>
00026 #include <ctype.h>
00027 
00028 #include "support.h"
00029 #include "serialport.h"
00030 #include "softmodem.h"
00031 #include "misc_util.h"
00032 
00033 //#include "mixer.h"
00034 
00035 
00036 CSerialModem::CSerialModem(Bitu id, CommandLine* cmd):CSerial(id, cmd) {
00037         InstallationSuccessful=false;
00038         connected=false;
00039 
00040         rqueue=new CFifo(MODEM_BUFFER_QUEUE_SIZE);
00041         tqueue=new CFifo(MODEM_BUFFER_QUEUE_SIZE);
00042         
00043         // Default to direct null modem connection.  Telnet mode interprets IAC codes
00044         telnetmode = false;
00045 
00046         // Initialize the sockets and setup the listening port
00047         listenport = 23;
00048         waitingclientsocket=0;
00049         clientsocket = 0;
00050         serversocket = 0;
00051         getBituSubstring("listenport:", &listenport, cmd);
00052         
00053         // TODO: Fix dialtones if requested
00054         //mhd.chan=MIXER_AddChannel((MIXER_MixHandler)this->MODEM_CallBack,8000,"MODEM");
00055         //MIXER_Enable(mhd.chan,false);
00056         //MIXER_SetMode(mhd.chan,MIXER_16MONO);
00057                 
00058         CSerial::Init_Registers();
00059         Reset(); // reset calls EnterIdleState
00060                 
00061         setEvent(SERIAL_POLLING_EVENT,1);
00062         InstallationSuccessful=true;
00063 }
00064 
00065 CSerialModem::~CSerialModem() {
00066         if(serversocket) delete serversocket;
00067         if(clientsocket) delete clientsocket;
00068         if(waitingclientsocket) delete waitingclientsocket;
00069 
00070         delete rqueue;
00071         delete tqueue;
00072 
00073         // remove events
00074         for(Bitu i = SERIAL_BASE_EVENT_COUNT+1; i <= SERIAL_MODEM_EVENT_COUNT; i++)
00075                 removeEvent(i);
00076 }
00077 
00078 void CSerialModem::handleUpperEvent(Bit16u type) {
00079         switch (type) {
00080         case SERIAL_RX_EVENT: {
00081                 // check for bytes to be sent to port
00082                 if(CSerial::CanReceiveByte())
00083                         if(rqueue->inuse() && (CSerial::getRTS()||(flowcontrol!=3))) {
00084                                 Bit8u rbyte = rqueue->getb();
00085                                 //LOG_MSG("Modem: sending byte %2x back to UART3",rbyte);
00086                                 CSerial::receiveByte(rbyte);
00087                         }
00088                 if(CSerial::CanReceiveByte()) setEvent(SERIAL_RX_EVENT, bytetime*0.98f);
00089                 break;
00090         }
00091         case MODEM_TX_EVENT: {
00092                 if (tqueue->left()) {
00093                         tqueue->addb(waiting_tx_character);
00094                         if (tqueue->left() < 2) {
00095                                 CSerial::setCTS(false);
00096                         }
00097                 } else {
00098                         static Bits lcount=0;
00099                         if (lcount<1000) {
00100                                 lcount++;
00101                                 LOG_MSG("MODEM: TX Buffer overflow!");
00102                         }
00103                 }
00104                 ByteTransmitted();
00105                 break;
00106         }
00107         case SERIAL_POLLING_EVENT: {
00108                 if (rqueue->inuse()) {
00109                         removeEvent(SERIAL_RX_EVENT);
00110                         setEvent(SERIAL_RX_EVENT, (float)0.01);
00111                 }
00112                 Timer2();
00113                 setEvent(SERIAL_POLLING_EVENT,1);
00114                 break;
00115         }
00116 
00117         case MODEM_RING_EVENT: {
00118                 break;
00119         }
00120         }
00121 }
00122 
00123 void CSerialModem::SendLine(const char *line) {
00124         rqueue->addb(0xd);
00125         rqueue->addb(0xa);
00126         rqueue->adds((Bit8u *)line,(Bitu)strlen(line));
00127         rqueue->addb(0xd);
00128         rqueue->addb(0xa);
00129 }
00130 
00131 // only for numbers < 1000...
00132 void CSerialModem::SendNumber(Bitu val) {
00133         rqueue->addb(0xd);
00134         rqueue->addb(0xa);
00135         
00136         rqueue->addb(val/100+'0');
00137         val = val%100;
00138         rqueue->addb(val/10+'0');
00139         val = val%10;
00140         rqueue->addb(val+'0');
00141 
00142         rqueue->addb(0xd);
00143         rqueue->addb(0xa);
00144 }
00145 
00146 void CSerialModem::SendRes(ResTypes response) {
00147         char const * string;Bitu code;
00148         switch (response)
00149         {
00150                 case ResNONE:           return;
00151                 case ResOK:                     string="OK"; code=0; break;
00152                 case ResERROR:          string="ERROR"; code=4; break;
00153                 case ResRING:           string="RING"; code=2; break;
00154                 case ResNODIALTONE: string="NO DIALTONE"; code=6; break;
00155                 case ResNOCARRIER:      string="NO CARRIER" ;code=3; break;
00156                 case ResCONNECT:        string="CONNECT 57600"; code=1; break;
00157                 default:                return;
00158         }
00159         
00160         if(doresponse!=1) {
00161                 if(doresponse==2 && (response==ResRING || 
00162                         response == ResCONNECT || response==ResNOCARRIER)) return;
00163                 if(numericresponse) SendNumber(code);
00164                 else SendLine(string);
00165 
00166                 //if(CSerial::CanReceiveByte()) // very fast response
00167                 //      if(rqueue->inuse() && CSerial::getRTS())
00168                 //      { Bit8u rbyte =rqueue->getb();
00169                 //              CSerial::receiveByte(rbyte);
00170                 //      LOG_MSG("Modem: sending byte %2x back to UART2",rbyte);
00171                 //      }
00172 
00173                 LOG_MSG("Modem response: %s", string);
00174         }
00175 }
00176 
00177 bool CSerialModem::Dial(char * host) {
00178 
00179         // Scan host for port
00180         Bit16u port;
00181         char * hasport=strrchr(host,':');
00182         if (hasport) {
00183                 *hasport++=0;
00184                 port=(Bit16u)atoi(hasport);
00185         }
00186         else port=MODEM_DEFAULT_PORT;
00187         // Resolve host we're gonna dial
00188         LOG_MSG("Connecting to host %s port %d",host,port);
00189         clientsocket = new TCPClientSocket(host, port);
00190         if(!clientsocket->isopen) {
00191                 delete clientsocket;
00192                 clientsocket=0;
00193                 LOG_MSG("Failed to connect.");
00194                 SendRes(ResNOCARRIER);
00195                 EnterIdleState();
00196                 return false;
00197         } else {
00198                 EnterConnectedState();
00199                 return true;
00200         }
00201 }
00202 
00203 void CSerialModem::AcceptIncomingCall(void) {
00204         if(waitingclientsocket) {
00205                 clientsocket=waitingclientsocket;
00206                 waitingclientsocket=0;
00207                 EnterConnectedState();
00208         } else {
00209                 EnterIdleState();
00210         }
00211 }
00212 
00213 Bitu CSerialModem::ScanNumber(char * & scan) {
00214         Bitu ret=0;
00215         while (char c=*scan) {
00216                 if (c>='0' && c<='9') {
00217                         ret*=10;
00218                         ret+=c-'0';
00219                         scan++;
00220                 } else break;
00221         }
00222         return ret;
00223 }
00224 
00225 char CSerialModem::GetChar(char * & scan) {
00226         char ch = *scan;
00227         scan++;
00228         return ch;
00229 }
00230 
00231 void CSerialModem::Reset(){
00232         EnterIdleState();
00233         cmdpos = 0;
00234         cmdbuf[0]=0;
00235         oldDTRstate = getDTR();
00236         flowcontrol = 0;
00237         plusinc = 0;
00238         if(clientsocket) {
00239                 delete clientsocket;
00240                 clientsocket=0;
00241         }
00242         memset(&reg,0,sizeof(reg));
00243         reg[MREG_AUTOANSWER_COUNT]=0;   // no autoanswer
00244         reg[MREG_RING_COUNT] = 1;
00245         reg[MREG_ESCAPE_CHAR]='+';
00246         reg[MREG_CR_CHAR]='\r';
00247         reg[MREG_LF_CHAR]='\n';
00248         reg[MREG_BACKSPACE_CHAR]='\b';
00249 
00250         cmdpause = 0;   
00251         echo = true;
00252         doresponse = 0;
00253         numericresponse = false;
00254 
00255         /* Default to direct null modem connection.  Telnet mode interprets IAC codes */
00256         telnetmode = false;
00257 }
00258 
00259 void CSerialModem::EnterIdleState(void){
00260         connected=false;
00261         ringing=false;
00262         
00263         if(clientsocket) {
00264                 delete clientsocket;
00265                 clientsocket=0;
00266         }
00267 
00268         if(waitingclientsocket) {       // clear current incoming socket
00269                 delete waitingclientsocket;
00270                 waitingclientsocket=0;
00271         }
00272         // get rid of everything
00273         if(serversocket) {
00274                 while ((waitingclientsocket=serversocket->Accept()))
00275                         delete waitingclientsocket;
00276         } else if (listenport) {
00277                 
00278                 serversocket=new TCPServerSocket(listenport);   
00279                 if(!serversocket->isopen) {
00280                         LOG_MSG("Serial%d: Modem could not open TCP port %d.",(int)COMNUMBER,(int)listenport);
00281                         delete serversocket;
00282                         serversocket=0;
00283                 } else LOG_MSG("Serial%d: Modem listening on port %d...",(int)COMNUMBER,(int)listenport);
00284         }
00285         waitingclientsocket=0;
00286         
00287         commandmode = true;
00288         CSerial::setCD(false);
00289         CSerial::setRI(false);
00290         CSerial::setDSR(true);
00291         CSerial::setCTS(true);
00292         tqueue->clear();
00293 }
00294 
00295 void CSerialModem::EnterConnectedState(void) {
00296         if(serversocket) {
00297                 // we don't accept further calls
00298                 delete serversocket;
00299                 serversocket=0;
00300         }
00301         SendRes(ResCONNECT);
00302         commandmode = false;
00303         memset(&telClient, 0, sizeof(telClient));
00304         connected = true;
00305         ringing = false;
00306         CSerial::setCD(true);
00307         CSerial::setRI(false);
00308 }
00309 
00310 void CSerialModem::DoCommand() {
00311         cmdbuf[cmdpos] = 0;
00312         cmdpos = 0;                     //Reset for next command
00313         upcase(cmdbuf);
00314         LOG_MSG("Command sent to modem: ->%s<-\n", cmdbuf);
00315         /* Check for empty line, stops dialing and autoanswer */
00316         if (!cmdbuf[0]) {
00317                 reg[0]=0;       // autoanswer off
00318                 return;
00319         }
00320         //else {
00321                 //MIXER_Enable(mhd.chan,false);
00322         //      dialing = false;
00323         //      SendRes(ResNOCARRIER);
00324         //      goto ret_none;
00325         //}
00326         /* AT command set interpretation */
00327 
00328         if ((cmdbuf[0] != 'A') || (cmdbuf[1] != 'T')) {
00329                 SendRes(ResERROR);
00330                 return;
00331         }
00332         if (strstr(cmdbuf,"NET0")) {
00333                 telnetmode = false;
00334                 SendRes(ResOK);
00335                 return;
00336         }
00337         else if (strstr(cmdbuf,"NET1")) {
00338                 telnetmode = true;
00339                 SendRes(ResOK);
00340                 return;
00341         }
00342 
00343         char * scanbuf = &cmdbuf[2];
00344         while (1) {
00345                 // LOG_MSG("loopstart ->%s<-",scanbuf);
00346                 char chr = GetChar(scanbuf);
00347                 switch (chr) {
00348                 case 'D': { // Dial
00349                         char * foundstr=&scanbuf[0];
00350                         if (*foundstr=='T' || *foundstr=='P') foundstr++;
00351                         // Small protection against empty line and long string
00352                         if ((!foundstr[0]) || (strlen(foundstr)>100)) {
00353                                 SendRes(ResERROR);
00354                                 return;
00355                         }
00356                         char* helper;
00357                         // scan for and remove spaces; weird bug: with leading spaces in the string,
00358                         // SDLNet_ResolveHost will return no error but not work anyway (win)
00359                         while(foundstr[0]==' ') foundstr++;
00360                         helper=foundstr;
00361                         helper+=strlen(foundstr);
00362                         while(helper[0]==' ') {
00363                                 helper[0]=0;
00364                                 helper--;
00365                         }
00366                         if (strlen(foundstr) >= 12) {
00367                                 // Check if supplied parameter only consists of digits
00368                                 bool isNum = true;
00369                                 for (Bitu i=0; i<strlen(foundstr); i++)
00370                                         if (foundstr[i] < '0' || foundstr[i] > '9') isNum = false;
00371                                 if (isNum) {
00372                                         // Parameter is a number with at least 12 digits => this cannot
00373                                         // be a valid IP/name
00374                                         // Transform by adding dots
00375                                         char buffer[128];
00376                                         Bitu j = 0;
00377                                         for (Bitu i=0; i<strlen(foundstr); i++) {
00378                                                 buffer[j++] = foundstr[i];
00379                                                 // Add a dot after the third, sixth and ninth number
00380                                                 if (i == 2 || i == 5 || i == 8)
00381                                                         buffer[j++] = '.';
00382                                                 // If the string is longer than 12 digits,
00383                                                 // interpret the rest as port
00384                                                 if (i == 11 && strlen(foundstr)>12)
00385                                                         buffer[j++] = ':';
00386                                         }
00387                                         buffer[j] = 0;
00388                                         foundstr = buffer;
00389                                 }
00390                         }
00391                         Dial(foundstr);
00392                         return;
00393                 }
00394                 case 'I': // Some strings about firmware
00395                         switch (ScanNumber(scanbuf)) {
00396                         case 3: SendLine("DosBox Emulated Modem Firmware V1.00"); break;
00397                         case 4: SendLine("Modem compiled for DosBox version " VERSION); break;
00398                         }
00399                         break;
00400                 case 'E': // Echo on/off
00401                         switch (ScanNumber(scanbuf)) {
00402                         case 0: echo = false; break;
00403                         case 1: echo = true; break;
00404                         }
00405                         break;
00406                 case 'V':
00407                         switch (ScanNumber(scanbuf)) {
00408                         case 0: numericresponse = true; break;
00409                         case 1: numericresponse = false; break;
00410                         }
00411                         break;
00412                 case 'H': // Hang up
00413                         switch (ScanNumber(scanbuf)) {
00414                         case 0:
00415                                 if (connected) {
00416                                         SendRes(ResNOCARRIER);
00417                                         EnterIdleState();
00418                                         return;
00419                                 }
00420                                 // else return ok
00421                         }
00422                         break;
00423                 case 'O': // Return to data mode
00424                         switch (ScanNumber(scanbuf)) {
00425                         case 0:
00426                                 if (clientsocket) {
00427                                         commandmode = false;
00428                                         return;
00429                                 } else {
00430                                         SendRes(ResERROR);
00431                                         return;
00432                                 }
00433                         }
00434                         break;
00435                 case 'T': // Tone Dial
00436                 case 'P': // Pulse Dial
00437                         break;
00438                 case 'M': // Monitor
00439                 case 'L': // Volume
00440                         ScanNumber(scanbuf);
00441                         break;
00442                 case 'A': // Answer call
00443                         if (waitingclientsocket) {
00444                                 AcceptIncomingCall();
00445                         } else {
00446                                 SendRes(ResERROR);
00447                                 return;
00448                         }
00449                         return;
00450                 case 'Z': { // Reset and load profiles
00451                         // scan the number away, if any
00452                         ScanNumber(scanbuf);
00453                         if (clientsocket) SendRes(ResNOCARRIER);
00454                         Reset();
00455                         break;
00456                 }
00457                 case ' ': // skip space
00458                         break;
00459                 case 'Q': {
00460                         // Response options
00461                         // 0 = all on, 1 = all off,
00462                         // 2 = no ring and no connect/carrier in answermode
00463                         Bitu val = ScanNumber(scanbuf); 
00464                         if(!(val>2)) {
00465                                 doresponse=val;
00466                                 break;
00467                         } else {
00468                                 SendRes(ResERROR);
00469                                 return;
00470                         }
00471                 }
00472                 case 'S': { // Registers        
00473                         Bitu index=ScanNumber(scanbuf);
00474                         if(index>=SREGS) {
00475                                 SendRes(ResERROR);
00476                                 return; //goto ret_none;
00477                         }
00478                         
00479                         while(scanbuf[0]==' ') scanbuf++;       // skip spaces
00480                         
00481                         if(scanbuf[0]=='=') {   // set register
00482                                 scanbuf++;
00483                                 while(scanbuf[0]==' ') scanbuf++;       // skip spaces
00484                                 Bitu val = ScanNumber(scanbuf);
00485                                 reg[index]=val;
00486                                 break;
00487                         }
00488                         else if(scanbuf[0]=='?') {      // get register
00489                                 SendNumber(reg[index]);
00490                                 scanbuf++;
00491                                 break;
00492                         }
00493                         //else LOG_MSG("print reg %d with %d",index,reg[index]);
00494                 }
00495                 break;
00496                 case '&': { // & escaped commands
00497                         char cmdchar = GetChar(scanbuf);
00498                         switch(cmdchar) {
00499                                 case 'K': {
00500                                         Bitu val = ScanNumber(scanbuf);
00501                                         if(val<5) flowcontrol=val;
00502                                         else {
00503                                                 SendRes(ResERROR);
00504                                                 return;
00505                                         }
00506                                         break;
00507                                 }
00508                                 case '\0':
00509                                         // end of string
00510                                         SendRes(ResERROR);
00511                                         return;
00512                                 default:
00513                                         LOG_MSG("Modem: Unhandled command: &%c%d",cmdchar,(int)ScanNumber(scanbuf));
00514                                         break;
00515                         }
00516                         break;
00517                 }
00518                 case '\\': { // \ escaped commands
00519                         char cmdchar = GetChar(scanbuf);
00520                         switch(cmdchar) {
00521                                 case 'N':
00522                                         // error correction stuff - not emulated
00523                                         if (ScanNumber(scanbuf) > 5) {
00524                                                 SendRes(ResERROR);
00525                                                 return;
00526                                         }
00527                                         break;
00528                                 case '\0':
00529                                         // end of string
00530                                         SendRes(ResERROR);
00531                                         return;
00532                                 default:
00533                                         LOG_MSG("Modem: Unhandled command: \\%c%d",cmdchar, (int)ScanNumber(scanbuf));
00534                                         break;
00535                         }
00536                         break;
00537                 }
00538                 case '\0':
00539                         SendRes(ResOK);
00540                         return;
00541                 default:
00542                         LOG_MSG("Modem: Unhandled command: %c%d",chr,(int)ScanNumber(scanbuf));
00543                         break;
00544                 }
00545         }
00546 }
00547 
00548 void CSerialModem::TelnetEmulation(Bit8u * data, Bitu size) {
00549         Bitu i;
00550         Bit8u c;
00551         for(i=0;i<size;i++) {
00552                 c = data[i];
00553                 if(telClient.inIAC) {
00554                         if(telClient.recCommand) {
00555                                 if((c != 0) && (c != 1) && (c != 3)) {
00556                                         LOG_MSG("MODEM: Unrecognized option %d", c);
00557                                         if(telClient.command>250) {
00558                                                 /* Reject anything we don't recognize */
00559                                                 tqueue->addb(0xff);
00560                                                 tqueue->addb(252);
00561                                                 tqueue->addb(c); /* We won't do crap! */
00562                                         }
00563                         }
00564                         switch(telClient.command) {
00565                                 case 251: /* Will */
00566                                         if(c == 0) telClient.binary[TEL_SERVER] = true;
00567                                         if(c == 1) telClient.echo[TEL_SERVER] = true;
00568                                         if(c == 3) telClient.supressGA[TEL_SERVER] = true;
00569                                         break;
00570                                 case 252: /* Won't */
00571                                         if(c == 0) telClient.binary[TEL_SERVER] = false;
00572                                         if(c == 1) telClient.echo[TEL_SERVER] = false;
00573                                         if(c == 3) telClient.supressGA[TEL_SERVER] = false;
00574                                         break;
00575                                 case 253: /* Do */
00576                                         if(c == 0) {
00577                                                 telClient.binary[TEL_CLIENT] = true;
00578                                                         tqueue->addb(0xff);
00579                                                         tqueue->addb(251);
00580                                                         tqueue->addb(0); /* Will do binary transfer */
00581                                         }
00582                                         if(c == 1) {
00583                                                 telClient.echo[TEL_CLIENT] = false;
00584                                                         tqueue->addb(0xff);
00585                                                         tqueue->addb(252);
00586                                                         tqueue->addb(1); /* Won't echo (too lazy) */
00587                                         }
00588                                         if(c == 3) {
00589                                                 telClient.supressGA[TEL_CLIENT] = true;
00590                                                         tqueue->addb(0xff);
00591                                                         tqueue->addb(251);
00592                                                         tqueue->addb(3); /* Will Suppress GA */
00593                                         }
00594                                         break;
00595                                 case 254: /* Don't */
00596                                         if(c == 0) {
00597                                                 telClient.binary[TEL_CLIENT] = false;
00598                                                         tqueue->addb(0xff);
00599                                                         tqueue->addb(252);
00600                                                         tqueue->addb(0); /* Won't do binary transfer */
00601                                         }
00602                                         if(c == 1) {
00603                                                 telClient.echo[TEL_CLIENT] = false;
00604                                                         tqueue->addb(0xff);
00605                                                         tqueue->addb(252);
00606                                                         tqueue->addb(1); /* Won't echo (fine by me) */
00607                                         }
00608                                         if(c == 3) {
00609                                                 telClient.supressGA[TEL_CLIENT] = true;
00610                                                         tqueue->addb(0xff);
00611                                                         tqueue->addb(251);
00612                                                         tqueue->addb(3); /* Will Suppress GA (too lazy) */
00613                                         }
00614                                         break;
00615                                 default:
00616                                         LOG_MSG("MODEM: Telnet client sent IAC %d", telClient.command);
00617                                         break;
00618                         }
00619                         telClient.inIAC = false;
00620                         telClient.recCommand = false;
00621                         continue;
00622                 } else {
00623                         if(c==249) {
00624                                 /* Go Ahead received */
00625                                 telClient.inIAC = false;
00626                                 continue;
00627                         }
00628                         telClient.command = c;
00629                         telClient.recCommand = true;
00630                         
00631                         if((telClient.binary[TEL_SERVER]) && (c == 0xff)) {
00632                                 /* Binary data with value of 255 */
00633                                 telClient.inIAC = false;
00634                                 telClient.recCommand = false;
00635                                         rqueue->addb(0xff);
00636                                 continue;
00637                         }
00638                 }
00639         } else {
00640                 if(c == 0xff) {
00641                         telClient.inIAC = true;
00642                         continue;
00643                 }
00644                         rqueue->addb(c);
00645                 }
00646         }
00647 }
00648 
00649 void CSerialModem::Timer2(void) {
00650 
00651         bool sendbyte = true;
00652         Bitu usesize;
00653         Bit8u txval;
00654         Bitu txbuffersize =0;
00655 
00656         // Check for eventual break command
00657         if (!commandmode) cmdpause++;
00658         // Handle incoming data from serial port, read as much as available
00659         CSerial::setCTS(true);  // buffer will get 'emptier', new data can be received 
00660         while (tqueue->inuse()) {
00661                 txval = tqueue->getb();
00662                 if (commandmode) {
00663                         if (echo) {
00664                                 rqueue->addb(txval);
00665                                 //LOG_MSG("Echo back to queue: %x",txval);
00666                         }
00667                         if (txval==0xa) continue;               //Real modem doesn't seem to skip this?
00668                         else if (txval==0x8 && (cmdpos > 0)) --cmdpos;  // backspace
00669                         else if (txval==0xd) DoCommand();                               // return
00670                         else if (txval != '+') {
00671                                 if(cmdpos<99) {
00672                                         cmdbuf[cmdpos] = txval;
00673                                         cmdpos++;
00674                                 }
00675                         }
00676                 }
00677                 else {// + character
00678                         // 1000 ticks have passed, can check for pause command
00679                         if (cmdpause > 1000) {
00680                                 if(txval ==reg[MREG_ESCAPE_CHAR]) // +
00681                                 {
00682                                         plusinc++;
00683                                         if(plusinc>=3) {
00684                                                 LOG_MSG("Modem: Entering command mode(escape sequence)");
00685                                                 commandmode = true;
00686                                                 SendRes(ResOK);
00687                                                 plusinc = 0;
00688                                         }
00689                                         sendbyte=false;
00690                                 } else {
00691                                         plusinc=0;
00692                                 }
00693         // If not a special pause command, should go for bigger blocks to send 
00694                         }
00695                         tmpbuf[txbuffersize] = txval;
00696                         txbuffersize++;
00697                 }
00698         } // while loop
00699         
00700         if (clientsocket && sendbyte && txbuffersize) {
00701                 // down here it saves a lot of network traffic
00702                 if(!clientsocket->SendArray(tmpbuf,txbuffersize)) {
00703                         SendRes(ResNOCARRIER);
00704                         EnterIdleState();
00705                 }
00706         }
00707         // Handle incoming to the serial port
00708         if(!commandmode && clientsocket && rqueue->left()) {
00709                 usesize = rqueue->left();
00710                 if (usesize>16) usesize=16;
00711                 if(!clientsocket->ReceiveArray(tmpbuf, &usesize)) {
00712                         SendRes(ResNOCARRIER);
00713                         EnterIdleState();
00714                 } else if(usesize) {
00715                         // Filter telnet commands 
00716                         if(telnetmode) TelnetEmulation(tmpbuf, usesize);
00717                         else rqueue->adds(tmpbuf,usesize);
00718                         cmdpause = 0;
00719                 } 
00720         }
00721         // Check for incoming calls
00722         if (!connected && !waitingclientsocket && serversocket) {
00723                 waitingclientsocket=serversocket->Accept();
00724                 if(waitingclientsocket) {       
00725                         if(!CSerial::getDTR()) {
00726                                 // accept no calls with DTR off; TODO: AT &Dn
00727                                 EnterIdleState();
00728                         } else {
00729                                 ringing=true;
00730                                 SendRes(ResRING);
00731                                 CSerial::setRI(!CSerial::getRI());
00732                                 //MIXER_Enable(mhd.chan,true);
00733                                 ringtimer = 3000;
00734                                 reg[1] = 0;             //Reset ring counter reg
00735                         }
00736                 }
00737         }
00738         if (ringing) {
00739                 if (ringtimer <= 0) {
00740                         reg[1]++;
00741                         if ((reg[0]>0) && (reg[0]>=reg[1])) {
00742                                 AcceptIncomingCall();
00743                                 return;
00744                         }
00745                         SendRes(ResRING);
00746                         CSerial::setRI(!CSerial::getRI());
00747 
00748                         //MIXER_Enable(mhd.chan,true);
00749                         ringtimer = 3000;
00750                 }
00751                 --ringtimer;
00752         }
00753 }
00754 
00755 
00756 //TODO
00757 void CSerialModem::RXBufferEmpty() {
00758         // see if rqueue has some more bytes
00759         if(rqueue->inuse() && (CSerial::getRTS()||(flowcontrol!=3))){
00760                 Bit8u rbyte = rqueue->getb();
00761                 //LOG_MSG("Modem: sending byte %2x back to UART1",rbyte);
00762                 CSerial::receiveByte(rbyte);
00763         }
00764 }
00765 
00766 void CSerialModem::transmitByte(Bit8u val, bool first) {
00767         waiting_tx_character=val;
00768         setEvent(MODEM_TX_EVENT, bytetime); // TX event
00769         if(first) ByteTransmitting();
00770         //LOG_MSG("MODEM: Byte %x to be transmitted",val);
00771 }
00772 
00773 void CSerialModem::updatePortConfig(Bit16u, Bit8u lcr) { 
00774 // nothing to do here right?
00775 }
00776 
00777 void CSerialModem::updateMSR() {
00778         // think it is not needed
00779 }
00780 
00781 void CSerialModem::setBreak(bool) {
00782         // TODO: handle this
00783 }
00784 
00785 void CSerialModem::setRTSDTR(bool rts, bool dtr) {
00786         setDTR(dtr);
00787 }
00788 void CSerialModem::setRTS(bool val) {
00789         
00790 }
00791 void CSerialModem::setDTR(bool val) {
00792         if(!val && connected) {
00793                 // If DTR goes low, hang up.
00794                 SendRes(ResNOCARRIER);
00795                 EnterIdleState();
00796                 LOG_MSG("Modem: Hang up due to dropped DTR.");
00797         }       
00798 }
00799 /*
00800 void CSerialModem::updateModemControlLines() {
00801         //bool txrdy=tqueue->left();
00802         //if(CSerial::getRTS() && txrdy) CSerial::setCTS(true);
00803         //else CSerial::setCTS(tqueue->left());
00804         
00805         // If DTR goes low, hang up.
00806         if(connected)
00807                 if(oldDTRstate)
00808                         if(!getDTR()) {
00809                                 SendRes(ResNOCARRIER);
00810                                 EnterIdleState();
00811                                 LOG_MSG("Modem: Hang up due to dropped DTR.");
00812                         }
00813 
00814         oldDTRstate = getDTR();
00815 }
00816 */
00817 
00818 #endif
00819