75 struct timespec lastIter = {0};
76 clock_gettime(CLOCK_MONOTONIC, &lastIter);
78 for (
int mm = 0; mm < i2cInfo->
en_count; mm++) {
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;
98 struct timespec now = {0};
99 clock_gettime(CLOCK_MONOTONIC, &now);
101 (1000 * now.tv_sec + now.tv_nsec / 1000000));
109 struct timespec target = {0};
113 clock_gettime(CLOCK_MONOTONIC, &lastIter);
115 clock_gettime(CLOCK_MONOTONIC, &lastIter);
118 nanosleep(&target, NULL);
135 if (i2cInfo->
handle >= 0) {
178 for (
int i = 0; i < i2cInfo->
en_count; i++) {
188 for (
int i = 0; i < i2cInfo->
en_count; i++) {
243 bool seen[128] = {0};
244 if (!cmap) {
return false; }
254 for (
int i = 0; i < ip->
en_count; i++) {
276 if (!ip) {
return false; }
277 if (baseID < 4 || baseID > 121) {
return false; }
279 if (!tmp) {
return false; }
284 snprintf(tmpS, 18,
"0x%02x:ShuntVoltage", devAddr);
294 snprintf(tmpS, 16,
"0x%02x:BusVoltage", devAddr);
303 snprintf(tmpS, 16,
"0x%02x:BusCurrent", devAddr);
334 const float scale,
const float offset,
const float minV,
336 if (!ip) {
return false; }
337 if (baseID < 4 || baseID > 121) {
return false; }
339 if (!tmp) {
return false; }
340 if ((minV == maxV) || (maxV < minV)) {
return false; }
346 if (adsopts == NULL) {
347 perror(
"_add_ads1015");
353 adsopts->
scale = scale;
356 snprintf(tmpS, 8,
"0x%02x:A0", devAddr);
367 snprintf(tmpS, 8,
"0x%02x:A1", devAddr);
377 snprintf(tmpS, 8,
"0x%02x:A2", devAddr);
387 snprintf(tmpS, 8,
"0x%02x:A3", devAddr);
413 log_error(lta->
pstate,
"[I2C:%s] Unable to allocate memory for device parameters",
436 lta->
tag, strerror(errno));
443 "[I2C:%s] Invalid frequency requested (%d) - must be positive and non-zero",
453 int sn = strtol(t->
value, NULL, 0);
456 lta->
tag, strerror(errno));
473 "[I2C:%s] Unexpected Source ID number (0x%02x)- this may cause analysis problems",
483 uint8_t baseMsgID = 4;
487 for (
int i = 0; i < s->
numopts; i++) {
489 if (strncasecmp(t->
key,
"ina219", 7) == 0) {
491 if (strtok_r(t->
value,
":", &strtsp)) {
494 int baddr = strtol(t->
value, NULL, 16);
495 int msgid = strtol(strtok_r(NULL,
":", &strtsp), NULL, 16);
499 "[I2C:%s] Failed to register INA219 device at address 0x%02x and base message ID 0x%02x",
500 lta->
tag, baddr, msgid);
508 int baddr = strtol(t->
value, NULL, 16);
512 "[I2C:%s] Failed to register INA219 device at address 0x%02x and base message ID 0x%02x",
513 lta->
tag, baddr, baseMsgID);
519 }
else if (strncasecmp(t->
key,
"ads1015", 8) == 0) {
521 if (strtok_r(t->
value,
":", &strtsp)) {
526 int baddr = strtol(t->
value, NULL, 16);
527 int msgid = strtol(strtok_r(NULL,
":", &strtsp), NULL, 16);
530 "[I2C:%s] Error parsing values in configuration",
538 float min = -INFINITY;
539 float max = INFINITY;
540 char *tt = strtok_r(NULL,
":", &strtsp);
542 scale = strtof(tt, NULL);
546 "[I2C:%s] Error parsing scale value in configuration",
552 tt = strtok_r(NULL,
":", &strtsp);
555 offset = strtof(tt, NULL);
559 "[I2C:%s] Error parsing offset value in configuration",
564 tt = strtok_r(NULL,
":", &strtsp);
567 min = strtof(tt, NULL);
571 "[I2C:%s] Error parsing minimum value in configuration",
576 tt = strtok_r(NULL,
":", &strtsp);
579 max = strtof(tt, NULL);
583 "[I2C:%s] Error parsing maximum value in configuration",
597 "[I2C:%s] Failed to register ADS1015 device at address 0x%02x and base message ID 0x%02x",
598 lta->
tag, baddr, msgid);
606 int baddr = strtol(t->
value, NULL, 16);
611 "[I2C:%s] Failed to register ADS1015 device at address 0x%02x and base message ID 0x%02x",
612 lta->
tag, baddr, baseMsgID);
char * config_qstrdup(const char *c)
Duplicate string, stripping optional leading/trailing quote marks.
config_kv * config_get_key(const config_section *cs, const char *kn)
Find configugration key within specific section, by name.
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.
void msg_destroy(msg_t *msg)
Destroy a message.
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.
msg_t * msg_new_timestamp(const uint8_t source, const uint8_t type, const uint32_t ts)
Create a timestamp message.
msg_t * msg_new_float(const uint8_t source, const uint8_t type, const float val)
Create new message with a single numeric value.
int i2c_openConnection(const char *bus)
Set up a connection to the specified bus.
void i2c_closeConnection(int handle)
Close existing connection.
float i2c_ads1015_read_ch1(const int busHandle, const int devAddr, const void *opts)
Get single-ended voltage measurement from channel 1.
float i2c_ads1015_read_ch2(const int busHandle, const int devAddr, const void *opts)
Get single-ended voltage measurement from channel 2.
float i2c_ads1015_read_ch0(const int busHandle, const int devAddr, const void *opts)
Get single-ended voltage measurement from channel 0.
float i2c_ads1015_read_ch3(const int busHandle, const int devAddr, const void *opts)
Get single-ended voltage measurement from channel 3.
float i2c_ina219_read_shuntVoltage(const int busHandle, const int devAddr, const void *opts)
Get voltage across the shunt resistor in millivolts.
float i2c_ina219_read_current(const int busHandle, const int devAddr, const void *opts)
Get current flow through shunt resistor in amps.
float i2c_ina219_read_busVoltage(const int busHandle, const int devAddr, const void *opts)
Get bus voltage (at V- terminal) in volts.
#define SLCHAN_TSTAMP
Source timestamp (milliseconds, arbitrary epoch)
#define SLCHAN_RAW
Raw device data (Not mandatory)
#define SLCHAN_LOG_ERR
Error messages.
#define SLCHAN_LOG_INFO
Information messages.
#define SLCHAN_MAP
Channel name map (excludes log channels)
#define SLCHAN_NAME
Name of source device.
#define SLCHAN_LOG_WARN
Warning messages.
void * i2c_shutdown(void *ptargs)
I2C shutdown.
void * i2c_channels(void *ptargs)
Generate I2C channel map.
void * i2c_logging(void *ptargs)
I2C main logging loop.
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.
bool i2c_validate_chanmap(i2c_params *ip)
Check channel mapping is valid.
bool i2c_parseConfig(log_thread_args_t *lta, config_section *s)
Take a configuration section, parse parameters and register devices.
device_callbacks i2c_getCallbacks()
Fill out device callback functions for logging.
void * i2c_setup(void *ptargs)
I2C Connection setup.
i2c_params i2c_getParams()
Fill out default I2C parameters.
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.
#define SLSOURCE_I2C
I2C Bus.
atomic_bool shutdownFlag
Trigger clean software shutdown.
bool timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y)
Difference between timespecs (used for rate keeping)
void log_info(const program_state *s, const int level, const char *format,...)
Output formatted information message at a given level.
void log_warning(const program_state *s, const char *format,...)
Output formatted warning message.
void log_error(const program_state *s, const char *format,...)
Output formatted error message.
bool queue_push(msgqueue *queue, msg_t *msg)
Add a message to the tail of the queue.
void sa_destroy(strarray *sa)
Destroy array and contents.
bool str_update(string *str, const size_t len, const char *src)
Update an existing string from a character array of given length.
bool sa_set_entry(strarray *array, const int index, string *str)
Copy a string to a given position in the array.
strarray * sa_new(int entries)
Allocate storage for a new array.
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.
Represent a key=value pair.
char * value
Configuration item value.
char * key
Configuration item key.
Configuration file section.
int numopts
Number of *opts in use.
config_kv * opts
Key=value pairs belonging to this section.
Device specific function information.
device_fn startup
Called serially at startup, opens devices etc.
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.
uint8_t messageID
Message ID to report.
void * ext
If not NULL, pointer to additional device data.
uint8_t deviceAddr
I2C Device address.
i2c_dev_read_fn func
Pointer to device read function.
string message_name
Message name to report.
I2C Source device specific parameters.
int en_count
Number of messages in chanmap.
char * busName
Target port name.
int frequency
Aim to sample this many times per second.
char * sourceName
Reported source name.
uint8_t sourceNum
Source ID for messages.
i2c_msg_map * chanmap
Map of device functions to poll.
int handle
Handle for currently opened device.
Logging thread information.
msgqueue * logQ
Main message queue. Pushed to by threads, consumed by main()
char * tag
Tag/source name for messages etc.
void * dParams
Device/Thread specific data.
program_state * pstate
Current program state, used for logging.
int returnCode
Thread return code (output)
char * data
Character array, should be null terminated.
size_t length
This should include a terminating null byte where possible.