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;
525 int rc = faudes_setsocket_nonblocking(slavesock,
true);
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);
580 if(faudes_getsocket_error(slavesock)<0) {
581 FD_DH(
"mbDevice::DoLoopCallBack():: connection to slave failed: internal error A2");
582 faudes_closesocket(slavesock);
586 rc = faudes_setsocket_nonblocking(slavesock,
false);
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)
std::string IpColonPort(void) const
std::string Ip(void) const
std::string FileLine(void) const
bool Eos(const std::string &rLabel)
void ReadEnd(const std::string &rLabel)
void ReadBegin(const std::string &rLabel)
void WriteEnd(const std::string &rLabel)
void WriteBegin(const std::string &rLabel)
const std::string & StringValue(void) const
Int AttributeIntegerValue(const std::string &name)
bool ExistsAttributeString(const std::string &name)
void SetEmpty(const std::string &rName)
bool ExistsAttributeInteger(const std::string &name)
void InsAttributeInteger(const std::string &name, Int value)
void InsAttributeString(const std::string &name, const std::string &value)
const std::string & AttributeStringValue(const std::string &name)
void DoReadPreface(TokenReader &rTr, const std::string &rLabel="", const Type *pContext=0)
virtual bool DoReadSignal(int bitaddr)
int MbSendResponse(int mastersock)
int MbReceiveRequest(int mastersock)
virtual void DoReadSignalsPost(void)
void SlaveAddress(const std::string &rAddr)
virtual void Compile(void)
int MbReceiveResponse(void)
virtual bool DoWriteSignalsPre(void)
void DoWritePreface(TokenWriter &rTw, const std::string &rLabel, const Type *pContext) const
std::vector< IoRange > mSlaveIoRanges
virtual void DoLoopCallback(void)
virtual void DoWriteSignal(int bitaddr, bool value)
virtual bool DoReadSignalsPre(void)
virtual void DoWriteSignalsPost(void)
int MbSendRequest(int id)
std::vector< int > mMasterSockets
void AppendRemoteInputs(int mbid, int mbaddr, int cnt, int fdaddr)
SimplenetAddress mSlaveAddress
void AppendRemoteOutputs(int mbid, int mbaddr, int cnt, int fdaddr)
virtual int CycleTime() const
virtual void DoReadPreface(TokenReader &rTr, const std::string &rLabel="", const Type *pContext=0)
void DoWritePreface(TokenWriter &rTw, const std::string &rLabel, const Type *pContext=0) const
std::map< int, EventSet > mOutputLevelIndexMap
virtual void Compile(void)
virtual DeviceState Status(void)
AutoRegisterType< mbDevice > gRtiRegisterSpiDevice("ModbusDevice")