static void show_packet(byte *pkt, uint len)
{
- if (len == 1) {
- printf("Received status %u\n", pkt[0]);
+ if (!len) {
+ printf("ERROR: Received empty frame!\n");
+ return;
+ }
+
+ byte status = *pkt++;
+ len--;
+
+ if (!len) {
+ printf("Transmit status: %u\n", status);
return;
}
#if 1
- printf(":");
+ printf(": [%d]", status);
for (uint i=0; i<len; i++)
printf(" %02x", pkt[i]);
putchar('\n');
#endif
- printf("%02x -> %02x: ", pkt[1] ^ 0x80, pkt[2]);
+ printf("%02x -> %02x: ", pkt[BF_SRC] ^ 0x80, pkt[BF_DEST]);
+ if (status)
+ printf("[REPLY] ");
switch (pkt[4]) {
case 2:
printf("INFO %04x:%04x =", (pkt[5]<<8) | pkt[6], (pkt[7]<<8) | pkt[8]);
}
if (last_query + 10 < now) {
- byte pkt[] = { 0xdc, 0xc2, 0x00, 0x0b, 0x06, 0x3d, 0x2e, 0x11, 0x25 };
+ byte pkt[] = { 0xdc, 0xc2, 0x00, 0x0b, 0x06, 0x3d, 0x2e, 0x11, 0x25, 0x00, 0x00 };
if (err = libusb_bulk_transfer(devh, 0x01, pkt, sizeof(pkt), &received, 2000)) {
printf("Send failed: error %d\n", err);
// usb_error("Receive failed: error %d", received);
/*** BSB ***/
#define BSB_MAX_SIZE 32
-#define BSB_RX_TIMEOUT 10 // ms
-#define BSB_TX_IDLE_LINE 100 // ms
+#define BSB_RX_TIMEOUT 10 // If no byte was received for this time, end the current frame [ms]
+#define BSB_TX_IDLE_LINE 100 // Consider the line idle if no byte was received for this time [ms]
#define BSB_TX_MAX_ATTEMPTS 3
-#define BSB_TX_WAIT_LOG 10 // base 2 log of timeout in ms
-#define BSB_TX_TIMEOUT 10000 // ms
+#define BSB_TX_WAIT_LOG 8 // base 2 log of pre-frame waiting time in ms
+#define BSB_TX_TIMEOUT 10000 // Total time to transmit a frame including all retries and waiting for reply [ms]
+#define BSB_REPLY_TIMEOUT 1000 // How long to wait for a reply [ms]
#define DEBUG_BSB
#ifdef DEBUG_BSB
byte tx_result; // TX_RESULT_xxx
u32 tx_start_timestamp;
u32 tx_ticks_to_send;
+ u32 tx_end_timestamp;
+ u32 reply_type_mask; // Expected reply types (0=no reply)
byte rx_buf[BSB_MAX_SIZE];
byte tx_buf[BSB_MAX_SIZE];
static struct bsb_state bsb;
// Passing received frames and status codes to the main loop
-static byte bsb_rx_frame[BSB_MAX_SIZE];
+static byte bsb_rx_status_and_frame[1 + BSB_MAX_SIZE];
static volatile byte bsb_rx_frame_len;
static byte bsb_tx_result;
TX_STATE_WAITING_FOR_IDLE_LINE,
TX_STATE_PRE_PACKET_DELAY,
TX_STATE_SENDING,
- TX_STATE_DONE,
+ TX_STATE_SENT,
+ TX_STATE_WAITING_FOR_REPLY,
TX_STATE_COLLISION,
};
} else if (ch == bsb.tx_buf[bsb.tx_check_index++]) {
if (bsb.tx_check_index >= bsb.tx_len) {
BSB_DEBUG('d');
- bsb.tx_state = TX_STATE_DONE;
+ bsb.tx_state = TX_STATE_SENT;
}
} else {
BSB_DEBUG('c');
// First three bytes: SOF, source addr, destination addr
} else if (bsb.rx_len == 4) {
// Received length byte
- if (bsb.rx_buf[3] < 7 || bsb.rx_buf[3] > BSB_MAX_SIZE) {
+ if (bsb.rx_buf[BF_LEN] < 7 || bsb.rx_buf[BF_LEN] > BSB_MAX_SIZE) {
bsb_stats.rx_invalid++;
bsb.rx_len = 0;
BSB_DEBUG('L');
}
- } else if (bsb.rx_len == bsb.rx_buf[3]) {
+ } else if (bsb.rx_len == bsb.rx_buf[BF_LEN]) {
// Received a complete frame: check CRC and pass it to the main loop
if (bsb.rx_crc) {
bsb_stats.rx_bad_crc++;
bsb_stats.rx_overruns++;
BSB_DEBUG('O');
} else {
- memcpy(bsb_rx_frame, bsb.rx_buf, bsb.rx_buf[3]);
- bsb_rx_frame_len = bsb.rx_buf[3] - 2;
+ bsb_rx_frame_len = bsb.rx_buf[BF_LEN];
+ memcpy(bsb_rx_status_and_frame + 1, bsb.rx_buf, bsb_rx_frame_len);
bsb_stats.rx_ok++;
BSB_DEBUG('.');
+ // Will match with expected replies in main loop
}
gpio_clear(GPIOB, GPIO1);
bsb.rx_led = 100;
bsb_stats.tx_collisions++;
bsb_attempt_tx();
return;
- case TX_STATE_DONE:
- bsb_stats.tx_ok++;
- bsb.tx_state = TX_STATE_OFF;
- bsb_tx_result = TX_RESULT_OK;
+ case TX_STATE_SENT:
+ if (!bsb.reply_type_mask) {
+ // The frame needs no reply => confirm transmission
+ bsb_stats.tx_ok_no_reply++;
+ bsb.tx_state = TX_STATE_OFF;
+ bsb_tx_result = TX_RESULT_OK;
+ } else {
+ bsb.tx_state = TX_STATE_WAITING_FOR_REPLY;
+ bsb.tx_end_timestamp = ms_ticks;
+ BSB_DEBUG('w');
+ }
+ return;
+ case TX_STATE_WAITING_FOR_REPLY:
+ if (ms_ticks - bsb.tx_end_timestamp > BSB_REPLY_TIMEOUT) {
+ // We did not receive a reply. Maybe the request was lost? Re-transmit it.
+ bsb_stats.tx_reply_timeouts++;
+ BSB_DEBUG('t');
+ bsb_attempt_tx();
+ }
return;
default:
;
static void bsb_attempt_tx(void)
{
if (bsb.tx_attempts++ >= BSB_TX_MAX_ATTEMPTS) {
- bsb_tx_result = TX_RESULT_TOO_MANY_RETRIES;
bsb.tx_state = TX_STATE_OFF;
+ bsb_tx_result = TX_RESULT_TOO_MANY_RETRIES;
return;
}
}
// Check frame validity
- if (len < 5 || len > BSB_MAX_SIZE - 2 || buf[0] != 0xdc || buf[3] != len + 2) {
+ if (len < 7 || len > BSB_MAX_SIZE || buf[BF_SOF] != 0xdc || buf[BF_LEN] != len) {
bsb_stats.tx_rejects++;
bsb_tx_result = TX_RESULT_MALFORMED;
return;
}
- // So far, we allow only QUERY frames from address 42
- if (buf[1] != 0x80 + 42 && buf[4] != 0x06) {
+ // Detect frame type and prepare expected reply types
+ if (buf[BF_OP] == BSB_OP_QUERY) {
+ // So far, we allow only QUERY frames
+ bsb.reply_type_mask = (1 << BSB_OP_ANSWER) | (1 << BSB_OP_ERROR);
+ } else {
bsb_stats.tx_rejects++;
bsb_tx_result = TX_RESULT_FORBIDDEN;
return;
}
- // Copy frame and calculate CRC
+ // Fill in source address
+ buf[BF_SRC] = 0x80 + BSB_ADDR_GATEWAY;
+
+ // Calculate CRC
u16 crc = 0;
- for (uint i=0; i<len; i++) {
- bsb.tx_buf[i] = buf[i];
+ for (uint i = 0; i < len - 2; i++)
crc = bsb_crc_update(crc, buf[i]);
- }
- bsb.tx_buf[len++] = crc >> 8;
- bsb.tx_buf[len++] = crc;
- debug_printf("TX: Prepared frame of %u bytes with CRC %04x\n", len, crc);
+ buf[len-2] = crc >> 8;
+ buf[len-1] = crc;
+ debug_printf("TX: Prepared frame: type=%02x dest=%02x len=%u crc=%04x reply=%08x\n", buf[BF_OP], buf[BF_DEST], len, crc, (uint) bsb.reply_type_mask);
// Queue frame for transmission
+ memcpy(bsb.tx_buf, buf, len);
bsb.tx_len = len;
bsb.tx_start_timestamp = ms_ticks;
bsb.tx_attempts = 0;
gpio_clear(GPIOB, GPIO0);
}
+static void bsb_check_reply(void)
+{
+ // Match received frame in bsb_rx_status_and_frame to expected replies
+ // and set the status byte in byte 0.
+
+ byte *frame = bsb_rx_status_and_frame + 1;
+ // XXX: This might be executed too fast, so we can still be in TX_STATE_SENT
+ if (bsb.tx_state == TX_STATE_WAITING_FOR_REPLY || bsb.tx_state == TX_STATE_SENT) {
+ if (frame[BF_DEST] == BSB_ADDR_GATEWAY &&
+ frame[BF_SRC] == bsb.tx_buf[BF_DEST] ^ 0x80 &&
+ frame[BF_OP] < 32 &&
+ bsb.reply_type_mask & (1 << frame[BF_OP])) {
+ debug_printf("BSB: Matched reply\n");
+ bsb.tx_state = TX_STATE_OFF;
+ bsb_stats.tx_ok_replied++;
+ bsb_rx_status_and_frame[0] = TX_RESULT_OK;
+ gpio_set(GPIOB, GPIO0); // Turn the TX LED off
+ return;
+ }
+ }
+
+ bsb_rx_status_and_frame[0] = TX_RESULT_NONE;
+}
+
static void bsb_init(void)
{
usart_set_baudrate(USART3, 4800);
// Passing of received frames to USB
if (!usb_ep82_pending) {
if (bsb_rx_frame_len) {
+ // Received frame, possibly marked as reply
barrier();
- usbd_ep_write_packet(usbd_dev, 0x82, bsb_rx_frame, bsb_rx_frame_len);
+ bsb_check_reply();
+ usbd_ep_write_packet(usbd_dev, 0x82, bsb_rx_status_and_frame, 1 + bsb_rx_frame_len);
usb_ep82_pending = 1;
barrier();
bsb_rx_frame_len = 0;
debug_printf("USB: Sending frame to interrupt EP\n");
- }
- if (bsb_tx_result != TX_RESULT_NONE) {
+ } else if (bsb_tx_result != TX_RESULT_NONE) {
+ // Only a transmission result
usbd_ep_write_packet(usbd_dev, 0x82, &bsb_tx_result, 1);
usb_ep82_pending = 1;
gpio_set(GPIOB, GPIO0); // Turn the TX LED off