310 lines
9.1 KiB
C
310 lines
9.1 KiB
C
/*********************************************************************************************
|
|
* 本文件仅仅用于低功耗休眠恢复的一些demo,不是完整的,更多的应用休眠和恢复要根据实际应用逻辑和硬件
|
|
* 去实现,demo有部分说明
|
|
********************************************************************************************/
|
|
|
|
#include "sys_config.h"
|
|
#include "typesdef.h"
|
|
#include "list.h"
|
|
#include "dev.h"
|
|
#include "devid.h"
|
|
#include "osal/string.h"
|
|
#include "osal/task.h"
|
|
#include "audio_app/audio_adc.h"
|
|
#include "audio_app/audio_dac.h"
|
|
#include "lib/video/dvp/cmos_sensor/csi.h"
|
|
#include "hal/jpeg.h"
|
|
#include "lib/video/dvp/jpeg/jpg.h"
|
|
#include "osal/msgqueue.h"
|
|
#include "osal/sleep.h"
|
|
#include "osal/semaphore.h"
|
|
#if LOWPOWER_DEMO == 1
|
|
#ifdef CONFIG_SLEEP
|
|
#include "lib/lmac/lmac_dsleep.h"
|
|
#include "lib/common/dsleepdata.h"
|
|
#endif
|
|
#include "lib/net/eloop/eloop.h"
|
|
|
|
#include "stream_frame.h"
|
|
#include "app_lcd/osd_encode_stream.h"
|
|
|
|
#ifdef CONFIG_SLEEP
|
|
|
|
//休眠定时器起来,如果需要添加io唤醒,需要自行修改
|
|
//默认用了保活方式,所以需要连接路由器成功后才会休眠
|
|
void sleep_test(uint32_t time)
|
|
{
|
|
uint32 sleep_type = 1;
|
|
struct system_sleep_param args;
|
|
memset(&args,0,sizeof(args));
|
|
args.sleep_ms = time;
|
|
//args.wkup_io_sel[0] = PA_13;//LP Module PA_8
|
|
args.wkup_io_edge = 0x00;//0: Rising; 1:Falling Edge
|
|
args.wkup_io_en = 0x00;//IO0 En
|
|
os_printf("%s:%d\tenter sleep\n",__FUNCTION__,__LINE__);
|
|
system_sleep(sleep_type, &args);
|
|
}
|
|
|
|
|
|
|
|
static void enter_lowpower_timer(struct event *ei, void *d)
|
|
{
|
|
uint32_t time = (uint32_t)d;
|
|
os_printf("%s:%d\ttime:%d\n",__FUNCTION__,__LINE__,time);
|
|
//进入休眠,休眠500ms起来
|
|
sleep_test(time);
|
|
}
|
|
|
|
|
|
|
|
//恢复顺序根据硬件以及程序逻辑去适配(比如io复用之类都要考虑)
|
|
void lowPower_resume_task(void *d)
|
|
{
|
|
//uint32_t flags;
|
|
struct os_msgqueue *msgq = (struct os_msgqueue *)d;
|
|
uint32_t res = os_msgq_get(msgq,-1);
|
|
//收到信号量,恢复对应的硬件
|
|
if(res)
|
|
{
|
|
|
|
//usb u盘的恢复
|
|
#if USB_EN
|
|
#ifdef RT_USBH
|
|
hg_usbh_register(HG_USB_HOST_CONTROLLER_DEVID);
|
|
#endif
|
|
#endif
|
|
|
|
//lcd相关恢复,由于恢复与儿童相机的原框架不匹配,这里只是对lcd简单恢复,没有任何应用恢复
|
|
#if LVGL_STREAM_ENABLE == 1 && LCD_EN == 1
|
|
uint16_t w,h;
|
|
uint16_t screen_w,screen_h;
|
|
uint8_t rotate,video_rotate;
|
|
stream *s1 = get_stream_available(R_OSD_ENCODE);
|
|
stream *s2 = get_stream_available(R_OSD_SHOW);
|
|
extern void lcd_driver_reinit();
|
|
extern void lcd_hardware_init(uint16_t *w,uint16_t *h,uint8_t *rotate,uint16_t *screen_w,uint16_t *screen_h,uint8_t *video_rotate);
|
|
lcd_hardware_init(&w,&h,&rotate,&screen_w,&screen_h,&video_rotate);
|
|
lcd_driver_reinit();
|
|
stream_self_cmd_func(s1, OSD_HARDWARE_STREAM_RESET, 0);
|
|
close_stream(s1);
|
|
close_stream(s2);
|
|
lvgl_hdl_resume();
|
|
#endif
|
|
|
|
|
|
//这里是dvp恢复
|
|
#if JPG_EN
|
|
jpg_cfg(HG_JPG0_DEVID,VPP_DATA0);
|
|
#endif
|
|
#if DVP_EN
|
|
bool csi_cfg();
|
|
bool csi_open();
|
|
csi_cfg();
|
|
csi_open();
|
|
#endif
|
|
|
|
//恢复sd
|
|
#if SDH_EN && FS_EN
|
|
extern bool fatfs_register();
|
|
fatfs_register();
|
|
#endif
|
|
}
|
|
|
|
|
|
//释放空间
|
|
os_msgq_del(msgq);
|
|
os_free(msgq);
|
|
}
|
|
|
|
static uint8_t suspend_flag = 0;
|
|
static struct os_msgqueue *msgq = NULL;
|
|
//开始进入低功耗模式,首先将自己应用层的资源释放,创建一个高优先级的线程,主要用于低功耗唤醒后,可以第一时间快速恢复外部硬件
|
|
void lowPower_start()
|
|
{
|
|
if(suspend_flag)
|
|
{
|
|
return;
|
|
}
|
|
os_printf("%s:%d\n",__FUNCTION__,__LINE__);
|
|
|
|
//lcd的休眠,如果硬件有特殊,需要额外处理
|
|
#if LVGL_STREAM_ENABLE == 1 && LCD_EN == 1
|
|
lvgl_hdl_suspend();
|
|
wait_lcd_exit();
|
|
#endif
|
|
|
|
|
|
//u盘恢复
|
|
#if USB_EN
|
|
#ifdef RT_USBH
|
|
hg_usbh_unregister(HG_USB_HOST_CONTROLLER_DEVID);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
//卸载文件系统
|
|
#if SDH_EN && FS_EN
|
|
fatfs_unregister();
|
|
#endif
|
|
|
|
|
|
//开始主动关闭硬件以及硬件模块,外围硬件需要自己去关闭
|
|
os_printf("%s:%d\n",__FUNCTION__,__LINE__);
|
|
#if DVP_EN
|
|
struct vpp_device *vpp = (struct vpp_device *)dev_get(HG_VPP_DEVID);
|
|
struct dvp_device *dvp= (struct dvp_device *)dev_get(HG_DVP_DEVID);
|
|
dvp_close(dvp);
|
|
vpp_close(vpp);
|
|
#endif
|
|
os_printf("%s:%d\n",__FUNCTION__,__LINE__);
|
|
#if JPG_EN
|
|
jpg_clear_init_flag(0);
|
|
#endif
|
|
msgq = (struct os_msgqueue *)os_malloc(sizeof(struct os_msgqueue));
|
|
memset(msgq,0,sizeof(struct os_msgqueue));
|
|
os_msgq_init(msgq,1);
|
|
//创建线程任务
|
|
suspend_flag = 1;
|
|
os_task_create("resume", lowPower_resume_task, (void*)msgq, OS_TASK_PRIORITY_ABOVE_NORMAL, 0, NULL, 1024);
|
|
//os_msgq_put(msgq,msgq,0);
|
|
}
|
|
|
|
void lowPower_task_wakeup()
|
|
{
|
|
suspend_flag = 0;
|
|
os_msgq_put(msgq,msgq,0);
|
|
}
|
|
|
|
|
|
|
|
//应用层的休眠唤醒回调函数,所有操作在上面几个函数实现,不同应用实现不一样,所以上面的函数根据自己应用作改动
|
|
int32 app_sleepcb(uint16_t type, struct sys_sleepcb_param *args, void *priv)
|
|
{
|
|
uint8_t action = args->action;
|
|
uint8_t step = args->step;
|
|
uint8_t reason = args->resume.wkreason;
|
|
switch(action)
|
|
{
|
|
case SYS_SLEEPCB_ACTION_SUSPEND:
|
|
if(step == SYS_SLEEPCB_APP)
|
|
{
|
|
lowPower_start();
|
|
}
|
|
break;
|
|
case SYS_SLEEPCB_ACTION_RESUME:
|
|
if(step == SYS_SLEEPCB_APP)
|
|
{
|
|
//注意这里需要判断一下唤醒的原因,由于这里是demo,所有的原因都会唤醒
|
|
//if(reason == DSLEEP_WK_REASON_WK_DATA)
|
|
{
|
|
lowPower_task_wakeup();
|
|
}
|
|
|
|
}
|
|
break;
|
|
}
|
|
return RET_OK;
|
|
}
|
|
|
|
//这个返回1代表收到需要的数据,会唤醒,原因是DSLEEP_WK_REASON_WK_DATA
|
|
//返回0就不是匹配数据,会继续休眠
|
|
|
|
//这里demo只是检测到tcp就唤醒,如果自己的应用,还需要判断数据是否匹配等
|
|
//还有就是tcp即使不是数据包,可能也要唤醒,需要维持tcp的连接
|
|
int32 user_check_data(void *usr_wkdet_priv, uint8 *data, uint32 len)
|
|
{
|
|
//tcp的长度会超过10
|
|
if(len >= 10)
|
|
{
|
|
//判断一下是否为tcp,简单去处理了,tcp就回应一个心跳包,实际应用可能还要判断一下是否为自己需要的ip
|
|
//应用层就是唤醒后就去写卡 dvp 录像之类
|
|
if(data[9] == 0x06)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//应用层低功耗初始化
|
|
void app_lowpower_init()
|
|
{
|
|
sys_register_sleepcb(app_sleepcb,NULL);
|
|
dsleep_set_usr_wkdet_cb(NULL, user_check_data);
|
|
|
|
//定时休眠
|
|
eloop_add_timer(5000,EVENT_F_ENABLED,enter_lowpower_timer,(void*)5000);
|
|
}
|
|
|
|
|
|
|
|
|
|
static int32 app_sleepcb_test(uint16_t type, struct sys_sleepcb_param *args, void *priv)
|
|
{
|
|
uint8_t action = args->action;
|
|
uint8_t step = args->step;
|
|
uint8_t reason = args->resume.wkreason;
|
|
switch(action)
|
|
{
|
|
//低功耗休眠的时候会调用的接口,这里处理完毕后,尽量保证自己的线程不要再运行或者不要运行一些外设网络的东西
|
|
case SYS_SLEEPCB_ACTION_SUSPEND:
|
|
if(step == SYS_SLEEPCB_APP)
|
|
{
|
|
os_printf("##########################enter %s:%d\n",__FUNCTION__,__LINE__);
|
|
}
|
|
break;
|
|
|
|
//低功耗恢复,这里恢复可以是别原因,APP只会调用一次才对
|
|
case SYS_SLEEPCB_ACTION_RESUME:
|
|
if(step == SYS_SLEEPCB_APP)
|
|
{
|
|
//注意这里需要判断一下唤醒的原因,由于这里是demo,所有的原因都会唤醒
|
|
//if(reason == DSLEEP_WK_REASON_WK_DATA)
|
|
{
|
|
os_printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$exit %s:%d\n",__FUNCTION__,__LINE__);
|
|
}
|
|
|
|
}
|
|
break;
|
|
}
|
|
return RET_OK;
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************
|
|
* type:
|
|
typedef enum {
|
|
SYSTEM_SLEEP_TYPE_SRAM_WIFI = 1,
|
|
SYSTEM_SLEEP_TYPE_WIFI_DSLEEP = 2,
|
|
SYSTEM_SLEEP_TYPE_SRAM_ONLY = 3,
|
|
SYSTEM_SLEEP_TYPE_LIGHT_SLEEP = 4,
|
|
SYSTEM_SLEEP_TYPE_RTCC = 5,
|
|
SYSTEM_SLEEP_TYPE_MAX = 6,
|
|
} SYSTEM_SLEEP_TYPE;
|
|
|
|
time:代表休眠多久时间后唤醒
|
|
* ******************************************************************/
|
|
//测试的时候可以将type设置为3(SYSTEM_SLEEP_TYPE_SRAM_ONLY),不需要连接wifi
|
|
void enter_sleep_test(uint32_t type,uint32_t time)
|
|
{
|
|
uint32 sleep_type = type;
|
|
struct system_sleep_param args;
|
|
memset(&args,0,sizeof(args));
|
|
args.sleep_ms = time;
|
|
//args.wkup_io_sel[0] = PA_13;//LP Module PA_8
|
|
args.wkup_io_edge = 0x00;//0: Rising; 1:Falling Edge
|
|
args.wkup_io_en = 0x00;//IO0 En
|
|
os_printf("%s:%d\tenter sleep\n",__FUNCTION__,__LINE__);
|
|
system_sleep(sleep_type, &args);
|
|
}
|
|
|
|
|
|
//内部测试低功耗使用
|
|
void lowpoer_sleep_test_init()
|
|
{
|
|
sys_register_sleepcb(app_sleepcb_test,NULL);
|
|
}
|
|
#endif
|
|
#endif |