/******************************************************************************
版权所有：	 
文件名称：	rt_log.c
文件版本：	01.01
创建作者:	sunxi
创建日期：	2020-6-18
功能说明：	日志记录
其它说明：	没有资源竞争保护处理，只能在大循环级别使用。
修改记录：
*/
#include <rt.h>
#include "my_rtc.h"
#include <semaphore.h>

struct log_file g_log_file[] =
{
 	{"/app/data/log_err.txt",		50*1024,0,0},
 	{"/app/data/log_operate.txt",	50*1024,0,0},
 	{"/app/data/log_soe.txt",		50*1024,0,0},
	{"/app/data/log_yx.txt",		50*1024,0,0},
	{"/app/data/log_printf.txt",	100*1024,0,0},
};

#define LOG_FILE_NUM ((int)(sizeof(g_log_file)/sizeof(g_log_file[0])))
#define LOG_FILE_BUFSIZE	1024

int g_logfile_update[LOG_FILE_NUM];
static char writebuf[LOG_FILE_NUM][LOG_FILE_BUFSIZE];  //数据缓存区
static int  writebuf_count[LOG_FILE_NUM];			  //缓存已存字节数	
static char g_malloc_buf[LOG_FILE_NUM][LOG_FILE_BUFSIZE];  //数据缓存区


sem_t	log_sem_buf[LOG_FILE_NUM];         	// 信号量 对空指针进行读写操作会导致编译错误
static sem_t	*log_sem[LOG_FILE_NUM];	    

int sem_for_type = 0;
int log_init(void)
{
	int i,j,file_length,max_length;
	char * file_buf;
	off_t pos;
	int err,ret;
	int len;

	pos=0;  

	//找到最大的文件长度
	max_length = 0;
	for(i = 0; i< LOG_FILE_NUM; i++)
	{
	    log_sem[i]=&log_sem_buf[i];
		if(g_log_file[i].size > max_length)
		{
			max_length = g_log_file[i].size;
		}

		writebuf_count[i] = 0; //清零 
		//if(sem_init(log_sem[i], sem_for_type, 0))
		if(sem_init(log_sem[i], sem_for_type, 1))    //先创建一个1值信号量
			return -1;
	}

	//分配内存
	file_buf = (char *)rt_malloc(max_length);
	if(file_buf == NULL)
	{
		return -111; 	
	}

	//循环打开文件，找到00的位置
	err = 0;
	for(i = 0; i< LOG_FILE_NUM; i++)
	{
		//打开文件
		g_log_file[i].handle = rt_file_open(g_log_file[i].name, O_CREAT|O_RDWR, 0);
		if(IS_ERR(g_log_file[i].handle))
		{ 
			printf("%s open error!\r\n",g_log_file[i].name);
			err++;
			continue;
		}
		len = rt_file_getfile_size(g_log_file[i].handle);
		if(len < 0)
		{
			printf("%s fstat error!\r\n", g_log_file[i].name);
			rt_file_close(g_log_file[i].handle, 0);
			g_log_file[i].handle = -1;
			err++;
			continue;
		}

		 //得到文件长度
		file_length = len;

                     
		 //读出文件内容
		pos = 0;
		ret = rt_file_read(g_log_file[i].handle, file_buf, file_length, &pos);
		if(ret !=  file_length) //读出log内容
		{
			rt_file_close(g_log_file[i].handle, 0);
			g_log_file[i].handle = -1;
			
			printf("%s read error:file_length=%d,ret=%d!\r\n",g_log_file[i].name,file_length,ret);
			err++;
			continue;
		}

		g_log_file[i].offset = 0;
		
		//如果文件长度，偏移量为0
		if(file_length == 0)
		{	
			g_log_file[i].offset = 0;
			continue;

		}

		//找到00位置，得到偏移量
		for(j = 0; j < file_length-1; j++)
		{
			if(file_buf[j] == 0 && (file_buf[j+1] == 0))
			{
				g_log_file[i].offset = j+1;
				break;
			}
		}		
	}

	//释放内存
	rt_free(file_buf);

	log_str_time(LOG_ERR,"装置上电",1,1);
	

	memset (g_logfile_update, 0, sizeof(g_logfile_update));
	
	return -err;
}

//退出函数
int log_exit(void)
{
	int i;

	//循环关闭文件
	for(i = 0; i< LOG_FILE_NUM; i++)
	{
		if(log_sem[i])
		{
			sem_destroy(log_sem[i]);
			log_sem[i] = NULL;
		}
		if(g_log_file[i].handle != 0)
		{
			rt_file_close(g_log_file[i].handle, 0);
			g_log_file[i].handle = -1;
		}
	}
	return 0;
}


static int _log_str(int index, char *log_buf,int log_len)
{
	char flag[2],*buf,read_buf[2];
	int end_len,over_len,file_length;
	off_t pos;
	off_t write_pos;
	int write_len;
	int tmp = 0;
	int ret=0;

	if(log_len == 0)
	{
		return 0;
	}


	if(log_len > LOG_FILE_BUFSIZE)
	{
		return -1;
	}
	// 检查参数
	if(index > LOG_FILE_NUM)
	{
		return -1; 
	}

	if(g_log_file[index].handle < 0)
	{
		return -2;
	}
	
	if(log_buf == NULL)
	{
		return -3;
	}

	//初始化
	end_len = 0;
	over_len = 0;
	memset(flag,0x0,sizeof(flag));

	pos=g_log_file[index].offset;
	buf=g_malloc_buf[index];

	//判断是否记录长度超过文件长度
	if(g_log_file[index].offset + log_len + 6 >= g_log_file[index].size)		
	{
		//得到最后剩余的长度
		end_len = g_log_file[index].size-g_log_file[index].offset;
		
		memset(buf,0,end_len);

		//将最后部分填0
		if(rt_file_write(g_log_file[index].handle,buf,end_len,&pos) != end_len)
		{
			return -5;			
		}

		//从头开始写入
		pos = 0;
	}

	write_pos = pos;
	

	pos = pos + 2 + log_len + 2;
	g_log_file[index].offset = pos-1;

	pos += 2;

	write_len =  2 + log_len + 2 + 2;


	memcpy(buf, "\r\n", 2);
	tmp += 2;
	memcpy(buf+tmp, log_buf, log_len);
	tmp += log_len;
	memcpy(buf+tmp, flag, 2);
	tmp += 2;
	memcpy(buf+tmp, "\r\n", 2);

	memcpy(writebuf[index], buf, write_len);
	
	//在文件长度小于最大长度时，需要找到当前文件长度
	fsync(g_log_file[index].handle);
	file_length = rt_file_getfile_size(g_log_file[index].handle);
	rt_file_llseek(g_log_file[index].handle, 0, SEEK_SET);

	//从换行后开始查找，找到被覆盖剩余记录部分长度
	pos = g_log_file[index].offset  + 3;
	
	while(pos <=  (file_length - 2))
	{
		if(rt_file_read(g_log_file[index].handle,read_buf, 2,&pos) !=  2)
		{		
			rt_printf("%s read error!\r\n",g_log_file[index].name);
			ret = -10;
			goto END;
		}
		if(read_buf[0] == 0 && read_buf[1] != 0)
		{
			break;
		}
		pos -= 1;
		
	}
	over_len = pos  - g_log_file[index].offset - 4;
	
	if(over_len < 0)
	{
		goto END;
	}
	//将被覆盖剩余记录填0
	memset(writebuf[index]+write_len,0,over_len);
	write_len += over_len; 
	
END:	

	if(rt_file_write(g_log_file[index].handle,writebuf[index],write_len,&write_pos) != write_len)
	{
		
		rt_printf("%s write error!\r\n",g_log_file[index].name);
		return -12;			
	}

	// 文件已更新
	g_logfile_update[index] = 1;
	return ret;
}


int log_str(int index, char *log_buf)
{
	int ret = 0,len;

	len = strlen(log_buf);
	sem_wait(log_sem[index]);
	ret = _log_str(index, log_buf,len); //写内容到文件
	sem_post(log_sem[index]);
	return ret;
	
}

int log_str_len(int index, char *log_buf,int len)
{
	int ret = 0;
	sem_wait(log_sem[index]);
	ret = _log_str(index, log_buf,len); //写内容到文件
	sem_post(log_sem[index]);
	return ret;
	
}


static int  log_str_flush(int index, char *log_buf, int log_len)
{
	char flag[2],*buf,read_buf[2];
	int end_len,over_len,file_length;
	off_t pos;

	if(log_len == 0)
	{
		return 0;
	}

	// 检查参数
	if(index > LOG_FILE_NUM)
	{
		return -1;
	}

	if(g_log_file[index].handle == 0)
	{
		return -2;
	}
	
	if(log_buf == NULL)
	{
		return -3;
	}

	//初始化
	end_len = 0;
	over_len = 0;
	memset(flag,0x0,sizeof(flag));

	//log_len = strlen(log_buf);   
	pos=g_log_file[index].offset;

	//判断是否记录长度超过文件长度
	if(g_log_file[index].offset + log_len  >= g_log_file[index].size)		
	{
		//得到最后剩余的长度
		end_len = g_log_file[index].size-g_log_file[index].offset;

		//分配内存
		buf = (char *)rt_malloc(end_len);
		if(buf == 0)
		{
			return -4;
		}

		memset(buf,0,end_len);

		//将最后部分填0
		if(rt_file_write(g_log_file[index].handle,buf,end_len,&pos) != end_len)
		{
			rt_free(buf);
			return -5;			
		}
		rt_free(buf);

		//从头开始写入
		pos = 0;
	}

	

	//写文件
	if(rt_file_write(g_log_file[index].handle,log_buf, log_len ,&pos) != log_len)
	{
		return -9;			
	}	

	g_log_file[index].offset = pos-3;

			
	//在文件长度小于最大长度时，需要找到当前文件长度
	fsync(g_log_file[index].handle);
	file_length= rt_file_getfile_size(g_log_file[index].handle);
	rt_file_llseek(g_log_file[index].handle, 0, SEEK_SET);
	//rt_free(buf);
	//从换行后开始查找，找到被覆盖剩余记录部分长度
	pos = g_log_file[index].offset  + 3;

	while(pos <=  (file_length - 2))
	{
		if(rt_file_read(g_log_file[index].handle,read_buf, 2,&pos) !=  2)
		{		
			rt_printf("%s read error!\r\n",g_log_file[index].name);
			return -10;
		}
		if(read_buf[0] == 0 && read_buf[1] != 0)
		{
			break;
		}
		pos -= 1;
		
	}

	over_len = pos  - g_log_file[index].offset - 4;
	if(over_len < 0)
	{
		goto END;
	}

	//分配内存
	buf = (char *)rt_malloc(over_len);
	if(buf == 0)
	{
		return -11;
	}
	
	memset(buf,0,over_len);
	
	pos =  g_log_file[index].offset + 3;

	//将被覆盖剩余记录填0
	if(rt_file_write(g_log_file[index].handle,buf,over_len,&pos) != over_len)
	{
		rt_free(buf);
		rt_printf("%s write error!\r\n",g_log_file[index].name);
		return -12;			
	}
	rt_free(buf);
END:	
	// 文件已更新
	g_logfile_update[index] = 1;
	return 0;

}

int log_str_ext(int index, char *log_buf)
{
	int log_len= strlen(log_buf);

	sem_wait(log_sem[index]);

	//缓存数据内容已经足够大,写到文件中
	if((log_len+3+writebuf_count[index]) >=  LOG_FILE_BUFSIZE)
	{

		//最后一行结束字符00 00 0D 0A
		writebuf[index][writebuf_count[index]-2]=0;
		writebuf[index][writebuf_count[index]-1]=(unsigned char)'\r';
		writebuf[index][writebuf_count[index]]=(unsigned char)'\n';
		//写到文件中
		log_str_flush(index, writebuf[index], writebuf_count[index]+1);	
		writebuf_count[index] = 0;//清零
	}

	//文件开头填充0D 0A
	if(writebuf_count[index]==0)
	{
		//数据末尾00 00 0D 0A
		//填充           0D 0A 数据
		writebuf[index][0] = '\r';	
		writebuf[index][1] = '\n';	
		writebuf_count[index] += 2;	
	}
	
	//缓存数据内容
	memcpy(writebuf[index]+writebuf_count[index], log_buf, log_len);
	writebuf_count[index] += log_len;

	//一行内容以 00 0D 0A作为结束
	writebuf[index][writebuf_count[index] ] = 0;
	writebuf_count[index] ++;
	
	memcpy(writebuf[index]+writebuf_count[index], "\r\n", 2);
	writebuf_count[index] +=2;

	sem_post(log_sem[index]);
	
	return 0;
}

void log_str_ext_flush(int index)
{
	sem_wait(log_sem[index]);
	
	if(writebuf_count[index] > 0)
	{
		//结束字符00 00 0D 0A
		writebuf[index][writebuf_count[index]-2]=0;
		writebuf[index][writebuf_count[index]-1]=(unsigned char)'\r';
		writebuf[index][writebuf_count[index]]=(unsigned char)'\n';
		log_str_flush(index, writebuf[index], writebuf_count[index]+1);	
		writebuf_count[index] = 0;			
	}			
	sem_post(log_sem[index]);
	

}



int log_str_time(int index, char *log_buf,int is_rtc,u8 val)
{
	char * wirte_buf;
	int log_len;

	struct timespec ts={0,0};
	struct rtc_time_t tm;

#if  0    //jack.liu 20200911 获取rtc时间失能
	if(is_rtc) // 装置上电时才用到
	{
		// rtc_time_read(&tm);
	}
	else
#endif
	{
		clk_time_get(&ts);
		timespec_to_rtc(ts,&tm,0);
	}

	// 检查参数
	if(index > LOG_FILE_NUM)
	{
		return -1;
	}
	if(log_buf == NULL)
	{
		return -2;
	}

	 //得到待写入字符串长度
	log_len = strlen(log_buf)+16;                        
	wirte_buf = (char *)rt_malloc(log_len+strlen("2020-07-01 01:01:01.000000 "));
	if((wirte_buf) == NULL)
	{
		return -1; 	
	}	

	//得到系统时间
	sprintf(wirte_buf,"20%02hu-%02hu-%02hu %02hu:%02hu:%02hu.%06lu ",
			tm.year,tm.month,tm.day,tm.hour,tm.min,tm.ms/1000,ts.tv_nsec/1000);
	
	strcat(wirte_buf,log_buf);

	log_str(index,wirte_buf);


	rt_free(wirte_buf);
 
	return 0;
}

int log_file_check(s8 * name)
{
	int i;

	for(i=0; i<LOG_FILE_NUM; i++)
	{
		if(strstr(name,g_log_file[i].name) == 0)
		{
			return i;
		}
	}

	return -1;
}

int log_file_is_overrun(int index)
{
	int file_length;

	if(index >= LOG_FILE_NUM)
	{
		return 1;
	}

	if(g_log_file[index].handle == 0)
	{
		return 1;
	}
	
	 //得到文件长度
	fsync(g_log_file[index].handle);
	file_length= rt_file_getfile_size(g_log_file[index].handle);
	rt_file_llseek(g_log_file[index].handle, 0, SEEK_SET);

	if(g_log_file[index].offset + 128 > g_log_file[index].size)
	{
		return 1;
	}

	return 0;
}


 
