Lydia - Printhead
ModbusBridge.cpp
Go to the documentation of this file.
1 #include "config.h"
2 
3 #ifdef MODBUS_BRIDGE
4 
5 #include <ArduinoLog.h>
6 #include "./Addon.h"
7 #include "ModbusRtu.h"
8 #include "ModbusBridge.h"
9 #include "config.h"
10 #include <SPI.h>
11 #include <Ethernet.h>
12 #include "enums.h"
13 #include "debug_utils.h"
14 
15 #include "./OmronVFD.h"
16 #include "./OmronPID.h"
17 
18 #define HAS_DEBUG_MODBUS_BRIDGE_PRINT_QUEUE
19 
20 #define RS485Serial 3
21 #define MasterModbusAdd 0
25 millis_t WaitingTime;
26 int _state = IDLE;
27 bool __debugQuery = false;
28 bool debugReset = false;
29 bool debugErrors = false;
30 
32 {
34 }
36 {
37  return &master;
38 }
40 {
43  WaitingTime = millis() + nextWaitingTime;
44  _state = IDLE;
45  startTS = millis();
46 
47  // defaults
48  for (uchar i = 0; i < MAX_QUERY_BUFFER; i++)
49  {
50  queries[i].reset();
51  queries[i].id = i;
52  }
53  for (uchar i = 0; i < MODBUS_TCP_MAX_REGISTERS; i++)
54  {
57  }
58  return E_OK;
59 }
60 Query *ModbusBridge::nextByPrio(uchar state, int prio)
61 {
62  Query *oldest;
63  for (int i = 0; i < MAX_QUERY_BUFFER; i++)
64  {
65  if (!oldest)
66  {
67  oldest = &queries[i];
68  }
69  if (queries[i].state == state && queries[i].prio == prio)
70  {
71  oldest = &queries[i];
72  }
73  }
74  return oldest;
75 }
76 Query *ModbusBridge::nextQueryByState2(uchar state, int owner)
77 {
78  Query *ret = NULL;
79  for (int i = 0; i < MAX_QUERY_BUFFER; i++)
80  {
81  if (queries[i].state == state && queries[i].owner == owner)
82  {
83  if (!ret)
84  {
85  ret = &queries[i];
86  }
87 
88  if (queries[i].prio > ret->prio)
89  {
90  ret = &queries[i];
91  }
92  }
93  }
94  return ret;
95 }
96 bool ModbusBridge::skipRead(int slave, int fn, int addr, int num, int prio){
97  Query *same = nextSame(QUEUED, slave, addr, fn, num);
98  if (same && millis() - same->ts < MODBUS_SAME_REQUEST_INTERVAL)
99  {
100  return true;
101  }
102 
104  {
105  return true;
106  }
107 
108  if (numSame(QUEUED, slave, addr, fn, num) >= 1)
109  {
110  return true;
111  }
112 
113  if (numSame(PROCESSING, slave, addr, fn, num) >= 1)
114  {
115  return true;
116  }
117  return false;
118 }
120 {
121  millis_t t = millis();
122  for (int i = 0; i < MAX_QUERY_BUFFER; i++)
123  {
124  if ((queries[i].state == QUEUED ||
125  queries[i].state == PROCESSING) &&
126  t - queries[i].ts > MODBUS_MAX_LIFESPAN)
127  {
128  if (debugReset)
129  {
130  queries[i].print();
131  print();
132  }
133  queries[i].reset();
134  continue;
135  }
136  }
137 }
138 Query *ModbusBridge::nextQueryByState(uchar state, int owner)
139 {
140  if (owner > 0)
141  {
142  Query *q = nextQueryByOwner(state, owner);
143  if (q != NULL)
144  {
145  return q;
146  }
147  }
148 
149  millis_t t = millis();
150  Query *oldest = NULL;
151  for (int i = 0; i < MAX_QUERY_BUFFER; i++)
152  {
153  if (queries[i].state == state)
154  {
155  if (queries[i].prio != MB_QUERY_TYPE_CMD && t - queries[i].ts > 1000)
156  {
157  return &queries[i];
158  }
159 
160  if (!oldest)
161  {
162  oldest = &queries[i];
163  }
164 
165  if (queries[i].ts > oldest->ts)
166  {
167  oldest = &queries[i];
168  }
169  }
170  }
171  return oldest;
172 }
173 Query *ModbusBridge::nextQueryByOwner(uchar state, int owner)
174 {
175  millis_t t = millis();
176  Query *oldest = NULL;
177  for (int i = 0; i < MAX_QUERY_BUFFER; i++)
178  {
179  if (queries[i].state == state && queries[i].owner == owner)
180  {
181 
182  if (queries[i].ts == 0)
183  {
184  queries[i].ts = t;
185  continue;
186  }
187 
188  if (queries[i].prio == MB_QUERY_TYPE_CMD && t - queries[i].ts > 300)
189  {
190  return &queries[i];
191  }
192 
193  if (!oldest)
194  {
195  oldest = &queries[i];
196  }
197 
198  if (queries[i].ts > oldest->ts)
199  {
200  oldest = &queries[i];
201  }
202  }
203  }
204  return oldest;
205 }
206 Query *ModbusBridge::nextSame(uchar state, short slave, int addr, short fn, int value)
207 {
208  Query *oldest = NULL;
209  for (int i = 0; i < MAX_QUERY_BUFFER; i++)
210  {
211  if (queries[i].state == state)
212  {
213  Query *q = &queries[i];
214  if (q->addr == addr && q->fn == fn && q->value == value && q->slave == slave)
215  {
216  if (!oldest)
217  {
218  oldest = &queries[i];
219  }
220  if (queries[i].ts > oldest->ts)
221  {
222  oldest = &queries[i];
223  }
224  }
225  }
226  }
227  return oldest;
228 }
229 int ModbusBridge::numSame(uchar state, short slave, int addr, short fn, int value)
230 {
231  int num = 0;
232  for (int i = 0; i < MAX_QUERY_BUFFER; i++)
233  {
234  if (queries[i].state == state)
235  {
236  Query *q = &queries[i];
237  if (q->addr == addr && q->fn == fn && q->value == value && q->slave == slave)
238  {
239  num++;
240  }
241  }
242  }
243  return num;
244 }
245 int ModbusBridge::numSameOwner(uchar state, short slave, int addr, short fn, int value, int owner)
246 {
247  int num = 0;
248  for (int i = 0; i < MAX_QUERY_BUFFER; i++)
249  {
250  if (queries[i].state == state && queries[i].owner == owner)
251  {
252  Query *q = &queries[i];
253  if (q->addr == addr && q->fn == fn && q->value == value && q->slave == slave)
254  {
255  num++;
256  }
257  }
258  }
259  return num;
260 }
262 {
263  int num = 0;
264  for (int i = 0; i < MAX_QUERY_BUFFER; i++)
265  {
266  if (queries[i].state == state)
267  {
268  num++;
269  }
270  }
271  return num;
272 }
274 {
275 #ifdef HAS_DEBUG_MODBUS_BRIDGE_PRINT_QUEUE
276  Serial.print("----- Queries : --- ");
277  Serial.print("Proccessing : ");
278  Serial.print(numByState(PROCESSING));
279  Serial.print(" | QUEUED : ");
280  Serial.print(numByState(QUEUED));
281  Serial.print(" | DONE: ");
282  Serial.print(numByState(DONE));
283  Serial.print(" | ADDR: ");
284  Serial.print(cAddr);
285  Serial.print(" | FN: ");
286  Serial.print(cFN);
287  Serial.print(" | NOW : ");
288  Serial.print(millis());
289  Serial.print("-----\n");
290  for (int i = 0; i < MAX_QUERY_BUFFER; i++)
291  {
292  if (queries[i].state == DONE)
293  {
294  continue;
295  }
296  Serial.print(" - ");
297  Serial.print(queries[i].id);
298  Serial.print(". \t ");
299  queries[i].print();
300  Serial.print("\n");
301  }
302 #endif
303 }
305 {
306  return _state;
307  // return modbus->getState();
308 }
310 {
311  clearQueue();
312  loopPoll();
313  mb->Run();
314  return E_OK;
315 }
317  int slave,
318  short function,
319  long start,
320  int coils,
321  Component *_owner,
322  ComponentFnPtr _responseFn)
323 {
324  if (qstate() != IDLE)
325  {
326  return WAITING;
327  }
328 
329  cAddr = 0;
330  cSlave = slave;
331  cFN = function;
332  cAddr = start;
333  cNB = coils;
334  rOwner = _owner;
335  responseFn = _responseFn;
336 #ifdef HAS_DEBUG_MODBUS_BRIDGE_PRINT_QUERY
337  if (__debugQuery)
338  {
339  Serial.print("\n --------------Modbus QUERY --------- SLAVE : ");
340  Serial.print(slave);
341  Serial.print(" | FN : ");
342  Serial.print(cFN);
343  Serial.print(" | NB : ");
344  Serial.print(coils);
345  Serial.print(" | Address : ");
346  Serial.print(cAddr, HEX);
347  Serial.print(" | STATE : ");
348  Serial.print(_state);
349  Serial.print(" | OWNER : ");
350  Serial.println(rOwner->id);
351  Serial.println(" \n ");
352  }
353 #endif
354  _state = WAITING;
355 
356  return E_OK;
357 }
358 
359 short ModbusBridge::query(int slave, short function, long start, int coils, int _ownerId)
360 {
361  if (qstate() != IDLE)
362  {
363  return WAITING;
364  }
365 
366  cAddr = 0;
367  cSlave = slave;
368  cFN = function;
369  cAddr = start;
370  cNB = coils;
371  ownerId = _ownerId;
372 #ifdef HAS_DEBUG_MODBUS_BRIDGE_PRINT_QUERY
373  if (__debugQuery)
374  {
375  Serial.print("\n --------------Modbus QUERY --------- SLAVE : ");
376  Serial.print(slave);
377  Serial.print(" | FN : ");
378  Serial.print(cFN);
379  Serial.print(" | NB : ");
380  Serial.print(coils);
381  Serial.print(" | Address : ");
382  Serial.print(cAddr, HEX);
383  Serial.print(" | STATE : ");
384  Serial.print(_state);
385  Serial.print(" | OWNER : ");
386  Serial.println(ownerId);
387  Serial.println(" \n ");
388  }
389 #endif
390  _state = WAITING;
391  return E_OK;
392 }
394 {
395  switch (_state)
396  {
397 
398  case IDLE:
399  {
400  return E_OK;
401  }
402 
403  case WAITING:
404  {
405  if (millis() > WaitingTime)
406  {
407  _state = QUERY;
408  }
409  break;
410  }
411  case QUERY:
412  {
413  ModbusQuery[0].u8id = cSlave; // slave address
414  ModbusQuery[0].u8fct = cFN; // function code (this one is registers read)
415  ModbusQuery[0].u16RegAdd = cAddr; // start address in slave
416  ModbusQuery[0].u16CoilsNo = cNB; // number of elements (coils or registers) to read
417  ModbusQuery[0].au16reg = ModbusSlaveRegisters; // pointer to a memory array in the CONTROLLINO
418  master.query(ModbusQuery[0]); // send query (only once)
419  _state = RESPONSE; // set to RESPONSE
420  break;
421  }
422  case RESPONSE:
423  {
424  master.poll();
425  Component *c = NULL;
426 
427  if (owner && ownerId)
428  {
429  c = app->byId(ownerId);
430  }
431 
432  if (master.getState() == COM_IDLE)
433  {
434  _state = IDLE;
435  int errors = master.getErrCnt();
436  if (errors)
437  {
438  if (debugErrors)
439  {
440  Log.verboseln("Modbus Error : %d | Slave=%d | FN=%d", master.getLastError(), cSlave, cFN);
441  }
442  if (c)
443  {
444  c->onError(id, master.getLastError());
445  }
446  master.clearError();
447  ownerId = 0;
448  return E_OK;
449  }
450 
451  long onMessageError = 0;
452  if (c)
453  {
454  onMessageError = c->onRawResponse(master.rxSize, master.rxBuffer);
455  c->onResponse(onMessageError);
456  }
457  WaitingTime = millis() + nextWaitingTime;
458 
459  ownerId = 0;
460  }
461  break;
462  }
463  }
464  return E_OK;
465 }
467 {
468  switch (_state)
469  {
470 
471  case IDLE:
472  {
473  return E_OK;
474  }
475 
476  case WAITING:
477  {
478  if (millis() > WaitingTime)
479  {
480  _state++; // set to query state
481  }
482  break;
483  }
484  case QUERY:
485  {
486  ModbusQuery[0].u8id = cSlave; // slave address
487  ModbusQuery[0].u8fct = cFN; // function code (this one is registers read)
488  ModbusQuery[0].u16RegAdd = cAddr; // start address in slave
489  ModbusQuery[0].u16CoilsNo = cNB; // number of elements (coils or registers) to read
490  ModbusQuery[0].au16reg = ModbusSlaveRegisters; // pointer to a memory array in the CONTROLLINO
491  master.query(ModbusQuery[0]); // send query (only once)
492  _state++; // set to RESPONSE
493  break;
494  }
495  case RESPONSE:
496  {
497  master.poll();
498  if (master.getState() == COM_IDLE)
499  {
500  int errors = master.getErrCnt();
501  if (errors)
502  {
503  if (rOwner && onError != NULL)
504  {
505  (rOwner->*onError)(master.getLastError(), 1);
506  Log.verboseln("MB-Error: %d | Slave=%d | FN=%d", master.getLastError(), cSlave, cFN);
507  master.clearError();
508  }
509  else
510  {
511  Log.errorln("MB-Error::%d", master.getLastError());
512  }
513  _state = IDLE;
514  return E_OK;
515  }
516 
517  long onMessageError = 0;
518  if (rOwner && onMessage)
519  {
520  onMessageError = (rOwner->*onMessage)(master.rxSize, master.rxBuffer);
521  }
522  (rOwner->*responseFn)(onMessageError, 1);
523  WaitingTime = millis() + nextWaitingTime;
524  _state = IDLE;
525  }
526  break;
527  }
528  }
529  return E_OK;
530 }
532 {
533  return E_OK;
534 }
536 {
537  return E_OK;
538 }
539 
540 #endif
QUERY
@ QUERY
Definition: enums.h:81
Query::value
short value
Definition: ModbusBridge.h:23
MODBUS_RS485_BAUDRATE
#define MODBUS_RS485_BAUDRATE
Definition: config.h:86
ModbusBridge::skipRead
bool skipRead(int slave, int fn, int addr, int num, int prio)
Definition: ModbusBridge.cpp:96
Modbus::setTimeOut
void setTimeOut(uint16_t u16timeout)
write communication watch-dog timer
Definition: ModbusRtu.h:493
ModbusBridge::ownerId
int ownerId
Definition: ModbusBridge.h:164
OmronPID.h
ModbusBridge::onMessage
ComponentRxFn onMessage
Definition: ModbusBridge.h:161
ModbusBridge::onError
ComponentFnPtr onError
Definition: ModbusBridge.h:159
ModbusBridge::nextWaitingTime
int nextWaitingTime
Definition: ModbusBridge.h:165
ModbusBridge::info
short info()
Definition: ModbusBridge.cpp:535
COM_IDLE
@ COM_IDLE
Definition: ModbusRtu.h:113
Modbus::getErrCnt
uint16_t getErrCnt()
error counter
Definition: ModbusRtu.h:545
PROCESSING
@ PROCESSING
Definition: enums.h:91
Query::id
int id
Definition: ModbusBridge.h:26
Modbus::debugSend
bool debugSend
Definition: ModbusRtu.h:214
ModbusBridge::nextByPrio
Query * nextByPrio(uchar state, int prio)
Definition: ModbusBridge.cpp:60
modbus_t::au16reg
uint16_t * au16reg
Definition: ModbusRtu.h:73
ModbusBridge::numByState
int numByState(int state=DONE)
Definition: ModbusBridge.cpp:261
MODBUS_TCP_MAX_REGISTERS
#define MODBUS_TCP_MAX_REGISTERS
Definition: config_adv.h:24
modbus_t
Master query structure: This includes all the necessary fields to make the Master generate a Modbus q...
Definition: ModbusRtu.h:67
ModbusBridge::query
short query(int slave, short function, long start, int coils, Component *_owner, ComponentFnPtr _responseFn)
Definition: ModbusBridge.cpp:316
ModbusBridge::print
void print()
Definition: ModbusBridge.cpp:273
Modbus::getState
uint8_t getState()
Definition: ModbusRtu.h:561
Query::ts
millis_t ts
Definition: ModbusBridge.h:29
IDLE
@ IDLE
Definition: enums.h:83
ModbusBridge::ModbusSlaveRegisters
uint16_t ModbusSlaveRegisters[8]
Definition: ModbusBridge.h:131
ModbusBridge::queries
Query queries[MAX_QUERY_BUFFER]
Definition: ModbusBridge.h:186
RESPONSE
@ RESPONSE
Definition: enums.h:82
ModbusBridge::loop
short loop()
Definition: ModbusBridge.cpp:309
ModbusBridge::debug
short debug()
Definition: ModbusBridge.cpp:531
ModbusQuery
modbus_t ModbusQuery[1]
Definition: ModbusBridge.cpp:23
__debugQuery
bool __debugQuery
Definition: ModbusBridge.cpp:27
ModbusBridge::nextSame
Query * nextSame(uchar state, short slave, int addr, short fn, int value)
Definition: ModbusBridge.cpp:206
ModbusBridge::app
PHApp * app
Definition: ModbusBridge.h:154
ModbusBridge::mb
Mudbus * mb
Definition: ModbusBridge.h:166
ModbusBridge::cAddr
short cAddr
Definition: ModbusBridge.h:144
ModbusBridge::nextQueryByState
Query * nextQueryByState(uchar state=DONE, int owner=-1)
Definition: ModbusBridge.cpp:138
MODBUS_MAX_LIFESPAN
#define MODBUS_MAX_LIFESPAN
Definition: config_adv.h:11
ModbusBridge::setDebugSend
void setDebugSend(bool debug)
Definition: ModbusBridge.cpp:31
Modbus::query
int8_t query(modbus_t telegram)
only for master
Definition: ModbusRtu.h:592
ModbusRtu.h
ModbusBridge::rOwner
Component * rOwner
Definition: ModbusBridge.h:163
ModbusBridge.h
Modbus::rxSize
uint8_t rxSize
Definition: ModbusRtu.h:216
ModbusBridge::startTS
millis_t startTS
Definition: ModbusBridge.h:187
ModbusBridge::modbus
Modbus * modbus()
Definition: ModbusBridge.cpp:35
Query::reset
void reset()
Definition: ModbusBridge.h:94
MB_QUERY_TYPE_CMD
#define MB_QUERY_TYPE_CMD
Definition: config_adv.h:21
Query::print
void print()
Definition: ModbusBridge.h:55
MODBUS_TCP_DEFAULT_REGISTER_VALUE
#define MODBUS_TCP_DEFAULT_REGISTER_VALUE
Definition: config_adv.h:26
Modbus::rxBuffer
uint8_t rxBuffer[MAX_BUFFER]
Definition: ModbusRtu.h:217
modbus_t::u16CoilsNo
uint16_t u16CoilsNo
Definition: ModbusRtu.h:72
ModbusBridge::numSameOwner
int numSameOwner(uchar state, short slave, int addr, short fn, int value, int owner)
Definition: ModbusBridge.cpp:245
Query::addr
long addr
Definition: ModbusBridge.h:22
MODBUS_RS485_PORT
#define MODBUS_RS485_PORT
Definition: config.h:87
ModbusBridge::numSame
int numSame(uchar state, short slave, int addr, short fn, int value)
Definition: ModbusBridge.cpp:229
WAITING
@ WAITING
Definition: enums.h:80
ModbusBridge::clearQueue
void clearQueue()
Definition: ModbusBridge.cpp:119
ModbusBridge::loop_test
short loop_test()
Definition: ModbusBridge.cpp:466
RS485Serial
#define RS485Serial
Definition: ModbusBridge.cpp:20
ModbusBridge::cNB
int cNB
Definition: ModbusBridge.h:145
modbus_t::u8id
uint8_t u8id
Definition: ModbusRtu.h:69
modbus_t::u8fct
uint8_t u8fct
Definition: ModbusRtu.h:70
Modbus::clearError
void clearError()
Definition: ModbusRtu.h:550
DONE
@ DONE
Definition: enums.h:94
MODBUS_RS485_TIMEOUT
#define MODBUS_RS485_TIMEOUT
Definition: config.h:88
ModbusBridge::nextQueryByState2
Query * nextQueryByState2(uchar state, int owner)
Definition: ModbusBridge.cpp:76
QUEUED
@ QUEUED
Definition: enums.h:90
Query::prio
int prio
Definition: ModbusBridge.h:27
_state
int _state
Definition: ModbusBridge.cpp:26
ModbusBridge::cFN
short cFN
Definition: ModbusBridge.h:143
ModbusSlaveRegisters
uint16_t ModbusSlaveRegisters[8]
Definition: ModbusBridge.cpp:24
debugErrors
bool debugErrors
Definition: ModbusBridge.cpp:29
modbus_t::u16RegAdd
uint16_t u16RegAdd
Definition: ModbusRtu.h:71
E_OK
#define E_OK
Definition: enums.h:11
OmronVFD.h
enums.h
MODBUS_QUEUE_MIN_FREE
#define MODBUS_QUEUE_MIN_FREE
Definition: config.h:91
ModbusBridge::loopPoll
short loopPoll()
Definition: ModbusBridge.cpp:393
debug_utils.h
MODBUS_SAME_REQUEST_INTERVAL
#define MODBUS_SAME_REQUEST_INTERVAL
Definition: config.h:90
MAX_QUERY_BUFFER
#define MAX_QUERY_BUFFER
Definition: config_adv.h:14
ModbusBridge::cSlave
short cSlave
Definition: ModbusBridge.h:142
config.h
ModbusBridge::nextQueryByOwner
Query * nextQueryByOwner(uchar state=DONE, int owner=-1)
Definition: ModbusBridge.cpp:173
Query
Definition: ModbusBridge.h:18
Modbus::getLastError
uint8_t getLastError()
get last error message
Definition: ModbusRtu.h:575
ModbusBridge::setup
short setup()
Definition: ModbusBridge.cpp:39
master
Modbus master(MasterModbusAdd, RS485Serial)
ModbusBridge::responseFn
ComponentFnPtr responseFn
Definition: ModbusBridge.h:157
debugReset
bool debugReset
Definition: ModbusBridge.cpp:28
Query::fn
short fn
Definition: ModbusBridge.h:25
ModbusBridge::qstate
short qstate()
Definition: ModbusBridge.cpp:304
MasterModbusAdd
#define MasterModbusAdd
Definition: ModbusBridge.cpp:21
Modbus::begin
void begin(long u32speed)
Initialize class object.
Definition: ModbusRtu.h:298
WaitingTime
millis_t WaitingTime
Definition: ModbusBridge.cpp:25
Modbus::poll
int8_t poll()
cyclic poll for master
Definition: ModbusRtu.h:691
Modbus
Arduino class library for communicating with Modbus devices over USB/RS232/485 (via RTU protocol).
Definition: ModbusRtu.h:152
Query::slave
short slave
Definition: ModbusBridge.h:21