Dear All fellows.
I am trying to implement an IEC-60870-5-104 RTU at my Arduino UNO R3 board. For this purpose, I am using standard Ethernet.h library with Ethernet shield. When I implement the whole protocol in cyclic pattern i.e. no external hardware interrupts so it works fine. Similarly when I program it with external interrupts only (no cyclic running) again it works fine. But actual IEC 104 protocol uses both routines i.e. Cyclic running where it exchanges control messages with client master using client.read() function, and whenever any hardware interrupt occurs it must stop the cyclic running and send the data to client using client.write function. When I try to run both routines at a time, it does not work. What I conclude from the debugging that client.read(); and client.write functions could not be used in the pattern what I am programming and this is causing problem. To summarize, client.read is in the loop() function while client. write() function is in the ISR.
Please have a look at the following code:
#include <Ethernet.h>
byte mac[] = {0x90, 0xA2, 0xDA, 0x0E, 0x94, 0xB7 }; // MAC Address,
IPAddress ip(172, 31, 15, 2); // ip address of the monitored device or RTU
IPAddress gateway(172, 31,15, 1); // IP Address of Gateway, My Laptop or in network it may be Router.
IPAddress subnet(255, 255, 255, 248); // Subnet Mask
EthernetClient client; // It creates a Client instance,
EthernetServer iec104Server(2404); // for IEC 670-5-104- port- 2404, this is our RTU
uint8_t iec104ReciveArray[24]; //Incoming buffer,
uint8_t iec104SPI1[24]; //IEC data to be exchanged with client
int txcnt = 0; //counters of transmitted packets, 2 bytes each
int rxcnt = 0; //counters of received packets, 2 bytes each
uint8_t MessageLength;
// to avoid switch debouncing
long debouncing_time = 10; //Debouncing Time in Milliseconds
volatile unsigned long last_micros;
void setup()
{
pinMode(2, INPUT); //using pin 2 as harware interrupt, coupled with pin 4
pinMode(4, INPUT);
attachInterrupt(0,debounceInterrupt,CHANGE);// for spontaneous input
//server creation
Ethernet.begin(mac, ip, gateway, subnet); // Ethernet device initialization
}
void loop()
{
client = iec104Server.available();
if(client.available())
{
iec104ReciveArray[6]=00;
int i = 0;
while(client.available())
{
iec104ReciveArray = client.read();//write data to the receive buffer
- i++;*
- }*
} - delay(20);*
if(iec104ReciveArray[2]==7)
STARTDTCON();
else if(iec104ReciveArray[2]==67)
TESTTFRCON();
}
// To avoid Switch Debouncing
void debounceInterrupt()
{
if((long)(micros() - last_micros) >= debouncing_time * 1000)
- {*
- SPONT(); // calling the send to client function for spontaneous data*
- last_micros = micros();*
- }*
}
void SPONT()
{ - bitWrite( iec104SPI1[15], 0, digitalRead( 4 )); // reads Pin 4 status*
- iec104SPI1[0]=104;*
- iec104SPI1[1]=14;//APDU length = APCI (4) + ASDU (10), M_SP_NA_1*
- iec104SPI1[2]=lowByte(txcnt);*
- iec104SPI1[3]=highByte(txcnt);*
- iec104SPI1[4]=lowByte(rxcnt);*
- iec104SPI1[5]=highByte(rxcnt);*
- iec104SPI1[6]=1;//type 1, M_SP_NA_1*
- iec104SPI1[7]=1;//no. of objects*
- iec104SPI1[8]=3;//Spontaneous*
- iec104SPI1[9]=00;//OA*
- iec104SPI1[10]=01;// CA*
- iec104SPI1[11]=00;// CA*
- iec104SPI1[12]=00;//IOA*
- iec104SPI1[13]=02;//IOA*
- iec104SPI1[14]=00;//IOA*
- txcnt=txcnt+2;*
- client.write(iec104SPI1, 16);*
- i=0;*
}
void STARTDTCON() // a function to send Start Data Confirmation message to client
{ - rxcnt=0;*
- txcnt=0;*
- iec104ReciveArray[2]=11;//type APDU, its STARTDT Confirmation U-Frame 68 04 0B 00 00 00,*
- MessageLength = iec104ReciveArray[1]+2;//message length + 2 bytes Start and Lenght APCI,*
- client.write(iec104ReciveArray, MessageLength);//sending back*
}
void TESTTFRCON() // a function to send a test transfer confirmation message to client.
{ - iec104ReciveArray[2] =131; //TI for TESTFR con, remains same*
- MessageLength = iec104ReciveArray[1]+2;*
- client.write(iec104ReciveArray, MessageLength);*
}