diff --git a/10.02_devices/2_src/dl11w.cpp b/10.02_devices/2_src/dl11w.cpp index db2a40d..8b5ab16 100644 --- a/10.02_devices/2_src/dl11w.cpp +++ b/10.02_devices/2_src/dl11w.cpp @@ -33,26 +33,25 @@ #include #include #include +#include #include #include #include #include +#include "utils.hpp" +#include "gpios.hpp" #include "unibusadapter.hpp" #include "unibusdevice.hpp" // definition of class device_c #include "unibus.h" #include "dl11w.hpp" -#include "gpios.hpp" #include "rs232.hpp" -char buffer[BUFLEN + 1]; - //------------------------------------------------- -slu_c::slu_c() : - unibusdevice_c() // super class constructor -{ +slu_c::slu_c() : unibusdevice_c() { + set_workers_count(2); // receiver and transmitte have own threads //ip_host.value = IP_HOST; // not used //ip_port.value = IP_PORT; // not used @@ -62,7 +61,8 @@ slu_c::slu_c() : type_name.value = "slu_c"; log_label = "slu"; - set_default_bus_params(SLU_ADDR, SLU_VECTOR + 4, SLU_LEVEL); // base addr, intr-vector, intr level + // SLU has 2 Interrupt vectors: base = RCV, base+= XMT + set_default_bus_params(SLU_ADDR, SLU_VECTOR, SLU_LEVEL); // base addr, intr-vector, intr level // init parameters @@ -71,33 +71,34 @@ slu_c::slu_c() : reg_rcsr = &(this->registers[slu_idx_rcsr]); // @ base addr strcpy(reg_rcsr->name, "RCSR"); // Receiver Status Register - reg_rcsr->active_on_dati = true; + reg_rcsr->active_on_dati = false; reg_rcsr->active_on_dato = true; - reg_rcsr->reset_value = 0 & ! RCSR_RCVR_DONE; + reg_rcsr->reset_value = 0; reg_rcsr->writable_bits = 0xff; reg_rbuf = &(this->registers[slu_idx_rbuf]); // @ base addr strcpy(reg_rbuf->name, "RBUF"); // Receiver Buffer Register - reg_rbuf->active_on_dati = true; // no controller state change - reg_rbuf->active_on_dato = true; + reg_rbuf->active_on_dati = true; + reg_rbuf->active_on_dato = true; // required for "active on dati"" reg_rbuf->reset_value = 0; - reg_rbuf->writable_bits = 0xff; + reg_rbuf->writable_bits = 0x00; reg_xcsr = &(this->registers[slu_idx_xcsr]); // @ base addr strcpy(reg_xcsr->name, "XCSR"); // Transmitter Status Register - reg_xcsr->active_on_dati = true; + reg_xcsr->active_on_dati = false; reg_xcsr->active_on_dato = true; reg_xcsr->reset_value = XCSR_XMIT_RDY; // set reg_xcsr->writable_bits = 0xff; reg_xbuf = &(this->registers[slu_idx_xbuf]); // @ base addr strcpy(reg_xbuf->name, "XBUF"); //Transmitter Buffer Register - reg_xbuf->active_on_dati = true; // no controller state change + reg_xbuf->active_on_dati = false; // no controller state change reg_xbuf->active_on_dato = true; reg_xbuf->reset_value = 0; reg_xbuf->writable_bits = 0xff; // initialize serial format + serialport.value = "ttyS2"; // labeled "UART2" on PCB baudrate.value = 9600; mode.value = "8N1"; } @@ -107,24 +108,30 @@ slu_c::~slu_c() { bool slu_c::on_param_changed(parameter_c *param) { if (param == &enabled) { - cport_nr = 2; /* UART2 */ if (enabled.new_value) { - // enable SLU: setup COM port - if (RS232_OpenComport(cport_nr, baudrate.value, mode.value.c_str())) { - ERROR("Can not open comport"); + // enable SLU: setup COM serial port + // setup for BREAK and parity evaluation + if (rs232.OpenComport(serialport.value.c_str(), baudrate.value, mode.value.c_str(), + true)) { + ERROR("Can not open serial port %s", serialport.value.c_str()); return false; // reject "enable" } - // lock serial format settings + + // lock serial port and settings + serialport.readonly = true; baudrate.readonly = true; mode.readonly = true; - RS232_cputs(cport_nr, "Comport opened\n\r"); + INFO("Serial port %s opened", serialport.value.c_str()); + rs232.cputs("Serial port opened\n\r"); } else { // disable SLU - RS232_CloseComport(cport_nr); - // lock serial format settings + rs232.CloseComport(); + // unlock serial port and settings + serialport.readonly = false; baudrate.readonly = false; mode.readonly = false; + INFO("Serial port %s closed", serialport.value.c_str()); } } return unibusdevice_c::on_param_changed(param); // more actions (for enable) @@ -132,54 +139,68 @@ bool slu_c::on_param_changed(parameter_c *param) { //-------------------------------------------- -// background worker. -void slu_c::worker(void) { - timeout_c timeout; - char mychar; - int i, n; - - while (!worker_terminate) { - timeout.wait_ms(SLU_MSRATE_MS); - - /* read character from socket */ - if (!(RCSR_RCVR_DONE & rcsr.value)) { - bzero(buffer, BUFLEN); -#if 1 - if (slu_maint.value) { - n = 1; - buffer[0] = rbuf.value; - buffer[1] = 0; - } else -#endif - { - /* read serial data, if any */ - n = RS232_PollComport(cport_nr, (unsigned char*) buffer, 1); - } - for (i = 0; i < n; i++) { - mychar = buffer[i]; - // transmit chr to bus - rbuf.value = mychar; - set_register_dati_value(reg_rbuf, rbuf.value, __func__); - - // signal data on bus ready to read - rcsr.value |= RCSR_RCVR_DONE; - set_register_dati_value(reg_rcsr, rcsr.value, __func__); - } - } - - // transfer received character to socket - if (!(XCSR_XMIT_RDY & xcsr.value)) { - buffer[0] = get_register_dato_value(reg_xbuf); - RS232_SendByte(cport_nr, buffer[0]); - - // signal data written - xcsr.value |= XCSR_XMIT_RDY; - set_register_dati_value(reg_xcsr, xcsr.value, __func__); - } - - } +// Update RCSR +void slu_c::set_rcsr_dati_value(void) { + uint16_t val = (rcv_active ? RCSR_RCVR_ACT : 0) | (rcv_done ? RCSR_RCVR_DONE : 0) + | (rcv_intr_enable ? RCSR_RCVR_INT_ENB : 0); + set_register_dati_value(reg_rcsr, val, __func__); } +// PDP-11 writes into RCSR +void slu_c::eval_rcsr_dato_value(void) { + uint16_t val = get_register_dato_value(reg_rcsr); + bool old_rdr_enab = rcv_rdr_enb; + bool old_intr = rcv_done && rcv_intr_enable; + + rcv_intr_enable = val & RCSR_RCVR_INT_ENB ? 1 : 0; + rcv_rdr_enb = val & RCSR_RDR_ENB ? 1 : 0; + if (!old_rdr_enab && rcv_rdr_enb) + rcv_done = 0; // raising edge clears rcv_done + // if rcvr_done and int enable goes high: INTR + bool new_intr = rcv_done && rcv_intr_enable; + if (!old_intr && new_intr) // raising edge + interrupt(intr_vector.value, intr_level.value); +} + +// Update RBUF, readonly +void slu_c::set_rbuf_dati_value(void) { + uint16_t val = (rcv_or_err ? RBUF_OR_ERR : 0) | (rcv_fr_err ? RBUF_FR_ERR : 0) + | (rcv_p_err ? RBUF_P_ERR : 0); + if (val) // set general error flag + val |= RBUF_ERROR; + val |= rcv_buffer; // received char in bits 7..0 + set_register_dati_value(reg_rbuf, val, __func__); +} + +// Update Transmit Status Register XCSR +void slu_c::set_xcsr_dati_value(void) { + uint16_t val = (xmt_ready ? XCSR_XMIT_RDY : 0) | (xmt_intr_enable ? XCSR_XMIT_INT_ENB : 0) + | (xmt_maint ? XCSR_MAINT : 0) | (xmt_break ? XCSR_BREAK : 0); + set_register_dati_value(reg_xcsr, val, __func__); +} + +void slu_c::eval_xcsr_dato_value(void) { + uint16_t val = get_register_dato_value(reg_xcsr); + bool old_intr = xmt_ready && xmt_intr_enable; + bool old_break = xmt_break; + + xmt_intr_enable = val & XCSR_XMIT_INT_ENB ? 1 : 0; + xmt_maint = val & XCSR_MAINT ? 1 : 0; + xmt_break = val & XCSR_BREAK ? 1 : 0; + // if xmt_ready and int enable goes high: INTR + bool new_intr = xmt_ready && xmt_intr_enable; + if (!old_intr && new_intr) // raising edge + interrupt(intr_vector.value + 4, intr_level.value); + if (old_break != xmt_break) + rs232.SetBreak(xmt_break); +} + +void slu_c::eval_xbuf_dato_value(void) { + // transmit data buffer contains only the character in bits 7..0 + xmt_buffer = get_register_dato_value(reg_xbuf) & 0xff; +} + + // process DATI/DATO access to one of my "active" registers // !! called asynchronuously by PRU, with SSYN asserted and blocking UNIBUS. // The time between PRU event and program flow into this callback @@ -190,45 +211,47 @@ void slu_c::worker(void) { void slu_c::on_after_register_access(unibusdevice_register_t *device_reg, uint8_t unibus_control) { - if (unibus_control == UNIBUS_CONTROL_DATO) // bus write - set_register_dati_value(device_reg, device_reg->active_dato_flipflops, __func__); +// if (unibus_control == UNIBUS_CONTROL_DATO) // bus write +// set_register_dati_value(device_reg, device_reg->active_dato_flipflops, __func__); switch (device_reg->index) { case slu_idx_rcsr: - if (unibus_control == UNIBUS_CONTROL_DATO) { // bus write - rcvr_interrupt_enable.value = !!(reg_rcsr->active_dato_flipflops - & (RCSR_RCVR_INT_ENB)); - rdr_enable.value = !!(reg_rcsr->active_dato_flipflops & (RCSR_RDR_ENB)); + if (unibus_control == UNIBUS_CONTROL_DATO) { // bus write into RCSR + pthread_mutex_lock(&on_after_rcv_register_access_mutex); // signal changes atomic against UNIBUS accesses + eval_rcsr_dato_value(); // may generate INTR + set_rcsr_dati_value(); + // ignore reader enable + pthread_mutex_unlock(&on_after_rcv_register_access_mutex); } break; - - case slu_idx_xbuf: - if (unibus_control == UNIBUS_CONTROL_DATO) { // bus write - // signal data has been written to bus - xcsr.value &= ~ XCSR_XMIT_RDY; - set_register_dati_value(reg_xcsr, xcsr.value, __func__); - // get value from bus write and put it into rx buffer - xbuf.value = reg_xbuf->active_dato_flipflops; - } + case slu_idx_rbuf: { // DATI/DATO: is read only, but write also clears "rcvr_done" + // signal data has been read from bus + pthread_mutex_lock(&on_after_rcv_register_access_mutex); + rcv_done = 0; + set_rcsr_dati_value(); + pthread_mutex_unlock(&on_after_rcv_register_access_mutex); + } break; - case slu_idx_xcsr: if (unibus_control == UNIBUS_CONTROL_DATO) { // bus write - xmit_interrupt_enable.value = !!(reg_xcsr->active_dato_flipflops - & (XCSR_XMIT_INT_ENB)); - slu_maint.value = !!(reg_xcsr->active_dato_flipflops & (XCSR_MAINT)); + pthread_mutex_lock(&on_after_xmt_register_access_mutex); + eval_xcsr_dato_value(); // may trigger INTR + set_xcsr_dati_value(); + pthread_mutex_unlock(&on_after_xmt_register_access_mutex); } break; - - case slu_idx_rbuf: - if (unibus_control == UNIBUS_CONTROL_DATI) { // bus read - // signal data has been read from bus - rcsr.value &= ~ RCSR_RCVR_DONE; - set_register_dati_value(reg_rcsr, rcsr.value, __func__); + case slu_idx_xbuf: + if (unibus_control == UNIBUS_CONTROL_DATO) { // bus write into XBUF + pthread_mutex_lock(&on_after_xmt_register_access_mutex); + eval_xbuf_dato_value(); + xmt_ready = 0; // signal worker: xmt_data pending + set_xcsr_dati_value(); + // on_after_register_access_cond used for xmt worker + pthread_cond_signal(&on_after_xmt_register_access_cond); + pthread_mutex_unlock(&on_after_xmt_register_access_mutex); } break; - default: break; } @@ -245,10 +268,119 @@ void slu_c::on_init_changed(void) { // write all registers to "reset-values" if (init_asserted) { reset_unibus_registers(); + rcv_active = 0; + rcv_done = 0; + rcv_intr_enable = 0; + rcv_or_err = 0; + rcv_fr_err = 0; + rcv_p_err = 0; + rcv_buffer = 0; + xmt_ready = 1; + xmt_intr_enable = 0; + xmt_maint = 0; + xmt_break = 0; INFO("slu_c::on_init()"); } } +// background worker. +void slu_c::worker_rcv(void) { + timeout_c timeout; + int n; + char buffer[BUFLEN + 1]; + + // 1. poll with frequency > baudrate, to see single bits + unsigned poll_periods_us = 1000000 / baudrate.value; + + while (!workers_terminate) { + timeout.wait_us(poll_periods_us); + // "query + // rcv_active: can only be set by polling the UART inpit GPIiO pin? + // at the moments, it is onyl sen on maintenance loopback xmt + /* read serial data, if any */ + if (rs232.PollComport((unsigned char*) buffer, 1)) { + pthread_mutex_lock(&on_after_rcv_register_access_mutex); // signal changes atomic against UNIBUS accesses + rcv_or_err = rcv_fr_err = rcv_p_err = 0; + if (rcv_done) // not yet cleared? overrun! + rcv_or_err = 1; + if (buffer[0] == 0xff) { + /* How to receive framing and parity errors: see termios(3) + If IGNPAR=0, PARMRK=1: error on received as \377 \0 + \377 received as \377 \377 + */ + n = rs232.PollComport((unsigned char*) buffer, 1); + assert(n); // next char after 0xff escape immediately available + + if (buffer[0] == 0) { // error flags + rcv_fr_err = rcv_p_err = 1; + n = rs232.PollComport((unsigned char*) buffer, 1); + assert(n); // next char after 0xff 0 seq is data" + rcv_buffer = buffer[0]; + rcv_done = 1; + } else if (buffer[0] == 0xff) { // enocoded 0xff + rcv_buffer = 0xff; + } else { + WARNING("Received 0xff seqeuence"); + rcv_buffer = buffer[0]; + } + } else + // received non escaped data byte + rcv_buffer = buffer[0]; + rcv_done = 1; + set_rbuf_dati_value(); + set_rcsr_dati_value(); // INTR! + pthread_mutex_unlock(&on_after_rcv_register_access_mutex); // signal changes atomic against UNIBUS accesses + } + } +} + +void slu_c::worker_xmt(void) { + timeout_c timeout; + assert(!pthread_mutex_lock(&on_after_register_access_mutex)); + while (!workers_terminate) { + // 1. wait for xmt signal + int res = pthread_cond_wait(&on_after_xmt_register_access_cond, &on_after_xmt_register_access_mutex); + // on_after_xmt_register_access_mutex remains locked all the time + if (res != 0) { + ERROR("SLU::worker_xmt() pthread_cond_wait = %d = %s>", res, strerror(res)); + continue; + } + + // 2. transmit + rs232.SendByte(xmt_buffer); + xmt_ready = 0; + set_xcsr_dati_value(); + if (xmt_maint) { // loop back: simulate data byte coming in + pthread_mutex_lock(&on_after_rcv_register_access_mutex); + rcv_active = 1; + set_rcsr_dati_value(); + pthread_mutex_unlock(&on_after_rcv_register_access_mutex); + } + + // 3. wait for data byte being shifted out + pthread_mutex_unlock(&on_after_xmt_register_access_mutex); + timeout.wait_us(rs232.TransmissionTime_us); + pthread_mutex_lock(&on_after_xmt_register_access_mutex); + if (xmt_maint) + // put sent byte into rcv buffer, receiver will poll it + rs232.LoopbackByte(xmt_buffer); + xmt_ready = 1; + set_rcsr_dati_value(); // generates interrupt + set_xcsr_dati_value(); + // has rcv or xmt interrupt priority on maintennace loop back + } + assert(!pthread_mutex_unlock(&on_after_xmt_register_access_mutex)); +} + +void slu_c::worker(unsigned instance) { + // 2 parallel worker() instances: 0 and 1 + if (instance == 0) + worker_rcv(); + else + worker_xmt(); + +} + //-------------------------------------------------------------------------------------------------- ltc_c::ltc_c() : @@ -285,9 +417,10 @@ bool ltc_c::on_param_changed(parameter_c *param) { } // background worker. -void ltc_c::worker(void) { +void ltc_c::worker(unsigned instance) { + UNUSED(instance); // only one timeout_c timeout; - while (!worker_terminate) { + while (!workers_terminate) { if (ltc_input.value) { //should really wait for LTC input trailing edge here timeout.wait_ms(10000); @@ -323,13 +456,7 @@ void ltc_c::on_after_register_access(unibusdevice_register_t *device_reg, if (unibus_control == UNIBUS_CONTROL_DATO) { // bus write lks.value = reg_lks->active_dato_flipflops; ltc_interrupt_enable.value = !!(reg_lks->active_dato_flipflops & (LKS_INT_ENB)); -#if 0 - if (reg_lks->active_dato_flipflops && 1) - { - interrupt(); - //DEBUG("Interrupt!"); - } -#endif + interrupt(intr_vector.value, intr_level.value); } break; diff --git a/10.02_devices/2_src/dl11w.hpp b/10.02_devices/2_src/dl11w.hpp index d5918a0..42cd0ff 100644 --- a/10.02_devices/2_src/dl11w.hpp +++ b/10.02_devices/2_src/dl11w.hpp @@ -34,6 +34,7 @@ using namespace std; #include "utils.hpp" #include "unibusdevice.hpp" #include "parameter.hpp" +#include "rs232.hpp" // socket console settings //#define IP_PORT 5001 @@ -44,7 +45,7 @@ using namespace std; #if DL11A // console (teletype keyboard & printer) #define SLU_ADDR 0777560 #define SLU_LEVEL 04 -#define SLU_VECTOR 060 +#define SLU_VECTOR 060 // RCV +0, XMT +4 #elif DL11B // paper tape punch and reader #define SLU_ADDR 0777550 #define SLU_LEVEL 04 @@ -98,25 +99,64 @@ enum ltc_reg_index { // ------------------------------------------ SLU ----------------------------- class slu_c: public unibusdevice_c { private: - int cport_nr; // COM port handle for RS232 library + rs232_c rs232; /// COM port interface unibusdevice_register_t *reg_rcsr; unibusdevice_register_t *reg_rbuf; unibusdevice_register_t *reg_xcsr; unibusdevice_register_t *reg_xbuf; + /*** SLU is infact 2 independend devices: RCV and XMT ***/ + pthread_cond_t on_after_rcv_register_access_cond = PTHREAD_COND_INITIALIZER; + pthread_mutex_t on_after_rcv_register_access_mutex = PTHREAD_MUTEX_INITIALIZER; + + // bits in registers + bool rcv_active; /// while a char is receive ... not available + bool rcv_done; // char received. INTR. cleared by rdr_enable, access to rbuf, init + bool rcv_overrun;bool rcv_intr_enable; // receiver interrupt enabled + bool rcv_or_err; // receiver overrun: rcv_done 1 on receive + bool rcv_fr_err; // framing error. high on received BREAK + bool rcv_p_err; // parity error + uint8_t rcv_buffer;bool rcv_rdr_enb; // reader enable. Cleared by receive or init + + pthread_cond_t on_after_xmt_register_access_cond = PTHREAD_COND_INITIALIZER; + pthread_mutex_t on_after_xmt_register_access_mutex = PTHREAD_MUTEX_INITIALIZER; + bool xmt_ready;// transmitter ready. INTR, cleared on XBUF access + bool xmt_intr_enable; // receiver interrupt enabled + + bool xmt_maint; // set 1 for local loop back + bool xmt_break; // transmit continuous break + uint8_t xmt_buffer; + + // convert between register ansd state variables + void set_rcsr_dati_value(void); + void eval_rcsr_dato_value(void); + void set_rbuf_dati_value(void); + void set_xcsr_dati_value(void); + void eval_xcsr_dato_value(void); + void eval_xbuf_dato_value(void); + public: slu_c(); ~slu_c(); //parameter_string_c ip_host = parameter_string_c( this, "SLU socket IP host", "host", /*readonly*/ false, "ip hostname"); - //parameter_unsigned_c ip_port = parameter_unsigned_c(this, "SLU socket IP port", "port", /*readonly*/ false, "", "%d", "ip port", 32, 10); + //parameter_unsigned_c ip_port = parameter_unsigned_c(this, "SLU socket IP serialport", "serialport", /*readonly*/ false, "", "%d", "ip serialport", 32, 10); + parameter_string_c serialport = parameter_string_c(this, "serialport", "p", /*readonly*/ + false, "Linux serial port: \"ttyS1\" or \"ttyS2\""); + parameter_unsigned_c baudrate = parameter_unsigned_c(this, "baudrate", "b", /*readonly*/ - false, "", "%d", "Baudrate: 110, 300, ... 115200", 115200, 10); + false, "", "%d", "Baudrate: 110, 300, ... 38400", 38400, 10); + // 40kbaud -> 25us bit polling period needed + parameter_string_c mode = parameter_string_c(this, "mode", "m", /*readonly*/false, "Mode: 8N1, 7E1, ... "); + parameter_bool_c break_enable = parameter_bool_c(this, "break", "b", /*readonly*/false, + "Enable BREAK transmission"); + +#ifdef USED // @David: duplicating device registers as parameters is not necessary ... // they can be seen with "exam" anyhow. parameter_unsigned_c rcsr = parameter_unsigned_c(this, "Receiver Status Register", "rcsr", /*readonly*/ @@ -136,9 +176,11 @@ public: false, "1 = enable Maintenance mode enabled"); parameter_bool_c rdr_enable = parameter_bool_c(this, "RDR enable", "rdre",/*readonly*/false, "1 = enable reader enable"); - +#endif // background worker function - void worker(void) override; + void worker(unsigned instance) override; + void worker_rcv(void); + void worker_xmt(void); // called by unibusadapter on emulated register access void on_after_register_access(unibusdevice_register_t *device_reg, uint8_t unibus_control) @@ -161,16 +203,16 @@ public: ~ltc_c(); parameter_unsigned_c lks = parameter_unsigned_c(this, "Line Clock Status Register", "lks", /*readonly*/ - false, "", "%o", "Internal state", 32, 8); + false, "", "%o", "Internal state", 32, 8); parameter_bool_c lke = parameter_bool_c(this, "LKS timer enable", "lke",/*readonly*/false, "1 = enable update of LKS_IMON by timer"); parameter_bool_c ltc_input = parameter_bool_c(this, "LTC input enable", "ltc",/*readonly*/ - false, "1 = enable update of LKS_IMON by LTC Input"); + false, "1 = enable update of LKS_IMON by LTC Input"); parameter_bool_c ltc_interrupt_enable = parameter_bool_c(this, "LTC interrupt enable", "lie",/*readonly*/false, "1 = enable interrupt"); // background worker function - void worker(void) override; + void worker(unsigned instance) override; // called by unibusadapter on emulated register access void on_after_register_access(unibusdevice_register_t *device_reg, uint8_t unibus_control) diff --git a/10.02_devices/2_src/rs232.cpp b/10.02_devices/2_src/rs232.cpp index 20bb5f6..2d5c71b 100644 --- a/10.02_devices/2_src/rs232.cpp +++ b/10.02_devices/2_src/rs232.cpp @@ -1,823 +1,498 @@ /* -*************************************************************************** -* -* Author: Teunis van Beelen -* -* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Teunis van Beelen -* -* Email: teuniz@gmail.com -* -*************************************************************************** -* -* 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 3 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 General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -* -*************************************************************************** -*/ - + *************************************************************************** + * + * Author: Teunis van Beelen + * + * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Teunis van Beelen + * + * Email: teuniz@gmail.com + * + *************************************************************************** + * + * 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 3 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + *************************************************************************** + */ +/* 2019, June: made C++, Joerg Hoppe */ /* Last revision: November 22, 2017 */ /* For more info and how to use this library, visit: http://www.teuniz.net/RS-232/ */ - #include "rs232.hpp" +rs232_c::rs232_c() { + TransmissionTime_us = 0; +} -#if defined(__linux__) || defined(__FreeBSD__) /* Linux & FreeBSD */ - -#define RS232_PORTNR 38 - - -int Cport[RS232_PORTNR], - error; - -struct termios new_port_settings, - old_port_settings[RS232_PORTNR]; - -const char *comports[RS232_PORTNR]={ -// "/dev/ttyO0","/dev/ttyO1","/dev/ttyO2","/dev/ttyO3","/dev/ttyO4","/dev/ttyO5", - "/dev/ttyS0","/dev/ttyS1","/dev/ttyS2","/dev/ttyS3","/dev/ttyS4","/dev/ttyS5", - "/dev/ttyS6","/dev/ttyS7","/dev/ttyS8","/dev/ttyS9","/dev/ttyS10","/dev/ttyS11", - "/dev/ttyS12","/dev/ttyS13","/dev/ttyS14","/dev/ttyS15","/dev/ttyUSB0", - "/dev/ttyUSB1","/dev/ttyUSB2","/dev/ttyUSB3","/dev/ttyUSB4","/dev/ttyUSB5", - "/dev/ttyAMA0","/dev/ttyAMA1","/dev/ttyACM0","/dev/ttyACM1", - "/dev/rfcomm0","/dev/rfcomm1","/dev/ircomm0","/dev/ircomm1", - "/dev/cuau0","/dev/cuau1","/dev/cuau2","/dev/cuau3", - "/dev/cuaU0","/dev/cuaU1","/dev/cuaU2","/dev/cuaU3"}; - +// devname without leading "/dev/" // returns 0 on success, else error -int RS232_OpenComport(int comport_number, int baudrate, const char *mode) -{ - int baudr, - status; +int rs232_c::OpenComport(const char *devname, int baudrate, const char *mode, + bool par_and_break) { + char full_devname[256]; - if((comport_number>=RS232_PORTNR)||(comport_number<0)) - { - printf("illegal comport number\n"); - return(1); - } + int baudr; + int status; - switch(baudrate) - { - case 50 : baudr = B50; - break; - case 75 : baudr = B75; - break; - case 110 : baudr = B110; - break; - case 134 : baudr = B134; - break; - case 150 : baudr = B150; - break; - case 200 : baudr = B200; - break; - case 300 : baudr = B300; - break; - case 600 : baudr = B600; - break; - case 1200 : baudr = B1200; - break; - case 1800 : baudr = B1800; - break; - case 2400 : baudr = B2400; - break; - case 4800 : baudr = B4800; - break; - case 9600 : baudr = B9600; - break; - case 19200 : baudr = B19200; - break; - case 38400 : baudr = B38400; - break; - case 57600 : baudr = B57600; - break; - case 115200 : baudr = B115200; - break; - case 230400 : baudr = B230400; - break; - case 460800 : baudr = B460800; - break; - case 500000 : baudr = B500000; - break; - case 576000 : baudr = B576000; - break; - case 921600 : baudr = B921600; - break; - case 1000000 : baudr = B1000000; - break; - case 1152000 : baudr = B1152000; - break; - case 1500000 : baudr = B1500000; - break; - case 2000000 : baudr = B2000000; - break; - case 2500000 : baudr = B2500000; - break; - case 3000000 : baudr = B3000000; - break; - case 3500000 : baudr = B3500000; - break; - case 4000000 : baudr = B4000000; - break; - default : printf("invalid baudrate\n"); - return(1); - break; - } + strcpy(full_devname, "/dev/"); + strncat(full_devname, devname, 255); + full_devname[255] = 0; - int cbits=CS8, - cpar=0, - ipar=IGNPAR, - bstop=0; + switch (baudrate) { + case 50: + baudr = B50; + break; + case 75: + baudr = B75; + break; + case 110: + baudr = B110; + break; + case 134: + baudr = B134; + break; + case 150: + baudr = B150; + break; + case 200: + baudr = B200; + break; + case 300: + baudr = B300; + break; + case 600: + baudr = B600; + break; + case 1200: + baudr = B1200; + break; + case 1800: + baudr = B1800; + break; + case 2400: + baudr = B2400; + break; + case 4800: + baudr = B4800; + break; + case 9600: + baudr = B9600; + break; + case 19200: + baudr = B19200; + break; + case 38400: + baudr = B38400; + break; + case 57600: + baudr = B57600; + break; + case 115200: + baudr = B115200; + break; + case 230400: + baudr = B230400; + break; + case 460800: + baudr = B460800; + break; + case 500000: + baudr = B500000; + break; + case 576000: + baudr = B576000; + break; + case 921600: + baudr = B921600; + break; + case 1000000: + baudr = B1000000; + break; + case 1152000: + baudr = B1152000; + break; + case 1500000: + baudr = B1500000; + break; + case 2000000: + baudr = B2000000; + break; + case 2500000: + baudr = B2500000; + break; + case 3000000: + baudr = B3000000; + break; + case 3500000: + baudr = B3500000; + break; + case 4000000: + baudr = B4000000; + break; + default: + printf("invalid baudrate\n"); + return (1); + break; + } - if(strlen(mode) != 3) - { - printf("invalid mode \"%s\"\n", mode); - return(1); - } + int cbits = CS8; + int cpar = 0; + int ipar = IGNPAR; + int bstop = 0; - switch(mode[0]) - { - case '8': cbits = CS8; - break; - case '7': cbits = CS7; - break; - case '6': cbits = CS6; - break; - case '5': cbits = CS5; - break; - default : printf("invalid number of data-bits '%c'\n", mode[0]); - return(1); - break; - } + if (strlen(mode) != 3) { + printf("invalid mode \"%s\"\n", mode); + return (1); + } + unsigned bitcount = 1; // start bit + switch (mode[0]) { + case '8': + cbits = CS8; + bitcount += 8; + break; + case '7': + cbits = CS7; + bitcount += 7; + break; + case '6': + cbits = CS6; + bitcount += 6; + break; + case '5': + cbits = CS5; + bitcount += 5; + break; + default: + printf("invalid number of data-bits '%c'\n", mode[0]); + return (1); + break; + } - switch(mode[1]) - { - case 'N': - case 'n': cpar = 0; - ipar = IGNPAR; - break; - case 'E': - case 'e': cpar = PARENB; - ipar = INPCK; - break; - case 'O': - case 'o': cpar = (PARENB | PARODD); - ipar = INPCK; - break; - default : printf("invalid parity '%c'\n", mode[1]); - return(1); - break; - } + switch (mode[1]) { + case 'N': + case 'n': + cpar = 0; + ipar = IGNPAR; + break; + case 'E': + case 'e': + cpar = PARENB; + ipar = INPCK; + bitcount += 1; + break; + case 'O': + case 'o': + cpar = (PARENB | PARODD); + ipar = INPCK; + bitcount += 1; + break; + default: + printf("invalid parity '%c'\n", mode[1]); + return (1); + break; + } - switch(mode[2]) - { - case '1': bstop = 0; - break; - case '2': bstop = CSTOPB; - break; - default : printf("invalid number of stop bits '%c'\n", mode[2]); - return(1); - break; - } + switch (mode[2]) { + case '1': + bstop = 0; + bitcount += 1; + break; + case '2': + bstop = CSTOPB; + bitcount += 2; + break; + default: + printf("invalid number of stop bits '%c'\n", mode[2]); + return (1); + break; + } + // bit count is 10 for 8N1 + // Calc time to transmit on character + TransmissionTime_us = (1000000 * bitcount) / baudrate; -/* -http://pubs.opengroup.org/onlinepubs/7908799/xsh/termios.h.html + /* scan for BREAK and frame/parity errors? + To read BREAK not as \0: + PARMRK=1 and parity checking -> BREAK violates frame pattern -> is recieved as \377 \0 \0 + */ + int iflag; + if (par_and_break) + iflag = IGNBRK | PARMRK | INPCK; + else + iflag = ipar; -http://man7.org/linux/man-pages/man3/termios.3.html -*/ + /* + http://pubs.opengroup.org/onlinepubs/7908799/xsh/termios.h.html - Cport[comport_number] = open(comports[comport_number], O_RDWR | O_NOCTTY | O_NDELAY); - if(Cport[comport_number]==-1) - { - perror("unable to open comport "); - return(1); - } + http://man7.org/linux/man-pages/man3/termios.3.html + */ - /* lock access so that another process can't also use the port */ - if(flock(Cport[comport_number], LOCK_EX | LOCK_NB) != 0) - { - close(Cport[comport_number]); - perror("Another process has locked the comport."); - return(1); - } + Cport = open(full_devname, O_RDWR | O_NOCTTY | O_NDELAY); + if (Cport == -1) { + perror("unable to open comport "); + return (1); + } - error = tcgetattr(Cport[comport_number], old_port_settings + comport_number); - if(error==-1) - { - close(Cport[comport_number]); - flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */ - perror("unable to read portsettings "); - return(1); - } - memset(&new_port_settings, 0, sizeof(new_port_settings)); /* clear the new struct */ + /* lock access so that another process can't also use the port */ + if (flock(Cport, LOCK_EX | LOCK_NB) != 0) { + close(Cport); + perror("Another process has locked the comport."); + return (1); + } - new_port_settings.c_cflag = cbits | cpar | bstop | CLOCAL | CREAD; - new_port_settings.c_iflag = ipar; - new_port_settings.c_oflag = 0; - new_port_settings.c_lflag = 0; - new_port_settings.c_cc[VMIN] = 0; /* block untill n bytes are received */ - new_port_settings.c_cc[VTIME] = 0; /* block untill a timer expires (n * 100 mSec.) */ + error = tcgetattr(Cport, &old_port_settings); + if (error == -1) { + close(Cport); + flock(Cport, LOCK_UN); /* free the port so that others can use it. */ + perror("unable to read portsettings "); + return (1); + } + memset(&new_port_settings, 0, sizeof(new_port_settings)); /* clear the new struct */ - cfsetispeed(&new_port_settings, baudr); - cfsetospeed(&new_port_settings, baudr); + new_port_settings.c_cflag = cbits | cpar | bstop | CLOCAL | CREAD; + new_port_settings.c_iflag = iflag; + new_port_settings.c_oflag = 0; + new_port_settings.c_lflag = 0; + new_port_settings.c_cc[VMIN] = 0; /* block untill n bytes are received */ + new_port_settings.c_cc[VTIME] = 0; /* block untill a timer expires (n * 100 mSec.) */ - error = tcsetattr(Cport[comport_number], TCSANOW, &new_port_settings); - if(error==-1) - { - tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number); - close(Cport[comport_number]); - flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */ - perror("unable to adjust portsettings "); - return(1); - } + cfsetispeed(&new_port_settings, baudr); + cfsetospeed(&new_port_settings, baudr); -/* http://man7.org/linux/man-pages/man4/tty_ioctl.4.html */ + error = tcsetattr(Cport, TCSANOW, &new_port_settings); + if (error == -1) { + tcsetattr(Cport, TCSANOW, &old_port_settings); + close(Cport); + flock(Cport, LOCK_UN); /* free the port so that others can use it. */ + perror("unable to adjust portsettings "); + return (1); + } - if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1) - { - tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number); - flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */ - perror("unable to get portstatus"); - return(1); - } + /* http://man7.org/linux/man-pages/man4/tty_ioctl.4.html */ - status |= TIOCM_DTR; /* turn on DTR */ - status |= TIOCM_RTS; /* turn on RTS */ + if (ioctl(Cport, TIOCMGET, &status) == -1) { + tcsetattr(Cport, TCSANOW, &old_port_settings); + flock(Cport, LOCK_UN); /* free the port so that others can use it. */ + perror("unable to get portstatus"); + return (1); + } - if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1) - { - tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number); - flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */ - perror("unable to set portstatus"); - return(1); - } + status |= TIOCM_DTR; /* turn on DTR */ + status |= TIOCM_RTS; /* turn on RTS */ - return(0); + if (ioctl(Cport, TIOCMSET, &status) == -1) { + tcsetattr(Cport, TCSANOW, &old_port_settings); + flock(Cport, LOCK_UN); /* free the port so that others can use it. */ + perror("unable to set portstatus"); + return (1); + } + + return (0); } +int rs232_c::PollComport(unsigned char *buf, int size) { + int n; -int RS232_PollComport(int comport_number, unsigned char *buf, int size) -{ - int n; + n = read(Cport, buf, size); - n = read(Cport[comport_number], buf, size); + if (n < 0) { + if (errno == EAGAIN) + return 0; + } - if(n < 0) - { - if(errno == EAGAIN) return 0; - } - - return(n); + return (n); } - -int RS232_SendByte(int comport_number, unsigned char byte) -{ - int n = write(Cport[comport_number], &byte, 1); - if(n < 0) - { - if(errno == EAGAIN) - { - return 0; - } - else - { - return 1; - } - } - - return(0); +int rs232_c::SendByte(unsigned char byte) { + int n = write(Cport, &byte, 1); + if (n < 0) { + if (errno == EAGAIN) { + return 0; + } else { + return 1; + } + } + return (0); } +int rs232_c::SendBuf(unsigned char *buf, int size) { + int n = write(Cport, buf, size); + if (n < 0) { + if (errno == EAGAIN) { + return 0; + } else { + return -1; + } + } -int RS232_SendBuf(int comport_number, unsigned char *buf, int size) -{ - int n = write(Cport[comport_number], buf, size); - if(n < 0) - { - if(errno == EAGAIN) - { - return 0; - } - else - { - return -1; - } - } - - return(n); + return (n); } +// put byte in to rcv queue +void rs232_c::LoopbackByte(unsigned char byte) { + if (ioctl(Cport, TIOCSTI, byte) == -1) { + perror("unable to insert byte into input queue"); + } +} -void RS232_CloseComport(int comport_number) -{ - int status; +void rs232_c::SetBreak(int break_state) { + if (ioctl(Cport, break_state ? TIOCSBRK : TIOCCBRK) == -1) { + perror("unable to set break status"); + } +} - if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1) - { - perror("unable to get portstatus"); - } +void rs232_c::CloseComport(void) { + int status; + TransmissionTime_us = 0; - status &= ~TIOCM_DTR; /* turn off DTR */ - status &= ~TIOCM_RTS; /* turn off RTS */ + if (ioctl(Cport, TIOCMGET, &status) == -1) { + perror("unable to get portstatus"); + } - if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1) - { - perror("unable to set portstatus"); - } + status &= ~TIOCM_DTR; /* turn off DTR */ + status &= ~TIOCM_RTS; /* turn off RTS */ - tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number); - close(Cport[comport_number]); + if (ioctl(Cport, TIOCMSET, &status) == -1) { + perror("unable to set portstatus"); + } - flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */ + tcsetattr(Cport, TCSANOW, &old_port_settings); + close(Cport); + + flock(Cport, LOCK_UN); /* free the port so that others can use it. */ } /* -Constant Description -TIOCM_LE DSR (data set ready/line enable) -TIOCM_DTR DTR (data terminal ready) -TIOCM_RTS RTS (request to send) -TIOCM_ST Secondary TXD (transmit) -TIOCM_SR Secondary RXD (receive) -TIOCM_CTS CTS (clear to send) -TIOCM_CAR DCD (data carrier detect) -TIOCM_CD see TIOCM_CAR -TIOCM_RNG RNG (ring) -TIOCM_RI see TIOCM_RNG -TIOCM_DSR DSR (data set ready) + Constant Description + TIOCM_LE DSR (data set ready/line enable) + TIOCM_DTR DTR (data terminal ready) + TIOCM_RTS RTS (request to send) + TIOCM_ST Secondary TXD (transmit) + TIOCM_SR Secondary RXD (receive) + TIOCM_CTS CTS (clear to send) + TIOCM_CAR DCD (data carrier detect) + TIOCM_CD see TIOCM_CAR + TIOCM_RNG RNG (ring) + TIOCM_RI see TIOCM_RNG + TIOCM_DSR DSR (data set ready) -http://man7.org/linux/man-pages/man4/tty_ioctl.4.html -*/ + http://man7.org/linux/man-pages/man4/tty_ioctl.4.html + */ -int RS232_IsDCDEnabled(int comport_number) -{ - int status; +int rs232_c::IsDCDEnabled(void) { + int status; - ioctl(Cport[comport_number], TIOCMGET, &status); + ioctl(Cport, TIOCMGET, &status); - if(status&TIOCM_CAR) return(1); - else return(0); + if (status & TIOCM_CAR) + return (1); + else + return (0); } +int rs232_c::IsCTSEnabled(void) { + int status; -int RS232_IsCTSEnabled(int comport_number) -{ - int status; + ioctl(Cport, TIOCMGET, &status); - ioctl(Cport[comport_number], TIOCMGET, &status); - - if(status&TIOCM_CTS) return(1); - else return(0); + if (status & TIOCM_CTS) + return (1); + else + return (0); } +int rs232_c::IsDSREnabled(void) { + int status; -int RS232_IsDSREnabled(int comport_number) -{ - int status; + ioctl(Cport, TIOCMGET, &status); - ioctl(Cport[comport_number], TIOCMGET, &status); - - if(status&TIOCM_DSR) return(1); - else return(0); + if (status & TIOCM_DSR) + return (1); + else + return (0); } +void rs232_c::enableDTR(void) { + int status; -void RS232_enableDTR(int comport_number) -{ - int status; + if (ioctl(Cport, TIOCMGET, &status) == -1) { + perror("unable to get portstatus"); + } - if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1) - { - perror("unable to get portstatus"); - } + status |= TIOCM_DTR; /* turn on DTR */ - status |= TIOCM_DTR; /* turn on DTR */ - - if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1) - { - perror("unable to set portstatus"); - } + if (ioctl(Cport, TIOCMSET, &status) == -1) { + perror("unable to set portstatus"); + } } +void rs232_c::disableDTR(void) { + int status; -void RS232_disableDTR(int comport_number) -{ - int status; + if (ioctl(Cport, TIOCMGET, &status) == -1) { + perror("unable to get portstatus"); + } - if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1) - { - perror("unable to get portstatus"); - } + status &= ~TIOCM_DTR; /* turn off DTR */ - status &= ~TIOCM_DTR; /* turn off DTR */ - - if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1) - { - perror("unable to set portstatus"); - } + if (ioctl(Cport, TIOCMSET, &status) == -1) { + perror("unable to set portstatus"); + } } +void rs232_c::enableRTS(void) { + int status; -void RS232_enableRTS(int comport_number) -{ - int status; + if (ioctl(Cport, TIOCMGET, &status) == -1) { + perror("unable to get portstatus"); + } - if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1) - { - perror("unable to get portstatus"); - } + status |= TIOCM_RTS; /* turn on RTS */ - status |= TIOCM_RTS; /* turn on RTS */ - - if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1) - { - perror("unable to set portstatus"); - } + if (ioctl(Cport, TIOCMSET, &status) == -1) { + perror("unable to set portstatus"); + } } +void rs232_c::disableRTS(void) { + int status; -void RS232_disableRTS(int comport_number) -{ - int status; + if (ioctl(Cport, TIOCMGET, &status) == -1) { + perror("unable to get portstatus"); + } - if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1) - { - perror("unable to get portstatus"); - } + status &= ~TIOCM_RTS; /* turn off RTS */ - status &= ~TIOCM_RTS; /* turn off RTS */ - - if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1) - { - perror("unable to set portstatus"); - } + if (ioctl(Cport, TIOCMSET, &status) == -1) { + perror("unable to set portstatus"); + } } - -void RS232_flushRX(int comport_number) -{ - tcflush(Cport[comport_number], TCIFLUSH); +void rs232_c::flushRX(void) { + tcflush(Cport, TCIFLUSH); } - -void RS232_flushTX(int comport_number) -{ - tcflush(Cport[comport_number], TCOFLUSH); +void rs232_c::flushTX(void) { + tcflush(Cport, TCOFLUSH); } - -void RS232_flushRXTX(int comport_number) -{ - tcflush(Cport[comport_number], TCIOFLUSH); +void rs232_c::flushRXTX(void) { + tcflush(Cport, TCIOFLUSH); } - -#else /* windows */ - -#define RS232_PORTNR 16 - -HANDLE Cport[RS232_PORTNR]; - - -char *comports[RS232_PORTNR]={"\\\\.\\COM1", "\\\\.\\COM2", "\\\\.\\COM3", "\\\\.\\COM4", - "\\\\.\\COM5", "\\\\.\\COM6", "\\\\.\\COM7", "\\\\.\\COM8", - "\\\\.\\COM9", "\\\\.\\COM10", "\\\\.\\COM11", "\\\\.\\COM12", - "\\\\.\\COM13", "\\\\.\\COM14", "\\\\.\\COM15", "\\\\.\\COM16"}; - -char mode_str[128]; - - -int RS232_OpenComport(int comport_number, int baudrate, const char *mode) +void rs232_c::cputs(const char *text) /* sends a string to serial port */ { - if((comport_number>=RS232_PORTNR)||(comport_number<0)) - { - printf("illegal comport number\n"); - return(1); - } - - switch(baudrate) - { - case 110 : strcpy(mode_str, "baud=110"); - break; - case 300 : strcpy(mode_str, "baud=300"); - break; - case 600 : strcpy(mode_str, "baud=600"); - break; - case 1200 : strcpy(mode_str, "baud=1200"); - break; - case 2400 : strcpy(mode_str, "baud=2400"); - break; - case 4800 : strcpy(mode_str, "baud=4800"); - break; - case 9600 : strcpy(mode_str, "baud=9600"); - break; - case 19200 : strcpy(mode_str, "baud=19200"); - break; - case 38400 : strcpy(mode_str, "baud=38400"); - break; - case 57600 : strcpy(mode_str, "baud=57600"); - break; - case 115200 : strcpy(mode_str, "baud=115200"); - break; - case 128000 : strcpy(mode_str, "baud=128000"); - break; - case 256000 : strcpy(mode_str, "baud=256000"); - break; - case 500000 : strcpy(mode_str, "baud=500000"); - break; - case 1000000 : strcpy(mode_str, "baud=1000000"); - break; - default : printf("invalid baudrate\n"); - return(1); - break; - } - - if(strlen(mode) != 3) - { - printf("invalid mode \"%s\"\n", mode); - return(1); - } - - switch(mode[0]) - { - case '8': strcat(mode_str, " data=8"); - break; - case '7': strcat(mode_str, " data=7"); - break; - case '6': strcat(mode_str, " data=6"); - break; - case '5': strcat(mode_str, " data=5"); - break; - default : printf("invalid number of data-bits '%c'\n", mode[0]); - return(1); - break; - } - - switch(mode[1]) - { - case 'N': - case 'n': strcat(mode_str, " parity=n"); - break; - case 'E': - case 'e': strcat(mode_str, " parity=e"); - break; - case 'O': - case 'o': strcat(mode_str, " parity=o"); - break; - default : printf("invalid parity '%c'\n", mode[1]); - return(1); - break; - } - - switch(mode[2]) - { - case '1': strcat(mode_str, " stop=1"); - break; - case '2': strcat(mode_str, " stop=2"); - break; - default : printf("invalid number of stop bits '%c'\n", mode[2]); - return(1); - break; - } - - strcat(mode_str, " dtr=on rts=on"); - -/* -http://msdn.microsoft.com/en-us/library/windows/desktop/aa363145%28v=vs.85%29.aspx - -http://technet.microsoft.com/en-us/library/cc732236.aspx -*/ - - Cport[comport_number] = CreateFileA(comports[comport_number], - GENERIC_READ|GENERIC_WRITE, - 0, /* no share */ - NULL, /* no security */ - OPEN_EXISTING, - 0, /* no threads */ - NULL); /* no templates */ - - if(Cport[comport_number]==INVALID_HANDLE_VALUE) - { - printf("unable to open comport\n"); - return(1); - } - - DCB port_settings; - memset(&port_settings, 0, sizeof(port_settings)); /* clear the new struct */ - port_settings.DCBlength = sizeof(port_settings); - - if(!BuildCommDCBA(mode_str, &port_settings)) - { - printf("unable to set comport dcb settings\n"); - CloseHandle(Cport[comport_number]); - return(1); - } - - if(!SetCommState(Cport[comport_number], &port_settings)) - { - printf("unable to set comport cfg settings\n"); - CloseHandle(Cport[comport_number]); - return(1); - } - - COMMTIMEOUTS Cptimeouts; - - Cptimeouts.ReadIntervalTimeout = MAXDWORD; - Cptimeouts.ReadTotalTimeoutMultiplier = 0; - Cptimeouts.ReadTotalTimeoutConstant = 0; - Cptimeouts.WriteTotalTimeoutMultiplier = 0; - Cptimeouts.WriteTotalTimeoutConstant = 0; - - if(!SetCommTimeouts(Cport[comport_number], &Cptimeouts)) - { - printf("unable to set comport time-out settings\n"); - CloseHandle(Cport[comport_number]); - return(1); - } - - return(0); + while (*text != 0) + SendByte(*(text++)); } - -int RS232_PollComport(int comport_number, unsigned char *buf, int size) -{ - int n; - -/* added the void pointer cast, otherwise gcc will complain about */ -/* "warning: dereferencing type-punned pointer will break strict aliasing rules" */ - - ReadFile(Cport[comport_number], buf, size, (LPDWORD)((void *)&n), NULL); - - return(n); -} - - -int RS232_SendByte(int comport_number, unsigned char byte) -{ - int n; - - WriteFile(Cport[comport_number], &byte, 1, (LPDWORD)((void *)&n), NULL); - - if(n<0) return(1); - - return(0); -} - - -int RS232_SendBuf(int comport_number, unsigned char *buf, int size) -{ - int n; - - if(WriteFile(Cport[comport_number], buf, size, (LPDWORD)((void *)&n), NULL)) - { - return(n); - } - - return(-1); -} - - -void RS232_CloseComport(int comport_number) -{ - CloseHandle(Cport[comport_number]); -} - -/* -http://msdn.microsoft.com/en-us/library/windows/desktop/aa363258%28v=vs.85%29.aspx -*/ - -int RS232_IsDCDEnabled(int comport_number) -{ - int status; - - GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status)); - - if(status&MS_RLSD_ON) return(1); - else return(0); -} - - -int RS232_IsCTSEnabled(int comport_number) -{ - int status; - - GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status)); - - if(status&MS_CTS_ON) return(1); - else return(0); -} - - -int RS232_IsDSREnabled(int comport_number) -{ - int status; - - GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status)); - - if(status&MS_DSR_ON) return(1); - else return(0); -} - - -void RS232_enableDTR(int comport_number) -{ - EscapeCommFunction(Cport[comport_number], SETDTR); -} - - -void RS232_disableDTR(int comport_number) -{ - EscapeCommFunction(Cport[comport_number], CLRDTR); -} - - -void RS232_enableRTS(int comport_number) -{ - EscapeCommFunction(Cport[comport_number], SETRTS); -} - - -void RS232_disableRTS(int comport_number) -{ - EscapeCommFunction(Cport[comport_number], CLRRTS); -} - -/* -https://msdn.microsoft.com/en-us/library/windows/desktop/aa363428%28v=vs.85%29.aspx -*/ - -void RS232_flushRX(int comport_number) -{ - PurgeComm(Cport[comport_number], PURGE_RXCLEAR | PURGE_RXABORT); -} - - -void RS232_flushTX(int comport_number) -{ - PurgeComm(Cport[comport_number], PURGE_TXCLEAR | PURGE_TXABORT); -} - - -void RS232_flushRXTX(int comport_number) -{ - PurgeComm(Cport[comport_number], PURGE_RXCLEAR | PURGE_RXABORT); - PurgeComm(Cport[comport_number], PURGE_TXCLEAR | PURGE_TXABORT); -} - - -#endif - - -void RS232_cputs(int comport_number, const char *text) /* sends a string to serial port */ -{ - while(*text != 0) RS232_SendByte(comport_number, *(text++)); -} - - -/* return index in comports matching to device name or -1 if not found */ -int RS232_GetPortnr(const char *devname) -{ - int i; - - char str[32]; - -#if defined(__linux__) || defined(__FreeBSD__) /* Linux & FreeBSD */ - strcpy(str, "/dev/"); -#else /* windows */ - strcpy(str, "\\\\.\\"); -#endif - strncat(str, devname, 16); - str[31] = 0; - - for(i=0; i. -* -*************************************************************************** -*/ + *************************************************************************** + * + * Author: Teunis van Beelen + * + * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Teunis van Beelen + * + * Email: teuniz@gmail.com + * + *************************************************************************** + * + * 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 3 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + *************************************************************************** + */ /* Last revision: August 5, 2017 */ /* For more info and how to use this library, visit: http://www.teuniz.net/RS-232/ */ - #ifndef rs232_INCLUDED #define rs232_INCLUDED -#ifdef __cplusplus -extern "C" { -#endif - #include #include - - #if defined(__linux__) || defined(__FreeBSD__) #include @@ -60,28 +53,38 @@ extern "C" { #endif -int RS232_OpenComport(int, int, const char *); -int RS232_PollComport(int, unsigned char *, int); -int RS232_SendByte(int, unsigned char); -int RS232_SendBuf(int, unsigned char *, int); -void RS232_CloseComport(int); -void RS232_cputs(int, const char *); -int RS232_IsDCDEnabled(int); -int RS232_IsCTSEnabled(int); -int RS232_IsDSREnabled(int); -void RS232_enableDTR(int); -void RS232_disableDTR(int); -void RS232_enableRTS(int); -void RS232_disableRTS(int); -void RS232_flushRX(int); -void RS232_flushTX(int); -void RS232_flushRXTX(int); -int RS232_GetPortnr(const char *); +#define RS232_PORTNR 38 -#ifdef __cplusplus -} /* extern "C" */ -#endif +class rs232_c { +private: + + int Cport; // file handle of COM port + int error; + + struct termios new_port_settings, old_port_settings; + +public: + rs232_c(); + unsigned TransmissionTime_us; + int OpenComport(const char *devname, int baudrate, const char *mode, bool par_and_break); + int PollComport(unsigned char *buf, int size); + int SendByte(unsigned char byte); + void LoopbackByte(unsigned char byte); + int SendBuf(unsigned char *buf, int size); + void SetBreak(int break_state); + void CloseComport(void); + void cputs(const char *); + int IsDCDEnabled(void); + int IsCTSEnabled(void); + int IsDSREnabled(void); + void enableDTR(void); + void disableDTR(void); + void enableRTS(void); + void disableRTS(void); + void flushRX(void); + void flushTX(void); + void flushRXTX(void); +}; #endif -