Radiocraft Wireless M-Bus extension module  2.18
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 #include <semaphore.h>
22 #include <errno.h>
23 
24 /*****************************************************************************
25  **
26  ** DEFINITIONS AND MACROS
27  **
28  *****************************************************************************/
30 #define MBUS_DATA_LENGTH 0xF6
31 #define MAX_SLAVE_REGISTERS 64
32 
33 #define MUTEX_LOCK(m) pthread_mutex_lock(&m)
34 #define MUTEX_UNLOCK(m) pthread_mutex_unlock(&m)
35 #define TH_SEM_RESET(s) while (sem_trywait(&s) == 0)
36 /******************************************************************************
37  **
38  ** TYPEDEFS AND STRUCTURES
39  **
40  *****************************************************************************/
41 
54 struct ALIGN_ATTR mbus_open
55 {
56  //*** var
57  int16 retval;
58  int16 error;
59 
60  //*** var_input
61  int8 mode;
62  int8 rssi;
70  int16 max_frames;
72  int8 overwrite;
73 //*** var_input (access)
74 };
76 typedef struct mbus_open tdef_mbus_open;
77 
83 struct ALIGN_ATTR mbus_frame
84 {
85  //*** var_input
86  int8 control;
87  int8 reserved;
88  int16 manufacture;
89  uint32 id;
90  uint8 version;
91  uint8 type;
92  int16 rssi;
93  uint32 linsec;
95  int16 length;
96  int8 data[MBUS_DATA_LENGTH];
97 };
98 
100 typedef struct mbus_frame tdef_mbus_frame;
101 
106 struct ALIGN_ATTR mbus_send
107 {
108  //*** var
109  int16 retval;
110  int16 error;
111 
112  //*** var_input
113  int16 control;
114  int16 length;
115  int8* data;
116 
117 //*** var_input (access)
118 };
119 
121 typedef struct mbus_send tdef_mbus_send;
122 
129 struct ALIGN_ATTR mbus_filter_receive
130 {
131  //*** var
132  int16 retval;
133  int16 error;
134 
135  //*** var_input
136  int16 idx;
137 
138  //*** var_input (access)
140 };
141 
144 
151 struct ALIGN_ATTR mbus_receive
152 {
153  //*** var
154  int16 retval;
155  int16 error;
156 
157  //*** var_input
158  int32 timeout;
159  int16 manufacturer;
160  uint32 id;
161  uint8 version;
162  uint8 type;
163 
164  //*** var_input (access)
166 };
167 
169 typedef struct mbus_receive tdef_mbus_receive;
170 
177 struct ALIGN_ATTR mbus_reg_slave
178 {
179  //*** var
180  int16 retval;
181  int16 error;
182 
183  //*** var_input
184  int16 idx;
185  int16 manufacturer;
186  uint32 id;
187  uint8 version;
188  uint8 type;
189 
190  uint8* key;
191 
192 //*** var_input (access)
193 };
194 
196 typedef struct mbus_reg_slave tdef_mbus_reg_slave;
197 
203 struct ALIGN_ATTR mbus_set_filter
204 {
205  //*** var
206  int16 retval;
207  int16 error;
208 
209  //*** var_input
211 
212 //*** var_input (access)
213 };
214 
217 
223 struct PACKED_ATTR mbus_start_frame
224 {
226  uint8 length;
228  uint8 control;
232  uint32 id;
234  uint8 version;
236  uint8 type;
237 };
240 
246 {
253 };
256 
257 
263 {
265  uint16 counter;
267  uint16 frames_max;
269  uint16 discarded;
271  int8 overwrite;
276 };
279 
285 {
286  int16 manufacturer;
287  uint32 id;
288  uint8 version;
289  uint8 type;
290 };
293 
294 /******************************************************************************
295  **
296  ** LOCAL VARIABLES
297  **
298  *****************************************************************************/
299 
301 static int fd = -1;
302 
304 static int cfg_active = 0;
306 static int cfg_activated = 0;
308 static int rssi_included = 0;
309 
311 static tdef_mbus_frame_list mbus_flist = {0, 100, 0, 1, NULL, NULL};
312 
315 
317 static pthread_mutex_t lock;
319 static pthread_mutex_t list_lock;
321 static pthread_mutex_t rw_lock;
323 static pthread_t reader;
325 static int run_thread = 0;
327 static sem_t read_sem;
328 /******************************************************************************
329  **
330  ** LOCAL FUNCTIONS
331  **
332  *****************************************************************************/
347 #ifdef DEBUG
348 static void
349 mbusDebug(const char* prefix, const char *format, ...)
350 {
351  va_list valist;
352  char buffer[480];
353 
354  // build debug message;
355  strcpy(buffer, prefix);
356  strcat(buffer, ":");
357  va_start(valist, format);
358  vsprintf(&buffer[strlen(buffer)], format, valist);
359  va_end(valist);
360  vplDebug(buffer);
361 }
362 #else
363 static void
364 mbusDebug(const char* prefix __attribute__((unused)), const char *format __attribute__((unused)), ...)
365 {
366 }
367 #endif
368 
375 static void
376 mbusPrintInfo(const char* prefix, const char *format, ...)
377 {
378  va_list valist;
379  char buffer[480];
380 
381  // build debug message;
382  strcpy(buffer, prefix);
383  strcat(buffer, ":");
384  va_start(valist, format);
385  vsprintf(&buffer[strlen(buffer)], format, valist);
386  va_end(valist);
387  vplDebug(buffer);
388 }
389 
400 {
401  if (a->type == f->type)
402  {
403  if (a->version == f->version && a->id == f->id )
404  {
405  if (a->manufacturer == f->manufacture)
406  {
407  return 1;
408  }
409  }
410  }
411  return 0;
412 }
413 
423 static int
424 mbusPower(uint8 power)
425 {
426  if (vplSetIOSignal(RF_OFF, !power) != 0)
427  {
428  mbusDebug(__func__, "ERR (%d): Failed to set signal", __LINE__);
429  return -1;
430  }
431  if (power)
432  {
433  // Disable CFG mode, as we are now powering the system
434  vplSetIOSignal(RF_CFG, 0);
435  } else {
436  // Assert CFG pin to prevent it from keeping the module powered.
437  vplSetIOSignal(RF_CFG, 1);
438  // power turned off, mark as inactive
439  cfg_activated = 0;
440  }
441 
442  return 0;
443 }
444 
458 static int
460 {
461  uint8 cmd = 0x00;
462  uint8 reply = 0x00;
463  int rc;
464 
465  if (cfg_active)
466  {
467  mbusDebug(__func__, "ERR (%d): Already in config mode", __LINE__);
468  return -1;
469  }
470  // Deassert RF_CFG, to make it ready to assert it in the loop
471  if (vplSetIOSignal(RF_CFG, 0) != 0)
472  {
473  mbusDebug(__func__, "ERR (%d): Failed to set signal", __LINE__);
474  // We failed to set CFG signal, so we are fully depending on the 0x00 command.
475  }
476 
477  for (int try = 0; try < 3; ++try)
478  {
479  // flush both data received but not read and data written but not transmitted.
480  if (tcflush(fd, TCIOFLUSH))
481  {
482  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
483  return -1;
484  }
485 
486  // flush send buffer
487  if (tcdrain(fd))
488  {
489  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
490  return -1;
491  }
492  // set configuration mode request
493  if (vplSetIOSignal(RF_CFG, 1) != 0)
494  {
495  mbusDebug(__func__, "ERR (%d): Failed to set signal", __LINE__);
496  }
497 
498  if (!cfg_activated)
499  {
500  // send enter configuration mode request the first time, in case we already has entered it before, as this will resend the '>'.
501  rc = write(fd, &cmd, 1);
502  if (rc == -1)
503  {
504  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
505  return -1;
506  }
507  if (rc != 1)
508  {
509  mbusDebug(__func__, "ERR (%d): failed to send exit command",
510  __LINE__);
511  return -1;
512  }
513  }
514  usleep(100);
515 
516  // look for OK '>'
517  reply = 0x00;
518  rc = 0;
519  int tries = 0;
520  while (rc == 0 && tries < 3)
521  {
522  rc = read(fd, &reply, 1);
523  if (rc == -1)
524  {
525  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
526  return -1;
527  }
528  tries++;
529  }
530  // deassert config mode signal
531  if (vplSetIOSignal(RF_CFG, 0) != 0)
532  {
533  mbusDebug(__func__, "ERR (%d): Failed to set signal", __LINE__);
534  }
535 
536  if ((rc == 1) && reply == '>')
537  {
538  cfg_activated = 1;
539  break;
540  }
541  }
542  cfg_active = reply == '>';
543  return (reply == '>') ? 0 : 1;
544 }
545 
557 static int
559 {
560  uint8 cmd = 'X';
561  if (!cfg_active)
562  {
563  mbusDebug(__func__, "ERR (%d): config not active", __LINE__);
564  return -1;
565  }
566 
567  // send exit request
568  int rc = write(fd, &cmd, 1);
569  if (rc == -1)
570  {
571  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
572  return -1;
573  }
574  if (rc != 1)
575  {
576  mbusDebug(__func__, "ERR (%d): failed to send exit command", __LINE__);
577  return -1;
578 
579  }
580 
581  // flush send buffer
582  if (tcdrain(fd))
583  {
584  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
585  return -1;
586  }
587  // flush recv buffer
588  if (tcflush(fd, TCIOFLUSH))
589  {
590  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
591  return -1;
592  }
593  cfg_active = 0;
594  cfg_activated = 0;
595  return 0;
596 }
597 
616 static int
617 mbusConfigTransact(uint8 cmd, uint8* data, int d_size, uint8* reply, int r_size)
618 {
619  // write command
620  int rc;
621  rc = write(fd, &cmd, 1);
622  if (rc == -1)
623  {
624  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
625  return -1;
626  }
627  if (rc != 1)
628  {
629  mbusDebug(__func__, "ERR (%d): failed to send 0x%02X", __LINE__, cmd);
630  return -1;
631  }
632 
633  if (data && d_size > 0)
634  {
635  rc = write(fd, data, d_size);
636  if (rc == -1)
637  {
638  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
639  return -1;
640  }
641  if (rc != d_size)
642  {
643  mbusDebug(__func__, "ERR (%d): failed to send 0x%02X", __LINE__, cmd);
644  return -1;
645  }
646  }
647 
648  // flush send buffer
649  if (tcdrain(fd))
650  {
651  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
652  return -1;
653  }
654 
655  // get reply
656  if (r_size > 0)
657  {
658  int remaining = r_size;
659  for (int try = 0; try < 5; try++)
660  {
661  int rc = read(fd, &reply[r_size - remaining], remaining);
662  if (rc == -1)
663  {
664  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
665  return -1;
666  }
667  remaining -= rc;
668  if (remaining == 0)
669  break;
670  usleep(100);
671  }
672  if (remaining)
673  {
674  mbusDebug(__func__,
675  "ERR (%d): unexpected reply to 0x%02X (missing %d of %d)",
676  __LINE__, (cmd & 0xFF), remaining, r_size);
677  return -1;
678  }
679  }
680 
681  // wait for '>'
682  uint8 cfm = 0;
683  for (int try = 0; try < 5; try++)
684  {
685  rc = read(fd, &cfm, 1);
686  if (rc == -1)
687  {
688  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
689  return -1;
690  }
691  if ((rc == 1) && cfm == '>')
692  break;
693  usleep(100);
694  }
695  // no OK reply
696  if (cfm != '>')
697  {
698  mbusDebug(__func__, "ERR (%d): no reply to 0x%02X, 0x%x(%c)", __LINE__,
699  cmd, cfm, cfm);
700  return 1;
701  }
702 
703  return 0;
704 }
705 
722 static int
723 mbusConfigCmd(uint8 cmd, uint8* reply, int size)
724 {
725  return mbusConfigTransact(cmd, NULL, 0, reply, size);
726 }
727 
740 static int
741 mbusConfigData(uint8 cmd)
742 {
743  // write command
744  int rc = write(fd, &cmd, 1);
745  if (rc == -1)
746  {
747  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
748  return -1;
749  }
750  if (rc != 1)
751  {
752  mbusDebug(__func__, "ERR (%d): failed to send 0x%02X", __LINE__, cmd);
753  return -1;
754  }
755 
756  // flush send buffer
757  if (tcdrain(fd))
758  {
759  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
760  return -1;
761  }
762 
763  return 0;
764 }
765 
774 static int mbus_read_reg(int8 reg, int size, const char* name)
775 {
776  uint8 reply[20];
777  char buf[60 + 1];
778  if (size > 20)
779  return -1;
780 
781  // Memory read + reg
782  memset(reply, 0x00, size);
783  for (int i = 0; i < size; ++i)
784  {
785  if (mbusConfigCmd('Y', NULL, 0))
786  return -1;
787  if (mbusConfigCmd(reg + i, &reply[i], 1))
788  return -1;
789  sprintf(&buf[i * 3], "%02X ", reply[i]);
790  }
791 
792  mbusDebug(__func__, "%s = '%s'", name, buf);
793  return 0;
794 
795 }
796 
805 static int mbus_read_regs(int8 reg, uint8* buffer, int size)
806 {
807 
808  // Memory read + reg
809  memset(buffer, 0x00, size);
810  for (int i = 0; i < size; ++i)
811  {
812  if (mbusConfigCmd('Y', NULL, 0))
813  return -1;
814  if (mbusConfigCmd(reg + i, &buffer[i], 1))
815  return -1;
816  }
817 
818  return 0;
819 
820 }
821 
830 static int mbus_config_mem_reg(uint8 reg, uint8 val)
831 {
832  uint8 old_val;
833  // Read before modify
834  if (mbusConfigCmd('Y', NULL, 0))
835  return -1;
836  if (mbusConfigCmd(reg, &old_val, 1))
837  return -1;
838 
839  if (old_val == val)
840  {
841  return 0;
842  }
843 
844  // Memory modify
845  if (mbusConfigCmd('M', NULL, 0))
846  return -1;
847  if (mbusConfigData(reg))
848  return -1; // Addr
849  if (mbusConfigData(val))
850  return -1; // Val
851  if (mbusConfigCmd(0xFF, NULL, 0))
852  return -1; //0xff to end
853  return 0;
854 }
855 
864 static int mbus_config(int8 mode, int8 rssi, int8 only_installed)
865 {
866 
867  if (MUTEX_LOCK(rw_lock))
868  {
869  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
870  return -1;
871  }
872 
873  // request configuration mode
874  if (mbusConfigEnter())
875  {
877  return -1;
878  }
879 
880  if (mode >= 0)
881  {
882  // Memory modify + MBUS_MODE
883  if (mbus_config_mem_reg(0x03, mode))
884  {
886  return -1;
887  }
888  mbus_read_reg(0x03, 1, "MBUS_MODE");
889  }
890 
891  if (rssi >= 0)
892  {
893  // Memory modify + RSSI_MODE
894  if (mbus_config_mem_reg(0x05, rssi ? 1 : 0))
895  {
897  return -1; // Val
898  }
899 
900  mbus_read_reg(0x05, 1, "MBUS_RSSI");
901  rssi_included = rssi;
902  }
903 
904  if (only_installed >= 0)
905  {
906  // Memory modify + INSTALL_MODE
907  if (mbus_config_mem_reg(0x3D, only_installed ? 0 : 2))
908  {
910  return -1;
911  }
912  mbus_read_reg(0x3d, 1, "MBUS_INSTALL_MODE");
913  }
914 
915  // decrypt flag, always enabled
916  if (mbus_config_mem_reg(0x3F, 1))
917  {
919  return -1;
920  }
921  // exit configuration mode and return to IDLE state
922  if (mbusConfigExit())
923  {
925  return -1;
926  }
927 
929  return 0;
930 }
931 
943 static int
944 mbus_receive(tdef_mbus_start_frame *start, int8 *data, int16* rssi)
945 {
946  int rlen, data_size;
947  int remaining = sizeof(*start);
948 
949  if (MUTEX_LOCK(rw_lock))
950  {
951  return -1;
952  }
953  // get length
954  rlen = read(fd, &start->length, 1);
955  if (rlen < 0)
956  {
958  return -1;
959  }
960  if (rlen == 0)
961  {
963  return 0; // no length present in receive buffer
964  }
965  if (start->length == 0)
966  {
968  return 0; // no length present in receive buffer
969  }
970  remaining--;
971 
972  // get rest of start frame
973  int tries = 0;
974  int pos = 0;
975  while (pos < remaining && tries < 3)
976  {
977  rlen = read(fd, (&start->length) + 1 + pos, remaining - pos);
978  if (rlen < 0)
979  {
981  return -1;
982  }
983  pos += rlen;
984  tries++;
985  usleep(1000);
986  }
987 
988  if (pos != remaining)
989  {
990  tcflush(fd, TCIFLUSH); // flush in an attempt to recover
992  return -1; // no length present in receive buffer
993  }
994  if (pos != remaining)
995  {
996  tcflush(fd, TCIFLUSH); // flush in an attempt to recover
998  return -1; // no length present in receive buffer
999  }
1000  // get data
1001  data_size = start->length - sizeof(*start) + 1;
1002 
1003  if (data_size < 0)
1004  {
1005  tcflush(fd, TCIFLUSH); // flush in an attempt to recover
1007  return -1; // no length present in receive buffer
1008  }
1009  if (rssi_included)
1010  {
1011  data_size--;
1012  }
1013  if (data_size > 0)
1014  {
1015  tries = 0;
1016  pos = 0;
1017  memset(data, 0x00, MBUS_DATA_LENGTH);
1018  while (pos < data_size && tries < 3)
1019  {
1020  rlen = read(fd, &data[pos], data_size - pos);
1021  if (rlen < 0)
1022  {
1024  return -1;
1025  }
1026  pos += rlen;
1027  tries++;
1028  usleep(1000);
1029  }
1030  if (pos != data_size)
1031  {
1032  tcflush(fd, TCIFLUSH); // flush in an attempt to recover
1034  return -1; // no length present in receive buffer
1035  }
1036 
1037  }
1038  if (rssi_included)
1039  {
1040  uint8 buf = 0;
1041  rlen = read(fd, &buf, 1);
1042  if (rlen < 0)
1043  {
1045  return -1;
1046  }
1047  if (rlen == 1)
1048  {
1049  if (rssi)
1050  {
1051  *rssi = buf;
1052  }
1053  }
1054  }
1055  start->length = (uint8) data_size;
1057  return 1;
1058 }
1059 
1065 static void mbus_th_reader(void *arg __attribute__((unused)))
1066 {
1067  int rc;
1068  int16 rssi = 0;
1069  int32 linsec = 0;
1070  tdef_mbus_start_frame header;
1071  tdef_mbus_frame_list_elem *e = NULL;
1072 
1073  do {
1074  e = (tdef_mbus_frame_list_elem *) malloc(sizeof(*e));
1075  do {
1076  if ( !(cfg_active) )
1077  {
1078  rc = mbus_receive(&header, e->frame.data, &rssi);
1079  usleep(50);
1080  }
1081  } while ( (rc < 1) && run_thread);
1082  if (rc == 1)
1083  {
1084  linsec = vplClockGet();
1085  e->frame.control = header.control;
1086  e->frame.control = (int8) header.control;
1087  write16b(&e->frame.manufacture, header.manufacturer);
1088  write32b(&e->frame.id, header.id);
1089  e->frame.version = (int8) header.version;
1090  e->frame.type = header.type;
1091  write16b(&e->frame.rssi, rssi);
1092  write32b(&e->frame.linsec, linsec);
1093  write16b(&e->frame.length, header.length);
1094  flist_append(e);
1095  } else {
1096  free(e);
1097  }
1098  } while (run_thread);
1099  pthread_exit(&rc);
1100 }
1101 
1109 static int __attribute__( (unused))
1111 {
1112  uint8 cmd = 0x00;
1113  uint8 reply = 0x00;
1114  int rc;
1115 
1116  if (cfg_active)
1117  {
1118  mbusDebug(__func__, "ERR (%d): Already in config mode", __LINE__);
1119  return -1;
1120  }
1121 
1122  if (MUTEX_LOCK(rw_lock))
1123  {
1124  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
1125  return -1;
1126  }
1127  if (vplSetIOSignal(RF_CFG, 0) != 0)
1128  {
1129  mbusDebug(__func__, "ERR (%d): Failed to set signal", __LINE__);
1130  }
1131  //sleep(1);
1132  for (int try = 0; try < 3; ++try)
1133  {
1134  // flush both data received but not read and data written but not transmitted.
1135  if (tcflush(fd, TCIOFLUSH))
1136  {
1138  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1139  return -1;
1140  }
1141 
1142  // flush send buffer
1143  if (tcdrain(fd))
1144  {
1146  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1147  return -1;
1148  }
1149  // set configuration mode request
1150  if (vplSetIOSignal(RF_CFG, 1) != 0)
1151  {
1152  mbusDebug(__func__, "ERR (%d): Failed to set signal", __LINE__);
1153  }
1154 
1155  if (!cfg_activated)
1156  {
1157  // send enter configuration mode request the first time, in case we already has entered it before, as this will resend the '>'.
1158  rc = write(fd, &cmd, 1);
1159  if (rc == -1)
1160  {
1162  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1163  return -1;
1164  }
1165  if (rc != 1)
1166  {
1168  mbusDebug(__func__, "ERR (%d): failed to send exit command",
1169  __LINE__);
1170  return -1;
1171  }
1172 
1173  }
1174  usleep(100);
1175 
1176  // look for OK '>'
1177  reply = 0x00;
1178  rc = 0;
1179  int tries = 0;
1180  while (rc == 0 && tries < 3)
1181  {
1182  rc = read(fd, &reply, 1);
1183  if (rc == -1)
1184  {
1186  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1187  return -1;
1188  }
1189  tries++;
1190  usleep(10000);
1191  }
1192 
1193  if ((rc == 1) && reply == '>')
1194  {
1195  cfg_activated = 1;
1196  // In config mode: Send "reset to factory settings" request
1197  rc = mbusConfigTransact('@', (uint8*) "RC", 2, NULL, 0);
1198 
1199  // deassert config mode signal
1200  if (vplSetIOSignal(RF_CFG, 0) != 0)
1201  {
1202  mbusDebug(__func__, "ERR (%d): Failed to set signal", __LINE__);
1203  }
1204  break;
1205  }
1206  else
1207  {
1208 
1209  //sleep(1);
1210  }
1211  // deassert config mode signal
1212  if (vplSetIOSignal(RF_CFG, 0) != 0)
1213  {
1214  mbusDebug(__func__, "ERR (%d): Failed to set signal", __LINE__);
1215  }
1216 
1217  }
1218 
1219  cfg_active = reply == '>';
1220 
1221  rc = mbusConfigExit();
1223  return rc;
1224 }
1225 
1240 {
1242  tdef_mbus_frame_list_elem* e = NULL;
1243 
1244  if (fl->flist_tail != NULL)
1245  {
1246  e = fl->flist_tail;
1247  if (fl->flist_tail == fl->flist_head)
1248  {
1249  if ( !(fl->counter == 1 && e->next == NULL) )
1250  {
1251  mbusDebug(__func__, "ERR (%d): list corruption! Counter was %d", __LINE__, fl->counter);
1252  }
1253  fl->flist_head = NULL;
1254  fl->flist_tail = NULL;
1255  fl->counter--;
1256  return e;
1257  }
1258  fl->flist_tail = e->prev;
1259  fl->flist_tail->next = NULL;
1260  e->next = NULL;
1261  e->prev = NULL;
1262  fl->counter--;
1263  }
1264  return e;
1265 }
1266 
1275 {
1277  tdef_mbus_frame_list_elem* e = NULL;
1278  int match = 0;
1279 
1280  if (MUTEX_LOCK(list_lock))
1281  {
1282  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
1283  return NULL;
1284  }
1285  if ( !(fl->flist_head && fl->flist_tail) )
1286  {
1288  return NULL;
1289  }
1290  if (address->type == 0xff) // Wildcard value 0xff: See Open Metering System Specification Vol 2 - Table 4 – Device Types of not certifiable device
1291  {
1294  return e;
1295  }
1296  e = fl->flist_tail;
1297  do
1298  {
1299  if (!e)
1300  {
1302  return NULL;
1303  }
1304  match = mbus_address_compare(address, &e->frame);
1305  if (match)
1306  {
1307  if (e == fl->flist_tail)
1308  {
1311  return e;
1312  }
1313  if (e == fl->flist_head)
1314  {
1315  fl->flist_head = fl->flist_head->next;
1316  fl->flist_head->prev = NULL;
1317  e->next = NULL;
1318  e->prev = NULL;
1319  fl->counter--;
1321  return e;
1322  }
1323  e->next->prev = e->prev;
1324  e->prev->next = e->next;
1325  e->next = NULL;
1326  e->prev = NULL;
1327  fl->counter--;
1328  }
1329  else
1330  {
1331  e = e->prev;
1332  }
1333  }
1334  while(!match);
1335 
1337  return e;
1338 }
1339 
1340 
1347 {
1349  tdef_mbus_frame_list_elem* e2 = NULL;
1350 
1351  if (MUTEX_LOCK(list_lock))
1352  {
1353  return;
1354  }
1355  if (fl->counter >= fl->frames_max)
1356  {
1357  if (fl->overwrite)
1358  {
1359  e2 = fl->flist_tail;
1360  if (e2->next) {
1361  mbusDebug(__func__, "ERR (%d): list corruption! Element next pointer should be NULL. Counter was %d", __LINE__, fl->counter);
1362  }
1363  e2->prev->next = NULL;
1364  fl->flist_tail = e2->prev;
1365  e2->next = NULL;
1366  e2->prev = NULL;
1367  free(e2);
1368  fl->flist_head->prev = e;
1369  e->next = fl->flist_head;
1370  e->prev = NULL;
1371  fl->flist_head = e;
1372  fl->discarded++;
1373  } else {
1374  free(e);
1375  fl->discarded++;
1376  }
1378  return;
1379  }
1380  if (fl->flist_head == NULL)
1381  {
1382  fl->flist_head = e;
1383  fl->flist_tail = e;
1384  e->next = NULL;
1385  e->prev = NULL;
1386  } else {
1387  fl->flist_head->prev = e;
1388  e->next = fl->flist_head;
1389  e->prev = NULL;
1390  fl->flist_head = e;
1391  }
1392  fl->counter++;
1393  sem_post(&read_sem);
1395 }
1396 
1405 static int flist_clear(void)
1406 {
1409  int rc;
1410 
1411  if (MUTEX_LOCK(list_lock))
1412  {
1413  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
1414  return -1;
1415  }
1416  do {
1418  if (e)
1419  {
1420  free(e);
1421  }
1422  } while (e);
1423  fl->flist_head = NULL;
1424  fl->flist_tail = NULL;
1425  rc = fl->counter;
1427  return rc;
1428 }
1429 
1454 static int mbusBufferReceive(tdef_mbus_frame *rframe, tdef_mbus_slave_address *address, int32 timeout)
1455 {
1456  struct timespec ts;
1458  int rc = 0;
1459  int rc2;
1460 
1461  if (!run_thread) return -2;
1462  if (clock_gettime(CLOCK_REALTIME, &ts) == -1) return -1;
1463 
1464  ts.tv_sec += timeout/1000;
1465  ts.tv_nsec +=(timeout%1000)*1000000;
1466  do
1467  {
1468  e = flist_search_remove(address);
1469  if (!e)
1470  {
1471  if (timeout)
1472  {
1474  MUTEX_UNLOCK(lock);
1475  if (timeout < 0)
1476  {
1477  rc2 = sem_wait(&read_sem);
1478  }
1479  else
1480  {
1481  rc2 = sem_timedwait(&read_sem, &ts);
1482  }
1483  MUTEX_LOCK(lock);
1484  }
1485  }
1486  } while ( !e && errno != ETIMEDOUT && timeout && rc2 >= 0 );
1487 
1488  if (e)
1489  {
1490  rframe->control = (int8) e->frame.control;
1491  write16b(&rframe->manufacture, e->frame.manufacture);
1492  write32b(&rframe->id, e->frame.id);
1493  rframe->version = (int8) e->frame.version;
1494  rframe->type = e->frame.type;
1495  write16b(&rframe->rssi, e->frame.rssi);
1496  write32b(&rframe->linsec, e->frame.linsec);
1497  write16b(&rframe->length, e->frame.length);
1498  memcpy(&rframe->data, e->frame.data, e->frame.length);
1499  rc = 1;
1500  free(e);
1501  }
1502 
1503  return rc;
1504 }
1505 
1511 static int
1513 {
1514  if (MUTEX_LOCK(rw_lock))
1515  {
1516  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
1517  return -1;
1518  }
1519  if (fd >= 0)
1520  {
1521  // flush both data received but not read and data written but not transmitted.
1522  tcflush(fd, TCIOFLUSH);
1523  if (close(fd))
1524  {
1525  cfg_active = 0;
1526  cfg_activated = 0;
1528  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1529  return -1;
1530  }
1531  mbusPower(0);
1532  fd = -1;
1533  }
1534  cfg_active = 0;
1535  cfg_activated = 0;
1537  return 0;
1538 }
1539 
1557 static int
1558 mbusOpen(int8 mode, int8 rssi)
1559 {
1560  char port_path[200];
1561  struct termios tty;
1562 
1563  if (MUTEX_LOCK(rw_lock))
1564  {
1565  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
1566  return -1;
1567  }
1568  if (fd >= 0) {
1570  mbusDebug(__func__, "ERR: Communication interface already opened:");
1571  return -1;
1572  }
1573 
1574  if (vplFsMapFile(port_path, 200, "dev:ser3"))
1575  {
1577  mbusDebug(__func__, "ERR: Failed to open port:");
1578  return -1;
1579  }
1580 
1581  fd = open(port_path, O_RDWR | O_NOCTTY | O_SYNC);
1582  if (fd < 0)
1583  {
1585  mbusDebug(__func__, "ERR: Failed to open '%s': %s", port_path,
1586  strerror(errno));
1587  return -1;
1588  }
1589 
1590  memset(&tty, 0, sizeof tty);
1591  if (tcgetattr(fd, &tty) != 0)
1592  {
1594  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1595  return -1;
1596  }
1597 
1598  // default baud rate 19.2kBs
1599  cfsetospeed(&tty, B19200);
1600  cfsetispeed(&tty, B19200);
1601 
1602  tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
1603  tty.c_cflag &= ~CSIZE;
1604  tty.c_cflag |= CS8; /* 8-bit characters */
1605  tty.c_cflag &= ~PARENB; /* no parity bit */
1606  tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
1607  tty.c_cflag &= ~CRTSCTS; /* no hardware flow control */
1608 
1609  /* setup for non-canonical mode */
1610  tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL
1611  | IXON);
1612  tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
1613  tty.c_oflag &= ~OPOST;
1614 
1615  /* fetch bytes as they become available */
1616  tty.c_cc[VMIN] = (cc_t) 0; // non-blocking mode, only using timeout
1617  tty.c_cc[VTIME] = (cc_t) 10; // 1 seconds read timeout
1618 
1619  if (tcsetattr(fd, TCSANOW, &tty) != 0)
1620  {
1621  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1622  }
1623 
1624  if (mbusPower(1))
1625  {
1627  return -1;
1628  }
1629  // reset module by entering and exiting configuration mode
1630  int i;
1631  for (i = 0; i < 5; ++i)
1632  {
1633  if (mbusConfigEnter() == 0)
1634  {
1635  if (mbusConfigExit() == 0)
1636  {
1637  break;
1638  }
1639  }
1640  }
1641  if (i >= 5)
1642  {
1643  mbusDebug(__func__, "ERR (%d): failed to reset module", __LINE__);
1644  }
1646 
1647  if (mbus_config(mode, rssi, -1))
1648  {
1649  mbusPower(0);
1650  return -1;
1651  }
1652 
1653  return 0;
1654 }
1655 
1669 static int
1670 mbusSend(int16 c, int8* data, int8 size)
1671 {
1672  int send = 0;
1673 
1674  if (MUTEX_LOCK(rw_lock)) {
1675  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
1676  return -1;
1677  }
1678  if (c >= 0)
1679  {
1680  // change control byte
1681  if (mbusConfigEnter()) {
1683  return -1;
1684  }
1685  if (mbusConfigCmd('F', NULL, 0))
1686  {
1687  mbusConfigExit();
1689  return -1;
1690  }
1691  if (mbusConfigCmd(c, NULL, 0))
1692  {
1693  mbusConfigExit();
1695  return -1;
1696  }
1697  if (mbusConfigExit()) {
1699  return -1;
1700  }
1701  // Delay 1.1ms from end of config to idle.
1702  usleep(1100);
1703  }
1704 
1705  // send length if given else request header only
1706  if (size == 0)
1707  {
1708  int cmd = 0xFE;
1709  // send only header information
1710  send = write(fd, &cmd, 1);
1711  if (send == -1)
1712  {
1714  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1715  return -1;
1716  }
1717  if (send != 1)
1718  {
1720  mbusDebug(__func__, "(%d): Failed to write send request", __LINE__);
1721  return -1;
1722  }
1723  }
1724  else
1725  {
1726  // send data length
1727  send = write(fd, &size, 1);
1728  if (send == -1)
1729  {
1731  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1732  return -1;
1733  }
1734  if (send != 1)
1735  {
1737  mbusDebug(__func__, "(%d): Failed to write data length", __LINE__);
1738  return -1;
1739  }
1740  send = write(fd, data, size);
1741  if (send == -1)
1742  {
1744  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
1745  return -1;
1746  }
1747  if (send != size)
1748  {
1750  mbusDebug(__func__, "(%d): Failed to write data (%d of %d)", __LINE__,
1751  send, size);
1752  return -1;
1753  }
1754  }
1755 
1757  return 0;
1758 }
1759 
1774 static int
1775 mbus_register_slave(int idx, int16 manufacturer, int32 id, int8 version,
1776  int8 type,
1777  uint8* key)
1778 {
1779  uint8 addr[8];
1780 
1781 // curent slave index
1782  if (idx >= MAX_SLAVE_REGISTERS || idx < 0)
1783  {
1784  return -2;
1785  }
1786  memcpy(&addr[0], &id, 4);
1787  memcpy(&addr[4], &manufacturer, 2);
1788  memcpy(&addr[6], &version, 1);
1789  memcpy(&addr[7], &type, 1);
1790  memcpy(&mbus_slave_register[idx].id, &id, 4);
1791  memcpy(&mbus_slave_register[idx].manufacturer, &manufacturer, 2);
1792  memcpy(&mbus_slave_register[idx].version, &version, 1);
1793  memcpy(&mbus_slave_register[idx].type, &type, 1);
1794  if (MUTEX_LOCK(rw_lock))
1795  {
1796  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
1797  return -1;
1798  }
1799  // request configuration mode
1800  if (mbusConfigEnter())
1801  {
1803  return -1;
1804  }
1805  // bind slave
1806  if (mbusConfigCmd('B', NULL, 0))
1807  {
1809  return -1;
1810  }
1811  if (mbusConfigTransact(idx+1, addr, 8, NULL, 0))
1812  {
1814  return -1;
1815  }
1816 
1817  if (key)
1818  {
1819  // set key for slave
1820  if (mbusConfigCmd('K', NULL, 0))
1821  {
1823  return -1;
1824  }
1825  if (mbusConfigTransact(idx+1, key, 16, NULL, 0))
1826  {
1828  return -1; // Slave ID
1829  }
1830  }
1831 
1832  // exit configuration mode and return to IDLE state
1833  if (mbusConfigExit())
1834  {
1836  return -1;
1837  }
1838 
1840  return 0;
1841 }
1842 
1849 static int
1851 {
1852  uint8 reply[20];
1853  char serial[8 * 3];
1854  int i;
1855 
1856  if (MUTEX_LOCK(rw_lock))
1857  {
1858  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
1859  return -1;
1860  }
1861 
1862  // request configuration mode
1863  if (mbusConfigEnter())
1864  {
1866  return -1;
1867  }
1868 
1869  // Signal strength
1870  if (mbusConfigCmd('Q', reply, 1))
1871  {
1873  return -1;
1874  }
1875  mbusPrintInfo(__func__, "Signal quality = %d", reply[0]);
1876 
1877  // Signal strength
1878  if (mbusConfigCmd('S', reply, 1))
1879  {
1881  return -1;
1882  }
1883  mbusPrintInfo(__func__, "RSSI = %d (%d dBm)", reply[0],
1884  ((-reply[0]) / 2));
1885 
1886  // Temperature monitoring
1887  if (mbusConfigCmd('U', reply, 1))
1888  {
1890  return -1;
1891  }
1892  mbusPrintInfo(__func__, "Temperature = %d C", (reply[0] - 128));
1893 
1894  // Battery Monitoring
1895  if (mbusConfigCmd('V', reply, 1))
1896  {
1898  return -1;
1899  }
1900  mbusPrintInfo(__func__, "VCC = %dmV", (reply[0] * 30));
1901 
1902  // Memory read + MBUS_MODE
1903  if (mbusConfigCmd('Y', NULL, 0))
1904  {
1906  return -1;
1907  }
1908  if (mbusConfigCmd(0x03, reply, 1))
1909  {
1911  return -1;
1912  }
1913  mbusPrintInfo(__func__, "MBUS_MODE = 0x%02X", reply[0]);
1914 
1915  // Memory read + DATA_INTERFACE
1916  if (mbus_read_regs(0x36, reply, 1))
1917  {
1919  return -1;
1920  }
1921  mbusPrintInfo(__func__, "DATA_INTERFACE = 0x%02X", reply[0]);
1922 
1923  // Memory read + PART_NUMBER
1924  if (mbus_read_regs(0x61, reply, 12))
1925  {
1927  return -1;
1928  }
1929  reply[12] = 0;
1930  mbusPrintInfo(__func__, "PART_NUMBER = '%s'", reply);
1931 
1932  // Memory read + HW_REV_NO
1933  if (mbus_read_regs(0x6E, reply, 4))
1934  {
1936  return -1;
1937  }
1938  reply[4] = 0;
1939  mbusPrintInfo(__func__, "HW_REV_NO = '%s'", reply);
1940 
1941  // Memory read + FW_REV_NO
1942  if (mbus_read_regs(0x73, reply, 4))
1943  {
1945  return -1;
1946  }
1947  reply[4] = 0;
1948  mbusPrintInfo(__func__, "FW_REV_NO = '%s'", reply);
1949 
1950  // Memory read + SERIAL_NUMBER
1951  if (mbus_read_regs(0x78, reply, 8))
1952  {
1954  return -1;
1955  }
1956  for (i = 0; i < 8; i++)
1957  {
1958  sprintf(&serial[i * 3], "%02X ", reply[i]);
1959  }
1960  serial[8 * 3 - 1] = 0;
1961  mbusPrintInfo(__func__, "SERIAL_NUMBER = %s", serial);
1962 
1963  if (mbus_read_regs(0x3d, reply, 1))
1964  {
1966  return -1;
1967  }
1968  mbusPrintInfo(__func__, "INSTALL_MODE = 0x%02X", reply[0]);
1969 
1970  if (mbus_read_regs(0x05, reply, 1))
1971  {
1973  return -1;
1974  }
1975  mbusPrintInfo(__func__, "RSSI_MODE = 0x%02X", reply[0]);
1976 
1977  // exit configuration mode and return to IDLE state
1978  if (mbusConfigExit())
1979  {
1981  return -1;
1982  }
1983 
1985  return 0;
1986 }
1987 
1997 static int mbusStartReader(uint16 buf_size, int8 overwrite)
1998 {
2000  int rc;
2001 
2002  if ( !(buf_size > 0 && buf_size <= 1000) )
2003  {
2004  return -2;
2005  }
2006  fl->frames_max = buf_size;
2007  fl->overwrite = overwrite;
2008  fl->counter = 0;
2009  fl->discarded = 0;
2010  fl->flist_head = NULL;
2011  fl->flist_tail = NULL;
2012  run_thread = 1;
2013  rc = sem_init(&read_sem,0,0);
2014 
2015  rc += pthread_create(&reader, NULL, (void *) &mbus_th_reader, NULL);
2016  return rc;
2017 }
2018 
2019 
2026 static int mbusStopReader(void)
2027 {
2028  int rc;
2029 
2030  run_thread = 0;
2031  sem_post(&read_sem);
2032  usleep(2000000);
2033  rc = flist_clear();
2034  return rc;
2035 }
2036 
2037 
2043 static int mbusGetBufferLevel(void)
2044 {
2046 
2047  if ( fl->counter == fl->frames_max) return 1000;
2048  return ( (fl->counter*1000)/fl->frames_max );
2049 }
2050 
2067 static int32 MODDECL
2068 mbusCallOpen(HANDLE* pCPU __attribute__( (unused)),
2069  void* pBase)
2070 {
2071  tdef_mbus_open* pdata = (tdef_mbus_open*) pBase;
2072  if (MUTEX_LOCK(lock))
2073  {
2074  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
2075  return -1;
2076  }
2077  int rc = mbusOpen(pdata->mode, pdata->rssi);
2078  int rc2 = mbusStartReader(pdata->max_frames, pdata->overwrite);
2079  MUTEX_UNLOCK(lock);
2080  if (rc == 0 && rc2 == -2) return -2;
2081  return rc;
2082 }
2083 
2094 static int32 MODDECL
2095 mbusCallClose(HANDLE* pCPU __attribute__((unused)),
2096  void* pBase __attribute__((unused)))
2097 {
2098  if (MUTEX_LOCK(lock))
2099  {
2100  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
2101  return -1;
2102  }
2103  int rc2 = mbusStopReader();
2104  int rc = mbusClose();
2105  MUTEX_UNLOCK(lock);
2106  if (rc == 0) return rc2? -2 : 0;
2107  return rc2? -3 : -1;
2108 }
2109 
2122 static int32 MODDECL
2123 mbusCallFilterReceive(HANDLE* pCPU __attribute__((unused)), void* pBase)
2124 {
2126  tdef_mbus_slave_address address;
2127  int rc = 0;
2128  int idx;
2129 
2130  if ( pdata->idx > MAX_SLAVE_REGISTERS || pdata->idx <= 0) return -3;
2131  idx = pdata->idx - 1;
2132  if ( mbus_slave_register[idx].manufacturer == 0) return -4;
2133 
2134  if (MUTEX_LOCK(lock))
2135  {
2136  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
2137  return -1;
2138  }
2139  write16b(&address.manufacturer, mbus_slave_register[idx].manufacturer);
2140  write32b(&address.id, mbus_slave_register[idx].id);
2141  address.type = mbus_slave_register[idx].type;
2142  address.version = mbus_slave_register[idx].version;
2143  rc = mbusBufferReceive(pdata->frame, &address, 0);
2144 
2145  MUTEX_UNLOCK(lock);
2146  return rc;
2147 }
2148 
2159 static int32 MODDECL
2160 mbusCallReceive(HANDLE* pCPU __attribute__((unused)), void* pBase)
2161 {
2162  tdef_mbus_slave_address address;
2163  tdef_mbus_receive *pdata = (tdef_mbus_receive*) pBase;
2164  int rc;
2165 
2166  if (MUTEX_LOCK(lock))
2167  {
2168  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
2169  return -1;
2170  }
2171  write16b(&address.manufacturer, pdata->manufacturer);
2172  write32b(&address.id, pdata->id);
2173  address.type = pdata->type;
2174  address.version = pdata->version;
2175  rc = mbusBufferReceive(pdata->frame, &address, pdata->timeout);
2176 
2177  MUTEX_UNLOCK(lock);
2178  return rc;
2179 }
2180 
2189 static int32 MODDECL
2190 mbusCallSend(HANDLE* pCPU __attribute__((unused)), void* pBase)
2191 {
2192  tdef_mbus_send *pdata = (tdef_mbus_send*) pBase;
2193 
2194  if ((pdata->length > 0) && !pdata->data)
2195  {
2196  mbusDebug(__func__, "ERR (%d): missing data", __LINE__);
2197  return -1;
2198  }
2199 
2200  if ((pdata->length < 0) || (pdata->length > MBUS_DATA_LENGTH))
2201  {
2202  mbusDebug(__func__, "ERR (%d): illegal data length %d", __LINE__,
2203  pdata->length);
2204  return -1;
2205  }
2206 
2207  if ((pdata->control < -1) || (pdata->control > 0xFF))
2208  {
2209  mbusDebug(__func__, "ERR (%d): illegal control value %d", __LINE__,
2210  pdata->length);
2211  return -1;
2212  }
2213 
2214  if (MUTEX_LOCK(lock)) {
2215  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
2216  return -1;
2217  }
2218 
2219  int rc = mbusSend(pdata->control, pdata->data, pdata->length);
2220  if (rc && (pdata->control >= 0) )
2221  {
2222  mbusDebug(__func__, "error (%d) - resetting interface", rc);
2223  mbusClose();
2224  mbusOpen(-1, rssi_included);
2225  }
2226 
2227  MUTEX_UNLOCK(lock);
2228  return rc ? -2 : 0;
2229 }
2230 
2273 static int32 MODDECL
2274 mbusCallInfo(HANDLE* pCPU __attribute__((unused)),
2275  void* pBase __attribute__((unused)))
2276 {
2277  if (MUTEX_LOCK(lock))
2278  {
2279  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
2280  return -1;
2281  }
2282 
2283  int rc = mbus_info();
2284  if (rc)
2285  {
2286  mbusDebug(__func__, "error (%d) - resetting interface", rc);
2287  mbusClose();
2288  mbusOpen(-1, rssi_included);
2289  }
2290 
2291  MUTEX_UNLOCK(lock);
2292  return rc ? -2 : 0;
2293 }
2294 
2301 static int32 MODDECL
2302 mbusCallFilterEnable(HANDLE* pCPU __attribute__( (unused)),
2303  void* pBase)
2304 {
2305  tdef_mbus_set_filter* pdata = (tdef_mbus_set_filter*) pBase;
2306  if (MUTEX_LOCK(lock))
2307  {
2308  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
2309  return -1;
2310  }
2311 
2312  int rc = mbus_config(-1, -1, pdata->only_installed);
2313  if (rc)
2314  {
2315  mbusDebug(__func__, "error (%d) - resetting interface", rc);
2316  mbusClose();
2317  mbusOpen(-1, rssi_included);
2318  }
2319  MUTEX_UNLOCK(lock);
2320 
2321  return rc;
2322 }
2323 
2330 static int32 MODDECL
2331 mbusCallRegisterSlave(HANDLE* pCPU __attribute__( (unused)),
2332  void* pBase)
2333 {
2334  tdef_mbus_reg_slave* pdata = (tdef_mbus_reg_slave*) pBase;
2335  if (MUTEX_LOCK(lock))
2336  {
2337  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
2338  return -1;
2339  }
2340 
2341  int rc = mbus_register_slave(pdata->idx-1, pdata->manufacturer, pdata->id,
2342  pdata->version, pdata->type, pdata->key);
2343 
2344  if (rc)
2345  {
2346  mbusDebug(__func__, "error (%d) - resetting interface", rc);
2347  mbusClose();
2348  mbusOpen(-1, rssi_included);
2349  }
2350 
2351  MUTEX_UNLOCK(lock);
2352 
2353  return rc;
2354 }
2355 
2364 static int32 MODDECL
2365 mbusCallGetBufferLevel(HANDLE* pCPU __attribute__( (unused)),
2366  void* pBase __attribute__( (unused)))
2367 {
2368  if (MUTEX_LOCK(lock))
2369  {
2370  mbusDebug(__func__, "ERR (%d): failed to get lock", __LINE__);
2371  return -1;
2372  }
2373  int rc = mbusGetBufferLevel();
2374  MUTEX_UNLOCK(lock);
2375  return rc;
2376 }
2377 
2394 int
2396 {
2397  // Var
2398  uint16 rc;
2399  pthread_mutexattr_t lock_attr;
2400  pthread_mutexattr_t list_lock_attr;
2401  pthread_mutexattr_t rw_lock_attr;
2402 
2403  vplFunctionEntry ftable[] =
2404  {
2405  { "mbusOpen", mbusCallOpen },
2406  { "mbusClose", mbusCallClose },
2407  { "mbusSend", mbusCallSend },
2408  { "mbusFilterReceive", mbusCallFilterReceive },
2409  { "mbusReceive", mbusCallReceive },
2410  { "mbusInfo", mbusCallInfo },
2411  { "mbusRegisterSlave", mbusCallRegisterSlave },
2412  { "mbusFilterEnable", mbusCallFilterEnable },
2413  { "mbusGetBufferLevel", mbusCallGetBufferLevel },
2414  {
2415  NULL, NULL } };
2416 
2417  mbusDebug(__func__, "Initializing");
2418 
2419  // initialize API lock
2420  rc = pthread_mutexattr_init(&lock_attr);
2421  if (rc != 0)
2422  {
2423  mbusDebug(__func__, "ERR (%d): %d", __LINE__, rc);
2424  return 1;
2425  }
2426  rc = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
2427  if (rc != 0)
2428  {
2429  mbusDebug(__func__, "ERR (%d): %d", __LINE__, rc);
2430  return 1;
2431  }
2432  rc = pthread_mutex_init(&lock, &lock_attr);
2433  if (rc != 0)
2434  {
2435  mbusDebug(__func__, "ERR (%d): %d", __LINE__, rc);
2436  return 1;
2437  }
2438 
2439  rc = pthread_mutexattr_init(&list_lock_attr);
2440  if (rc != 0)
2441  {
2442  mbusDebug(__func__, "ERR (%d): %d", __LINE__, rc);
2443  return 1;
2444  }
2445  rc = pthread_mutexattr_settype(&list_lock_attr, PTHREAD_MUTEX_RECURSIVE);
2446  if (rc != 0)
2447  {
2448  mbusDebug(__func__, "ERR (%d): %d", __LINE__, rc);
2449  return 1;
2450  }
2451  rc = pthread_mutex_init(&lock, &list_lock_attr);
2452  if (rc != 0)
2453  {
2454  mbusDebug(__func__, "ERR (%d): %d", __LINE__, rc);
2455  return 1;
2456  }
2457 
2458  rc = pthread_mutexattr_init(&rw_lock_attr);
2459  if (rc != 0)
2460  {
2461  mbusDebug(__func__, "ERR (%d): %d", __LINE__, rc);
2462  return 1;
2463  }
2464  rc = pthread_mutexattr_settype(&rw_lock_attr, PTHREAD_MUTEX_RECURSIVE);
2465  if (rc != 0)
2466  {
2467  mbusDebug(__func__, "ERR (%d): %d", __LINE__, rc);
2468  return 1;
2469  }
2470  rc = pthread_mutex_init(&lock, &rw_lock_attr);
2471  if (rc != 0)
2472  {
2473  mbusDebug(__func__, "ERR (%d): %d", __LINE__, rc);
2474  return 1;
2475  }
2476 
2477  // Initialize module
2478  rc = vplInstallFunctions("mod_mbus", ftable);
2479  if (rc)
2480  {
2481  // Install failed
2482  mbusDebug(__func__, "failed to install 'mod_mbus' functions err %d", rc);
2483  return 1;
2484  }
2485 
2486  if (vplSetIOSignal(RF_CFG, 0) != 0)
2487  {
2488  mbusDebug(__func__, "ERR (%d): %s", __LINE__, strerror(errno));
2489  }
2490 
2491  if (mbusPower(0))
2492  return -1;
2493 
2494  for (int i=0; i<MAX_SLAVE_REGISTERS; i++)
2495  {
2496  mbus_slave_register[i].id = 0;
2499  mbus_slave_register[i].type = 0;
2500  }
2501  cfg_active = 0;
2502  cfg_activated = 0;
2503 
2504  // Completed
2505  return 0;
2506 }
2507 
2521 void
2522 moduleNotify(int event, int parm)
2523 {
2524  switch (event)
2525  {
2526  case EVENT_HALT:
2527  case EVENT_RESET:
2528  case EVENT_SHUTDOWN:
2529  mbusClose();
2530  mbusStopReader();
2531  break;
2532 
2533  case EVENT_POWERFAIL:
2534  if (parm)
2535  {
2536  // Running on battery
2537  }
2538  else
2539  {
2540  // Running on external power
2541  }
2542  break;
2543 
2544  case EVENT_POWERSAVE:
2545  if (parm)
2546  {
2547  // Suspend system
2548  }
2549  else
2550  {
2551  // Resume system
2552  }
2553  break;
2554 
2555  default:
2556  mbusDebug(__func__, "Unknown event %d", event);
2557  break;
2558  }
2559 }
2562 /******************************************************************************
2563  **
2564  ** EOF
2565  **
2566  *****************************************************************************/
flist_remove_first_element
static tdef_mbus_frame_list_elem * flist_remove_first_element(void)
Take out the oldest element in the buffer list and return a pointer to it.
Definition: mod_mbus.c:1239
mbus_start_frame::manufacturer
int16 manufacturer
M-Field : Manufacture ID, e.g. 0x0646 (ARF)
Definition: mod_mbus.c:230
flist_clear
static int flist_clear(void)
Clear the internal buffer list.
Definition: mod_mbus.c:1405
mbus_slave_address::manufacturer
int16 manufacturer
Manufacturer ID. Part of the address of the slave.
Definition: mod_mbus.c:286
mbusGetBufferLevel
static int mbusGetBufferLevel(void)
Get the actual level of how full the buffer is in promille.
Definition: mod_mbus.c:2043
mbus_frame_list_elem::frame
tdef_mbus_frame frame
Received frame.
Definition: mod_mbus.c:252
mbusSend
static int mbusSend(int16 c, int8 *data, int8 size)
Send an M-BUS packet.
Definition: mod_mbus.c:1670
flist_search_remove
static tdef_mbus_frame_list_elem * flist_search_remove(tdef_mbus_slave_address *address)
Search for and remove element from the buffer list, based on a given slave address,...
Definition: mod_mbus.c:1274
mbus_receive
FUNCTION mbusReceive Defines the data structure of the VPL function mbusReceive.
Definition: mod_mbus.c:152
mbus_frame::length
int16 length
The length of the additional data in the frame.
Definition: mod_mbus.c:95
lock
static pthread_mutex_t lock
thread synchronization lock
Definition: mod_mbus.c:317
mbusClose
static int mbusClose(void)
Closes the communication interface.
Definition: mod_mbus.c:1512
cfg_activated
static int cfg_activated
Flag to monitor if we have received the reply showing the we are in config mode.
Definition: mod_mbus.c:306
mbusCallGetBufferLevel
static int32 MODDECL mbusCallGetBufferLevel(HANDLE *pCPU, void *pBase)
Get the actual level of how full the buffer is in promille.
Definition: mod_mbus.c:2365
mbusCallRegisterSlave
static int32 MODDECL mbusCallRegisterSlave(HANDLE *pCPU, void *pBase)
Register a slave device.
Definition: mod_mbus.c:2331
mbusCallInfo
static int32 MODDECL mbusCallInfo(HANDLE *pCPU, void *pBase)
Perform a series of tests to validate communication.
Definition: mod_mbus.c:2274
mbus_receive::error
int16 error
error value from call, set by VPL
Definition: mod_mbus.c:155
mbus_set_filter
FUNCTION mbusSetFilter Defines the data structure of the VPL function mbusSetFilter.
Definition: mod_mbus.c:204
mbus_register_slave
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:1775
mbus_open::rssi
int8 rssi
Set to true to include the signal strength (RSSI) for each valid packet.
Definition: mod_mbus.c:69
mbus_frame_list::frames_max
uint16 frames_max
Maximum amount of elements the list will accept.
Definition: mod_mbus.c:267
mbusBufferReceive
static int mbusBufferReceive(tdef_mbus_frame *rframe, tdef_mbus_slave_address *address, int32 timeout)
Get element from buffer with timeout.
Definition: mod_mbus.c:1454
run_thread
static int run_thread
thread running state
Definition: mod_mbus.c:325
mbus_frame
STRUCT_BLOCK mbusFrame Defines the data structure of the VPL STRUCT_BLOCK mbusFrame.
Definition: mod_mbus.c:84
mbus_reg_slave::error
int16 error
error value from call, set by VPL
Definition: mod_mbus.c:181
mbus_frame_list::discarded
uint16 discarded
Counter that tells how many entries were discarded, also in the case of overwriting.
Definition: mod_mbus.c:269
mbus_frame_list_elem::next
struct mbus_frame_list_elem * next
Pointer to the later received frames.
Definition: mod_mbus.c:250
moduleInit
int moduleInit(void)
This function is called by the firmware when 'extModuleLoad' is called.
Definition: mod_mbus.c:2395
list_lock
static pthread_mutex_t list_lock
list synchronization lock
Definition: mod_mbus.c:319
mbus_slave_address::version
uint8 version
Version number. Part of the address of the slave.
Definition: mod_mbus.c:288
mbus_config_mem_reg
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:830
mbus_read_reg
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:774
mbus_frame::linsec
uint32 linsec
Timestamp. Time of receiving frame in linsec. See clockGet VPL function block.
Definition: mod_mbus.c:94
mbus_set_filter::only_installed
int8 only_installed
Set to true to only receive packets from installed slaves.
Definition: mod_mbus.c:210
mbus_frame::reserved
int8 reserved
Definition: mod_mbus.c:87
mbus_start_frame::version
uint8 version
A-Field[5]:Device version part of address field.
Definition: mod_mbus.c:234
cfg_active
static int cfg_active
Flag to monitor if we are in config mode.
Definition: mod_mbus.c:304
mbus_frame::rssi
int16 rssi
The signal strength (RSSI), if enabled in mbusOpen().
Definition: mod_mbus.c:92
mbus_frame_list::overwrite
int8 overwrite
Boolean value to decide on policy when buffer is full. On True we overwrite by removing oldest frame ...
Definition: mod_mbus.c:271
moduleNotify
void moduleNotify(int event, int parm)
This function is called by the firmware to notify the module about an event.
Definition: mod_mbus.c:2522
rssi_included
static int rssi_included
Flag to keep track of whether the RSSI is included in each packet.
Definition: mod_mbus.c:308
mbus_reg_slave::type
uint8 type
Device Type. Part of the address of the slave.
Definition: mod_mbus.c:188
mbus_reg_slave
FUNCTION mbusRegisterSlave Defines the data structure of the VPL function mbusRegisterSlave.
Definition: mod_mbus.c:178
mbus_read_regs
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:805
mbus_set_filter::error
int16 error
error value from call, set by VPL
Definition: mod_mbus.c:207
MAX_SLAVE_REGISTERS
#define MAX_SLAVE_REGISTERS
Definition: mod_mbus.c:31
mbus_receive::version
uint8 version
Version number. Part of the address of the slave.
Definition: mod_mbus.c:161
mbus_frame::type
uint8 type
Device Type. Part of the device address.
Definition: mod_mbus.c:91
mbus_config
static int mbus_config(int8 mode, int8 rssi, int8 only_installed)
Configure a number of common settings.
Definition: mod_mbus.c:864
mbus_reg_slave::manufacturer
int16 manufacturer
Manufacturer ID. Part of the address of the slave.
Definition: mod_mbus.c:185
fd
static int fd
serial port handle
Definition: mod_mbus.c:301
mbus_start_frame
The first block of data when a new MBUS message is received.
Definition: mod_mbus.c:224
mbusStopReader
static int mbusStopReader(void)
Stop the receive thread and clean up.
Definition: mod_mbus.c:2026
mbusStartReader
static int mbusStartReader(uint16 buf_size, int8 overwrite)
Start the receive thread.
Definition: mod_mbus.c:1997
mbus_filter_receive::idx
int16 idx
id of filter to receive from.
Definition: mod_mbus.c:136
mbus_slave_register
static tdef_mbus_slave_address mbus_slave_register[MAX_SLAVE_REGISTERS]
The stored addresses of registered slaves.
Definition: mod_mbus.c:314
mbus_frame_list::flist_tail
tdef_mbus_frame_list_elem * flist_tail
Pointer to the tail of the list, where the oldest frames are kept.
Definition: mod_mbus.c:275
mbus_open::retval
int16 retval
return value from call, set by VPL
Definition: mod_mbus.c:57
mbus_filter_receive
FUNCTION mbusFilterReceive Defines the data structure of the VPL function mbusFilterReceive.
Definition: mod_mbus.c:130
mbus_address_compare
static int8 mbus_address_compare(tdef_mbus_slave_address *a, tdef_mbus_frame *f)
Compare the address in a received frame to a given address.
Definition: mod_mbus.c:399
mbus_receive::type
uint8 type
Device Type. Part of the address of the slave.
Definition: mod_mbus.c:162
mbus_frame::manufacture
int16 manufacture
Manufacture ID. Part of the device address.
Definition: mod_mbus.c:88
mbus_receive::frame
tdef_mbus_frame * frame
The provided struct is filled with the values of a received M-Bus frame.
Definition: mod_mbus.c:165
mbus_flist
static tdef_mbus_frame_list mbus_flist
The frame list buffer.
Definition: mod_mbus.c:311
mbus_frame::data
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:96
mbus_filter_receive::retval
int16 retval
return value from call, set by VPL
Definition: mod_mbus.c:132
mbus_slave_address
Slave address entries.
Definition: mod_mbus.c:285
mbus_frame_list::counter
uint16 counter
Counter that tells how many elements has been inserted in the buffer list.
Definition: mod_mbus.c:265
mbusCallFilterEnable
static int32 MODDECL mbusCallFilterEnable(HANDLE *pCPU, void *pBase)
Set mode.
Definition: mod_mbus.c:2302
mbus_slave_address::type
uint8 type
Device Type. Part of the address of the slave.
Definition: mod_mbus.c:289
mbusOpen
static int mbusOpen(int8 mode, int8 rssi)
Opens the connection to the M-Bus module.
Definition: mod_mbus.c:1558
mbus_receive::manufacturer
int16 manufacturer
Manufacturer ID. Part of the address of the slave.
Definition: mod_mbus.c:159
mbusCallFilterReceive
static int32 MODDECL mbusCallFilterReceive(HANDLE *pCPU, void *pBase)
Check if any MBUS packets has been received for a given filter.
Definition: mod_mbus.c:2123
mbus_send
FUNCTION mbusSend Defines the data structure of the VPL function mbusSend.
Definition: mod_mbus.c:107
mbus_receive::retval
int16 retval
return value from call, set by VPL
Definition: mod_mbus.c:154
mbusCallSend
static int32 MODDECL mbusCallSend(HANDLE *pCPU, void *pBase)
Send a MBUS message.
Definition: mod_mbus.c:2190
mbus_open
FUNCTION mbusOpen Defines the data structure of the VPL function mbusOpen.
Definition: mod_mbus.c:55
mbusConfigCmd
static int mbusConfigCmd(uint8 cmd, uint8 *reply, int size)
Send a single command/argument.
Definition: mod_mbus.c:723
mbus_start_frame::control
uint8 control
C-field : Control byte used to identify packet type.
Definition: mod_mbus.c:228
mbus_frame_list_elem::prev
struct mbus_frame_list_elem * prev
Pointer to the previous received frames.
Definition: mod_mbus.c:248
mbusDebug
static void mbusDebug(const char *prefix, const char *format,...)
Send mbus debug message to the device output in the format "<prefix>:<formated string>" This function...
Definition: mod_mbus.c:364
mbus_send::error
int16 error
error value from call, set by VPL
Definition: mod_mbus.c:110
mbus_set_filter::retval
int16 retval
return value from call, set by VPL
Definition: mod_mbus.c:206
mbus_send::control
int16 control
Value of the control field to use when sending.
Definition: mod_mbus.c:113
mbus_reg_slave::version
uint8 version
Version number. Part of the address of the slave.
Definition: mod_mbus.c:187
mbus_slave_address::id
uint32 id
Identification number/serial number. Part of the address of the slave.
Definition: mod_mbus.c:287
mbusConfigExit
static int mbusConfigExit(void)
Exit configuration mode.
Definition: mod_mbus.c:558
mbusCallReceive
static int32 MODDECL mbusCallReceive(HANDLE *pCPU, void *pBase)
Check if any MBUS packets has been received.
Definition: mod_mbus.c:2160
mbus_th_reader
static void mbus_th_reader(void *arg)
Thread function to recieve data and add to frame buffer list.
Definition: mod_mbus.c:1065
mbus_send::data
int8 * data
Data to send.
Definition: mod_mbus.c:115
mbus_reg_slave::id
uint32 id
Identification number/serial number. Part of the address of the slave.
Definition: mod_mbus.c:186
mbusConfigFactoryReset
static int mbusConfigFactoryReset(void)
This function performs a factory reset of the RF module.
Definition: mod_mbus.c:1110
mbus_reg_slave::retval
int16 retval
return value from call, set by VPL
Definition: mod_mbus.c:180
mbus_open::error
int16 error
error value from call, set by VPL
Definition: mod_mbus.c:58
mbus_start_frame::length
uint8 length
L-field : Length of full frame not including length or any start/stop bytes.
Definition: mod_mbus.c:226
mbus_frame_list_elem
The doubly-connected frame buffer list keeping received frames.
Definition: mod_mbus.c:246
mbus_send::length
int16 length
Length of the data to send.
Definition: mod_mbus.c:114
reader
static pthread_t reader
thread configuration
Definition: mod_mbus.c:323
mbusCallClose
static int32 MODDECL mbusCallClose(HANDLE *pCPU, void *pBase)
Close communication interface to the module.
Definition: mod_mbus.c:2095
mbusPower
static int mbusPower(uint8 power)
Control power to module.
Definition: mod_mbus.c:424
rw_lock
static pthread_mutex_t rw_lock
device read/write lock
Definition: mod_mbus.c:321
mbus_reg_slave::idx
int16 idx
The index of the slave to register. 1-64.
Definition: mod_mbus.c:184
mbus_send::retval
int16 retval
return value from call, set by VPL
Definition: mod_mbus.c:109
mbus_open::mode
int8 mode
The M-Bus mode to use.
Definition: mod_mbus.c:61
mbus_frame::control
int8 control
Control field.
Definition: mod_mbus.c:86
read_sem
static sem_t read_sem
semaphore to await data with timeout
Definition: mod_mbus.c:327
mbusCallOpen
static int32 MODDECL mbusCallOpen(HANDLE *pCPU, void *pBase)
Open communication interface to the module.
Definition: mod_mbus.c:2068
mbus_receive
static int mbus_receive(tdef_mbus_start_frame *start, int8 *data, int16 *rssi)
Receive a new frame from the M-Bus module.
Definition: mod_mbus.c:944
mbusConfigEnter
static int mbusConfigEnter(void)
Entering configuration mode.
Definition: mod_mbus.c:459
mbusConfigData
static int mbusConfigData(uint8 cmd)
Send configuration data.
Definition: mod_mbus.c:741
mbusConfigTransact
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:617
mbus_frame_list
The buffer list structure, specifying overwrite policy, buffer size and counters.
Definition: mod_mbus.c:263
MUTEX_UNLOCK
#define MUTEX_UNLOCK(m)
Definition: mod_mbus.c:34
mbus_start_frame::type
uint8 type
A-Field[6]:Device type part of address field.
Definition: mod_mbus.c:236
mbus_receive::timeout
int32 timeout
Time to wait for data if buffer is empty in milliseconds. If timeout is -1, wait until data is receiv...
Definition: mod_mbus.c:158
mbus_reg_slave::key
uint8 * key
Encryption key, 16 bytes. Can be set to NULL when encryption is not used.
Definition: mod_mbus.c:190
TH_SEM_RESET
#define TH_SEM_RESET(s)
Definition: mod_mbus.c:35
mbus_start_frame::id
uint32 id
A-Field[4]:ID/Serial number part of address field.
Definition: mod_mbus.c:232
MBUS_DATA_LENGTH
#define MBUS_DATA_LENGTH
Maximum size of a MBUS message not including header information.
Definition: mod_mbus.c:30
mbus_frame::id
uint32 id
Identification number/serial number. Part of the device address.
Definition: mod_mbus.c:89
mbus_open::overwrite
int8 overwrite
If 1 (true), use overwrite policy, if 0 (false), discard newly received frame.
Definition: mod_mbus.c:72
mbus_filter_receive::error
int16 error
error value from call, set by VPL
Definition: mod_mbus.c:133
mbus_filter_receive::frame
tdef_mbus_frame * frame
The provided struct is filled with the values of a received M-Bus frame.
Definition: mod_mbus.c:139
mbusPrintInfo
static void mbusPrintInfo(const char *prefix, const char *format,...)
Send mbus info message to the device output in the format "<prefix>:<formated string>".
Definition: mod_mbus.c:376
mbus_open::max_frames
int16 max_frames
Amount of elements the buffer will accept. Maximum value 1000.
Definition: mod_mbus.c:71
MUTEX_LOCK
#define MUTEX_LOCK(m)
Definition: mod_mbus.c:33
mbus_frame_list::flist_head
tdef_mbus_frame_list_elem * flist_head
Pointer to the head of the list, where the latest frames received are kept.
Definition: mod_mbus.c:273
flist_append
static void flist_append(tdef_mbus_frame_list_elem *e)
Add element containing received frame data to list.
Definition: mod_mbus.c:1346
mbus_receive::id
uint32 id
Identification number/serial number. Part of the address of the slave.
Definition: mod_mbus.c:160
mbus_info
static int mbus_info(void)
Print some information about the RF module to the device output.
Definition: mod_mbus.c:1850
mbus_frame::version
uint8 version
Version number. Part of the device address.
Definition: mod_mbus.c:90