16size_t sdi12_build(
char *buf,
size_t cap,
char addr,
const char *body)
20 size_t blen = strnlen(body, cap);
21 size_t n = 1 + blen + 1;
25 memcpy(buf + 1, body, blen);
31size_t sdi12_build_ack(
char *buf,
size_t cap,
char addr)
33 return sdi12_build(buf, cap, addr,
"");
36size_t sdi12_build_identify(
char *buf,
size_t cap,
char addr)
38 return sdi12_build(buf, cap, addr,
"I");
41size_t sdi12_build_measure(
char *buf,
size_t cap,
char addr,
bool with_crc)
43 return sdi12_build(buf, cap, addr, with_crc ?
"MC" :
"M");
46size_t sdi12_build_concurrent(
char *buf,
size_t cap,
char addr,
bool with_crc)
48 return sdi12_build(buf, cap, addr, with_crc ?
"CC" :
"C");
51size_t sdi12_build_data(
char *buf,
size_t cap,
char addr, uint8_t d_index)
55 char body[3] = {
'D', (char)(
'0' + d_index),
'\0'};
56 return sdi12_build(buf, cap, addr, body);
59size_t sdi12_build_change_address(
char *buf,
size_t cap,
char addr,
char new_addr)
61 char body[3] = {
'A', new_addr,
'\0'};
62 return sdi12_build(buf, cap, addr, body);
65size_t sdi12_build_query_address(
char *buf,
size_t cap)
67 return sdi12_build(buf, cap,
'?',
"");
70bool sdi12_parse_measure(
const char *resp,
size_t len,
char *addr, uint16_t *ready_sec, uint8_t *num_values)
74 for (
int i = 1; i <= 3; i++)
82 *ready_sec = (uint16_t)((resp[1] -
'0') * 100 + (resp[2] -
'0') * 10 + (resp[3] -
'0'));
85 for (
size_t i = 4; i < len &&
det_np_digit(resp[i]); i++)
86 count = (uint16_t)(count * 10 + (resp[i] -
'0'));
88 *num_values = (uint8_t)count;
92bool sdi12_parse_values(
const char *resp,
size_t len,
float *out,
size_t max,
size_t *n)
94 if (!resp || !out || !n)
98 while (i < len && cnt < max)
101 if (c ==
'\r' || c ==
'\n')
103 if (c ==
'+' || c ==
'-')
105 const char *start = resp + i;
106 const char *end = start;
109 if (end == start || (c ==
'+' && end == start + 1))
115 i = (size_t)(end - resp);
126uint16_t sdi12_crc16(
const uint8_t *data,
size_t len)
129 for (
size_t i = 0; i < len; i++)
132 for (
int b = 0; b < 8; b++)
133 crc = (crc & 1u) ? (uint16_t)((crc >> 1) ^ SDI12_CRC_POLY) : (uint16_t)(crc >> 1);
138void sdi12_crc_encode(uint16_t crc,
char out[SDI12_CRC_CHARS])
140 out[0] = (char)(0x40u | (crc >> 12));
141 out[1] = (char)(0x40u | ((crc >> 6) & 0x3Fu));
142 out[2] = (char)(0x40u | (crc & 0x3Fu));
145bool sdi12_check_crc(
const char *resp,
size_t len)
150 while (len > 0 && (resp[len - 1] ==
'\n' || resp[len - 1] ==
'\r'))
152 if (len < SDI12_CRC_CHARS + 1)
154 size_t data_len = len - SDI12_CRC_CHARS;
155 char enc[SDI12_CRC_CHARS];
156 sdi12_crc_encode(sdi12_crc16((
const uint8_t *)resp, data_len), enc);
157 return memcmp(enc, resp + data_len, SDI12_CRC_CHARS) == 0;
Tiny no-stdlib base-10 number parsers (strtol/strtoul/strtof replacements).
float det_strtof(const char *s, const char **end)
Parse a float (integer[.frac][e[+/-]exp]); sets end (or to s if none).
bool det_np_digit(char c)
SDI-12 sensor-bus command / response codec (DETWS_ENABLE_SDI12).