如何验证附加了两位十六进制校验和的 ASCII 字符串



我正在使用带有HEW(高性能嵌入式工作台)编译器的瑞萨16 bt MCU。

系统接收以下形式的ACSII数据:

<data><cc>

其中<cc>包括两个 ASCII 十六进制数字,对应于前面所有字符的 8 位按位 XOR。包括<cc>的字符串的最大长度为 14。

这是我的尝试:

#pragma INTERRUPT Interrupt_Rx0
void Interrupt_Rx0 (void)
{
    unsigned char   rx_byte, rx_status_byte,hex;
    char buffer[15],test[5];
    int r,k[15];
    char * pEnd;
    unsigned char dat,arr[14],P3;
    unsigned int i,P1[10];
    rx_byte = u0rbl;    //get rx data
    rx_status_byte = u0rbh;
    if ((rx_status_byte & 0x80) == 0x00)        //if no error
    {
        if ((bf_rx0_start == 0) && (rx_byte == '?') && (bf_rx0_ready == 0))
        {

            byte_rx0_buffer[0]=rx_byte;
            bf_rx0_start = 1;                                    
            byte_rx0_ptr = 1;       
        }
        else
        {
            if (rx_byte == '?')
            {
                bf_rx0_start = 1;
                byte_rx0_ptr = 0;
            }
            if(bf_rx0_start == 1)
            {
                byte_rx0_buffer[byte_rx0_ptr++] = rx_byte;          
                sprintf(buffer,"%X",rx_byte); //ASCII CONVERSION
                dat=strtol(buffer,&pEnd,16);
                //  P1=(int)dat;
                //  sprintf(P1,"%s",dat);
                delay_ms(2000);
                k[byte_rx0_ptr++]=dat;  
            }                       
            if ((byte_rx0_ptr == 14))               
                bf_rx0_start = 0;//end further rx until detect new STX
        }
    }
}   

将此值转换为十六进制值和xor it,即(3F^30^31^53^52^57=68),如果我可以在程序中进行此计算

您从根本上不了解值和编码之间的区别。二加三等于五,无论您将两者表示为"2"、"二"还是"X X"。加法作用于,而不是表示。因此,"转换为十六进制和xor它"是没有意义的。您是异或,而不是表示。十六进制是一种表示形式。

要保持正在运行的 XOR,只需在顶部执行类似 int running_xor=0; 的操作,然后在每次收到字节时running_xor ^= rx_byte;。完成后,它将包含正确的值。将其设置为零以重置它。

完全摆脱十六进制。这就是打印这些值以供您使用的方式。这与程序的内部逻辑无关,程序只处理值。

您最好将数据验证与数据接收分开,即使您不在中断处理程序中执行此操作; 如果您使用的是 RTOS,则最好在未选中的情况下缓冲 ISR 中的数据,并将数据验证推迟到主代码线程或任务线程。 你当然不想在 ISR 中调用重量级的库函数,如 sprintf() 或 strtol()!

无论哪种方式,这里都有一个函数,它将获取指向已接收字符串及其长度的指针(以避免不必要的strlen()调用,因为您已经知道接收了多少个字符),并在校验和验证时返回true,否则false。 它对数据长度没有限制 - 这将由调用函数执行。

如果您知道校验和十六进制数字将始终为大写或小写,则可以简化decodeHexNibble()函数。

#include <stdint.h>
#include <stdbool.h>
uint8_t decodeHexNibble() ;
uint8_t decodeHexByte( char* hexbyte ) ;
uint8_t decodeHexNibble( char hexdigit ) ;
bool checkData( char* data, int length )
{
    int data_len = length - 2 ;
    char* bcc_ptr = &data[data_len] ;
    uint8_t rx_bcc_val = 0 ;
    uint8_t actual_bcc_val = 0 ;
    int i = 0 ;
    // Convert <cc> string to integer
    rx_bcc_val = decodeHexByte( bcc_ptr ) ;
    // Calculate XOR of <data>
    for( i = 0; i < data_len; i++ )
    {
        actual_bcc_val ^= data[i] ;
    }
    return actual_bcc_val == rx_bcc_val  ;
}
uint8_t decodeHexNibble( char hexdigit )
{
    uint8_t nibble ;
    if( hexdigit >= '0' && hexdigit <= '9' )
    {
        nibble = hexdigit - '0' ;
    }
    else if( hexdigit >= 'a' && hexdigit <= 'f' )
    {
        nibble = hexdigit - 'a' + 10 ;
    }
    else if( hexdigit >= 'A' && hexdigit <= 'F' )
    {
        nibble = hexdigit - 'A' + 10 ;
    }
    else
    {
        // Do something 'sensible' with invalid digits
        nibble = 0 ;
    }
    return nibble ;
}
uint8_t decodeHexByte( char* hexbyte )
{
    uint8_t byte = hexbyte[0] << 4 ;
    byte |= hexbyte[1] ;
    return byte ;
}

最新更新