SELKIELogger  1.0.0
LoggerI2C.c
1 /*
2  * Copyright (C) 2023 Swansea University
3  *
4  * This file is part of the SELKIELogger suite of tools.
5  *
6  * SELKIELogger is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation, either version 3 of the License, or (at your option)
9  * any later version.
10  *
11  * SELKIELogger is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this SELKIELogger product.
18  * If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include "Logger.h"
22 
23 #include "LoggerI2C.h"
24 #include "LoggerSignals.h"
25 
34 void *i2c_setup(void *ptargs) {
35  log_thread_args_t *args = (log_thread_args_t *)ptargs;
36  i2c_params *i2cInfo = (i2c_params *)args->dParams;
37 
38  if (!i2c_validate_chanmap(i2cInfo)) {
39  log_error(args->pstate, "[I2C:%s] Invalid channel map", args->tag);
40  args->returnCode = -2;
41  return NULL;
42  }
43 
44  i2cInfo->handle = i2c_openConnection(i2cInfo->busName);
45  if (i2cInfo->handle < 0) {
46  log_error(args->pstate, "[I2C:%s] Unable to open a connection", args->tag);
47  args->returnCode = -1;
48  return NULL;
49  }
50  log_info(args->pstate, 2, "[I2C:%s] Connected", args->tag);
51  args->returnCode = 0;
52  return NULL;
53 }
54 
68 void *i2c_logging(void *ptargs) {
70  log_thread_args_t *args = (log_thread_args_t *)ptargs;
71  i2c_params *i2cInfo = (i2c_params *)args->dParams;
72 
73  log_info(args->pstate, 1, "[I2C:%s] Logging thread started", args->tag);
74 
75  struct timespec lastIter = {0};
76  clock_gettime(CLOCK_MONOTONIC, &lastIter);
77  while (!shutdownFlag) {
78  for (int mm = 0; mm < i2cInfo->en_count; mm++) {
79  i2c_msg_map *map = &(i2cInfo->chanmap[mm]);
80  float value = map->func(i2cInfo->handle, map->deviceAddr, map->ext);
81 
82  msg_t *msg = msg_new_float(i2cInfo->sourceNum, map->messageID, value);
83  if (!queue_push(args->logQ, msg)) {
84  log_error(args->pstate, "[I2C:%s] Error pushing message to queue",
85  args->tag);
86  msg_destroy(msg);
87  args->returnCode = -1;
88  pthread_exit(&(args->returnCode));
89  }
90  }
91 
92  lastIter.tv_nsec += 1E9 / i2cInfo->frequency;
93  if (lastIter.tv_nsec > 1E9) {
94  int nsec = lastIter.tv_nsec / 1000000000;
95  lastIter.tv_nsec = lastIter.tv_nsec % 1000000000;
96  lastIter.tv_sec += nsec;
97  }
98  struct timespec now = {0};
99  clock_gettime(CLOCK_MONOTONIC, &now);
101  (1000 * now.tv_sec + now.tv_nsec / 1000000));
102  if (!queue_push(args->logQ, msg)) {
103  log_error(args->pstate, "[I2C:%s] Error pushing message to queue",
104  args->tag);
105  msg_destroy(msg);
106  args->returnCode = -1;
107  pthread_exit(&(args->returnCode));
108  }
109  struct timespec target = {0};
110  if (timespec_subtract(&target, &lastIter, &now)) {
111  // Target has passed!
112  log_warning(args->pstate, "[I2C:%s] Deadline missed", args->tag);
113  clock_gettime(CLOCK_MONOTONIC, &lastIter);
114  } else {
115  clock_gettime(CLOCK_MONOTONIC, &lastIter);
116  // If we're interrupted, just carry on. We might need to handle
117  // the shutdown flag, and worst case is we log a bit of extra data
118  nanosleep(&target, NULL);
119  }
120  }
121  pthread_exit(NULL);
122  return NULL; // Superfluous, as returning zero via pthread_exit above
123 }
124 
131 void *i2c_shutdown(void *ptargs) {
132  log_thread_args_t *args = (log_thread_args_t *)ptargs;
133  i2c_params *i2cInfo = (i2c_params *)args->dParams;
134 
135  if (i2cInfo->handle >= 0) { // Admittedly 0 is unlikely
136  i2c_closeConnection(i2cInfo->handle);
137  }
138  i2cInfo->handle = -1;
139 
140  if (i2cInfo->sourceName) {
141  free(i2cInfo->sourceName);
142  i2cInfo->sourceName = NULL;
143  }
144  if (i2cInfo->busName) {
145  free(i2cInfo->busName);
146  i2cInfo->busName = NULL;
147  }
148  if (i2cInfo->chanmap) {
149  free(i2cInfo->chanmap);
150  i2cInfo->chanmap = NULL;
151  }
152  return NULL;
153 }
154 
163 void *i2c_channels(void *ptargs) {
164  log_thread_args_t *args = (log_thread_args_t *)ptargs;
165  i2c_params *i2cInfo = (i2c_params *)args->dParams;
166 
167  msg_t *m_sn = msg_new_string(i2cInfo->sourceNum, SLCHAN_NAME, strlen(i2cInfo->sourceName),
168  i2cInfo->sourceName);
169 
170  if (!queue_push(args->logQ, m_sn)) {
171  log_error(args->pstate, "[I2C:%s] Error pushing channel name to queue", args->tag);
172  msg_destroy(m_sn);
173  args->returnCode = -1;
174  pthread_exit(&(args->returnCode));
175  }
176 
177  uint8_t maxID = 3;
178  for (int i = 0; i < i2cInfo->en_count; i++) {
179  if (i2cInfo->chanmap[i].messageID > maxID) {
180  maxID = i2cInfo->chanmap[i].messageID;
181  }
182  }
183  strarray *channels = sa_new(maxID + 1);
184  sa_create_entry(channels, SLCHAN_NAME, 4, "Name");
185  sa_create_entry(channels, SLCHAN_MAP, 8, "Channels");
186  sa_create_entry(channels, SLCHAN_TSTAMP, 9, "Timestamp");
187 
188  for (int i = 0; i < i2cInfo->en_count; i++) {
189  sa_set_entry(channels, i2cInfo->chanmap[i].messageID,
190  &(i2cInfo->chanmap[i].message_name));
191  }
192 
193  msg_t *m_cmap = msg_new_string_array(i2cInfo->sourceNum, SLCHAN_MAP, channels);
194 
195  if (!queue_push(args->logQ, m_cmap)) {
196  log_error(args->pstate, "[I2C:%s] Error pushing channel map to queue", args->tag);
197  msg_destroy(m_cmap);
198  sa_destroy(channels);
199  free(channels);
200  args->returnCode = -1;
201  pthread_exit(&(args->returnCode));
202  }
203 
204  sa_destroy(channels);
205  free(channels);
206  return NULL;
207 }
208 
214  .logging = &i2c_logging,
215  .shutdown = &i2c_shutdown,
216  .channels = &i2c_channels};
217  return cb;
218 }
219 
224  i2c_params i2c = {.busName = NULL,
225  .sourceName = NULL,
226  .sourceNum = SLSOURCE_I2C,
227  .handle = -1,
228  .frequency = 10,
229  .en_count = 0,
230  .chanmap = NULL};
231  return i2c;
232 }
233 
242  i2c_msg_map *cmap = ip->chanmap;
243  bool seen[128] = {0};
244  if (!cmap) { return false; }
245  // Reserved channels
246  seen[SLCHAN_NAME] = true;
247  seen[SLCHAN_MAP] = true;
248  seen[SLCHAN_TSTAMP] = true;
249  seen[SLCHAN_RAW] = true;
250  seen[SLCHAN_LOG_INFO] = true;
251  seen[SLCHAN_LOG_WARN] = true;
252  seen[SLCHAN_LOG_ERR] = true;
253 
254  for (int i = 0; i < ip->en_count; i++) {
255  if (seen[ip->chanmap[i].messageID]) { return false; }
256  seen[ip->chanmap[i].messageID] = true;
257  if (!ip->chanmap[i].func) { return false; }
258  if (!ip->chanmap[i].deviceAddr) { return false; }
259  }
260  return true;
261 }
262 
275 bool i2c_chanmap_add_ina219(i2c_params *ip, const uint8_t devAddr, const uint8_t baseID) {
276  if (!ip) { return false; }
277  if (baseID < 4 || baseID > 121) { return false; }
278  i2c_msg_map *tmp = realloc(ip->chanmap, sizeof(i2c_msg_map) * (ip->en_count + 3));
279  if (!tmp) { return false; }
280  ip->chanmap = tmp;
281 
282  char tmpS[50] = {0};
283 
284  snprintf(tmpS, 18, "0x%02x:ShuntVoltage", devAddr);
285  ip->chanmap[ip->en_count].messageID = baseID;
286  // Memory was allocated with malloc, so make sure we initialise these values
287  ip->chanmap[ip->en_count].message_name.length = 0;
288  ip->chanmap[ip->en_count].message_name.data = NULL;
289  str_update(&(ip->chanmap[ip->en_count].message_name), 18, tmpS);
290  ip->chanmap[ip->en_count].deviceAddr = devAddr;
292  ip->en_count++;
293 
294  snprintf(tmpS, 16, "0x%02x:BusVoltage", devAddr);
295  ip->chanmap[ip->en_count].messageID = baseID + 1;
296  ip->chanmap[ip->en_count].message_name.length = 0;
297  ip->chanmap[ip->en_count].message_name.data = NULL;
298  str_update(&(ip->chanmap[ip->en_count].message_name), 16, tmpS);
299  ip->chanmap[ip->en_count].deviceAddr = devAddr;
301  ip->en_count++;
302 
303  snprintf(tmpS, 16, "0x%02x:BusCurrent", devAddr);
304  ip->chanmap[ip->en_count].messageID = baseID + 2;
305  ip->chanmap[ip->en_count].message_name.length = 0;
306  ip->chanmap[ip->en_count].message_name.data = NULL;
307  str_update(&(ip->chanmap[ip->en_count].message_name), 16, tmpS);
308  ip->chanmap[ip->en_count].deviceAddr = devAddr;
310  ip->en_count++;
311 
312  return true;
313 }
314 
333 bool i2c_chanmap_add_ads1015(i2c_params *ip, const uint8_t devAddr, const uint8_t baseID,
334  const float scale, const float offset, const float minV,
335  const float maxV) {
336  if (!ip) { return false; }
337  if (baseID < 4 || baseID > 121) { return false; }
338  i2c_msg_map *tmp = realloc(ip->chanmap, sizeof(i2c_msg_map) * (ip->en_count + 4));
339  if (!tmp) { return false; }
340  if ((minV == maxV) || (maxV < minV)) { return false; }
341 
342  ip->chanmap = tmp;
343 
344  char tmpS[50] = {0};
345  i2c_ads1015_options *adsopts = calloc(1, sizeof(i2c_ads1015_options));
346  if (adsopts == NULL) {
347  perror("_add_ads1015");
348  return false;
349  }
350 
351  adsopts->min = minV;
352  adsopts->max = maxV;
353  adsopts->scale = scale;
354  adsopts->offset = offset;
355 
356  snprintf(tmpS, 8, "0x%02x:A0", devAddr);
357  ip->chanmap[ip->en_count].messageID = baseID;
358  // Memory was allocated with malloc, so make sure we initialise these values
359  ip->chanmap[ip->en_count].message_name.length = 0;
360  ip->chanmap[ip->en_count].message_name.data = NULL;
361  str_update(&(ip->chanmap[ip->en_count].message_name), 8, tmpS);
362  ip->chanmap[ip->en_count].deviceAddr = devAddr;
364  ip->chanmap[ip->en_count].ext = adsopts;
365  ip->en_count++;
366 
367  snprintf(tmpS, 8, "0x%02x:A1", devAddr);
368  ip->chanmap[ip->en_count].messageID = baseID + 1;
369  ip->chanmap[ip->en_count].message_name.length = 0;
370  ip->chanmap[ip->en_count].message_name.data = NULL;
371  str_update(&(ip->chanmap[ip->en_count].message_name), 8, tmpS);
372  ip->chanmap[ip->en_count].deviceAddr = devAddr;
374  ip->chanmap[ip->en_count].ext = adsopts;
375  ip->en_count++;
376 
377  snprintf(tmpS, 8, "0x%02x:A2", devAddr);
378  ip->chanmap[ip->en_count].messageID = baseID + 2;
379  ip->chanmap[ip->en_count].message_name.length = 0;
380  ip->chanmap[ip->en_count].message_name.data = NULL;
381  str_update(&(ip->chanmap[ip->en_count].message_name), 8, tmpS);
382  ip->chanmap[ip->en_count].deviceAddr = devAddr;
384  ip->chanmap[ip->en_count].ext = adsopts;
385  ip->en_count++;
386 
387  snprintf(tmpS, 8, "0x%02x:A3", devAddr);
388  ip->chanmap[ip->en_count].messageID = baseID + 3;
389  ip->chanmap[ip->en_count].message_name.length = 0;
390  ip->chanmap[ip->en_count].message_name.data = NULL;
391  str_update(&(ip->chanmap[ip->en_count].message_name), 8, tmpS);
392  ip->chanmap[ip->en_count].deviceAddr = devAddr;
394  ip->chanmap[ip->en_count].ext = adsopts;
395  ip->en_count++;
396 
397  return true;
398 }
399 
406  if (lta->dParams) {
407  log_error(lta->pstate, "[I2C:%s] Refusing to reconfigure", lta->tag);
408  return false;
409  }
410 
411  i2c_params *ip = calloc(1, sizeof(i2c_params));
412  if (!ip) {
413  log_error(lta->pstate, "[I2C:%s] Unable to allocate memory for device parameters",
414  lta->tag);
415  return false;
416  }
417  (*ip) = i2c_getParams();
418 
419  config_kv *t = NULL;
420  if ((t = config_get_key(s, "name"))) {
421  ip->sourceName = config_qstrdup(t->value);
422  } else {
423  // Must set a name, so nick the tag value
424  ip->sourceName = strdup(lta->tag);
425  }
426  t = NULL;
427 
428  if ((t = config_get_key(s, "bus"))) { ip->busName = config_qstrdup(t->value); }
429  t = NULL;
430 
431  if ((t = config_get_key(s, "frequency"))) {
432  errno = 0;
433  ip->frequency = strtol(t->value, NULL, 0);
434  if (errno) {
435  log_error(lta->pstate, "[I2C:%s] Error parsing sample frequency: %s",
436  lta->tag, strerror(errno));
437  free(ip);
438  return false;
439  }
440  if (ip->frequency <= 0) {
441  log_error(
442  lta->pstate,
443  "[I2C:%s] Invalid frequency requested (%d) - must be positive and non-zero",
444  lta->tag, ip->frequency);
445  free(ip);
446  return false;
447  }
448  }
449  t = NULL;
450 
451  if ((t = config_get_key(s, "sourcenum"))) {
452  errno = 0;
453  int sn = strtol(t->value, NULL, 0);
454  if (errno) {
455  log_error(lta->pstate, "[I2C:%s] Error parsing source number: %s",
456  lta->tag, strerror(errno));
457  free(ip);
458  return false;
459  }
460  if (sn < 0) {
461  log_error(lta->pstate, "[I2C:%s] Invalid source number (%s)", lta->tag,
462  t->value);
463  free(ip);
464  return false;
465  }
466  if (sn < 10) {
467  ip->sourceNum += sn;
468  } else {
469  ip->sourceNum = sn;
470  if (sn < SLSOURCE_I2C || sn > (SLSOURCE_I2C + 0x0F)) {
471  log_warning(
472  lta->pstate,
473  "[I2C:%s] Unexpected Source ID number (0x%02x)- this may cause analysis problems",
474  lta->tag, sn);
475  }
476  }
477  }
478  t = NULL;
479 
480  // Initial message ID, in case not specified in configuration.
481  // There is scope for conflict in case of a mix of automatic and
482  // manually specified IDs, which should be caught by i2c_validate_chanmap
483  uint8_t baseMsgID = 4;
484 
485  // Loop over all keys present, as the options parsed below this line may be
486  // present multiple times
487  for (int i = 0; i < s->numopts; i++) {
488  t = &(s->opts[i]);
489  if (strncasecmp(t->key, "ina219", 7) == 0) {
490  char *strtsp = NULL;
491  if (strtok_r(t->value, ":", &strtsp)) {
492  // First part is base address, second is base message ID
493  errno = 0;
494  int baddr = strtol(t->value, NULL, 16);
495  int msgid = strtol(strtok_r(NULL, ":", &strtsp), NULL, 16);
496  if (!i2c_chanmap_add_ina219(ip, baddr, msgid)) {
497  log_error(
498  lta->pstate,
499  "[I2C:%s] Failed to register INA219 device at address 0x%02x and base message ID 0x%02x",
500  lta->tag, baddr, msgid);
501  free(ip);
502  return false;
503  }
504 
505  } else {
506  // No base message ID, so start from next available
507  errno = 0;
508  int baddr = strtol(t->value, NULL, 16);
509  if (!i2c_chanmap_add_ina219(ip, baddr, baseMsgID)) {
510  log_error(
511  lta->pstate,
512  "[I2C:%s] Failed to register INA219 device at address 0x%02x and base message ID 0x%02x",
513  lta->tag, baddr, baseMsgID);
514  free(ip);
515  return false;
516  }
517  baseMsgID += 3;
518  }
519  } else if (strncasecmp(t->key, "ads1015", 8) == 0) {
520  char *strtsp = NULL;
521  if (strtok_r(t->value, ":", &strtsp)) {
522  // First part is base address, second is base message ID
523  // Optional third and fourth parts are scale and offset
524  // respectively
525  errno = 0;
526  int baddr = strtol(t->value, NULL, 16);
527  int msgid = strtol(strtok_r(NULL, ":", &strtsp), NULL, 16);
528  if (errno) {
529  log_error(lta->pstate,
530  "[I2C:%s] Error parsing values in configuration",
531  lta->tag);
532  free(ip);
533  return false;
534  }
535 
536  float scale = 1;
537  float offset = 0;
538  float min = -INFINITY;
539  float max = INFINITY;
540  char *tt = strtok_r(NULL, ":", &strtsp);
541  if (tt) {
542  scale = strtof(tt, NULL);
543  if (errno) {
544  log_error(
545  lta->pstate,
546  "[I2C:%s] Error parsing scale value in configuration",
547  lta->tag);
548  free(ip);
549  return false;
550  }
551 
552  tt = strtok_r(NULL, ":", &strtsp);
553  if (tt) {
554  errno = 0;
555  offset = strtof(tt, NULL);
556  if (errno) {
557  log_error(
558  lta->pstate,
559  "[I2C:%s] Error parsing offset value in configuration",
560  lta->tag);
561  free(ip);
562  return false;
563  }
564  tt = strtok_r(NULL, ":", &strtsp);
565  if (tt) {
566  errno = 0;
567  min = strtof(tt, NULL);
568  if (errno) {
569  log_error(
570  lta->pstate,
571  "[I2C:%s] Error parsing minimum value in configuration",
572  lta->tag);
573  free(ip);
574  return false;
575  }
576  tt = strtok_r(NULL, ":", &strtsp);
577  if (tt) {
578  errno = 0;
579  max = strtof(tt, NULL);
580  if (errno) {
581  log_error(
582  lta->pstate,
583  "[I2C:%s] Error parsing maximum value in configuration",
584  lta->tag);
585  free(ip);
586  return false;
587  }
588  }
589  }
590  }
591  }
592 
593  if (!i2c_chanmap_add_ads1015(ip, baddr, msgid, scale, offset, min,
594  max)) {
595  log_error(
596  lta->pstate,
597  "[I2C:%s] Failed to register ADS1015 device at address 0x%02x and base message ID 0x%02x",
598  lta->tag, baddr, msgid);
599  free(ip);
600  return false;
601  }
602 
603  } else {
604  // No base message ID, so start from next available
605  errno = 0;
606  int baddr = strtol(t->value, NULL, 16);
607  if (!i2c_chanmap_add_ads1015(ip, baddr, baseMsgID, 1, 0, -INFINITY,
608  INFINITY)) {
609  log_error(
610  lta->pstate,
611  "[I2C:%s] Failed to register ADS1015 device at address 0x%02x and base message ID 0x%02x",
612  lta->tag, baddr, baseMsgID);
613  free(ip);
614  return false;
615  }
616  baseMsgID += 4;
617  }
618  }
619  }
620  lta->dParams = ip;
621  return i2c_validate_chanmap(ip);
622 }
char * config_qstrdup(const char *c)
Duplicate string, stripping optional leading/trailing quote marks.
Definition: LoggerConfig.c:271
config_kv * config_get_key(const config_section *cs, const char *kn)
Find configugration key within specific section, by name.
Definition: LoggerConfig.c:204
void signalHandlersBlock(void)
Block signals that we have handlers for.
msg_t * msg_new_string(const uint8_t source, const uint8_t type, const size_t len, const char *str)
Create a new message with a single string embedded.
Definition: messages.c:84
void msg_destroy(msg_t *msg)
Destroy a message.
Definition: messages.c:349
msg_t * msg_new_string_array(const uint8_t source, const uint8_t type, const strarray *array)
Create a new message containing an array of strings.
Definition: messages.c:116
msg_t * msg_new_timestamp(const uint8_t source, const uint8_t type, const uint32_t ts)
Create a timestamp message.
Definition: messages.c:57
msg_t * msg_new_float(const uint8_t source, const uint8_t type, const float val)
Create new message with a single numeric value.
Definition: messages.c:38
int i2c_openConnection(const char *bus)
Set up a connection to the specified bus.
Definition: I2CConnection.c:34
void i2c_closeConnection(int handle)
Close existing connection.
Definition: I2CConnection.c:46
float i2c_ads1015_read_ch1(const int busHandle, const int devAddr, const void *opts)
Get single-ended voltage measurement from channel 1.
Definition: I2C-ADS1015.c:177
float i2c_ads1015_read_ch2(const int busHandle, const int devAddr, const void *opts)
Get single-ended voltage measurement from channel 2.
Definition: I2C-ADS1015.c:191
float i2c_ads1015_read_ch0(const int busHandle, const int devAddr, const void *opts)
Get single-ended voltage measurement from channel 0.
Definition: I2C-ADS1015.c:163
float i2c_ads1015_read_ch3(const int busHandle, const int devAddr, const void *opts)
Get single-ended voltage measurement from channel 3.
Definition: I2C-ADS1015.c:206
float i2c_ina219_read_shuntVoltage(const int busHandle, const int devAddr, const void *opts)
Get voltage across the shunt resistor in millivolts.
Definition: I2C-INA219.c:77
float i2c_ina219_read_current(const int busHandle, const int devAddr, const void *opts)
Get current flow through shunt resistor in amps.
Definition: I2C-INA219.c:173
float i2c_ina219_read_busVoltage(const int busHandle, const int devAddr, const void *opts)
Get bus voltage (at V- terminal) in volts.
Definition: I2C-INA219.c:115
#define SLCHAN_TSTAMP
Source timestamp (milliseconds, arbitrary epoch)
Definition: sources.h:99
#define SLCHAN_RAW
Raw device data (Not mandatory)
Definition: sources.h:100
#define SLCHAN_LOG_ERR
Error messages.
Definition: sources.h:103
#define SLCHAN_LOG_INFO
Information messages.
Definition: sources.h:101
#define SLCHAN_MAP
Channel name map (excludes log channels)
Definition: sources.h:98
#define SLCHAN_NAME
Name of source device.
Definition: sources.h:97
#define SLCHAN_LOG_WARN
Warning messages.
Definition: sources.h:102
void * i2c_shutdown(void *ptargs)
I2C shutdown.
Definition: LoggerI2C.c:131
void * i2c_channels(void *ptargs)
Generate I2C channel map.
Definition: LoggerI2C.c:163
void * i2c_logging(void *ptargs)
I2C main logging loop.
Definition: LoggerI2C.c:68
bool i2c_chanmap_add_ina219(i2c_params *ip, const uint8_t devAddr, const uint8_t baseID)
Add INA219 voltage and current readings to channel map.
Definition: LoggerI2C.c:275
bool i2c_validate_chanmap(i2c_params *ip)
Check channel mapping is valid.
Definition: LoggerI2C.c:241
bool i2c_parseConfig(log_thread_args_t *lta, config_section *s)
Take a configuration section, parse parameters and register devices.
Definition: LoggerI2C.c:405
device_callbacks i2c_getCallbacks()
Fill out device callback functions for logging.
Definition: LoggerI2C.c:212
void * i2c_setup(void *ptargs)
I2C Connection setup.
Definition: LoggerI2C.c:34
i2c_params i2c_getParams()
Fill out default I2C parameters.
Definition: LoggerI2C.c:223
bool i2c_chanmap_add_ads1015(i2c_params *ip, const uint8_t devAddr, const uint8_t baseID, const float scale, const float offset, const float minV, const float maxV)
Add ADS1015 single ended voltage measurements to channel map.
Definition: LoggerI2C.c:333
#define SLSOURCE_I2C
I2C Bus.
Definition: sources.h:68
atomic_bool shutdownFlag
Trigger clean software shutdown.
Definition: LoggerSignals.c:34
bool timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y)
Difference between timespecs (used for rate keeping)
Definition: Logger.c:900
void log_info(const program_state *s, const int level, const char *format,...)
Output formatted information message at a given level.
Definition: logging.c:125
void log_warning(const program_state *s, const char *format,...)
Output formatted warning message.
Definition: logging.c:86
void log_error(const program_state *s, const char *format,...)
Output formatted error message.
Definition: logging.c:47
bool queue_push(msgqueue *queue, msg_t *msg)
Add a message to the tail of the queue.
Definition: queue.c:103
void sa_destroy(strarray *sa)
Destroy array and contents.
Definition: strarray.c:182
bool str_update(string *str, const size_t len, const char *src)
Update an existing string from a character array of given length.
Definition: strarray.c:294
bool sa_set_entry(strarray *array, const int index, string *str)
Copy a string to a given position in the array.
Definition: strarray.c:131
strarray * sa_new(int entries)
Allocate storage for a new array.
Definition: strarray.c:37
bool sa_create_entry(strarray *array, const int index, const size_t len, const char *src)
Create an string in a given position from a character array and length.
Definition: strarray.c:149
Represent a key=value pair.
Definition: LoggerConfig.h:42
char * value
Configuration item value.
Definition: LoggerConfig.h:44
char * key
Configuration item key.
Definition: LoggerConfig.h:43
Configuration file section.
Definition: LoggerConfig.h:54
int numopts
Number of *opts in use.
Definition: LoggerConfig.h:57
config_kv * opts
Key=value pairs belonging to this section.
Definition: LoggerConfig.h:58
Device specific function information.
Definition: Logger.h.in:72
device_fn startup
Called serially at startup, opens devices etc.
Definition: Logger.h.in:73
float offset
Add this amount to received value.
float scale
Scale received value by this quantity.
float max
If not NaN, largest value considered valid.
float min
If not NaN, smallest value considered valid.
Map device functions to message IDs.
Definition: LoggerI2C.h:52
uint8_t messageID
Message ID to report.
Definition: LoggerI2C.h:53
void * ext
If not NULL, pointer to additional device data.
Definition: LoggerI2C.h:57
uint8_t deviceAddr
I2C Device address.
Definition: LoggerI2C.h:55
i2c_dev_read_fn func
Pointer to device read function.
Definition: LoggerI2C.h:56
string message_name
Message name to report.
Definition: LoggerI2C.h:54
I2C Source device specific parameters.
Definition: LoggerI2C.h:61
int en_count
Number of messages in chanmap.
Definition: LoggerI2C.h:67
char * busName
Target port name.
Definition: LoggerI2C.h:62
int frequency
Aim to sample this many times per second.
Definition: LoggerI2C.h:66
char * sourceName
Reported source name.
Definition: LoggerI2C.h:64
uint8_t sourceNum
Source ID for messages.
Definition: LoggerI2C.h:63
i2c_msg_map * chanmap
Map of device functions to poll.
Definition: LoggerI2C.h:68
int handle
Handle for currently opened device.
Definition: LoggerI2C.h:65
Logging thread information.
Definition: Logger.h.in:86
msgqueue * logQ
Main message queue. Pushed to by threads, consumed by main()
Definition: Logger.h.in:89
char * tag
Tag/source name for messages etc.
Definition: Logger.h.in:87
void * dParams
Device/Thread specific data.
Definition: Logger.h.in:92
program_state * pstate
Current program state, used for logging.
Definition: Logger.h.in:90
int returnCode
Thread return code (output)
Definition: Logger.h.in:93
Queuable message.
Definition: messages.h:71
Array of strings.
Definition: strarray.h:43
char * data
Character array, should be null terminated.
Definition: strarray.h:39
size_t length
This should include a terminating null byte where possible.
Definition: strarray.h:38