zoukankan      html  css  js  c++  java
  • 嵌入式网络设备一次盲点补报的开发经验(二)

    作者:良知犹存

    转载授权以及围观:欢迎添加微信公众号号: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
    "); //DEBUG
      }else{
        LOG("malloc g_cahce suc
    "); //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
    ");
       return 0;
     }
     else{
       *newItem = item;
       g_Caches[0] = newItem;
       LOG("newItem success
    ");
       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
    ",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
    ",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!
    ", __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;
    }
     

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

    更多分享,扫码关注我

  • 相关阅读:
    Vue对象提供的属性功能
    Vue快速入门
    Django-DRF(路由与扩展功能)
    Django-DRF(视图相关)
    Django-DRF(1)
    Django-Xadmin
    python 列表的append()和extend()
    map apply applymap
    pd.merge(), pd.concat()
    描述性分析与数据清洗 笔记
  • 原文地址:https://www.cnblogs.com/conscience-remain/p/13395179.html
Copyright © 2011-2022 走看看