在命令模式裏面,我們只需要維護一個命令列表就行了,而不需要關注解析函數本身。
// 當心字節對齊的問題
typedef struct {
uint8_t head;
uint8_t cmd;
uint16_t length;
uint8_t data[1];
} package_t;
static void parse_temperature( uint8_t *buffer )
{
int value = *buffer;
printf( "temperature = %d\n", value );
}
static void parse_humidity( uint8_t *buffer )
{
int value = *buffer;
printf( "humidity = %d\n", value );
}
static void parse_illumination( uint8_t *buffer )
{
int value = *buffer;
printf( "illumination = %d\n", value );
}
typedef struct {
uint8_t cmd;
void ( * handle )( uint8_t *buffer );
} package_entry_t;
static const package_entry_t package_items[] = {
{0x01, parse_temperature},
{0x02, parse_humidity},
{0x03, parse_illumination},
{0xFF, NULL},
};
static uint8_t parse( uint8_t *buffer, uint16_t length )
{
package_t *frame = ( package_t * )buffer;
uint8_t tail = buffer[length - 1];
const package_entry_t *entry;
if ( frame->head != 0xFF ) {
return 0;
}
for ( entry = package_items; entry->handle != NULL; ++entry ) {
if ( frame->cmd == entry->cmd ) {
entry->handle( frame->data );
break;
}
}
return 1;
}
int main( void )
{
uint8_t buffer[] = {0xFF, 0x01, 0x00, 0x05, 0x02};
parse( buffer, 5 );
uint8_t buffer_2[] = {0xFF, 0x02, 0x00, 0x05, 0x02};
parse( buffer_2, 5 );
uint8_t buffer_3[] = {0xFF, 0x03, 0x00, 0x05, 0x02};
parse( buffer_3, 5 );
}
我們可以看到,解析函數寫好之後就不用動了,需要變化的只是一個表。這樣寫能讓代碼看起來乾淨整潔清晰,命令也可以使用宏定義或者枚舉,看自己的喜好吧。一個命令對應一個處理函數,儘量使用此類方式去取代swicth case的方式,始終讓代碼保持整潔易擴展易維護的特性。
上面使用了命令模式作用於串口協議,同樣的方式可以適用於各種協議,網口協議的話,格式都不用改。如果是can協議的話,將can的id用作命令,就ok了。其他的,類似。