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 \n\n");
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 \n",i, LongCarCnt);
CarCnt = pRoad->pGetUpdated_CarCnt(pRoad, FakeData);
printf("pRoad%d: CarCnt = %d \n", i, CarCnt);
SmallCarCnt = pRoad->pGetUpdated_SmallCarCnt(pRoad, FakeData);
printf("pRoad%d: SmallCarCnt = %d \n", i, SmallCarCnt);
Occupancy = pRoad->pGetUpdated_Occupancy(pRoad, FakeData);
printf("pRoad%d: Occupancy = %d \n", i, Occupancy);
AveSpeed = pRoad->pGetUpdated_AveSpeed(pRoad, FakeData);
printf("pRoad%d: AveSpeed = %d \n", i, AveSpeed);
//本接口的使用方式二:让用户一个一个调用太麻烦了,再封装一层,直接返回5个有物理意义的字节作为结果。
pRoad->pGetUpdatedAllresults(pRoad, FakeData, Result);
for(j=0; j<5; j++)
{
printf(" Result[%d] = %d \n", j, Result[j]);
}
printf(" -----pRoad%d ---OVER---\n\n", i);
}
}
printf(" \n\n");
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 \n\n");
}
return ret;
}
C 面向对象编程 --- 一模块的串口协议解析的更多相关文章
- Python面向对象编程和模块
在面向对象编程中,你编写表示现实世界中的事物和情景的类,并基于这些类来创建对象. 编写类时,你定义一大类对象都有的通用行为.基于类创建对象时,每个对象都自动具备这种通用行为,然后根据需要赋予每个对象独 ...
- javascript面向对象编程的3种常见封装形式解析
javascript如何才能脱离函数式编程,拥抱面向对象编程呢,常见的有3种形式,其它形式可以说都是这3种的变种. 1.直接定义对象直接量的形式 var Util={ getType: ...
- java 面向对象编程 第20章 XML技术解析
1. XML:extended Markup Language 可扩展标记语言,利用标签和子标签方式描述数据. 2. 声明<?xml version=”1.0”?>版本号 注释< ...
- python模块、面向对象编程
目录: 模块补充 xml 面向对象 一.模块补充 shutil: 文件复制模块:进行文件copy.压缩: 使用方法: 将文件内容拷贝到另一个文件中,可以部分内容 shutil.copyfileobj( ...
- 洗礼灵魂,修炼python(40)--面向对象编程(10)—定制魔法方法+time模块
定制魔法方法 1.什么是定制魔法方法 首先定制是什么意思呢?其实就是自定义了,根据我们想要的要求来自定义.而在python中,其实那些所谓的内置函数,内置方法,内置属性之类的其实也是自定义出来的,不过 ...
- Python 编程核心知识体系-模块|面向对象编程(三)
模块 面向对象编程
- Day07:常用模块,面向对象编程(对象&类)及内置函数
今日内容:1.常用模块2.面向对象编程(*****) 介绍面向对象编程 类 对象3.内置函数------------------------------1.面向过程编程 核心“ ...
- day23 xml模块、面向对象编程介绍
今日内容: 1.xml模块 2.面向对象编程 一.xml模块 什么是xml? xml是一种可扩展的标记语言 xml语言的语法: <person name="jack"> ...
- Python(三)基础篇之「模块&面向对象编程」
[笔记]Python(三)基础篇之「模块&面向对象编程」 2016-12-07 ZOE 编程之魅 Python Notes: ★ 如果你是第一次阅读,推荐先浏览:[重要公告]文章更新. ...
随机推荐
- 为什么网站URL需要设置为静态化
http://www.wocaoseo.com/thread-95-1-1.html 为什么网站URL需要静态化?网站url静态化的好处是什么?现在很多网站的链接都是静态规的链接,但是网站 ...
- 焦大:seo思维光年(上)检索的价值观
http://www.wocaoseo.com/thread-55-1-1.html 检索的价值观是什么?最近很多人咨询我这个问题,因为在百度上根本找不到相关的资料,其实这个东西也是我自己总结的,比如 ...
- oracle备份之备份测试脚本(冷备、热备、rman)
1.数据库环境 数据库DBID及打开模式SQL> select dbid,open_mode from v$database; DBID OPEN_MODE---------- -------- ...
- 揭秘!containerd 镜像文件丢失问题,竟是镜像生成惹得祸
导语 作者李志宇,腾讯云后台开发工程师,日常负责集群节点和运行时相关的工作,熟悉 containerd.docker.runc 等运行时组件.近期在为某位客户提供技术支持过程中,遇到了 contain ...
- 虚拟机安装:VirtualBox上安装Ubuntu
在Win10 中使用VirtualBox安装Ubuntu 本教程将指引读者在Windows10操作系统下使用开源虚拟机软件VirtualBox安装Ubuntu,读者也可以使用其他虚拟机VMware W ...
- Azure Blob (三)参数设置说明
一,引言 上一篇将 Azure Blob 存储的时候,有使用到一个 .NET Core Web 项目,通过代码的方式进行操作 Azure Blob 的数据,接着上一篇的内容,今天继续看一下代码,具体 ...
- Django模型验证器详解和源码分析
转发请注明来源 在Django的模型字段参数中,有一个参数叫做validators,这个参数是用来指定当前字段需要使用的验证器,也就是对字段数据的合法性进行验证,比如大小.类型等. Django的验证 ...
- Myeclipse 连接数据库(jdbc)
1.找到DataBase Explorer,如下图所示: 2.点击下图红框内图标,new 3.进入下图界面 如果是JDBC驱动按下图配置: driver name自己起 url一定要注意:jdbc:m ...
- Java原生网络编程
一些常见术语 编程中的Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面 ...
- 前端插入date类型的数据到数据库
//插入 @Override public boolean insertEmp(Emp emp) { String sql = "insert into emp(lwlEmpno,lwlEn ...