• C 面向对象编程 --- 一模块的串口协议解析


    // 任务目的
    // 解析串口收到的54个字节。这54个字节包含了8个车道的5大信息以及校验信息。
    // 实现了查询每条车道包含了哪些信息。

    #include <stdio.h>
    #include <malloc.h>
    #include <assert.h>
    
    typedef unsigned char mybool; 
    typedef unsigned char u8; 
    typedef unsigned short u16; 
    typedef unsigned int u32;
    
    mybool SumCheck(const u8* pScrData);
    
    typedef enum{
    RoadID1=1, // 距离雷达最远的那条车道, 一个绿化带也算一条车道。
    RoadID2,
    RoadID3,
    RoadID4,
    RoadID5,
    RoadID6,
    RoadID7,
    RoadID8,
    RoadIDNull
    }RoadID_;
    
    
    typedef enum{    
    T_LongCarCnt=1,
    T_CarCnt, 
    T_SmallCarCnt,
    T_Occupancy,
    T_AveSpeed,
    T_AskNull
    }T_ask_;
    
    
    struct CertainRoad_; // 下面定义函数指针时,形参有这个结构体的指针, 所以,这里的结构体一定要先声明。
    
    typedef struct CertainRoad_{
    RoadID_ RoadID;
    
    // 成员函数的使用方法示例: pRoad->pGetUpdated_LongCarCnt(pRoad, FakeData); 
    // 第一个pRoad是CertainRoad类的一个对象的指针,作用不言而喻。 
    // 第二个pRoad起到类似this指针的作用。目的是可供调用对象的其他成员(对象的其他属性或者行为。)
    // C++的类内的成员函数的定义内可以直接使用this指针,但是C语言不支持这样,所以要通过形参再次传入对象指针。
    
    //u8(*pGetUpdated_LongCarCnt) ( struct CertainRoad_ *pRoad,  const u8 *pScrData);         // 所以说,形参命名为pRoad,还不能体现是和C++映衬的最佳的理解。
    
    u8(*pGetUpdated_LongCarCnt) ( struct CertainRoad_ *this,                  const u8 *pScrData); // 第二个参数是54字节的数据哦 
    u8(*pGetUpdated_CarCnt) ( struct CertainRoad_ *this,                          const u8 *pScrData);
    u8(*pGetUpdated_SmallCarCnt)( struct CertainRoad_ *this,                  const u8 *pScrData);
    u8(*pGetUpdated_Occupancy) ( struct CertainRoad_ *this,                   const u8 *pScrData);
    u8(*pGetUpdated_AveSpeed) ( struct CertainRoad_ *this,                    const u8 *pScrData);
    
    void(*pGetUpdatedAllresults)( struct CertainRoad_ *this,      const u8 *pScrData, u8 *result);
    
    }CertainRoad; // Certain是某的意思。CertainRoad:某条车道。
    
    
    // 根据车道号获取该时间段内的长车的流量
    // 规律:长车的流量 = pScrData[pRoad->RoadID+2];
    u8 GetUpdated_LongCarCnt(CertainRoad* pRoad, const u8* pScrData)
    {
    if( !(pRoad->RoadID >= RoadID1)&&(pRoad->RoadID <= RoadID8) )
    assert(0);
    return pScrData[pRoad->RoadID+2];
    }
    
    u8 GetUpdated_CarCnt(CertainRoad* pRoad, const u8* pScrData)
    {
    if( !(pRoad->RoadID >= RoadID1)&&(pRoad->RoadID <= RoadID8) )
    assert(0);
    return pScrData[pRoad->RoadID+15];
    }
    
    u8 GetUpdated_SmallCarCnt(CertainRoad* pRoad, const u8* pScrData)
    {
    if( !(pRoad->RoadID >= RoadID1)&&(pRoad->RoadID <= RoadID8) )
    assert(0);
    return GetUpdated_CarCnt(pRoad,pScrData) - GetUpdated_LongCarCnt(pRoad, pScrData);
    }
    
    u8 GetUpdated_Occupancy(CertainRoad* pRoad, const u8* pScrData)
    {
    if( !(pRoad->RoadID >= RoadID1)&&(pRoad->RoadID <= RoadID8) )
    assert(0);
    return pScrData[pRoad->RoadID+28];
    }
    
    u8 GetUpdated_AveSpeed(CertainRoad* pRoad, const u8* pScrData)
    {
    if( !(pRoad->RoadID >= RoadID1)&&(pRoad->RoadID <= RoadID8) )
    assert(0);
    return pScrData[pRoad->RoadID+41];
    }
    
    void GetUpdatedAllresults(CertainRoad* pRoad, const u8* pScrData, u8* result)
    {
    if( !(pRoad->RoadID >= RoadID1)&&(pRoad->RoadID <= RoadID8) )
    assert(0);
    
    result[0] = pRoad->pGetUpdated_LongCarCnt (pRoad, pScrData); 
    result[1] = pRoad->pGetUpdated_CarCnt (pRoad, pScrData); 
    result[2] = pRoad->pGetUpdated_SmallCarCnt(pRoad, pScrData); 
    result[3] = pRoad->pGetUpdated_Occupancy (pRoad, pScrData); 
    result[4] = pRoad->pGetUpdated_AveSpeed (pRoad, pScrData); 
    }
    
    
    CertainRoad* CreatNewRoad(RoadID_ RoadID)
    {
    CertainRoad* pNewRoadObj = (CertainRoad*)malloc(sizeof(CertainRoad)); 
    
    pNewRoadObj->RoadID = RoadID;
    
    pNewRoadObj->pGetUpdated_LongCarCnt = GetUpdated_LongCarCnt;
    pNewRoadObj->pGetUpdated_CarCnt = GetUpdated_CarCnt;
    pNewRoadObj->pGetUpdated_SmallCarCnt= GetUpdated_SmallCarCnt;
    pNewRoadObj->pGetUpdated_Occupancy = GetUpdated_Occupancy;
    pNewRoadObj->pGetUpdated_AveSpeed = GetUpdated_AveSpeed;
    
    // 对上面的5个再次封装,提供统一接口
    pNewRoadObj->pGetUpdatedAllresults = GetUpdatedAllresults;
    
    return pNewRoadObj;
    }
    
    
    //串口底层收到数据,先进性简单逻辑判断,
    //判断依据:0xff是第一个数据,之后的是0x1b 0x10 0x11 0x12四者之一。
    //不符合上述依据,丢弃数据。
    //符合上述依据,开始计数(要算上之前的2个),一共计数到54字节,发送一个信号量给相应的处理任务进行解析。
    //处理任务进行: 和校验 、 原始数据的格式封装与转换。
    int main(void)
    { 
    // 车道1 2 3 4 5 6 7 车道8 // 这里模拟一下原始数据
    u8 FakeData[54]={0xFF, 0x1B, 0x09, 0x02, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x76, 0x94, // T_LongCarCnt:这一行都是长车流量 
    0xFF, 0x10, 0x09, 0xf5, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x01, 0x12, // T_CarCnt 总车流量
    0xFF, 0x11, 0x09, 0x20, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x03, 0x3f, // T_Occupancy 占有率
    0xFF, 0x12, 0x0B, 0x88, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x00, 0x30, 0xD4};// T_AveSpeed 平均速度
    
    // 感觉这样写得很丑,其实输入就应该是一个车道的ID,u8类型的数据即可,而不是这样填写枚举值。
    // 改进方法:在CreatNewRoad函数内增加断言,利用switch case,将u8的ID值转为枚举值。并assert断言,防止输入参数大于8。
    // 暂不改进
    CertainRoad* pRoad1 = CreatNewRoad(RoadID1); // 每条车道是一个对象    
    CertainRoad* pRoad2 = CreatNewRoad(RoadID2); 
    CertainRoad* pRoad3 = CreatNewRoad(RoadID3);
    CertainRoad* pRoad4 = CreatNewRoad(RoadID4);
    CertainRoad* pRoad5 = CreatNewRoad(RoadID5);
    CertainRoad* pRoad6 = CreatNewRoad(RoadID6);
    CertainRoad* pRoad7 = CreatNewRoad(RoadID7);
    CertainRoad* pRoad8 = CreatNewRoad(RoadID8);
    // 注:当前VS是C89标准
    printf(" Main Begin 
    
    ");
    
    if(SumCheck(FakeData))
    {
    u8 LongCarCnt=0;
    u8 CarCnt=0;
    u8 SmallCarCnt=0;
    u8 Occupancy=0;
    u8 AveSpeed=0;
    
    u8 Result[5] = {0};
    u8 i=0, j=0;
    CertainRoad*pRoad = (CertainRoad*)0; // NULL
    
    for(i=1; i<=8; i++)
    {    
    switch(i)
    {
    case 1:
    pRoad = pRoad1;break;
    case 2:
    pRoad = pRoad2;break;
    case 3:
    pRoad = pRoad3;break;
    case 4:
    pRoad = pRoad4;break;
    case 5:
    pRoad = pRoad5;break;
    case 6:
    pRoad = pRoad6;break;
    case 7:
    pRoad = pRoad7;break;
    case 8:
    pRoad = pRoad8;break;
    }
    
    //本接口的使用方式一: 让用户一个一个调用
    LongCarCnt = pRoad->pGetUpdated_LongCarCnt(pRoad, FakeData); 
    printf("pRoad%d: LongCarCnt = %d 
    ",i, LongCarCnt);
    
    CarCnt = pRoad->pGetUpdated_CarCnt(pRoad, FakeData); 
    printf("pRoad%d: CarCnt = %d 
    ", i, CarCnt);
    
    SmallCarCnt = pRoad->pGetUpdated_SmallCarCnt(pRoad, FakeData); 
    printf("pRoad%d: SmallCarCnt = %d 
    ", i, SmallCarCnt);
    
    Occupancy = pRoad->pGetUpdated_Occupancy(pRoad, FakeData); 
    printf("pRoad%d: Occupancy = %d 
    ", i, Occupancy);
    
    AveSpeed = pRoad->pGetUpdated_AveSpeed(pRoad, FakeData); 
    printf("pRoad%d: AveSpeed = %d 
    ", i, AveSpeed);
    
    //本接口的使用方式二:让用户一个一个调用太麻烦了,再封装一层,直接返回5个有物理意义的字节作为结果。
    pRoad->pGetUpdatedAllresults(pRoad, FakeData, Result);
    
    for(j=0; j<5; j++)
    {
    printf(" Result[%d] = %d 
    ", j, Result[j]);
    }
    printf(" -----pRoad%d ---OVER---
    
    ", i); 
    }
    }
    printf(" 
    
    ");
    return 0;
    }
    
    
    //和校验,这是一个独立使用的函数
    mybool SumCheck(const u8* pScrData)
    {
    mybool ret = 0;
    u8 i = 0;
    u16 CheckSUM1=0, CheckSUM2=0, CheckSUM3=0, CheckSUM4=0;
    
    for(i=3; i<=11; i++)
    {
    CheckSUM1 += pScrData[i];
    }    
    CheckSUM1 = CheckSUM1%256;
    
    for(i=16; i<=24; i++)
    {
    CheckSUM2 += pScrData[i];
    }
    CheckSUM2 = CheckSUM2%256;
    
    for(i=29; i<=37; i++)
    {
    CheckSUM3 += pScrData[i];
    }
    CheckSUM3 = CheckSUM3%256;
    
    for(i=42; i<=52; i++)
    {
    CheckSUM4 += pScrData[i];
    }
    CheckSUM4 = CheckSUM4%256;
    
    if( ( (u8)CheckSUM1 == pScrData[12]) && ((u8)CheckSUM2 == pScrData[25]) 
    && ((u8)CheckSUM3 == pScrData[38]) && ((u8)CheckSUM4 == pScrData[53]) )
    {
    ret = 1;
    printf(" 本次串口收到的54字节 和检验 OK 
    
    ");
    }
    return ret;
    }

    .

    /************* 社会的有色眼光是:博士生、研究生、本科生、车间工人; 重点大学高材生、普通院校、二流院校、野鸡大学; 年薪百万、五十万、五万; 这些都只是帽子,可以失败千百次,但我和社会都觉得,人只要成功一次,就能换一顶帽子,只是社会看不见你之前的失败的帽子。 当然,换帽子决不是最终目的,走好自己的路就行。 杭州.大话西游 *******/
  • 相关阅读:
    MyBatis使用
    华为如何实现基于Git的跨地域协同开发
    推荐一款华为最新的自动化代码检查工具
    我是如何进行code review的
    谈谈敏捷开发
    软件测试管理的一点小心得
    (转)技术转管理可能遇到的 3 大挑战及解决方案
    领域驱动设计和实践
    NET开源项目
    asp.net搭建mybatis开发环境
  • 原文地址:https://www.cnblogs.com/happybirthdaytoyou/p/10323766.html
Copyright © 2020-2023  润新知