15size_t pc_dmx_build(uint8_t *buf,
size_t cap, uint8_t start_code,
const uint8_t *channels, uint16_t n)
17 if (!buf || n > DMX_MAX_CHANNELS || (n && !channels))
21 size_t total = (size_t)1 + n;
29 memcpy(buf + 1, channels, n);
34uint8_t pc_dmx_get_channel(
const uint8_t *buf,
size_t len, uint16_t ch)
36 if (!buf || ch < 1 || ch > DMX_MAX_CHANNELS || (
size_t)ch >= len)
43uint64_t pc_rdm_uid(uint16_t manufacturer, uint32_t device)
45 return ((uint64_t)manufacturer << 32) | device;
48uint16_t pc_rdm_checksum(
const uint8_t *buf,
size_t len)
51 for (
size_t i = 0; i < len; i++)
53 s = (uint16_t)(s + buf[i]);
59static void put_uid(uint8_t *p, uint64_t uid)
61 p[0] = (uint8_t)(uid >> 40);
62 p[1] = (uint8_t)(uid >> 32);
63 p[2] = (uint8_t)(uid >> 24);
64 p[3] = (uint8_t)(uid >> 16);
65 p[4] = (uint8_t)(uid >> 8);
69static uint64_t get_uid(
const uint8_t *p)
71 return ((uint64_t)p[0] << 40) | ((uint64_t)p[1] << 32) | ((uint64_t)p[2] << 24) | ((uint64_t)p[3] << 16) |
72 ((uint64_t)p[4] << 8) | (uint64_t)p[5];
75size_t pc_rdm_build(uint8_t *buf,
size_t cap,
const RdmPacket *p,
const uint8_t *pdata, uint8_t pdl)
77 if (!buf || !p || (pdl && !pdata))
81 uint8_t ml = (uint8_t)(24 + pdl);
82 size_t total = (size_t)ml + 2;
90 put_uid(buf + 3, p->dest_uid);
91 put_uid(buf + 9, p->src_uid);
94 buf[17] = p->msg_count;
95 buf[18] = (uint8_t)(p->sub_device >> 8);
96 buf[19] = (uint8_t)p->sub_device;
98 buf[21] = (uint8_t)(p->pid >> 8);
99 buf[22] = (uint8_t)p->pid;
103 memcpy(buf + 24, pdata, pdl);
105 uint16_t cs = pc_rdm_checksum(buf, ml);
106 buf[ml] = (uint8_t)(cs >> 8);
107 buf[ml + 1] = (uint8_t)cs;
111bool pc_rdm_parse(
const uint8_t *buf,
size_t len, RdmPacket *out,
size_t *consumed)
113 if (!buf || !out || len < RDM_OVERHEAD)
117 if (buf[0] != RDM_SC || buf[1] != RDM_SUB_SC)
126 uint8_t pdl = buf[23];
127 if (ml != (uint8_t)(24 + pdl))
131 size_t total = (size_t)ml + 2;
136 uint16_t cs = (uint16_t)((buf[ml] << 8) | buf[ml + 1]);
137 if (cs != pc_rdm_checksum(buf, ml))
142 out->dest_uid = get_uid(buf + 3);
143 out->src_uid = get_uid(buf + 9);
145 out->port_id = buf[16];
146 out->msg_count = buf[17];
147 out->sub_device = (uint16_t)((buf[18] << 8) | buf[19]);
149 out->pid = (uint16_t)((buf[21] << 8) | buf[22]);
151 out->pdata = pdl ? buf + 24 :
nullptr;
159bool pc_rdm_decode_disc_response(
const uint8_t *buf,
size_t len, uint64_t *uid)
167 while (p < len && p < 7 && buf[p] == 0xFE)
171 if (p >= len || buf[p] != 0xAA)
180 const uint8_t *euid = buf + p;
183 for (
int i = 0; i < 12; i++)
185 sum = (uint16_t)(sum + euid[i]);
187 uint8_t csum_hi = (uint8_t)(euid[12] & euid[13]);
188 uint8_t csum_lo = (uint8_t)(euid[14] & euid[15]);
189 if ((uint16_t)(((uint16_t)csum_hi << 8) | csum_lo) != sum)
195 for (
int i = 0; i < 6; i++)
197 u = (u << 8) | (uint8_t)(euid[i * 2] & euid[i * 2 + 1]);
203size_t pc_rdm_build_disc_response(uint8_t *buf,
size_t cap, uint64_t uid, uint8_t preamble_len)
205 if (!buf || preamble_len > 7)
209 size_t total = (size_t)preamble_len + 1 + 16;
215 for (uint8_t i = 0; i < preamble_len; i++)
222 for (
int i = 0; i < 6; i++)
224 uint8_t b = (uint8_t)(uid >> (8 * (5 - i)));
225 uint8_t e0 = (uint8_t)(b | 0xAA);
226 uint8_t e1 = (uint8_t)(b | 0x55);
229 sum = (uint16_t)(sum + e0 + e1);
231 uint8_t csum_hi = (uint8_t)(sum >> 8);
232 uint8_t csum_lo = (uint8_t)(sum & 0xFF);
233 buf[p++] = (uint8_t)(csum_hi | 0xAA);
234 buf[p++] = (uint8_t)(csum_hi | 0x55);
235 buf[p++] = (uint8_t)(csum_lo | 0xAA);
236 buf[p++] = (uint8_t)(csum_lo | 0x55);
240size_t pc_rdm_build_device_info(uint8_t *pdata,
size_t cap,
const RdmDeviceInfo *info)
242 if (!pdata || !info || cap < PC_RDM_DEVICE_INFO_PDL)
246 pdata[0] = info->proto_major;
247 pdata[1] = info->proto_minor;
248 pdata[2] = (uint8_t)(info->device_model_id >> 8);
249 pdata[3] = (uint8_t)info->device_model_id;
250 pdata[4] = (uint8_t)(info->product_category >> 8);
251 pdata[5] = (uint8_t)info->product_category;
252 pdata[6] = (uint8_t)(info->software_version_id >> 24);
253 pdata[7] = (uint8_t)(info->software_version_id >> 16);
254 pdata[8] = (uint8_t)(info->software_version_id >> 8);
255 pdata[9] = (uint8_t)info->software_version_id;
256 pdata[10] = (uint8_t)(info->dmx_footprint >> 8);
257 pdata[11] = (uint8_t)info->dmx_footprint;
258 pdata[12] = info->current_personality;
259 pdata[13] = info->personality_count;
260 pdata[14] = (uint8_t)(info->dmx_start_address >> 8);
261 pdata[15] = (uint8_t)info->dmx_start_address;
262 pdata[16] = (uint8_t)(info->sub_device_count >> 8);
263 pdata[17] = (uint8_t)info->sub_device_count;
264 pdata[18] = info->sensor_count;
265 return PC_RDM_DEVICE_INFO_PDL;
268bool pc_rdm_parse_device_info(
const uint8_t *pdata, uint8_t pdl, RdmDeviceInfo *out)
270 if (!pdata || !out || pdl < PC_RDM_DEVICE_INFO_PDL)
274 out->proto_major = pdata[0];
275 out->proto_minor = pdata[1];
276 out->device_model_id = (uint16_t)((pdata[2] << 8) | pdata[3]);
277 out->product_category = (uint16_t)((pdata[4] << 8) | pdata[5]);
278 out->software_version_id =
279 ((uint32_t)pdata[6] << 24) | ((uint32_t)pdata[7] << 16) | ((uint32_t)pdata[8] << 8) | (uint32_t)pdata[9];
280 out->dmx_footprint = (uint16_t)((pdata[10] << 8) | pdata[11]);
281 out->current_personality = pdata[12];
282 out->personality_count = pdata[13];
283 out->dmx_start_address = (uint16_t)((pdata[14] << 8) | pdata[15]);
284 out->sub_device_count = (uint16_t)((pdata[16] << 8) | pdata[17]);
285 out->sensor_count = pdata[18];
DMX512 framing + RDM (ANSI E1.20) management codec (PC_ENABLE_DMX).