12#if DETWS_ENABLE_IFACE_BRIDGE
37 const BridgeRule *rule;
50const BridgeRule *rule_for_slot(uint8_t slot)
52 uint8_t lid = det_conn_listener_id(slot);
54 if (s_ctx.binds[i].active && s_ctx.binds[i].listener_id == lid)
55 return s_ctx.binds[i].rule;
67HardwareSerial *uart_for(uint8_t unit)
88void bus_begin(
const BridgeTarget *t)
92 case BridgeBus::uart: {
93 HardwareSerial *s = uart_for(t->unit);
95 s->begin(t->rate ? t->rate : 115200);
99 pinMode(t->addr_cs, OUTPUT);
100 digitalWrite(t->addr_cs, HIGH);
101 if (!s_ctx.spi_begun)
104 s_ctx.spi_begun =
true;
115bool bus_txn(
const BridgeTarget *t,
const uint8_t *wbuf, uint16_t wlen, uint8_t *rbuf, uint16_t rlen)
122 Wire.beginTransmission((uint8_t)t->addr_cs);
123 Wire.write(wbuf, wlen);
125 if (Wire.endTransmission(rlen == 0) != 0)
130 uint16_t got = (uint16_t)Wire.requestFrom((
int)(uint8_t)t->addr_cs, (
int)rlen);
131 for (uint16_t i = 0; i < rlen; i++)
132 rbuf[i] = (i < got && Wire.available()) ? (uint8_t)Wire.read() : 0;
136 case BridgeBus::spi: {
137 uint8_t order = t->bit_order ? LSBFIRST : MSBFIRST;
138 SPI.beginTransaction(SPISettings(t->rate ? t->rate : 1000000, order, t->spi_mode & 0x3));
139 digitalWrite(t->addr_cs, LOW);
140 for (uint16_t i = 0; i < wlen; i++)
141 SPI.transfer(wbuf[i]);
142 for (uint16_t i = 0; i < rlen; i++)
143 rbuf[i] = SPI.transfer(0x00);
144 digitalWrite(t->addr_cs, HIGH);
145 SPI.endTransaction();
149 case BridgeBus::uart: {
150 HardwareSerial *s = uart_for(t->unit);
154 s->write(wbuf, wlen);
157 while (got < rlen && (int32_t)(
detws_millis() - deadline) < 0)
158 while (got < rlen && s->available())
159 rbuf[got++] = (uint8_t)s->read();
160 for (; got < rlen; got++)
169void stream_sock_to_uart(uint8_t slot,
const BridgeTarget *t)
171 HardwareSerial *s = uart_for(t->unit);
176 while ((n = det_conn_read(slot, buf,
sizeof buf)) > 0)
181void stream_uart_to_sock(uint8_t slot,
const BridgeTarget *t)
183 HardwareSerial *s = uart_for(t->unit);
187 while (s->available() > 0)
190 while (n < sizeof buf && s->available())
191 buf[n++] = (uint8_t)s->read();
192 if (n && det_conn_active(slot))
199void bus_begin(
const BridgeTarget *)
202bool bus_txn(
const BridgeTarget *,
const uint8_t *, uint16_t, uint8_t *, uint16_t)
206void stream_sock_to_uart(uint8_t,
const BridgeTarget *)
209void stream_uart_to_sock(uint8_t,
const BridgeTarget *)
218void service_txn(uint8_t slot,
const BridgeTarget *t)
224 size_t avail = det_conn_available(slot);
225 if (avail < DETWS_BRIDGE_TXN_HDR)
227 uint8_t hdr[DETWS_BRIDGE_TXN_HDR];
228 det_conn_peek(slot, 0, hdr, DETWS_BRIDGE_TXN_HDR);
229 uint16_t wlen = (uint16_t)((hdr[0] << 8) | hdr[1]);
230 uint16_t rlen = (uint16_t)((hdr[2] << 8) | hdr[3]);
236 size_t need = (size_t)DETWS_BRIDGE_TXN_HDR + wlen;
239 det_conn_peek(slot, 0, frame, need);
242 const uint8_t *wd =
nullptr;
243 if (bridge_txn_parse(frame, need, &pw, &pr, &wd) != need)
248 det_conn_consume(slot, need);
249 if (!bus_txn(t, wd, pw, rbuf, pr))
254 if (pr && det_conn_active(slot))
263void bridge_on_accept(uint8_t slot)
265 if (!rule_for_slot(slot))
269void bridge_on_data(uint8_t slot)
271 const BridgeRule *r = rule_for_slot(slot);
277 if (r->target.mode == BridgeMode::stream)
278 stream_sock_to_uart(slot, &r->target);
280 service_txn(slot, &r->target);
283void bridge_on_poll(uint8_t slot)
285 if (!det_conn_active(slot))
287 const BridgeRule *r = rule_for_slot(slot);
288 if (!r || r->target.mode != BridgeMode::stream)
290 stream_uart_to_sock(slot, &r->target);
293void bridge_on_close(uint8_t)
299const ProtoHandler s_bridge_handler = {bridge_on_accept, bridge_on_data, bridge_on_close, bridge_on_poll};
303bool det_bridge_publish(uint8_t listener_id, uint16_t port, BridgeProto proto,
const BridgeTarget *target)
307 if (!bridge_map(
nullptr, port, proto, target))
309 const BridgeRule *rule = bridge_find(port, proto);
314 if (!s_ctx.binds[i].active)
321 s_ctx.binds[idx].active =
true;
322 s_ctx.binds[idx].listener_id = listener_id;
323 s_ctx.binds[idx].rule = rule;
324 bus_begin(&rule->target);
325 if (!s_ctx.registered)
328 s_ctx.registered =
true;
333void det_bridge_listener_reset(
void)
336 s_ctx.binds[i].active =
false;
#define DETWS_BRIDGE_MAX_RULES
Max concurrent address:port -> bus rules (services/iface_bridge).
@ PROTO_BRIDGE
address:port -> hardware bus (DETWS_ENABLE_IFACE_BRIDGE): UART/SPI/I2C device server.
#define DETWS_BRIDGE_UART_TXN_MS
UART TRANSACTION read window (ms): how long a write-then-read waits for the read_len reply.
#define DETWS_BRIDGE_STREAM_CHUNK
STREAM (UART) pipe chunk size (bytes) for services/iface_bridge - one socket<->UART hop.
#define DETWS_BRIDGE_TXN_MAX
Max write / read payload (bytes) per TRANSACTION frame (services/iface_bridge).
Pluggable monotonic clock for all library timing.
uint32_t detws_millis(void)
The library's monotonic time at 1000 Hz (milliseconds).
The one owner of the shared I2C bus bring-up for the peripheral drivers.
void detws_i2c_begin()
Bring up the shared I2C bus on DETWS_I2C_SDA_PIN / DETWS_I2C_SCL_PIN (-1 = default).
ESP32 glue for the interface bridge (DETWS_ENABLE_IFACE_BRIDGE): the PROTO_BRIDGE listener that wires...
Layer 5 (Session) - per-protocol connection handler dispatch table.
void proto_register(ConnProto proto, const ProtoHandler *h)
Register h for protocol proto (replaces any previous handler).
Per-protocol connection event/poll callbacks (Layer 5 dispatch vtable).
bool det_conn_send(uint8_t slot, const void *data, u16_t len)
Send len bytes on connection slot (copies data; TLS-aware).
void det_conn_close(uint8_t slot)
Close connection slot gracefully (tcp_close), aborting if the FIN cannot be queued....
Layer 4 (Transport) - TCP connection pool, ring buffers, and lwIP integration.