rllib  1
rldf1.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  rldf1.cpp - description
3  -------------------
4 
5 This Class implements basic functions of DF1 Full Duplex protocall as
6 described in 1770-6.5.16 Publication of AB.
7 
8 This Class implements:
9  - Data Link Layer ( Message Frames )
10  - Application Layer ( Message Packets )
11  - Some Basic Communication Commands for reading and writting PLC files.
12  It is easy to add more Communication Commands.
13 
14 Some basic knowledge about the related PLCs is required.
15 The class supports only serial communication through RS232 port.
16 
17 DANGER: DON'T connect to a PLC unless you are certain it is safe to do so!!!
18 You are ABSOLUTELY RESPONSIBLE if you affect the operation of a running PLC.
19 
20 Evangelos Arkalis
21 mail:arkalis.e@gmail.com
22 ***************************************************************************/
23 
24 /***************************************************************************
25  * *
26  * This library is free software; you can redistribute it and/or modify *
27  * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as *
28  * published by the Free Software Foundation *
29  * *
30  ***************************************************************************/
31 
32 #include "rldf1.h"
33 #include <time.h>
34 
35 //#define DF1_DEBUG
36 
37 
38 #ifdef DF1_DEBUG
39 #define DBGPRINTF(x...) {printf(x);fflush(stdout);}
40 #else
41 #define DBGPRINTF(x...)
42 #endif
43 /*
44  df1Buffer
45  Simple buffer with DLE encoding for DF1 implementation
46 */
47 class df1Buffer
48 {
49  public:
50  df1Buffer(unsigned int maxsize=256);
51  virtual ~df1Buffer();
52  protected:
53  private:
54  unsigned int maxsize;
55  unsigned int len;
56  unsigned char *dat;
57  public:
58  unsigned int length() {return len;}
59  unsigned char *data() {return dat;}
60  unsigned int write( unsigned char c);
61  unsigned int writeDLE( unsigned char c);
62  unsigned char& operator [] (unsigned int pos);
63  void reset() {len=0;}
64  void print();
65 };
66 df1Buffer::df1Buffer( unsigned int _maxsize)
67 {
68  dat = new unsigned char[_maxsize];
69  maxsize = _maxsize;
70  len=0;
71 }
72 
74 {
75  delete [] dat;
76 }
77 
78 unsigned int df1Buffer::write( unsigned char c)
79 {
80  if (len+1<maxsize) {
81  dat[len] = c;
82  len++;
83  }
84  return len;
85 }
86 
87 unsigned int df1Buffer::writeDLE( unsigned char c)
88 {
89  if (len+1<maxsize) {
90  if (c==0x10) {
91  dat[len]=c;
92  len++;
93  }
94  dat[len] = c;
95  len++;
96  }
97  return len;
98 }
99 
100 unsigned char& df1Buffer::operator [] (unsigned int pos)
101 {
102  if ( pos>=len ) {
103  printf("*** rlBuffer read error! Pos:%u Len:%u\n", pos,len);
104  }
105  return dat[pos];
106 }
107 
109 {
110  printf("Buffer [%d]:",len);
111  if(len>0) {
112  for(int i=0; i<(int)len; i++) printf(" %02X", (unsigned int)dat[i]);
113  }
114  printf("\n");
115 }
116 /*-----------------------------------------------------------------------------------*/
117 // CRC COMPUTING
118 static unsigned short calcCRC (unsigned short crc, unsigned short buffer)
119 {
120  unsigned short temp1, y;
121  temp1 = crc ^ buffer;
122  crc = (crc & 0xff00) | (temp1 & 0xff);
123  for (y = 0; y < 8; y++) {
124  if (crc & 1) {
125  crc = crc >> 1;
126  crc ^= 0xa001;
127  } else
128  crc = crc >> 1;
129  }
130  return crc;
131 }
132 
133 static unsigned short computeCRC (const unsigned char *buffer, int len)
134 {
135  unsigned short crc = 0;
136  for (int x=0; x<len; x++) {
137  crc = calcCRC(crc, (unsigned short)buffer[x] );
138  }
139  crc = calcCRC (crc,0x03); // ETX
140  return (crc);
141 }
142 
143 /*-----------------------------------------------------------------------------------*/
144 
145 rlDF1::rlDF1( unsigned char src, int _timeout )
146 {
147  source = src;
148  timeout=_timeout;
149  tty = NULL;
150  active = false;
151  nRequests = 0;
152  nResponses = 0;
153  tns = (unsigned short) time((time_t *)0);
154 }
155 
157 {
158 }
159 
161 {
162  tty = serial;
163 }
164 
165 int rlDF1::writeBuffer( unsigned char *buffer, int len )
166 {
167  int ret=-1;
168  if ( tty!=NULL) {
169  ret = tty->writeBlock( buffer, len );
170  }
171  return ret;
172 }
173 
175 {
176  int ret=-1;
177  if ( tty!=NULL) {
178  ret = tty->writeBlock( buffer.data(), buffer.length() );
179  }
180  return ret;
181 }
182 
183 
184 int rlDF1::getSymbol(unsigned char *c)
185 {
186 
187  int ret = tty->readBlock( c, 1, timeout);
188  if (ret<=0) return FLAG_TIMEOUT;
189  if (*c!=DLE) {
190  return FLAG_DATA;
191  } else {
192  ret = tty->readBlock( c, 1, timeout);
193  if (ret<=0) return FLAG_TIMEOUT;
194  if (*c==DLE) {
195  return FLAG_DATA;
196  } else {
197  return FLAG_CONTROL;
198  }
199 
200  }
201 }
202 
203 int rlDF1::get(unsigned char *c)
204 {
205 
206  int ret = tty->readBlock( c, 1, timeout);
207  if (ret<=0) return FLAG_TIMEOUT;
208  return FLAG_DATA;
209 }
210 
212 {
213  static unsigned char buf[2];
214  DBGPRINTF("\nsendENQ()");
215  buf[0] = DLE;
216  buf[1] = ENQ;
217  return writeBuffer( buf, 2 );
218 }
219 
221 {
222  static unsigned char buf[2];
223  DBGPRINTF("\nsendACK()");
224  buf[0] = DLE;
225  buf[1] = ACK;
226  return writeBuffer( buf, 2 );
227 }
228 
230 {
231  static unsigned char buf[2];
232  DBGPRINTF("\nsendNAC()");
233  buf[0] = DLE;
234  buf[1] = NAC;
235  return writeBuffer( buf, 2 );
236 }
237 
238 
239 
240 int rlDF1::cmdSetCPUMode(unsigned char destination, unsigned char mode)
241 {
242 
243  unsigned char cdat[256];
244  cdat[0]=0x3A;
245  cdat[1]=mode;
246  int ret = sendCommand( destination, 0x0F, 0x00, cdat, 2);
247  if (ret==retSUCCESS) {
248  unsigned char dest,cmd,sts,len;
249  ret = receiveAnswer( dest, cmd, sts, cdat, len);
250  if (sts!=0) {
251  printf("\nSet CPU Mode Execution Error! STS:%02X",sts);
252  }
253  }
254  return ret;
255 }
256 
257 int rlDF1::cmdDiagnosticStatus( unsigned char destination, unsigned char *buffer)
258 {
259  unsigned char cdat[256];
260  cdat[0]=0x03;
261  int ret = sendCommand( destination, 0x06, 0x00, cdat, 1);
262  if (ret==retSUCCESS) {
263  unsigned char dest,cmd,sts,len;
264  ret = receiveAnswer( dest, cmd, sts, cdat, len);
265  if ( ret == retSUCCESS ) {
266  for (int i=0;i<len;i++) buffer[i]=cdat[i];
267  ret = len;
268  }
269  }
270  return ret;
271 }
272 
273 int rlDF1::cmdLogicalRead( unsigned char destination, unsigned char nsize, unsigned char filetype, unsigned char filenum, unsigned char adr, unsigned char sadr, unsigned char *buffer)
274 {
275  unsigned char cdat[256];
276  cdat[0]=0xA2;
277  cdat[1]=nsize;
278  cdat[2]=filenum;
279  cdat[3]=filetype;
280  cdat[4]=adr;
281  cdat[5]=sadr;
282  int ret = sendCommand( destination , 0x0F, 0x00, cdat, 6);
283  if (ret==retSUCCESS) {
284  unsigned char dest,cmd,sts,len;
285  ret = receiveAnswer( dest, cmd, sts, cdat, len);
286  if ( ret == retSUCCESS ) {
287  for (int i=0;i<len;i++) buffer[i]=cdat[i];
288  ret = len;
289  }
290  if (sts!=0) ret = retERROR_STS;
291  }
292  return ret;
293 }
294 int rlDF1::cmdLogicalWrite( unsigned char destination, unsigned char nsize, unsigned char filetype, unsigned char filenum, unsigned char adr, unsigned char sadr, unsigned char *buffer)
295 {
296  unsigned char cdat[256];
297  cdat[0]=0xAA;
298  cdat[1]=nsize;
299  cdat[2]=filenum;
300  cdat[3]=filetype;
301  cdat[4]=adr;
302  cdat[5]=sadr;
303  for (int i=0;i<nsize;i++) cdat[6+i] = buffer[i];
304  int ret = sendCommand( destination, 0x0F, 0x00, cdat, 6+nsize);
305  if (ret==retSUCCESS) {
306  unsigned char dest,cmd,sts,len;
307  ret = receiveAnswer( dest, cmd, sts, cdat, len);
308  if ( ret == retSUCCESS ) {
309  for ( int i=0;i<len;i++) buffer[i] = cdat[i];
310  ret = len;
311  }
312  if (sts!=0) ret = retERROR_STS;
313  }
314  return ret;
315 }
316 //-------------------------------------------------------------------------------
317 
318 
319 int rlDF1::sendCommand( unsigned char destination, unsigned char cmd, unsigned char sts, unsigned char *cdata, unsigned char len)
320 {
321  df1Buffer msg;
322  df1Buffer fullmsg;
323  unsigned short crc;
324 
325  tns++;
326  nRequests++;
327  DBGPRINTF("\n\tDF1::sendCommand >");
328  DBGPRINTF(" Dest:%02X", destination);
329  DBGPRINTF(" CMD:%02X", cmd);
330  DBGPRINTF(" STS:%02X", sts);
331  DBGPRINTF(" TNS:%04X", tns);
332  DBGPRINTF(" DATA [%d]: ",len);
333  for (int i=0; i<len; i++) { DBGPRINTF("[%02X] ",cdata[i]); }
334  msg.write( destination );
335  msg.write( source );
336  msg.write( cmd );
337  msg.write( sts );
338  msg.write( (unsigned char)(tns&0x00FF) );
339  msg.write( (unsigned char)(tns>>8) );
340  for(int i=0; i<len; i++) msg.write( cdata[i] );
341  //msg.print();
342  crc = computeCRC( msg.data(), msg.length() );
343  DBGPRINTF(" [CRC=%04X] ",crc);
344  fullmsg.write( DLE );
345  fullmsg.write( STX );
346  for(int i=0; i<(int)msg.length(); i++) fullmsg.writeDLE( *(msg.data()+i) );
347  fullmsg.write( DLE );
348  fullmsg.write( ETX );
349  fullmsg.write( (unsigned char)(crc&0x00FF) );
350  fullmsg.write( (unsigned char)(crc>>8) );
351 
352  // TRANSMIT LOOP
353  int naks=0;
354  int enq=0;
355  int flag;
356  unsigned char rxc;
357  int ret;
358  writeBuffer( fullmsg );
359  while(1) {
360  flag = getSymbol(&rxc);
361  if (( flag==FLAG_CONTROL )&&( rxc == ACK )) {
362  DBGPRINTF(" -> ACK RECEIVED");
363  ret = retSUCCESS;
364  break;
365  } else if (( flag==FLAG_CONTROL )&&( rxc == NAC )) {
366  naks++;
367  DBGPRINTF(" -> NAK RECEIVED:%d",naks);
368  if (naks>=3) {
369  ret = retERROR_NAC;
370  break;
371  }
372  writeBuffer( fullmsg );
373  } else if ( flag == FLAG_TIMEOUT ) {
374  enq++;
375  DBGPRINTF(" -> TIMEOUT ENQ:%d",enq);
376  if (enq>=3) {
377  ret = retNORESPONSE;
378  break;
379  }
380  sendENQ();
381  }
382  }
383  return ret;
384 }
385 
386 int rlDF1::receiveAnswer( unsigned char &destination, unsigned char &cmd, unsigned char &sts, unsigned char *cdata, unsigned char &len)
387 {
388  int ret;
389  static unsigned char response=NAC;
390  df1Buffer msg;
391  int flag;
392  unsigned char rxc;
393 
394  DBGPRINTF("\n\tDF1::receiveAnswer >");
395  while(1) {
396  flag = getSymbol(&rxc);
397  if ( flag == FLAG_TIMEOUT ) {
398  DBGPRINTF("\nreceiveAnswer() Timeout....");
399  ret = retNORESPONSE;
400  break;
401 
402  } else if ( ( flag==FLAG_CONTROL) && ( rxc == STX) ) {
403 
404  DBGPRINTF(" DLE STX >")
405  msg.reset();
406  while ( (flag=getSymbol(&rxc))==FLAG_DATA ) {
407  DBGPRINTF("[%02X]", rxc);
408  msg.write(rxc);
409  }
410  if ( rxc != ETX ) {
411  DBGPRINTF(" [NO ETX] ");
412  sendNAC();
413  response = NAC;
414  continue;
415  }
416  DBGPRINTF(" ETX \n\t");
417  flag = get(&rxc);
418  if ( flag == FLAG_TIMEOUT) {
419  sendNAC();
420  response = NAC;
421  continue;
422  }
423  DBGPRINTF(" CRCLH:[%02X", rxc);
424  unsigned short crc = (unsigned short)rxc;
425  flag = get(&rxc);
426  if ( flag == FLAG_TIMEOUT) {
427  sendNAC();
428  response = NAC;
429  continue;
430  }
431  DBGPRINTF(":%02X] ", rxc);
432  crc += ( (unsigned short)rxc )<<8;
433  if ( crc != computeCRC( msg.data(), msg.length() ) ) {
434  DBGPRINTF(" [CRC ERROR] ");
435  sendNAC();
436  response = NAC;
437  continue;
438  }
439  unsigned short tns_ = (unsigned short)msg[POS_TNSL];
440  tns_ += ( (unsigned short)msg[POS_TNSH] )<<8;
441  DBGPRINTF(" TNS:[%04X] ", tns_);
442  if ( tns_ != tns ) {
443  DBGPRINTF(" [TNS ERROR] ");
444  sendACK();
445  response = ACK;
446  ret = retERROR_TNS;
447  break;
448  }
449  /* STS is a software error. Handle it in upper layer!
450  if ( msg[POS_STS]!=0 ) {
451  DBGPRINTF(" [STS=%02X != 0] ",msg[POS_STS]);
452  sendACK();
453  response = ACK;
454  ret = retERROR_STS;
455  break;
456  }
457  */
458  destination = msg[POS_DST];
459  cmd = msg[POS_CMD];
460  sts = msg[POS_STS];
461  len = msg.length()-6;
462  for (int i=0; i<len; i++) cdata[i] = msg[i + POS_DATA];
463  sendACK();
464  nResponses++;
465  response = ACK;
466  ret = retSUCCESS;
467  break;
468  } else if ( ( flag==FLAG_CONTROL) && ( rxc == ENQ) ) {
469  if (response==ACK) sendACK(); else sendNAC();
470  ret = retERROR;
471  break;
472  } else {
473  response = NAC;
474  }
475 
476  }
477  return ret;
478 }
int nRequests
Definition: rldf1.h:195
int timeout
Definition: rldf1.h:198
int sendENQ()
Definition: rldf1.cpp:211
int readBlock(unsigned char *buf, int len, int timeout=-1)
Definition: rlserial.cpp:498
unsigned int len
Definition: rldf1.cpp:55
unsigned int writeDLE(unsigned char c)
Definition: rldf1.cpp:87
df1Buffer(unsigned int maxsize=256)
Definition: rldf1.cpp:66
int writeBuffer(unsigned char *buffer, int len)
Definition: rldf1.cpp:165
void reset()
Definition: rldf1.cpp:63
unsigned short tns
Definition: rldf1.h:193
unsigned char * data()
Definition: rldf1.cpp:59
void registerSerial(rlSerial *serial)
Definition: rldf1.cpp:160
virtual ~rlDF1()
Definition: rldf1.cpp:156
rlDF1(unsigned char src=0, int timeout=1000)
Definition: rldf1.cpp:145
int sendACK()
Definition: rldf1.cpp:220
unsigned char & operator[](unsigned int pos)
Definition: rldf1.cpp:100
int nResponses
Definition: rldf1.h:196
unsigned char * dat
Definition: rldf1.cpp:56
bool active
Definition: rldf1.h:192
int sendCommand(unsigned char destination, unsigned char cmd, unsigned char sts, unsigned char *cdata, unsigned char len)
Definition: rldf1.cpp:319
static unsigned short calcCRC(unsigned short crc, unsigned short buffer)
Definition: rldf1.cpp:118
unsigned char source
Definition: rldf1.h:197
unsigned int maxsize
Definition: rldf1.cpp:54
int cmdLogicalWrite(unsigned char destination, unsigned char nsize, unsigned char filetype, unsigned char filenum, unsigned char adr, unsigned char sadr, unsigned char *buffer)
Definition: rldf1.cpp:294
virtual ~df1Buffer()
Definition: rldf1.cpp:73
int get(unsigned char *c)
Definition: rldf1.cpp:203
int cmdSetCPUMode(unsigned char destination, unsigned char mode)
Definition: rldf1.cpp:240
rlSerial * tty
Definition: rldf1.h:191
unsigned int write(unsigned char c)
Definition: rldf1.cpp:78
int getSymbol(unsigned char *c)
Definition: rldf1.cpp:184
int sendNAC()
Definition: rldf1.cpp:229
int cmdDiagnosticStatus(unsigned char destination, unsigned char *data)
Definition: rldf1.cpp:257
#define DBGPRINTF(x...)
Definition: rldf1.cpp:41
void print()
Definition: rldf1.cpp:108
static unsigned short computeCRC(const unsigned char *buffer, int len)
Definition: rldf1.cpp:133
int cmdLogicalRead(unsigned char destination, unsigned char nsize, unsigned char filetype, unsigned char filenum, unsigned char adr, unsigned char sadr, unsigned char *buffer)
Definition: rldf1.cpp:273
int writeBlock(const unsigned char *buf, int len)
Definition: rlserial.cpp:584
int receiveAnswer(unsigned char &destination, unsigned char &cmd, unsigned char &sts, unsigned char *cdata, unsigned char &len)
Definition: rldf1.cpp:386
unsigned int length()
Definition: rldf1.cpp:58