15 #ifdef FAUDES_IODEVICE_MODBUS
44 FD_DHV(
"mbDevice(" << mName <<
")::mbDevice()");
46 mDefaultLabel =
"ModbusDevice";
53 mMessage=
new char[260];
56 mSlaveAddress.IpColonPort(
"localhost:502");
96 std::stringstream errstr;
97 errstr <<
"image size must not exceed 2000 bits (image #" << i+1 <<
")";
98 throw Exception(
"mbDevice:Read", errstr.str(), 52);
113 std::stringstream errstr;
114 errstr <<
"Slave must have localhost as SlaveAddress";
115 throw Exception(
"mbDevice:Compile()", errstr.str(), 52);
209 while(rTr.
Peek(token)) {
215 std::stringstream errstr;
216 errstr <<
"Invalid role tag, value attribute missing" << rTr.
FileLine();
217 throw Exception(
"mpiDevice:Read", errstr.str(), 52);
220 std::transform(val.begin(), val.end(), val.begin(), tolower);
224 std::stringstream errstr;
225 errstr <<
"Invalid value attribute in role tag" << rTr.
FileLine();
226 throw Exception(
"spiDevice:Read", errstr.str(), 52);
232 if(token.
IsBegin(
"SlaveAddress")) {
233 FD_DHV(
"mBDevice::DoRead(): found slave address");
236 std::stringstream errstr;
237 errstr <<
"Invalid ip address" << rTr.
FileLine();
238 throw Exception(
"mbDevice:Read", errstr.str(), 52);
245 if(token.
IsBegin(
"RemoteImage")) {
247 while(!rTr.
Eos(
"RemoteImage")) {
251 if(!rtoken.
IsBegin(
"Outputs")) {
252 std::stringstream errstr;
253 errstr <<
"invalid io range" << rTr.
FileLine();
254 throw Exception(
"mbDevice:Read", errstr.str(), 52);
263 std::stringstream errstr;
264 errstr <<
"missing remote address" << rTr.
FileLine();
265 throw Exception(
"mbDevice:Read", errstr.str(), 52);
276 std::stringstream errstr;
277 errstr <<
"image size must not exceed 2000 bits" << rTr.
FileLine();
278 throw Exception(
"mbDevice:Read", errstr.str(), 52);
303 mSlaveSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
305 std::stringstream errstr;
306 errstr <<
"Modbus fatal network error (cannot open server socket)";
307 throw Exception(
"mbDevice::Start", errstr.str(), 553);
310 faudes_setsockopt(
mSlaveSocket,SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse));
312 struct sockaddr_in slaveaddress;
313 memset(&slaveaddress, 0,
sizeof(slaveaddress));
314 slaveaddress.sin_family = AF_INET;
315 slaveaddress.sin_addr.s_addr = htonl(INADDR_ANY);
318 if(bind(
mSlaveSocket, (
struct sockaddr *) &slaveaddress,
sizeof(slaveaddress)) <0) {
319 std::stringstream errstr;
320 errstr <<
"Modbus fatal network error (cannot bind socket)";
321 throw Exception(
"nDevice::Start", errstr.str(), 553);
325 std::stringstream errstr;
326 errstr <<
"Simplenet fatal network error (cannot listen from socket)";
327 throw Exception(
"mbDevice::Start", errstr.str(), 553);
353 FD_DH(
"mbDevice::Stop(): closing slave socket");
358 FD_DH(
"mbDevice::Stop(): done");
364 #define MB_SETINT(p,v) { mMessage[p] = ((v)>>8); mMessage[p+1] = ((v) & 0xff); }
365 #define MB_GETINT(p) ( ( mMessage[p] << 8) + ((int) mMessage[p+1]) )
366 #define MB_SETBYTE(p,v) { mMessage[p] = (v);}
367 #define MB_GETBYTE(p) ( mMessage[p] )
381 int avail= select(
mSlaveSocket+1, &mysocks, NULL, NULL, &tv);
384 FD_DH(
"mbDevice::MbFlushBuffers(): flush recv buffer");
388 FD_DH(
"mbDevice::MbFlushBuffers(): flush recv buffer: fatal error?");
391 FD_DHV(
"mbDevice::MbFlushBuffers(): ok");
431 int avail=select(mysocks_max+1, &mysocks, NULL, NULL, &tv);
434 if(avail<=0)
return -1;
440 FD_DH(
"mbDevice::MbReceiveResponse(): invalid MBAB header (size mismatch)");
455 FD_DH(
"mbDevice::MbReceiveRequest(): invalid MBAB header (size mismatch)");
471 int rc=send(mastersock,
mMessage+from, left, 0);
489 if(ctimer< 1000000)
return;
494 int slavesock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
496 FD_DH(
"mbDevice::DoLoopCallBack(): connection to slave failed: internal err A0");
500 unsigned long int slaveinaddr = INADDR_NONE;
501 if(slaveinaddr==INADDR_NONE) {
502 FD_DHV(
"mbDevice::DoLoopCallBack(): using provided address literaly");
505 if(slaveinaddr==INADDR_NONE) {
506 struct hostent *host;
509 FD_DHV(
"mbDevice::DoLooCallBack(): retrieve alternative address by name-lookup");
510 slaveinaddr = *(
unsigned long int*) host->h_addr;
513 if(slaveinaddr==INADDR_NONE) {
514 FD_DH(
"mbDevice::DoLooCallBack():: connection to slave failed: invalid address " <<
mSlaveAddress.
Ip());
515 faudes_closesocket(slavesock);
519 struct sockaddr_in slaveaddress;
520 memset(&slaveaddress, 0,
sizeof(slaveaddress));
521 slaveaddress.sin_family = AF_INET;
522 slaveaddress.sin_addr.s_addr=slaveinaddr;
527 FD_DH(
"mbDevice::DoLoopCallBack():: connection to slave failed: internal error A1");
528 faudes_closesocket(slavesock);
532 int rcc= connect(slavesock, (
struct sockaddr*) &slaveaddress,
sizeof(slaveaddress));
536 if(errno!=EINPROGRESS) {
537 FD_DH(
"mbDevice::DoLoopCallBack(): connection to slave failed: connect() errno " << errno);
539 FD_DH(
"mbDevice::DoLoopCallBack(): connection to slave: wait for host to accept");
546 FD_SET(slavesock, &mysocks);
547 rcc= select(slavesock+1, NULL, &mysocks, NULL, &tv);
549 if(rcc<0)
FD_DH(
"mbDevice::DoLoopCallBack(): connection to slave failed: timeout");
553 #ifdef FAUDES_WINDOWS
555 int lerr = WSAGetLastError();
556 if(lerr!=WSAEWOULDBLOCK) {
557 FD_DH(
"mbDevice::DoLoopCallBack(): connection to slave failed: connect() errno " << lerr);
559 FD_DH(
"mbDevice::DoLoopCallBack(): wait for host to accept");
566 FD_SET(slavesock, &mysocks);
567 rcc= select(slavesock+1, NULL, &mysocks, NULL, &tv);
569 if(rcc<0)
FD_DH(
"mbDevice::DoLoopCallBack(): connection to slave failed: timeout");
575 FD_DH(
"mbDevice::DoLoopCallBack():: connection to slave failed: host unreachable");
576 faudes_closesocket(slavesock);
581 FD_DH(
"mbDevice::DoLoopCallBack():: connection to slave failed: internal error A2");
582 faudes_closesocket(slavesock);
588 FD_DH(
"mbDevice::DoLoopCallBack():: connection to slave failed: internal error A3");
589 faudes_closesocket(slavesock);
593 FD_DH(
"mbDevice::DoLoopCallBack(): connected to remote slave, using socket #" << slavesock);
609 int avail = select(
mSlaveSocket+1, &mysocks, NULL, NULL, &tv);
614 FD_DH(
"mbDevice::DoLoopCallBack(): accepting remote master to connect");
615 struct sockaddr_in masteraddr;
616 socklen_t masteraddr_len =
sizeof(masteraddr);
617 int mastersock=accept(
mSlaveSocket, (
struct sockaddr *) &masteraddr, &masteraddr_len );
619 FD_DH(
"mbDevice::DoLoopCallback(): failed to accept incomming connection");
631 FD_DHV(
"mbDevice::DoLooCallBack(): update image from remote slave");
642 FD_DHV(
"mbDevice::DoLoopCallBack(): sending request");
644 FD_DHV(
"mbDevice::DoLoopCallBack(): read response");
649 FD_DHV(
"mbDevice::DoLoopCallBack(): input image received");
658 addr++; count--; shft = shft <<1;
659 if(shft==0x100) { shft=0x01; data=
MB_GETBYTE(++src);};
662 FD_DH(
"mbDevice::DoLoopCallBack(): received error response on read inputs");
673 int bcount= (ior.
mCount-1)/8 +1;
681 if(
mpImage[addr]) data |= shft;
682 addr++; count--; shft = shft <<1;
683 if(shft==0x100) { shft=0x01;
MB_SETBYTE(dst,data); data=0x00; dst++;}
688 FD_DHV(
"mbDevice::DoLoopCallBack(): sending request");
692 FD_DH(
"mbDevice::DoLoopCallBack(): received error response on write coils");
708 if(mastersock<0)
continue;
709 FD_SET(mastersock, &mysocks);
710 if(mysocks_max< mastersock) mysocks_max=mastersock;
717 int avail=select(mysocks_max+1, &mysocks, NULL, NULL, &tv);
723 if(mastersock<0)
continue;
724 if(!FD_ISSET(mastersock, &mysocks))
continue;
725 FD_DHV(
"mbDevice::DoLoopCallback(): received message on sock " << mastersock);
727 FD_DH(
"mbDevice::DoLoopCallback(): receive error on sock " << mastersock);
728 faudes_closesocket(mastersock);
737 if((fnct==0x01) || (fnct==0x02)) {
738 FD_DHV(
"mbDevice::DoLoopCallback(): coil-read or input read request");
741 int bcount= ((count-1)/8+1);
742 FD_DHV(
"mbDevice::DoLoopCallback(): address range: @" << addr <<
" #" << count);
746 if(count>2000) errcode=0x02;
754 if(
mpImage[addr]) data |= shft;
755 addr++; count--; shft = shft <<1;
756 if(shft==0x100) { shft=0x01;
MB_SETBYTE(dst,data); dst++; data=0x00;}
765 if((fnct==0x03) || (fnct==0x04)) {
766 FD_DHV(
"mbDevice::DoLoopCallback(): register or holding register read request");
769 FD_DHV(
"mbDevice::DoLoopCallback(): address range: @" << addr <<
" #" << count);
782 for(;count>0; count--) {
785 for(;src<
mImageSize && shft!=0x100; src++, shft = shft << 1)
786 if(
mpImage[src]) lbyte |= shft;
789 for(;src<
mImageSize && shft!=0x100; src++, shft = shft << 1)
790 if(
mpImage[src]) hbyte |= shft;
798 FD_DHV(
"mbDevice::DoLoopCallback(): write single coil request");
801 FD_DHV(
"mbDevice::DoLoopCallback(): write single coil request: " << addr <<
" to " << val);
813 FD_DHV(
"mbDevice::DoLoopCallback(): write holding register request");
816 FD_DHV(
"mbDevice::DoLoopCallback(): set @" << addr <<
" to " << val);
825 int hbyte= (val >> 8);
826 int lbyte= (val & 0xff);
828 for(shft=0x01; shft!=0x100; shft = shft << 1, dst++)
829 mpImage[dst] = (( lbyte & shft) != 0);
830 for(shft=0x01; shft!=0x100; shft = shft << 1, dst++)
831 mpImage[dst] = (( hbyte & shft) != 0);
838 FD_DHV(
"mbDevice::DoLoopCallback(): write multiple coils request");
842 FD_DHV(
"mbDevice::DoLoopCallback(): address range: @" << addr <<
" #" << count <<
"(" << bcount <<
")");
846 if( (bcount < ((count-1)/8+1)) || (
mMessageLen < 6+bcount) ) errcode=0x03;
854 if(shft==0x100) { shft=0x01; data=
MB_GETBYTE(src);src++;};
856 addr++; count--; shft = shft <<1;
864 FD_DHV(
"mbDevice::DoLoopCallback(): write multiple holding registers request");
868 FD_DHV(
"mbDevice::DoLoopCallback(): address range: @" << addr <<
" #" << count <<
"(" << bcount <<
")");
873 if( bcount != 2* count)
880 for(;count>0;count--) {
884 for(shft=0x01; shft!=0x100; shft = shft << 1, dst++)
885 mpImage[dst] = (( lbyte & shft) != 0);
886 for(shft=0x01; shft!=0x100; shft = shft << 1, dst++)
887 mpImage[dst] = (( hbyte & shft) != 0);
900 FD_DH(
"mbDevice::DoLoopCallback(): sending error reply, code " << errcode);
#define FAUDES_TYPE_IMPLEMENTATION(ftype, ctype, cbase)
faudes type implementation macros, overall
Auto register faudes-type with specified type name.
int Port(void) const
Get TCP port.
std::string IpColonPort(void) const
Get as colon seperated string.
std::string Ip(void) const
Get IP address.
A TokenReader reads sequential tokens from a file or string.
std::string FileLine(void) const
Return "filename:line".
bool Eos(const std::string &rLabel)
Peek a token and check whether it ends the specified section.
void ReadEnd(const std::string &rLabel)
Close the current section by matching the previous ReadBegin().
void ReadBegin(const std::string &rLabel)
Open a section by specified label.
bool Get(Token &token)
Get next token.
bool Peek(Token &token)
Peek next token.
A TokenWriter writes sequential tokens to a file, a string or stdout.
void WriteEnd(const std::string &rLabel)
Write end label.
void WriteBegin(const std::string &rLabel)
Write begin label.
Tokens model atomic data for stream IO.
const std::string & StringValue(void) const
Get string value of a name token.
Int AttributeIntegerValue(const std::string &name)
Access attribute value.
bool ExistsAttributeString(const std::string &name)
Test attibute existence.
bool IsBegin(void) const
Test token Type.
void SetEmpty(const std::string &rName)
Initialize as empty-tag token.
bool ExistsAttributeInteger(const std::string &name)
Test attibute existence.
void InsAttributeInteger(const std::string &name, Int value)
Insert named attribute with integer value.
void InsAttributeString(const std::string &name, const std::string &value)
Insert named attribute with string value.
const std::string & AttributeStringValue(const std::string &name)
Access attribute value.
Base class of all libFAUDES objects that participate in the run-time interface.
Processimage synchronisation via Modbus/TCP.
virtual ~mbDevice(void)
Explicit destructor.
void DoReadPreface(TokenReader &rTr, const std::string &rLabel="", const Type *pContext=0)
Read non-event-related configuration data from tokenreader.
virtual bool DoReadSignal(int bitaddr)
Get input signal.
int MbSendResponse(int mastersock)
int MbReceiveRequest(int mastersock)
virtual void DoReadSignalsPost(void)
IO Hook, inputs.
void SlaveAddress(const std::string &rAddr)
Set server address of this node.
virtual void Compile(void)
Compile to internal data-structures.
bool mMasterRole
Role: master/slave.
virtual void Stop(void)
Deactivate the device.
int mImageSize
Remote process image buffer.
virtual void Start(void)
Activate the device.
int MbReceiveResponse(void)
int MbFlushBuffers(void)
I/O helper.
virtual bool DoWriteSignalsPre(void)
IO Hook, outputs.
void DoWritePreface(TokenWriter &rTw, const std::string &rLabel, const Type *pContext) const
Write non-event-related configuration data to tokenreader.
std::vector< IoRange > mSlaveIoRanges
virtual void Clear(void)
Clear all configuration (implies Stop)
virtual void DoLoopCallback(void)
Loop hook.
virtual void DoWriteSignal(int bitaddr, bool value)
Set output signal.
virtual bool DoReadSignalsPre(void)
IO Hook, inputs.
virtual void DoWriteSignalsPost(void)
IO Hook, outputs.
int MbSendRequest(int id)
std::vector< int > mMasterSockets
Background thread: tcp connection to remote masters.
int mSlaveSocket
Background thread: tcp connection to remote slave.
void AppendRemoteInputs(int mbid, int mbaddr, int cnt, int fdaddr)
Append remotely implemented inputs.
SimplenetAddress mSlaveAddress
IP addresses.
void AppendRemoteOutputs(int mbid, int mbaddr, int cnt, int fdaddr)
Append remotely implemented outputs.
An sDevice implements signal based semantics for faudes events.
virtual int CycleTime() const
Report cycle time.
virtual void Stop(void)
Deactivate the device.
int mMaxBitAddress
Address range.
virtual void DoReadPreface(TokenReader &rTr, const std::string &rLabel="", const Type *pContext=0)
Reads non-event-related configuration from TokenReader.
virtual void Clear(void)
Clear all configuration.
bool mSyncWrite
True for synchronous output writes.
void DoWritePreface(TokenWriter &rTw, const std::string &rLabel, const Type *pContext=0) const
Writes non-event-related configuration to TokenWriter.
virtual void Start(void)
Activate the device.
std::map< int, EventSet > mOutputLevelIndexMap
Reverse output map: map signal addres to events that affect the resp.
virtual void Compile(void)
Build up internal data-structure (e.g.
virtual DeviceState Status(void)
Get status.
DeviceState mState
Status: running, starting etc.
Process image via modbus/tcp.
libFAUDES resides within the namespace faudes.
AutoRegisterType< mbDevice > gRtiRegisterSpiDevice("ModbusDevice")