提到监控设备,人们会首先想到监控摄像头,这种监控设备所传输的数据是视频数据,而本设计的物联网在线相机终端系统所要传输的是图片数据,在提供定时监控能力的同时,提供一个更轻量级、消耗数据量更小、更稳定、功能更实用的物联网在线相机终端系统。
特性
- 物联网在线相机终端系统基于FreeRTOS实时操作系统设计。
- 通过基于TCP的自定义IoT通信协议连接到服务端。
- 自定义IoT通信协议带有应答机制、自动重传机制、CRC校验、AES加密机制。
- 自定义IoT通信协议带有注册、登录、对时、参数下发、参数请求、设备控制、文件上传、文件下载的通用服务流程。
- 自动网络重连机制。
- OTA升级机制
- 运行信息统计功能:记录设备状态、每次开机的原因、设备开机次数、运行时长
- 支持6种工作模式:待机模式、节能模式、实时模式、半实时模式、定时模式、半定时模式。灵活适应不同的应用场景。
- 供电状态监测:可监测终端设备的供电状态,并向服务端发出断电告警。
- 远程控制:重启、恢复出厂设置、蓝牙开关、控制拍照、OTA升级。
- 参数设定:终端设备的配置参数可以远程更改。
硬件部分
成品展示




拆解展示

硬件架构

PCB

应用现场

端侧软件
开发工具
- 开发环境:ESP-IDF, VSCode
- 开发语言:C
端侧框架

工作模式

OTA升级策略

IoT平台展示
蓝牙打卡与照片记录

断电告警

IoT管理平台
IoT管理平台支持应用管理、设备管理、设备消息日志管理、协议数据类型定义、设备参数管理功能

OTA管理平台
支持版本管理、自定义白名单等功能

小程序应用展示

端侧部分代码实现
传输控制层帧格式


传输控制层窗口发送部分
寻找空闲窗口位,组包,发送
static uint8_t MyTSFC_FindIdle_Windows(my_tsfc_windows_t** windows_array, my_tsfc_windows_t** idle_fp)
{
uint8_t i=0;
for(i=0; i<MY_TSFC_WINDOWS_SIZE; i++)
{
if(windows_array[i]!=NULL)
{
if(windows_array[i]->state==tsf_win_fps_idle)
{
*idle_fp = windows_array[i];
break;
}
}
else
{
ESP_LOGE("MyTSFC_FindIdle_Windows()", "error: windows_array[%d]!=NULL is false\n", i);
}
}
return i;
}
static void MyTSFC_NoAck_Mark( my_tsfc_windows_t* idle_fp, my_tsfc_queue_t* queue_data, uint32_t crc_, int index)
{
idle_fp->state = tsf_win_fps_send_noack;
ESP_LOGI("MyTSFC_NoAck_Mark()", "sn=%d, crc=0x%08x, frame_len=%d", \
my_tsfc_send_windows_array[index]->frame_sn, crc_, idle_fp->data_len);
idle_fp->start_timestamp = esp_timer_get_time()/1000;
my_tsfc_statistic.up.frame_count_total++;
my_tsfc_statistic.up.data_count_total+=idle_fp->data_len;
if(queue_data->my_tsfc_data_type==msg_frame)
{
my_tsfc_statistic.up.frame_count_type_msg++;
my_tsfc_statistic.up.frame_count_type_msg_valid++;
}
else if(queue_data->my_tsfc_data_type==data_frame)
{
my_tsfc_statistic.up.frame_count_type_data++;
my_tsfc_statistic.up.frame_count_type_data_valid++;
}
else if(queue_data->my_tsfc_data_type==ack_frame)
{
my_tsfc_statistic.up.frame_count_type_ack++;
}
else if(queue_data->my_tsfc_data_type==cd_frame)
{
my_tsfc_statistic.up.frame_count_type_cc++;
}
}
static int MyTSFC_Packager_To_Windows(my_tsfc_windows_t** windows_array, my_tsfc_queue_t* queue_data)
{
int ret = 0;
if(windows_array==NULL)
{
ESP_LOGE("MyTSFC_Packager_To_Windows()", "error: windows_array==NULL\n");
return -1;
}
my_tsfc_windows_t* idle_fp = NULL;
xSemaphoreTake(my_tsfc_send_windowsMutexSemaphore, portMAX_DELAY);
//寻找空闲窗口位
uint8_t idle_posi = MyTSFC_FindIdle_Windows(windows_array, &idle_fp);
if(idle_fp!=NULL)
{
if(queue_data->len <= TSFC_FRAME_DATA_SIZE_MAX)
{
//加入头部
idle_fp->data->head.type = queue_data->my_tsfc_data_type;
idle_fp->data->head.pd = MY_TSFC_PD;
idle_fp->data->sn = my_tsfc_send_windows_frame_counter++;
idle_fp->data->app_id = my_tsfc_info.app_id;
idle_fp->data->data_len = queue_data->len;
//加入数据部分
memcpy(idle_fp->data->data, queue_data->data, queue_data->len);
//补齐,16字节对齐,用于AES加密
if(idle_fp->data->data_len%16)
{
memset(idle_fp->data->data+idle_fp->data->data_len, 0, 16-(idle_fp->data->data_len%16));
idle_fp->data->data_len+=(16-idle_fp->data->data_len%16);
}
//加密
#if MY_TSFC_DEBUG_CHECK_AES
if(My_EspAes_Cipher(my_tsfc_info.aes_ctx, (void*)idle_fp->data->data, idle_fp->data->data_len, (void*)idle_fp->data->data, idle_fp->data->data_len))
{
ESP_LOGE("MyTSFC_Packager_To_Windows()", "error: MyAes_Cipher()\n");
ret = 2;
goto MyTSFC_Packager_To_Windows_return;
}
#endif
uint16_t idle_fp_data_data_len = idle_fp->data->data_len;
//计算CRC
uint32_t* p_crc = (uint32_t*)(idle_fp->data->data+idle_fp_data_data_len);
*p_crc = crc_32((void*)idle_fp->data, idle_fp_data_data_len+8);
uint32_t crc_ = *((uint32_t*)p_crc);
//加入TAIL
memcpy(p_crc+1, MY_TSF_DATAFRAME_TAIL, strlen(MY_TSF_DATAFRAME_TAIL));
//设置状态
idle_fp->frame_type = queue_data->my_tsfc_data_type;
idle_fp->data_len = idle_fp_data_data_len+16;
idle_fp->timeout_time = frame_ack_time_out_time;//ms
idle_fp->frame_position = idle_posi;
idle_fp->id = queue_data->id;
idle_fp->frame_sn = idle_fp->data->sn;
// my_tsfc_send_windows_frame_counter++;
if(my_tsfc_send_windows_frame_counter%MY_TSFC_WINDOWS_SIZE==0)
{
// ESP_LOGI("MyTSFC_Packager()", "my_tsfc_windows_enough = 1");
my_tsfc_windows_enough = true;
}
//发送到驱动传输层
int err = MyWHGM5_TcpSendData(idle_fp->data, idle_fp->data_len, 1000, idle_fp->id);
// ESP_LOGI("MyTSFC_Packager_To_Windows()", "err=%d", err);
if(!err)
{
MyTSFC_NoAck_Mark( idle_fp, queue_data, crc_, idle_posi);
ret = 0;
goto MyTSFC_Packager_To_Windows_return;
}
else
{
ESP_LOGE("MyTSFC_Packager_To_Windows()", "MyWHGM5_TcpSendData() timeout");
}
}
else
{
ESP_LOGE("MyTSFC_Packager_To_Windows()", "error: queue_data->len=%d\n", queue_data->len);
}
}
else
{
ESP_LOGE("MyTSFC_Packager_To_Windows()", "idle_fp!=NULL is false\n");
ret = 3;
goto MyTSFC_Packager_To_Windows_return;
}
MyTSFC_Packager_To_Windows_return:
xSemaphoreGive(my_tsfc_send_windowsMutexSemaphore);
return ret;
}
传输控制层接收部分
头部处理
static my_tsf_ackcode_t MyTSFC_Rcv_Check_FrameHead(my_tsfc_rcv_frame_info_t* p_frame_info)
{
if(p_frame_info==NULL)
{
return -1;
}
if(p_frame_info->p_frame_start==NULL)
{
return -2;
}
//读取帧头
my_tsf_frame_head_t* my_tsf_frame_head = (my_tsf_frame_head_t*)(p_frame_info->p_frame_start);
char* frame_start_byte = (char*)(p_frame_info->p_frame_start);
if(!(my_tsf_frame_head->type>=my_tsf_frametype_min&&my_tsf_frame_head->type<=my_tsf_frametype_max))
{
p_frame_info->sn++;
return tsf_ackcode_frametype_unrecognized;
}
if(my_tsf_frame_head->pd!=MY_TSFC_PD)
{
#if MY_TSFC_DEBUG_CHECK_PD
ESP_LOGE("MyTSFC_Rcv_Check_FrameHead()", "error tsf_ackcode_pd_unsupported, my_tsf_frame_head->pd=0x%x\n", my_tsf_frame_head->pd);
return tsf_ackcode_pd_unsupported;
#else
ESP_LOGE("MyTSFC_Rcv_Check_FrameHead()", "error tsf_ackcode_pd_unsupported, my_tsf_frame_head->pd=0x%x, ignore!\n", my_tsf_frame_head->pd);
#endif
}
//获取帧头信息
p_frame_info->type = my_tsf_frame_head->type;
p_frame_info->pd = my_tsf_frame_head->pd;
//获取sn、appid、data_len、crc
p_frame_info->sn = *((uint8_t*)(frame_start_byte+2));
if(my_tsf_frame_head->type==msg_frame||my_tsf_frame_head->type==data_frame)
{
p_frame_info->app_id = my_endian_conversion_16(*((uint16_t*)(frame_start_byte+4)));
p_frame_info->data_len = my_endian_conversion_16(*((uint16_t*)(frame_start_byte+6)));
p_frame_info->crc_original = my_endian_conversion_32(*(uint32_t*)(frame_start_byte+p_frame_info->data_len+8));
}
else
{
p_frame_info->crc_original = my_endian_conversion_32(*(uint32_t*)(frame_start_byte+4));
if(my_tsf_frame_head->type==ack_frame)
{
p_frame_info->ack_code = *((uint8_t*)(frame_start_byte+3));
}
}
if(my_tsf_frame_head->type==ack_frame)
{
if(p_frame_info->ack_code!=tsf_ackcode_success)
{
ESP_LOGW("MyTSFC_Rcv_Check_FrameHead()", "ack_code error, p_frame_info->ack_code=0x%x!\n", p_frame_info->ack_code);
}
}
//比对app_id
if(my_tsf_frame_head->type==msg_frame||my_tsf_frame_head->type==data_frame)
{
if(p_frame_info->app_id!=my_tsfc_info.app_id)
{
#if MY_TSFC_DEBUG_CHECK_APPID
ESP_LOGE("MyTSFC_Rcv_Check_FrameHead()", "error tsf_ackcode_appid_unrecognized, p_frame_info->app_id=0x%x", \
p_frame_info->app_id);
return tsf_ackcode_appid_unrecognized;
#else
ESP_LOGE("MyTSFC_Rcv_Check_FrameHead()", "error tsf_ackcode_appid_unrecognized, p_frame_info->app_id=0x%x, ignore!", \
p_frame_info->app_id);
#endif
}
}
//比对数据长度是否一致
if(my_tsf_frame_head->type==msg_frame||my_tsf_frame_head->type==data_frame)
{
if(p_frame_info->frame_len < p_frame_info->data_len+16)
{
ESP_LOGE("MyTSFC_Rcv_Check_FrameHead()", "error tsf_ackcode_insufficient_len, p_frame_info->frame_len=%d\n", p_frame_info->frame_len);
return tsf_ackcode_insufficient_len;
}
}
else
{
if(p_frame_info->frame_len!=12)
{
ESP_LOGE("MyTSFC_Rcv_Check_FrameHead()", "error tsf_ackcode_insufficient_len, p_frame_info->frame_len=%d\n", p_frame_info->frame_len);
return tsf_ackcode_insufficient_len;
}
}
//计算crc并比对
if(my_tsf_frame_head->type==msg_frame||my_tsf_frame_head->type==data_frame)
{
p_frame_info->crc_calcu_result = crc_32((void*)my_tsf_frame_head, p_frame_info->data_len+8);
}
else
{
p_frame_info->crc_calcu_result = crc_32((void*)my_tsf_frame_head, 4);
}
if(p_frame_info->crc_original!=p_frame_info->crc_calcu_result)
{
#if MY_TSFC_DEBUG_CHECK_CRC
ESP_LOGE("MyTSFC_Rcv_Check_FrameHead()", "error tsf_ackcode_crc_check_error, 0x%08x:0x%08x", \
p_frame_info->crc_original, p_frame_info->crc_calcu_result);
return tsf_ackcode_appid_unrecognized;
#else
ESP_LOGE("MyTSFC_Rcv_Check_FrameHead()", "error tsf_ackcode_crc_check_error, 0x%08x:0x%08x, ignore!", \
p_frame_info->crc_original, p_frame_info->crc_calcu_result);
#endif
}
p_frame_info->p_frame_data_start = frame_start_byte+8;
//AES解密
#if MY_TSFC_DEBUG_CHECK_AES
if(my_tsf_frame_head->type==msg_frame)
{
my_tsf_msgframe_t* p_msgframe = (my_tsf_msgframe_t*)p_frame_info->p_frame_start;
if(My_EspAes_InvCipher(my_tsfc_info.aes_ctx, (void*)p_msgframe->data, p_frame_info->data_len, (void*)p_msgframe->data, p_frame_info->data_len))
{
#if MY_TSFC_DEBUG_CHECK_AES
ESP_LOGE("MyTSFC_Rcv_Check_FrameHead()", "error tsf_ackcode_decrypt_error");
return tsf_ackcode_decrypt_error;
#else
ESP_LOGE("MyTSFC_Rcv_Check_FrameHead()", "error tsf_ackcode_decrypt_error, ignore!");
#endif
}
}
else if(my_tsf_frame_head->type==data_frame)
{
my_tsf_dataframe_t* p_dataframe = (my_tsf_dataframe_t*)p_frame_info->p_frame_start;
if(My_EspAes_InvCipher(my_tsfc_info.aes_ctx, (void*)p_dataframe->data, p_frame_info->data_len, (void*)p_dataframe->data, p_frame_info->data_len))
{
#if MY_TSFC_DEBUG_CHECK_AES
ESP_LOGE("MyTSFC_Rcv_Check_FrameHead()", "error tsf_ackcode_decrypt_error");
return tsf_ackcode_decrypt_error;
#else
ESP_LOGE("MyTSFC_Rcv_Check_FrameHead()", "error tsf_ackcode_decrypt_error, ignore!");
#endif
}
}
#endif
return tsf_ackcode_success;
}
static int MyTSFC_Rcv_Frame_Uni_Check(my_tsfc_rcv_frame_info_t* p_frame_info)
{
if((p_frame_info->sn < 8) || (p_frame_info->sn >= 256-8))
{
return 0;
}
uint8_t sn_uni_check = 1;
//检查sn有无重复
int m = 0;
for(m=0; m<MY_TSFC_WINDOWS_SIZE; m++)
{
if(p_frame_info->rcv_windows_posi_mark[m]==p_frame_info->sn)
{
break;
}
}
if(m>=MY_TSFC_WINDOWS_SIZE)
{//窗口内没有重复的sn
sn_uni_check = 0;
if(p_frame_info->rcv_windows_posi_mark_index>=MY_TSFC_WINDOWS_SIZE)
{
p_frame_info->rcv_windows_posi_mark_index = 0;
}
p_frame_info->rcv_windows_posi_mark[p_frame_info->rcv_windows_posi_mark_index]=p_frame_info->sn;
p_frame_info->rcv_windows_posi_mark_index++;
}
else
{
my_tsfc_statistic.error.sn_repeat_error_count++;
ESP_LOGE("MyTSFC_Rcv_Task()", "rcv similar frame_sn=%d, abandon the frame", p_frame_info->sn);
}
return sn_uni_check;
}
接收解包
提取出应用服务层数据
static void MyTSFC_Rcv_Task(void* param)
{
my_whgm5_queue_item_t* p_rcv_buf=NULL;
char* rcv_buf = (char*)calloc(MyTSFC_Rcv_Task_rcvbuf_field_size, sizeof(my_tsf_dataframe_t));
int rcv_len = 0;
int tail_pos = 0;
char* p_frame_start = NULL;
char* p_frame_end = NULL;
char* cur_read_pointer_posi = rcv_buf;
char* p_empty_position = rcv_buf;
char* p_good_bugfix_good_tail_posi = NULL;
int i = 0;
int rcv_frame_count = 0;
my_tsfc_rcv_frame_info_t my_tsfc_rcv_frame_info;
memset(my_tsfc_rcv_frame_info.rcv_windows_posi_mark, -1, sizeof(my_tsfc_rcv_frame_info.rcv_windows_posi_mark));
my_tsfc_rcv_frame_info.rcv_windows_posi_mark_index = 0;
int clear_uni_check_mark = 0;
for(;;)
{
if(my_tsfc_info.tsfc_work_state == TSFC_WORK_STATE_OK)
{
clear_uni_check_mark = 0;
if(!MyWHGM5_TcpRcvData(&p_rcv_buf, portMAX_DELAY))
{
memcpy(p_empty_position, p_rcv_buf->data, p_rcv_buf->len);
rcv_len = p_rcv_buf->len;
p_empty_position+=rcv_len;
do
{
my_tsfc_GOOD_bugfix:
if(p_good_bugfix_good_tail_posi==NULL)
{
tail_pos = MatchString(cur_read_pointer_posi, p_empty_position-cur_read_pointer_posi, MY_TSF_DATAFRAME_TAIL, strlen(MY_TSF_DATAFRAME_TAIL));
}
else
{
tail_pos+=4;
tail_pos += MatchString(p_good_bugfix_good_tail_posi, p_empty_position-p_good_bugfix_good_tail_posi, MY_TSF_DATAFRAME_TAIL, strlen(MY_TSF_DATAFRAME_TAIL));
p_good_bugfix_good_tail_posi = NULL;
}
//if( (p_frame_tail = FindBinary(p_read, remain_len, MY_TSF_DATAFRAME_TAIL, strlen(MY_TSF_DATAFRAME_TAIL)) )!=NULL)MatchString
if(tail_pos!=0xffff)
{
p_frame_start = cur_read_pointer_posi;
p_frame_end = p_frame_start+tail_pos+4;
rcv_frame_count++;
my_tsfc_statistic.down.data_count_total+= (p_frame_end-p_frame_start);
//----------------------
//解析头部
my_tsfc_rcv_frame_info.p_frame_start = p_frame_start;
my_tsfc_rcv_frame_info.frame_len = p_frame_end-p_frame_start;
int err = MyTSFC_Rcv_Check_FrameHead(&my_tsfc_rcv_frame_info);
if(my_tsfc_rcv_frame_info.type==msg_frame||my_tsfc_rcv_frame_info.type==data_frame)
{
if(err!=tsf_ackcode_success)
{
ESP_LOGE("MyTSFC_Rcv_Task()", "Check_FrameHead error, err=0x%x(%d)\n", err, err);
if(err!=tsf_ackcode_frametype_unrecognized)
{
if(err==tsf_ackcode_insufficient_len)
{
p_good_bugfix_good_tail_posi = p_frame_end;
goto my_tsfc_GOOD_bugfix;
}
if(MyTSFC_Ack(my_tsfc_rcv_frame_info.sn, err, 1000, 1, 1))
{
ESP_LOGE("MyTSFC_Rcv_Task()", "MyTSFC_Ack error:\n");
}
}
goto MyTSFC_Rcv_Task_frame_move;
}
int frame_uni_check = MyTSFC_Rcv_Frame_Uni_Check(&my_tsfc_rcv_frame_info);
// frame_uni_check = 0;
if(!frame_uni_check)
{
my_tsfc_rcv_windows_frame_counter++;
my_tsfc_statistic.down.frame_count_type_msg_valid++;
//发送到队列
int find_empty_count = 0;
do
{
for(i=0; i<MY_TSFC_QUEUE_LEN; i++)
{
if(!my_tsfc_rcv_queue_array[i]->valid)
{
int queue_send_ret = pdTRUE;
memcpy(my_tsfc_rcv_queue_array[i]->data, my_tsfc_rcv_frame_info.p_frame_data_start, my_tsfc_rcv_frame_info.data_len);
my_tsfc_rcv_queue_array[i]->len = my_tsfc_rcv_frame_info.data_len;
my_tsfc_rcv_queue_array[i]->my_tsfc_data_type = my_tsfc_rcv_frame_info.type;
my_tsfc_rcv_queue_array[i]->sn = my_tsfc_rcv_frame_info.sn;
my_tsfc_rcv_queue_array[i]->id = 1;
my_tsfc_rcv_queue_array[i]->valid = 1;
queue_send_ret = xQueueSend(my_tsfc_rcv_queue, &my_tsfc_rcv_queue_array[i], 1000 / portTICK_PERIOD_MS);
if(queue_send_ret!=pdTRUE)
{
ESP_LOGE("MyTSFC_Rcv_Task()", "xQueueSend ERROR, queue_send_ret=%d\n", queue_send_ret);
}
break;
}
}
if(i>=MY_TSFC_QUEUE_LEN)
{
ESP_LOGE("MyTSFC_Rcv_Task()", "not find empty in rcv queue count=%d\n", find_empty_count);
vTaskDelay(50 / portTICK_PERIOD_MS);
}
else
{
break;
}
} while ((++find_empty_count<3)&&(i>=MY_TSFC_QUEUE_LEN));
if(find_empty_count>=3)
{
ESP_LOGE("MyTSFC_Rcv_Task()", "not find empty in rcv queue finally!!!\n");
}
else
{
find_empty_count = 0;
}
if(MyTSFC_Ack(my_tsfc_rcv_frame_info.sn, tsf_ackcode_success, 1000, 1, 1))
{
ESP_LOGE("MyTSFC_Rcv_Task()", "msg_frame:ack error:tsf_ackcode_success\n");
}
}
else
{
ESP_LOGE("MyTSFC_Rcv_Task()", "sn_uni_check error!\n");
//暂时处理作 应答 处理成功
if(MyTSFC_Ack(my_tsfc_rcv_frame_info.sn, tsf_ackcode_success, 1000, 1, 1))
{
ESP_LOGE("MyTSFC_Rcv_Task()", "msg_frame:ack error:tsf_ackcode_success\n");
}
}
}
else if(my_tsfc_rcv_frame_info.type==ack_frame)
{
my_tsfc_statistic.down.frame_count_valid++;
my_tsfc_statistic.down.frame_count_type_ack++;
ESP_LOGI("MyTSFC_Rcv_Task()", "-ack_frame-, ack_sn=%d", my_tsfc_rcv_frame_info.sn);
if(my_tsfc_rcv_frame_info.ack_code==tsf_ackcode_success)
{
MyTSFC_ClearWindowAfterAck(my_tsfc_rcv_frame_info.sn);
}
else if(my_tsfc_rcv_frame_info.ack_code==tsf_ackcode_frametype_unrecognized)
{
}
else
{
ESP_LOGE("MyTSFC_Rcv_Task()", "ack_code error=0x%0x, resend_sn=%d!\n", my_tsfc_rcv_frame_info.ack_code, my_tsfc_rcv_frame_info.sn);
int k = 0;
for( ; k<MY_TSFC_WINDOWS_SIZE; k++)
{
if(my_tsfc_rcv_frame_info.sn==my_tsfc_send_windows_array[k]->frame_sn)
{
if(my_tsfc_send_windows_array[k]->state==tsf_win_fps_send_noack)
break;
}
}
if(k<MY_TSFC_WINDOWS_SIZE)
{
if(!MyWHGM5_TcpSendData(my_tsfc_send_windows_array[k]->data, my_tsfc_send_windows_array[k]->data_len, 1000, my_tsfc_send_windows_array[k]->id))
{
ESP_LOGW("MyTSFC_Rcv_Task()", "resend_sn=%d!\n", my_tsfc_rcv_frame_info.sn);
}
else
{
ESP_LOGW("MyTSFC_Rcv_Task()", "failed to resend_sn=%d!\n", my_tsfc_rcv_frame_info.sn);
}
}
else
{
ESP_LOGE("MyTSFC_Rcv_Task()", "not find sn=%d!\n", my_tsfc_rcv_frame_info.sn);
}
}
}
else if(my_tsfc_rcv_frame_info.type==cd_frame)
{
my_tsfc_statistic.down.frame_count_valid++;
my_tsfc_statistic.down.frame_count_type_cc++;
ESP_LOGI("MyTSFC_Rcv_Task()", "-cd_frame-");
//my_tsf_checkcnctframe_t* checkcnct = (my_tsf_checkcnctframe_t*)p_frame_start;
if(MyTSFC_Ack(my_tsfc_rcv_frame_info.sn, tsf_ackcode_success, 1000, 1, 1))
{
ESP_LOGE("MyTSFC_Rcv_Task()", "cd_frame:ack error:tsf_ackcode_success\n");
}
}
MyTSFC_Rcv_Task_frame_move:
cur_read_pointer_posi+=tail_pos+4;
}
else
{
if(p_empty_position>rcv_buf+(MyTSFC_Rcv_Task_rcvbuf_field_size/2)*sizeof(my_tsf_dataframe_t))
{
memset(rcv_buf, 0, cur_read_pointer_posi-rcv_buf);
memcpy(rcv_buf, cur_read_pointer_posi, p_empty_position-cur_read_pointer_posi);
memset(cur_read_pointer_posi, 0, p_empty_position-cur_read_pointer_posi);
p_empty_position = rcv_buf + (p_empty_position-cur_read_pointer_posi);
cur_read_pointer_posi = rcv_buf;
}
else
{
}
break;
}
} while (p_empty_position-cur_read_pointer_posi>0);
if(p_empty_position==cur_read_pointer_posi)
{
memset(rcv_buf, 0, p_empty_position-rcv_buf);
p_empty_position = rcv_buf;
cur_read_pointer_posi = rcv_buf;
}
p_rcv_buf->valid = 0;
}
}
else
{
if(!clear_uni_check_mark)
{
ESP_LOGE("MyTSFC_Rcv_Task()", "connection error, clear rcv_task marks!");
clear_uni_check_mark = 1;
memset(rcv_buf, 0, MyTSFC_Rcv_Task_rcvbuf_field_size*sizeof(my_tsf_dataframe_t));
rcv_len = 0;
tail_pos = 0;
p_frame_start = NULL;
p_frame_end = NULL;
cur_read_pointer_posi = rcv_buf;
p_empty_position = rcv_buf;
i = 0;
// rcv_frame_count = 0;
MyTSFC_Rcv_Frame_Uni_Check_info_clear(&my_tsfc_rcv_frame_info);
}
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
}
应用服务层发送
发送至传输控制层
static void MyASL_Send_Task(void* param)
{
int queue_rcv_ret = pdFALSE;
char* asl_send_buf = (char*)calloc(1, 5120+MY_ASL_PACK_SIZE_MAX+1);
my_asl_queue_t* queue_rcv_item = NULL;
uint32_t data_packager_count = 0;
uint32_t packed_len;
if(asl_send_buf==NULL)
{
ESP_LOGE("MyASL_Send_Task()", "asl_send_buf==NULL\n");
}
for(;;)
{
//队列接收
queue_rcv_ret = xQueueReceive(my_asl_send_queue, &queue_rcv_item, portMAX_DELAY);
if(queue_rcv_ret==pdTRUE)
{
if(queue_rcv_item!=NULL)
{
if(queue_rcv_item->valid)
{
data_packager_count = 0;
if((queue_rcv_item->data!=NULL))
{
do
{
data_packager_count = MyASL_DataBlockTsf_Packager(asl_send_buf, MY_ASL_PACK_SIZE_MAX, queue_rcv_item->data, queue_rcv_item->len, data_packager_count, MY_ASL_PACK_SIZE_MAX, &packed_len);
//发送到传输控制层
if(queue_rcv_item->my_asl_data_type==datablock_tsf)
{
MyTSFC_Send(data_frame, queue_rcv_item->sn, asl_send_buf, packed_len, 1000, 1);
}
else
{
MyTSFC_Send(msg_frame, queue_rcv_item->sn, asl_send_buf, packed_len, 1000, 1);
}
//发送失败将阻塞
} while (data_packager_count<queue_rcv_item->len);
}
//清空队列缓冲区
queue_rcv_item->valid = 0;
//发送完成事件
}
}
else
{
ESP_LOGE("MyASL_Send_Task()", "queue_rcv_item!=NULL is false\n");
}
}
}
}
应用服务层接收
从传输控制层接收
int MyAsl_EventList_Matching(uint8_t* list, uint16_t list_len, uint8_t id)
{
for(int i=0; i<list_len; i++)
{
for(int j=0; j<2; j++)
{
if(*(list+i*2+j)==id)
{
if(j==0)
{
return *(list+i*2+j+1);
}
else if(j==1)
{
return *(list+i*2+j-1);
}
}
}
}
return -1;
}
static void MyASL_Rcv_Task(void* param)
{
my_tsfc_queue_t* p_rcv_buf=NULL;
char* rcv_buf = (char*)calloc(2, 4096);
uint8_t my_asl_eventlist_id_table[20][2];
int i=0;
uint16_t table_len = 0;
my_asl_eventlist_id_table[i][0] = dev_reg_req, my_asl_eventlist_id_table[i][1] = dev_reg_res, i++;
my_asl_eventlist_id_table[i][0] = dev_login_req, my_asl_eventlist_id_table[i][1] = dev_login_res, i++;
my_asl_eventlist_id_table[i][0] = net_time_sync_req, my_asl_eventlist_id_table[i][1] = net_time_sync_res, i++;
my_asl_eventlist_id_table[i][0] = dev_param_req, my_asl_eventlist_id_table[i][1] = dev_param_res, i++;
my_asl_eventlist_id_table[i][0] = dev_param_update_indication, my_asl_eventlist_id_table[i][1] = dev_param_update_res, i++;
my_asl_eventlist_id_table[i][0] = dev_param_query_indication, my_asl_eventlist_id_table[i][1] = dev_param_query_res, i++;
my_asl_eventlist_id_table[i][0] = dev_param_report, my_asl_eventlist_id_table[i][1] = dev_param_report_res, i++;
my_asl_eventlist_id_table[i][0] = dev_ctrl_param_indication, my_asl_eventlist_id_table[i][1] = dev_ctrl_param_res, i++;
my_asl_eventlist_id_table[i][0] = dev_measure_report, my_asl_eventlist_id_table[i][1] = 0, i++;
my_asl_eventlist_id_table[i][0] = dev_event_report, my_asl_eventlist_id_table[i][1] = dev_event_res, i++;
my_asl_eventlist_id_table[i][0] = file_upload_req, my_asl_eventlist_id_table[i][1] = file_upload_res, i++;
my_asl_eventlist_id_table[i][0] = file_down_req, my_asl_eventlist_id_table[i][1] = file_down_res, i++;
my_asl_eventlist_id_table[i][0] = data_direct_tsf_req, my_asl_eventlist_id_table[i][1] = data_direct_tsf_res, i++;
my_asl_eventlist_id_table[i][0] = file_tsf_finish, my_asl_eventlist_id_table[i][1] = 0, i++;
my_asl_eventlist_id_table[i][0] = datablock_tsf, my_asl_eventlist_id_table[i][1] = 0, i++;
table_len = i;
for(;;)
{
MyTSFC_RcvData(&p_rcv_buf, portMAX_DELAY);
memcpy(rcv_buf, p_rcv_buf->data, p_rcv_buf->len);
my_asl_head_t* my_asl_head = (my_asl_head_t*)p_rcv_buf->data;
if(my_asl_head->vercode==0x01)
{
#if DEBUG_PRINT_LEVEL_my_asl_PRINT >= MY_DEBUG_PRINT_LEVEL_1_SIMPLE
ESP_LOGI("MyASL_Rcv_Task()", "my_asl_head->type=%x\n", my_asl_head->type);
#endif
int event_id = MyAsl_EventList_Matching(my_asl_eventlist_id_table, table_len, my_asl_head->type);
if(event_id>=0)
{
uint16_t retcode = my_endian_conversion_16(*((uint16_t*)(p_rcv_buf->data+sizeof(my_asl_head_t))));
if(retcode==aslrc_TokenWrong)
{
if(my_asl_info.MyAslECCB_Callback!=NULL)
{
my_asl_info.MyAslECCB_Callback(retcode);
}
}
my_asl_rcvdata_cache_t* my_asl_rcvdata_cache = (my_asl_rcvdata_cache_t*)MyAslEvent_GetItem_Storage_ById(&my_asl_event_list, event_id);
if(my_asl_rcvdata_cache!=NULL)
{
if(!my_asl_rcvdata_cache->valid)
{
memcpy(my_asl_rcvdata_cache->data, p_rcv_buf->data, p_rcv_buf->len);
my_asl_rcvdata_cache->type = my_asl_head->type;
my_asl_rcvdata_cache->len = p_rcv_buf->len;
}
else
{
ESP_LOGE("MyASL_Rcv_Task()", "my_asl_rcvdata_cache->valid is True");
}
MyAslEvent_Delete(&my_asl_event_list, event_id);
if(my_asl_rcvdata_cache->taskhandle!=NULL)
{
xTaskNotify(my_asl_rcvdata_cache->taskhandle, 1, eSetValueWithOverwrite);
}
else
{
ESP_LOGE("MyASL_Rcv_Task()", "my_asl_rcvdata_cache->taskhandle==NULL");
}
}
else
{
MyASL_DPU_Send(my_asl_head->type, p_rcv_buf->data, p_rcv_buf->len, 5000, 1);
}
}
else
{
ESP_LOGE("MyASL_Rcv_Task()", "not found id=0x%x in my_asl_eventlist_id_table", my_asl_head->type);
}
}
else
{
ESP_LOGE("MyASL_Rcv_Task()", "error:asl protocol version not support=%d, required=%d\n", my_asl_head->vercode, 1);
}
p_rcv_buf->valid = 0;
}
}
工作模式
根据设定,生成从一天0时算起的工作计划时间表,可跨天
根据工作计划表唤醒或进入睡眠
#include "my_workmode.h"
#if MY_WORKMODE_FUNC
#include "my_time.h"
#include "my_lowpower.h"
#include "my_debug.h"
#include <esp_log.h>
my_workmode_info_t my_workmode_info;
int MyWorkmode_WorkList_To_SleepList(workplan_list_item_t* p_worklist, int workplan_num, sleepplan_list_item_t* p_sleeplist, int sleepplan_num)
{
if(p_worklist==NULL)
{
ESP_LOGE("WorkList_To_SleepList()", "p_worklist==NULL");
return -1;
}
if(p_sleeplist==NULL)
{
ESP_LOGE("WorkList_To_SleepList()", "p_sleeplist==NULL");
return -1;
}
if(sleepplan_num<workplan_num)
{
ESP_LOGE("WorkList_To_SleepList()", "sleepplan_num<workplan_num");
return -11;
}
if(workplan_num<=0)
{
ESP_LOGE("WorkList_To_SleepList()", "workplan_num<=0");
return -12;
}
//将工作表按开始时间排序
workplan_list_item_t workplan_temp;
for(int j=0; j<workplan_num-1; j++)
{
for(int i=j+1; i<workplan_num; i++)
{
if((p_worklist+j)->work_start_time > (p_worklist+i)->work_start_time)
{
workplan_temp.work_start_time = (p_worklist+i)->work_start_time;
workplan_temp.work_end_time = (p_worklist+i)->work_end_time;
(p_worklist+i)->work_start_time = (p_worklist+j)->work_start_time;
(p_worklist+i)->work_end_time = (p_worklist+j)->work_end_time;
(p_worklist+j)->work_start_time = workplan_temp.work_start_time;
(p_worklist+j)->work_end_time = workplan_temp.work_end_time;
}
}
}
//计算睡眠列表
for(int i=0; i<workplan_num; i++)
{
//睡眠开始时间就是工作结束时间
(p_sleeplist+i)->sleep_start_time = (p_worklist+i)->work_end_time;
//根据前workplan_num-1项工作计划计算出对应的睡眠计划
if(i<workplan_num-1)
{
//没有跨天
if((p_worklist+i)->work_end_time - (p_worklist+i)->work_start_time > 0)
{
//workplan_num+1项的开始时间大于workplan_num项的结束时间才会计算睡眠保持时间,否则将这项工作计划对应的睡眠计划置零
if((p_worklist+i+1)->work_start_time - (p_worklist+i)->work_end_time > 0)
{
(p_sleeplist+i)->sleep_keep_time = (p_worklist+i+1)->work_start_time - (p_worklist+i)->work_end_time;
}
else
{
(p_sleeplist+i)->sleep_start_time = 0;
(p_sleeplist+i)->sleep_keep_time = 0;
}
}
else
{
//貌似不需要这个分支,因为若出现跨天的情况,经过前一步的 对工作表排序后,跨天的那一项总是在工作表的最后一项,不会到上一层if中来
}
}
//工作表的第根据前workplan_num项,也就是最后一项
else
{
//没有跨天
if((p_worklist+i)->work_end_time - (p_worklist+i)->work_start_time > 0)
{
//检查这个工作表中有几项有效的计划
int n = 0;
int y = 0;
for(n=0; n<workplan_num; n++)
{
if(((p_worklist+n)->work_end_time!=0)&&((p_worklist+n)->work_start_time!=0))
{
y++;
}
}
//只有一项,其他都是0
if(y==1)
{
//睡眠时间是一天的秒数减去工作表中仅有的一项工作计划的结束时间再加上这项计划自己的开始时间
(p_sleeplist+i)->sleep_keep_time = 24*3600-(p_worklist+i)->work_end_time + (p_worklist+i)->work_start_time;
}
//有多项计划
else
{
//找出工作表中开始时间最小的那项计划的开始时间
int32_t min_start_time = 86400+1;
for(int m=0; m<workplan_num; m++)
{
if((p_worklist+m)->work_end_time - (p_worklist+m)->work_start_time > 0)
{
if(min_start_time > (p_worklist+m)->work_start_time)
{
min_start_time = (p_worklist+m)->work_start_time;
}
}
}
//睡眠时间是一天的秒数减去工作表最后一项工作计划的结束时间加上工作表最早开始的计划的开始时间
(p_sleeplist+i)->sleep_keep_time = 24*3600-(p_worklist+i)->work_end_time + min_start_time;
}
}
//最后一项计划跨天了
else if((p_worklist+i)->work_end_time - (p_worklist+i)->work_start_time < 0)
{
//检查这个工作表中有几项有效的计划
int n = 0;
int y = 0;
for(n=0; n<workplan_num; n++)
{
if(((p_worklist+n)->work_end_time!=0)&&((p_worklist+n)->work_start_time!=0))
{
y++;
}
}
//只有一项,其他都是0
if(y==1)
{
//睡眠时间是工作表中仅有的一项工作计划的开始时间再加上这项计划自己的结束时间,因为跨天肯定是开始时间比结束时间秒数大
//除非跨天之后又垮了24*3600秒,那将会导致这个式子计算出的结果很大!!!
(p_sleeplist+i)->sleep_keep_time = (p_worklist+i)->work_start_time - (p_worklist+i)->work_end_time;
}
//有多项计划
else
{
//找出工作表中开始时间最小的那项计划的开始时间
int32_t min_start_time = 86400+1;
for(int m=0; m<workplan_num; m++)
{
if((p_worklist+m)->work_end_time - (p_worklist+m)->work_start_time > 0)
{
if(min_start_time > (p_worklist+m)->work_start_time)
{
min_start_time = (p_worklist+m)->work_start_time;
}
}
}
//和前面一样,仍需要判断最早开始时间是否晚于本项计划的结束时间
if(min_start_time - (p_worklist+i)->work_end_time > 0)
{
//睡眠时间是工作表中最早开始的那项计划的开始时间减去跨天后的结束时间
(p_sleeplist+i)->sleep_keep_time = min_start_time - (p_worklist+i)->work_end_time;
}
else
{
(p_sleeplist+i)->sleep_start_time = 0;
(p_sleeplist+i)->sleep_keep_time = 0;
}
}
}
else if((p_worklist+i)->work_end_time - (p_worklist+i)->work_start_time == 0)
{
(p_sleeplist+i)->sleep_start_time = 0;
(p_sleeplist+i)->sleep_keep_time = 0;
}
}
}
//合并睡眠表中的跨天分割,间隙为0的,相邻两项(这一步要不要无所谓)
for(int i=0; i<workplan_num; i++)
{
if((p_sleeplist+i)->sleep_start_time + (p_sleeplist+i)->sleep_keep_time == 24*3600)
{
for(int j=0; j<workplan_num; j++)
{
if(((p_sleeplist+j)->sleep_start_time==0)&&((p_sleeplist+j)->sleep_keep_time>0))
{
(p_sleeplist+i)->sleep_keep_time += (p_sleeplist+j)->sleep_keep_time;
(p_sleeplist+j)->sleep_keep_time = 0;
}
}
}
}
return 0;
}
static int MyWorkmode_PickSleepKeepTime_Afterfirstpoweron(my_workmode_conf_t* conf)
{
time_t cur_time_in_day = MyTime_GetTime()%(3600*24);
ESP_LOGI("MyWorkmode_PickSleepKeepTime_Afterfirstpoweron()", "cur_time_in_day=%ld\n", cur_time_in_day);
//若当前时间处于工作时段,则直接将fisrt_poweron_sleep_keep_time置零
for(int i=0; i<5; i++)
{
if(( (conf->workplan_list+i)->work_start_time > 0 ) && ( (conf->workplan_list+i)->work_end_time > 0 ) )
{
if( (conf->workplan_list+i)->work_end_time - (conf->workplan_list+i)->work_start_time > 0 )
{
if( (cur_time_in_day >= (conf->workplan_list+i)->work_start_time) && \
(cur_time_in_day < (conf->workplan_list+i)->work_end_time))
{
conf->fisrt_poweron_sleep_keep_time = 0;
return 0;
}
}
else if( (conf->workplan_list+i)->work_start_time - (conf->workplan_list+i)->work_end_time > 0 )
{
if( (cur_time_in_day >= (conf->workplan_list+i)->work_start_time) || \
(cur_time_in_day < (conf->workplan_list+i)->work_end_time) )
{
conf->fisrt_poweron_sleep_keep_time = 0;
return 0;
}
}
}
}
//来到这里说明当前时间不在工作时段
//查找有无跨天工作计划
int i_ftdp = 0;
for(i_ftdp=0; i_ftdp<5; i_ftdp++)
{
if(( (conf->workplan_list+i_ftdp)->work_start_time > 0 ) && ( (conf->workplan_list+i_ftdp)->work_end_time > 0 ) )
{
if( (conf->workplan_list+i_ftdp)->work_start_time - (conf->workplan_list+i_ftdp)->work_end_time > 0 )
{
break;
}
}
}
//工作表中无跨天工作计划
if(i_ftdp>=5)
{
//找到工作表中在一天之内最后结束的那项计划的结束时间
int32_t max_end_time = 0;
for(int m=0; m<5; m++)
{
if(( (conf->workplan_list+m)->work_start_time > 0 ) && ( (conf->workplan_list+m)->work_end_time > 0 ) )
{
if((conf->workplan_list+m)->work_end_time > max_end_time)
{
max_end_time = (conf->workplan_list+m)->work_end_time;
}
}
}
//当前时间超过了一天之内最晚结束的那项工作计划的结束时间(隐藏成立:肯定没超过凌晨,若超过凌晨,条件不可能成立)
if(cur_time_in_day > max_end_time)
{
//查找工作表中一天内最早开始的那项计划的开始时间
int32_t min_start_time = 86400+1;
for(int m=0; m<5; m++)
{
if(( (conf->workplan_list+m)->work_start_time > 0 ) && ( (conf->workplan_list+m)->work_end_time > 0 ) )
{
if((conf->workplan_list+m)->work_start_time < min_start_time)
{
min_start_time = (conf->workplan_list+m)->work_start_time;
}
}
}
//fisrt_poweron_sleep_keep_time一天的秒数减去当前时间再加上一天中最早那项计划的开始时间
conf->fisrt_poweron_sleep_keep_time = 24*3600 - cur_time_in_day + min_start_time;
return 0;
}
//当前时间没有超过一天之内最晚结束的那项工作计划的结束时间
else
{
//在工作表中查找下一项最早的计划,以当前时间为参考
int32_t next_min_start_time = 86400+1;
for(int m=0; m<5; m++)
{
if(( (conf->workplan_list+m)->work_start_time > 0 ) && ( (conf->workplan_list+m)->work_end_time > 0 ) )
{
if((conf->workplan_list+m)->work_start_time > cur_time_in_day)
{
if((conf->workplan_list+m)->work_start_time < next_min_start_time)
{
next_min_start_time = (conf->workplan_list+m)->work_start_time;
}
}
}
}
if(cur_time_in_day<next_min_start_time)
{
//计算fisrt_poweron_sleep_keep_time距离下一项计划开始的时间
conf->fisrt_poweron_sleep_keep_time = next_min_start_time - cur_time_in_day;
}
else
{
//不应该到达这里
conf->fisrt_poweron_sleep_keep_time = 0;
ESP_LOGE("MyWorkmode_PickSleepKeepTime_Afterfirstpoweron()", "error2");
}
return 0;
}
//不应该到达这里
return 0;
}
//工作表中有跨天工作计划
else
{
//找出跨天计划
int frdp_index = 0;
for(frdp_index=0; frdp_index<5; frdp_index++)
{
if((conf->workplan_list+frdp_index)->work_start_time - (conf->workplan_list+frdp_index)->work_end_time > 0)
{
break;
}
}
//如果当前时间在跨天计划结束之后,(隐藏成立:当前时间肯定不在工作时段之内)
if(cur_time_in_day>(conf->workplan_list+frdp_index)->work_end_time)
{
//在工作表中查找下一项最早的计划,以当前时间为参考
int32_t next_min_start_time = 86400+1;
for(int m=0; m<5; m++)
{
if((conf->workplan_list+m)->work_start_time > cur_time_in_day)
{
if((conf->workplan_list+m)->work_start_time < next_min_start_time)
{
next_min_start_time = (conf->workplan_list+m)->work_start_time;
}
}
}
if(cur_time_in_day<next_min_start_time)
{
//计算fisrt_poweron_sleep_keep_time距离下一项计划开始的时间
conf->fisrt_poweron_sleep_keep_time = next_min_start_time - cur_time_in_day;
}
else
{
//不应该到达这里
conf->fisrt_poweron_sleep_keep_time = 0;
ESP_LOGE("MyWorkmode_PickSleepKeepTime_Afterfirstpoweron()", "error2");
}
return 0;
}
else if(cur_time_in_day<(conf->workplan_list+frdp_index)->work_start_time)
{
//不应该到达这里
//不需要这个分支,因为跨天的结束时间肯定是整个工作表中最早的时间,跨天工作计划的开始时间肯定是整个工作表中最晚的时间
//所以:如果当前时间既不在工作计划内,又小于跨天计划的开始时间,那么肯定会进入上一个分支。
}
else
{
//不应该到达这里
}
}
ESP_LOGE("MyWorkmode_PickSleepKeepTime_Afterfirstpoweron()", "error3");
conf->fisrt_poweron_sleep_keep_time = 0;
return 0;
}
int MyWorkmode_Check_WhetherInWorktime(my_workmode_conf_t* conf)
{
int ret = 0;
time_t cur_time_in_day = MyTime_GetTime()%(3600*24);
// ESP_LOGI("MyWorkmode_Check_WhetherInWorktime()", "cur_time_in_day=%ld\n", cur_time_in_day);
int zero_check_index=0;
for(zero_check_index=0; zero_check_index<5; zero_check_index++)
{
if(( (conf->workplan_list+zero_check_index)->work_start_time != 0 ) && ( (conf->workplan_list+zero_check_index)->work_end_time != 0 ) )
{
break;
}
}
if(zero_check_index==5)
{
return 1;
}
//若当前时间处于工作时段,则直接将fisrt_poweron_sleep_keep_time置零
for(int i=0; i<5; i++)
{
if(( (conf->workplan_list+i)->work_start_time > 0 ) && ( (conf->workplan_list+i)->work_end_time > 0 ) )
{
if( (conf->workplan_list+i)->work_end_time - (conf->workplan_list+i)->work_start_time > 0 )
{
if( (cur_time_in_day >= (conf->workplan_list+i)->work_start_time) && \
(cur_time_in_day < (conf->workplan_list+i)->work_end_time))
{
conf->fisrt_poweron_sleep_keep_time = 0;
ret = 1;
goto MyWorkmode_Check_WhetherInWorktime_goto;
}
}
else if( (conf->workplan_list+i)->work_start_time - (conf->workplan_list+i)->work_end_time > 0 )
{
if( (cur_time_in_day >= (conf->workplan_list+i)->work_start_time) || \
(cur_time_in_day < (conf->workplan_list+i)->work_end_time) )
{
conf->fisrt_poweron_sleep_keep_time = 0;
ret = 1;
goto MyWorkmode_Check_WhetherInWorktime_goto;
}
}
}
}
//来到这里说明当前时间不在工作时段
MyWorkmode_Check_WhetherInWorktime_goto:
if(ret)
{
// ESP_LOGI("MyWorkmode_Check_WhetherInWorktime()", "It's working time\n");
}
else
{
// ESP_LOGI("MyWorkmode_Check_WhetherInWorktime()", "It's not working time\n");
}
return ret;
}
int MyWorkmode_Check(void)
{
time_t cur_time_in_day = MyTime_GetTime()%(3600*24);
uint32_t sleep_keep_time = 0;
uint8_t wakeup_reason = MYLOWPOWER_WAKEUP_TYPE_NO_SLEEP;
switch(my_workmode_info.conf.workmode)
{
int i=0;
case(workmode_standby):break;
case(workmode1_realtime):break;
case(workmode2_semirealtime):
for(i=0; i<5; i++)
{
if((my_workmode_info.conf.sleepplan_list[i].sleep_start_time>0) && (my_workmode_info.conf.sleepplan_list[i].sleep_keep_time>0))
{
if(my_workmode_info.conf.sleepplan_list[i].sleep_start_time + my_workmode_info.conf.sleepplan_list[i].sleep_keep_time < 24*3600)
{
if( ( cur_time_in_day >= my_workmode_info.conf.sleepplan_list[i].sleep_start_time ) && \
( cur_time_in_day < my_workmode_info.conf.sleepplan_list[i].sleep_start_time + my_workmode_info.conf.sleepplan_list[i].sleep_keep_time ) )
{
sleep_keep_time = my_workmode_info.conf.sleepplan_list[i].sleep_keep_time - (cur_time_in_day - my_workmode_info.conf.sleepplan_list[i].sleep_start_time);
break;
}
}
else
{
if( ( ( cur_time_in_day >= my_workmode_info.conf.sleepplan_list[i].sleep_start_time ) && (cur_time_in_day<24*3600) ) )
{
sleep_keep_time = my_workmode_info.conf.sleepplan_list[i].sleep_keep_time - (cur_time_in_day - my_workmode_info.conf.sleepplan_list[i].sleep_start_time);
break;
}
else if( cur_time_in_day < my_workmode_info.conf.sleepplan_list[i].sleep_keep_time-(24*3600-my_workmode_info.conf.sleepplan_list[i].sleep_start_time) )
{
sleep_keep_time = my_workmode_info.conf.sleepplan_list[i].sleep_keep_time - (cur_time_in_day + 24*3600 - my_workmode_info.conf.sleepplan_list[i].sleep_start_time);
break;
}
}
}
}
ESP_LOGI("MyWorkmode_Check(workmode2_semirealtime)", "i=%d, sleep_keep_time=%ds", i, sleep_keep_time);
break;
case(workmode_energy_saving):
ESP_LOGI("MyWorkmode_Check(workmode3_timer)", "workmode_energy_saving");
case(workmode3_timer):
sleep_keep_time = my_workmode_info.conf.workmode3_timer_sleep_keep_time;
ESP_LOGI("MyWorkmode_Check(workmode3_timer)", "sleep_keep_time=%ds", sleep_keep_time);
break;
case(workmode4_semitimer):
for(i=0; i<5; i++)
{
if((my_workmode_info.conf.sleepplan_list[i].sleep_start_time>0) && (my_workmode_info.conf.sleepplan_list[i].sleep_keep_time>0))
{
if(my_workmode_info.conf.sleepplan_list[i].sleep_start_time + my_workmode_info.conf.sleepplan_list[i].sleep_keep_time < 24*3600)
{
if( ( cur_time_in_day >= my_workmode_info.conf.sleepplan_list[i].sleep_start_time ) && \
( cur_time_in_day < my_workmode_info.conf.sleepplan_list[i].sleep_start_time + my_workmode_info.conf.sleepplan_list[i].sleep_keep_time ) )
{
sleep_keep_time = my_workmode_info.conf.sleepplan_list[i].sleep_keep_time - (cur_time_in_day - my_workmode_info.conf.sleepplan_list[i].sleep_start_time);
break;
}
}
else
{
if( ( ( cur_time_in_day >= my_workmode_info.conf.sleepplan_list[i].sleep_start_time ) && (cur_time_in_day<24*3600) ) )
{
sleep_keep_time = my_workmode_info.conf.sleepplan_list[i].sleep_keep_time - (cur_time_in_day - my_workmode_info.conf.sleepplan_list[i].sleep_start_time);
break;
}
else if( cur_time_in_day < my_workmode_info.conf.sleepplan_list[i].sleep_keep_time-(24*3600-my_workmode_info.conf.sleepplan_list[i].sleep_start_time) )
{
sleep_keep_time = my_workmode_info.conf.sleepplan_list[i].sleep_keep_time - (cur_time_in_day + 24*3600 - my_workmode_info.conf.sleepplan_list[i].sleep_start_time);
break;
}
}
}
}
if(i>=5)
{
if(my_workmode_info.conf.workmode3_timer_sleep_keep_time>0)
{
sleep_keep_time = my_workmode_info.conf.workmode3_timer_sleep_keep_time;
}
}
ESP_LOGI("MyWorkmode_Check(workmode4_semitimer)", "i=%d, sleep_keep_time=%ds", i, sleep_keep_time);
break;
}
ESP_LOGI("MyWorkmode_Check()", "final sleep_keep_time=%ds", sleep_keep_time);
if(sleep_keep_time>0)
{
if(sleep_keep_time > MYWORKMODE_ONCE_SLEEP_TIME_ULIMIT)
{
sleep_keep_time = MYWORKMODE_ONCE_SLEEP_TIME_ULIMIT;
}
my_workmode_info.MyLowPower_Init_BeforeSleep();
MyTime_PrintTime();
wakeup_reason = MyLowPower_EnterLightSleepFor(sleep_keep_time);
MyTime_PrintTime();
my_workmode_info.MyLowPower_Init_AfterWakeup(wakeup_reason);
}
if(wakeup_reason!=MYLOWPOWER_WAKEUP_TYPE_NO_SLEEP)
{
}
return wakeup_reason;
}
void MyWorkmode_CallbackRegister_MyLowPower_Init_BeforeWakeup(void (*callback_func_beforesleep)(void))
{
my_workmode_info.MyLowPower_Init_BeforeSleep = callback_func_beforesleep;
}
void MyWorkmode_CallbackRegister_MyLowPower_Init_AfterWakeup(void (*callback_func_aftersleep)(int))
{
my_workmode_info.MyLowPower_Init_AfterWakeup = callback_func_aftersleep;
}
int MyWorkmode_Init(my_workmode_conf_t* conf, void (*callback_func_beforesleep)(void), void (*callback_func_aftersleep)(int))
{
MyWorkmode_WorkList_To_SleepList(conf->workplan_list, 5, conf->sleepplan_list, 5);
MyWorkmode_PickSleepKeepTime_Afterfirstpoweron(conf);
if(conf!=NULL)
{
memcpy(&my_workmode_info.conf, conf, sizeof(my_workmode_info.conf));
}
else
{
my_workmode_info.conf.workmode = myworkmode_workmode_default;
}
if(callback_func_beforesleep!=NULL)
{
MyWorkmode_CallbackRegister_MyLowPower_Init_BeforeWakeup(callback_func_beforesleep);
}
if(callback_func_aftersleep!=NULL)
{
MyWorkmode_CallbackRegister_MyLowPower_Init_AfterWakeup(callback_func_aftersleep);
}
return 0;
}
int MyWorkmode_ReLoad_Conf(my_workmode_conf_t* conf)
{
return MyWorkmode_Init(conf, NULL, NULL);
}
my_workmode_t MyWorkmode_GetCurrentWorkmode(void)
{
return my_workmode_info.conf.workmode;
}
#endif