30 uint32_t window_start;
44 pc_gateway_uplink_fn uplink =
nullptr;
45 void *uplink_ctx =
nullptr;
48 pc_gateway_stats stats;
68port *find_port(GatewayCtx &g, uint8_t
id)
72 if (g.ports[i].used && g.ports[i].id ==
id)
81bool rate_exceeded(port *p)
87 uint32_t now = gw_now();
88 if ((uint32_t)(now - p->window_start) >= 1000)
90 p->window_start = now;
93 if (p->count >= p->rate_cap)
101bool put_ch(
char *buf, uint16_t *pos, uint16_t cap,
char c)
103 if ((uint16_t)(*pos + 1) >= cap)
111bool put_u32(
char *buf, uint16_t *pos, uint16_t cap, uint32_t v)
121 tmp[n++] = (char)(
'0' + (v % 10));
126 if (!put_ch(buf, pos, cap, tmp[--n]))
135void pc_gateway_reset(
void)
137 memset(s_gw.ports, 0,
sizeof(s_gw.ports));
138 s_gw.uplink =
nullptr;
139 s_gw.uplink_ctx =
nullptr;
142 memset(&s_gw.stats, 0,
sizeof(s_gw.stats));
145bool pc_gateway_add_port(
const pc_gateway_port_config *cfg)
147 if (!cfg || find_port(s_gw, cfg->port_id))
153 if (s_gw.ports[i].used)
157 s_gw.ports[i].tx = cfg->tx;
158 s_gw.ports[i].ctx = cfg->ctx;
159 s_gw.ports[i].window_start = 0;
160 s_gw.ports[i].rate_cap = cfg->rate_cap;
161 s_gw.ports[i].count = 0;
162 s_gw.ports[i].id = cfg->port_id;
163 s_gw.ports[i].kind = cfg->kind;
164 s_gw.ports[i].used =
true;
170void pc_gateway_set_uplink_cb(pc_gateway_uplink_fn fn,
void *ctx)
173 s_gw.uplink_ctx = ctx;
176void pc_gateway_set_topic_prefix(
const char *prefix)
181bool pc_gateway_uplink(uint8_t port_id, uint16_t src_addr,
const uint8_t *payload, uint16_t len, int16_t rssi)
184 port *p = find_port(s_gw, port_id);
185 if (!p || !s_gw.uplink || rate_exceeded(p))
187 s_gw.stats.up_dropped++;
191 msg.payload = payload;
192 msg.seq = s_gw.seq++;
194 msg.src_addr = src_addr;
196 msg.port_id = port_id;
198 if (s_gw.uplink(&msg, s_gw.uplink_ctx))
200 s_gw.stats.up_published++;
203 s_gw.stats.up_dropped++;
207bool pc_gateway_downlink(uint8_t port_id, uint16_t dst_addr,
const uint8_t *payload, uint16_t len)
209 s_gw.stats.down_in++;
210 port *p = find_port(s_gw, port_id);
211 if (!p || !p->tx || !p->tx(port_id, dst_addr, payload, len, p->ctx))
213 s_gw.stats.down_dropped++;
216 s_gw.stats.down_sent++;
220uint16_t pc_gateway_topic(
const pc_gateway_msg *msg,
char *buf, uint16_t buflen)
222 if (!msg || !buf || buflen == 0)
227 for (
const char *s = s_gw.prefix; *s; s++)
229 if (!put_ch(buf, &pos, buflen, *s))
237 if (!put_ch(buf, &pos, buflen,
'/'))
241 if (!put_u32(buf, &pos, buflen, msg->port_id))
245 if (!put_ch(buf, &pos, buflen,
'/'))
249 if (!put_u32(buf, &pos, buflen, msg->src_addr))
257void pc_gateway_get_stats(pc_gateway_stats *out)
266void pc_gateway_test_set_now(uint32_t ms)
Pluggable monotonic clock for all library timing.
uint32_t pc_millis(void)
The library's monotonic time at 1000 Hz (milliseconds).
Radio / wireless gateway bridge (PC_ENABLE_GATEWAY) - the v5 southbound-to- northbound bridge.
#define PC_GW_MAX_PORTS
Max southbound gateway ports (radios / buses; static-allocated).
#define PC_GW_DEFAULT_PREFIX
Default northbound topic prefix (overridable at runtime via pc_gateway_set_topic_prefix).