stm32f4-uart-bootloader

Simple UART bootloader for STM32F4 MCU's
git clone git://git.mdnr.space/stm32f4-uart-bootloader
Log | Files | Refs | Submodules | README | LICENSE

packet.c (8391B)


      1 #include "packet.h"
      2 #include "app/os.h"
      3 #include "libopencm3/stm32/f4/nvic.h"
      4 #include "shared/protocol.h"
      5 #include "shared/ring-buffer.h"
      6 #include "shared/drv-usart-dma.h"
      7 #include <string.h>
      8 #include "libopencm3/cm3/scb.h"
      9 #include "shared/flash-io.h"
     10 
     11 RingBuffer_t dbgRxRingBuf;
     12 RingBuffer_t dbgTxRingBuf;
     13 RingBuffer_t gsmRxRingBuf;
     14 RingBuffer_t gsmTxRingBuf;
     15 
     16 uint8_t packetBuf[DMA_RX_BUFFER_SIZE] = {0};
     17 
     18 typedef struct {
     19     uint16_t offset;
     20     uint16_t len;
     21     USART_t *usart;
     22 } PacketTxChunk_t;
     23 
     24 const OS_TaskAttr_t packet_rx_taskAttr = {
     25     .function = packet_rx_task,
     26     .name = "packet tx task",
     27     .stackSize = configMINIMAL_STACK_SIZE * 10,
     28     .parameters = NULL,
     29     .priority = 1,
     30 };
     31 TaskHandle_t packet_rx_taskHandle = NULL;
     32 
     33 const OS_TaskAttr_t packet_tx_taskAttr = {
     34     .function = packet_tx_task,
     35     .name = "packet rx task",
     36     .stackSize = configMINIMAL_STACK_SIZE * 10,
     37     .parameters = NULL,
     38     .priority = 1,
     39 };
     40 TaskHandle_t packet_tx_taskHandle = NULL;
     41 
     42 PacketTxChunk_t packet_tx_queueStorageBuf[8];
     43 StaticQueue_t packet_tx_staticQueue;
     44 OS_QueueAttr_t packet_tx_queueAttr = {.length = 8,
     45                                       .itemSize = sizeof(PacketTxChunk_t),
     46                                       .pxStorageBuf = (uint8_t *)packet_tx_queueStorageBuf,
     47                                       .pxQueueBuf = &packet_tx_staticQueue};
     48 QueueHandle_t packet_tx_queueHandle = NULL;
     49 
     50 static bool packetLineFree = true;
     51 
     52 static void packet_send_nack(void) {
     53     uint8_t packet[4] = {PROTOCOL_TAG_NACK, 0, 30, 0};
     54     packet_tx_enqueue_data(comm, packet, sizeof packet);
     55 }
     56 
     57 static void packet_send_ack(void) {
     58     uint8_t packet[4] = {PROTOCOL_TAG_ACK, 0, 152, 3};
     59     packet_tx_enqueue_data(comm, packet, sizeof packet);
     60 }
     61 
     62 
     63 bool packet_usart_line_free(void) { return packetLineFree; }
     64 
     65 static void packet_state_machine(ProtocolPacketAttr_t attr) {
     66     uint8_t response[DMA_RX_BUFFER_SIZE] = {0};
     67     switch (attr.tag) {
     68         case PROTOCOL_TAG_PR: {
     69               if (flash_io_read_params(response + PACK_DATA_INDEX, attr.offset, attr.length) == attr.length) {
     70                   protocol_create_packet(response, PROTOCOL_TAG_ACK, attr.length);
     71                   packet_tx_enqueue_data(comm, response, attr.length + 4);
     72               }
     73               else packet_send_nack();
     74         } break;
     75         case PROTOCOL_TAG_PW: {
     76               vTaskEnterCritical();
     77               if (flash_io_write_params(packetBuf + PACK_DATA_INDEX, attr.offset, attr.length) == attr.length) packet_send_ack();
     78               else packet_send_nack();
     79               vTaskExitCritical();
     80         } break;
     81         case PROTOCOL_TAG_FIR: {
     82               if (flash_io_read_fw_info(response + PACK_DATA_INDEX, attr.offset, attr.length) == attr.length) {
     83                   protocol_create_packet(response, PROTOCOL_TAG_ACK, attr.length);
     84                   packet_tx_enqueue_data(comm, response, attr.length + 4);
     85               }
     86               else packet_send_nack();
     87         } break;
     88         case PROTOCOL_TAG_RST: {
     89             packet_send_ack();
     90             vTaskDelay(100);
     91             scb_reset_core();
     92         } break;
     93         case PROTOCOL_TAG_LOCK: {
     94             packetLineFree = false;
     95             packet_send_ack();
     96         } break;
     97         case PROTOCOL_TAG_UNLOCK: {
     98             packetLineFree = true;
     99             packet_send_ack();
    100         } break;
    101         case PROTOCOL_TAG_DIAG: {
    102             uint8_t diagLength = flash_io_read_diagnostic(response + PACK_DATA_INDEX);
    103             protocol_create_packet(response, PROTOCOL_TAG_ACK, diagLength);
    104             packet_tx_enqueue_data(comm, response, diagLength + 4);
    105         } break;
    106         case PROTOCOL_TAG_ACK: {
    107         } break;
    108         case PROTOCOL_TAG_NACK: {
    109         } break;
    110         default:
    111             packet_send_nack();
    112             break;
    113     }
    114 }
    115 
    116 /* TODO: This can be removed probably
    117  * Find a way to bond ring buffers to dma buffers other than this so 
    118  * that in the packet_tx_enqueue_data function there's no need to
    119  * check the usart port
    120  */
    121 void packet_init(void) {
    122     ring_buffer_setup(&gsmRxRingBuf, gsm.dma.rxBuf, DMA_RX_BUFFER_SIZE);
    123     ring_buffer_setup(&gsmTxRingBuf, gsm.dma.txBuf, DMA_TX_BUFFER_SIZE);
    124     ring_buffer_setup(&dbgRxRingBuf, dbg.dma.rxBuf, DMA_RX_BUFFER_SIZE);
    125     ring_buffer_setup(&dbgTxRingBuf, dbg.dma.txBuf, DMA_TX_BUFFER_SIZE);
    126     usart_enable(gsm.port);
    127     usart_enable(dbg.port);
    128     comm = &dbg; // set serial communication port to dbg (usart1)
    129 }
    130 
    131 void packet_rx_task(void *parameters) {
    132     (void)parameters;
    133     uint16_t len = 0;
    134     for (;;) {
    135         xTaskNotifyWait(0, 0, (uint32_t *)&len, portMAX_DELAY);
    136         osDoggyRegister |= OS_DOGGY_PACKET_T;
    137         if (comm == &dbg) ring_buffer_read_chunk(&dbgRxRingBuf, packetBuf, len);
    138         else ring_buffer_read_chunk(&gsmRxRingBuf, packetBuf, len);
    139         ProtocolPacketAttr_t attr = protocol_extract_packet_attr(packetBuf, false);
    140         if (attr.tag != PROTOCOL_TAG_INVALID) packet_state_machine(attr);
    141         else packet_send_nack();
    142     }
    143 }
    144 
    145 void packet_tx_task(void *parameters) {
    146     PacketTxChunk_t chunk;
    147     uint32_t dummy = 0;
    148     (void)parameters;
    149     for (;;) {
    150         if (xQueuePeek(packet_tx_queueHandle, &chunk, portMAX_DELAY)) {
    151             xTaskNotifyWait(0, 0, &dummy, portMAX_DELAY);
    152             xQueueReceive(packet_tx_queueHandle, &chunk, portMAX_DELAY);
    153             res_usart_dma_write(chunk.usart, chunk.offset, chunk.len);
    154         }
    155     }
    156 }
    157 
    158 void packet_tx_enqueue_data(USART_t *usart, const uint8_t *data, const uint16_t len) {
    159     // write data to tx ring buffer
    160     PacketTxChunk_t chunk;
    161     RingBuffer_t *pBuf = NULL;
    162     if (usart == &gsm) pBuf = &gsmTxRingBuf;
    163     else if (usart == &dbg) pBuf = &dbgTxRingBuf;
    164     chunk.usart = usart;
    165     ring_buffer_write_chunk(pBuf, data, len);
    166     if ((DMA_TX_BUFFER_SIZE - pBuf->head) < len) {
    167         chunk.offset = pBuf->head;
    168         chunk.len = DMA_TX_BUFFER_SIZE - pBuf->head;
    169         xQueueSend(packet_tx_queueHandle, &chunk, 2);
    170         chunk.offset = 0;
    171         chunk.len = len - (DMA_TX_BUFFER_SIZE - pBuf->head);
    172         xQueueSend(packet_tx_queueHandle, &chunk, 2);
    173         pBuf->head = pBuf->tail;
    174         return;
    175     }
    176     chunk.offset = pBuf->head;
    177     chunk.len = len;
    178     pBuf->head = pBuf->tail;
    179     // Enqueue whole chunk for transmit
    180     xQueueSend(packet_tx_queueHandle, &chunk, 2);
    181 }
    182 
    183 void usart2_isr(void) {
    184     uint16_t packetLen = 0;
    185     (void)USART_SR(USART2);
    186     (void)USART_DR(USART2); // This read sequence clears the idle interrupt flag
    187     gsmRxRingBuf.tail = res_usart_dma_get_buffer_tail(&gsm);
    188     packetLen = (DMA_RX_BUFFER_SIZE - 1) & (gsmRxRingBuf.tail - gsmRxRingBuf.head);
    189     comm = &gsm;
    190     BaseType_t xHigherTaskWoken = pdFALSE;
    191     xTaskNotifyFromISR(packet_rx_taskHandle, packetLen, eSetValueWithOverwrite, &xHigherTaskWoken);
    192     osDoggyRegister |= OS_DOGGY_UART_DATA;
    193     portYIELD_FROM_ISR(xHigherTaskWoken);
    194 }
    195 
    196 void usart1_isr(void) {
    197     uint16_t packetLen = 0;
    198     (void)USART_SR(USART1);
    199     (void)USART_DR(USART1); // This read sequence clears the idle interrupt flag
    200     dbgRxRingBuf.tail = res_usart_dma_get_buffer_tail(&dbg);
    201     packetLen = (DMA_RX_BUFFER_SIZE - 1) & (dbgRxRingBuf.tail - dbgRxRingBuf.head);
    202     comm = &dbg;
    203     BaseType_t xHigherTaskWoken = pdFALSE;
    204     xTaskNotifyFromISR(packet_rx_taskHandle, packetLen, eSetValueWithOverwrite, &xHigherTaskWoken);
    205     osDoggyRegister |= OS_DOGGY_UART_DATA;
    206     portYIELD_FROM_ISR(xHigherTaskWoken);
    207 }
    208 
    209 void dma1_stream5_isr(void) {
    210     // TODO: deactivate dma interrupt if nothing is done here
    211     dma_clear_interrupt_flags(DMA1, DMA_STREAM5, DMA_TCIF);
    212 }
    213 
    214 void dma2_stream2_isr(void) {
    215     dma_clear_interrupt_flags(DMA2, DMA_STREAM2, DMA_TCIF);
    216 }
    217 
    218 void dma2_stream7_isr(void) {
    219     uint8_t dummy = 0;
    220     dma_clear_interrupt_flags(DMA2, DMA_STREAM7, DMA_TCIF);
    221     dma_disable_stream(DMA2, DMA_STREAM7);
    222     BaseType_t xHigherTaskWoken = pdFALSE;
    223     xTaskNotifyFromISR(packet_tx_taskHandle, dummy, eSetValueWithOverwrite, &xHigherTaskWoken);
    224     portYIELD_FROM_ISR(xHigherTaskWoken);
    225 }
    226 
    227 void dma1_stream6_isr(void) {
    228     uint8_t dummy = 0;
    229     dma_clear_interrupt_flags(DMA1, DMA_STREAM6, DMA_TCIF);
    230     dma_disable_stream(DMA1, DMA_STREAM6);
    231     BaseType_t xHigherTaskWoken = pdFALSE;
    232     xTaskNotifyFromISR(packet_tx_taskHandle, dummy, eSetValueWithOverwrite, &xHigherTaskWoken);
    233     portYIELD_FROM_ISR(xHigherTaskWoken);
    234 }