// updatePortConfig is called when emulated app changes the serial port // parameters baudrate, stopbits, number of databits, parity. void CDirectSerial::updatePortConfig (Bit16u divider, Bit8u lcr) { Bit8u parity = 0; switch ((lcr & 0x38)>>3) { case 0x1: parity='o'; break; case 0x3: parity='e'; break; case 0x5: parity='m'; break; case 0x7: parity='s'; break; default: parity='n'; break; } Bit8u bytelength = (lcr & 0x3)+5; // baudrate Bitu baudrate; if(divider==0) baudrate=115200; else baudrate = 115200 / divider; // stopbits Bit8u stopbits; if (lcr & 0x4) { if (bytelength == 5) stopbits = SERIAL_15STOP; else stopbits = SERIAL_2STOP; } else stopbits = SERIAL_1STOP; if(!SERIAL_setCommParameters(comport, baudrate, parity, stopbits, bytelength)) { #if SERIAL_DEBUG log_ser(dbg_aux,"Serial port settings not supported by host." ); #endif LOG_MSG ("Serial%d: Desired serial mode not supported (%d,%d,%c,%d)", COMNUMBER, baudrate,bytelength,parity,stopbits); } CDirectSerial::setRTSDTR(getRTS(), getDTR()); }
void CSerialModem::Reset(){ EnterIdleState(); cmdpos = 0; cmdbuf[0]=0; oldDTRstate = getDTR(); flowcontrol = 0; plusinc = 0; if(clientsocket) { delete clientsocket; clientsocket=0; } memset(®,0,sizeof(reg)); reg[MREG_AUTOANSWER_COUNT]=0; // no autoanswer reg[MREG_RING_COUNT] = 1; reg[MREG_ESCAPE_CHAR]='+'; reg[MREG_CR_CHAR]='\r'; reg[MREG_LF_CHAR]='\n'; reg[MREG_BACKSPACE_CHAR]='\b'; cmdpause = 0; echo = true; doresponse = 0; numericresponse = false; /* Default to direct null modem connection. Telnet mode interprets IAC codes */ telnetmode = false; }
bool CNullModem::ServerConnect() { // check if a connection is available. clientsocket=serversocket->Accept(); if (!clientsocket) return false; Bit8u peeripbuf[16]; clientsocket->GetRemoteAddressString(peeripbuf); LOG_MSG("Serial%d: A client (%s) has connected.",(int)COMNUMBER,peeripbuf); #if SERIAL_DEBUG log_ser(dbg_aux,"Nullmodem: A client (%s) has connected.", peeripbuf); #endif /* FIXME: It would be nice if the SDL net library had a bind() call to bind only to a specific interface. * Or maybe it does... what am I missing? */ if (!nonlocal && strcmp((char*)peeripbuf,"127.0.0.1") != 0) { LOG_MSG("Serial%d: Non-localhost client (%s) dropped by nonlocal:0 policy. To accept connections from network, set nonlocal:1",(int)COMNUMBER,peeripbuf); delete clientsocket; clientsocket = NULL; return false; } clientsocket->SetSendBufferSize(256); rx_state=N_RX_IDLE; setEvent(SERIAL_POLLING_EVENT, 1); // we don't accept further connections delete serversocket; serversocket=0; // transmit the line status setRTSDTR(getRTS(), getDTR()); if (transparent) setCD(true); return true; }
void CNullModem::Disconnect() { removeEvent(SERIAL_POLLING_EVENT); removeEvent(SERIAL_RX_EVENT); // it was disconnected; free the socket and restart the server socket LOG_MSG("Serial%d: Disconnected.",COMNUMBER); delete clientsocket; clientsocket=0; setDSR(false); setCTS(false); setCD(false); if (serverport) { serversocket = new TCPServerSocket(serverport); if (serversocket->isopen) setEvent(SERIAL_SERVER_POLLING_EVENT, 50); else delete serversocket; } else if (dtrrespect) { setEvent(SERIAL_NULLMODEM_DTR_EVENT,50); DTR_delta = getDTR(); // try to reconnect the next time DTR is set } }
bool CNullModem::ClientConnect(TCPClientSocket* newsocket) { Bit8u peernamebuf[16]; clientsocket = newsocket; if (!clientsocket->isopen) { LOG_MSG("Serial%d: Connection failed.",COMNUMBER); delete clientsocket; clientsocket=0; setCD(false); return false; } clientsocket->SetSendBufferSize(256); clientsocket->GetRemoteAddressString(peernamebuf); // transmit the line status if (!transparent) setRTSDTR(getRTS(), getDTR()); rx_state=N_RX_IDLE; LOG_MSG("Serial%d: Connected to %s",COMNUMBER,peernamebuf); setEvent(SERIAL_POLLING_EVENT, 1); setCD(true); return true; }
bool CNullModem::ServerConnect() { // check if a connection is available. clientsocket=serversocket->Accept(); if (!clientsocket) return false; Bit8u peeripbuf[16]; clientsocket->GetRemoteAddressString(peeripbuf); LOG_MSG("Serial%d: A client (%s) has connected.",COMNUMBER,peeripbuf); #if SERIAL_DEBUG log_ser(dbg_aux,"Nullmodem: A client (%s) has connected.", peeripbuf); #endif clientsocket->SetSendBufferSize(256); rx_state=N_RX_IDLE; setEvent(SERIAL_POLLING_EVENT, 1); // we don't accept further connections delete serversocket; serversocket=0; // transmit the line status setRTSDTR(getRTS(), getDTR()); if (transparent) setCD(true); return true; }
void CNullModem::setRTS(bool val) { setRTSDTR(val, getDTR()); }
void CNullModem::setBreak (bool /*value*/) { CNullModem::setRTSDTR(getRTS(), getDTR()); }
void CNullModem::handleUpperEvent(Bit16u type) { switch(type) { case SERIAL_POLLING_EVENT: { // periodically check if new data arrived, disconnect // if required. Add it back. setEvent(SERIAL_POLLING_EVENT, 1.0f); // update Modem input line states updateMSR(); switch(rx_state) { case N_RX_IDLE: if (CanReceiveByte()) { if (doReceive()) { // a byte was received rx_state=N_RX_WAIT; setEvent(SERIAL_RX_EVENT, bytetime*0.9f); } // else still idle } else { #if SERIAL_DEBUG log_ser(dbg_aux,"Nullmodem: block on polling."); #endif rx_state=N_RX_BLOCKED; // have both delays (1ms + bytetime) setEvent(SERIAL_RX_EVENT, bytetime*0.9f); } break; case N_RX_BLOCKED: // one timeout tick if (!CanReceiveByte()) { rx_retry++; if (rx_retry>=rx_retry_max) { // it has timed out: rx_retry=0; removeEvent(SERIAL_RX_EVENT); if (doReceive()) { // read away everything while(doReceive()); rx_state=N_RX_WAIT; setEvent(SERIAL_RX_EVENT, bytetime*0.9f); } else { // much trouble about nothing rx_state=N_RX_IDLE; #if SERIAL_DEBUG log_ser(dbg_aux,"Nullmodem: unblock due to no more data",rx_retry); #endif } } // else wait further } else { // good: we can receive again removeEvent(SERIAL_RX_EVENT); rx_retry=0; if (doReceive()) { rx_state=N_RX_FASTWAIT; setEvent(SERIAL_RX_EVENT, bytetime*0.65f); } else { // much trouble about nothing rx_state=N_RX_IDLE; } } break; case N_RX_WAIT: case N_RX_FASTWAIT: break; } break; } case SERIAL_RX_EVENT: { switch(rx_state) { case N_RX_IDLE: LOG_MSG("internal error in nullmodem"); break; case N_RX_BLOCKED: // try to receive case N_RX_WAIT: case N_RX_FASTWAIT: if (CanReceiveByte()) { // just works or unblocked if (doReceive()) { rx_retry=0; // not waiting anymore if (rx_state==N_RX_WAIT) setEvent(SERIAL_RX_EVENT, bytetime*0.9f); else { // maybe unblocked rx_state=N_RX_FASTWAIT; setEvent(SERIAL_RX_EVENT, bytetime*0.65f); } } else { // didn't receive anything rx_retry=0; rx_state=N_RX_IDLE; } } else { // blocking now or still blocked #if SERIAL_DEBUG if (rx_state==N_RX_BLOCKED) log_ser(dbg_aux,"Nullmodem: rx still blocked (retry=%d)",rx_retry); else log_ser(dbg_aux,"Nullmodem: block on continued rx (retry=%d).",rx_retry); #endif setEvent(SERIAL_RX_EVENT, bytetime*0.65f); rx_state=N_RX_BLOCKED; } break; } break; } case SERIAL_TX_EVENT: { // Maybe echo cirquit works a bit better this way if (rx_state==N_RX_IDLE && CanReceiveByte() && clientsocket) { if (doReceive()) { // a byte was received rx_state=N_RX_WAIT; setEvent(SERIAL_RX_EVENT, bytetime*0.9f); } } ByteTransmitted(); break; } case SERIAL_THR_EVENT: { ByteTransmitting(); // actually send it setEvent(SERIAL_TX_EVENT,bytetime+0.01f); break; } case SERIAL_SERVER_POLLING_EVENT: { // As long as nothing is connected to our server poll the // connection. if (!ServerConnect()) { // continue looking setEvent(SERIAL_SERVER_POLLING_EVENT, 50); } break; } case SERIAL_TX_REDUCTION: { // Flush the data in the transmitting buffer. if (clientsocket) clientsocket->FlushBuffer(); tx_block=false; break; } case SERIAL_NULLMODEM_DTR_EVENT: { if ((!DTR_delta) && getDTR()) { // DTR went positive. Try to connect. if (ClientConnect(new TCPClientSocket((char*)hostnamebuffer, (Bit16u)clientport))) break; // no more DTR wait event when connected } DTR_delta = getDTR(); setEvent(SERIAL_NULLMODEM_DTR_EVENT,50); break; } } }