#include "lib.h" #ifdef BRIDGEQ struct srv_state { SRV_COMMON; uint8_t enabled; uint8_t pin_cs, pin_txrq; uint8_t rx_size, shift, skip_one; queue_t rx_q; uint32_t next_send; jd_frame_t spi_rx; }; REG_DEFINITION( // bridge_regs, // REG_SRV_BASE, // REG_U8(JD_REG_INTENSITY), // ) void jd_send_low(jd_frame_t *f); static srv_t *_state; static void spi_done_handler(void) { srv_t *state = _state; unsigned frmsz = JD_FRAME_SIZE(&state->spi_rx); if (state->spi_rx.size == 0xFE) { // m:b didn't manage to read the packet; try again state->rx_size = 0; pin_set(state->pin_cs, 1); pwr_leave_tim(); state->next_send = now; tim_max_sleep = 100; return; } if (frmsz > state->rx_size && state->spi_rx.size != 0xFF) { // we didn't read enough uint8_t *d = (uint8_t *)&state->spi_rx + state->rx_size; unsigned left = frmsz - state->rx_size; state->rx_size = frmsz; dspi_xfer(NULL, d, left, spi_done_handler); } else { state->rx_size = 0; pin_set(state->pin_cs, 1); pwr_leave_tim(); if (state->shift) queue_shift(state->rx_q); if (4 <= state->spi_rx.size && state->spi_rx.size <= 240) { if (state->spi_rx.flags & JD_FRAME_FLAG_LOOPBACK) { jd_packet_t *pkt = (jd_packet_t *)&state->spi_rx; if (pkt->service_number == 0) switch (pkt->service_command) { case 0xf0: ns_set(pkt->device_identifier, (const char *)pkt->data); break; case 0xf1: ns_clear(); break; } } } else { jd_send_low(&state->spi_rx); // also process packets ourselves - m:b might be talking to us jd_services_process_frame(&state->spi_rx); } } state->next_send = now + 99; tim_max_sleep = 100; } static void xchg(srv_t *state) { if (state->rx_size) return; if (in_future(state->next_send)) { tim_max_sleep = 100; return; } if (state->skip_one) { state->skip_one = 0; return; } // tim_max_sleep = 0; // TODO work on power consumption jd_frame_t *fwd = queue_front(state->rx_q); int size = 32; if (fwd && JD_FRAME_SIZE(fwd) > size) size = JD_FRAME_SIZE(fwd); state->rx_size = size; state->shift = !!fwd; pin_set(state->pin_cs, 0); pwr_enter_tim(); *(uint32_t *)&state->spi_rx = 0; dspi_xfer(fwd, &state->spi_rx, size, spi_done_handler); } void bridge_forward_frame(jd_frame_t *frame) { if (frame != &_state->spi_rx) { // for announce packets jd_packet_t *pkt = (jd_packet_t *)frame; if (pkt->service_command == JD_SERVICE_NUMBER_CONTROL && pkt->service_number == JD_CONTROL_CMD_SERVICES && !(frame->flags & JD_FRAME_FLAG_COMMAND)) { // we check if we have name for the source device const char *name = ns_get(pkt->device_identifier); if (name) { unsigned namelen = strlen(name); unsigned len = (namelen + 4 + 3) & ~3; // and if it will fit in frame if (frame->size + len < JD_SERIAL_PAYLOAD_SIZE + 4) { // we shift everything forward uint32_t *src = (uint32_t *)(frame->data + frame->size - 4); uint32_t *dst = src + (len >> 2); while (src >= (uint32_t *)frame->data) *dst-- = *src--; // and add the name at the beginning pkt->service_command = JD_GET(JD_REG_CTRL_SELF_NAME); pkt->service_size = namelen; memcpy(pkt->data, name, namelen); frame->size += len; } } } queue_push(_state->rx_q, frame); } } void bridge_process(srv_t *state) { if (queue_front(state->rx_q) || (!in_future(state->next_send) && pin_get(state->pin_txrq) == 0)) xchg(state); } void bridge_handle_packet(srv_t *state, jd_packet_t *pkt) { service_handle_register(state, pkt, bridge_regs); } SRV_DEF(bridge, JD_SERVICE_CLASS_BRIDGE); void bridge_init(uint8_t pin_cs, uint8_t pin_txrq) { SRV_ALLOC(bridge); ns_init(); dspi_init(); state->pin_cs = pin_cs; pin_set(pin_cs, 1); pin_setup_output(pin_cs); state->pin_txrq = pin_txrq; pin_setup_input(pin_txrq, 1); state->rx_q = queue_alloc(512); _state = state; } // alternative tx_Q impl. static queue_t tx_q; static bool isSending; int jd_tx_is_idle() { return !isSending && queue_front(tx_q) == NULL; } void jd_tx_init(void) { tx_q = queue_alloc(512); } void jd_send_low(jd_frame_t *f) { jd_compute_crc(f); queue_push(tx_q, f); jd_packet_ready(); } int jd_send(unsigned service_num, unsigned service_cmd, const void *data, unsigned service_size) { if (service_size > 32) jd_panic(); uint32_t buf[(service_size + 16 + 3) / 4]; jd_frame_t *f = (jd_frame_t *)buf; jd_reset_frame(f); void *trg = jd_push_in_frame(f, service_num, service_cmd, service_size); memcpy(trg, data, service_size); f->device_identifier = jd_device_id(); jd_send_low(f); if (_state) { queue_push(_state->rx_q, f); // also forward packets we generate ourselves _state->skip_one = 1; } return 0; } void jd_send_event_ext(srv_t *srv, uint32_t eventid, uint32_t arg) { srv_common_t *state = (srv_common_t *)srv; if (eventid >> 16) jd_panic(); uint32_t data[] = {eventid, arg}; jd_send(state->service_number, JD_CMD_EVENT, data, 8); } // bridge between phys and queue imp, phys calls this to get the next frame. jd_frame_t *jd_tx_get_frame(void) { jd_frame_t *f = queue_front(tx_q); if (f) isSending = true; return f; } // bridge between phys and queue imp, marks as sent. void jd_tx_frame_sent(jd_frame_t *pkt) { isSending = false; queue_shift(tx_q); if (queue_front(tx_q)) jd_packet_ready(); // there's more to do } void jd_tx_flush() { // do nothing } #endif