/******************************************************************************
版权所有：	
文件名称：	rt_printf.c
文件版本：	01.01
创建作者：	sunxi
创建日期：	2020-06-18
功能说明：	打印输出功能。
其它说明：
修改记录：
*/
/*------------------------------- 头文件 --------------------------------------
*/

#include <rt.h>
#include <sys/time.h>
#include <stdarg.h>
#include  "head.h"
#include <arpa/inet.h>
#include  "rt_printf.h"
#include <sys/prctl.h>


/*------------------------------- 宏定义 --------------------------------------
*/
#define PRINTF_BUF_SIZE		4096

/*------------------------------ 类型结构 -------------------------------------
*/

typedef struct
{
	unsigned short  year;
	unsigned char  month;
	unsigned char  day;
	unsigned char  hour;
	unsigned char  minute;	
	unsigned char  second;	
	unsigned char  week;
	unsigned int us; // 微锟斤拷
	
}CO_TIME;

static pthread_t printf_tid = 0;
static int exit_flag = 0; 

static uint8_t p_buf[PRINTF_BUF_SIZE];//输出
static uint8_t p_buf_s[PRINTF_BUF_SIZE];//源
static char printf_buf[PRINTF_BUF_SIZE];


static uint32_t	w_p = 0; //写指针
static uint32_t	r_p = 0; //读指针

static pthread_mutex_t     printf_mutex;


extern int main_mod_is_exit(void);

void sys_gettime_tm(CO_TIME *tm_t)
{
	struct tm *p;
	struct timeval tv;
	
	gettimeofday (&tv , NULL);
	
	//p=gmtime(&tv.tv_sec);	  
	p=localtime(&tv.tv_sec);
	
	tm_t->year=1900+p->tm_year;	//tm_year锟斤拷锟斤拷1900为锟斤拷愕斤拷锟斤拷诘锟斤拷锟斤拷锟斤拷锟?
	//printf("year=%d",tm_t->year);
	tm_t->month=p->tm_mon+1;	//tm_mon锟斤拷值锟斤拷围0-11锟斤拷
	//printf("month=%d",tm_t->month);
	tm_t->day=p->tm_mday;
	//printf("day=%d",tm_t->day);
	tm_t->hour=p->tm_hour;
	//printf("hour=%d",tm_t->hour);
	tm_t->minute=p->tm_min;
	//printf("minute=%d",tm_t->minute);
	tm_t->second=p->tm_sec;
	//printf("second=%d",tm_t->second);
	tm_t->week=p->tm_wday;
	//printf("week=%d",tm_t->week);
	tm_t->us=tv.tv_usec;                                           
	//printf("us=%d\n",tm_t->us);
}

void sys_gettime_CP56(CP56_TIME2A *tm_t)
{
	CO_TIME co_tm_t;
	sys_gettime_tm(&co_tm_t);
	
	tm_t->time_t.year=(unsigned char)(co_tm_t.year-2000);
	tm_t->time_t.month=co_tm_t.month;
	tm_t->time_t.day=co_tm_t.day;
	tm_t->time_t.week=co_tm_t.week;
	tm_t->time_t.hour=co_tm_t.hour;
	tm_t->time_t.min=co_tm_t.minute;
	tm_t->time_t.ms=co_tm_t.second*1000+co_tm_t.us/1000;	
}


//把印时间，具体在那个文件和行号
void co_printf(const char *fp,const int line)
{
	char sDebug[1024];
	char *ptr=NULL;
	struct timespec ts;
	struct rtc_time_t pt;
	// CP56_TIME2A	Clock_u;

	memset(sDebug,'\0',sizeof(sDebug));
	
	// sys_gettime_CP56(&Clock_u);
	gps_get_time(&ts);
	timespec_to_rtc(ts,&pt,1);

	sprintf(sDebug,"%04d-%02d-%02d %02d:%02d:%02d:%03d ",pt.year + 2000,pt.month,
		   pt.day,pt.hour,pt.min,pt.ms/1000,pt.ms%1000);

	ptr=strrchr(fp,'/');

	if(ptr)
	{
		sprintf(sDebug+strlen(sDebug),"%s[%d]:",ptr+1,line);
	}
	else
	{
		sprintf(sDebug+strlen(sDebug),"%s[%d]:",fp,line);
	}

	rt_printf(sDebug);

}

//可变参形式进行实现myprintf 
int myprintf(const char *fmt, ...)
{
	char buf[1024];
	va_list args;
	int printed;
	va_start(args, fmt);
	printed = vsprintf(buf, fmt, args);
	va_end(args);
	
	rt_printf(buf);

	return printed;
}


void rt_printf_time2(struct timespec ts)
{
	struct rtc_time_t tm;

	timespec_to_rtc(ts,&tm,0);
	rt_printf("%04d-%02d-%02d %02d:%02d:%02d:%09d!\r\n",
			tm.year + 2000,
			tm.month,
			tm.day,
			tm.hour,
			tm.min,
			tm.ms/1000,
			ts.tv_nsec
			);

	return;

}


/******************************************************************************
函数名称：	print_mem
函数版本：	01.01
创建作者：	sunxi
创建日期：	2020-06-18
函数说明：	以十六进制的方式显示内存的内容
参数说明：
	addr:	输出内容的起始地址
	len:	输出内容的长度
返回值：  	无
修改记录：
*/
void print_mem(char *name,void * addr,unsigned int len)
{
	int once;
	int i,name_len;

	if(name)
	{
		rt_printf(name);
		name_len = strlen(name);
	}
	else
	{
		rt_printf("addr=0x%08x,len=%d\r\n",(unsigned int)addr,len);
		name_len = 10;
	}

	while(1)
	{
		once = len < 16 ? len : 16;
		if(!name)
		{
			rt_printf("%08x:",(unsigned int)addr);
		}
		for(i=0;i<once;i++)
		{
			if(i == 8)
				rt_printf("  "); // 使用2个空格，不使用"-"，因为规约解析工具不支持"-".
			rt_printf(" %02x",*(unsigned char *)addr++);
		}
		rt_printf("\r\n");

		len -= once;
		if(len == 0)
		{
			break;
		}

		// 打印对齐空格
		for(i=0;i<name_len;i++)
		{
			rt_printf(" ");
		}

	}

	return;
}

void print_mem_time(char *name,void * addr,unsigned int len)
{
	struct rtc_time_t tm;
	struct timespec ts;
	char buf[64];

	clk_time_get(&ts);
	timespec_to_rtc(ts,&tm,0);

	if(name)
	{
		sprintf(buf,
				"%s(%04d-%02d-%02d %02d:%02d:%02d:%06ld)",
				name,
				tm.year + 2000,
				tm.month,
				tm.day,
				tm.hour,
				tm.min,
				tm.ms/1000,
				ts.tv_nsec/1000
				);

	}
	else
	{
		sprintf(buf,
				"mem(%04d-%02d-%02d %02d:%02d:%05d)",
				tm.year + 2000,
				tm.month,
				tm.day,
				tm.hour,
				tm.min,
				tm.ms
				);
	}

	print_mem(buf,addr,len);
}

// int g_print_time = 0;
void print_msg(char *name,void * addr,unsigned int len)
{
	if(g_print_time)
	{
		print_mem_time(name,addr,len);
	}
	else
	{
		print_mem(name,addr,len);
	}
}

int rt_printf(const char *fmt, ...)
{
#if 0
	char pbuf[1024];
	va_list args;
	int printed;
	va_start(args, fmt);
	printed = vsprintf(pbuf, fmt, args);
	va_end(args);

	//直接打印
	printf(pbuf);
#else
	//放入显示缓冲区

		va_list args;
		int length, byte;
	

		va_start(args, fmt);
		vsnprintf(printf_buf, PRINTF_BUF_SIZE, (char *)fmt, args);
		va_end(args);
	
		length = strlen(printf_buf);

		pthread_mutex_lock(&printf_mutex);

		if((w_p + length) < PRINTF_BUF_SIZE)
		{
			memcpy((uint8_t *)&p_buf_s[w_p],(uint8_t *)printf_buf,length);			
			w_p += length;
		}
		else
		{
			byte = PRINTF_BUF_SIZE - w_p;
			memcpy((uint8_t *)&p_buf_s[w_p],(uint8_t *)printf_buf,byte);		
			w_p = length - byte;
			memcpy((uint8_t *)p_buf_s,(uint8_t *)&printf_buf[byte],w_p);	
		}

		//printf("-----test printf----wp=%d---%s",w_p, printf_buf);

		pthread_mutex_unlock(&printf_mutex);

#endif

	return 0;
}




/******************************************************************************
函数名称：	rt_printf_func
函数版本：	01.01
创建作者：	sunxi
创建日期：	2022-5-31
函数说明：	打印工作函数.
参数说明：		
返回值：	返回0
修改记录：	
*/
static int rt_printf_func(void *arg)
{
	int len = 0;
	int len_1 = 0;

	memset(p_buf,0,sizeof(p_buf));
	memset(p_buf_s,0,sizeof(p_buf_s));
	w_p = 0;
	r_p = 0;

	pthread_mutex_init(&printf_mutex, NULL);

#if 0
	strcpy(&p_buf[w_p],test_1);
	w_p += strlen(test_1);
	strcpy(&p_buf[w_p],test_2);
	w_p += strlen(test_2);
	strcpy(&p_buf[w_p],test_3);
	w_p += strlen(test_3);

	rt_printf(p_buf);
#endif

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

	prctl(PR_SET_NAME, "rt_printf_func");
	while(!exit_flag)
	{

		msleep(10);

		watchdog_feed(wdt_id);

		if(main_mod_is_exit())
		{
			break;
		}
		
		//rt_printf("w_p = %d, r_p = %d\r\n",w_p,r_p);
		
		pthread_mutex_lock(&printf_mutex);
		len = 0;
		len_1 = 0;

		if(w_p != r_p)
		{
			memset(p_buf,0,sizeof(p_buf));
			
			//获取打印信息
			if(w_p > r_p)
			{
				len = w_p - r_p;
				memcpy(p_buf,&p_buf_s[r_p],len);
				r_p += len;
			}
			else
			{
				//w_p指针翻滚，过0
				//分两段读取，再合并
				len = PRINTF_BUF_SIZE-r_p;
				memcpy(p_buf,&p_buf_s[r_p],len);
				r_p += len;

				len_1 = w_p;
				memcpy(&p_buf[len],p_buf_s,len_1);
				r_p = len_1;
			}

			if(r_p >= PRINTF_BUF_SIZE)
				r_p = 0;

			p_buf[sizeof(p_buf)-1] = 0;//保证结束


		}

		pthread_mutex_unlock(&printf_mutex);
		
		if((len > 0) || (len_1 > 0))
		{
			//noted by sunxi: 20221122 重定向6000端口打印
			if(g_print_to_net)
			{
				net_debug_send(p_buf,sizeof(p_buf));
		//		return 0;
			}
			else
			{
				printf(p_buf);
				//printf("\r\n");

			}
		}
	}

	watchdog_remove_item(wdt_id);

	return 0;
}


/******************************************************************************
函数名称：	rt_printf_init
函数版本：	01.01
创建作者：	sunxi
创建日期：	2022-5-31
函数说明：	初始化.
参数说明：	
					无					
返回值：	成功返回0, 失败返回-1
修改记录：	
*/
int rt_printf_init(void)
{
	int ret;

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

/******************************************************************************
函数名称：	rt_printf_exit
函数版本：	01.01
创建作者：	sunxi
创建日期：	2022-5-31
函数说明：	反初始化.
参数说明：	
					无					
返回值：	总是返回0.
修改记录：	
*/
int rt_printf_exit(void)
{
	exit_flag = 1;

	pthread_join(printf_tid, NULL);
	return 0;
}




 



/*------------------------------ 测试函数 -------------------------------------
一个实体文件必须带一个本模块的测试函数来进行单元测试，如果的确不方便在本模块中
进行单元测试，必须在此注明实际的测试位置（例如在哪个实体文件中使用哪个测试函数）.
*/







/*------------------------------ 文件结束 -------------------------------------
*/
