/**
*@file    sr_ota.c
*@brief   ota组件接口
*@details 提供初始化、启动OTA等基本接口
*@copyright Copyright (c) 2024 lierda. All rights reserved.
*@author  Lierda-RDC
*@date    2024-05-07
*@example ZhaoyangSDK\example\component\ota_example.c
*/

#include "sr_ota.h"
#include "sr_log.h"
#include "cmsis_os2.h"

static SR_OTA_MNG_T g_otaMng;


//http事件回调
static void _OtaHttpEventCb(SR_HTTP_CLIENT_T *httpc,void *args,SR_HTTP_EVT_E event,char *data, uint32_t dataLen)
{
	int ret = 0;
	static srSize_t doneLen=0;  //已下载大小
	switch(event)
	{
		case SR_HTTP_EVT_GET_HEAD:
			//收到HEAD数据，在data中，用户自行处理			
		break;

		case SR_HTTP_EVT_GET_HEAD_END:
			//HEAD数据接收完
			doneLen =0;		
		break;
		
		case SR_HTTP_EVT_GET_BODY:
			//收到BODY数据，在data中，写入OTA分区
			
			if(g_otaMng.storeType == SR_OTA_STORE_FOTA)
				ret = _Fotawrite(doneLen,(uint8_t *)data,dataLen);
			
			//对错误处理
			if(ret != 0)
			{					
				g_otaMng.status = SR_OTA_STA_STORE_FAIL;			
			    SR_NetHttpcStop(httpc);  //停止httpc
			    break;
			}	
			doneLen += dataLen;
		break;

		case SR_HTTP_EVT_GET_BODY_END:		
			g_otaMng.status = SR_OTA_STA_DLD_OK;
		break;

		case SR_HTTP_EVT_FAIL:	
			g_otaMng.status = SR_OTA_STA_DLD_FAIL;
		break;
			
		default:
		break;
	}

}


//OTA http下载任务线程
static void _OtaFwHttpDldThd(void *args)
{
	int ret = 0;

	SR_HTTP_CLIENT_T *httpc = SR_NULL;

	if(!g_otaMng.netAdp) 
	{
		ret = SR_NOEXIST;		
		g_otaMng.status = SR_OTA_STA_INIT_FAIL;
		goto _ADP_ERR;
	}

	//1、存储前期处理
	if(g_otaMng.storeType == SR_OTA_STORE_FOTA)
		ret = _FotaBefore();
	
	if(ret !=0)
	{
		BSP_LOG(DEBUG,"[OTA] fota before fail!");
		ret = SR_EIO;
		g_otaMng.status = SR_OTA_STA_STORE_FAIL;
		goto _FOTA_BEF_ERR;
	}
	
	//2、创建http客户端	
	httpc =  SR_NetHttpcCreate(g_otaMng.netAdp ,_OtaHttpEventCb,SR_NULL);
	if(!httpc)
	{
		BSP_LOG(DEBUG,"[OTA] httpc create fail!");	
		ret = SR_ENET;
		g_otaMng.status = SR_OTA_STA_DLD_FAIL;
		goto _HTTPC_ERR;
	}
	
	//3、http GET 请求
	g_otaMng.status = SR_OTA_STA_DLDING;
	ret =  SR_NetHttpcGet(httpc,g_otaMng.url);
	BSP_LOG(DEBUG,"[OTA] GET request,ret=%d\r\n",ret);
	if(ret != 0) 
	{
		ret = SR_ENET;	
		goto _HTTP_GET_ERR;
	}

    //4、存储后期处理
	if(g_otaMng.storeType == SR_OTA_STORE_FOTA)
    	ret = _FotaAfter();	

	if((g_otaMng.status != SR_OTA_STA_STORE_FAIL) && ret ==0 )  //OTA包写入完成
	{
		//5、执行校验      待完善LW_ERR
		
		g_otaMng.status = SR_OTA_STA_VRF_OK;  //校验成功
	}
	else
	{		
		BSP_LOG(DEBUG,"[OTA] fota after fail\r\n");	
		ret = SR_EIO;
		g_otaMng.status = SR_OTA_STA_STORE_FAIL;
		
	}


_HTTP_GET_ERR:
	//6、http 客户端销毁
	SR_NetHttpcDestroy(httpc);
_HTTPC_ERR:
_FOTA_BEF_ERR:
_ADP_ERR:	
	//调用用户回调
	if(g_otaMng.evtCb) g_otaMng.evtCb((ret ==0)?SR_OTA_EVT_OK:SR_OTA_EVT_FAIL,g_otaMng.status);
	BSP_LOG(DEBUG,"[OTA] httpc thd exit\r\n");
	osThreadExit();
}


//启动OTA固件异步下载
int SR_OtaFwDownloadAsync(void)
{
	int ret = 0;
	osThreadId_t otathdId = SR_NULL;
	osThreadFunc_t thdFun = SR_NULL;

	if(SR_OTA_PROTO_HTTP == g_otaMng.protoType)
		thdFun = _OtaFwHttpDldThd;
	else
	{
		BSP_LOG(ERR,"[OTA] proto not impt");		
		g_otaMng.status = SR_OTA_STA_INIT_FAIL;
		ret = SR_NOIMPT;
		goto _PROTO_ERR;
	}
		
	//创建线程，并设置线程参数
	const osThreadAttr_t thdAttr = 
	{ 
		.name = "ota",	     //线程名称
		.stack_size = 4096,  //线程栈大小
		.priority = osPriorityNormal1,	//线程优先级
	};

	otathdId = osThreadNew(thdFun, NULL, &thdAttr);
	if(!otathdId) 
	{	
		g_otaMng.status = SR_OTA_STA_INIT_FAIL;
		ret = SR_EKERNEL;
	}

_PROTO_ERR:
	if(ret != 0) 
	{
		if(g_otaMng.evtCb) g_otaMng.evtCb(SR_OTA_EVT_FAIL,g_otaMng.status);
	}
	return ret;
}



//OTA固件下载初始化
int SR_OtaFwDownloadInit(SR_OTA_INIT_PARAMS_T *params)
{
	int ret = 0;
	memset(&g_otaMng,0,sizeof(SR_OTA_MNG_T));

	//查找适配器
	g_otaMng.netAdp  = SR_NetAdpFind(params->netAdpName);
	if(!g_otaMng.netAdp )
	{
		BSP_LOG(DEBUG,"[OTA] adapter(%s) not find!",params->netAdpName);
		ret = SR_NOEXIST;
		g_otaMng.status = SR_OTA_STA_INIT_FAIL;
		goto _ADP_ERR;
	}

	g_otaMng.protoType = params->proteType;
	g_otaMng.storeType = params->storeType;
	g_otaMng.fwSize = params->fwSize;
	strcpy(g_otaMng.url,params->url);
	strcpy(g_otaMng.storeName,params->storeName);	
	strcpy(g_otaMng.verifyCode,params->verifyCode);
	
_ADP_ERR:
	return ret;
}


//设置OTA事件回调函数
int SR_OtaSetEventCb(OtaEventCb cb,void *args)
{
	g_otaMng.evtCb = cb;
	g_otaMng.evtCbArgs = args;

	return 0;
}

