ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
southbound.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 southbound.cpp
6 * @brief Southbound protocol-driver framework registry + dispatch (see southbound.h).
7 */
8
10
11#if PC_ENABLE_SOUTHBOUND
12
13#include <string.h>
14
15#ifndef PC_SOUTHBOUND_MAX_DRIVERS
16#define PC_SOUTHBOUND_MAX_DRIVERS 8 ///< bounded registry; no heap.
17#endif
18
19namespace
20{
21// All southbound-registry state, owned by one instance (internal linkage): the bounded
22// driver table and its count, grouped so it is one named owner, unreachable cross-TU.
23struct SouthboundCtx
24{
25 const SouthboundDriver *drivers[PC_SOUTHBOUND_MAX_DRIVERS] = {};
26 size_t count = 0;
27};
28SouthboundCtx s_sb;
29} // namespace
30
31int pc_southbound_register(const SouthboundDriver *drv)
32{
33 if (!drv || !drv->name)
34 {
35 return Sb::SB_ERR_ARG;
36 }
37 if (pc_southbound_find(drv->name))
38 {
39 return Sb::SB_ERR_DUP;
40 }
41 if (s_sb.count >= PC_SOUTHBOUND_MAX_DRIVERS)
42 {
43 return Sb::SB_ERR_FULL;
44 }
45 s_sb.drivers[s_sb.count++] = drv;
46 return Sb::SB_OK;
47}
48
49void pc_southbound_clear(void)
50{
51 for (size_t i = 0; i < PC_SOUTHBOUND_MAX_DRIVERS; i++)
52 {
53 s_sb.drivers[i] = nullptr;
54 }
55 s_sb.count = 0;
56}
57
58size_t pc_southbound_count(void)
59{
60 return s_sb.count;
61}
62
63const SouthboundDriver *pc_southbound_find(const char *name)
64{
65 if (!name)
66 {
67 return nullptr;
68 }
69 // Only the first && arm's false side is structurally unreachable: s_sb.drivers[i] can never be
70 // null for i < count, because register() only ever stores a drv already proven non-null (its own
71 // !drv check above) in the same statement that increments count, and clear() resets the whole
72 // array and count together - no public-API path leaves a live index holding a null pointer. The
73 // second arm (drivers[i]->name) is NOT similarly guaranteed: the registry stores a *borrowed*
74 // pointer, so a caller can null out a registered driver's name field after registration (see
75 // test_find_skips_driver_mutated_name_null) - that guard is live, tested defensive code, not dead
76 // code; the exclusion below covers only the first arm's genuinely dead branch.
77 for (size_t i = 0; i < s_sb.count; i++)
78 {
79 if (s_sb.drivers[i] && s_sb.drivers[i]->name && strcmp(s_sb.drivers[i]->name, name) == 0) // GCOVR_EXCL_BR_LINE
80 {
81 return s_sb.drivers[i];
82 }
83 }
84 return nullptr;
85}
86
87int pc_southbound_read(const char *name, uint32_t point, int32_t *value_out)
88{
89 if (!value_out)
90 {
91 return Sb::SB_ERR_ARG;
92 }
93 const SouthboundDriver *d = pc_southbound_find(name);
94 if (!d)
95 {
96 return Sb::SB_ERR_NOT_FOUND;
97 }
98 if (!d->read)
99 {
100 return Sb::SB_ERR_UNSUPPORTED;
101 }
102 return d->read(d->ctx, point, value_out);
103}
104
105int pc_southbound_write(const char *name, uint32_t point, int32_t value)
106{
107 const SouthboundDriver *d = pc_southbound_find(name);
108 if (!d)
109 {
110 return Sb::SB_ERR_NOT_FOUND;
111 }
112 if (!d->write)
113 {
114 return Sb::SB_ERR_UNSUPPORTED;
115 }
116 return d->write(d->ctx, point, value);
117}
118
119int pc_southbound_read_block(const char *name, uint32_t first, int32_t *out, size_t n)
120{
121 if (!out || n == 0)
122 {
123 return Sb::SB_ERR_ARG;
124 }
125 const SouthboundDriver *d = pc_southbound_find(name);
126 if (!d)
127 {
128 return Sb::SB_ERR_NOT_FOUND;
129 }
130 if (!d->read_block)
131 {
132 return Sb::SB_ERR_UNSUPPORTED;
133 }
134 return d->read_block(d->ctx, first, out, n);
135}
136
137int pc_southbound_write_block(const char *name, uint32_t first, const int32_t *in, size_t n)
138{
139 if (!in || n == 0)
140 {
141 return Sb::SB_ERR_ARG;
142 }
143 const SouthboundDriver *d = pc_southbound_find(name);
144 if (!d)
145 {
146 return Sb::SB_ERR_NOT_FOUND;
147 }
148 if (!d->write_block)
149 {
150 return Sb::SB_ERR_UNSUPPORTED;
151 }
152 return d->write_block(d->ctx, first, in, n);
153}
154
155#endif // PC_ENABLE_SOUTHBOUND
Southbound protocol-driver framework (PC_ENABLE_SOUTHBOUND).