嵌入式网络设备一次盲点补报的开发经验(二)

简介: 嵌入式网络设备一次盲点补报的开发经验(二)

作者:良知犹存

转载授权以及围观:欢迎添加微信公众号号:Conscience_Remains

总述

   曾经开发的时候遇到这样一个情况,我们的设备是车载设备,在车辆行驶过程中需要实时上报车辆数据,但是由于用的网络端是2G网,在行驶过程中,会遇到信号不好导致网络中断的情况,最早时候因为配置联网状态机很快,重联网时间很小,我直接就选择重联网之后再进行上报。可是在实际使用过程中发现,基站的切换、网络信号不好都会导致网络中断,重联网机制也不是每次都很迅速。所以开始考虑将数据本地保存,等待联网成功之后再次进行补报。下面我就介绍一下具体的思路。

嵌入式网络设备一次盲点补报的开发经验(一)这是上一篇文章。


二、程序的介紹

昨天介绍从接到项目到最终选定实现的数据结构,下面我就来介绍一下实际的代码。

首先盲点补报的数据我们要清楚,是车辆行驶过程中,由于各种原因网络中断,导致数据无法实时上传,这个时候需要本地将车辆的一些信息保存,等待重联网成功再进行上报到服务器。

先建立一个可以支持数据保存的结构体:包括UTC时间和经纬度,以及车辆的一些基本信息

__packed typedef struct  
{                    
  u32 year    :12; //年
  u32 month   :4;//月
  u32 day     :5;//日
  u32 hour    :5;//时
  u32 min     :6;//分
  u8 sec      :6;//秒
  u8 res      :2;
}utcTypeDef; //UTC时间结构体定义 /*nmea_utc_time 此结构体达不到精度,会导致 UTC2Sec 函数计算错误*/
__packed typedef struct 
{
 utcTypeDef utc;
 u32 Longitude;
 u32 Latitude;
 u16 Speed;
 u16 RPM;
}Message;

开始定义我们需要保存的并且分配的内存大小,这里有个提示分配的时候,因为是malloc,此时芯片中数据堆对应的内存被我们分配,所以分配的第一件事就是先设置好堆的大小。

首先我们使用的是双级指针(一级指针地址指向储存的数据,二级指针地址指向一级指针的地址),一次性分配的方法进行栈排序存储,利用所以第一步初始化栈的空间和头地址。

/*全局变量*/
const int MaxCachesLen = 22 * 1024;
const int MaxCachesCount = MaxCachesLen / sizeof(Message);
u32 g_CachesCount = 0; //缓存计数
Message** g_Caches =NULL;// malloc(sizeof(char*) * MaxCachesCount);
void GpsCacheInit(void)
{
  g_Caches  = (Message**)malloc(sizeof(Message*) * MaxCachesCount);//MaxCachesCount);//最大是1408*16=22*1204数据量  //建立MaxCachesCount个缓存空间 首地址
  if(NULL == g_Caches)
  {
    LOG("malloc g_cahce error\r\n"); //DEBUG
  }else{
    LOG("malloc g_cahce suc\r\n"); //DEBUG
  }
}
int GetCachesTotalSize(void){
 return sizeof(Message) * g_CachesCount;
}

写入栈和出栈的函数:

// 压入
u32 Push(Message item)
{
 /*如果满了  就把栈底最后一条数据地址的地址清空,丢弃掉旧的数据 把栈底以上的地址重新排列*/
 if (GetCachesTotalSize() >= MaxCachesLen
  || g_CachesCount >= MaxCachesCount)
 {
  free((g_Caches[g_CachesCount - 1]));//先free栈底
  memmove(g_Caches + 1, g_Caches, sizeof(Message*) * (g_CachesCount-1));
 }
 else
 {
  memmove(g_Caches + 1, g_Caches, sizeof(Message*) * g_CachesCount);
  g_CachesCount++;
 }
 /*分配新的地址的指针空间 存放到栈中*/
 Message* newItem = (Message*)malloc(sizeof(Message));
 if(NULL == newItem)
 {
   LOG("newItem NULL\r\n");
   return 0;
 }
 else{
   *newItem = item;
   g_Caches[0] = newItem;
   LOG("newItem success\r\n");
   return 1;
 }
}
// 弹出
u32 Pop(Message* out)
{
 if (!out || g_CachesCount == 0)
  return 0;
 *out = *(g_Caches[0]);
 free(g_Caches[0]);/*把栈顶的地址的指针数据释放掉*/
 memmove(g_Caches, g_Caches + 1, sizeof(Message*) * (g_CachesCount-1));
 g_CachesCount--;
 return 1;
}

把行驶态的车辆信息打包压入栈中保存(有两种方式保存一种是把UTC转化成秒计数存放到内存,一种是利用数据结构保存到内存中,最后我选择了第一种保存方式)

u8 InCache(void)/*缓存包*/
{
  u8 ret;
/*得到当前GPS的UTC*/
  Message pIn;
  pIn.utc.year  = gpsx.utc.year;
  pIn.utc.month = gpsx.utc.month;
  pIn.utc.day   = gpsx.utc.date;
  pIn.utc.hour  = gpsx.utc.hour;
  pIn.utc.min   = gpsx.utc.min;
  pIn.utc.sec   = gpsx.utc.sec;;
//  pIn.utc = UTC2Sec(gpsUtc);//转换成秒存储
  pIn.Latitude = gpsx.latitude;
  pIn.Longitude = gpsx.longitude;
  pIn.RPM   = carPulse.EngRpm ;
  pIn.Speed = carPulse.carSpeed;
  ret = Push(pIn);
  LOG("Incache Message Count:%d.TotalSize:%d\r\n",g_CachesCount,GetCachesTotalSize());
  return ret;
}

把数据从栈中取出打包发到服务器

u8 OutCache(void)
{
  u8 ret=0;
  Message pOut;
  ret = Pop(&pOut);
  if(ret)
  {
    LOG("outcache Message Count:%d.TotalSize:%d\r\n",g_CachesCount,GetCachesTotalSize());
    char *p,*p1,*p2,length;    
    p2= malloc(30);
    p=malloc(300);
    p1=p;
    memset(p,0x00,300);
    memset(p2,0x00,30);
    if(p1 == NULL )
    {
      LOG("%s:malloc p1 fault!\n", __FILE__);
      return 0;
    }
    sprintf(p2,"%04d-%02d-%02d %02d:%02d:%02d,",pOut.utc.year,pOut.utc.month,pOut.utc.day,pOut.utc.hour,pOut.utc.min,pOut.utc.sec);
    strcat(p1,p2); 
    //1,2 3/**/
    memset(p2,0x00,20); /*经纬度*/                                              
    sprintf(p2,"%03d.%05d,%02d.%05d, ,",(pOut.Longitude/100000),(pOut.Longitude%100000),(pOut.Latitude/100000),(pOut.Latitude%100000));  
    strcat(p1,p2);
    //4
    memset(p2,0x00,20);
    sprintf(p2,"%d,",pOut.Speed);//车速
    strcat(p1,p2);
    p1=p;
    length = strlen(p);
    p[length] = MsgOrCRC((u8*)&p[2],length-2);
    SendBuf(USART1, p, length+1);
    free(p);
    free(p2);
  }  
  return ret;
}

这就是我分享的第二篇篇盲点补报的文章,代码都是实践过的,如果大家有什么更好的思路,欢迎分享交流哈。

相关文章
|
10天前
|
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
61 20
利用Python脚本自动备份网络设备配置
通过本文的介绍,我们了解了如何利用Python脚本自动备份网络设备配置。该脚本使用 `paramiko`库通过SSH连接到设备,获取并保存配置文件。通过定时任务调度,可以实现定期自动备份,确保网络设备配置的安全和可用。希望这些内容能够帮助你在实际工作中实现网络设备的自动化备份。
58 14
【01】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-硬件设备实时监控系统运营版发布-本产品基于企业级开源项目Zabbix深度二开-分步骤实现预计10篇合集-自营版
【01】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-硬件设备实时监控系统运营版发布-本产品基于企业级开源项目Zabbix深度二开-分步骤实现预计10篇合集-自营版
24 0
Ubuntu20.04搭建嵌入式linux网络加载内核、设备树和根文件系统
使用上述U-Boot命令配置并启动嵌入式设备。如果配置正确,设备将通过TFTP加载内核和设备树,并通过NFS挂载根文件系统。
106 15
网络设备日志记录
网络设备日志记录是追踪设备事件(如错误、警告、信息活动)的过程,帮助IT管理员进行故障排除和违规后分析。日志详细记录用户活动,涵盖登录、帐户创建及数据访问等。为优化日志记录,需启用日志功能、管理记录内容、区分常规与异常活动,并使用专用工具进行事件关联和分析。集中式日志记录解决方案可收集并统一管理来自多种设备和应用的日志,提供简化搜索、安全存储、主动监控和更好的事件可见性,增强网络安全。常用工具如EventLog Analyzer能灵活收集、存储和分析日志,确保高效管理。
如果已经链接了5Gwifi网络设备是否还能搜索到其他5Gwifi网络
当设备已经连接到一个5G Wi-Fi网络时,它仍然有能力搜索和发现其他可用的5G Wi-Fi网络。这里所说的“5G Wi-Fi”通常指的是运行在5GHz频段的Wi-Fi网络,而不是与移动通信中的5G网络(即第五代移动通信技术)混淆。
动态DNS(DDNS)技术在当前网络环境中日益重要,它允许使用动态IP地址的设备通过固定域名访问
动态DNS(DDNS)技术在当前网络环境中日益重要,它允许使用动态IP地址的设备通过固定域名访问,即使IP地址变化,也能通过DDNS服务保持连接。适用于家庭网络远程访问设备及企业临时或移动设备管理,提供便捷性和灵活性。示例代码展示了如何使用Python实现基本的DDNS更新。尽管存在服务可靠性和安全性挑战,DDNS仍极大提升了网络资源的利用效率。
185 6
局域网络设备
网卡、中继器、集线器、网桥和交换机是网络通信中的关键设备。网卡实现计算机与网络的连接,中继器用于延长网络传输距离,集线器将多台设备连接至共享网络,网桥通过MAC地址转发数据,而交换机提供高性能的数据转发和过滤服务,支持VLAN、QoS等功能,适用于不同规模的网络环境。
88 3
对比了思科和华为网络设备的基本配置、接口配置、VLAN配置、路由配置、访问控制列表配置及其他重要命令
本文对比了思科和华为网络设备的基本配置、接口配置、VLAN配置、路由配置、访问控制列表配置及其他重要命令,帮助网络工程师更好地理解和使用这两个品牌的产品。通过详细对比,展示了两者的相似之处和差异,强调了持续学习的重要性。
120 2

热门文章

最新文章