ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
cclink.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file cclink.cpp
6 * @brief CC-Link cyclic fieldbus frame codec (see cclink.h).
7 */
8
10
11#if PC_ENABLE_CCLINK
12
13#include <string.h>
14
15uint8_t pc_cclink_sum(const uint8_t *bytes, size_t len)
16{
17 uint8_t sum = 0;
18 for (size_t i = 0; i < len; i++)
19 {
20 sum = (uint8_t)(sum + bytes[i]);
21 }
22 return sum;
23}
24
25size_t pc_cclink_build(uint8_t station, uint8_t command, const uint8_t *bits, size_t bit_len, const uint8_t *words,
26 size_t word_len, uint8_t *out, size_t cap)
27{
28 if (!out || (bit_len && !bits) || (word_len && !words) || station > 63)
29 {
30 return 0;
31 }
32 size_t n = 2 + bit_len + word_len + 1;
33 if (n > cap)
34 {
35 return 0;
36 }
37 size_t i = 0;
38 out[i++] = station;
39 out[i++] = command;
40 if (bit_len)
41 {
42 memcpy(out + i, bits, bit_len);
43 i += bit_len;
44 }
45 if (word_len)
46 {
47 memcpy(out + i, words, word_len);
48 i += word_len;
49 }
50 out[i] = pc_cclink_sum(out, i); // checksum over station..last data
51 i++;
52 return i;
53}
54
55bool pc_cclink_parse(const uint8_t *frame, size_t len, CcLinkFrame *out)
56{
57 if (!frame || !out || len < 3) // station + command + checksum
58 {
59 return false;
60 }
61 size_t body = len - 1;
62 if (pc_cclink_sum(frame, body) != frame[body])
63 {
64 return false;
65 }
66 out->station = frame[0];
67 out->command = frame[1];
68 out->payload = (body > 2) ? (frame + 2) : nullptr;
69 out->payload_len = body - 2;
70 return true;
71}
72
73bool pc_cclink_get_bit(const uint8_t *bits, size_t bit_len, size_t index)
74{
75 if (!bits || index / 8 >= bit_len)
76 {
77 return false;
78 }
79 return (bits[index / 8] >> (index % 8)) & 1u;
80}
81
82void pc_cclink_set_bit(uint8_t *bits, size_t bit_len, size_t index, bool value)
83{
84 if (!bits || index / 8 >= bit_len)
85 {
86 return;
87 }
88 uint8_t mask = (uint8_t)(1u << (index % 8));
89 if (value)
90 {
91 bits[index / 8] |= mask;
92 }
93 else
94 {
95 bits[index / 8] &= (uint8_t)~mask;
96 }
97}
98
99uint16_t pc_cclink_get_word(const uint8_t *words, size_t word_len, size_t index)
100{
101 size_t off = index * 2;
102 if (!words || off + 1 >= word_len)
103 {
104 return 0;
105 }
106 return (uint16_t)(words[off] | (words[off + 1] << 8)); // little-endian
107}
108
109#endif // PC_ENABLE_CCLINK
uint32_t mask(uint8_t width)
Mask of width low bits (width 32 handled without a 32-bit shift, which is UB).
Definition crc.h:61