2026年5月3日 星期日

無中斷的直譯器及Xmodem

 在main.c中加入一個工作

  extern PT_THREAD(ui(struct pt *pt));
  add_task(0, ui);
  while (1)
  {
    scheduler();
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

將bdg_parser.c也放入

/*
 * dbg_parser.c
 *
 *  Created on: 2023年2月8日
 *      Author: wallace
 */
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "pt.h"
#include "coroutine.h"

/* Forward declaration — defined later in this file */
static void Uart2TransmitDMA(unsigned char *src, int size);
static int Get_Uart2Value(unsigned char *Value);

/*
    return  0:Failed, 1:Successful
    str : Pointer to pointer to the string
    res : Pointer to the valiable to store the value */
int xatoi(char **str, long *res)
{
    unsigned long val;
    unsigned char c, r, s = 0;

    *res = 0;

    while ((c = **str) == ' ')
        (*str)++; /* Skip leading spaces */

    if (c == '-')
    { /* negative? */
        s = 1;
        c = *(++(*str));
    }

    if (c == '0')
    {
        c = *(++(*str));
        switch (c)
        {
        case 'x': /* hexdecimal */
            r = 16;
            c = *(++(*str));
            break;
        case 'b': /* binary */
            r = 2;
            c = *(++(*str));
            break;
        default:
            if (c <= ' ')
                return 1; /* single zero */
            if (c < '0' || c > '9')
                return 0; /* invalid char */
            r = 8;        /* octal */
        }
    }
    else
    {
        if (c < '0' || c > '9')
            return 0; /* EOL or invalid char */
        r = 10;       /* decimal */
    }

    val = 0;
    while (c > ' ')
    {
        if (c >= 'a')
            c -= 0x20;
        c -= '0';
        if (c >= 17)
        {
            c -= 7;
            if (c <= 9)
                return 0; /* invalid char */
        }
        if (c >= r)
            return 0; /* invalid char for current radix */
        val = val * r + c;
        c = *(++(*str));
    }
    if (s)
        val = 0 - val; /* apply sign if needed */

    *res = val;
    return 1;
}

// Moved from ui.c
#define PT_DBG_PARSER 0
#define PT_DBG_TX 1
#define PT_DBG_RX 2
#define PT_MODEM 3

unsigned char Line[128];
int sLength = 0;

char *p_ptr;
const char console_ready[] = ">";
long p[5];
#define p1 p[0]
#define p2 p[1]
#define p3 p[2]
#define p4 p[3]
#define p5 p[4]
struct timer tx_timer;
int i, j, k;
unsigned char *pc;
int count;
struct pt pt_temp[16];

#define TX_BUF_SIZE (256U)
static uint8_t tx_buffer[TX_BUF_SIZE];  /* DMA staging buffer — used only inside tx_output */
static uint8_t fmt_buffer[TX_BUF_SIZE]; /* format buffer for callers */
static const uint8_t *tx_src;           /* source data pointer */
static uint16_t tx_total;               /* total bytes to send */

/* ---- Xmodem transport interface ----------------------------------------- */
typedef struct
{
    int (*get_byte)(uint8_t *dst);                      /* non-blocking: 1=got byte, 0=empty */
    void (*flush_rx)(void);                             /* discard buffered RX */
    void (*start_tx)(const uint8_t *buf, uint16_t len); /* initiate (possibly async) TX */
    int (*tx_idle)(void);                               /* 1 = TX hardware fully done */
} xmodem_io_t;

static const xmodem_io_t *xmodem_io; /* assigned before spawning xmodem_rx / xmodem_tx */
// static struct timer tx_output_timer;

static PT_THREAD(tx_output(struct pt *pt))
{
    static uint16_t offset;
    static uint16_t chunk;
    PT_BEGIN(pt);
    offset = 0;
    while (offset < tx_total)
    {
        chunk = tx_total - offset;
        if (chunk > TX_BUF_SIZE)
            chunk = (uint16_t)TX_BUF_SIZE;
        memcpy(tx_buffer, tx_src + offset, chunk);
        Uart2TransmitDMA(tx_buffer, chunk);
#if 1
        PT_YIELD(pt);
#else
        timer_set(&tx_output_timer, 1);
        PT_WAIT_UNTIL(pt, timer_expired(&tx_output_timer));
#endif
        PT_WAIT_UNTIL(pt, !LL_DMA_IsEnabledStream(DMA1, LL_DMA_STREAM_6));
        PT_WAIT_UNTIL(pt, LL_USART_IsActiveFlag_TC(USART2));
        offset += chunk;
    }
    PT_END(pt);
}

/* ---- xmodem_send: chunked TX through the xmodem_io vtable --------------- */
static PT_THREAD(xmodem_send(struct pt *pt))
{
    static uint16_t offset;
    static uint16_t chunk;
    PT_BEGIN(pt);
    offset = 0;
    while (offset < tx_total)
    {
        chunk = tx_total - offset;
        if (chunk > TX_BUF_SIZE)
            chunk = (uint16_t)TX_BUF_SIZE;
        memcpy(tx_buffer, tx_src + offset, chunk);
        xmodem_io->start_tx(tx_buffer, chunk);
        PT_WAIT_UNTIL(pt, xmodem_io->tx_idle());
        offset += chunk;
    }
    PT_END(pt);
}

/* ---- rx_byte: wait for one byte with timeout -----------------------------
 * Set rx_byte_dst and rx_byte_timeout before spawning.
 * After the spawn, rx_byte_ok == 1 means a byte was stored; 0 means timeout. */
static uint8_t *rx_byte_dst;
static uint16_t rx_byte_timeout;
static uint8_t rx_byte_ok;
static struct timer rx_byte_timer;

static PT_THREAD(rx_byte(struct pt *pt))
{
    PT_BEGIN(pt);
    timer_set(&rx_byte_timer, rx_byte_timeout);
    PT_WAIT_UNTIL(pt, xmodem_io->get_byte(rx_byte_dst) || timer_expired(&rx_byte_timer));
    rx_byte_ok = (uint8_t)(!timer_expired(&rx_byte_timer));
    PT_END(pt);
}

/* ---- UART2 RX: circular DMA (DMA1 Stream 5, Channel 4) ------------------ */
#define UART2_RX_DMA_BUF_SIZE 128
static unsigned char RxBuffer[UART2_RX_DMA_BUF_SIZE];
static unsigned short uart2_rx_tail = 0;

void EnableUart2Receive(void)
{
    LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_5, (uint32_t)RxBuffer);
    LL_DMA_SetPeriphAddress(DMA1, LL_DMA_STREAM_5, (uint32_t)&USART2->DR);
    LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_5, UART2_RX_DMA_BUF_SIZE);
    LL_USART_EnableDMAReq_RX(USART2);
    LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_5);
}

void Reset_Uart2Buffer(void)
{
    uart2_rx_tail = (unsigned short)(UART2_RX_DMA_BUF_SIZE -
                                     LL_DMA_GetDataLength(DMA1, LL_DMA_STREAM_5)) &
                    (UART2_RX_DMA_BUF_SIZE - 1);
}

static int Get_Uart2Value(unsigned char *Value)
{
    unsigned short head = (unsigned short)(UART2_RX_DMA_BUF_SIZE -
                                           LL_DMA_GetDataLength(DMA1, LL_DMA_STREAM_5)) &
                          (UART2_RX_DMA_BUF_SIZE - 1);
    if (head == uart2_rx_tail)
        return 0;
    *Value = RxBuffer[uart2_rx_tail];
    uart2_rx_tail = (uart2_rx_tail + 1u) & (UART2_RX_DMA_BUF_SIZE - 1);
    return -1;
}

/* ---- UART2 TX: normal DMA (DMA1 Stream 6, Channel 4) -------------------- */
static void Uart2TransmitDMA(unsigned char *src, int size)
{
    /* Ensure previous DMA transfer is complete */
    while (LL_DMA_IsEnabledStream(DMA1, LL_DMA_STREAM_6))
        ;

    LL_DMA_ClearFlag_TC6(DMA1);
    LL_DMA_ClearFlag_HT6(DMA1);
    LL_DMA_ClearFlag_TE6(DMA1);
    LL_USART_ClearFlag_TC(USART2); /* clear stale TC before new transfer */

    LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_6, (uint32_t)src);
    LL_DMA_SetPeriphAddress(DMA1, LL_DMA_STREAM_6, (uint32_t)&USART2->DR);
    LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_6, (uint32_t)size);
    LL_USART_EnableDMAReq_TX(USART2);
    LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_6);
}

/* ---- UART2 xmodem transport implementation ------------------------------ */
static int xio_uart2_get_byte(uint8_t *dst) { return Get_Uart2Value(dst); }
static void xio_uart2_flush_rx(void) { Reset_Uart2Buffer(); }
static void xio_uart2_start_tx(const uint8_t *buf, uint16_t len) { Uart2TransmitDMA((unsigned char *)buf, (int)len); }
static int xio_uart2_tx_idle(void)
{
    return !LL_DMA_IsEnabledStream(DMA1, LL_DMA_STREAM_6) &&
           LL_USART_IsActiveFlag_TC(USART2);
}
const xmodem_io_t xmodem_io_uart2 = {
    xio_uart2_get_byte,
    xio_uart2_flush_rx,
    xio_uart2_start_tx,
    xio_uart2_tx_idle,
};

PT_THREAD(ui(struct pt *pt))
{
    static unsigned char *ptrLine;
    static unsigned char c;

    PT_BEGIN(pt);

    Reset_Uart2Buffer();
    EnableUart2Receive();

    Line[0] = 0;
    ptrLine = &Line[0];

    while (!Idle_enable)
    {
        if (Get_Uart2Value(&c))
        {
            if ('\n' == c)
            {
                // skip
            }
            else if ('\r' == c)
            {
                extern PT_THREAD(dbg_parser(struct pt * pt));
                *ptrLine = 0;
                sLength = (int)(ptrLine - &Line[0]);
                ptrLine = &Line[0];
                PT_SPAWN(pt, &pt_temp[PT_DBG_PARSER], dbg_parser(&pt_temp[PT_DBG_PARSER]));
            }
            else if ('\b' == c)
            {
                if (ptrLine > &Line[0])
                    ptrLine--;
            }
            else
            {
                *ptrLine++ = c;
            }
        }
        else
        {
            PT_YIELD(pt);
        }
    }

    PT_END(pt);
}

#define XMODEM_SOH (0x01)
#define XMODEM_STX (0x02)
#define XMODEM_EOT (0x04)
#define XMODEM_ACK (0x06)
#define XMODEM_NAK (0x15)
#define XMODEM_CAN (0x18)

static uint8_t *xmodem_dst;
static uint32_t xmodem_max;
static uint32_t xmodem_received;
static uint32_t xmodem_stored;
static int xmodem_overflow;
static int xmodem_result;

static const uint8_t *xmodem_src;
static uint32_t xmodem_size;
static uint32_t xmodem_sent;
static int xmodem_tx_result;

static uint16_t xmodem_crc16_update(uint16_t crc, uint8_t data)
{
    crc ^= (uint16_t)data << 8;
    for (uint8_t i = 0; i < 8; i++)
    {
        if (crc & 0x8000)
            crc = (crc << 1) ^ 0x1021;
        else
            crc <<= 1;
    }
    return crc;
}

static PT_THREAD(xmodem_rx(struct pt *pt))
{
    static uint8_t c;
    static uint8_t blk;
    static uint8_t blk_inv;
    static uint8_t d; /* data/CRC byte — static so it survives yields */
    static uint16_t crc_calc;
    static uint16_t crc_recv;
    static uint16_t i;
    static uint16_t block_size;
    static uint8_t expected_blk;
    static uint8_t retries;

    PT_BEGIN(pt);

    xmodem_io->flush_rx(); /* discard any stale RX bytes before handshake */
    xmodem_received = 0;
    xmodem_stored = 0;
    xmodem_overflow = 0;
    xmodem_result = -1;
    expected_blk = 1;
    retries = 0;

    /* Handshake: send 'C' until the sender responds */
    while (1)
    {
        fmt_buffer[0] = 'C';
        tx_src = fmt_buffer;
        tx_total = 1;
        PT_SPAWN(pt, &pt_temp[PT_DBG_TX], xmodem_send(&pt_temp[PT_DBG_TX]));

        rx_byte_dst = &c;
        rx_byte_timeout = 1000;
        PT_SPAWN(pt, &pt_temp[PT_DBG_RX], rx_byte(&pt_temp[PT_DBG_RX]));
        if (rx_byte_ok)
            goto xmodem_got_first;

        if (++retries >= 30)
        {
            xmodem_result = -2; // timeout
            PT_EXIT(pt);
        }
    }

xmodem_got_first:
    retries = 0;

    while (1)
    {
        if (c == XMODEM_EOT)
        {
            fmt_buffer[0] = XMODEM_ACK;
            tx_src = fmt_buffer;
            tx_total = 1;
            PT_SPAWN(pt, &pt_temp[PT_DBG_TX], xmodem_send(&pt_temp[PT_DBG_TX]));
            xmodem_result = 0;
            PT_EXIT(pt);
        }
        if (c == XMODEM_CAN)
        {
            xmodem_result = -3; // canceled by sender
            PT_EXIT(pt);
        }

        if (c != XMODEM_SOH && c != XMODEM_STX)
        {
            /* Ignore stray byte — wait for the next one */
            rx_byte_dst = &c;
            rx_byte_timeout = 1000;
            PT_SPAWN(pt, &pt_temp[PT_DBG_RX], rx_byte(&pt_temp[PT_DBG_RX]));
            continue;
        }

        block_size = (c == XMODEM_SOH) ? 128 : 1024;

        /* Block number */
        rx_byte_dst = &blk;
        rx_byte_timeout = 1000;
        PT_SPAWN(pt, &pt_temp[PT_DBG_RX], rx_byte(&pt_temp[PT_DBG_RX]));
        if (!rx_byte_ok)
            goto xmodem_nak;

        /* Block number inverse */
        rx_byte_dst = &blk_inv;
        rx_byte_timeout = 1000;
        PT_SPAWN(pt, &pt_temp[PT_DBG_RX], rx_byte(&pt_temp[PT_DBG_RX]));
        if (!rx_byte_ok)
            goto xmodem_nak;

        if ((uint8_t)(blk + blk_inv) != 0xFF)
            goto xmodem_nak;

        /* Data bytes */
        crc_calc = 0;
        for (i = 0; i < block_size; i++)
        {
            rx_byte_dst = &d;
            rx_byte_timeout = 1000;
            PT_SPAWN(pt, &pt_temp[PT_DBG_RX], rx_byte(&pt_temp[PT_DBG_RX]));
            if (!rx_byte_ok)
                goto xmodem_nak;

            crc_calc = xmodem_crc16_update(crc_calc, d);
            if (xmodem_stored < xmodem_max)
                xmodem_dst[xmodem_stored++] = d;
            else
                xmodem_overflow = 1;
            xmodem_received++;
        }

        /* CRC16 high byte */
        rx_byte_dst = &d;
        rx_byte_timeout = 1000;
        PT_SPAWN(pt, &pt_temp[PT_DBG_RX], rx_byte(&pt_temp[PT_DBG_RX]));
        if (!rx_byte_ok)
            goto xmodem_nak;
        crc_recv = (uint16_t)d << 8;

        /* CRC16 low byte */
        rx_byte_dst = &d;
        rx_byte_timeout = 1000;
        PT_SPAWN(pt, &pt_temp[PT_DBG_RX], rx_byte(&pt_temp[PT_DBG_RX]));
        if (!rx_byte_ok)
            goto xmodem_nak;
        crc_recv |= d;

        if (crc_recv != crc_calc)
            goto xmodem_nak;

        /* Accept expected block, or ACK a duplicate */
        if (blk == expected_blk)
        {
            expected_blk++;
            retries = 0;
            fmt_buffer[0] = XMODEM_ACK;
            tx_src = fmt_buffer;
            tx_total = 1;
            PT_SPAWN(pt, &pt_temp[PT_DBG_TX], xmodem_send(&pt_temp[PT_DBG_TX]));
        }
        else if (blk == (uint8_t)(expected_blk - 1))
        {
            retries = 0;
            fmt_buffer[0] = XMODEM_ACK;
            tx_src = fmt_buffer;
            tx_total = 1;
            PT_SPAWN(pt, &pt_temp[PT_DBG_TX], xmodem_send(&pt_temp[PT_DBG_TX]));
        }
        else
        {
            goto xmodem_nak;
        }

        /* Wait for the next block's SOH/STX */
        rx_byte_dst = &c;
        rx_byte_timeout = 3000;
        PT_SPAWN(pt, &pt_temp[PT_DBG_RX], rx_byte(&pt_temp[PT_DBG_RX]));
        if (!rx_byte_ok)
        {
            /* Prompt sender to retransmit */
            fmt_buffer[0] = XMODEM_NAK;
            tx_src = fmt_buffer;
            tx_total = 1;
            PT_SPAWN(pt, &pt_temp[PT_DBG_TX], xmodem_send(&pt_temp[PT_DBG_TX]));
        }
        continue;

    xmodem_nak:
        if (++retries >= 10)
        {
            fmt_buffer[0] = XMODEM_CAN;
            tx_src = fmt_buffer;
            tx_total = 1;
            PT_SPAWN(pt, &pt_temp[PT_DBG_TX], xmodem_send(&pt_temp[PT_DBG_TX]));
            PT_SPAWN(pt, &pt_temp[PT_DBG_TX], xmodem_send(&pt_temp[PT_DBG_TX]));
            xmodem_result = -4; // too many errors
            PT_EXIT(pt);
        }
        fmt_buffer[0] = XMODEM_NAK;
        tx_src = fmt_buffer;
        tx_total = 1;
        PT_SPAWN(pt, &pt_temp[PT_DBG_TX], xmodem_send(&pt_temp[PT_DBG_TX]));

        /* Flush any stray bytes, then loop to top */
        rx_byte_dst = &c;
        rx_byte_timeout = 3000;
        PT_SPAWN(pt, &pt_temp[PT_DBG_RX], rx_byte(&pt_temp[PT_DBG_RX]));
    }

    PT_END(pt);
}

static PT_THREAD(xmodem_tx(struct pt *pt))
{
    static uint8_t c;
    static uint8_t blk;
    static uint8_t retries;
    static uint16_t crc;
    static uint16_t i;
    static uint8_t pkt[3 + 128 + 2];
    static uint32_t offset;

    PT_BEGIN(pt);

    xmodem_sent = 0;
    xmodem_tx_result = -1;

    /* Wait for receiver 'C' (CRC mode) or NAK */
    retries = 0;
    while (1)
    {
        rx_byte_dst = &c;
        rx_byte_timeout = 1000;
        PT_SPAWN(pt, &pt_temp[PT_DBG_RX], rx_byte(&pt_temp[PT_DBG_RX]));
        if (rx_byte_ok)
            goto xmodem_tx_got_first;

        if (++retries >= 30)
        {
            xmodem_tx_result = -2; // timeout
            PT_EXIT(pt);
        }
    }

xmodem_tx_got_first:
    if (!(c == 'C' || c == XMODEM_NAK))
    {
        if (c == XMODEM_CAN)
        {
            xmodem_tx_result = -3;
            PT_EXIT(pt);
        }
        // ignore stray bytes and keep waiting
        PT_RESTART(pt);
    }

    blk = 1;
    offset = 0;

    while (offset < xmodem_size)
    {
        // Build 128-byte block
        pkt[0] = XMODEM_SOH;
        pkt[1] = blk;
        pkt[2] = (uint8_t)(0xFF - blk);

        crc = 0;
        for (i = 0; i < 128; i++)
        {
            uint8_t d = 0x1A; // CPM EOF padding
            if ((offset + i) < xmodem_size)
                d = xmodem_src[offset + i];
            pkt[3 + i] = d;
            crc = xmodem_crc16_update(crc, d);
        }
        pkt[3 + 128] = (uint8_t)(crc >> 8);
        pkt[3 + 128 + 1] = (uint8_t)(crc & 0xFF);

        retries = 0;
        while (1)
        {
            // Send packet directly from pkt (no copy needed)
            tx_src = pkt;
            tx_total = sizeof(pkt);
            PT_SPAWN(pt, &pt_temp[PT_DBG_TX], xmodem_send(&pt_temp[PT_DBG_TX]));

            // Wait for ACK/NAK
            rx_byte_dst = &c;
            rx_byte_timeout = 10000;
            PT_SPAWN(pt, &pt_temp[PT_DBG_RX], rx_byte(&pt_temp[PT_DBG_RX]));
            if (!rx_byte_ok)
                c = XMODEM_NAK;

            if (c == XMODEM_ACK)
                break;
            if (c == XMODEM_CAN)
            {
                xmodem_tx_result = -3;
                PT_EXIT(pt);
            }

            if (++retries >= 10)
            {
                // Abort
                fmt_buffer[0] = XMODEM_CAN;
                tx_src = fmt_buffer;
                tx_total = 1;
                PT_SPAWN(pt, &pt_temp[PT_DBG_TX], xmodem_send(&pt_temp[PT_DBG_TX]));
                PT_SPAWN(pt, &pt_temp[PT_DBG_TX], xmodem_send(&pt_temp[PT_DBG_TX]));
                xmodem_tx_result = -4;
                PT_EXIT(pt);
            }
        }

        offset += 128;
        xmodem_sent = (offset > xmodem_size) ? xmodem_size : offset;
        blk++;
    }

    // Send EOT until ACK
    retries = 0;
    while (1)
    {
        fmt_buffer[0] = XMODEM_EOT;
        tx_src = fmt_buffer;
        tx_total = 1;
        PT_SPAWN(pt, &pt_temp[PT_DBG_TX], xmodem_send(&pt_temp[PT_DBG_TX]));

        rx_byte_dst = &c;
        rx_byte_timeout = 10000;
        PT_SPAWN(pt, &pt_temp[PT_DBG_RX], rx_byte(&pt_temp[PT_DBG_RX]));
        if (rx_byte_ok && c == XMODEM_ACK)
        {
            xmodem_tx_result = 0;
            PT_EXIT(pt);
        }

        if (++retries >= 10)
        {
            xmodem_tx_result = -5;
            PT_EXIT(pt);
        }
    }

    PT_END(pt);
}

struct timer dbg_timer;

PT_THREAD(dbg_parser(struct pt *pt))
{
    PT_BEGIN(pt);
    //    timer_set(&dbg_timer, 10);
    //    PT_WAIT_UNTIL(pt, timer_expired(&dbg_timer));
    p_ptr = (char *)&Line[0];
    switch (*p_ptr++)
    {
    case '?': // ? -- Show information
        tx_total = (uint16_t)snprintf((char *)fmt_buffer, TX_BUF_SIZE,
                                      "Build: %s %s\r\n"
                                      "Commands: ? | md/mf/mw/mr | xs <addr> [max] | xr <addr> <size>\r\n",
                                      __DATE__, __TIME__);
        tx_src = fmt_buffer;
        PT_SPAWN(pt, &pt_temp[PT_DBG_TX], tx_output(&pt_temp[PT_DBG_TX]));
        break; // end ?
    case 'm':  // m?
        switch (*p_ptr++)
        {
        case 'd': // md <addr> <count> -- memory dump
            if (!xatoi(&p_ptr, &p1))
                break;
            if (!xatoi(&p_ptr, &p2))
                p2 = 0x80;
            do
            {
                pc = (unsigned char *)p1;
                count = (int)p2;
                k = 0;
                while (k < count)
                {
                    tx_total = (uint16_t)snprintf((char *)fmt_buffer, TX_BUF_SIZE, "%08lX ", (long unsigned int)pc);
                    for (i = 0; i < 16; i++)
                    {
                        j = snprintf((char *)&fmt_buffer[tx_total], TX_BUF_SIZE - tx_total, " %02X", pc[i]);
                        tx_total = (uint16_t)(tx_total + j);
                    }
                    fmt_buffer[tx_total++] = ' ';
                    for (i = 0; i < 16; i++)
                        fmt_buffer[tx_total++] = (unsigned char)((pc[i] >= ' ' && pc[i] <= '~') ? pc[i] : '.');
                    fmt_buffer[tx_total++] = '\r';
                    fmt_buffer[tx_total++] = '\n';
                    tx_src = fmt_buffer;
                    PT_SPAWN(pt, &pt_temp[PT_DBG_TX], tx_output(&pt_temp[PT_DBG_TX]));
                    k += 0x10;
                    pc += 0x10;
                }
            } while (0);
            break;
        case 'f': // mf [addr] [value] [size] -- fill memory
            if (!xatoi(&p_ptr, &p1))
                break;
            if (!xatoi(&p_ptr, &p2))
                break;
            if (!xatoi(&p_ptr, &p3))
                break;
            do
            {
                int i;
                uint8_t *tp = (uint8_t *)p1;
                uint8_t val = p2;
                for (i = 0; i < p3; i++)
                    *tp++ = val;
                tx_total = (uint16_t)snprintf((char *)fmt_buffer, TX_BUF_SIZE, "Fill memory.\r\n");
                tx_src = fmt_buffer;
                PT_SPAWN(pt, &pt_temp[PT_DBG_TX], tx_output(&pt_temp[PT_DBG_TX]));
            } while (0);
            break;
        case 'w': // mw <address> <count> [data] - memory write
            if (!xatoi(&p_ptr, &p1))
                break;
            if (!xatoi(&p_ptr, &p2))
                p2 = 0;
            do
            {
                unsigned char *ptemp;
                ptemp = (unsigned char *)p1;
                while (p2)
                {
                    if (!xatoi(&p_ptr, &p3))
                        break;
                    *ptemp++ = p3;
                    p2--;
                };
                tx_total = (uint16_t)snprintf((char *)fmt_buffer, TX_BUF_SIZE, "Write memory.\r\n");
                tx_src = fmt_buffer;
                PT_SPAWN(pt, &pt_temp[PT_DBG_TX], tx_output(&pt_temp[PT_DBG_TX]));
            } while (0);
            break;
        case 's': // ms <tick> - delay ticks
            if (!xatoi(&p_ptr, &p1))
                break;
            do
            {
                timer_set(&dbg_timer, p1);
                PT_WAIT_UNTIL(pt, timer_expired(&dbg_timer));
                tx_total = (uint16_t)snprintf((char *)fmt_buffer, TX_BUF_SIZE, "Delay %lu ticks.\r\n", (unsigned long)p1);
                tx_src = fmt_buffer;
                PT_SPAWN(pt, &pt_temp[PT_DBG_TX], tx_output(&pt_temp[PT_DBG_TX]));
            } while (0);
            break;
        case 'r': // mr -- nvic reset
            tx_total = (uint16_t)snprintf((char *)fmt_buffer, TX_BUF_SIZE, "NVIC Reset!\r\n");
            tx_src = fmt_buffer;
            PT_SPAWN(pt, &pt_temp[PT_DBG_TX], tx_output(&pt_temp[PT_DBG_TX]));
            NVIC_SystemReset();
            break;
        }
        break; // end m?
    case 'x':  // x
        switch (*p_ptr++)
        {
        case 'r': // xr <addr> [max] -- XMODEM receive to memory (CRC)
            if (!xatoi(&p_ptr, &p1))
                break;
            if (!xatoi(&p_ptr, &p2))
                p2 = 0x1000;

            xmodem_dst = (uint8_t *)p1;
            xmodem_max = (uint32_t)p2;

            tx_total = (uint16_t)snprintf((char *)fmt_buffer, TX_BUF_SIZE, "XMODEM RX: start (CRC), dst=%08lX max=%lu\r\n", (unsigned long)p1, (unsigned long)p2);
            tx_src = fmt_buffer;
            PT_SPAWN(pt, &pt_temp[PT_DBG_TX], tx_output(&pt_temp[PT_DBG_TX]));

            xmodem_io = &xmodem_io_uart2;
            PT_SPAWN(pt, &pt_temp[PT_MODEM], xmodem_rx(&pt_temp[PT_MODEM]));

            if (xmodem_result == 0 && !xmodem_overflow)
                tx_total = (uint16_t)snprintf((char *)fmt_buffer, TX_BUF_SIZE, "XMODEM RX OK: stored=%lu bytes\r\n", (unsigned long)xmodem_stored);
            else if (xmodem_result == 0 && xmodem_overflow)
                tx_total = (uint16_t)snprintf((char *)fmt_buffer, TX_BUF_SIZE, "XMODEM RX OK (truncated): stored=%lu max=%lu total=%lu\r\n", (unsigned long)xmodem_stored, (unsigned long)xmodem_max, (unsigned long)xmodem_received);
            else
                tx_total = (uint16_t)snprintf((char *)fmt_buffer, TX_BUF_SIZE, "XMODEM RX FAIL: err=%d stored=%lu total=%lu\r\n", xmodem_result, (unsigned long)xmodem_stored, (unsigned long)xmodem_received);
            tx_src = fmt_buffer;

            PT_SPAWN(pt, &pt_temp[PT_DBG_TX], tx_output(&pt_temp[PT_DBG_TX]));
            break;
        case 's': // xs <addr> <size> -- XMODEM send from memory
            if (!xatoi(&p_ptr, &p1))
                break;
            if (!xatoi(&p_ptr, &p2))
                break;

            xmodem_src = (const uint8_t *)p1;
            xmodem_size = (uint32_t)p2;

            tx_total = (uint16_t)snprintf((char *)fmt_buffer, TX_BUF_SIZE, "XMODEM TX: receiver start now (CRC), src=%08lX size=%lu\r\n", (unsigned long)p1, (unsigned long)p2);
            tx_src = fmt_buffer;
            PT_SPAWN(pt, &pt_temp[PT_DBG_TX], tx_output(&pt_temp[PT_DBG_TX]));

            xmodem_io = &xmodem_io_uart2;
            PT_SPAWN(pt, &pt_temp[PT_MODEM], xmodem_tx(&pt_temp[PT_MODEM]));

            if (xmodem_tx_result == 0)
                tx_total = (uint16_t)snprintf((char *)fmt_buffer, TX_BUF_SIZE, "XMODEM TX OK: sent=%lu bytes\r\n", (unsigned long)xmodem_sent);
            else
                tx_total = (uint16_t)snprintf((char *)fmt_buffer, TX_BUF_SIZE, "XMODEM TX FAIL: err=%d sent=%lu\r\n", xmodem_tx_result, (unsigned long)xmodem_sent);
            tx_src = fmt_buffer;

            PT_SPAWN(pt, &pt_temp[PT_DBG_TX], tx_output(&pt_temp[PT_DBG_TX]));
            break;
        case '?': // x? -- show xmodem usage
            tx_total = (uint16_t)snprintf((char *)fmt_buffer, TX_BUF_SIZE, "XMODEM Commands:\r\nxr <addr> [max] -- receive to memory (CRC)\r\nxs <addr> <size> -- send from memory\r\n");
            tx_src = fmt_buffer;
            PT_SPAWN(pt, &pt_temp[PT_DBG_TX], tx_output(&pt_temp[PT_DBG_TX]));
            break;
        }
        break; // x
    }
    fmt_buffer[0] = '>';
    tx_src = fmt_buffer;
    tx_total = 1;
    PT_SPAWN(pt, &pt_temp[PT_DBG_TX], tx_output(&pt_temp[PT_DBG_TX]));
    PT_END(pt);
}

它是使用FatFs作者的命令器為主,再加上一個ui工作。

然後就叫AI寫xmodem收發,用LL函式庫。主要是測試能不能用,有沒有問題。

就完成一個不使用中斷的直譯器,以及大量資料傳輸的簡單架構。

沒有留言:

張貼留言