24const uint8_t HDR[4] = {0xF4, 0xF3, 0xF2, 0xF1};
25const uint8_t FTR[4] = {0xF8, 0xF7, 0xF6, 0xF5};
26const uint8_t CMD_HDR[4] = {0xFD, 0xFC, 0xFB, 0xFA};
27const uint8_t CMD_FTR[4] = {0x04, 0x03, 0x02, 0x01};
29uint16_t rd16(
const uint8_t *p)
31 return (uint16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8));
35bool pc_hmmd_parse_report(
const uint8_t *f,
size_t len, HmmdReport *out)
37 if (!f || !out || len != PC_HMMD_FRAME_MAX)
41 if (memcmp(f, HDR, 4) != 0)
45 if (rd16(f + 4) != PC_HMMD_REPORT_LEN)
49 if (memcmp(f + 6 + PC_HMMD_REPORT_LEN, FTR, 4) != 0)
54 const uint8_t *p = f + 6;
56 memset(&r, 0,
sizeof(r));
57 r.detected = (p[0] == 0x01) ? 1u : 0u;
58 r.distance_cm = rd16(p + 1);
59 for (
int i = 0; i < PC_HMMD_GATES; i++)
61 r.gate_energy[i] = rd16(p + 3 + 2 * i);
67void pc_hmmd_stream_reset(HmmdStream *s)
79bool pc_hmmd_stream_push(HmmdStream *s, uint8_t b, HmmdReport *out)
88 if (b == HDR[s->hdr_match])
90 s->buf[s->hdr_match++] = b;
91 if (s->hdr_match == 4)
99 s->hdr_match = (b == HDR[0]) ? 1 : 0;
107 s->buf[s->pos++] = b;
111 uint32_t total = 6u + (uint32_t)rd16(s->buf + 4) + 4u;
112 if (total > PC_HMMD_FRAME_MAX)
114 pc_hmmd_stream_reset(s);
117 s->total = (uint16_t)total;
122 s->buf[s->pos++] = b;
123 if (s->pos >= s->total)
125 bool ok = pc_hmmd_parse_report(s->buf, s->total, out);
126 pc_hmmd_stream_reset(s);
133bool pc_hmmd_present(
const HmmdReport *r)
135 return r && r->detected != 0;
138uint16_t pc_hmmd_distance_cm(
const HmmdReport *r)
140 return (r && r->detected) ? r->distance_cm : 0;
145size_t pc_hmmd_cmd_build(uint8_t *buf,
size_t cap, uint16_t word,
const uint8_t *value,
size_t vlen)
151 size_t need = 4 + 2 + 2 + vlen + 4;
152 if (!buf || cap < need)
157 for (
int k = 0; k < 4; k++)
159 buf[i++] = CMD_HDR[k];
161 uint16_t dl = (uint16_t)(2 + vlen);
162 buf[i++] = (uint8_t)(dl & 0xFF);
163 buf[i++] = (uint8_t)(dl >> 8);
164 buf[i++] = (uint8_t)(word & 0xFF);
165 buf[i++] = (uint8_t)(word >> 8);
166 for (
size_t k = 0; k < vlen; k++)
170 for (
int k = 0; k < 4; k++)
172 buf[i++] = CMD_FTR[k];
177size_t pc_hmmd_cmd_open(uint8_t *buf,
size_t cap)
179 static const uint8_t v[2] = {0x01, 0x00};
180 return pc_hmmd_cmd_build(buf, cap, 0x00FF, v, 2);
183size_t pc_hmmd_cmd_close(uint8_t *buf,
size_t cap)
185 return pc_hmmd_cmd_build(buf, cap, 0x00FE,
nullptr, 0);
188size_t pc_hmmd_cmd_read_firmware(uint8_t *buf,
size_t cap)
190 return pc_hmmd_cmd_build(buf, cap, 0x0000,
nullptr, 0);
193size_t pc_hmmd_cmd_read_serial(uint8_t *buf,
size_t cap)
195 return pc_hmmd_cmd_build(buf, cap, 0x0011,
nullptr, 0);
198size_t pc_hmmd_cmd_read_config(uint8_t *buf,
size_t cap)
200 return pc_hmmd_cmd_build(buf, cap, 0x0008,
nullptr, 0);
203size_t pc_hmmd_cmd_read_register(uint8_t *buf,
size_t cap,
const uint8_t *value,
size_t vlen)
205 return pc_hmmd_cmd_build(buf, cap, 0x0002, value, vlen);
210bool pc_hmmd_parse_ack(
const uint8_t *f,
size_t len, HmmdAck *out)
213 if (!f || !out || len < 12)
217 if (memcmp(f, CMD_HDR, 4) != 0)
221 size_t dl = (size_t)rd16(f + 4);
222 if (dl < 2 || len != 4 + 2 + dl + 4)
226 if (memcmp(f + 6 + dl, CMD_FTR, 4) != 0)
230 out->command = rd16(f + 6);
231 out->payload_len = dl - 2;
232 out->payload = out->payload_len ? f + 8 :
nullptr;
236bool pc_hmmd_ack_matches(
const HmmdAck *ack, uint16_t word)
238 return ack && (uint8_t)(ack->command & 0xFF) == (uint8_t)(word & 0xFF);
261bool pc_hmmd_begin(
int rx_pin,
int tx_pin)
263 pc_hmmd_stream_reset(&s_hmmd.stream);
265 Serial2.begin(
PC_HMMD_BAUD, SERIAL_8N1, rx_pin, tx_pin);
272 while (Serial2.available())
275 if (pc_hmmd_stream_push(&s_hmmd.stream, (uint8_t)Serial2.read(), &r))
285const HmmdReport *pc_hmmd_last()
287 return s_hmmd.have ? &s_hmmd.last :
nullptr;
292bool pc_hmmd_begin(
int,
int)
302const HmmdReport *pc_hmmd_last()
Waveshare HMMD 24 GHz mmWave human micro-motion radar codec (PC_ENABLE_HMMD).
#define PC_HMMD_BAUD
HMMD UART baud rate (the module's factory default is 115200).