XMODEM design and C code implementation (3. Test)

1. Test method and code

  in the last article, we implemented the design of XMODEM communication protocol library through C code. In this article, we will write a test program to test the XMODEM library.
   the test process is realized by PC serial port. The operating system is UBUNTU20 and the compilation tool is GCC. The implementation process is as follows.

1.1. Create XMODEM object

  first, we need to create an XMODEM object

//Define XMODEM objects
static xmodem_t xmodem_obj={
    XMODEM_DATA_128,    //128 byte data is adopted
    XMODEM_CHK_MD_ADD,  //Cumulative sum verification
    XMODEM_REQ_NONE,    //Initialize XMODEM request
    XMODEM_STATE_IDLE,  //Initialize XMODEM state
    80,                 //Wait threshold 80 times
    0,                  //Initialize wait counter
    XMODEM_RX_ST_IDLE,  //Initialize receive idle
    10,                 //Receive retry timeout threshold 10 times
    0,                  //Initialization timeout retry counter
    xmodem_tx,          //Registration sending process
    xmodem_rx,          //Registration receiving process
    xmodem_cb,          //Register callback procedure
    {0},                //Initialize buffer
    0,                  //Current receive length
    0,                  //Initialize frame count
};

1.2. Interface function implementation

    in the object, there are three interface functions, which are "XMODEM"_ tx”,”xmodem_rx”,”xmodem_cb "these three functions.
  where xmodem_tx implements the XMODEM sending function by calling the system code as follows:

//xmodem sending process, configured to serial port
type_err xmodem_tx(type_uint8 *buf, type_uint16 len)
{
    uart_write(uart_fd,(type_char *)buf,len);
    return STATE_OK;
}

  xmodem_rx implements the XMODEM data receiving process, and also calls the system serial port to realize:

//xmodem receiving process, configured to serial port
xmodem_rx_st_t xmodem_rx(type_uint8 *buf, type_uint16 buf_len, type_uint16 *len, type_uint16 timeout)
{
    type_int16 rx_len=0;
    type_uint8 data;
    printf("RECEIVING\n\r");
    //Receive circularly until one frame of data is full
    while(rx_len<buf_len)
    {
        //Receive in blocking mode, receive one byte at a time, and return timeout if timeout
        if(uart_read(uart_fd,(type_char *)&data,1)<=0)
        {
            printf("RX TIMEOUT\n\r");
            return XMODEM_RX_ST_TIMEOUT;
        }
        //If EOT is received, it will directly return to reception completion
        else if((0x04==data)&&(0==rx_len))
        {
            buf[rx_len]=data;
            rx_len++;
            *len=rx_len;
            printf("NEW PACKAGE,EOT\n\r");
            return XMODEM_RX_ST_OK;
        }
        //receive data 
        else
        {
            buf[rx_len]=data;
            rx_len++;
        }
    }
    //When one frame is received, return to reception completion
    *len=rx_len;
    printf("NEW PACKAGE,id=%d\n\r",buf[1]);
    return XMODEM_RX_ST_OK;
}

   it should be noted that there are several problems to pay attention to when initializing the serial port in LINUX:
1. Receive in blocking mode
   when calling the open function, do not add non blocking parameters. The initialization code is as follows:

type_int32 uart_open(type_char *port)
{
    type_int32 fd=-1;
    return open(port,O_RDWR|O_NOCTTY);
}

2. Solve the abnormal display problems of 0x0A,0x0D,0x11,0x13, etc
  mask the following flag bits in the configuration parameters:

options.c_iflag &= ~ (INLCR | ICRNL | IGNCR);
options.c_oflag &= ~ (ONLCR | OCRNL | IXOFF);
options.c_iflag &= ~ (BRKINT | ICRNL | INPCK | ISTRIP | IXON);

3. Set timeout time and data receiving length
   the Linux serial port controls the received data length and timeout time by configuring the following two parameters:

//Set the waiting time and minimum received characters
options.c_cc[VTIME] = 40; /* Read a character and wait 1*(1/10)s */
options.c_cc[VMIN] = 0;

   where VTIME is the timeout time, with 100ms as the unit, VMIN is the minimum received data length. The code above indicates that if there is received data, the data will be returned. If the data has been received, the timeout will be returned after 4 seconds.

  xmodem_ The CB function realizes the data processing process received by the upper layer on XMODEM. In this test process, the received data is printed through the terminal.

//Upper receiving function
void xmodem_cb(type_uint8 *buf, type_uint16 len)
{
    type_uint16 pos=0;
    //If an empty buffer is passed, an error is displayed
    if(!buf)
    {
        printf("XMODEM ERR!\n\r");
        return;
    }
    //If the buffer is valid and the length is 0, the reception is completed
    if((buf)&&(0==len))
    {
        printf("XMODEM FINISH!\n\r");
        return;
    }
    //Print received data
    printf("===============================================\n\r");
    printf("00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15\n\r");
    printf("===============================================\n\r");
    while(pos<len)
    {
        for(type_uint8 i=0;i<16;i++)
        {
            if(i==15)
                printf("%02x",buf[pos++]);
            else
                printf("%02x,",buf[pos++]);
            if(pos>=len)
            {
                printf("\n\r");
                return;
            }
        }
        printf("\n\r");
    }
}

1.3. Test main function implementation

   test the main function. Test XMODEM by using multithreading. The main process is used to obtain user keyboard input, so as to control the operation of the current XMODEM state machine. Create a thread for the XMODEM system call. The code is as follows:

void main()
{
    int key;
    type_char lf=0x0A;
    //Open the serial port, and fill in here according to the actual situation
    uart_fd=uart_open("/dev/ttyUSB0");
    if(0>uart_fd)
    {
        printf("UART OPEN ERR!\n\r");
        return;
    }
    //Serial port configuration
    if(uart_set(uart_fd,UART_BAUD_115200,UART_FLOWCTRL_NONE,8,1,UART_PARITY_NONE)!=STATE_OK)
    {
        printf("UART CFG ERR!\n\r");
        uart_close(uart_fd);
        return;
    }
    //Initialize xmodem object
    xmodem_init(&xmodem_obj);
    //Create xmodem processing thread
    pthread_create(&ntid, NULL, xmodem_pth, NULL);
    printf("************************************\n\r");
    printf("Press X to start XMODEM transmission\n\r");
    printf("Press S to stop XMODEM transmission\n\r");
    printf("Press E to exit\n\r");
    printf("************************************\n\r");
    while(1)
    {
        //Get keys
        key=getch();
        switch(key)
        {
            case 'X':
            case 'x':
                //Request to start xmodem transfer
                printf("XMODEM START REQ\n\r");
                tcflush(uart_fd,TCIFLUSH);
                xmodem_req(&xmodem_obj,XMODEM_REQ_START);
                break;
            case 'S':
            case 's':
                //Request to end xmodem transmission
                printf("XMODEM STOP REQ\n\r");
                xmodem_req(&xmodem_obj,XMODEM_REQ_STOP);
                break;
            case 'E':
            case 'e':
                uart_close(uart_fd);
                exit(0);
            default:
                break;
        }
    }
}

   after the system runs, first initialize UART and XMODEM. See the driver in the project for the initialization code. A thread is then created for the XMODEM system to run. After creating the thread, print the control information, and finally carry out the control loop.

2. Compilation and operation

   open the terminal window, switch to the project directory, and enter the make command to compile. If normal, the following information will appear:

Continue typing. / bin/xmodem_sim runs the newly compiled program and the following interface will be displayed

3. Test

  before the test, you need to prepare an xmodem transmission tool. Because the cutecom software under linux is not very stable, Tera Term is recommended here. And two USB to serial port boards.
   first, insert two U-to-series interface boards into the computer, one for transmitting and one for receiving. It is worth noting that TX and RX need to be connected in exchange, as shown in the figure:

Then, open Tera Term, select serial port, configure the baud rate to 115200, and click New setting


Return to the terminal and press the x key. At this time, XMODEM test program enters the receiving mode

   go back to Tera Term, select File - > transfer - > XMODEM - > send, then select the file to be transferred, and click open. The interface is as follows:

Then, XMODEM starts transmission, as shown in the figure:

After the transmission is completed, you will be prompted that the reception is complete

4. End

So far, XMODEM design, coding and testing have been completed, and the relevant codes can be obtained at the following address
Project code download

https://gitee.com/ekd/XMODEM.git

Tags: C IDE ARM MCU

Posted on Sun, 26 Sep 2021 00:07:57 -0400 by uniflare