TT12-MCU/applications/func/func.c
CSSC-WORK\murmur 851c1c2352 添加初始化时建立sd目录避免sd卡挂载失败的问题
自检功能测试ok
tools.c 添加部分基本函数
func.c 解析逻辑部分初步完成
2023-07-18 19:23:48 +08:00

489 lines
11 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-07-06 murmur the first version
*/
#include <rtthread.h>
#include <usrcfg.h>
#include <ttmsg/ttmsg.h>
#include "func.h"
#define LOG_TAG "func"
#define LOG_LVL LOG_LVL_DBG
#include <ulog.h>
//3.2.1双模通信功能
//1为TT通信0为BD短报文通信
void setCommMode(int isTT)
{
if (isTT) {
//change mode
}
else {
}
//write to cfg file
set_cfg("commMode", isTT);
LOG_D("set commMode to %s",isTT?"TT":"BD");
}
int getCommMode()
{
//load from cfg file
int flag = get_cfg("commMode");
if (flag < 0) {
LOG_W("get mode fault.");
}
return flag;
}
//3.2.2状态自检
/**
* 系统自检,自动发送自检结果
*/
extern int df(const char *path);
/**
* 获取磁盘剩余空间大小单位MB
* @param path指定磁盘挂载的路径为空时表示挂载在根目录的磁盘
* @return 返回结果单位MB
*/
static uint16_t getFreeSpace(const char *path)
{
long long cap;
struct statfs buffer;
int result = dfs_statfs(path ? path : "/", &buffer);
if (result != 0)
{
LOG_E("dfs_statfs failed.");
return 0;
}
cap = (uint16_t)((long long)buffer.f_bsize) * ((long long)buffer.f_bfree) / 1024LL / 1024LL ;//转换为MB
return cap;
}
void ddf()
{
LOG_D("free space of flash is %d MB.",getFreeSpace(NULL));
uint16_t rst = getFreeSpace("/sd");
LOG_D("free space of sd is %d MB.%02X,%02X",rst,rst>>8,rst&0xff);
}
MSH_CMD_EXPORT(ddf,getFreeSpace);
/**
* 獲取電池電量。
* @return 返回電量百分比
*/
RT_WEAK int getPowerLevel(void)
{
return 0;
}
/**
* 上傳天通數據
* @param din 待發送數據
* @param len 待發送數據的長度
* @return
*/
RT_WEAK int uploadData(uint8_t *din, size_t len)
{
return 0;
}
void sysSelfTest()
{
rt_uint8_t rst[100]={0x5A, 0xA5, 0x32, 0x3E, 0x0A, 0x41};
int p = 6;
rt_uint8_t sysSta=1,xh=0,jh=0,commSpeed=0;
rst[p++]=0x00;
rst[p++]=0x09;
rst[p++] = sysSta;
rst[p++] = xh;
rst[p++] = jh;
rst[p++] = commSpeed;
rst[p++] = getPowerLevel();
//flash 剩餘空間
uint16_t cap = getFreeSpace("/");
rst[p++] = (uint8_t)(cap >> 8);
rst[p++] = (uint8_t)(cap & 0xff);
//SD卡剩餘空間
cap = getFreeSpace("/sd");
rst[p++] = (uint8_t)(cap >> 8);
rst[p++] = (uint8_t)(cap & 0xff);
rst[p++] = bccCRC(rst+2, p-1); ////校验位为1个字节采用异或运算从指令的第3个字节开始到奇偶校验位的前一个字节结束
rst[p++] = 0xED; //结束位
LOG_HEX("selfTestRes",16,rst,p);
//发送结果
uploadData(rst,p);
}
MSH_CMD_EXPORT(sysSelfTest,sysSelfTest);
//3.2.3日志记录
//日志功能由各函数通过LOG_D()实现
//3.2.4自毁功能
/**
* 设置自毁功能开关
* @param setON 1-自毁功能开启0-关闭
*/
void setSelfDestructSWT(int setON)
{
//write to cfg file
set_cfg("SelfDesSW", setON);
LOG_D("set SelfDesSW to %s",setON?"ON":"OFF");
}
/**
* 获取自毁开关状态
* @return 1-自毁功能开启0-关闭
*/
int getSelfDestructSWT()
{
//load from cfg file
int flag = get_cfg("SelfDesSW");
if (flag < 0) {
LOG_W("get mode fault.");
}
return flag;
}
/**
* 启动自毁
*/
void selfDestruct()
{
if (getSelfDestructSWT()) {
//硬件自毁
LOG_W("SELF DESTRUCT START.");
}
}
//3.2.5开、关窗功能
extern void updateAlarm(int *t);
/**
* 更新开窗时间,目前支持两组开窗时段。更新会清除之前的开窗设置
*/
void setCommWindow(int *t)
{
updateAlarm(t);
LOG_D("更新开窗时间完成。");
}
/**
* 手动控制开窗
* @param t 开窗时长单位分钟时间到则自动关窗。t=0时需要手动关窗。
*/
void openWindow(int t)
{
//开启TT
pwTT_thread_entry("1");//开机
if (!t) {
LOG_D("手动开窗完成,需手动关窗。");
return;
}
//设置定时器,定时器到则关窗
/* 创建定时器,单次定时器 */
rt_timer_t timer1;
timer1 = rt_timer_create("window", pwTT_thread_entry,
0, rt_tick_from_millisecond(t*60*1000),
RT_TIMER_FLAG_ONE_SHOT);
/* 启动定时器 */
if (timer1 != RT_NULL)
{
rt_timer_start(timer1);
LOG_D("手动开窗完成,%d分钟后自动关窗。",t);
}
}
/**
* 手动关窗
*/
void closeWindow()
{
pwTT_thread_entry("0");//关 机
LOG_D("手动关窗完成。");
}
//3.2.6工作参数配置、状态查询
//包含浮体自身、标体透传、两者结合
//这里主要实现浮体自身
//浮体自身的参数配置各功能函数有实现,此处需规定参数下发协议和解码实现
//3.2.8定时自报位置信息
//每小时传数据时同步传位置信息
//3.2.9深度异常告警
int packDeepMsg(uint8_t *din, int len, uint8_t *dout)
{
//获取并更新位置信息
uint8_t loc[]={};
rt_memcpy(din+6, loc, 8);//位置数据从【】字节开始共8个字节
//加密。因加密后数据长度会变化,故不能只加密位置数据。
uint8_t cd[200];
size_t nlen = cryp_data(din, len, cd);
//打包数据
static MSG cfg;
rt_memset(&cfg, 0, sizeof(MSG)); // 分配空间
char *fin;
time2Str(fin);
packInit(&cfg, fin, 0);//写入配置
size_t rst = packMsg(&cfg, din, nlen, dout);
LOG_D("位置数据打包完成");
return rst;
}
//3.2.10位置异常告警
//map.c中实现
/**
* 判断是否在电子围栏内部
* @param x 当前位置经度
* @param y 当前位置纬度
* @return 在内部则返回true反之false
*/
static int isInFence(float x, float y)
{
float polyX[]={},polyY[]={};
int polyCorners = mapParse("/map.geojson",polyX,polyY);
return pointInPolygon(polyCorners,polyX,polyY,x,y);
}
/**
* 设置位置告警功能开关
* @param setON 1-告警功能开启0-关闭
*/
void setLocationAlertSWT(int setON)
{
}
/**
* 检查是否在电子围栏内部,并发出告警
*/
void checkLocAndAlert()
{
//get Lon and Lat
float x,y;
if (!x || !y) {
LOG_W("location info is not ready.");
return;
}
int isIN = isInFence(x, y);
if (isIN) {
LOG_I("设备在预设范围内,位置正常。");
}
else {
LOG_W("警告!设备不在预设范围内!");
//告警
}
}
//3.2.12数据存储区清空
//
/**
* 采用格式化命令对存储区进行清空,谨慎使用!
*/
void clearAllData()
{
mkfs("elm", "W25Q128");//format flash
mkfs("elm","sd0");//format SD
}
/**
* @brief TT根据下发的指令执行对应的功能
*
* @param din 待执行的指令数据
* @param len 数据长度,单位字节
*/
void ttRunCMD(uint8_t *din, size_t len)
{
int cmd=(din[4]<<8) + din[5];
switch (cmd)
{
case _CFG_COMM_MODE:
/* code */
break;
case _CMD_SELF_TEST:
break;
case _CFG_SELF_DESTRUCT:
break;
case _CMD_SELF_DESTRUCT:
break;
case _CFG_COMM_WINDOW:
break;
case _CMD_OPEN_WINDOW:
break;
case _CMD_CLOSE_WINDOW:
break;
case _CFG_LOCATION_ALERT:
break;
case _CMD_CLEAR_DATA:
break;
default:
LOG_W("未支持的指令。");
break;
}
}
//原计划将指令粗解析放在上位机考虑到上位机到位时间晚现放到MCU端
/**
* @brief 校验、解析3S数据以0x5AA5开头0xED结尾。
*
* @param din 待解析数据
* @param count 待解析数据长度
*/
void parse3SData(uint8_t *din, size_t count)
{
uint8_t head[]={0x5a,0xA5};
//header[4] addr[2]  func[2]  len[2]  data[N]  fcrc[1] tail[1]
uint8_t rst = memcmp(din,head,sizeof(head[0]));
if (rst)
{
LOG_W("0x%02X%02X != 0x%5AA5,帧头不匹配",din[0],din[1]);
return;
}
if (din[count-2] != bccCRC(din+2,count-2-2))//校验位为1个字节采用异或运算从指令的第3个字节开始到奇偶校验位的前一个字节结束
{
LOG_W("0x%02X != 0x%02X,校验值不匹配",din[count-2] , bccCRC(din+2,count-2-2));
return;
}
if (din[count-1] != 0xED)
{
LOG_W("0x%02X != 0xED,帧尾不匹配",din[count-1]);
return;
}
uint8_t dout[200];
size_t len=0;
if (din[3] == ADDR_TT)//仅给TT的消息
{
ttRunCMD(din,len);
}
if (din[3] == ADDR_3S)//给3S的指令需要再加工返回数据可能也需要再加工
{
//
LOG_D("直接调用小彭的函数进行处理。");
// extern void xpParse(uint8_t *din, size_t len);
// xpParse(din,len);
//以下处理逻辑作废
//绝大部分数据均需要转换。详见《主要指令一览》
// int cmd = (din[4]<<8) + din[5]
// switch (cmd)
// {
// case _CMD_RTC_CHECK:
// case 0:
// /* 不转换 */
// break;
// default:
// //转换
// char rst[]="";
// bytes2str(din,count,16,"",rst);
// break;
// }
// //发送
}
}
/**
* @brief 解析TT数据TT收到的指令必是单指令解析容易。
*
* @param din
* @param len
*/
void parseTTData(uint8_t *din, size_t len)
{
uint8_t head[]={0x88,0xAA,0xBB,0x88, 0x00,0x01, 0x00,0x22, 0x70,0x21, 0x00,0xaa, 0x00, 0x27,0x22,0x22,0x22 };
//fstart[4] fnum[2]  bak[2]  ftype[2]  fdlen[2]  fcrc[1] ftccid[4]
uint8_t rst = memcmp(din,head,sizeof(head));
if (rst)
{
LOG_W("帧头不匹配");
return;
}
uint8_t id[30]="";
LOG_D("get new data: id=\"%s\", cur/all=[%d/%d]",bytes2str(din+17,7,10,"_",id),din[25],din[26]);
if (din[24] >> 7) // fcfg=数据类型。解析TT收到的数据时仅需解析“命令”“数据”传输是单向的。
{
LOG_W("浮标端仅接受指令,暂不支持数据。");
return;
}
uint8_t rawData[200];
uint8_t rawDataLen=len-27;
memcpy(rawData, din + 27, rawDataLen);
parse3SData(rawData,rawDataLen);
// switch (din[24] & 0x7F) // 识别指令的目标地址
// {
// case _ONLY_FOR_TT:
// ttRunCMD(rawData, len - 27);
// break;
// case _ONLY_FOR_3S:
// /* code */
// // 发送数据至3S
// break;
// case _FOR_BOTH:
// // 发送数据至3S
// // 等待返回数据
// // 打包
// // 上传
// break;
// default:
// LOG_W("未识别到指令的目标地址");
// break;
// }
}