/******************************************************************************
版权所有：	
文件名称：	main_mod.c
文件版本：	01.01
创建作者：	sunxi
创建日期：	2025-06-09
功能说明：	实时微系统。
其它说明：
修改记录：
*/
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/wait.h> 

#include "bsp.h"
#include "rt.h"
#include "app.h"
#include "head.h"
#include "tmp/bsp_share/bsp_ustimer.h"
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <signal.h>
#include <stdbool.h>
#include <errno.h>

#include <stdio.h>
// #define __USE_GNU
#define _GNU_SOURCE
#include <sched.h>
#include <pthread.h>
// #include <alchemy/task.h>

static int m_reset; //看门狗复位变量
struct completion *g_exit_completion_gprs_net_IEC_proc;
static int g_exit_flag;

bool SystemInit_finish_flag __attribute__((aligned(8))) = false;  

static int sync_cnt = 0;
static pthread_t sync_tid = 0;

enum
{
    PTHREAD_MQ=0,           // 消息队列
    PTHREAD_C0NSOLE,        // 控制台
    PTHREAD_PRINTF,         // 打印信息
    PTHREAD_MAIN_LOOP,      // 主循环
    PTHREAD_MAIN_APP,
    PTHREAD_MAIN_DIDO_ADC,
    PTHREAD_RCD,            // 录波
    PTHREAD_CAL_SAMPLE,  

	PTHREAD_MAX_NUM
};

pthread_t AW_DTU_PTHREAD_TAB[PTHREAD_MAX_NUM];	//线程表
struct rt_stat g_stat_periodus_5ms;

int app_main (void *arg);
int di_do_adc (void *arg);
#ifdef ENCRYPT_SM2 
int gh_sm2_dev_init(void);
void gh_sm2_dev_exit(void);
#endif
int console_init(void);
void console_exit(void);
int encrypt_test(void);
int snprintf_test(void);
extern void uart_putchar (int channel, char ch);
extern int net_if_test(void);
extern int clk_test(void);
extern int ac_e2prom_test(void);
void watchdog_m_reset(int flag){}
extern int printf_e907_exit(void);

int kernel_callback(void);

static void main_mod_exit(int signo);

// static DECLARE_WAIT_QUEUE_HEAD(wq);
static int g_soft_irq_flag = 0;

static struct proc_dir_entry *corp_info_proc_entry;

int corp_info_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *data)
{
	sprintf(buf, "XXXXXX XXXXXX XXXXXXX XXXXX XXXXXXX Co.,Ltd(XXXXXXXXXX) 2025\r\n");

	len = strlen(buf);

	return len;

}

pid_t gettid()
{
    return syscall(SYS_gettid);    
}

int mainloop_soft_isr(int irq, void *dev_id)
{
    // int offset=0,tmp,count=1,count2=1,count3=0;
    // struct timespec ts;
    // struct rtc_time_t rtcs;
    struct sched_param sch_par;
    sch_par.sched_priority = 6;
    pthread_setschedparam(pthread_self(), SCHED_RR, &sch_par);   // 设置当前线程优先级
	prctl(PR_SET_NAME, "mainloop_soft_isr_thread");
#ifdef RT_THREAD_DEBUG
	rt_printf("Thread created successfully: %s,PID: %d LWP: %d\r\n", 
              	"mainloop_soft_isr_thread", (int)getpid(), (int)syscall(SYS_gettid));
#endif
    while(1)
    {
        msleep(100);// 延时100ms
        kernel_callback();
#if  0
        if(count++>=40)
        {
            //gps_get_time(&ts);
            //timespec_to_rtc(ts, &rtcs, 0);

            //tmp=GetUsCounterValue();
            //offset=tmp-offset;
            //rt_printf("%d---%d-%d-%d,%d:%d:%d mainloop=%d,offset=%d\r\n",ts.tv_sec,rtcs.year,rtcs.month,rtcs.day,rtcs.hour,rtcs.min,rtcs.ms,tmp,offset);
            //offset=tmp;
            
            //rt_printf("di=0x%08X\r\n",gpio_get_di());

           if(count3==0)
              gpio_kout_do(0,DO_OUT7);
           else
           {
              if((count3-1)!=DO_OUT4)
                gpio_kout_do(0,count3-1);
           }
           gpio_kout_do(1,count3);
           rt_printf("count=%d\r\n",count3);
           ++count3;
           if(count3>=DO_NUM)
             count3=0;
          gpio_kout_do(1,DO_PWM0);
           count=1; 
        }
#endif
    }
}

void mainloop_wakeup(void)
{
	//rt_sirq_force(11);
}


int kernel_callback(void)
{
	static unsigned char init_end_flag = 0; // sunxi 20190416 added
	// 延时100ms
	//wait_event_interruptible_timeout(wq,g_soft_irq_flag,HZ/10);

	g_soft_irq_flag = 0;

	// sunxi 20190416 added start
	if(!init_end_flag)
	{
		//corp_info_proc_entry = create_proc_entry("corp_info", 0400, NULL);
		if (corp_info_proc_entry)
		{
			//corp_info_proc_entry->read_proc = corp_info_read_proc;
			//corp_info_proc_entry->write_proc = NULL;
		}

		init_end_flag = 1;
	}
	// sunxi 20190416 added end

	// 检查是否需要退出。
	if(g_exit_flag)
	{
		hzk_exit();
		led_exit();
		net_debug_exit();
		net_debug_s_exit();
		if(g_exit_completion_gprs_net_IEC_proc)
		{
			;//wait_for_completion(g_exit_completion_gprs_net_IEC_proc);		
		}
		printf_e907_exit();
		//complete_and_exit(&exit_completion, 1);
	}

	return 0;
}

int cal_thread (void *arg)
{
    uint32_t us0;
    int ms;
    struct sched_param sch_par;

    sch_par.sched_priority = 8;

	pthread_setschedparam(pthread_self(), SCHED_RR, &sch_par);   // 设置当前线程优先级暂定 20200910

	while(SystemInit_finish_flag == false)
	{
		msleep(10);
	}

    uint32_t wdt_id;
    int rc = watchdog_add_item("cal_thread", &wdt_id,120);
    if(rc != 0) {
        printf("can not add cal_thread task to wdt\r\n");
        return -1;
    }

    ms = 50;
    us0 = ustimer_get_origin();

	prctl(PR_SET_NAME, "cal_thread");
#ifdef RT_THREAD_DEBUG
	rt_printf("Thread created successfully: %s, PID: %d LWP: %d\r\n", 
              	"cal_thread", (int)getpid(), (int)syscall(SYS_gettid));
#endif
    while(1)
    {
    	watchdog_feed(wdt_id);
		
        // 100ms执行一次
        ms = 50 - (ustimer_get_duration(us0)/USTIMER_US+ 500)/1000;
        if(ms < 0)
        {
            ms = 0;
        }
        msleep(ms);
        us0 = ustimer_get_origin();

        // 检查是否需要退出。
        if(g_exit_flag)
        {

			//complete_and_exit(&exit_completion2, 1);
			break;
		}

		sw_cal_app();
		hisory_file_app();
		//pw_quality_app();
	}

	watchdog_remove_item(wdt_id);

	return 0;
}

int main_mod_is_exit(void)
{
	return g_exit_flag;		
}

// sunxi 20190417 added start
/*
 * 该接口在模块装载时调用，防止我们的模块在之前的内核版本中能被轻易使用。函数名称不要定义跟功能一样。
 */
int mod_init(void)
{
	char buf[256] = {0x00};
	int fd = rt_file_open("/proc/version", O_RDONLY, 0);
	if(fd < 0)
		return -1;

	rt_file_read(fd,  buf,  256, NULL);
	rt_file_close(fd, 0);

	if(strstr(buf, "root@Ubuntu") && strstr(buf, "-LYQ"))
		return 0;

	return -3;
}

extern void gps_isr(void);
int di_do_adc (void *unused)
{
	pid_t tid;
    cpu_set_t set;
    struct sched_param sch_par;
    sch_par.sched_priority = 90;

	// Set CPU affinity [T536-CPU-3]
    tid = gettid();
    CPU_ZERO(&set);
    CPU_SET(3, &set);
    sched_setaffinity(tid, sizeof(cpu_set_t), &set);

	while(SystemInit_finish_flag == false)
	{
		msleep(10);
	}

    uint32_t wdt_id;
    int rc = watchdog_add_item("di_do_adc", &wdt_id,120);
    if(rc != 0) {
        printf("can not add di_do_adc task to wdt\r\n");
        return -1;
    }

    //adc_init();
    dido_init();
	rt_stat_init(&g_stat_periodus_5ms, "pit_5ms_priod(1us)");
    pthread_setschedparam(pthread_self(), SCHED_FIFO, &sch_par);   // 设置当前线程优先级
	prctl(PR_SET_NAME, "di_do_adc");
#ifdef RT_THREAD_DEBUG
	rt_printf("Thread created successfully: %s, PID: %d LWP: %d\r\n", 
              	"di_do_adc", (int)getpid(), (int)syscall(SYS_gettid));
#endif

	// zhl add
	struct shmem_fd shmem_fd;
	if (share_mem_init_v2(&shmem_fd) < 0){
		dp_err_n_c("--->shmem_init fail !!!\r\n");
		return -1;
	} else {
		dp_info_n_c("--->shmem_init success !!!\r\n");
	}

	// 装置类型us_machine_type （分布式：1，集中式：2）
	struct t_shmdata_machine_type machine_type = {0};
	machine_type.us_machine_type = 1;
	shm_packet_write_v2(SHM_ADDR_R_MACHINETYPE, (uint8_t *)&machine_type, sizeof(struct t_shmdata_machine_type));	
	// printf("write SHM_ADDR_R_MACHINETYPE::0x%X -> us_updata: %d, us_op: %d, us_op_bk: %d, us_machine_type: %d, us_crc: 0x%04x\n\n", 
	// 		SHM_ADDR_R_MACHINETYPE, machine_type.us_updata, machine_type.us_op, machine_type.us_op_bk, machine_type.us_machine_type, machine_type.us_crc);
	
	sleep(5); // 注：下发装置类型后，需要等待大于5s，才能读取到R核的ADC初始化标志信息
	// ADC初始化标志信息
	struct t_shmdata_flag adc_flag = {0};
	int ret_flag = shm_packet_read_v2(SHM_ADDR_W_FLAG, sizeof(adc_flag), (uint8_t *)&adc_flag, sizeof(adc_flag));
	if(adc_flag.us_cfg_adc_err == 1 || ret_flag < 0){
		rt_err_set(ERR_CODE_INIT_ADC, 0);
	}
    else {
	    dp_info_nt("adc init ok!\r\n");
    }	
	// printf("ret_flag: %d, read SHM_ADDR_W_FLAG:0x%X -> us_updata: %u, us_op: %u, us_op_bk: %u, us_cfg_adc_err: %u, us_crc: 0x%04x\n\n", 
	// 		ret_flag, SHM_ADDR_W_FLAG, adc_flag.us_updata, adc_flag.us_op, adc_flag.us_op_bk, adc_flag.us_cfg_adc_err, adc_flag.us_crc);
		
    while(1)
    {
		static u8 flags = 0;
		static unsigned long us1 = 0;
		unsigned long origin_ext = 0;

        usleep(1000);
		// bsp_ustimer_delay(1000); // 1ms

		// 检查是否需要退出。
		if(g_exit_flag)
		{
			//complete_and_exit(&exit_completion2, 1);
			break;
		}

		origin_ext = bsp_ustimer_get_origin();
		if (flags) {
			rt_stat_in(&g_stat_periodus_5ms, (origin_ext - us1));
		}
		
		watchdog_feed(wdt_id);

        // adc_isr(0);
		if(adc_flag.us_cfg_adc_err == 0 && ret_flag > 0)
		{
			adc_isr_new(0);	
		}
				
		//保护计算
        if(prt_flag)     
        {
            pit_5ms_main(0);
            prt_flag=false;
        }


		// gps_isr(); // zhl upadte 放在另一个线程跑
		us1 = origin_ext;
		flags = 1;
    }
	watchdog_remove_item(wdt_id);

	return 0;
}

//当装置修改app文件夹里面的文件时，需要调用该函数，以sync_cnt数减为0时，调用sync，写入flash,保存数文件。
void start_sync(void)
{
	sync_cnt = 50;//500ms
}

static int sync_func(void *arg)
{

	// int ret = 0;

    uint32_t wdt_id;
    int rc = watchdog_add_item("sync_func", &wdt_id,60);
    if(rc != 0) {
        printf("can not add sync_func task to wdt\r\n");
        return 0;
    }

	sync_cnt = 0;

	prctl(PR_SET_NAME, "sync_func");
#ifdef RT_THREAD_DEBUG
	rt_printf("Thread created successfully: %s, PID: %d LWP: %d\r\n", 
              	"sync_func", (int)getpid(), (int)syscall(SYS_gettid));
#endif
	while(1)
	{

		msleep(10);

		watchdog_feed(wdt_id);

		if(main_mod_is_exit())
		{
			break;
		}


		if(sync_cnt > 0)
		{
			if(--sync_cnt <= 0)
			{
				system("sync");
				// rt_printf_time("--- sync.\r\n");
			}
		}
		
	
	}

	watchdog_remove_item(wdt_id);

	return 0;
}

int main(void)
{
	// pid_t pid;

	char *argv[] = { "/sbin/ifconfig", "eth1", "192.168.2.100",NULL};
 	char *envp[] = { NULL };

	// struct task_struct * ts;
	// struct sched_param sp;
	int ret;

	SystemInit_finish_flag = false;
	
	//停止喂狗,让程序复位.在命令行中输入insmod f306.ko m_reset=1
	if(m_reset==1)
	{
		rt_printf("watchdog_m_reset(1)...\n");
		watchdog_m_reset(1);
		return 0;
	}

	call_usermodehelper("/sbin/ifconfig", argv, envp, UMH_WAIT_PROC);

    dp_info_nt("%s %s\r\n", __DATE__, __TIME__);
    dp_info_nt("版本信息: SV%02d.%03d %s\r\n", (VER_NUM >> 16) & 0XFF, VER_NUM & 0XFFF, DEVICE_VERSION_INFORMATION);
    
	//if(mod_init() < 0)    //jack.liu 20200904 认证信息先不使用
	//	return -1;

	bsp_init();	// bsp必须先初始化  
	rt_init();	// 实时系统后初始化
	app_init();	// 应用初始化最后初始化
    adc_init();

	// 建立主函数入口线程
	ret = pthread_create(&AW_DTU_PTHREAD_TAB[PTHREAD_MAIN_LOOP], NULL, (void *)mainloop_soft_isr, NULL);
	if(ret)
	{
		rt_printf("mainloop_soft_isr thread create failed!\r\n");
		rt_printf("ret = %d, err = %s\r\n", ret, strerror(ret));
		memset((char *)&AW_DTU_PTHREAD_TAB,0,sizeof(AW_DTU_PTHREAD_TAB));
		return ret;
	}	

	// 创建主循环线程
	ret = pthread_create(&AW_DTU_PTHREAD_TAB[PTHREAD_MAIN_APP], NULL, (void *)app_main, NULL);
	if(ret)
	{
	    rt_printf("app_main thread create failed!\r\n");
		rt_printf("ret = %d, err = %s\r\n", ret, strerror(ret));
		AW_DTU_PTHREAD_TAB[PTHREAD_MAIN_APP] = 0;
		memset((char *)&AW_DTU_PTHREAD_TAB,0,sizeof(AW_DTU_PTHREAD_TAB));
		return ret;
	}

#if 1
	// 创建三遥线程
	ret = pthread_create(&AW_DTU_PTHREAD_TAB[PTHREAD_MAIN_DIDO_ADC], NULL, (void *)di_do_adc, NULL);
	if(ret)
	{
	    rt_printf("di_do_adc thread create failed!\r\n");
		rt_printf("ret = %d, err = %s\r\n", ret, strerror(ret));
		AW_DTU_PTHREAD_TAB[PTHREAD_MAIN_DIDO_ADC] = 0;
		memset((char *)&AW_DTU_PTHREAD_TAB,0,sizeof(AW_DTU_PTHREAD_TAB));
		return ret;
	}

    // 创建采样数据计算线程
    ret = pthread_create(&AW_DTU_PTHREAD_TAB[PTHREAD_CAL_SAMPLE], NULL, (void *)cal_thread, NULL);
    if(ret)
    {
        rt_printf("cal_thread thread create failed!\r\n");
        rt_printf("ret = %d, err = %s\r\n", ret, strerror(ret));
        AW_DTU_PTHREAD_TAB[PTHREAD_CAL_SAMPLE] = 0;
        memset((char *)&AW_DTU_PTHREAD_TAB,0,sizeof(AW_DTU_PTHREAD_TAB));
        return ret;
    }

	ret = pthread_create(&sync_tid, NULL, (void *)sync_func, NULL);
	if(ret)
	{
		rt_printf("ret = %d, err = %s\r\n", ret, strerror(ret));
		sync_tid = 0;
		return ret;
	}

    // 设置进程名字
    prctl( PR_SET_NAME, "AW_DTU_CALL", 0, 0, 0);

    signal(SIGINT, main_mod_exit);
#endif
#ifdef RT_THREAD_DEBUG
    rt_printf("thread create success!\r\n"); 
#endif
    
	// 主线程阻塞
	while(1) {
		usleep(1000*100);
	}

	return 0;	
}

int net_debug_exit(void);
int net_maintain_exit(void);
int	net_104_exit(void);


static void main_mod_exit(int signo)
{

	if (corp_info_proc_entry)
	{
		;//remove_proc_entry("corp_info", NULL);
	}

	//
	if(m_reset == 1)
	{
		watchdog_m_reset(0);
		rt_printf("watchdog_m_reset(0)...\n");
		return ;
	}	
	//gh_sm2_dev_exit();
	//console_exit();
	
	//watchdog_unregister_all();

	//rt_sirq_unregister(RT_SOFT_IRQ_MAINLOOP);
	
	net_maintain_exit();
	net_104_exit();
	net_104link_exit();
	g_exit_flag = 1;

	//wait_for_completion(&exit_completion);
	//wait_for_completion(&exit_completion2);

	app_exit();
	rt_exit();
	bsp_exit();

	// sunxi 20190418 goose_app_exit();
	open_inet_port();

	rt_printf("main_mod_exit\n");	
}



