2024-12-01 19:35:24 +00:00
|
|
|
//| Copyright: (C) 2020-2024 Kevin Larke <contact AT larke DOT org>
|
|
|
|
//| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
|
2019-12-24 15:05:24 +00:00
|
|
|
#include "cwCommon.h"
|
|
|
|
#include "cwLog.h"
|
|
|
|
#include "cwCommonImpl.h"
|
|
|
|
#include "cwMem.h"
|
|
|
|
#include "cwThread.h"
|
|
|
|
#include "cwSerialPort.h"
|
|
|
|
#include "cwSerialPortSrv.h"
|
|
|
|
|
|
|
|
|
|
|
|
namespace cw
|
|
|
|
{
|
|
|
|
namespace serialPortSrv
|
|
|
|
{
|
|
|
|
typedef struct this_str
|
|
|
|
{
|
2020-03-06 03:04:53 +00:00
|
|
|
serialPort::handle_t mgrH;
|
2019-12-24 15:05:24 +00:00
|
|
|
thread::handle_t threadH;
|
2020-03-06 03:04:53 +00:00
|
|
|
unsigned pollPeriodMs;
|
2019-12-24 15:05:24 +00:00
|
|
|
} this_t;
|
|
|
|
|
|
|
|
inline this_t* _handleToPtr( handle_t h ) { return handleToPtr<handle_t,this_t>(h); }
|
|
|
|
|
|
|
|
rc_t _destroy( this_t* p )
|
|
|
|
{
|
|
|
|
rc_t rc = kOkRC;
|
|
|
|
|
|
|
|
if((rc = thread::destroy(p->threadH)) != kOkRC )
|
|
|
|
return rc;
|
2020-03-06 03:04:53 +00:00
|
|
|
|
|
|
|
if((rc = serialPort::destroy(p->mgrH)) != kOkRC )
|
|
|
|
return rc;
|
|
|
|
|
2019-12-24 15:05:24 +00:00
|
|
|
|
2019-12-28 02:51:28 +00:00
|
|
|
mem::release(p);
|
2019-12-24 15:05:24 +00:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2020-03-06 03:04:53 +00:00
|
|
|
|
|
|
|
// Do periodic non-blocking reads of each serial port and sleep between reads.
|
|
|
|
bool threadCallbackAlt( void* arg )
|
|
|
|
{
|
|
|
|
this_t* p = static_cast<this_t*>(arg);
|
|
|
|
unsigned portN = serialPort::portCount( p->mgrH );
|
|
|
|
|
|
|
|
unsigned readN;
|
|
|
|
|
|
|
|
for(unsigned i=0; i<portN; ++i)
|
|
|
|
{
|
|
|
|
|
|
|
|
rc_t rc = serialPort::receive_nb( p->mgrH, serialPort::portIndexToId(p->mgrH,i), readN );
|
|
|
|
|
|
|
|
if( rc != kOkRC && rc != kTimeOutRC )
|
|
|
|
{
|
|
|
|
cwLogError(rc,"Serial server receive failed.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( readN == 0)
|
|
|
|
sleepMs(20);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for data to arrive on any port.
|
2019-12-24 15:05:24 +00:00
|
|
|
bool threadCallback( void* arg )
|
|
|
|
{
|
|
|
|
this_t* p = static_cast<this_t*>(arg);
|
|
|
|
|
|
|
|
unsigned readN;
|
2020-03-06 03:04:53 +00:00
|
|
|
rc_t rc = serialPort::receive(p->mgrH,p->pollPeriodMs,readN);
|
|
|
|
if( rc != kOkRC && rc != kTimeOutRC )
|
|
|
|
{
|
|
|
|
cwLogError(rc,"Serial server receive failed.");
|
|
|
|
return false;
|
|
|
|
}
|
2019-12-24 15:05:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-03-06 03:04:53 +00:00
|
|
|
cw::rc_t cw::serialPortSrv::create( handle_t& h, unsigned pollPeriodMs, unsigned recvBufByteN )
|
2019-12-24 15:05:24 +00:00
|
|
|
{
|
|
|
|
rc_t rc = kOkRC;
|
|
|
|
|
2019-12-28 02:51:28 +00:00
|
|
|
this_t* p = mem::allocZ<this_t>();
|
2020-03-06 03:04:53 +00:00
|
|
|
|
|
|
|
if((rc = serialPort::create( p->mgrH, recvBufByteN)) != kOkRC )
|
|
|
|
goto errLabel;
|
2019-12-24 15:05:24 +00:00
|
|
|
|
2024-02-18 13:37:33 +00:00
|
|
|
if((rc = thread::create( p->threadH, threadCallback, p, "serial_srv")) != kOkRC )
|
2019-12-24 15:05:24 +00:00
|
|
|
goto errLabel;
|
|
|
|
|
2020-03-06 03:04:53 +00:00
|
|
|
p->pollPeriodMs = pollPeriodMs;
|
2019-12-24 15:05:24 +00:00
|
|
|
|
|
|
|
errLabel:
|
|
|
|
if( rc != kOkRC )
|
|
|
|
_destroy(p);
|
|
|
|
else
|
|
|
|
h.set(p);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
cw::rc_t cw::serialPortSrv::destroy(handle_t& h )
|
|
|
|
{
|
|
|
|
rc_t rc = kOkRC;
|
|
|
|
|
|
|
|
if( !h.isValid() )
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
this_t* p = _handleToPtr(h);
|
|
|
|
|
|
|
|
if((rc = _destroy(p)) != kOkRC )
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
h.clear();
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-06 03:04:53 +00:00
|
|
|
cw::serialPort::handle_t cw::serialPortSrv::serialHandle( handle_t h )
|
2019-12-24 15:05:24 +00:00
|
|
|
{
|
|
|
|
this_t* p = _handleToPtr(h);
|
2020-03-06 03:04:53 +00:00
|
|
|
return p->mgrH;
|
2019-12-24 15:05:24 +00:00
|
|
|
}
|
|
|
|
|
2020-01-27 22:48:59 +00:00
|
|
|
cw::thread::handle_t cw::serialPortSrv::threadHandle( handle_t h )
|
2019-12-24 15:05:24 +00:00
|
|
|
{
|
|
|
|
this_t* p = _handleToPtr(h);
|
|
|
|
return p->threadH;
|
|
|
|
}
|
|
|
|
|
|
|
|
cw::rc_t cw::serialPortSrv::start( handle_t h )
|
|
|
|
{
|
|
|
|
this_t* p = _handleToPtr(h);
|
|
|
|
return cw::thread::pause(p->threadH, thread::kWaitFl );
|
|
|
|
}
|
|
|
|
|
|
|
|
cw::rc_t cw::serialPortSrv::pause( handle_t h )
|
|
|
|
{
|
|
|
|
this_t* p = _handleToPtr(h);
|
|
|
|
return cw::thread::pause(p->threadH, thread::kPauseFl | thread::kWaitFl );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-06 03:04:53 +00:00
|
|
|
cw::rc_t cw::serialPortSrv::send( handle_t h, unsigned portId, const void* byteA, unsigned byteN )
|
2019-12-24 15:05:24 +00:00
|
|
|
{
|
|
|
|
this_t* p = _handleToPtr(h);
|
2020-03-06 03:04:53 +00:00
|
|
|
return cw::serialPort::send(p->mgrH,portId,byteA,byteN);
|
2019-12-24 15:05:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
namespace cw
|
|
|
|
{
|
|
|
|
|
2020-03-06 03:04:53 +00:00
|
|
|
void serialPortSrvTestCb( void* arg, unsigned userId, const void* byteA, unsigned byteN )
|
2019-12-24 15:05:24 +00:00
|
|
|
{
|
|
|
|
const char* text = static_cast<const char*>(byteA);
|
|
|
|
|
|
|
|
for(unsigned i=0; i<byteN; ++i)
|
2020-03-06 03:04:53 +00:00
|
|
|
printf("id:%i %c:%i\n",userId,text[i],(int)text[i]);
|
2019-12-24 15:05:24 +00:00
|
|
|
|
|
|
|
if( byteN )
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cw::rc_t cw::serialPortSrvTest()
|
|
|
|
{
|
2020-03-06 03:04:53 +00:00
|
|
|
// Use this test an Arduino running study/serial/arduino_xmt_rcv/main.c
|
2019-12-24 15:05:24 +00:00
|
|
|
|
2020-03-06 03:04:53 +00:00
|
|
|
rc_t rc = kOkRC;
|
|
|
|
bool quitFl = false;
|
|
|
|
unsigned pollPeriodMs = 50;
|
|
|
|
unsigned portId[] = {0,1};
|
|
|
|
const char* device[] = {"/dev/ttyACM1","/dev/ttyACM0"};
|
|
|
|
unsigned baud[] = {38400,38400};
|
|
|
|
unsigned serialCfgFlags[] = {serialPort::kDefaultCfgFlags,serialPort::kDefaultCfgFlags};
|
|
|
|
unsigned portN = 2; //sizeof(portId)/sizeof(portId[0]);
|
|
|
|
unsigned portIdx = 0;
|
|
|
|
serialPortSrv::handle_t h;
|
|
|
|
|
|
|
|
// open the serial port mgr
|
|
|
|
if((rc = serialPortSrv::create(h,pollPeriodMs)) != kOkRC )
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
// open the serial ports
|
|
|
|
for(unsigned i=0; i<portN; ++i)
|
|
|
|
if((rc = serialPort::createPort( serialPortSrv::serialHandle(h), portId[i], device[i], baud[i], serialCfgFlags[i], &serialPortSrvTestCb, nullptr)) != kOkRC )
|
|
|
|
goto errLabel;
|
2019-12-24 15:05:24 +00:00
|
|
|
|
2020-03-06 03:04:53 +00:00
|
|
|
// start the server
|
2019-12-24 15:05:24 +00:00
|
|
|
serialPortSrv::start(h);
|
|
|
|
|
|
|
|
printf("q=quit\n");
|
|
|
|
while(!quitFl)
|
|
|
|
{
|
|
|
|
char c = getchar();
|
|
|
|
|
|
|
|
if( c == 'q')
|
|
|
|
quitFl = true;
|
|
|
|
else
|
|
|
|
if( '0' <= c and c <= 'z' )
|
2020-03-06 03:04:53 +00:00
|
|
|
{
|
|
|
|
// send the output to consecutive ports
|
|
|
|
serialPortSrv::send(h,portId[portIdx],&c,1);
|
|
|
|
portIdx = (portIdx+1) % portN;
|
|
|
|
}
|
2019-12-24 15:05:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-03-06 03:04:53 +00:00
|
|
|
errLabel:
|
|
|
|
|
2019-12-24 15:05:24 +00:00
|
|
|
serialPortSrv::destroy(h);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|