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:
- 2020-01-23
- Revision:
- 19:cae910c9c06a
- Parent:
- 18:69846c990e04
File content as of revision 19:cae910c9c06a:
#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" #include "netStatusReg.h" #include "voltageRegulator.h" Ticker nettimer; Timer netDevTimers[7]; struct netsys net1; netDevStatus netStat(0,0,0,0,0,setConsFailCount); voltageRegulator myDevice; bool polltick; bool sendtick; BufferedSerial sport0(sport0tx, sport0rx, rxtxbuffer, sport0mult); // UART2 CircularBuffer<char, rxtxbuffer> receiveBuffer; CircularBuffer<char, 256> unSolReceiveBuffer; CircularBuffer<char, 64> sendLength; CircularBuffer<char, 256> sendBuffer; Thread rxtxdatathread[4]; unsigned int currenttime=0; nsapi_error_t ret; //Provides the deivce poll timing void heartbeat() { setPollTick(true); //Provide Sender Task Tick if (netDevTimers[0].read_ms()>=100) { netDevTimers[0].reset(); setSendTick(true); } if (netStat.bit_isset(pollEnabled)) { if (netStat.bit_isset(devOnline)) { //Fast Demand Poll Tick if (netStat.bit_isset(fmdEnabled)) { if (netStat.bit_isset(fmdOnline)) { if (netDevTimers[2].read_ms()>=setfmdemandpollinterval) { netDevTimers[2].reset(); netStat.bit_toset(fmdPollReq); } } else { if (netDevTimers[2].read_ms()>=8000) { netDevTimers[2].reset(); netStat.bit_toset(fmdPollReq); } } } //Fast Meter Poll Tick if (netStat.bit_isset(fmEnabled)) { if (netStat.bit_isset(fmOnline)) { if (netDevTimers[3].read_ms()>=setfmpollinterval) { netDevTimers[3].reset(); netStat.bit_toset(fmPollReq); } } else { if (netDevTimers[3].read_ms()>=8000) { netDevTimers[3].reset(); netStat.bit_toset(fmPollReq); } } } if (netStat.bit_isset(recEnabled)) { if (netDevTimers[6].read_ms()>=setDataRecInterval) { netStat.bit_toset(recDataFile); netDevTimers[6].stop(); } } } else { if (netDevTimers[3].read_ms()>=8000) { netDevTimers[3].reset(); netStat.bit_toset(fmCfgReq); } } } //Fast Message Timeout if ((netStat.bit_isset(fmCfgInProg)) || (netStat.bit_isset(fmPollInProg)) || (netStat.bit_isset(fmdPollInProg))) { if (netDevTimers[4].read_ms()>=2000) { netDevTimers[4].stop(); netStat.bit_toset(fmCloseConnection); netStat.bit_toset(fmTimeout); } } //Serial Message Timeout if (netStat.bit_isset(serPollInProg)) { if (netDevTimers[5].read_ms()>=net1.serMsgTimeout) { netDevTimers[5].stop(); netStat.bit_toset(serCloseConnection); netStat.bit_toset(serTimeout); } } } void sendCmd(char cmdNum) { sendLength.push(2); for (char txc=0;txc<2;txc++) { sendBuffer.push(fmCmd[cmdNum][txc]); } } void sendSerCmd(char cmdNum, char cmdCnt) { sendLength.push(cmdCnt); for (char txc=0;txc<cmdCnt;txc++) { sendBuffer.push(serCmd[cmdNum][txc]); } } void confignetdevices(EthernetInterface *eth) { #ifdef sportEnabled netStat.bit_toset(serEnabled); #endif #ifdef setPollEnabled netStat.bit_toset(pollEnabled); #endif #ifdef fastMeterEnabled netStat.bit_toset(fmEnabled); #endif #ifdef fastDemandEnabled netStat.bit_toset(fmdEnabled); #endif #ifdef recordDataEnabled netStat.bit_toset(recEnabled); #endif net1.cltPort=setclientport; net1.srv_addr=setclientaddress; net1.srv_sock.set_blocking(false); net1.srv_sock.set_timeout(100); net1.sendRetryCount=0; net1.messageFailCount=0; net1.serMsgTimeout=2000; /* Open the server on ethernet stack */ net1.srv.open(eth); sport0.baud(sport0baud); } void dataprocess(netsys *net2) { char cchar; char cbuf[rxtxbuffer]; unsigned int clen=0; unsigned int cbc; 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 netStat.bit_sis(serPollInProg,serRespRx); netStat.bit_sis(fmPollInProg,fmRespRx); netStat.bit_sis(fmdPollInProg,fmdRespRx); //Check to see if bulk data and reports being sent from device due to serial command if (netStat.bit_isset(serMsgRx)) { while (!receiveBuffer.empty()) { receiveBuffer.pop(cchar); sport0.putc(cchar); //cbuf[clen]=cchar; //clen++; } /*if (clen>0) { sport0.write(cbuf,clen); netDevTimers[5].reset(); clen=0; netStat.iedOnline(true); }*/ } else { while (!receiveBuffer.empty()) { receiveBuffer.pop(cchar); cbuf[clen]=cchar; clen++; } } //Check to see if at least 4 characters have been received if (clen>3) { //Cycle through received data to search for a command for (cbc=0;cbc<clen-3;cbc++) { //Check fast message configuration if ((cbuf[cbc]==0xA5) && (cbuf[cbc+1]==0xC0)) { sport0.write(cbuf,clen); if (myDevice.chkCfgMsg(cbuf,clen)) { //netStat.bit_toclear(fmCfgInProg); netStat.bit_toset(devOnline); clen=0; netStat.iedOnline(true); } break; } //Check to see if serial commands are currently being received if (netStat.bit_isset(serPollInProg)) { //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); netStat.bit_toset(serMsgRx); netDevTimers[5].reset(); netStat.setDevMsgReq(0); clen=0; netStat.iedOnline(true); 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); netStat.bit_toset(serMsgRx); netDevTimers[5].reset(); netStat.setDevMsgReq(0); clen=0; netStat.iedOnline(true); 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); netStat.setDevMsgPos(1); sendSerCmd(serCmdSeq[netStat.getDevMsgReq()][netStat.getDevMsgPos()],serCmdlen[netStat.getDevMsgReq()][netStat.getDevMsgPos()]); netDevTimers[5].reset(); clen=0; netStat.iedOnline(true); break; } //If relay sends mask character increment command pointer to send \r\n if (cbuf[cbc]==0x2a) { sport0.write(cbuf,clen); netStat.setDevMsgPos(2); sendSerCmd(serCmdSeq[netStat.getDevMsgReq()][netStat.getDevMsgPos()],serCmdlen[netStat.getDevMsgReq()][netStat.getDevMsgPos()]); netDevTimers[5].reset(); clen=0; netStat.iedOnline(true); 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); netStat.setDevMsgPos(4); sendSerCmd(serCmdSeq[netStat.getDevMsgReq()][netStat.getDevMsgPos()],serCmdlen[netStat.getDevMsgReq()][netStat.getDevMsgPos()]); netDevTimers[5].reset(); clen=0; netStat.iedOnline(true); break; } //If relay in level 0 increment command pointer to access command if ((cbuf[cbc]==0x3d)) { sport0.write(cbuf,clen); netStat.setDevMsgPos(0); sendSerCmd(serCmdSeq[netStat.getDevMsgReq()][netStat.getDevMsgPos()],serCmdlen[netStat.getDevMsgReq()][netStat.getDevMsgPos()]); netDevTimers[5].reset(); clen=0; netStat.iedOnline(true); break; } } //if (bit_isset(net2->statusReg,fmPollInProg)) if (netStat.bit_isset(fmPollInProg)) { //Check fast meter configuration if ((cbuf[cbc]==0xA5) && (cbuf[cbc+1]==0xC1)) { sport0.write(cbuf,clen); if (myDevice.chkMeterMsg(cbuf,clen)) { netStat.bit_toset(fmOnline); clen=0; netStat.iedOnline(true); break; } break; } //Receive data if ((cbuf[cbc]==0xA5) && (cbuf[cbc+1]==0xD1)) { myDevice.setMeterData(cbuf, cbc,clen); clen=0; netStat.iedOnline(true); break; } } if (netStat.bit_isset(fmdPollInProg)) { //Check fast demand meter configuration if ((cbuf[cbc]==0xA5) && (cbuf[cbc+1]==0xC2)) { sport0.write(cbuf,clen); if (myDevice.chkDemMeterMsg(cbuf,clen)) { netStat.bit_toset(fmdOnline); clen=0; netStat.iedOnline(true); break; } break; } //Receive demand data if ((cbuf[cbc]==0xA5) && (cbuf[cbc+1]==0xD2)) { myDevice.setDemMeterData(cbuf, cbc,clen); netStat.iedOnline(true); 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 (netStat.bit_isset(cltIsActive)) { //Attempt to connect to server while (net2->sendState==3) { //Attempt to connect ret = net2->srv_sock.connect(net2->srv_addr,net2->cltPort); //If connect successful proceed to send data if (ret==0) { #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->sendState=4; } else { #ifdef netmsgdebug printf("Communication Failed, Closing\r\n"); #endif net2->sendRetryCount = 0; netStat.iedOnline(false); netStat.bit_toset(cltCloseConnection); net2->sendState=0; } } //Attempt to send data while (net2->sendState==4) { if (net2->sendLen>0) { //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) { net2->sendLen=0; #ifdef netmsgdebug printf("Send Result %d\r\n",ret); #endif netStat.incCount(1); net2->sendState=5; } else { #ifdef netmsgdebug printf("Communication Failed, Closing\r\n"); #endif net2->sendRetryCount = 0; netStat.iedOnline(false); netStat.bit_toset(cltCloseConnection); net2->sendState=0; } } else { net2->sendState=5; } } } } } //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 (netStat.bit_isset(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) { for (rxc = 0;rxc<rxlen;rxc++) { receiveBuffer.push(rxbuf[rxc]); } #ifdef netmsgdebug printf("Client Received Data\r\n"); #endif //Increment received message counter netStat.incCount(2); } } } } //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++) { #ifdef netmsgdebug printf("Serial Data Received\r\n"); #endif 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; //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]; //Search for the Min/Max command if (cmdpack.cmdint==0x4d45544d) { #ifdef netmsgdebug printf("MIN MAX METERING\r\n"); #endif netStat.setDevMsgReq(0); netStat.setDevMsgPos(2); netStat.bit_toset(serPollReq); rxindex=0; } //Search for the Tap Report Command if (cmdpack.cmdint==0x54415052) { #ifdef netmsgdebug printf("TAP REPORT\r\n"); #endif netStat.setDevMsgReq(1); netStat.setDevMsgPos(2); netStat.bit_toset(serPollReq); rxindex=0; } //Search for the Status Command if (cmdpack.cmdint==0x53544154) { #ifdef netmsgdebug printf("STATS\r\n"); #endif sport0.printf("\r\nStatus %08x\r\n",netStat.getStatus()); sport0.printf("Messages Sent: %d\r\n",netStat.getCount(1)); sport0.printf("Messages Received: %d\r\n",netStat.getCount(2)); sport0.printf("Fast Message Timeouts: %d\r\n",netStat.getCount(3)); sport0.printf("Serial Timeouts: %d\r\n",netStat.getCount(4)); sport0.printf("Messages Failed: %d\r\n\r\n",netStat.getCount(5)); rxindex=0; } //Search for the Target Command if (cmdpack.cmdint==0x54415247) { char *dTargets; #ifdef netmsgdebug printf("Targets\r\n"); #endif sport0.printf("\r\nTarget 0 %08x\r\n",dTargets[0]); sport0.printf("\r\nTarget 1 %08x\r\n",dTargets[1]); sport0.printf("\r\nTarget 2 %08x\r\n",dTargets[2]); sport0.printf("\r\nTarget 3 %08x\r\n",dTargets[3]); sport0.printf("\r\nTarget 4 %08x\r\n",dTargets[4]); sport0.printf("\r\nTarget 5 %08x\r\n",dTargets[5]); sport0.printf("\r\nTarget 6 %08x\r\n",dTargets[6]); sport0.printf("\r\nTarget 7 %08x\r\n",dTargets[7]); sport0.printf("\r\nTarget 8 %08x\r\n",dTargets[8]); sport0.printf("\r\nTarget 9 %08x\r\n",dTargets[9]); rxindex=0; } } //If no command found set cursor location to zero if (rxindex>0) { #ifdef netmsgdebug printf("Serial Command Not Found"); #endif rxindex=0; } } } } } 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 polltick Ticker */ nettimer.attach_us(heartbeat,10000); /* Setup Ethernet to Serial transmit data Thread */ rxtxdatathread[0].start(callback(datancrx,&net1)); /* Setup Ethernet to Serial receive data Thread */ rxtxdatathread[1].start(callback(datasrx,&net1)); rxtxdatathread[2].start(callback(datantx,&net1)); rxtxdatathread[3].start(callback(dataprocess,&net1)); unsigned int sxc; netDevTimers[0].start(); netDevTimers[2].start(); netDevTimers[3].start(); netDevTimers[6].start(); while (true) { polltick=getPollTick(); if (polltick) { setPollTick(false); if (netStat.bit_isset(serCloseConnection)) { #ifdef netmsgdebug printf("Serial Connection Closed\r\n"); #endif if (netStat.bit_isset(serRespRx)) { netStat.incCount(2); } else { netStat.incCount(4); } netStat.bit_toclear(serclose); netStat.bit_toset(cltCloseConnection); } if (netStat.bit_isset(fmCloseConnection)) { #ifdef netmsgdebug printf("Fast Meter Connection Closed\r\n"); #endif if ((netStat.bit_isset(fmRespRx)) || (netStat.bit_isset(fmdRespRx))) { netStat.incCount(2); } else { netStat.incCount(3); } netStat.bit_toclear(fmclose); netStat.bit_toset(cltCloseConnection); } if (netStat.bit_isset(cltCloseConnection)) { sport0.printf("Status %08x\r\n",netStat.getStatus()); #ifdef netmsgdebug printf("Connection Closed\r\n"); #endif net1.srv_sock.close(); net1.sendState=0; netStat.bit_toclear(cltclose); } if ((netStat.bit_isclear(serPollInProg)) && (netStat.bit_isclear(fmPollInProg)) && (netStat.bit_isclear(fmdPollInProg))) { if (netStat.bit_isset(recDataFile)) { char dataStrLen=0; char dataStr[256]; dataStrLen=myDevice.getMeterReport(&dataStr[0]); sport0.write(dataStr,dataStrLen); netStat.bit_toclear(recDataFile); netDevTimers[6].reset(); netDevTimers[6].start(); } if ((net1.sendState==0) || (net1.sendState==5)) { if ((netStat.bit_isset(fmdPollReq)) && (netStat.bit_isset(devOnline))) { if (netStat.bit_isset(fmdOnline)) { printf("Demand Reading\r\n"); sendCmd(4); netStat.bit_toclear(fmdPollReq); netStat.bit_toset(fmdPollInProg); } else { printf("Demand Configuration\r\n"); sendCmd(3); netStat.bit_toclear(fmdPollReq); netStat.bit_toset(fmdPollInProg); } netDevTimers[4].reset(); netDevTimers[4].start(); } else if (netStat.bit_isset(serPollReq)) { if (netStat.bit_isset(serEnabled)) { sendSerCmd(serCmdSeq[netStat.getDevMsgReq()][netStat.getDevMsgPos()],serCmdlen[netStat.getDevMsgReq()][netStat.getDevMsgPos()]); netStat.bit_toclear(serPollReq); netStat.bit_toset(serPollInProg); netDevTimers[5].reset(); netDevTimers[5].start(); } else { netStat.bit_toclear(serPollReq); } } else if ((netStat.bit_isset(fmPollReq)) && (netStat.bit_isset(devOnline))) { if (netStat.bit_isset(fmOnline)) { printf("Meter Reading\r\n"); sendCmd(2); netStat.bit_toclear(fmPollReq); netStat.bit_toset(fmPollInProg); } else { printf("Meter Configuration\r\n"); sendCmd(1); netStat.bit_toclear(fmPollReq); netStat.bit_toset(fmPollInProg); } netDevTimers[4].reset(); netDevTimers[4].start(); } } } if ((netStat.bit_isclear(devOnline)) && (netStat.bit_isclear(fmCfgInProg)) && (netStat.bit_isset(fmCfgReq))) { sendCmd(0); netStat.bit_toclear(fmCfgReq); netStat.bit_toset(fmCfgInProg); net1.sendState=1; netDevTimers[4].reset(); netDevTimers[4].start(); } } //Begin Sending Data sendtick=getSendTick(); if (sendtick) { setSendTick(false); switch (net1.sendState) { case 0: if (!sendLength.empty()) { sport0.printf("Status %08x\r\n",netStat.getStatus()); sendLength.pop(net1.sendLen); for (sxc=0;sxc<net1.sendLen;sxc++) { sendBuffer.pop(net1.sendString[sxc]); } net1.sendState=1; } break; case 1: 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 { #ifdef netmsgdebug printf("Communication Failed, Closing\r\n"); #endif net1.sendRetryCount = 0; netStat.iedOnline(false); net1.sendState=0; break; } } net1.sendState=3; netStat.bit_toset(cltIsActive); break; case 5: if (!sendLength.empty()) { sport0.printf("Status %08x\r\n",netStat.getStatus()); sendLength.pop(net1.sendLen); for (sxc=0;sxc<net1.sendLen;sxc++) { sendBuffer.pop(net1.sendString[sxc]); } net1.sendState=4; } break; default: break; } } } }