16#if DETWS_ENABLE_GATEWAY
30 uint32_t window_start;
44 det_gw_uplink_fn uplink =
nullptr;
45 void *uplink_ctx =
nullptr;
68port *find_port(GatewayCtx &g, uint8_t
id)
71 if (g.ports[i].used && g.ports[i].id ==
id)
77bool rate_exceeded(port *p)
81 uint32_t now = gw_now();
82 if ((uint32_t)(now - p->window_start) >= 1000)
84 p->window_start = now;
87 if (p->count >= p->rate_cap)
93bool put_ch(
char *buf, uint16_t *pos, uint16_t cap,
char c)
95 if ((uint16_t)(*pos + 1) >= cap)
101bool put_u32(
char *buf, uint16_t *pos, uint16_t cap, uint32_t v)
109 tmp[n++] = (char)(
'0' + (v % 10));
113 if (!put_ch(buf, pos, cap, tmp[--n]))
119void det_gw_reset(
void)
121 memset(s_gw.ports, 0,
sizeof(s_gw.ports));
122 s_gw.uplink =
nullptr;
123 s_gw.uplink_ctx =
nullptr;
126 memset(&s_gw.stats, 0,
sizeof(s_gw.stats));
129bool det_gw_add_port(
const det_gw_port_config *cfg)
131 if (!cfg || find_port(s_gw, cfg->port_id))
135 if (s_gw.ports[i].used)
137 s_gw.ports[i].tx = cfg->tx;
138 s_gw.ports[i].ctx = cfg->ctx;
139 s_gw.ports[i].window_start = 0;
140 s_gw.ports[i].rate_cap = cfg->rate_cap;
141 s_gw.ports[i].count = 0;
142 s_gw.ports[i].id = cfg->port_id;
143 s_gw.ports[i].kind = cfg->kind;
144 s_gw.ports[i].used =
true;
150void det_gw_set_uplink(det_gw_uplink_fn fn,
void *ctx)
153 s_gw.uplink_ctx = ctx;
156void det_gw_set_topic_prefix(
const char *prefix)
161bool det_gw_uplink(uint8_t port_id, uint16_t src_addr,
const uint8_t *payload, uint16_t len, int16_t rssi)
164 port *p = find_port(s_gw, port_id);
165 if (!p || !s_gw.uplink || rate_exceeded(p))
167 s_gw.stats.up_dropped++;
171 msg.payload = payload;
172 msg.seq = s_gw.seq++;
174 msg.src_addr = src_addr;
176 msg.port_id = port_id;
178 if (s_gw.uplink(&msg, s_gw.uplink_ctx))
180 s_gw.stats.up_published++;
183 s_gw.stats.up_dropped++;
187bool det_gw_downlink(uint8_t port_id, uint16_t dst_addr,
const uint8_t *payload, uint16_t len)
189 s_gw.stats.down_in++;
190 port *p = find_port(s_gw, port_id);
191 if (!p || !p->tx || !p->tx(port_id, dst_addr, payload, len, p->ctx))
193 s_gw.stats.down_dropped++;
196 s_gw.stats.down_sent++;
200uint16_t det_gw_topic(
const det_gw_msg *msg,
char *buf, uint16_t buflen)
202 if (!msg || !buf || buflen == 0)
205 for (
const char *s = s_gw.prefix; *s; s++)
206 if (!put_ch(buf, &pos, buflen, *s))
211 if (!put_ch(buf, &pos, buflen,
'/'))
213 if (!put_u32(buf, &pos, buflen, msg->port_id))
215 if (!put_ch(buf, &pos, buflen,
'/'))
217 if (!put_u32(buf, &pos, buflen, msg->src_addr))
223void det_gw_get_stats(det_gw_stats *out)
230void det_gw_test_set_now(uint32_t ms)
#define DETWS_GW_MAX_PORTS
Max southbound gateway ports (radios / buses; static-allocated).
#define DETWS_GW_DEFAULT_PREFIX
Default northbound topic prefix (overridable at runtime via det_gw_set_topic_prefix).
Pluggable monotonic clock for all library timing.
uint32_t detws_millis(void)
The library's monotonic time at 1000 Hz (milliseconds).
Radio / wireless gateway bridge (DETWS_ENABLE_GATEWAY) - the v5 southbound-to- northbound bridge.