From 23005cba52d6ba5b8d3767da2851d363ccb2fee6 Mon Sep 17 00:00:00 2001 From: Dean Beeler Date: Mon, 28 Jun 2004 01:41:56 +0000 Subject: [PATCH] Adding Win32 passthrough serial support Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@1858 --- src/dosbox.cpp | 14 +- src/hardware/directserial_win32.cpp | 190 +++++++ src/hardware/serialport.cpp | 411 ++++---------- src/hardware/softmodem.cpp | 852 +++++++++++++--------------- src/platform/visualc/config.h | 4 +- 5 files changed, 724 insertions(+), 747 deletions(-) create mode 100644 src/hardware/directserial_win32.cpp diff --git a/src/dosbox.cpp b/src/dosbox.cpp index 993540d9..8b2eea92 100644 --- a/src/dosbox.cpp +++ b/src/dosbox.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dosbox.cpp,v 1.69 2004-05-11 18:42:37 harekiet Exp $ */ +/* $Id: dosbox.cpp,v 1.70 2004-06-28 01:41:20 canadacow Exp $ */ #include #include @@ -79,6 +79,7 @@ void DISNEY_Init(Section*); void SERIAL_Init(Section*); void MODEM_Init(Section*); void IPX_Init(Section*); +void DIRECTSERIAL_Init(Section* sec); void PIC_Init(Section*); void TIMER_Init(Section*); @@ -368,6 +369,17 @@ void DOSBOX_Init(void) { "modem -- Enable virtual modem emulation.\n" "comport -- COM Port modem is connected to.\n" "listenport -- TCP Port the momdem listens on for incoming connections.\n" +#if C_DIRECTSERIAL + secprop=control->AddSection_prop("directserial",&DIRECTSERIAL_Init); + secprop->Add_bool("directserial", true); + secprop->Add_hex("comport",1); + secprop->Add_string("realport", "COM1"); + secprop->Add_int("defaultbps", 1200); + secprop->Add_string("parity", "N"); // Could be N, E, O + secprop->Add_int("bytesize", 8); // Could be 5 to 8 + secprop->Add_int("stopbit", 1); // Could be 1 or 2 +#endif + ); #endif diff --git a/src/hardware/directserial_win32.cpp b/src/hardware/directserial_win32.cpp new file mode 100644 index 00000000..83efd464 --- /dev/null +++ b/src/hardware/directserial_win32.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2002-2004 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "dosbox.h" + +#if C_DIRECTSERIAL + +#include +#include +#include + +#include "setup.h" +#include "serialport.h" + +// Win32 related headers +#include + +/* This is a serial passthrough class. Its amazingly simple to */ +/* write now that the serial ports themselves were abstracted out */ + + +class CDirectSerial : public CSerial { +public: + HANDLE hCom; + DCB dcb; + BOOL fSuccess; + + CDirectSerial(char * realPort, Bit16u baseAddr, Bit8u initIrq, Bit32u initBps, Bit16u bytesize, char *parity, Bit16u stopbits ) : CSerial(baseAddr, initIrq, initBps) { + LOG_MSG("Opening Windows serial port"); + hCom = CreateFile(realPort, GENERIC_READ | GENERIC_WRITE, + 0, // must be opened with exclusive-access + NULL, // no security attributes + OPEN_EXISTING, // must use OPEN_EXISTING + 0, // non overlapped I/O + NULL // hTemplate must be NULL for comm devices + ); + + if (hCom == INVALID_HANDLE_VALUE) + { + LOG_MSG("CreateFile failed with error %d.\n", GetLastError()); + hCom = 0; + return; + } + + fSuccess = GetCommState(hCom, &dcb); + + if (!fSuccess) + { + // Handle the error. + LOG_MSG("GetCommState failed with error %d.\n", GetLastError()); + return; + } + + + dcb.BaudRate = initBps; // set the baud rate + dcb.ByteSize = bytesize; // data size, xmit, and rcv + if(parity[0] == 'N') + dcb.Parity = NOPARITY; // no parity bit + if(parity[1] == 'E') + dcb.Parity = EVENPARITY; // even parity bit + if(parity[2] == 'O') + dcb.Parity = ODDPARITY; // odd parity bit + + + if(stopbits == 1) + dcb.StopBits = ONESTOPBIT; // one stop bit + if(stopbits == 2) + dcb.StopBits = TWOSTOPBITS; // two stop bits + + fSuccess = SetCommState(hCom, &dcb); + + // Configure timeouts to effectively use polling + COMMTIMEOUTS ct; + ct.ReadIntervalTimeout = MAXDWORD; + ct.ReadTotalTimeoutConstant = 0; + ct.ReadTotalTimeoutMultiplier = 0; + ct.WriteTotalTimeoutConstant = 0; + ct.WriteTotalTimeoutMultiplier = 0; + SetCommTimeouts(hCom, &ct); + + } + + ~CDirectSerial() { + if(hCom != INVALID_HANDLE_VALUE) CloseHandle(hCom); + } + + bool CanRecv(void) { return true; } + bool CanSend(void) { return true; } + + void Send(Bit8u val) { tqueue->addb(val); } + + Bit8u Recv(Bit8u val) { return rqueue->getb(); } + + void updatestatus(void) { + Bit8u ms=0; + DWORD stat = 0; + GetCommModemStatus(hCom, &stat); + + //Check for data carrier + if(stat & MS_RLSD_ON) ms|=MS_DCD; + if (stat & MS_RING_ON) ms|=MS_RI; + if (stat & MS_DSR_ON) ms|=MS_DSR; + if (stat & MS_CTS_ON) ms|=MS_CTS; + SetModemStatus(ms); + } + + void Timer(void) { + DWORD dwRead; + Bit8u chRead; + + if (ReadFile(hCom, &chRead, 1, &dwRead, NULL)) { + if(dwRead != 0) { + if(!rqueue->isFull()) rqueue->addb(chRead); + } + } + + updatestatus(); + + Bit8u txval; + + Bitu tx_size=tqueue->inuse(); + while (tx_size--) { + txval = tqueue->getb(); + DWORD bytesWritten; + BOOL result; + result = WriteFile(hCom, &txval, 1, &bytesWritten, NULL); + if (!result) + { + // Handle the error. + LOG_MSG("WriteFile failed with error %d.\n", GetLastError()); + return; + } + + } + } + +}; + +CDirectSerial *cds; + +void DIRECTSERIAL_Init(Section* sec) { + + unsigned long args = 1; + Section_prop * section=static_cast(sec); + + + if(!section->Get_bool("directserial")) return; + + Bit16u comport = section->Get_int("comport"); + Bit32u bps = section->Get_int("defaultbps"); + switch (comport) { + case 1: + cds = new CDirectSerial((char *)section->Get_string("realport"), 0x3f0, 4, bps, section->Get_int("bytesize"), (char *)section->Get_string("parity"), section->Get_int("stopbit")); + break; + case 2: + cds = new CDirectSerial((char *)section->Get_string("realport"), 0x2f0, 3, bps, section->Get_int("bytesize"), (char *)section->Get_string("parity"), section->Get_int("stopbit")); + break; + case 3: + cds = new CDirectSerial((char *)section->Get_string("realport"), 0x3e0, 4, bps, section->Get_int("bytesize"), (char *)section->Get_string("parity"), section->Get_int("stopbit")); + break; + case 4: + cds = new CDirectSerial((char *)section->Get_string("realport"), 0x2e0, 3, bps, section->Get_int("bytesize"), (char *)section->Get_string("parity"), section->Get_int("stopbit")); + break; + default: + cds = new CDirectSerial((char *)section->Get_string("realport"), 0x3f0, 4, bps, section->Get_int("bytesize"), (char *)section->Get_string("parity"), section->Get_int("stopbit")); + break; + + } + + + + seriallist.push_back(cds); +} + +#endif \ No newline at end of file diff --git a/src/hardware/serialport.cpp b/src/hardware/serialport.cpp index 1baccaef..77823315 100644 --- a/src/hardware/serialport.cpp +++ b/src/hardware/serialport.cpp @@ -17,6 +17,8 @@ */ #include +#include +#include #include "dosbox.h" #include "inout.h" @@ -29,390 +31,221 @@ #include "serialport.h" #define SERIALBASERATE 115200 -#define SERIALPORT_COUNT 2 - #define LOG_UART LOG_MSG -CSerial *serialports[SERIALPORT_COUNT]; +CSerialList seriallist; -void CSerial::setdivisor(Bit8u dmsb, Bit8u dlsb) { - Bitu divsize=(dmsb << 8) | dlsb; - if (divsize!=0) { +void CSerial::UpdateBaudrate(void) { + Bitu divsize=(divisor_msb << 8) | divisor_lsb; + if (divsize) { bps = SERIALBASERATE / divsize; } } +void CSerial::Timer(void) { + dotxint=true; + checkint(); +} + void CSerial::checkint(void) { - /* Find lowest priority interrupt to activate */ - Bitu i; - for (i=0;iinuse()) { +// LOG_MSG("RX IRQ with %d",rqueue->inuse()); + iir=0x4; + } else if ((ier & 0x2) && !tqueue->inuse() && dotxint) { + iir=0x2; + } else if ((ier & 0x8) && (mstatus & 0x0f)) { + iir=0x0; + } else { + iir=0x1; + PIC_DeActivateIRQ(irq); return; } - } - /* Not a single interrupt schedulded, lower IRQ */ - PIC_DeActivateIRQ(irq); - ints.active=INT_NONE; + if (mctrl & 0x8) PIC_ActivateIRQ(irq); + else PIC_DeActivateIRQ(irq); } -void CSerial::raiseint(INT_TYPES type) { -// LOG_MSG("Raising int %X rx size %d tx size %d",type,rx_fifo.used,tx_fifo.used); - ints.requested|=1 << type; - checkint(); -} - -void CSerial::lowerint(INT_TYPES type){ - ints.requested&=~(1 << type); - checkint(); -} - - -void CSerial::write_port(Bitu port, Bitu val) { - - port-=base; -// LOG_UART("Serial write %X val %x %c",port,val,val); - switch(port) { +void CSerial::write_reg(Bitu reg, Bitu val) { +// if (port!=9 && port!=8) LOG_MSG("Serial write %X val %x %c",port,val,val); + switch(reg) { case 0x8: // Transmit holding buffer + Divisor LSB if (dlab) { divisor_lsb = val; - setdivisor(divisor_msb, divisor_lsb); + UpdateBaudrate(); return; } - if (local_loopback) { - rx_addb(val); - } else tx_addb(val); + if (local_loopback) rqueue->addb(val); + else tqueue->addb(val); break; case 0x9: // Interrupt enable register + Divisor MSB if (dlab) { divisor_msb = val; - setdivisor(divisor_msb, divisor_lsb); + UpdateBaudrate(); return; + } else { + ier = val; + dotxint=true; } - /* Only enable the FIFO interrupt by default */ - ints.enabled=1 << INT_RX_FIFO; - if (val & 0x1) ints.enabled|=1 << INT_RX; - if (val & 0x2) ints.enabled|=1 << INT_TX; - if (val & 0x4) ints.enabled|=1 << INT_LS; - if (val & 0x8) ints.enabled|=1 << INT_MS; - ierval = val; - checkint(); break; case 0xa: // FIFO Control register - FIFOenabled = false; - if (val & 0x1) { -// FIFOenabled = true; - timeout = 0; - } - if (val & 0x2) { //Clear receiver FIFO - rx_fifo.used=0; - rx_fifo.pos=0; - } - if (val & 0x4) { //Clear transmit FIFO - tx_fifo.used=0; - tx_fifo.pos=0; - } + FIFOenabled = (val & 0x1) > 0; + if (val & 0x2) rqueue->clear(); //Clear receiver FIFO + if (val & 0x4) tqueue->clear(); //Clear transmit FIFO if (val & 0x8) LOG(LOG_MISC,LOG_WARN)("UART:Enabled DMA mode"); switch (val >> 6) { - case 0: - FIFOsize = 1; - break; - case 1: - FIFOsize = 4; - break; - case 2: - FIFOsize = 8; - break; - case 3: - FIFOsize = 14; - break; + case 0:FIFOsize = 1;break; + case 1:FIFOsize = 4;break; + case 2:FIFOsize = 8;break; + case 3:FIFOsize = 14;break; } break; case 0xb: // Line control register linectrl = val; - wordlen = (val & 0x3); - dlab = (val & 0x80) > 0; + dlab = (val & 0x80); break; case 0xc: // Modem control register - dtr = val & 0x01; - rts = (val & 0x02) > 0 ; - out1 = (val & 0x04) > 0; - out2 = (val & 0x08) > 0; - if (mc_handler) (*mc_handler)(val & 0xf); - local_loopback = (val & 0x10) > 0; + mctrl=val; + local_loopback = (val & 0x10); break; case 0xf: // Scratch register scratch = val; break; default: - LOG_UART("Modem: Write to 0x%x, with 0x%x '%c'\n", port,val,val); + LOG_UART("Modem: Write to 0x%x, with 0x%x '%c'\n", reg,val,val); break; } } -void CSerial::write_serial(Bitu port, Bitu val,Bitu iolen) { - int i; - - for(i=0;i=serialports[i]->base+0x8) && (port<=(serialports[i]->base+0xf)) ) { - serialports[i]->write_port(port,val); +static void WriteSerial(Bitu port,Bitu val,Bitu iolen) { + Bitu check=port&~0xf; + for (CSerial_it it=seriallist.begin();it!=seriallist.end();it++){ + CSerial * serial=(*it); + if (check==serial->base) { + serial->write_reg(port&0xf,val); + return; } } } -Bitu CSerial::read_port(Bitu port) { - Bit8u outval = 0; +static Bitu ReadSerial(Bitu port,Bitu iolen) { + Bitu check=port&~0xf; + + for (CSerial_it it=seriallist.begin();it!=seriallist.end();it++){ + CSerial * serial=(*it); + if (check==serial->base) { - port-=base; -// LOG_MSG("Serial read form %X",port); - switch(port) { + return serial->read_reg(port&0xf); + } + } + return 0; +} + +void SERIAL_Update(void) { + for (CSerial_it it=seriallist.begin();it!=seriallist.end();it++){ + CSerial * serial=(*it); + serial->Timer(); + } +} + + + +Bitu CSerial::read_reg(Bitu reg) { + Bitu retval; +// if (port!=0xd && port!=0xa) LOG_MSG("REad from port %x",reg); + switch(reg) { case 0x8: // Receive buffer + Divisor LSB if (dlab) { return divisor_lsb ; } else { - outval = rx_readb(); -// LOG_UART("Read from %X %X %c remain %d",port,outval,outval,rx_fifo.used); - return outval; + retval=rqueue->getb(); + //LOG_MSG("Received char %x %c",retval,retval); + checkint(); + return retval; } case 0x9: // Interrupt enable register + Divisor MSB if (dlab) { return divisor_msb ; } else { -// LOG_UART("Read from %X %X",port,ierval); - return ierval; + return ier; } case 0xa: // Interrupt identification register - switch (ints.active) { - case INT_MS: - outval = 0x0; - break; - case INT_TX: - outval = 0x2; - lowerint(INT_TX); - goto skipreset; - case INT_RX: - outval = 0x4; - break; - case INT_RX_FIFO: - lowerint(INT_RX_FIFO); - outval = 0xc; - goto skipreset; - case INT_LS: - outval = 0x6; - break; - case INT_NONE: - outval = 0x1; - break; + retval=iir; + if (iir==2) { + dotxint=false; + iir=1; } - ints.active=INT_NONE; -skipreset: - if (FIFOenabled) outval |= 3 << 6; -// LOG_UART("Read from %X %X",port,outval); - return outval; +// LOG_MSG("Read iir %d after %d",retval,iir); + return retval | ((FIFOenabled) ? (3 << 6) : 0); case 0xb: // Line control register - LOG_UART("Read from %X %X",port,outval); return linectrl; case 0xC: // Modem control register - outval = dtr | (rts << 1) | (out1 << 2) | (out2 << 3) | (local_loopback << 4); -// LOG_UART("Read from %X %X",port,outval); - return outval; + return mctrl; case 0xD: // Line status register - lowerint(INT_LS); - outval = 0x40; - if (FIFOenabled) { - if (!tx_fifo.used) outval|=0x20; - } else if (tx_fifo.usedinuse()) retval|=0x20; + if (rqueue->inuse()) retval|= 1; +// LOG_MSG("Read from line status %x",retval); + return retval; case 0xE: // modem status register - lowerint(INT_MS); -// LOG_UART("Read from %X %X",port,outval); - outval=mstatus; + retval=mstatus; mstatus&=0xf0; - return outval; + checkint(); + return retval; case 0xF: // Scratch register return scratch; default: //LOG_DEBUG("Modem: Read from 0x%x\n", port); break; } - - return 0x00; - - - -} - -Bitu CSerial::read_serial(Bitu port,Bitu iolen) -{ - int i; - for(i=0;i=serialports[i]->base+0x8) && (port<=(serialports[i]->base+0xf)) ) { - return serialports[i]->read_port(port); - } - } return 0x00; } -Bitu CSerial::rx_free() { - return FIFO_SIZE-rx_fifo.used; -} -Bitu CSerial::tx_free() { - return FIFO_SIZE-tx_fifo.used; -} - -Bitu CSerial::tx_size() { - if (FIFOenabled && rx_fifo.used && (rx_lastread < (PIC_Ticks-2))) { - raiseint(INT_RX_FIFO); - } - return tx_fifo.used; -} - -Bitu CSerial::rx_size() { - return rx_fifo.used; -} - -void CSerial::rx_addb(Bit8u data) { -// LOG_UART("RX add %c",data); - if (rx_fifo.used=FIFO_SIZE) where-=FIFO_SIZE; - rx_fifo.data[where]=data; - rx_fifo.used++; - if (FIFOenabled && (rx_fifo.used < FIFOsize)) return; - /* Raise rx irq if possible */ - if (ints.active != INT_RX) raiseint(INT_RX); - } -} - -void CSerial::rx_adds(Bit8u * data,Bitu size) { - if ((rx_fifo.used+size)<=FIFO_SIZE) { - Bitu where=rx_fifo.pos+rx_fifo.used; - rx_fifo.used+=size; - while (size--) { - if (where>=FIFO_SIZE) where-=FIFO_SIZE; - rx_fifo.data[where++]=*data++; - } - if (FIFOenabled && (rx_fifo.used < FIFOsize)) return; - if (ints.active != INT_RX) raiseint(INT_RX); - } -// else LOG_MSG("WTF"); -} - -void CSerial::tx_addb(Bit8u data) { -// LOG_UART("TX add %c",data); - if (tx_fifo.used=FIFO_SIZE) where-=FIFO_SIZE; - tx_fifo.data[where]=data; - tx_fifo.used++; - if (tx_fifo.used<(FIFO_SIZE-16)) { - /* Only generate FIFO irq's every 16 bytes */ - if (FIFOenabled && (tx_fifo.used & 0xf)) return; - raiseint(INT_TX); - } - } else { -// LOG_MSG("tx addb"); +void CSerial::SetModemStatus(Bit8u status) { + status&=0xf; + Bit8u oldstatus=mstatus >> 4; + if (oldstatus ^ status ) { + mstatus=(mstatus & 0xf) | status << 4; + mstatus|=(oldstatus ^ status) & ((status & 0x4) | (0xf-0x4)); } } -Bit8u CSerial::rx_readb() { - if (rx_fifo.used) { - rx_lastread=PIC_Ticks; - Bit8u val=rx_fifo.data[rx_fifo.pos]; - rx_fifo.pos++; - if (rx_fifo.pos>=FIFO_SIZE) rx_fifo.pos-=FIFO_SIZE; - rx_fifo.used--; - //Don't care for FIFO Size - if (FIFOenabled || !rx_fifo.used) lowerint(INT_RX); - else raiseint(INT_RX); - return val; - } else { -// LOG_MSG("WTF rx readb"); - return 0; - } -} - -Bit8u CSerial::tx_readb() { - if (tx_fifo.used) { - Bit8u val=tx_fifo.data[tx_fifo.pos]; - tx_fifo.pos++; - if (tx_fifo.pos>=FIFO_SIZE) tx_fifo.pos-=FIFO_SIZE; - tx_fifo.used--; - if (FIFOenabled && !tx_fifo.used) raiseint(INT_TX); - return val; - } else { -// LOG_MSG("WTF tx readb"); - return 0; - } -} - - -void CSerial::setmodemstatus(Bit8u status) { - Bitu oldstatus=mstatus >> 4; - if(oldstatus ^ status ) { - mstatus=status << 4; - mstatus|=(oldstatus ^ status); - raiseint(INT_MS); - } -} - -Bit8u CSerial::getmodemstatus() { - return (mstatus >> 4); -} - -Bit8u CSerial::getlinestatus() { - return read_port(0xd); -} - - -void CSerial::SetMCHandler(MControl_Handler * mcontrol) { - mc_handler=mcontrol; -} CSerial::CSerial (Bit16u initbase, Bit8u initirq, Bit32u initbps) { - int i; + Bitu i; Bit16u initdiv; base=initbase; irq=initirq; bps=initbps; - mc_handler = 0; - tx_fifo.used = tx_fifo.pos = 0; - rx_fifo.used = rx_fifo.pos = 0; - - rx_lastread = PIC_Ticks; - linectrl = dtr = rts = out1 = out2 = 0; local_loopback = 0; - ierval = 0; - ints.enabled=1 << INT_RX_FIFO; - ints.active=INT_NONE; - ints.requested=0; + ier = 0; + iir = 1; FIFOenabled = false; FIFOsize = 1; - timeout = 0; dlab = 0; - ierval = 0; + mstatus = 0; initdiv = SERIALBASERATE / bps; - setdivisor(initdiv >> 8, initdiv & 0x0f); + UpdateBaudrate(); - for (i=8;i<=0xf;i++) { - IO_RegisterWriteHandler(initbase+i,write_serial,IO_MB); - IO_RegisterReadHandler(initbase+i,read_serial,IO_MB); + for (i=base;i<=(base+8);i++) { + IO_RegisterWriteHandler(i+8,WriteSerial,IO_MB); + IO_RegisterReadHandler(i+8,ReadSerial,IO_MB); } PIC_RegisterIRQ(irq,0,"SERIAL"); + rqueue=new CFifo(QUEUE_SIZE); + tqueue=new CFifo(QUEUE_SIZE); + + }; @@ -422,20 +255,12 @@ CSerial::~CSerial(void) }; - -CSerial *getComport(Bitu portnum) -{ - return serialports[portnum-1]; -} - void SERIAL_Init(Section* sec) { - unsigned long args = 1; Section_prop * section=static_cast(sec); // if(!section->Get_bool("enabled")) return; - serialports[0] = new CSerial(0x3f0,4,SERIALBASERATE); - serialports[1] = new CSerial(0x2f0,3,SERIALBASERATE); + TIMER_AddTickHandler(&SERIAL_Update); } diff --git a/src/hardware/softmodem.cpp b/src/hardware/softmodem.cpp index 937df31d..968d8c94 100644 --- a/src/hardware/softmodem.cpp +++ b/src/hardware/softmodem.cpp @@ -16,21 +16,18 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - - #include "dosbox.h" #if C_MODEM +#include #include #include #include "SDL_net.h" #include "inout.h" #include "mixer.h" -#include "dma.h" #include "pic.h" -#include "hardware.h" #include "setup.h" #include "programs.h" #include "debug.h" @@ -41,31 +38,25 @@ #include "serialport.h" #define MODEMSPD 57600 -#define CONNECTED (M_CTS | M_DSR | M_DCD ) -#define DISCONNECTED (M_CTS | M_DSR ) +#define SREGS 100 -/* DTMF tone generator */ -float col[] = { 1209.0, 1336.0, 1477.0, 1633.0 }; -float row[] = { 697.0, 770.0, 852.0, 941.0 }; -char positions[] = "123A456B789C*0#D"; -#define duration 1000 -#define pause 400 -static Bit8u tmpbuf[FIFO_SIZE+1]; +static Bit8u tmpbuf[QUEUE_SIZE]; struct ModemHd { - char cmdbuf[FIFO_SIZE]; + char cmdbuf[QUEUE_SIZE]; bool commandmode; - bool cantrans; - bool incomingcall; - bool autoanswer; - bool echo; + bool answermode; + bool echo,response,numericresponse; bool telnetmode; Bitu cmdpause; - Bits ringcounter; - Bit16u plusinc; - Bit16u cmdpos; + Bits ringtimer; + Bits ringcount; + Bitu plusinc; + Bitu cmdpos; + Bit8u reg[SREGS]; + TCPsocket incomingsocket; TCPsocket socket; TCPsocket listensocket; SDLNet_SocketSet socketset; @@ -82,7 +73,15 @@ struct ModemHd { Bitu diallen; Bitu dialpos; char dialstr[256]; - MIXER_Channel * chan; + // TODO: Re-enable dialtons + //MIXER_Channel * chan; +}; + +enum ResTypes { + ResNONE, + ResOK,ResERROR, + ResCONNECT,ResRING, + ResBUSY,ResNODIALTONE,ResNOCARRIER, }; #define TEL_CLIENT 0 @@ -96,40 +95,11 @@ struct telnetClient { bool inIAC; bool recCommand; - Bit8u command; - }; -static CSerial * mdm; -static ModemHd mhd; -static telnetClient telClient; -static void sendStr(const char *usestr) { - if (!mhd.echo) return; - Bitu i=0; - while (*usestr != 0) { - if (*usestr == 10) { - mdm->rx_addb(0xd); - mdm->rx_addb(0xa); - } else { - mdm->rx_addb((Bit8u)*usestr); - } - usestr++; - } -} - -static void sendOK() { - sendStr("\nOK\n"); -} - -static void sendError() { - sendStr("\nERROR\n"); -} - -void InitTelnet() { - memset(&telClient, 0, sizeof(telClient)); -} +#if 1 static void toUpcase(char *buffer) { Bitu i=0; @@ -139,26 +109,127 @@ static void toUpcase(char *buffer) { } } -static void openConnection() { + + +class CSerialModem : public CSerial { +public: + ModemHd mhd; + + CSerialModem(Bit16u baseAddr, Bit8u initIrq, Bit32u initBps, const char *remotestr = NULL, Bit16u lport = 27) + : CSerial(baseAddr, initIrq, initBps) + { + + + mhd.cmdpos = 0; + mhd.commandmode = true; + mhd.plusinc = 0; + mhd.incomingsocket = 0; + mhd.answermode = false; + memset(&mhd.reg,0,sizeof(mhd.reg)); + mhd.cmdpause = 0; + mhd.echo = true; + mhd.response = true; + mhd.numericresponse = false; + + /* Default to direct null modem connection. Telnet mode interprets IAC codes */ + mhd.telnetmode = false; + + /* Bind the modem to the correct serial port */ + //strcpy(mhd.remotestr, remotestr); + + /* Initialize the sockets and setup the listening port */ + mhd.socketset = SDLNet_AllocSocketSet(1); + if (!mhd.socketset) { + LOG_MSG("MODEM:Can't open socketset:%s",SDLNet_GetError()); + //TODO Should probably just exit + return; + } + mhd.socket=0; + mhd.listenport=lport; + if (mhd.listenport) { + IPaddress listen_ip; + SDLNet_ResolveHost(&listen_ip, NULL, mhd.listenport); + mhd.listensocket=SDLNet_TCP_Open(&listen_ip); + if (!mhd.listensocket) LOG_MSG("MODEM:Can't open listen port:%s",SDLNet_GetError()); + } else mhd.listensocket=0; + + // TODO: Fix dialtones if requested + //mhd.chan=MIXER_AddChannel((MIXER_MixHandler)this->MODEM_CallBack,8000,"MODEM"); + //MIXER_Enable(mhd.chan,false); + //MIXER_SetMode(mhd.chan,MIXER_16MONO); + + } + + + + void SendLine(const char *line) { + rqueue->addb(0xd); + rqueue->addb(0xa); + rqueue->adds((Bit8u *)line,strlen(line)); + rqueue->addb(0xd); + rqueue->addb(0xa); + + } + + void SendRes(ResTypes response) { + char * string;char * code; + switch (response) { + case ResNONE: + return; + case ResOK:string="OK";code="0";break; + case ResERROR:string="ERROR";code="4";break; + case ResRING:string="RING";code="2"; + case ResNODIALTONE:string="NO DIALTONE";code="6";break; + case ResNOCARRIER:string="NO CARRIER";code="3";break; + case ResCONNECT:string="CONNECT 57600";code="1";break; + } + + rqueue->addb(0xd);rqueue->addb(0xa); + rqueue->adds((Bit8u *)string,strlen(string)); + rqueue->addb(0xd);rqueue->addb(0xa); + } + + void Send(Bit8u val) { + tqueue->addb(val); + } + + Bit8u Recv(Bit8u val) { + return rqueue->getb(); + + } + + void openConnection(void) { if (mhd.socket) { LOG_MSG("Huh? already connected"); SDLNet_TCP_DelSocket(mhd.socketset,mhd.socket); SDLNet_TCP_Close(mhd.socket); } - mhd.socket = SDLNet_TCP_Open(&mhd.openip); + mhd.socket = SDLNet_TCP_Open(&openip); if (mhd.socket) { SDLNet_TCP_AddSocket(mhd.socketset,mhd.socket); - sendStr("\nCONNECT 57600\n"); + SendRes(ResCONNECT); mhd.commandmode = false; - mdm->setmodemstatus(CONNECTED); - InitTelnet(); + memset(&telClient, 0, sizeof(telClient)); + updatemstatus(); } else { - sendStr("\nNO DIALTONE\n"); + SendRes(ResNODIALTONE); + } } -} -static bool Dial(char * host) { + void updatemstatus(void) { + Bit8u ms=0; + //Check for data carrier, a connection that is + if (mhd.incomingsocket) ms|=MS_RI; + if (mhd.socket) ms|=MS_DCD; + if (!mhd.commandmode) ms|=MS_DSR; + //Check for DTR reply with DSR + // if (cport->mctrl & MC_DTR) ms|=MS_DSR; + //Check for RTS reply with CTS + if (mctrl & MC_RTS) ms|=MS_CTS; + SetModemStatus(ms); + } + bool Dial(char * host) { /* Scan host for port */ Bit16u port; char * hasport=strrchr(host,':'); @@ -168,141 +239,90 @@ static bool Dial(char * host) { } else port=23; /* Resolve host we're gonna dial */ LOG_MSG("host %s port %x",host,port); - if (!SDLNet_ResolveHost(&mhd.openip,host,port)) { - /* Prepare string for dial sound generator */ - int c; - char *addrptr=host; - mhd.dialstr[0] = 'd'; - mhd.dialstr[1] = 'd'; - mhd.dialstr[2] = 'd'; - mhd.dialstr[3] = 'd'; - mhd.dialstr[4] = 'd'; - mhd.dialstr[5] = 'p'; - c=6; - while(*addrptr != 0x00) { - if (strchr(positions, *addrptr)) { - mhd.dialstr[c] = *addrptr; - c++; - } - addrptr++; - } - mhd.dialstr[c] = 0x00; - - mhd.diallen = strlen(mhd.dialstr) * (Bit32u)(duration + pause); - mhd.dialpos = 0; - mhd.f1 = 0; - mhd.f2 = 0; - mhd.dialing = true; - MIXER_Enable(mhd.chan,true); + if (!SDLNet_ResolveHost(&openip,host,port)) { + openConnection(); return true; } else { LOG_MSG("Failed to resolve host %s:%s",host,SDLNet_GetError()); - sendStr("\nNO CARRIER\n"); + SendRes(ResNOCARRIER); return false; } -} - - -static void DoCommand() { - bool found = false; - bool foundat = false; - char *foundstr; - bool connResult = false; - char msgbuf[4096]; - - Bitu result; - mhd.cmdbuf[mhd.cmdpos] = 0; - toUpcase(mhd.cmdbuf); - LOG_MSG("Modem Sent Command: %s\n", mhd.cmdbuf); - mhd.cmdpos = 0; - - result = 0; - - - /* AT command set interpretation */ - if ((mhd.cmdbuf[0] == 'A') && (mhd.cmdbuf[1] == 'T')) foundat = true; - if (foundat) { - if (strstr(mhd.cmdbuf,"I3")) { - sendStr("\nDosBox Emulated Modem Firmware V1.00\n"); - result = 1; - } - if (strstr(mhd.cmdbuf,"I4")) { - sprintf(msgbuf, "\nModem compiled for DosBox version %s\n", VERSION); - sendStr(msgbuf); - result = 1; - } - if (strstr(mhd.cmdbuf,"S0=1")) { - mhd.autoanswer = true; - } - if (strstr(mhd.cmdbuf,"S0=0")) { - mhd.autoanswer = false; } - if (strstr(mhd.cmdbuf,"E0")) { - mhd.echo = false; - } - if (strstr(mhd.cmdbuf,"E1")) { - mhd.echo = true; + void AcceptIncomingCall(void) { + assert(!mhd.socket); + mhd.socket=mhd.incomingsocket; + SDLNet_TCP_AddSocket(mhd.socketset,mhd.socket); + SendRes(ResCONNECT); + LOG_MSG("Connected!\n"); + + mhd.incomingsocket = 0; + mhd.commandmode = false; } - if (strstr(mhd.cmdbuf,"NET0")) { - mhd.telnetmode = false; + Bitu ScanNumber(char * & scan) { + Bitu ret=0; + while (char c=*scan) { + if (c>='0' && c<='9') { + ret*=10; + ret+=c-'0'; + scan++; + } else break; } - if (strstr(mhd.cmdbuf,"NET1")) { - mhd.telnetmode = true; + return ret; } - if (strstr(mhd.cmdbuf,"ATH")) { - /* Check if we're actually connected */ - if (mhd.socket) { - sendStr("\nNO CARRIER\n"); + void HangUp(void) { + SendRes(ResNOCARRIER); SDLNet_TCP_DelSocket(mhd.socketset,mhd.socket); SDLNet_TCP_Close(mhd.socket); mhd.socket=0; - mdm->setmodemstatus(DISCONNECTED); mhd.commandmode = true; - result = 3; - } else result = 2; + updatemstatus(); } - if(strstr(mhd.cmdbuf,"ATO")) { - /* Check for connection before switching to data mode */ - if (mhd.socket) { - mhd.commandmode = false; - result=3; + + void DoCommand() { + mhd.cmdbuf[mhd.cmdpos] = 0; + mhd.cmdpos = 0; //Reset for next command + toUpcase(mhd.cmdbuf); + LOG_MSG("Modem Sent Command: %s\n", mhd.cmdbuf); + /* Check for empty line, stops dialing and autoanswer */ + if (!mhd.cmdbuf[0]) { + if(!mhd.dialing) { + mhd.answermode = false; + goto ret_none; } else { - result=2; + //MIXER_Enable(mhd.chan,false); + mhd.dialing = false; + SendRes(ResNOCARRIER); + goto ret_none; } } - if(strstr(mhd.cmdbuf,"ATDT")) { - foundstr = strstr(mhd.cmdbuf,"ATDT"); - foundstr+=4; + /* AT command set interpretation */ + if ((mhd.cmdbuf[0] != 'A') || (mhd.cmdbuf[1] != 'T')) goto ret_error; + /* Check for dial command */ + if(strncmp(mhd.cmdbuf,"ATD3",3)==0) { + char * foundstr=&mhd.cmdbuf[3]; + if (*foundstr=='T' || *foundstr=='P') foundstr++; /* Small protection against empty line */ - if (!foundstr[0]) { - result=2; - } else { - if (strlen(foundstr) >= 12) - { + if (!foundstr[0]) goto ret_error; + if (strlen(foundstr) >= 12){ // Check if supplied parameter only consists of digits bool isNum = true; - for (int i=0; i '9') isNum = false; - - if (isNum) - { + if (isNum) { // Parameter is a number with at least 12 digits => this cannot be a valid IP/name // Transform by adding dots char buffer[128]; - int j = 0; - for (int i=0; i12) buffer[j++] = ':'; @@ -311,71 +331,113 @@ static void DoCommand() { foundstr = buffer; } } - connResult = Dial(foundstr); - result=3; + Dial(foundstr); + goto ret_none; } + char * scanbuf=&mhd.cmdbuf[2];char chr;Bitu num; + while (chr=*scanbuf++) { + switch (chr) { + case 'I': //Some strings about firmware + switch (num=ScanNumber(scanbuf)) { + case 3:SendLine("DosBox Emulated Modem Firmware V1.00");break; + case 4:SendLine("Modem compiled for DosBox version " VERSION);break; + };break; + case 'E': //Echo on/off + switch (num=ScanNumber(scanbuf)) { + case 0:mhd.echo = false;break; + case 1:mhd.echo = true;break; + };break; + case 'V': + switch (num=ScanNumber(scanbuf)) { + case 0:mhd.numericresponse = true;break; + case 1:mhd.numericresponse = false;break; + };break; + case 'H': //Hang up + switch (num=ScanNumber(scanbuf)) { + case 0: + if (mhd.socket) { + HangUp(); + goto ret_none; } - if(strstr(mhd.cmdbuf,"ATA")) { - if (mhd.incomingcall) { - sendStr("\nCONNECT 57600\n"); - LOG_MSG("Connected!\n"); - MIXER_Enable(mhd.chan,false); - mdm->setmodemstatus(CONNECTED); - mhd.incomingcall = false; + //Else return ok + };break; + case 'O': //Return to data mode + switch (num=ScanNumber(scanbuf)) { + case 0: + if (mhd.socket) { mhd.commandmode = false; - SDLNet_TCP_AddSocket(mhd.socketset,mhd.socket); - result = 3; + goto ret_none; } else { - mhd.autoanswer = true; - result = 3; + goto ret_error; + } + };break; + case 'T': //Tone Dial + case 'P': //Pulse Dial + break; + case 'M': //Monitor + case 'L': //Volume + ScanNumber(scanbuf); + break; + case 'A': //Answer call + if (mhd.incomingsocket) { + AcceptIncomingCall(); + } else { + mhd.answermode = true; + } + goto ret_none; + case 'Z': //Reset and load profiles + num=ScanNumber(scanbuf); + break; + case ' ': //Space just skip + break; + case 'S': //Registers + { + Bitu index=ScanNumber(scanbuf); + bool hasequal=(*scanbuf == '='); + if (hasequal) scanbuf++; + Bitu val=ScanNumber(scanbuf); + if (index>=SREGS) goto ret_error; + if (hasequal) mhd.reg[index]=val; + else LOG_MSG("print reg %d with %d",index,mhd.reg[index]); + };break; + default: + LOG_MSG("Unhandled cmd %c%d",chr,ScanNumber(scanbuf)); + } } + #if 0 + if (strstr(mhd.cmdbuf,"S0=1")) { + mhd.autoanswer = true; + } + if (strstr(mhd.cmdbuf,"S0=0")) { + mhd.autoanswer = false; } - if (result==0) result = 1; - } else result=2; - if (strlen(mhd.cmdbuf)<2) { - if(!mhd.dialing) { - result = 0; - mhd.autoanswer = false; - } else { - MIXER_Enable(mhd.chan,false); - mhd.dialing = false; - sendStr("\nNO CARRIER\n"); - result = 0; + if (strstr(mhd.cmdbuf,"NET0")) { + mhd.telnetmode = false; } + if (strstr(mhd.cmdbuf,"NET1")) { + mhd.telnetmode = true; } + #endif + LOG_MSG("Sending OK"); + SendRes(ResOK); + return; + ret_error: + LOG_MSG("Sending ERROR"); + SendRes(ResERROR); + ret_none: + return; - switch (result) { - case 1: - sendOK(); - break; - case 2: - sendError(); - break; } -} - - -static void MC_Changed(Bitu new_mc) { - LOG_MSG("DTR %d RTS %d",new_mc & 1,new_mc & 2); - if (!(new_mc & 1) && mhd.socket) { - sendStr("\nNO CARRIER\n"); - SDLNet_TCP_DelSocket(mhd.socketset,mhd.socket); - SDLNet_TCP_Close(mhd.socket); - mhd.socket=0; - mhd.commandmode = true; + void MC_Changed(Bitu new_mc) { + LOG_MSG("New MC %x",new_mc ); + if (!(new_mc & 1) && mhd.socket) HangUp(); + updatemstatus(); } - mdm->setmodemstatus( - ((new_mc & 1 ) ? M_DSR : 0) | - ((new_mc & 2) ? M_CTS : 0) | - (mhd.socket ? M_DCD : 0) - ); -} - -static void TelnetEmulation(Bit8u * data, Bitu size) { - int i; + void TelnetEmulation(Bit8u * data, Bitu size) { + Bitu i; Bit8u c; for(i=0;i250) { /* Reject anything we don't recognize */ - mdm->tx_addb(0xff); mdm->tx_addb(252); mdm->tx_addb(c); /* We won't do crap! */ + tqueue->addb(0xff); + tqueue->addb(252); + tqueue->addb(c); /* We won't do crap! */ } } - switch(telClient.command) { case 251: /* Will */ if(c == 0) telClient.binary[TEL_SERVER] = true; @@ -403,29 +466,41 @@ static void TelnetEmulation(Bit8u * data, Bitu size) { case 253: /* Do */ if(c == 0) { telClient.binary[TEL_CLIENT] = true; - mdm->tx_addb(0xff); mdm->tx_addb(251); mdm->tx_addb(0); /* Will do binary transfer */ + tqueue->addb(0xff); + tqueue->addb(251); + tqueue->addb(0); /* Will do binary transfer */ } if(c == 1) { telClient.echo[TEL_CLIENT] = false; - mdm->tx_addb(0xff); mdm->tx_addb(252); mdm->tx_addb(1); /* Won't echo (too lazy) */ + tqueue->addb(0xff); + tqueue->addb(252); + tqueue->addb(1); /* Won't echo (too lazy) */ } if(c == 3) { telClient.supressGA[TEL_CLIENT] = true; - mdm->tx_addb(0xff); mdm->tx_addb(251); mdm->tx_addb(3); /* Will Suppress GA */ + tqueue->addb(0xff); + tqueue->addb(251); + tqueue->addb(3); /* Will Suppress GA */ } break; case 254: /* Don't */ if(c == 0) { telClient.binary[TEL_CLIENT] = false; - mdm->tx_addb(0xff); mdm->tx_addb(252); mdm->tx_addb(0); /* Won't do binary transfer */ + tqueue->addb(0xff); + tqueue->addb(252); + tqueue->addb(0); /* Won't do binary transfer */ } if(c == 1) { telClient.echo[TEL_CLIENT] = false; - mdm->tx_addb(0xff); mdm->tx_addb(252); mdm->tx_addb(1); /* Won't echo (fine by me) */ + tqueue->addb(0xff); + tqueue->addb(252); + tqueue->addb(1); /* Won't echo (fine by me) */ } if(c == 3) { telClient.supressGA[TEL_CLIENT] = true; - mdm->tx_addb(0xff); mdm->tx_addb(251); mdm->tx_addb(3); /* Will Suppress GA (too lazy) */ + tqueue->addb(0xff); + tqueue->addb(251); + tqueue->addb(3); /* Will Suppress GA (too lazy) */ } break; default: @@ -450,7 +525,7 @@ static void TelnetEmulation(Bit8u * data, Bitu size) { /* Binary data with value of 255 */ telClient.inIAC = false; telClient.recCommand = false; - mdm->rx_addb(0xff); + rqueue->addb(0xff); continue; } @@ -460,12 +535,12 @@ static void TelnetEmulation(Bit8u * data, Bitu size) { telClient.inIAC = true; continue; } - mdm->rx_addb(c); + rqueue->addb(c); + } } } -} -static void MODEM_Hardware(void) { + void Timer(void) { int result =0; unsigned long args = 1; bool sendbyte = true; @@ -475,32 +550,20 @@ static void MODEM_Hardware(void) { /* Check for eventual break command */ if (!mhd.commandmode) mhd.cmdpause++; /* Handle incoming data from serial port, read as much as available */ - Bitu tx_size=mdm->tx_size(); + Bitu tx_size=tqueue->inuse(); while (tx_size--) { - txval = mdm->tx_readb(); + txval = tqueue->getb(); if (mhd.commandmode) { - if(txval != 0xd) { - if(txval == 0x8) { - if (mhd.cmdpos > 0) { - --mhd.cmdpos; - } - } else { - if (txval != '+') { - if(mhd.cmdposaddb(txval); + if (txval==0xa) continue; //Real modem doesn't seem to skip this? + else if (txval==0x8 && (mhd.cmdpos > 0)) --mhd.cmdpos; + else if (txval==0xd) DoCommand(); + else if (txval != '+') { + if(mhd.cmdposrx_addb(txval); - } else if (mhd.echo) { - mdm->rx_addb(10); - mdm->rx_addb(13); - } - } else { - DoCommand(); - } } else { /* 1000 ticks have passed, can check for pause command */ if (mhd.cmdpause > 1000) { @@ -509,14 +572,14 @@ static void MODEM_Hardware(void) { if(mhd.plusinc>=3) { LOG_MSG("Entering command mode"); mhd.commandmode = true; - sendStr("\nOK\n"); + SendRes(ResOK); mhd.plusinc = 0; } sendbyte=false; } else { mhd.plusinc=0; } -//If not a special pause command, should go for bigger blocks to send + //If not a special pause command, should go for bigger blocks to send } tmpbuf[0] = txval; @@ -530,207 +593,106 @@ static void MODEM_Hardware(void) { } SDLNet_CheckSockets(mhd.socketset,0); - /* Handle outgoing to the serial port */ - if(mdm->rx_size() == 0) { - if(!mhd.commandmode && mhd.socket && mdm->rx_free() && SDLNet_SocketReady(mhd.socket)) { - usesize = mdm->rx_free(); + /* Handle incoming to the serial port */ + if(!mhd.commandmode && mhd.socket) { + if(rqueue->left() && SDLNet_SocketReady(mhd.socket) && (mctrl & MC_RTS)) { + usesize = rqueue->left(); + if (usesize>16) usesize=16; result = SDLNet_TCP_Recv(mhd.socket, tmpbuf, usesize); if (result>0) { if(mhd.telnetmode) { /* Filter telnet commands */ TelnetEmulation(tmpbuf, result); - } else { - mdm->rx_adds(tmpbuf,result); + rqueue->adds(tmpbuf,result); } mhd.cmdpause = 0; - } else { - /* Error close the socket and disconnect */ - mdm->setmodemstatus(DISCONNECTED); - mhd.commandmode = true; - sendStr("\nNO CARRIER\n"); - SDLNet_TCP_DelSocket(mhd.socketset,mhd.socket); - SDLNet_TCP_Close(mhd.socket); - mhd.socket=0; + } else HangUp(); } } - } - /* Check for incoming calls */ - if (!mhd.socket && !mhd.incomingcall && mhd.listensocket) { - mhd.socket = SDLNet_TCP_Accept(mhd.listensocket); - if (mhd.socket) { - mhd.dialpos = 0; - mhd.incomingcall = true; + if (!mhd.socket && !mhd.incomingsocket && mhd.listensocket) { + mhd.incomingsocket = SDLNet_TCP_Accept(mhd.listensocket); + if (mhd.incomingsocket) { mhd.diallen = 12000; mhd.dialpos = 0; -//TODO Set ring in Modemstatus? - sendStr("\nRING\n"); - MIXER_Enable(mhd.chan,true); - mhd.ringcounter = 24000; + SendRes(ResRING); + //MIXER_Enable(mhd.chan,true); + mhd.ringtimer = 3000; + mhd.reg[1] = 0; //Reset ring counter reg } } - - if (mhd.incomingcall) { - if (mhd.ringcounter <= 0) { - if (mhd.autoanswer) { - mhd.incomingcall = false; - sendStr("\nCONNECT 57600\n"); - MIXER_Enable(mhd.chan,false); - mdm->setmodemstatus(CONNECTED); - mhd.incomingcall = false; - mhd.commandmode = false; - SDLNet_TCP_AddSocket(mhd.socketset,mhd.socket); + if (mhd.incomingsocket) { + if (mhd.ringtimer <= 0) { + mhd.reg[1]++; + if (mhd.answermode || (mhd.reg[0]==mhd.reg[1])) { + AcceptIncomingCall(); return; } - sendStr("\nRING\n"); + SendRes(ResRING); mhd.diallen = 12000; mhd.dialpos = 0; - - MIXER_Enable(mhd.chan,true); - - mhd.ringcounter = 3000; /* Ring every three seconds for accurate emulation */ - + //MIXER_Enable(mhd.chan,true); + mhd.ringtimer = 3000; } - if (mhd.ringcounter > 0) --mhd.ringcounter; - + --mhd.ringtimer; + } + updatemstatus(); } -} + bool CanSend(void) { + return true; + } -static void MODEM_CallBack(Bit8u * stream,Bit32u len) { - char *cp; - float ci,ri; - int innum, splitnum, quad, eighth, sixth, amp; - Bit8u curchar; - Bit32s buflen = (Bit32s)len; - if(mhd.incomingcall) { + bool CanRecv(void) { + return true; + } + + +protected: + char cmdbuf[QUEUE_SIZE]; + bool commandmode; + bool answermode; + bool echo; + bool telnetmode; + Bitu cmdpause; + Bits ringtimer; + Bits ringcount; + Bitu plusinc; + Bitu cmdpos; - if(mhd.dialpos>=mhd.diallen) { - MIXER_Enable(mhd.chan,false); - return; - } else { - quad = (mhd.diallen/14); - eighth = quad / 2; - sixth = eighth /2; + Bit8u reg[SREGS]; + IPaddress openip; + TCPsocket incomingsocket; + TCPsocket socket; + TCPsocket listensocket; + SDLNet_SocketSet socketset; - while ((buflen>0) && (mhd.dialpos=mhd.diallen) { - while(len-->0) { - *(Bit16s*)(stream) = 0; - stream+=2; - } - MIXER_Enable(mhd.chan,false); - mhd.dialing = false; - openConnection(); - return; - } else { +CSerialModem *csm; - while ((buflen>0) && (mhd.dialposGet_int("comport"); - /* Default to direct null modem connection. Telnet mode interprets IAC codes */ - mhd.telnetmode = false; + csm = NULL; - /* Bind the modem to the correct serial port */ - mhd.comport=section->Get_int("comport"); - strcpy(mhd.remotestr, section->Get_string("remote")); - mdm = getComport(mhd.comport); - mdm->setmodemstatus(DISCONNECTED); - mdm->SetMCHandler(&MC_Changed); + switch (comport) { + case 1: + csm = new CSerialModem(0x3f0, 4, 57600, section->Get_string("remote"), section->Get_int("listenport")); + break; + case 2: + csm = new CSerialModem(0x2f0, 3, 57600, section->Get_string("remote"), section->Get_int("listenport")); + break; + case 3: + csm = new CSerialModem(0x3e0, 4, 57600, section->Get_string("remote"), section->Get_int("listenport")); + break; + case 4: + csm = new CSerialModem(0x2e0, 3, 57600, section->Get_string("remote"), section->Get_int("listenport")); + break; + default: + // Default to COM2 + csm = new CSerialModem(0x2f0, 3, 57600, section->Get_string("remote"), section->Get_int("listenport")); + break; - TIMER_AddTickHandler(&MODEM_Hardware); - - /* Initialize the sockets and setup the listening port */ - mhd.socketset = SDLNet_AllocSocketSet(1); - if (!mhd.socketset) { - LOG_MSG("MODEM:Can't open socketset:%s",SDLNet_GetError()); -//TODO Should probably just exit - return; } - mhd.socket=0; - mhd.listenport=section->Get_int("listenport"); - if (mhd.listenport) { - IPaddress listen_ip; - SDLNet_ResolveHost(&listen_ip, NULL, mhd.listenport); - mhd.listensocket=SDLNet_TCP_Open(&listen_ip); - if (!mhd.listensocket) LOG_MSG("MODEM:Can't open listen port:%s",SDLNet_GetError()); - } else mhd.listensocket=0; - mhd.chan=MIXER_AddChannel(&MODEM_CallBack,8000,"MODEM"); - MIXER_Enable(mhd.chan,false); - MIXER_SetMode(mhd.chan,MIXER_16MONO); + if(csm != NULL) seriallist.push_back(csm); } + #endif diff --git a/src/platform/visualc/config.h b/src/platform/visualc/config.h index 78ccbefc..1751d54f 100644 --- a/src/platform/visualc/config.h +++ b/src/platform/visualc/config.h @@ -1,6 +1,8 @@ #define INLINE __forceinline -#define VERSION "0.60" +#define VERSION "0.61" + +#define C_DIRECTSERIAL 1 /* Define to 1 to enable internal debugger, requires libcurses */ #define C_DEBUG 1