ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
sigfox.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 sigfox.cpp
6 * @brief Sigfox modem AT-command codec - implementation.
7 *
8 * `AT$SF=<hex>` sends one uplink; the modem replies "OK" on success or "ERROR". The payload
9 * is hex-encoded (uppercase, two nibbles per byte) into the command.
10 */
11
13
14#if PC_ENABLE_SIGFOX
15
16namespace
17{
18char hex_nibble(uint8_t v)
19{
20 return (char)(v < 10 ? '0' + v : 'A' + (v - 10));
21}
22
23// Is the needle present in the first len bytes of haystack?
24bool contains(const char *hay, uint16_t len, const char *needle)
25{
26 uint16_t nlen = 0;
27 while (needle[nlen])
28 {
29 nlen++;
30 }
31 if (nlen == 0 || len < nlen) // GCOVR_EXCL_LINE nlen==0 is unreachable: contains() is only ever called
32 {
33 return false; // (internally, both call sites below) with the literal non-empty needles "ERROR"/"OK"
34 }
35 for (uint16_t i = 0; i + nlen <= len; i++)
36 {
37 uint16_t j = 0;
38 while (j < nlen && hay[i + j] == needle[j])
39 {
40 j++;
41 }
42 if (j == nlen)
43 {
44 return true;
45 }
46 }
47 return false;
48}
49} // namespace
50
51uint16_t pc_sigfox_build_uplink(const uint8_t *payload, uint8_t len, char *out, uint16_t cap)
52{
53 if (!out || !payload || len == 0 || len > PC_SIGFOX_MAX_PAYLOAD)
54 {
55 return 0;
56 }
57 // "AT$SF=" (6) + 2*len hex + "\r\n" (2) + NUL (1)
58 uint16_t need = (uint16_t)(6 + 2 * len + 2 + 1);
59 if (need > cap)
60 {
61 return 0;
62 }
63 const char *pfx = "AT$SF=";
64 uint16_t p = 0;
65 for (const char *s = pfx; *s; s++)
66 {
67 out[p++] = *s;
68 }
69 for (uint8_t i = 0; i < len; i++)
70 {
71 out[p++] = hex_nibble((uint8_t)(payload[i] >> 4));
72 out[p++] = hex_nibble((uint8_t)(payload[i] & 0x0F));
73 }
74 out[p++] = '\r';
75 out[p++] = '\n';
76 out[p] = '\0';
77 return p;
78}
79
80pc_sigfox_result pc_sigfox_parse_response(const char *buf, uint16_t len)
81{
82 if (!buf || len == 0)
83 {
84 return pc_sigfox_result::SIGFOX_PENDING;
85 }
86 if (contains(buf, len, "ERROR"))
87 {
88 return pc_sigfox_result::SIGFOX_ERROR;
89 }
90 if (contains(buf, len, "OK"))
91 {
92 return pc_sigfox_result::SIGFOX_OK;
93 }
94 return pc_sigfox_result::SIGFOX_PENDING;
95}
96
97#endif // PC_ENABLE_SIGFOX
#define PC_SIGFOX_MAX_PAYLOAD
Maximum Sigfox uplink payload (the network caps a message at 12 bytes).
Sigfox modem AT-command codec (PC_ENABLE_SIGFOX) - Wisol / Murata over UART.