17size_t pc_sdi12_build(
char *buf,
size_t cap,
char addr,
const char *body)
23 size_t blen = strnlen(body, cap);
24 size_t n = 1 + blen + 1;
30 memcpy(buf + 1, body, blen);
36size_t pc_sdi12_build_ack(
char *buf,
size_t cap,
char addr)
38 return pc_sdi12_build(buf, cap, addr,
"");
41size_t pc_sdi12_build_identify(
char *buf,
size_t cap,
char addr)
43 return pc_sdi12_build(buf, cap, addr,
"I");
46size_t pc_sdi12_build_measure(
char *buf,
size_t cap,
char addr,
bool with_crc)
48 return pc_sdi12_build(buf, cap, addr, with_crc ?
"MC" :
"M");
51size_t pc_sdi12_build_concurrent(
char *buf,
size_t cap,
char addr,
bool with_crc)
53 return pc_sdi12_build(buf, cap, addr, with_crc ?
"CC" :
"C");
56size_t pc_sdi12_build_measure_additional(
char *buf,
size_t cap,
char addr, uint8_t m_index,
bool with_crc)
58 if (m_index < 1 || m_index > 9)
69 body[b++] = (char)(
'0' + m_index);
71 return pc_sdi12_build(buf, cap, addr, body);
74size_t pc_sdi12_build_concurrent_additional(
char *buf,
size_t cap,
char addr, uint8_t c_index,
bool with_crc)
76 if (c_index < 1 || c_index > 9)
87 body[b++] = (char)(
'0' + c_index);
89 return pc_sdi12_build(buf, cap, addr, body);
92size_t pc_sdi12_build_continuous(
char *buf,
size_t cap,
char addr, uint8_t r_index,
bool with_crc)
105 body[b++] = (char)(
'0' + r_index);
107 return pc_sdi12_build(buf, cap, addr, body);
110size_t pc_sdi12_build_verify(
char *buf,
size_t cap,
char addr)
112 return pc_sdi12_build(buf, cap, addr,
"V");
115size_t pc_sdi12_build_data(
char *buf,
size_t cap,
char addr, uint8_t d_index)
121 char body[3] = {
'D', (char)(
'0' + d_index),
'\0'};
122 return pc_sdi12_build(buf, cap, addr, body);
125size_t pc_sdi12_build_change_address(
char *buf,
size_t cap,
char addr,
char new_addr)
127 char body[3] = {
'A', new_addr,
'\0'};
128 return pc_sdi12_build(buf, cap, addr, body);
131size_t pc_sdi12_build_query_address(
char *buf,
size_t cap)
133 return pc_sdi12_build(buf, cap,
'?',
"");
136bool pc_sdi12_parse_measure(
const char *resp,
size_t len,
char *addr, uint16_t *ready_sec, uint8_t *num_values)
138 if (!resp || len < 5)
142 for (
int i = 1; i <= 3; i++)
159 *ready_sec = (uint16_t)((resp[1] -
'0') * 100 + (resp[2] -
'0') * 10 + (resp[3] -
'0'));
163 for (
size_t i = 4; i < len &&
pc_np_digit(resp[i]); i++)
165 count = (uint16_t)(count * 10 + (resp[i] -
'0'));
169 *num_values = (uint8_t)count;
174bool pc_sdi12_parse_values(
const char *resp,
size_t len,
float *out,
size_t max,
size_t *n)
176 if (!resp || !out || !n)
182 while (i < len && cnt < max)
185 if (c ==
'\r' || c ==
'\n')
189 if (c ==
'+' || c ==
'-')
191 const char *start = resp + i;
192 const char *end = start;
195 if (end == start || (c ==
'+' && end == start + 1))
201 i = (size_t)(end - resp);
212bool pc_sdi12_parse_identify(
const char *resp,
size_t len, Sdi12Identity *out)
214 if (!resp || !out || len < 20)
219 memcpy(out->sdi_version, resp + 1, 2);
220 out->sdi_version[2] =
'\0';
221 memcpy(out->vendor, resp + 3, 8);
222 out->vendor[8] =
'\0';
223 memcpy(out->model, resp + 11, 6);
224 out->model[6] =
'\0';
225 memcpy(out->sensor_version, resp + 17, 3);
226 out->sensor_version[3] =
'\0';
230uint16_t pc_sdi12_crc16(
const uint8_t *data,
size_t len)
238void pc_sdi12_crc_encode(uint16_t crc,
char out[SDI12_CRC_CHARS])
240 out[0] = (char)(0x40u | (crc >> 12));
241 out[1] = (char)(0x40u | ((crc >> 6) & 0x3Fu));
242 out[2] = (char)(0x40u | (crc & 0x3Fu));
245bool pc_sdi12_check_crc(
const char *resp,
size_t len)
252 while (len > 0 && (resp[len - 1] ==
'\n' || resp[len - 1] ==
'\r'))
256 if (len < SDI12_CRC_CHARS + 1)
260 size_t data_len = len - SDI12_CRC_CHARS;
261 char enc[SDI12_CRC_CHARS];
262 pc_sdi12_crc_encode(pc_sdi12_crc16((
const uint8_t *)resp, data_len), enc);
263 return memcmp(enc, resp + data_len, SDI12_CRC_CHARS) == 0;
Parameterized CRC engine - one source of truth for every cyclic redundancy check.
constexpr pc_crc_params PC_CRC16_ARC
CRC-16/ARC (a.k.a. CRC-16, IBM). check = 0xBB3D.
uint32_t pc_crc(const pc_crc_params *p, const uint8_t *data, size_t len)
One-shot CRC of len octets at data.
Tiny no-stdlib base-10 number parsers (strtol/strtoul/strtof replacements).
float pc_strtof(const char *s, const char **end)
Parse a float (integer[.frac][e[+/-]exp]); sets end (or to s if none).
SDI-12 sensor-bus command / response codec (PC_ENABLE_SDI12).