This demonstrates the process of communicating through ethernet to a SEL-2431 Voltage Regulator Control Panel using SEL Fast Message. Basic device commands and data cna be requested and displayed over a connected serial port. This is a basic version and full testing and documentation has yet to be completed.
Dependencies: BufferedSerial analogAverager voltageRegulator netStatReg analogMinMax CounterMinMax
main.cpp
- Committer:
- masterkookus
- Date:
- 2019-10-02
- Revision:
- 11:d40adc7de05f
- Parent:
- 10:9da863a6da3e
- Child:
- 12:4bb088c27838
File content as of revision 11:d40adc7de05f:
#if !FEATURE_LWIP #error [NOT_SUPPORTED] LWIP not supported for this target #endif //#define netmsgdebug #include "mbed.h" #include "EthernetInterface.h" #include "TCPServer.h" #include "TCPSocket.h" #include "BufferedSerial.h" #include "nettime.h" #include "netdevices.h" #include "mydevices.h" #include "platform/CircularBuffer.h" #include "netDataTypes.h" #include "selMsg.h" #include "string.h" #include "analogAverager.h" #include "analogMinMax.h" #include "counterMinMax.h" Ticker nettimer; struct netsys net1; struct vRegData vReg1; analogAverager voltageAvg(120,true,0.9,true,1.1); analogMinMax voltageMinMax(120,true,0.9,true,1.1); counterMinMax tapMinMax(0,true,-16,true,16); bool polltick; BufferedSerial sport0(sport0tx, sport0rx, sport0buff, sport0mult); // UART2 CircularBuffer<char, 1024> receiveBuffer; CircularBuffer<char, 64> sendLength; CircularBuffer<char, 1024> sendBuffer; CircularBuffer<char, 16> serrxbuffer; Thread conchkthread[2]; Thread rxtxdatathread[5]; unsigned int currenttime=0; nsapi_error_t ret; //Provides the deivce poll timing void heartbeat() { setTick(true); } void confignetdevices(EthernetInterface *eth) { net1.cltPort=setclientport; net1.srv_addr=setclientaddress; net1.cltIsActive=false; net1.serIsActive=false; net1.cltCloseConnection=false; net1.pollTime=0; net1.pollTimeout=0; net1.pollRequestSent=false; net1.pollResponseReceived=false; net1.srv_sock.set_blocking(true); net1.srv_sock.set_timeout(100); net1.aliveTimeout=setservertimeout; net1.srv.set_blocking(true); net1.srv.set_timeout(100); net1.pollEnabled=setpollenabled; net1.pollTimeoutCount=0; net1.configState=0; net1.pollTimeoutCount=0; net1.sendRetryCount=0; net1.messageFailCount=0; net1.txMessageCount=0; net1.rxMessageCount=0; net1.fmEnabled=false; net1.fmdEnabled=false; /* Open the server on ethernet stack */ net1.srv.open(eth); net1.srvIsActive=false; net1.srvCloseConnection=false; /* Bind port 23 to the server */ net1.srvPort=setserverport; net1.srv.bind(net1.srvPort); /* Can handle 5 simultaneous connections */ net1.srv.listen(5); sport0.baud(sport0baud); } void dataprocess(netsys *net2) { int txc; char cchar; char cbuf[256]; unsigned int clen=0; unsigned int cbc; float4byte valpack; short2byte timepack; while(1) { //Check to see if the Receive Buffer has anything while (!receiveBuffer.empty()) { receiveBuffer.pop(cchar); cbuf[clen]=cchar; clen++; } //If a Poll Request has been made and data has been received set flag if (net2->pollRequestSent) { if (clen>0) { net2->pollResponseReceived=true; } } //Check to see if bulk data and reports being sent from device due to serial command if (net2->devMsgOpenRx) { sport0.write(cbuf,clen); clen=0; } //Check to see if at least 4 characters have been received else if (clen>3) { //Cycle through received data to search for a command for (cbc=0;cbc<clen-3;cbc++) { //Check to see if serial commands are currently being received if (net2->serIsActive==true) { //If relay acknowledges max metering command set bulk receive flag if ((cbuf[cbc]==0x4d) && (cbuf[cbc+1]==0x45) && (cbuf[cbc+2]==0x54)) { sport0.write(cbuf,clen); net2->devMsgOpenRx=true; net2->devMsgReq=0; clen=0; break; } //If relay acknowledges tap report command set bulk receive flag if ((cbuf[cbc]==0x54) && (cbuf[cbc+1]==0x41) && (cbuf[cbc+2]==0x50)) { sport0.write(cbuf,clen); net2->devMsgOpenRx=true; net2->devMsgReq=0; clen=0; break; } //If relay acknowledges level 1 login attempt increment command pointer to password if ((cbuf[cbc]==0x41) && (cbuf[cbc+1]==0x43) && (cbuf[cbc+2]==0x43)) { sport0.write(cbuf,clen); net2->devMsgPos=1; clen=0; break; } //If relay sends mask character increment command pointer to send \r\n if (cbuf[cbc]==0x2a) { sport0.write(cbuf,clen); net2->devMsgPos=2; clen=0; break; } //If relay is in access level 1 or higher increment command pointer to desired command if ((cbuf[cbc]==0x3d) && (cbuf[cbc+1]==0x3e)) { sport0.write(cbuf,clen); net2->devMsgPos=4; clen=0; break; } //If relay in level 0 increment command pointer to access command if ((cbuf[cbc]==0x3d)) { sport0.write(cbuf,clen); net2->devMsgPos=0; clen=0; break; } } //Check fast message conficuration if ((cbuf[cbc]==0xA5) && (cbuf[cbc+1]==0xC0)) { sport0.write(cbuf,clen); net2->configState=1; clen=0; break; } //Check fast meter configuration if ((cbuf[cbc]==0xA5) && (cbuf[cbc+1]==0xC1)) { sport0.write(cbuf,clen); //Ensure Analog channl count is correct if (vReg1.numAnalog!=cbuf[6]) { #ifdef netmsgdebug printf("\r\nFast Meter Analog Channel Count Off\r\n"); #endif clen=0; break; } //Ensure Digital register count is correct if (vReg1.numDigital!=cbuf[8]) { #ifdef netmsgdebug printf("\r\nFast Meter Digital Channel Count Off\r\n"); #endif clen=0; break; } char anum=16; char nxc; //Verify Analog names are correct for (txc=0;txc<vReg1.numAnalog;txc++) { for (nxc=0;nxc<6;nxc++) { if(vReg1.analogs[txc].analogName[nxc]!=cbuf[anum+nxc]) { #ifdef netmsgdebug printf("\r\nPoint %d Failed\r\n",txc); #endif break; } } anum = anum + 11; } net2->configState=3; net2->fmEnabled=true; clen=0; break; } //Receive data if ((cbuf[cbc]==0xA5) && (cbuf[cbc+1]==0xD1)) { char anum=cbc+4; for (txc=0;txc<vReg1.numAnalog;txc++) { valpack.bytes[3]=cbuf[anum]; valpack.bytes[2]=cbuf[anum+1]; valpack.bytes[1]=cbuf[anum+2]; valpack.bytes[0]=cbuf[anum+3]; vReg1.analogs[txc].analog1Value = valpack.cmdflt; anum = anum + 4; printf("%.2f\r\n",vReg1.analogs[txc].analog1Value); } vReg1.timeStamp.month=cbuf[anum]; vReg1.timeStamp.day=cbuf[anum+1]; vReg1.timeStamp.year=cbuf[anum+2]; vReg1.timeStamp.hour=cbuf[anum+3]; vReg1.timeStamp.min=cbuf[anum+4]; vReg1.timeStamp.sec=cbuf[anum+5]; timepack.bytes[1]=cbuf[anum+6]; timepack.bytes[0]=cbuf[anum+7]; vReg1.timeStamp.msec=timepack.cmdshort; printf("%d/%d/%d %d:%d:%d.%d\r\n",vReg1.timeStamp.month,vReg1.timeStamp.day,vReg1.timeStamp.year,vReg1.timeStamp.hour,vReg1.timeStamp.min,vReg1.timeStamp.sec,vReg1.timeStamp.msec); anum=anum+8; for (txc=0;txc<vReg1.numDigital;txc++) { vReg1.digitalTargets[txc]=cbuf[anum+txc]; } clen=0; tapMinMax.putVal(vReg1.analogs[7].analog1Value); voltageMinMax.putVal(vReg1.analogs[9].analog1Value); voltageAvg.putVal(vReg1.analogs[9].analog1Value); break; } //Check fast demand meter configuration if ((cbuf[cbc]==0xA5) && (cbuf[cbc+1]==0xC2)) { sport0.write(cbuf,clen); //Ensure Analog channl count is correct if (vReg1.numDemAnalog!=cbuf[6]) { #ifdef netmsgdebug printf("\r\nDemand Analog Channel Count Off\r\n"); #endif clen=0; break; } char anum=18; char nxc; //Verify Analog names are correct for (txc=0;txc<vReg1.numDemAnalog;txc++) { for (nxc=0;nxc<6;nxc++) { if(vReg1.analogs[txc+vReg1.numAnalog].analogName[nxc]!=cbuf[anum+nxc]) { #ifdef netmsgdebug printf("\r\nPoint %d Failed\r\n",txc); #endif break; } } anum = anum + 11; } net2->configState=9; net2->fmdEnabled=true; clen=0; break; } //Receive demand data if ((cbuf[cbc]==0xA5) && (cbuf[cbc+1]==0xD2)) { char anum=cbc+4; for (txc=0;txc<vReg1.numDemAnalog;txc++) { valpack.bytes[3]=cbuf[anum]; valpack.bytes[2]=cbuf[anum+1]; valpack.bytes[1]=cbuf[anum+2]; valpack.bytes[0]=cbuf[anum+3]; vReg1.analogs[txc].analog1Value = valpack.cmdflt; anum = anum + 4; //printf("%.2f\r\n",vReg1.analogs[txc].analog1Value); } vReg1.demTimeStamp.month=cbuf[anum]; vReg1.demTimeStamp.day=cbuf[anum+1]; vReg1.demTimeStamp.year=cbuf[anum+2]; vReg1.demTimeStamp.hour=cbuf[anum+3]; vReg1.demTimeStamp.min=cbuf[anum+4]; vReg1.demTimeStamp.sec=cbuf[anum+5]; timepack.bytes[1]=cbuf[anum+6]; timepack.bytes[0]=cbuf[anum+7]; vReg1.demTimeStamp.msec=timepack.cmdshort; sport0.printf("%d/%d/%d %d:%d:%d.%d\r\n",vReg1.demTimeStamp.month,vReg1.demTimeStamp.day,vReg1.demTimeStamp.year,vReg1.demTimeStamp.hour,vReg1.demTimeStamp.min,vReg1.demTimeStamp.sec,vReg1.demTimeStamp.msec); vReg1.calculated[0].analog1Value=voltageMinMax.getMin(); vReg1.calculated[1].analog1Value=voltageAvg.getAvg(); vReg1.calculated[2].analog1Value=voltageMinMax.getMax(); vReg1.calculated[3].analog1Value=tapMinMax.getMin(); vReg1.calculated[4].analog1Value=tapMinMax.getMax(); sport0.printf("%.2f\r\n",vReg1.calculated[0].analog1Value); sport0.printf("%.2f\r\n",vReg1.calculated[1].analog1Value); sport0.printf("%.2f\r\n",vReg1.calculated[2].analog1Value); sport0.printf("%.2f\r\n",vReg1.calculated[3].analog1Value); sport0.printf("%.2f\r\n",vReg1.calculated[4].analog1Value); break; } } if (clen>0) { #ifdef netmsgdebug printf("Command not Received\r\n"); #endif clen=0; } } } } //Ethernet to Ethernet Send Data void datantx(netsys *net2) { while(1) { if (net2->cltIsActive) { //Attempt to connect to server while (net2->sendState==3) { //delay connect attempt if previous attempt unsuccessful if (net2->connectRetry == true) { wait_ms(100); } //Attempt to connectg ret = net2->srv_sock.connect(net2->srv_addr,net2->cltPort); //If connect successful proceed to send data if (ret==0) { net2->connectRetry = false; #ifdef netmsgdebug printf("Connected %d\r\n",ret); #endif net2->sendState=4; } //If connect attempt failed check to see if may already be connected else if (ret==-3015) { #ifdef netmsgdebug printf("May already be connected, attempting send.\r\n"); #endif net2->connectRetry = false; net2->sendState=4; } //If connect attempt failed on other error attempt reconnect else { net2->connectRetry = true; net2->sendRetryCount++; #ifdef netmsgdebug printf("Connect Attempt Failed, Code: %d\r\n",ret); #endif //If connect attempt failed exceeds 3 then end attempt if (net2->sendRetryCount>3) { #ifdef netmsgdebug printf("Communication Failed, Closing\r\n"); #endif net2->connectRetry = false; net2->sendRetryCount = 0; net2->messageFailCount++; net2->cltCloseConnection=true; net2->sendState=0; net2->sendTime=0; } } } //Attempt to send data while (net2->sendState==4) { //Delay send data attempt if previous attempt failed if (net2->sendRetry == true) { wait_ms(100); } //Attempt to send data ret = net2->srv_sock.send(net2->sendString,net2->sendLen); //If data send successful proceed to wait for response if (ret>=0) { #ifdef netmsgdebug printf("Send Result %d\r\n",ret); #endif net2->sendRetry = false; net2->txMessageCount++; net2->sendState=5; net2->sendTime=0; } //If send attempt failed attempt to re-send data else { net2->sendRetry = true; net2->sendRetryCount++; #ifdef netmsgdebug printf("Send Attempt Failed, Code: %d\r\n",ret); #endif //If send attempt failed exceeds 3 then end attempt if (net2->sendRetryCount>3) { #ifdef netmsgdebug printf("Communication Failed, Closing\r\n"); #endif net2->sendRetry = false; net2->sendRetryCount = 0; net2->messageFailCount++; net2->cltCloseConnection=true; net2->sendState=0; net2->sendTime=0; } } } } } } //Ethernet receive data and send to aux devices (serial, etc...) void datancrx(netsys *net2) { char rxbuf[256]; int rxlen=0; int rxc; while (1) { //If the client is active check to see if data has been received while (net2->cltIsActive) { //Store the length of the received data rxlen=net2->srv_sock.recv(rxbuf, sizeof(rxbuf)); //if there is data then push data into received buffer if (rxlen>0) { net2->aliveTime=0; for (rxc = 0;rxc<rxlen;rxc++) { receiveBuffer.push(rxbuf[rxc]); } #ifdef netmsgdebug printf("Client Received Data\r\n"); #endif //Increment received message counter net2->rxMessageCount++; } } } } //Ethernet receive data and send to aux devices (serial, etc...) void datansrx(netsys *net2) { char rxbuf[256]; int rxlen=0; int rxc; while (1) { //If the server is active check to see if data has been received while (net2->srvIsActive) { //Store the length of the received data rxlen=net2->clt_sock.recv(rxbuf, sizeof(rxbuf)); //if there is data then push data into received buffer if (rxlen>0) { net2->aliveTime=0; for (rxc = 0;rxc<rxlen;rxc++) { receiveBuffer.push(rxbuf[rxc]); } #ifdef netmsgdebug printf("Server Received Data\r\n"); #endif //Increment received message counter net2->rxMessageCount++; } } } } //Serial device to server void datasrx(netsys *net2) { char rxbuf[256]; int rxlen=0; int rxindex=0; int rxc; bool crRx = false; int4byte cmdpack; while (1) { //Check to see if there is any data received by serial port and store length rxlen=sport0.readable(); //If data is ready push into receive buffer if (rxlen>0) { for (rxc=0;rxc<rxlen;rxc++) { rxbuf[rxindex+rxc]=sport0.getc(); //Check to see if a carriage return has been detected if (rxbuf[rxindex+rxc]=='\r') { crRx=true; } } //Store the current cursor location in the buffer rxindex=rxindex+rxlen; //printf("%d\r\n",rxlen); //printf("%d\r\n",rxindex); //Set the received length to zero rxlen=0; //If there is data in the buffer and a carriage return has been detected search for a command if ((rxindex>2) && (crRx==true)) { //Set the carriage return flag false crRx=false; for (rxc=0;rxc<=rxindex-3;rxc++) { cmdpack.bytes[3]=rxbuf[rxc]; cmdpack.bytes[2]=rxbuf[rxc+1]; cmdpack.bytes[1]=rxbuf[rxc+2]; cmdpack.bytes[0]=rxbuf[rxc+3]; //printf("%08x\r\n",cmdpack.cmdint); //Search for the Min/Max command if (cmdpack.cmdint==0x4d45544d) { #ifdef netmsgdebug printf("MIN MAX METERING\r\n"); #endif net2->devMsgReq=1; net2->devMsgPos=2; rxindex=0; } //Search for the Tap Report Command if (cmdpack.cmdint==0x54415052) { #ifdef netmsgdebug printf("TAP REPORT\r\n"); #endif net2->devMsgReq=2; net2->devMsgPos=2; rxindex=0; } } //If no command found set cursor location to zero if (rxindex>0) { #ifdef netmsgdebug printf("Serial Command Not Found"); #endif rxindex=0; } } } } } //Checks for a Ethernet to Serial connection void conchk(netsys *net2) { TCPServer *server=&(net2->srv); TCPSocket *client_socket=&(net2->clt_sock); SocketAddress *client_address=&(net2->clt_addr); while(1) { //Wait for someone to connect while (server->accept(client_socket, client_address) < 0) { //printf("Connection Failed.\r\n"); } #ifdef netmsgdebug printf("Server Port %d\r\n", net2->srvPort); printf("accept %s:%d\r\n", client_address->get_ip_address(), client_address->get_port()); #endif net2->aliveTime=0; net2->srvIsActive=true; } } void sendCmd(char cmdNum) { sendLength.push(2); for (char txc=0;txc<2;txc++) { sendBuffer.push(fmCmd[cmdNum][txc]); } } int main() { EthernetInterface eth; eth.set_network(setseveraddress,setsevermask,setsevergateway); //Use these parameters for static IP eth.connect(); initVoltageRegulator(&vReg1); #ifdef netmsgdebug printf("The target IP address is '%s'\r\n", eth.get_ip_address()); #endif confignetdevices(ð); /* Setup Ethernet to Serial Connection Thread */ conchkthread[0].start(callback(conchk,&net1)); /* Setup polltick Ticker */ nettimer.attach_us(heartbeat,10000); /* Setup Ethernet to Serial transmit data Thread */ rxtxdatathread[0].start(callback(datansrx,&net1)); rxtxdatathread[1].start(callback(datancrx,&net1)); /* Setup Ethernet to Serial receive data Thread */ rxtxdatathread[2].start(callback(datasrx,&net1)); rxtxdatathread[3].start(callback(datantx,&net1)); rxtxdatathread[4].start(callback(dataprocess,&net1)); unsigned int txc; unsigned int sxc; while (true) { polltick=getTick(); if (polltick) { setTick(false); incTime(); currenttime=getTime(); net1.pollTime++; net1.fmPollTime++; net1.fmdPollTime++; net1.sendTime++; if (net1.srvIsActive) { net1.aliveTime++; if (net1.aliveTime>net1.aliveTimeout) { #ifdef netmsgdebug printf("Closed\r\n"); #endif net1.clt_sock.close(); net1.srvIsActive=false; net1.srvCloseConnection=false; } } if (net1.pollEnabled) { if (net1.pollTime >= setpollinterval) { if ((net1.sendState==0)||(net1.sendState==5)) { if (net1.devMsgReq>0) { net1.serTimeoutCount=0; sendLength.push(serCmdSeq[2][net1.devMsgPos]); for (txc=0;txc<serCmdSeq[2][net1.devMsgPos];txc++) { sendBuffer.push(serCmd[serCmdSeq[net1.devMsgReq-1][net1.devMsgPos]][txc]); } if (net1.serIsActive==false) { net1.serIsActive=true; } } else { if (net1.configState<9) { sendCmd(net1.configState); if (net1.sendState==0) { net1.sendState=1; net1.pollRequestSent=true; } } } } net1.pollTime=0; } if (net1.fmPollTime >= setfmpollinterval) { if (net1.serIsActive==false) { if ((net1.sendState==0)||(net1.sendState==5)) { { if (net1.fmEnabled) { sendCmd(2); if (net1.sendState==0) { net1.sendState=1; net1.pollRequestSent=true; } } } } if (net1.fmPollTime>setfmpollinterval) { net1.fmPollTime=net1.fmPollTime-setfmpollinterval; } else { net1.fmPollTime=0; } } } if (net1.fmdPollTime >= setfmdemandpollinterval) { if (net1.serIsActive==false) { if ((net1.sendState==0)||(net1.sendState==5)) { { if (net1.fmdEnabled) { sendCmd(4); if (net1.sendState==0) { net1.sendState=1; net1.pollRequestSent=true; } } } } if (net1.fmdPollTime>setfmdemandpollinterval) { net1.fmdPollTime=net1.fmdPollTime-setfmdemandpollinterval; } else { net1.fmdPollTime=0; } } } if ((net1.sendState==5) || (net1.serIsActive)) { net1.pollTimeout++; if (net1.pollTimeout==setpolltimeout) { if (net1.pollRequestSent) { #ifdef netmsgdebug printf("Poll Request Sent\r\n"); #endif if (net1.pollResponseReceived==false) { #ifdef netmsgdebug printf("Poll Response Not Received\r\n"); #endif } else { #ifdef netmsgdebug printf("Poll Response Received\r\n"); #endif } net1.pollRequestSent=false; net1.pollResponseReceived=false; if (net1.serIsActive==false) { net1.cltCloseConnection=true; net1.sendState=0; } } if (net1.serIsActive) { if ((net1.serTimeoutCount==sertimeoutperiods) || (net1.devMsgReq==0)) { net1.devMsgOpenRx=false; net1.cltCloseConnection=true; net1.devMsgReq=0; net1.serIsActive=false; net1.sendState=0; } else { net1.pollTimeout=0; net1.serTimeoutCount++; #ifdef netmsgdebug printf("Serial Active Timeout Count: %d\r\n",net1.serTimeoutCount); #endif } } } } else { net1.pollTimeout=0; } } if (net1.sendTime == 10) { switch (net1.sendState) { case 1: if (!sendLength.empty()) { sendLength.pop(net1.sendLen); for (sxc=0;sxc<net1.sendLen;sxc++) { sendBuffer.pop(net1.sendString[sxc]); } } else { net1.sendState=0; } ret=net1.srv_sock.open(ð); #ifdef netmsgdebug printf("Socket%d\r\n",ret); #endif if (ret < 0) { if (ret==-3003) { #ifdef netmsgdebug printf("May already be attached, attempting connect.\r\n"); #endif } else { net1.attachRetry = true; net1.sendRetryCount=0; net1.sendState=2; net1.sendTime=0; break; } } net1.sendState=3; net1.sendTime=11; net1.cltIsActive=true; break; case 2: ret=net1.srv_sock.open(ð); #ifdef netmsgdebug printf("Socket%d\r\n",ret); #endif if (ret < 0) { net1.attachRetry = true; net1.sendRetryCount++; net1.sendTime=0; #ifdef netmsgdebug printf("Attach Attempt Failed, Code: %d\r\n",ret); #endif if (net1.sendRetryCount>3) { #ifdef netmsgdebug printf("Communication Failed, Closing\r\n"); #endif net1.attachRetry = false; net1.sendRetryCount = 0; net1.messageFailCount++; net1.sendState=0; net1.sendTime=0; } break; } net1.sendState=0; net1.attachRetry = false; net1.sendTime=11; net1.cltIsActive=true; break; default: net1.sendTime=0; if (!sendLength.empty()) { if (net1.sendState==5) { sendLength.pop(net1.sendLen); for (sxc=0;sxc<net1.sendLen;sxc++) { sendBuffer.pop(net1.sendString[sxc]); } net1.sendState=4; } else { net1.sendState=1; } } break; } } } if (net1.cltCloseConnection==true) { #ifdef netmsgdebug printf("Client Socket Closed\r\n"); #endif net1.srv_sock.close(); net1.cltIsActive=false; net1.cltCloseConnection=false; net1.sendState=0; } } }