/* * serial.cxx * * copyright 2005 Derek J Smithies * * Simple program to illustrate usage of the serial port. * * Get two computers. Connect com1 port of both computers by cross over serial cable. * run this program on both computers (without arguments). * type text in one, hit return. See this text in the second computer. * * * $Log: serial.cxx,v $ * Revision 1.5 2005/11/30 12:47:40 csoutheren * Removed tabs, reformatted some code, and changed tags for Doxygen * * Revision 1.4 2005/03/18 21:06:09 dereksmithies * Add help messages. Enable different flow control options. * * Revision 1.3 2005/03/14 07:33:51 dereksmithies * Fix console input handling. Concatenate characters split by PSerialChannel reading. * * Revision 1.2 2005/03/12 06:44:22 dereksmithies * Fix typo in setting stopbits. Program now reports all serial parameters that are used. * * Revision 1.1 2005/03/10 09:21:46 dereksmithies * Initial release of a program to illustrate the operation of the serial port. * * * * */ #include #include #include class Serial : public PProcess { PCLASSINFO(Serial, PProcess); public: Serial(); void Main(); BOOL Initialise(PConfigArgs & args); void HandleConsoleInput(); void HandleSerialInput(); protected: PSerialChannel serial; PINDEX dataBits; PINDEX stopBits; PString flowControlString; PINDEX hardwarePort; PINDEX baud; PString parity; BOOL endNow; }; class UserInterfaceThread : public PThread { PCLASSINFO(UserInterfaceThread, PThread); public: UserInterfaceThread(Serial & _srl) : PThread(1000, NoAutoDeleteThread), srl(_srl) { Resume(); } void Main() { srl.HandleConsoleInput(); } protected: Serial & srl; }; class SerialInterfaceThread : public PThread { PCLASSINFO(SerialInterfaceThread, PThread); public: SerialInterfaceThread(Serial & _srl) : PThread(1000, NoAutoDeleteThread), srl(_srl) { Resume(); } void Main() { srl.HandleSerialInput(); } protected: Serial & srl; }; PCREATE_PROCESS(Serial) Serial::Serial() : PProcess("PwLib Example Factory", "serial", 1, 0, ReleaseCode, 0) { endNow = FALSE; } void Serial::Main() { PConfigArgs args(GetArguments()); // Example command line is : // serial --hardwareport 0 --baud 4800 --parity odd --stopbits 1 --databits 8 --flowcontrol XonXoff args.Parse( #if PTRACING "t-trace." "-no-trace." "o-output:" "-no-output." #endif #ifdef PMEMORY_CHECK "-setallocationbreakpoint:" #endif "-baud:" "-databits:" "-parity:" "-stopbits:" "-flowcontrol:" "-hardwareport:" "v-version." "h-help." , FALSE); #if PMEMORY_CHECK if (args.HasOption("setallocationbreakpoint")) PMemoryHeap::SetAllocationBreakpoint(args.GetOptionString("setallocationbreakpoint").AsInteger()); #endif PStringStream progName; progName << "Product Name: " << GetName() << endl << "Manufacturer: " << GetManufacturer() << endl << "Version : " << GetVersion(TRUE) << endl << "System : " << GetOSName() << '-' << GetOSHardware() << ' ' << GetOSVersion(); cout << progName << endl; if (args.HasOption('v')) return; #if PTRACING PTrace::Initialise(args.GetOptionCount('t'), args.HasOption('o') ? (const char *)args.GetOptionString('o') : NULL, PTrace::Blocks | PTrace::Timestamp | PTrace::Thread | PTrace::FileAndLine); #endif if (args.HasOption('h')) { cout << endl #if PTRACING << "-t --trace Debugging. Using more times for more detail" << endl << "-o --output name of trace output file. If not specified, goes to stdout" << endl #endif #ifdef PMEMORY_CHECK << " --setallocationbreakpoint stop program on allocation of memory block number" << endl #endif << " --baud Set the data rate for serial comms" << endl << " --databits Set the number of data bits (5, 6, 7, 8)" << endl << " --parity Set parity, even, odd or none " << endl << " --stopbits Set the number of stop bits (0, 1, 2) " << endl << " --flowcontrol Specifiy flow control, (none rtscts, xonxoff)" << endl << " --hardwareport Which serial port to use, 0, 1, 2..." << endl << "-v --version Print version information and exit" << endl << "-h --help Write this help out. " << endl << endl; return; } if (!Initialise(args)) { cout << "Failed to initialise the program with args of " << args << endl; PThread::Sleep(100); return; } UserInterfaceThread *ui = new UserInterfaceThread(*this); SerialInterfaceThread *si = new SerialInterfaceThread(*this); ui->WaitForTermination(); serial.Close(); si->WaitForTermination(); delete ui; delete si; cout << endl << "End of program" << endl << endl; } void Serial::HandleSerialInput() { #define MAXM 1000 char buffer[MAXM]; PString str; BOOL found = FALSE; while(serial.IsOpen()) { memset(buffer, 0, MAXM); serial.Read(buffer, MAXM); if (endNow) { PTRACE(3, "End of thread to handle serial input"); return; } PINDEX len = serial.GetLastReadCount(); if (len != 0) { buffer[len] = 0; PTRACE(1, "Read the string \"" << buffer << "\" from the serial port"); str += PString(buffer); if (str.Find("\n") != P_MAX_INDEX) found = TRUE; } PINDEX err = serial.GetErrorCode(); if ((err != PChannel::NoError) && (err != PChannel::Timeout)) { PTRACE(1, "get data from serial port, failed, error is " << serial.GetErrorText()); cout << "get data from serial port, failed, error is " << serial.GetErrorText() << endl; } if (found) { str.Replace("\n", ""); PTRACE(1, "Read the message \"" << str << "\""); cout << "have read the message \"" << str << "\" from the serial port" << endl; str = ""; found = FALSE; } } } BOOL Serial::Initialise(PConfigArgs & args) { if (!args.HasOption("baud")) { baud = 4800; cout << "Baud not specifed. Using 4800" << endl; } else { baud = args.GetOptionString("baud").AsInteger(); cout << "Baud specified. Using " << baud << endl; } if (!args.HasOption("databits")) { cout << "databits not specified. Using 8" << endl; dataBits = 1; } else { dataBits = args.GetOptionString("databits").AsInteger(); cout << "databits specified. Using " << dataBits << endl; } if (!args.HasOption("parity")) { cout << "parity not specified. Using \"odd\"" << endl; parity = "odd"; } else { parity = args.GetOptionString("parity"); cout << "parity specified Using \"" << parity << "\"" << endl; } if (!args.HasOption("stopbits")) { cout << "stopbits not specified. Using 1" << endl; stopBits = 1; } else { stopBits = args.GetOptionString("stopbits").AsInteger(); cout << "stopbits specified. Using " << stopBits << endl; } PString flow; if (!args.HasOption("flowcontrol")) { cout << "Flow control not specified. Flow control set to XonXoff" << endl; flow = "XonXoff"; } else { flow = args.GetOptionString("flowcontrol"); cout << "Flow control is specified. Flow control is set to " << flow << endl; } if ((flow *= "xonxoff") || (flow *= "rtscts") || (flow *= "none")) flowControlString = flow; else { cout << "Valid args to flowcontrol are \"XonXoff\" or \"RtsCts\" or \"none\"" << endl; return FALSE; } if (!args.HasOption("hardwareport")) { cout << "Hardware port is not set. Using 0 - the first hardware port" << endl; hardwarePort = 0; } else hardwarePort = args.GetOptionString("hardwareport").AsInteger(); PStringList names = serial.GetPortNames(); PStringStream allNames; for(PINDEX i = 0; i < names.GetSize(); i++) allNames << names[i] << " "; PTRACE(1, "available serial ports are " << allNames); PString portName; if (hardwarePort >= names.GetSize()) { cout << "hardware port is too large, list is only " << names.GetSize() << " long" << endl; return FALSE; } portName = names[hardwarePort]; PSerialChannel::Parity pValue = PSerialChannel::DefaultParity; if (parity *= "none") pValue = PSerialChannel::NoParity; if (parity *= "even") pValue = PSerialChannel::EvenParity; if (parity *= "odd") pValue = PSerialChannel::OddParity; if (pValue == PSerialChannel::DefaultParity) { cout << "Parity value of " << parity << " could not be interpreted" << endl; return FALSE; } PSerialChannel::FlowControl flowControl = PSerialChannel::DefaultFlowControl; if (flowControlString *= "xonxoff"){ flowControl = PSerialChannel::XonXoff; PTRACE(3, "Using xonxoff flow control"); } if (flowControlString *= "rtscts") { flowControl = PSerialChannel::RtsCts; PTRACE(3, "Using rts cts flow conrol "); } if (flowControlString *= "none") { flowControl = PSerialChannel::NoFlowControl; PTRACE(3, "Not using any flow control of any sort"); } if (!serial.Open(portName, baud, dataBits, pValue, stopBits, flowControl, flowControl)) { cout << "Failed to open serial port " << endl; cout << "Error code is " << serial.GetErrorText() << endl; cout << "Failed in attempt to open port /dev/" << portName << endl; return FALSE; } return TRUE; } void Serial::HandleConsoleInput() { PTRACE(2, "Serial\tUser interface thread started."); PStringStream help; help << "Select:\n"; help << " ? : display this help\n"; help << " H : display this help\n"; help << " X : Exit program\n"; help << " Q : Exit program\n"; help << " : anything else to send a message\n"; PError << " " << endl << help << endl; for (;;) { // display the prompt PError << "Command ? " << flush; char oneLine[200]; fgets(oneLine, 200, stdin); PString str(oneLine); if (str.GetLength() < 1) continue; BOOL helped = FALSE; if (str.GetLength() == 2) { char ch = str.ToLower()[0]; if ((ch == '?') || (ch == 'h')) { helped = TRUE; PError << help << endl; } if ((ch == 'x') || (ch == 'q')) { PTRACE(3, "\nEnd of thread to read from keyboard "); endNow = TRUE; return; } } if (!helped) { PTRACE(1, "Serial\t Write the message\"" << str << "\" to the serial port"); serial.Write(str.GetPointer(), str.GetLength()); continue; } } } // End of serial.cxx