Radiocraft Wireless M-Bus extension module  1.00.00
mod_mbus.c
Go to the documentation of this file.
1 
10 #include <module.h>
11 
12 #include <errno.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdarg.h>
16 #include <stdlib.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19 #include <termios.h>
20 #include <pthread.h>
21 
22 /*****************************************************************************
23  **
24  ** DEFINITIONS AND MACROS
25  **
26  *****************************************************************************/
28 #define MBUS_DATA_LENGTH 0xF6
29 
30 /******************************************************************************
31  **
32  ** TYPEDEFS AND STRUCTURES
33  **
34  *****************************************************************************/
35 
48 struct ALIGN_ATTR mbus_open
49 {
50  //*** var
51  int16 retval;
52  int16 error;
53 
54  //*** var_input
55  int8 mode;
56  int8 rssi;
64 //*** var_input (access)
66 };
68 typedef struct mbus_open tdef_mbus_open;
69 
75 struct ALIGN_ATTR mbus_frame
76 {
77  //*** var_input
78  int8 control;
79  int16 manufacture;
80  int32 id;
81  int8 version;
82  int8 type;
83  int16 rssi;
84  int16 length;
86  int8 data[MBUS_DATA_LENGTH];
87 };
88 
90 typedef struct mbus_frame tdef_mbus_frame;
91 
96 struct ALIGN_ATTR mbus_send
97 {
98  //*** var
99  int16 retval;
100  int16 error;
101 
102  //*** var_input
103  int16 control;
104  int16 length;
105  int8* data;
106 
107 //*** var_input (access)
108 };
109 
111 typedef struct mbus_send tdef_mbus_send;
112 
119 struct ALIGN_ATTR mbus_receive
120 {
121  //*** var
122  int16 retval;
123  int16 error;
124 
125  //*** var_input
126 
127  //*** var_input (access)
129 };
130 
133 
140 struct ALIGN_ATTR mbus_reg_slave
141 {
142  //*** var
143  int16 retval;
144  int16 error;
145 
146  //*** var_input
147  int16 idx;
148  int16 manufacturer;
149  int32 id;
150  int8 version;
151  int8 type;
152 
153  uint8* key;
154 
155 //*** var_input (access)
156 };
157 
160 
166 struct ALIGN_ATTR mbus_set_filter
167 {
168  //*** var
169  int16 retval;
170  int16 error;
171 
172  //*** var_input
174 
175 //*** var_input (access)
176 };
177 
180 
187 struct PACKED_ATTR mbus_start_frame
188 {
190  uint8 length;
192  uint8 control;
194  uint16 manufacturer;
196  uint32 id;
198  uint8 version;
200  uint8 type;
201 };
202 
205 
206 /******************************************************************************
207  **
208  ** LOCAL VARIABLES
209  **
210  *****************************************************************************/
211 
213 static int fd = -1;
214 
216 static int cfg_active = 0;
218 static int cfg_activated = 0;
220 static int rssi_included = 0;
221 
223 static pthread_mutex_t lock;
224 
225 /******************************************************************************
226  **
227  ** LOCAL FUNCTIONS
228  **
229  *****************************************************************************/
230 
243 static void
244 mbusDebug(const char* prefix, const char *format, ...)
245 {
246  va_list valist;
247  char buffer[480];
248 
249  // build debug message;
250  strcpy(buffer, prefix);
251  strcat(buffer, ":");
252  va_start(valist, format);
253  vsprintf(&buffer[strlen(buffer)], format, valist);
254  va_end(valist);
255 
256  vplDebug(buffer);
257 }
258 
268 static int
269 mbusPower(uint8 power)
270 {
271  if (vplSetIOSignal(RF_OFF, !power) != 0)
272  {
273  mbusDebug(__func__, "ERR (%d): Faield to set signal", __LINE__);
274  return -1;
275  }
276  if (power)
277  {
278  // Disable CFG mode, as we are now powering the system
279  vplSetIOSignal(RF_CFG, 0);
280  }else{
281  // Assert CFG pin to prevent it from keeping the module powered.
282  vplSetIOSignal(RF_CFG, 1);
283  // power turned off, mark as inactive
284  cfg_activated = 0;
285  }
286 
287  return 0;
288 }
289 
303 static int
305 {
306  uint8 cmd = 0x00;
307  uint8 reply = 0x00;
308  int rc;
309 
310  if (cfg_active)
311  {
312  mbusDebug(__func__, "ERR (%d): Already in config mode", __LINE__);
313  return -1;
314  }
315 
316  // Deassert RF_CFG, to make it ready to assert it in the loop
317  if (vplSetIOSignal(RF_CFG, 0) != 0)
318  {
319  mbusDebug(__func__, "ERR (%d): Failed to set signal", __LINE__);
320  // We failed to set CFG signal, so we are fully depending on the 0x00 command.
321  }
322 
323  for (int try = 0; try < 3; ++try)
324  {
325  // flush both data received but not read and data written but not transmitted.
326  if (tcflush(fd, TCIOFLUSH))
327  {
328  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
329  return -1;
330  }
331 
332  // flush send buffer
333  if (tcdrain(fd))
334  {
335  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
336  return -1;
337  }
338  // set configuration mode request
339  if (vplSetIOSignal(RF_CFG, 1) != 0)
340  {
341  mbusDebug(__func__, "ERR (%d): Failed to set signal", __LINE__);
342  }
343 
344  if (!cfg_activated)
345  {
346  // send enter configuration mode request the first time, in case we already has entered it before, as this will resend the '>'.
347  rc = write(fd, &cmd, 1);
348  if (rc == -1)
349  {
350  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
351  return -1;
352  }
353  if (rc != 1)
354  {
355  mbusDebug(__func__, "ERR (%d): failed to send exit command",
356  __LINE__);
357  return -1;
358  }
359 
360  }
361  usleep(50);
362 
363  // look for OK '>'
364  reply = 0x00;
365  rc = 0;
366  int tries = 0;
367  while (rc == 0 && tries < 3)
368  {
369  rc = read(fd, &reply, 1);
370  if (rc == -1)
371  {
372  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
373  return -1;
374  }
375  tries++;
376  usleep(10000);
377  }
378 
379  // deassert config mode signal
380  if (vplSetIOSignal(RF_CFG, 0) != 0)
381  {
382  mbusDebug(__func__, "ERR (%d): Failed to set signal", __LINE__);
383  }
384 
385  if ((rc == 1) && reply == '>')
386  {
387  cfg_activated = 1;
388  break;
389  }
390  }
391 
392  cfg_active = reply == '>';
393  return (reply == '>') ? 0 : 1;
394 }
395 
407 static int
409 {
410  uint8 cmd = 'X';
411  if (!cfg_active)
412  {
413  mbusDebug(__func__, "ERR (%d): config not active", __LINE__);
414  return -1;
415  }
416 
417  // send exit request
418  int rc = write(fd, &cmd, 1);
419  if (rc == -1)
420  {
421  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
422  return -1;
423  }
424  if (rc != 1)
425  {
426  mbusDebug(__func__, "ERR (%d): failed to send exit command", __LINE__);
427  return -1;
428 
429  }
430 
431  // flush send buffer
432  if (tcdrain(fd))
433  {
434  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
435  return -1;
436  }
437  // flush recv buffer
438  if (tcflush(fd, TCIOFLUSH))
439  {
440  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
441  return -1;
442  }
443 
444  cfg_active = 0;
445  return 0;
446 }
447 
466 static int
467 mbusConfigTransact(uint8 cmd, uint8* data, int d_size, uint8* reply, int r_size)
468 {
469  // write command
470  int rc;
471  rc = write(fd, &cmd, 1);
472  if (rc == -1)
473  {
474  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
475  return -1;
476  }
477  if (rc != 1)
478  {
479  mbusDebug(__func__, "ERR (%d): failed to send 0x%02X", __LINE__, cmd);
480  return -1;
481  }
482 
483  if (data && d_size > 0)
484  {
485  rc = write(fd, data, d_size);
486  if (rc == -1)
487  {
488  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
489  return -1;
490  }
491  if (rc != d_size)
492  {
493  mbusDebug(__func__, "ERR (%d): failed to send 0x%02X", __LINE__, cmd);
494  return -1;
495  }
496  }
497 
498  // flush send buffer
499  if (tcdrain(fd))
500  {
501  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
502  return -1;
503  }
504 
505  // get reply
506  if (r_size > 0)
507  {
508  int remaining = r_size;
509  for (int try = 0; try < 5; try++)
510  {
511  int rc = read(fd, &reply[r_size - remaining], remaining);
512  if (rc == -1)
513  {
514  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
515  return -1;
516  }
517  remaining -= rc;
518  if (remaining == 0)
519  break;
520  }
521  if (remaining)
522  {
523  mbusDebug(__func__,
524  "ERR (%d): unexpected reply to 0x%02X (missing %d of %d)",
525  __LINE__, (cmd & 0xFF), remaining, r_size);
526  return -1;
527  }
528  }
529 
530  // wait for '>'
531  uint8 cfm = 0;
532  for (int try = 0; try < 5; try++)
533  {
534  rc = read(fd, &cfm, 1);
535  if (rc == -1)
536  {
537  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
538  return -1;
539  }
540  if ((rc == 1) && cfm == '>')
541  break;
542  }
543  // no OK reply
544  if (cfm != '>')
545  {
546  mbusDebug(__func__, "ERR (%d): no reply to 0x%02X, 0x%x(%c)", __LINE__,
547  cmd, cfm, cfm);
548  return 1;
549  }
550 
551  return 0;
552 }
553 
570 static int
571 mbusConfigCmd(uint8 cmd, uint8* reply, int size)
572 {
573  return mbusConfigTransact(cmd, NULL, 0, reply, size);
574 }
575 
588 static int
589 mbusConfigData(uint8 cmd)
590 {
591  // write command
592  int rc = write(fd, &cmd, 1);
593  if (rc == -1)
594  {
595  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
596  return -1;
597  }
598  if (rc != 1)
599  {
600  mbusDebug(__func__, "ERR (%d): failed to send 0x%02X", __LINE__, cmd);
601  return -1;
602  }
603 
604  // flush send buffer
605  if (tcdrain(fd))
606  {
607  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
608  return -1;
609  }
610 
611  return 0;
612 }
613 
622 static int mbus_read_reg(int8 reg, int size, const char* name)
623 {
624  uint8 reply[20];
625  char buf[60 + 1];
626  if (size > 20)
627  return -1;
628 
629  // Memory read + reg
630  memset(reply, 0x00, size);
631  for (int i = 0; i < size; ++i)
632  {
633  if (mbusConfigCmd('Y', NULL, 0))
634  return -1;
635  if (mbusConfigCmd(reg + i, &reply[i], 1))
636  return -1;
637  sprintf(&buf[i * 3], "%02X ", reply[i]);
638  }
639 
640  mbusDebug(__func__, "%s = '%s'", name, buf);
641  return 0;
642 
643 }
644 
653 static int mbus_read_regs(int8 reg, uint8* buffer, int size)
654 {
655 
656  // Memory read + reg
657  memset(buffer, 0x00, size);
658  for (int i = 0; i < size; ++i)
659  {
660  if (mbusConfigCmd('Y', NULL, 0))
661  return -1;
662  if (mbusConfigCmd(reg + i, &buffer[i], 1))
663  return -1;
664  }
665 
666  return 0;
667 
668 }
669 
678 static int mbus_config_mem_reg(uint8 reg, uint8 val)
679 {
680  uint8 old_val;
681  // Read before modify
682  if (mbusConfigCmd('Y', NULL, 0))
683  return -1;
684  if (mbusConfigCmd(reg, &old_val, 1))
685  return -1;
686 
687  if (old_val == val)
688  {
689  return 0;
690  }
691 
692  // Memory modify
693  if (mbusConfigCmd('M', NULL, 0))
694  return -1;
695  if (mbusConfigData(reg))
696  return -1; // Addr
697  if (mbusConfigData(val))
698  return -1; // Val
699  if (mbusConfigCmd(0xFF, NULL, 0))
700  return -1; //0xff to end
701  return 0;
702 }
703 
712 static int mbus_config(int8 mode, int8 rssi, int8 only_installed)
713 {
714 
715  // request configuration mode
716  if (mbusConfigEnter())
717  return -1;
718 
719  if (mode >= 0)
720  {
721  // Memory modify + MBUS_MODE
722  if (mbus_config_mem_reg(0x03, mode))
723  return -1;
724  mbus_read_reg(0x03, 1, "MBUS_MODE");
725  }
726 
727  if (rssi >= 0)
728  {
729  // Memory modify + RSSI_MODE
730  if (mbus_config_mem_reg(0x05, rssi ? 1 : 0))
731  return -1; // Val
732 
733  mbus_read_reg(0x05, 1, "MBUS_RSSI");
734  rssi_included = rssi;
735  }
736 
737  if (only_installed >= 0)
738  {
739  // Memory modify + INSTALL_MODE
740  if (mbus_config_mem_reg(0x3D, only_installed ? 0 : 2))
741  return -1;
742  mbus_read_reg(0x3d, 1, "MBUS_INSTALL_MODE");
743  }
744 
745  // decrypt flag, always enabled
746  if (mbus_config_mem_reg(0x3F, 1))
747  return -1;
748 
749  // exit configuration mode and return to IDLE state
750  if (mbusConfigExit())
751  return -1;
752 
753  return 0;
754 }
755 
763 static int __attribute__( (unused))
765 {
766  uint8 cmd = 0x00;
767  uint8 reply = 0x00;
768  int rc;
769 
770  if (cfg_active)
771  {
772  mbusDebug(__func__, "ERR (%d): Already in config mode", __LINE__);
773  return -1;
774  }
775 
776  if (vplSetIOSignal(RF_CFG, 0) != 0)
777  {
778  mbusDebug(__func__, "ERR (%d): Failed to set signal", __LINE__);
779  }
780  //sleep(1);
781  for (int try = 0; try < 3; ++try)
782  {
783  // flush both data received but not read and data written but not transmitted.
784  if (tcflush(fd, TCIOFLUSH))
785  {
786  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
787  return -1;
788  }
789 
790  // flush send buffer
791  if (tcdrain(fd))
792  {
793  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
794  return -1;
795  }
796  // set configuration mode request
797  if (vplSetIOSignal(RF_CFG, 1) != 0)
798  {
799  mbusDebug(__func__, "ERR (%d): Failed to set signal", __LINE__);
800  }
801 
802  if (!cfg_activated)
803  {
804  // send enter configuration mode request the first time, in case we already has entered it before, as this will resend the '>'.
805  rc = write(fd, &cmd, 1);
806  if (rc == -1)
807  {
808  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
809  return -1;
810  }
811  if (rc != 1)
812  {
813  mbusDebug(__func__, "ERR (%d): failed to send exit command",
814  __LINE__);
815  return -1;
816  }
817 
818  }
819  usleep(50);
820 
821  // look for OK '>'
822  reply = 0x00;
823  rc = 0;
824  int tries = 0;
825  while (rc == 0 && tries < 3)
826  {
827  rc = read(fd, &reply, 1);
828  if (rc == -1)
829  {
830  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
831  return -1;
832  }
833  tries++;
834  usleep(10000);
835  }
836 
837  if ((rc == 1) && reply == '>')
838  {
839  cfg_activated = 1;
840  // In config mode: Send "reset to factory settings" request
841  rc = mbusConfigTransact('@', (uint8*) "RC", 2, NULL, 0);
842 
843  // deassert config mode signal
844  if (vplSetIOSignal(RF_CFG, 0) != 0)
845  {
846  mbusDebug(__func__, "ERR (%d): Failed to set signal", __LINE__);
847  }
848  break;
849  }
850  else
851  {
852 
853  //sleep(1);
854  }
855  // deassert config mode signal
856  if (vplSetIOSignal(RF_CFG, 0) != 0)
857  {
858  mbusDebug(__func__, "ERR (%d): Failed to set signal", __LINE__);
859  }
860 
861  }
862 
863  cfg_active = reply == '>';
864 
865  return mbusConfigExit();
866 
867 }
883 static int
885 {
886  if (fd >= 0)
887  {
888  // flush both data received but not read and data written but not transmitted.
889  tcflush(fd, TCIOFLUSH);
890  if (close(fd))
891  {
892  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
893  return -1;
894  }
895  mbusPower(0);
896  fd = -1;
897  }
898  return 0;
899 }
900 
918 static int
919 mbusOpen(int8 mode, int8 rssi)
920 {
921  char port_path[200];
922  struct termios tty;
923 
924  if (fd >= 0)
925  {
926  mbusDebug(__func__, "ERR: Communication interface already opened:");
927  return -1;
928  }
929 
930  if (vplFsMapFile(port_path, 200, "dev:ser3"))
931  {
932  mbusDebug(__func__, "ERR: Failed to open port:");
933  return -1;
934  }
935 
936  fd = open(port_path, O_RDWR | O_NOCTTY | O_SYNC);
937  if (fd < 0)
938  {
939  mbusDebug(__func__, "ERR: Failed to open '%s': %s", port_path,
940  strerror(errno));
941  return -1;
942  }
943 
944  memset(&tty, 0, sizeof tty);
945  if (tcgetattr(fd, &tty) != 0)
946  {
947  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
948  return -1;
949  }
950 
951  // default baud rate 19.2kBs
952  cfsetospeed(&tty, B19200);
953  cfsetispeed(&tty, B19200);
954 
955  tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
956  tty.c_cflag &= ~CSIZE;
957  tty.c_cflag |= CS8; /* 8-bit characters */
958  tty.c_cflag &= ~PARENB; /* no parity bit */
959  tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
960  tty.c_cflag &= ~CRTSCTS; /* no hardware flow control */
961 
962  /* setup for non-canonical mode */
963  tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL
964  | IXON);
965  tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
966  tty.c_oflag &= ~OPOST;
967 
968  /* fetch bytes as they become available */
969  tty.c_cc[VMIN] = (cc_t) 0; // non-blocking mode, only using timeout
970  tty.c_cc[VTIME] = (cc_t) 10; // 1 seconds read timeout
971 
972  if (tcsetattr(fd, TCSANOW, &tty) != 0)
973  {
974  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
975  }
976 
977  if (mbusPower(1))
978  return -1;
979 
980  // reset module by entering and exiting configuration mode
981  int i;
982  for (i = 0; i < 5; ++i)
983  {
984  if (mbusConfigEnter() == 0)
985  {
986  if (mbusConfigExit() == 0)
987  {
988  break;
989  }
990  }
991  }
992  if (i >= 5)
993  {
994  mbusDebug(__func__, "ERR (%d): failed to reset module", __LINE__);
995  }
996 
997  if (mbus_config(mode, rssi, -1))
998  {
999  mbusPower(0);
1000  return -1;
1001  }
1002 
1003  return 0;
1004 }
1005 
1019 static int
1020 mbusSend(int16 c, int8* data, int8 size)
1021 {
1022  int send = 0;
1023 
1024  if (c >= 0)
1025  {
1026  // change control byte
1027  if (mbusConfigEnter())
1028  return -1;
1029  if (mbusConfigCmd('F', NULL, 0))
1030  {
1031  mbusConfigExit();
1032  return -1;
1033  }
1034  if (mbusConfigCmd(c, NULL, 0))
1035  {
1036  mbusConfigExit();
1037  return -1;
1038  }
1039  if (mbusConfigExit())
1040  return -1;
1041  // Delay 1.1ms from end of config to idle.
1042  usleep(1100);
1043  }
1044 
1045  // send length if given else request header only
1046  if (size == 0)
1047  {
1048  int cmd = 0xFE;
1049  // send only header information
1050  send = write(fd, &cmd, 1);
1051  if (send == -1)
1052  {
1053  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1054  return -1;
1055  }
1056  if (send != 1)
1057  {
1058  mbusDebug(__func__, "(%d): Failed to write send request", __LINE__);
1059  return -1;
1060  }
1061  }
1062  else
1063  {
1064  // send data length
1065  send = write(fd, &size, 1);
1066  if (send == -1)
1067  {
1068  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1069  return -1;
1070  }
1071  if (send != 1)
1072  {
1073  mbusDebug(__func__, "(%d): Failed to write data length", __LINE__);
1074  return -1;
1075  }
1076  send = write(fd, data, size);
1077  if (send == -1)
1078  {
1079  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1080  return -1;
1081  }
1082  if (send != size)
1083  {
1084  mbusDebug(__func__, "(%d): Failed to write data (%d of %d)", __LINE__,
1085  send, size);
1086  return -1;
1087  }
1088  }
1089 
1090  return 0;
1091 }
1092 
1104 static int
1105 mbusReceive(tdef_mbus_start_frame *start, int8 *data, int16* rssi)
1106 {
1107  int rlen, data_size;
1108  int remaining = sizeof(*start);
1109 
1110  // get length
1111  rlen = read(fd, &start->length, 1);
1112  if (rlen < 0)
1113  {
1114  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1115  return -1;
1116  }
1117  if (rlen == 0)
1118  {
1119  // mbusDebug(__func__, "(%d): no length byte present", __LINE__);
1120  return 0; // no length present in receive buffer
1121  }
1122  if (start->length == 0)
1123  {
1124  mbusDebug(__func__, "(%d): zero length frame received", __LINE__);
1125  return 0; // no length present in receive buffer
1126  }
1127 
1128  remaining--;
1129 
1130  // get rest of start frame
1131  rlen = read(fd, (&start->length) + 1, remaining);
1132  if (rlen < 0)
1133  {
1134  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1135  return -1;
1136  }
1137  if (rlen != remaining)
1138  {
1139  mbusDebug(__func__, "(%d): failed to receive start frame (%d of %d)",
1140  __LINE__, rlen, remaining);
1141  tcflush(fd, TCIFLUSH); // flush in an attempt to recover
1142  return -1; // no length present in receive buffer
1143  }
1144  // get data
1145  data_size = start->length - sizeof(*start) + 1;
1146 
1147  if (data_size < 0)
1148  {
1149  mbusDebug(__func__, "(%d): invalid frame length (%d < %d)", __LINE__,
1150  start->length, sizeof(*start) + 1);
1151  tcflush(fd, TCIFLUSH); // flush in an attempt to recover
1152  return -1; // no length present in receive buffer
1153  }
1154  if (rssi_included)
1155  {
1156  data_size--;
1157  }
1158  if (data_size > 0)
1159  {
1160  int tries = 0;
1161  int pos = 0;
1162  memset(data, 0x00, MBUS_DATA_LENGTH);
1163  while (pos < data_size && tries < 3)
1164  {
1165  rlen = read(fd, &data[pos], data_size - pos);
1166  if (rlen < 0)
1167  {
1168  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1169  return -1;
1170  }
1171  pos += rlen;
1172  tries++;
1173  usleep(1000);
1174  }
1175  if (pos != data_size)
1176  {
1177  mbusDebug(__func__, "(%d): failed to receive data frame (%d of %d)",
1178  __LINE__, pos, data_size);
1179  tcflush(fd, TCIFLUSH); // flush in an attempt to recover
1180  return -1; // no length present in receive buffer
1181  }
1182 
1183  }
1184  if (rssi_included)
1185  {
1186  uint8 buf = 0;
1187  rlen = read(fd, &buf, 1);
1188  if (rlen < 0)
1189  {
1190  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1191  return -1;
1192  }
1193  if (rlen == 1)
1194  {
1195  if (rssi)
1196  {
1197  *rssi = buf;
1198  }
1199  }
1200 
1201  }
1202  start->length = (uint8) data_size;
1203 
1204  return 1;
1205 }
1206 
1221 static int
1222 mbus_register_slave(int idx, int16 manufacturer, int32 id, int8 version,
1223  int8 type,
1224  uint8* key)
1225 {
1226  uint8 addr[8];
1227 
1228 // curent slave index
1229  if (idx > 64 || idx <= 0)
1230  {
1231  return -2;
1232  }
1233 
1234  memcpy(&addr[0], &id, 4);
1235  memcpy(&addr[4], &manufacturer, 2);
1236  memcpy(&addr[6], &version, 1);
1237  memcpy(&addr[7], &type, 1);
1238 
1239  // request configuration mode
1240  if (mbusConfigEnter())
1241  return -1;
1242 
1243  // bind slave
1244  if (mbusConfigCmd('B', NULL, 0))
1245  return -1;
1246  if (mbusConfigTransact(idx, addr, 8, NULL, 0))
1247  return -1;
1248 
1249  if (key)
1250  {
1251  // set key for slave
1252  if (mbusConfigCmd('K', NULL, 0))
1253  return -1;
1254  if (mbusConfigTransact(idx, key, 16, NULL, 0))
1255  return -1; // Slave ID
1256  }
1257 
1258  // exit configuration mode and return to IDLE state
1259  if (mbusConfigExit())
1260  return -1;
1261 
1262  return 0;
1263 }
1264 
1271 static int
1273 {
1274  uint8 reply[20];
1275  char serial[8 * 3];
1276  int i;
1277 
1278  // request configuration mode
1279  if (mbusConfigEnter())
1280  return -1;
1281 
1282  // Signal strength
1283  if (mbusConfigCmd('Q', reply, 1))
1284  return -1;
1285  mbusDebug(__func__, "Signal quality = %d", reply[0]);
1286 
1287  // Signal strength
1288  if (mbusConfigCmd('S', reply, 1))
1289  return -1;
1290  mbusDebug(__func__, "RSSI = %d (%d dBm)", reply[0],
1291  ((-reply[0]) / 2));
1292 
1293  // Temperature monitoring
1294  if (mbusConfigCmd('U', reply, 1))
1295  return -1;
1296  mbusDebug(__func__, "Temperature = %d C", (reply[0] - 128));
1297 
1298  // Battery Monitoring
1299  if (mbusConfigCmd('V', reply, 1))
1300  return -1;
1301  mbusDebug(__func__, "VCC = %dmV", (reply[0] * 30));
1302 
1303  // Memory read + MBUS_MODE
1304  if (mbusConfigCmd('Y', NULL, 0))
1305  return -1;
1306  if (mbusConfigCmd(0x03, reply, 1))
1307  return -1;
1308  mbusDebug(__func__, "MBUS_MODE = 0x%02X", reply[0]);
1309 
1310  // Memory read + DATA_INTERFACE
1311  if (mbus_read_regs(0x36, reply, 1))
1312  return -1;
1313  mbusDebug(__func__, "DATA_INTERFACE = 0x%02X", reply[0]);
1314 
1315  // Memory read + PART_NUMBER
1316  if (mbus_read_regs(0x61, reply, 12))
1317  return -1;
1318  reply[12] = 0;
1319  mbusDebug(__func__, "PART_NUMBER = '%s'", reply);
1320 
1321  // Memory read + HW_REV_NO
1322  if (mbus_read_regs(0x6E, reply, 4))
1323  return -1;
1324  reply[4] = 0;
1325  mbusDebug(__func__, "HW_REV_NO = '%s'", reply);
1326 
1327  // Memory read + FW_REV_NO
1328  if (mbus_read_regs(0x73, reply, 4))
1329  return -1;
1330  reply[4] = 0;
1331  mbusDebug(__func__, "FW_REV_NO = '%s'", reply);
1332 
1333  // Memory read + SERIAL_NUMBER
1334  if (mbus_read_regs(0x78, reply, 8))
1335  return -1;
1336  for (i = 0; i < 8; i++)
1337  {
1338  sprintf(&serial[i * 3], "%02X ", reply[i]);
1339  }
1340  serial[8 * 3 - 1] = 0;
1341  mbusDebug(__func__, "SERIAL_NUMBER = %s", serial);
1342 
1343  if (mbus_read_regs(0x3d, reply, 1))
1344  return -1;
1345  mbusDebug(__func__, "INSTALL_MODE = 0x%02X", reply[0]);
1346 
1347  if (mbus_read_regs(0x05, reply, 1))
1348  return -1;
1349  mbusDebug(__func__, "RSSI_MODE = 0x%02X", reply[0]);
1350 
1351  // exit configuration mode and return to IDLE state
1352  if (mbusConfigExit())
1353  return -1;
1354 
1355  return 0;
1356 }
1357 
1373 static int32 MODDECL
1374 mbusCallOpen(HANDLE* pCPU __attribute__( (unused)),
1375  void* pBase)
1376 {
1377  tdef_mbus_open* pdata = (tdef_mbus_open*) pBase;
1378  if (pthread_mutex_lock(&lock))
1379  {
1380  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
1381  return -1;
1382  }
1383 
1384  int rc = mbusOpen(pdata->mode, pdata->rssi);
1385  pthread_mutex_unlock(&lock);
1386 
1387  return rc;
1388 }
1389 
1395 static int32 MODDECL
1396 mbusCallClose(HANDLE* pCPU __attribute__((unused)),
1397  void* pBase __attribute__((unused)))
1398 {
1399  if (pthread_mutex_lock(&lock))
1400  {
1401  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
1402  return -1;
1403  }
1404 
1405  int rc = mbusClose();
1406  pthread_mutex_unlock(&lock);
1407 
1408  return rc;
1409 }
1410 
1416 static int32 MODDECL
1417 mbusCallReceive(HANDLE* pCPU __attribute__((unused)), void* pBase)
1418 {
1419  int16 rssi = 0;
1420  tdef_mbus_start_frame head;
1421  tdef_mbus_receive *pdata = (tdef_mbus_receive*) pBase;
1422 
1423  if (pthread_mutex_lock(&lock))
1424  {
1425  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
1426  return -1;
1427  }
1428 
1429  int rc = mbusReceive(&head, pdata->frame->data, &rssi);
1430  if (rc > 0)
1431  {
1432  pdata->frame->control = head.control;
1433 
1434  pdata->frame->control = (int8) head.control;
1435  write16b(&pdata->frame->manufacture, head.manufacturer);
1436  write32b(&pdata->frame->id, head.id);
1437  pdata->frame->version = (int8) head.version;
1438  pdata->frame->type = head.type;
1439  write16b(&pdata->frame->rssi, rssi);
1440  write16b(&pdata->frame->length, head.length);
1441  }
1442 
1443  pthread_mutex_unlock(&lock);
1444 
1445  return rc;
1446 }
1447 
1456 static int32 MODDECL
1457 mbusCallSend(HANDLE* pCPU __attribute__((unused)), void* pBase)
1458 {
1459  tdef_mbus_send *pdata = (tdef_mbus_send*) pBase;
1460 
1461  if ((pdata->length > 0) && !pdata->data)
1462  {
1463  mbusDebug(__func__, "ERR (%d): missing data", __LINE__);
1464  return -1;
1465  }
1466 
1467  if ((pdata->length < 0) || (pdata->length > MBUS_DATA_LENGTH))
1468  {
1469  mbusDebug(__func__, "ERR (%d): illegal data length %d", __LINE__,
1470  pdata->length);
1471  return -1;
1472  }
1473 
1474  if ((pdata->control < -1) || (pdata->control > 0xFF))
1475  {
1476  mbusDebug(__func__, "ERR (%d): illegal control value %d", __LINE__,
1477  pdata->length);
1478  return -1;
1479  }
1480 
1481  if (pthread_mutex_lock(&lock))
1482  {
1483  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
1484  return -1;
1485  }
1486 
1487  int rc = mbusSend(pdata->control, pdata->data, pdata->length);
1488 
1489  pthread_mutex_unlock(&lock);
1490  return rc ? -2 : 0;
1491 }
1492 
1534 static int32 MODDECL
1535 mbusCallInfo(HANDLE* pCPU __attribute__((unused)),
1536  void* pBase __attribute__((unused)))
1537 {
1538  if (pthread_mutex_lock(&lock))
1539  {
1540  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
1541  return -1;
1542  }
1543 
1544  int rc = mbus_info();
1545  if (rc)
1546  {
1547  mbusDebug(__func__, "error resetting interface (%d)", rc);
1548  mbusClose();
1549  mbusOpen(-1, 0);
1550  }
1551 
1552  pthread_mutex_unlock(&lock);
1553  return 0;
1554 }
1555 
1561 static int32 MODDECL
1562 mbusCallSetFilter(HANDLE* pCPU __attribute__( (unused)),
1563  void* pBase)
1564 {
1565  tdef_mbus_set_filter* pdata = (tdef_mbus_set_filter*) pBase;
1566  if (pthread_mutex_lock(&lock))
1567  {
1568  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
1569  return -1;
1570  }
1571 
1572  int rc = mbus_config(-1, -1, pdata->only_installed);
1573  pthread_mutex_unlock(&lock);
1574 
1575  return rc;
1576 }
1577 
1583 static int32 MODDECL
1584 mbusCallRegisterSlave(HANDLE* pCPU __attribute__( (unused)),
1585  void* pBase)
1586 {
1587  tdef_mbus_reg_slave* pdata = (tdef_mbus_reg_slave*) pBase;
1588  if (pthread_mutex_lock(&lock))
1589  {
1590  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
1591  return -1;
1592  }
1593 
1594  int rc = mbus_register_slave(pdata->idx, pdata->manufacturer, pdata->id,
1595  pdata->version, pdata->type, pdata->key);
1596  pthread_mutex_unlock(&lock);
1597 
1598  return rc;
1599 }
1600 
1617 int
1619 {
1620  // Var
1621  uint16 rc;
1622  pthread_mutexattr_t lock_attr;
1623  vplFunctionEntry ftable[] =
1624  {
1625  { "mbusOpen", mbusCallOpen },
1626  { "mbusClose", mbusCallClose },
1627  { "mbusSend", mbusCallSend },
1628  { "mbusReceive", mbusCallReceive },
1629  { "mbusInfo", mbusCallInfo },
1630  { "mbusRegisterSlave", mbusCallRegisterSlave },
1631  { "mbusSetFilter", mbusCallSetFilter },
1632  {
1633  NULL, NULL } };
1634 
1635  mbusDebug(__func__, "Initializing");
1636 
1637  // initialize API lock
1638  rc = pthread_mutexattr_init(&lock_attr);
1639  if (rc != 0)
1640  {
1641  mbusDebug(__func__, "ERR (%d): %d", __LINE__, rc);
1642  return 1;
1643  }
1644  rc = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
1645  if (rc != 0)
1646  {
1647  mbusDebug(__func__, "ERR (%d): %d", __LINE__, rc);
1648  return 1;
1649  }
1650  rc = pthread_mutex_init(&lock, &lock_attr);
1651  if (rc != 0)
1652  {
1653  mbusDebug(__func__, "ERR (%d): %d", __LINE__, rc);
1654  return 1;
1655  }
1656 
1657  // Initialize module
1658  rc = vplInstallFunctions("mod_mbus", ftable);
1659  if (rc)
1660  {
1661  // Install failed
1662  mbusDebug(__func__, "failed to install 'mod_mbus' functions err %d", rc);
1663  return 1;
1664  }
1665 
1666  if (vplSetIOSignal(RF_CFG, 0) != 0)
1667  {
1668  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1669  }
1670 
1671  if (mbusPower(0))
1672  return -1;
1673 
1674  // Completed
1675  return 0;
1676 }
1677 
1691 void
1692 moduleNotify(int event, int parm)
1693 {
1694  switch (event)
1695  {
1696  case EVENT_HALT:
1697  case EVENT_RESET:
1698  case EVENT_SHUTDOWN:
1699  mbusClose();
1700  break;
1701 
1702  case EVENT_POWERFAIL:
1703  if (parm)
1704  {
1705  // Running on battery
1706  }
1707  else
1708  {
1709  // Running on external power
1710  }
1711  break;
1712 
1713  case EVENT_POWERSAVE:
1714  if (parm)
1715  {
1716  // Suspend system
1717  }
1718  else
1719  {
1720  // Resume system
1721  }
1722  break;
1723 
1724  default:
1725  mbusDebug(__func__, "Unknown event %d", event);
1726  break;
1727  }
1728 }
1731 /******************************************************************************
1732  **
1733  ** EOF
1734  **
1735  *****************************************************************************/
static pthread_mutex_t lock
thread synchronization lock
Definition: mod_mbus.c:223
static int mbusOpen(int8 mode, int8 rssi)
Opens the connection to the M-Bus module.
Definition: mod_mbus.c:919
int8 rssi
Set to true to include the signal strength (RSSI) for each valid packet.
Definition: mod_mbus.c:63
int16 length
The length of the additional data in the frame.
Definition: mod_mbus.c:85
static int mbusSend(int16 c, int8 *data, int8 size)
Send an M-BUS packet.
Definition: mod_mbus.c:1020
int8 data[MBUS_DATA_LENGTH]
The additional data received from the M-Bus module. Only the first [length] bytes are valid...
Definition: mod_mbus.c:86
static int mbus_config(int8 mode, int8 rssi, int8 only_installed)
Configure a number of common settings.
Definition: mod_mbus.c:712
FUNCTION mbusSend Defines the data structure of the VPL function mbusSend.
Definition: mod_mbus.c:96
static int32 MODDECL mbusCallInfo(HANDLE *pCPU, void *pBase)
Perform a series of tests to validate communication.
Definition: mod_mbus.c:1535
uint8 length
L-field : Length of full frame not including length or any start/stop bytes.
Definition: mod_mbus.c:190
int8 type
Device Type. Part of the address of the slave.
Definition: mod_mbus.c:151
int16 error
error value from call, set by VPL
Definition: mod_mbus.c:144
int16 manufacturer
Manufacturer ID. Part of the address of the slave.
Definition: mod_mbus.c:148
int32 id
Identification number/serial number. Part of the address of the slave.
Definition: mod_mbus.c:149
int16 retval
return value from call, set by VPL
Definition: mod_mbus.c:169
static int cfg_active
Flag to monitor if we are in config mode.
Definition: mod_mbus.c:216
int8 version
Version number. Part of the device address.
Definition: mod_mbus.c:81
FUNCTION mbusReceive Defines the data structure of the VPL function mbusReceive.
Definition: mod_mbus.c:119
int8 only_installed
Set to true to only show packets from installed slaves.
Definition: mod_mbus.c:173
int16 rssi
The signal strength (RSSI), if enabled in mbusOpen().
Definition: mod_mbus.c:83
uint8 type
A-Field[6]:Device type part of address field.
Definition: mod_mbus.c:200
static int32 MODDECL mbusCallSetFilter(HANDLE *pCPU, void *pBase)
Set mode.
Definition: mod_mbus.c:1562
static int fd
serial port handle
Definition: mod_mbus.c:213
static int32 MODDECL mbusCallOpen(HANDLE *pCPU, void *pBase)
Open communication interface to the module.
Definition: mod_mbus.c:1374
static int mbus_read_reg(int8 reg, int size, const char *name)
Reads the value of one or more registers in the M-Bus module and prints the value to the device outpu...
Definition: mod_mbus.c:622
int8 type
Device Type. Part of the device address.
Definition: mod_mbus.c:82
FUNCTION mbusOpen Defines the data structure of the VPL function mbusOpen.
Definition: mod_mbus.c:48
uint32 id
A-Field[4]:ID/Serial number part of address field.
Definition: mod_mbus.c:196
static int mbusConfigCmd(uint8 cmd, uint8 *reply, int size)
Send a single command/argument.
Definition: mod_mbus.c:571
static void mbusDebug(const char *prefix, const char *format,...)
Send a debug message to the device output in the format "<prefix>:<formated string>".
Definition: mod_mbus.c:244
static int mbusConfigExit(void)
Exit configuration mode.
Definition: mod_mbus.c:408
int16 retval
return value from call, set by VPL
Definition: mod_mbus.c:51
FUNCTION mbusSetFilter Defines the data structure of the VPL function mbusSetFilter.
Definition: mod_mbus.c:166
static int mbus_config_mem_reg(uint8 reg, uint8 val)
Change the value of a register in the M-Bus module.
Definition: mod_mbus.c:678
int8 * data
Data to send.
Definition: mod_mbus.c:105
int16 error
error value from call, set by VPL
Definition: mod_mbus.c:123
static int cfg_activated
Flag to monitor if we have received the reply showing the we are in config mode.
Definition: mod_mbus.c:218
static int mbusPower(uint8 power)
Control power to module.
Definition: mod_mbus.c:269
void moduleNotify(int event, int parm)
This function is called by the firmware to notify the module about an event.
Definition: mod_mbus.c:1692
static int32 MODDECL mbusCallClose(HANDLE *pCPU, void *pBase)
Close communication interface to the module.
Definition: mod_mbus.c:1396
int8 version
Version number. Part of the address of the slave.
Definition: mod_mbus.c:150
static int mbus_read_regs(int8 reg, uint8 *buffer, int size)
Reads the value of one or more registers in the M-Bus module and stores the value in the provided buf...
Definition: mod_mbus.c:653
int16 retval
return value from call, set by VPL
Definition: mod_mbus.c:143
static int mbusReceive(tdef_mbus_start_frame *start, int8 *data, int16 *rssi)
Receive a new frame from the M-Bus module.
Definition: mod_mbus.c:1105
static int mbus_info(void)
Print some information about the RF module to the device output.
Definition: mod_mbus.c:1272
static int mbusConfigTransact(uint8 cmd, uint8 *data, int d_size, uint8 *reply, int r_size)
Send a single configuration command with additional data and receive the reply.
Definition: mod_mbus.c:467
int32 id
Identification number/serial number. Part of the device address.
Definition: mod_mbus.c:80
int16 error
error value from call, set by VPL
Definition: mod_mbus.c:100
int16 retval
return value from call, set by VPL
Definition: mod_mbus.c:99
The first block of data when a new MBUS message is received.
Definition: mod_mbus.c:187
int8 control
Control field.
Definition: mod_mbus.c:78
static int mbusConfigFactoryReset(void)
This function performs a factory reset of the RF module.
Definition: mod_mbus.c:764
static int32 MODDECL mbusCallRegisterSlave(HANDLE *pCPU, void *pBase)
Register a slave device.
Definition: mod_mbus.c:1584
static int rssi_included
Flag to keep track of whether the RSSI is included in each packet.
Definition: mod_mbus.c:220
uint16 manufacturer
M-Field : Manufacture ID, e.g. 0x0646 (ARF)
Definition: mod_mbus.c:194
int16 control
Value of the control field to use when sending.
Definition: mod_mbus.c:103
int16 idx
The index of the slave to register. 1-64.
Definition: mod_mbus.c:147
static int32 MODDECL mbusCallSend(HANDLE *pCPU, void *pBase)
Send a MBUS message.
Definition: mod_mbus.c:1457
int16 error
error value from call, set by VPL
Definition: mod_mbus.c:52
STRUCT_BLOCK mbusFrame Defines the data structure of the VPL STRUCT_BLOCK mbusFrame.
Definition: mod_mbus.c:75
static int mbus_register_slave(int idx, int16 manufacturer, int32 id, int8 version, int8 type, uint8 *key)
Registers/installs a slave device on the M-Bus module.
Definition: mod_mbus.c:1222
int16 length
Length of the data to send.
Definition: mod_mbus.c:104
static int mbusClose(void)
Closes the communication interface.
Definition: mod_mbus.c:884
int16 error
error value from call, set by VPL
Definition: mod_mbus.c:170
uint8 * key
Encryption key, 16 bytes. Can be set to NULL when encryption is not used.
Definition: mod_mbus.c:153
uint8 control
C-field : Control byte used to identify packet type.
Definition: mod_mbus.c:192
#define MBUS_DATA_LENGTH
Maximum size of a MBUS message not including header information.
Definition: mod_mbus.c:28
int16 retval
return value from call, set by VPL
Definition: mod_mbus.c:122
int16 manufacture
Manufacture ID. Part of the device address.
Definition: mod_mbus.c:79
FUNCTION mbusRegisterSlave Defines the data structure of the VPL function mbusRegisterSlave.
Definition: mod_mbus.c:140
tdef_mbus_frame * frame
The provided struct is filled with the values of a received M-Bus frame.
Definition: mod_mbus.c:128
int moduleInit(void)
This function is called by the firmware when &#39;extModuleLoad&#39; is called.
Definition: mod_mbus.c:1618
static int32 MODDECL mbusCallReceive(HANDLE *pCPU, void *pBase)
Check if any MBUS packets has been received.
Definition: mod_mbus.c:1417
uint8 version
A-Field[5]:Device version part of address field.
Definition: mod_mbus.c:198
int8 mode
The M-Bus mode to use.
Definition: mod_mbus.c:55
static int mbusConfigEnter(void)
Entering configuration mode.
Definition: mod_mbus.c:304
static int mbusConfigData(uint8 cmd)
Send configuration data.
Definition: mod_mbus.c:589