12#if PC_ENABLE_IFACE_BRIDGE
37 const BridgeRule *rule;
50const BridgeRule *rule_for_slot(uint8_t slot)
52 uint8_t lid = pc_conn_listener_id(slot);
55 if (s_ctx.binds[i].active && s_ctx.binds[i].listener_id == lid)
57 return s_ctx.binds[i].rule;
71HardwareSerial *uart_for(uint8_t unit)
79#if ARDUINO_USB_CDC_ON_BOOT
99void bus_begin(
const BridgeTarget *t)
103 case BridgeBus::uart: {
104 HardwareSerial *s = uart_for(t->unit);
107 s->begin(t->rate ? t->rate : 115200);
112 pinMode(t->addr_cs, OUTPUT);
113 digitalWrite(t->addr_cs, HIGH);
114 if (!s_ctx.spi_begun)
117 s_ctx.spi_begun =
true;
128bool bus_txn(
const BridgeTarget *t,
const uint8_t *wbuf, uint16_t wlen, uint8_t *rbuf, uint16_t rlen)
135 Wire.beginTransmission((uint8_t)t->addr_cs);
136 Wire.write(wbuf, wlen);
138 if (Wire.endTransmission(rlen == 0) != 0)
145 uint16_t got = (uint16_t)Wire.requestFrom((
int)(uint8_t)t->addr_cs, (
int)rlen);
146 for (uint16_t i = 0; i < rlen; i++)
148 rbuf[i] = (i < got && Wire.available()) ? (uint8_t)Wire.read() : 0;
153 case BridgeBus::spi: {
154 uint8_t order = t->bit_order ? LSBFIRST : MSBFIRST;
155 SPI.beginTransaction(SPISettings(t->rate ? t->rate : 1000000, order, t->spi_mode & 0x3));
156 digitalWrite(t->addr_cs, LOW);
157 for (uint16_t i = 0; i < wlen; i++)
159 SPI.transfer(wbuf[i]);
161 for (uint16_t i = 0; i < rlen; i++)
163 rbuf[i] = SPI.transfer(0x00);
165 digitalWrite(t->addr_cs, HIGH);
166 SPI.endTransaction();
170 case BridgeBus::uart: {
171 HardwareSerial *s = uart_for(t->unit);
178 s->write(wbuf, wlen);
182 while (got < rlen && (int32_t)(
pc_millis() - deadline) < 0)
184 while (got < rlen && s->available())
186 rbuf[got++] = (uint8_t)s->read();
189 for (; got < rlen; got++)
200void stream_sock_to_uart(uint8_t slot,
const BridgeTarget *t)
202 HardwareSerial *s = uart_for(t->unit);
209 while ((n = pc_conn_read(slot, buf,
sizeof buf)) > 0)
216void stream_uart_to_sock(uint8_t slot,
const BridgeTarget *t)
218 HardwareSerial *s = uart_for(t->unit);
224 while (s->available() > 0)
227 while (n < sizeof buf && s->available())
229 buf[n++] = (uint8_t)s->read();
231 if (n && pc_conn_active(slot))
240void bus_begin(
const BridgeTarget *)
243bool bus_txn(
const BridgeTarget *,
const uint8_t *, uint16_t, uint8_t *, uint16_t)
247void stream_sock_to_uart(uint8_t,
const BridgeTarget *)
250void stream_uart_to_sock(uint8_t,
const BridgeTarget *)
259void service_txn(uint8_t slot,
const BridgeTarget *t)
265 size_t avail = pc_conn_available(slot);
266 if (avail < PC_BRIDGE_TXN_HDR)
270 uint8_t hdr[PC_BRIDGE_TXN_HDR];
271 pc_conn_peek(slot, 0, hdr, PC_BRIDGE_TXN_HDR);
272 uint16_t wlen = (uint16_t)((hdr[0] << 8) | hdr[1]);
273 uint16_t rlen = (uint16_t)((hdr[2] << 8) | hdr[3]);
279 size_t need = (size_t)PC_BRIDGE_TXN_HDR + wlen;
284 pc_conn_peek(slot, 0, frame, need);
287 const uint8_t *wd =
nullptr;
288 if (pc_iface_bridge_txn_parse(frame, need, &pw, &pr, &wd) != need)
293 pc_conn_consume(slot, need);
294 if (!bus_txn(t, wd, pw, rbuf, pr))
299 if (pr && pc_conn_active(slot))
310void bridge_on_accept(uint8_t slot)
312 if (!rule_for_slot(slot))
318void bridge_on_data(uint8_t slot)
320 const BridgeRule *r = rule_for_slot(slot);
326 if (r->target.mode == BridgeMode::stream)
328 stream_sock_to_uart(slot, &r->target);
332 service_txn(slot, &r->target);
336void bridge_on_poll(uint8_t slot)
338 if (!pc_conn_active(slot))
342 const BridgeRule *r = rule_for_slot(slot);
343 if (!r || r->target.mode != BridgeMode::stream)
347 stream_uart_to_sock(slot, &r->target);
350void bridge_on_close(uint8_t)
356const ProtoHandler s_bridge_handler = {bridge_on_accept, bridge_on_data, bridge_on_close, bridge_on_poll};
360bool pc_iface_bridge_publish(uint8_t listener_id, uint16_t port, BridgeProto proto,
const BridgeTarget *target)
366 if (!pc_iface_bridge_map(
nullptr, port, proto, target))
370 const BridgeRule *rule = pc_iface_bridge_find(port, proto);
378 if (!s_ctx.binds[i].active)
388 s_ctx.binds[idx].active =
true;
389 s_ctx.binds[idx].listener_id = listener_id;
390 s_ctx.binds[idx].rule = rule;
391 bus_begin(&rule->target);
392 if (!s_ctx.registered)
395 s_ctx.registered =
true;
400void pc_iface_bridge_listener_reset(
void)
404 s_ctx.binds[i].active =
false;
406 pc_iface_bridge_clear();
Pluggable monotonic clock for all library timing.
uint32_t pc_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 pc_i2c_begin()
Bring up the shared I2C bus on PC_I2C_SDA_PIN / PC_I2C_SCL_PIN (-1 = default).
ESP32 glue for the interface bridge (PC_ENABLE_IFACE_BRIDGE): the PROTO_BRIDGE listener that wires an...
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).
#define PC_BRIDGE_MAX_RULES
Max concurrent address:port -> bus rules (services/net/iface_bridge).
@ PROTO_BRIDGE
address:port -> hardware bus (PC_ENABLE_IFACE_BRIDGE): UART/SPI/I2C device server.
#define PC_BRIDGE_UART_TXN_MS
UART TRANSACTION read window (ms): how long a write-then-read waits for the read_len reply.
#define PC_BRIDGE_STREAM_CHUNK
STREAM (UART) pipe chunk size (bytes) for services/net/iface_bridge - one socket<->UART hop.
#define PC_BRIDGE_TXN_MAX
Max write / read payload (bytes) per TRANSACTION frame (services/net/iface_bridge).
Per-protocol connection event/poll callbacks (Layer 5 dispatch vtable).
void pc_conn_close(uint8_t slot)
Close connection slot gracefully (tcp_close), aborting if the FIN cannot be queued....
bool pc_conn_send(uint8_t slot, const void *data, u16_t len)
Send len bytes on connection slot (copies data; TLS-aware).
Layer 4 (Transport) - TCP connection pool, ring buffers, and lwIP integration.