15uint8_t pc_hostlink_fcs(
const char *data,
size_t len)
18 for (
size_t i = 0; i < len; i++)
20 f ^= (uint8_t)data[i];
25static char hex_digit(uint8_t v)
27 return (
char)(v < 10 ?
'0' + v :
'A' + (v - 10));
31static int hex_val(
char c)
33 if (c >=
'0' && c <=
'9')
37 if (c >=
'A' && c <=
'F')
41 if (c >=
'a' && c <=
'f')
48size_t pc_hostlink_build(
char *buf,
size_t cap, uint8_t node,
const char *header_code,
const char *text,
51 if (!buf || !header_code || node > 99 || (text_len && !text))
55 if (header_code[0] ==
'\0' || header_code[1] ==
'\0')
59 size_t total = 1 + 2 + 2 + text_len + 2 + 2;
67 buf[p++] = (char)(
'0' + node / 10);
68 buf[p++] = (char)(
'0' + node % 10);
69 buf[p++] = header_code[0];
70 buf[p++] = header_code[1];
73 memcpy(buf + p, text, text_len);
76 uint8_t f = pc_hostlink_fcs(buf, p);
77 buf[p++] = hex_digit((uint8_t)(f >> 4));
78 buf[p++] = hex_digit((uint8_t)(f & 0x0F));
85bool pc_hostlink_parse(
const char *buf,
size_t len, HostlinkFrame *out)
88 if (!buf || !out || len < 9)
92 if (buf[0] !=
'@' || buf[len - 1] !=
'\r' || buf[len - 2] !=
'*')
96 if (buf[1] <
'0' || buf[1] >
'9' || buf[2] <
'0' || buf[2] >
'9')
101 size_t fcs_pos = len - 4;
102 int hi = hex_val(buf[fcs_pos]);
103 int lo = hex_val(buf[fcs_pos + 1]);
104 if (hi < 0 || lo < 0)
108 uint8_t got = (uint8_t)((hi << 4) | lo);
109 if (pc_hostlink_fcs(buf, fcs_pos) != got)
114 out->node = (uint8_t)((buf[1] -
'0') * 10 + (buf[2] -
'0'));
115 out->header_code[0] = buf[3];
116 out->header_code[1] = buf[4];
117 out->header_code[2] =
'\0';
119 out->text_len = fcs_pos - 5;
123bool pc_hostlink_end_code(
const HostlinkFrame *f, uint8_t *code)
125 if (!f || f->text_len < 2)
129 int hi = hex_val(f->text[0]);
130 int lo = hex_val(f->text[1]);
131 if (hi < 0 || lo < 0)
137 *code = (uint8_t)((hi << 4) | lo);
142size_t pc_hostlink_build_read(
char *buf,
size_t cap, uint8_t node, uint16_t address, uint16_t count)
144 if (address > 9999 || count > 9999 || count == 0)
149 text[0] = (char)(
'0' + (address / 1000) % 10);
150 text[1] = (char)(
'0' + (address / 100) % 10);
151 text[2] = (char)(
'0' + (address / 10) % 10);
152 text[3] = (char)(
'0' + address % 10);
153 text[4] = (char)(
'0' + (count / 1000) % 10);
154 text[5] = (char)(
'0' + (count / 100) % 10);
155 text[6] = (char)(
'0' + (count / 10) % 10);
156 text[7] = (char)(
'0' + count % 10);
157 return pc_hostlink_build(buf, cap, node,
"RD", text,
sizeof(text));
160bool pc_hostlink_read_word(
const HostlinkFrame *f,
size_t index, uint16_t *out)
167 size_t pos = 2 + index * 4;
168 if (f->text_len < pos + 4)
172 int a = hex_val(f->text[pos]), b = hex_val(f->text[pos + 1]);
173 int c = hex_val(f->text[pos + 2]), d = hex_val(f->text[pos + 3]);
174 if (a < 0 || b < 0 || c < 0 || d < 0)
178 *out = (uint16_t)((a << 12) | (b << 8) | (c << 4) | d);
182size_t pc_hostlink_build_write(
char *buf,
size_t cap, uint8_t node, uint16_t address,
const uint16_t *words,
185 if (!buf || node > 99 || address > 9999 || word_count == 0 || !words)
189 if (word_count > cap / 4)
194 size_t total = 1 + 2 + 2 + 4 + word_count * 4 + 2 + 2;
202 buf[p++] = (char)(
'0' + node / 10);
203 buf[p++] = (char)(
'0' + node % 10);
206 buf[p++] = (char)(
'0' + (address / 1000) % 10);
207 buf[p++] = (char)(
'0' + (address / 100) % 10);
208 buf[p++] = (char)(
'0' + (address / 10) % 10);
209 buf[p++] = (char)(
'0' + address % 10);
210 for (
size_t i = 0; i < word_count; i++)
212 uint16_t w = words[i];
213 buf[p++] = hex_digit((uint8_t)((w >> 12) & 0x0F));
214 buf[p++] = hex_digit((uint8_t)((w >> 8) & 0x0F));
215 buf[p++] = hex_digit((uint8_t)((w >> 4) & 0x0F));
216 buf[p++] = hex_digit((uint8_t)(w & 0x0F));
218 uint8_t f = pc_hostlink_fcs(buf, p);
219 buf[p++] = hex_digit((uint8_t)(f >> 4));
220 buf[p++] = hex_digit((uint8_t)(f & 0x0F));
Omron Host Link (C-mode) frame codec (PC_ENABLE_HOSTLINK) - zero-heap ASCII command/response framing ...