Browse Source

add:ymodem,uart的一些扩展操作,ymodem建议直接在lua操作,c不够灵活

alienwalker 3 years ago
parent
commit
8cdfbaa5b5

+ 150 - 0
components/ymodem/luat_lib_ymodem.c

@@ -0,0 +1,150 @@
+#include "luat_base.h"
+#include "luat_malloc.h"
+#include "luat_ymodem.h"
+#include "luat_zbuff.h"
+#define LUAT_LOG_TAG "ymodem_lib"
+#include "luat_log.h"
+typedef struct
+{
+	void *ctrl;
+}ymodem_handler;
+/*
+创建一个ymodem处理句柄
+@api ymodem.create(dir_path,file_path)
+@string 保存的文件夹路径,默认是"/"
+@string 强制保存的绝对文件路径,默认是空,如果设置了,就会直接保存在该文件中
+@return boolean 成功true, 失败false
+@usage
+local handler = ymodem.create("/")
+*/
+
+static int l_ymodem_create(lua_State *L){
+	ymodem_handler *handler = (ymodem_handler *)lua_newuserdata(L, sizeof(ymodem_handler));
+	size_t len;
+	const char *dir_path,*file_path;
+	if (lua_isstring(L, 1))
+	{
+		dir_path = lua_tolstring(L, 1, &len);
+
+	}
+	else
+	{
+		dir_path = NULL;
+	}
+	if (lua_isstring(L, 2))
+	{
+		file_path = lua_tolstring(L, 2, &len);
+
+	}
+	else
+	{
+		file_path = NULL;
+	}
+	handler->ctrl = luat_ymodem_create_handler(dir_path?dir_path:"/", file_path);
+	lua_pushlightuserdata(L, handler);
+    return 1;
+}
+
+/*
+ymodem接收文件数据并保存
+@api ymodem.receive(handler, data)
+@userdata handler
+@zbuff or string输入的数据
+@return
+boolean 成功true,失败false
+int ack值,需要通过串口/网络等途径返回发送方
+int flag值,需要通过串口/网络等途径返回发送方
+boolean, 一个文件接收完成true,传输中false
+boolean, 整个传输完成true 否则false
+@usage
+*/
+
+static int l_ymodem_receive(lua_State *L){
+	ymodem_handler *handler = (ymodem_handler *)lua_touserdata(L, 1);
+	int result;
+	size_t len;
+	uint8_t ack, flag, file_ok, all_done;
+	char *data;
+	if (handler && handler->ctrl)
+	{
+		if (lua_isstring(L, 2))
+		{
+			data = lua_tolstring(L, 1, &len);
+		}
+		else if(lua_isuserdata(L, 2))
+	    {
+	        luat_zbuff_t *buff = ((luat_zbuff_t *)luaL_checkudata(L, 2, LUAT_ZBUFF_TYPE));
+	        len = buff->used;
+	        data = (const char *)(buff->addr);
+
+	    }
+		else
+		{
+			data = NULL;
+			len = 0;
+		}
+		result = luat_ymodem_receive(handler->ctrl, data, len, &ack, &flag, &file_ok, &all_done);
+		lua_pushboolean(L, !result);
+		lua_pushinteger(L, ack);
+		lua_pushinteger(L, flag);
+		lua_pushboolean(L, file_ok);
+		lua_pushboolean(L, all_done);
+	}
+	else
+	{
+		lua_pushboolean(L, 0);
+		lua_pushnil(L);
+		lua_pushnil(L);
+		lua_pushboolean(L, 0);
+		lua_pushboolean(L, 0);
+	}
+	return 5;
+}
+
+/*
+重置ymodem处理过程,恢复到初始状态,一般用于接收出错后重置,从而进行下一次接收
+@api ymodem.reset(handler)
+@userdata handler
+@return 无
+@usage
+ymodem.reset(handler)
+*/
+
+static int l_ymodem_reset(lua_State *L){
+	ymodem_handler *handler = (ymodem_handler *)lua_touserdata(L, 1);
+	if (handler && handler->ctrl) luat_ymodem_reset(handler->ctrl);
+    return 0;
+}
+
+/*
+释放ymodem处理句柄
+@api ymodem.release(handler)
+@userdata handler
+@return 无
+@usage
+ymodem.release(handler)
+*/
+
+static int l_ymodem_release(lua_State *L){
+	ymodem_handler *handler = (ymodem_handler *)lua_touserdata(L, 1);
+	if (handler && handler->ctrl) {
+		luat_ymodem_release(handler->ctrl);
+		handler->ctrl = NULL;
+	}
+    return 0;
+}
+
+#include "rotable2.h"
+static const rotable_Reg_t reg_ymodem[] =
+{
+    { "create",           ROREG_FUNC(l_ymodem_create)},
+    { "receive",   ROREG_FUNC(l_ymodem_receive)},
+    { "reset",      ROREG_FUNC(l_ymodem_reset)},
+    { "release", ROREG_FUNC(l_ymodem_release)},
+	{ NULL,             {}}
+};
+
+LUAMOD_API int luaopen_ymodem( lua_State *L ) {
+    luat_newlib2(L, reg_ymodem);
+    return 1;
+}

+ 341 - 0
components/ymodem/luat_ymodem.c

@@ -0,0 +1,341 @@
+#include "luat_ymodem.h"
+#include "luat_fs.h"
+#include "luat_malloc.h"
+
+#define LUAT_LOG_TAG "ymodem"
+#include "luat_log.h"
+
+#define XMODEM_FLAG 'C'
+#define XMODEM_SOH 0x01
+#define XMODEM_STX 0x02
+#define XMODEM_EOT 0x04
+#define XMODEM_ACK 0x06
+#define XMODEM_NAK 0x15
+#define XMODEM_CAN 0x18
+#define XMODEM_DATA_POS (3)
+#define XMODEM_SOH_DATA_LEN (128)
+#define XMODEM_STX_DATA_LEN (1024)
+
+typedef struct
+{
+	char *save_path;
+	const char *force_save_path;
+	FILE* fd;
+	uint32_t file_size;
+	uint32_t write_size;
+	uint16_t data_pos;
+	uint16_t data_max;
+	uint8_t state;
+	uint8_t next_sn;
+	uint8_t packet_data[XMODEM_STX_DATA_LEN + 8];
+}ymodem_ctrlstruct;
+
+static uint16_t CRC16_Cal(void *Data, uint16_t Len, uint16_t CRC16Last)
+{
+	uint16_t i;
+	uint16_t CRC16 = CRC16Last;
+	uint8_t *Src = (uint8_t *)Data;
+
+	while (Len--)
+	{
+		for (i = 8; i > 0; i--)
+		{
+			if ((CRC16 & 0x8000) != 0)
+			{
+				CRC16 <<= 1;
+				CRC16 ^= 0x1021;
+			}
+			else
+			{
+				CRC16 <<= 1;
+			}
+			if ((*Src&(1 << (i - 1))) != 0)
+			{
+				CRC16 ^= 0x1021;
+			}
+		}
+		Src++;
+	}
+	return CRC16;
+}
+
+void *luat_ymodem_create_handler(const char *save_path, const char *force_save_path)
+{
+	ymodem_ctrlstruct *handler = luat_heap_malloc(sizeof(ymodem_ctrlstruct));
+	if (handler)
+	{
+		memset(handler, 0, sizeof(ymodem_ctrlstruct));
+		if (save_path)
+		{
+			handler->save_path = luat_heap_malloc(strlen(save_path) + 1);
+			strcpy(handler->save_path, save_path);
+		}
+		if (force_save_path)
+		{
+			handler->force_save_path = luat_heap_malloc(strlen(force_save_path) + 1);
+			strcpy(handler->force_save_path, force_save_path);
+		}
+
+
+	}
+	return handler;
+}
+
+int luat_ymodem_receive(void *handler, uint8_t *data, uint32_t len, uint8_t *ack, uint8_t *flag, uint8_t *file_ok, uint8_t *all_done)
+{
+	ymodem_ctrlstruct *ctrl = handler;
+	uint16_t crc16_org, crc16;
+	uint32_t i, NameEnd, LenEnd;
+	char path[128];
+	*file_ok = 0;
+	*all_done = 0;
+	*flag = 0;
+	if (data)
+	{
+		if (data[0] == XMODEM_CAN)
+		{
+			luat_ymodem_reset(handler);
+			*ack = XMODEM_ACK;
+			*all_done = 1;
+			return 0;
+		}
+	}
+
+	switch (ctrl->state)
+	{
+	case 0:
+		if (!data)
+		{
+			*ack = XMODEM_FLAG;
+			return 0;
+		}
+		else
+		{
+			if ((ctrl->data_pos + len) >= (XMODEM_SOH_DATA_LEN + 5))
+			{
+				memcpy(&ctrl->packet_data[ctrl->data_pos], data, (XMODEM_SOH_DATA_LEN + 5) - ctrl->data_pos);
+				if (ctrl->packet_data[0] != XMODEM_SOH || ctrl->packet_data[1] != 0x00 || ctrl->packet_data[2] != 0xff)
+				{
+					LLOGD("head %x %x %x", ctrl->packet_data[0], ctrl->packet_data[1], ctrl->packet_data[2]);
+					goto DATA_RECIEVE_ERROR;
+				}
+				crc16_org = ctrl->packet_data[XMODEM_SOH_DATA_LEN + 3];
+				crc16_org = (crc16_org << 8) + ctrl->packet_data[XMODEM_SOH_DATA_LEN + 4];
+				crc16 = CRC16_Cal(&ctrl->packet_data[XMODEM_DATA_POS], XMODEM_SOH_DATA_LEN, 0);
+				if (crc16 != crc16_org)
+				{
+					LLOGD("crc16 %x %x ", crc16, crc16_org);
+					goto DATA_RECIEVE_ERROR;
+				}
+				else
+				{
+					if (!ctrl->packet_data[XMODEM_DATA_POS])
+					{
+						luat_ymodem_reset(handler);
+						*ack = XMODEM_ACK;
+						*all_done = 1;
+						return 0;
+					}
+					NameEnd = NULL;
+					for(i = XMODEM_DATA_POS; i++; i < (XMODEM_SOH_DATA_LEN + 5))
+					{
+						if (!ctrl->packet_data[i])
+						{
+							NameEnd = i;
+							break;
+						}
+					}
+					if (!NameEnd)
+					{
+						LLOGD("name end");
+						goto DATA_RECIEVE_ERROR;
+					}
+					LenEnd = NULL;
+					for(i = (NameEnd + 1); i++; i < (XMODEM_SOH_DATA_LEN + 5))
+					{
+						if (!ctrl->packet_data[i])
+						{
+							LenEnd = i;
+							break;
+						}
+					}
+					if (!LenEnd)
+					{
+						LLOGD("len end");
+						goto DATA_RECIEVE_ERROR;
+					}
+
+					ctrl->file_size = strtol(&ctrl->packet_data[NameEnd + 1], NULL, 10);
+					ctrl->write_size = 0;
+					if (ctrl->force_save_path)
+					{
+						ctrl->fd = luat_fs_fopen(ctrl->force_save_path, "w");
+						LLOGD("%s,%u,%x", ctrl->force_save_path, ctrl->file_size, ctrl->fd);
+					}
+					else
+					{
+						sprintf_(path, "%s%s", ctrl->save_path, &ctrl->packet_data[XMODEM_DATA_POS]);
+						ctrl->fd = luat_fs_fopen(path, "w");
+						LLOGD("%s,%u,%x", path, ctrl->file_size, ctrl->fd);
+					}
+
+
+
+					ctrl->state++;
+					ctrl->next_sn = 0;
+					ctrl->data_max = (XMODEM_STX_DATA_LEN + 5);
+					*flag = XMODEM_FLAG;
+					goto DATA_RECIEVE_OK;
+				}
+			}
+			else
+			{
+				memcpy(&ctrl->packet_data[ctrl->data_pos], data, len);
+				ctrl->data_pos += len;
+			}
+		}
+		break;
+	case 1:
+		if (!ctrl->data_pos)
+		{
+			switch(data[0])
+			{
+			case XMODEM_STX:
+				ctrl->data_max = (XMODEM_STX_DATA_LEN + 5);
+				break;
+			case XMODEM_SOH:
+				ctrl->data_max = (XMODEM_SOH_DATA_LEN + 5);
+				break;
+			default:
+				goto DATA_RECIEVE_ERROR;
+				break;
+			}
+			memcpy(ctrl->packet_data, data, len);
+			if (len >= ctrl->data_max) goto YMODEM_DATA_CHECK;
+		}
+		else
+		{
+			if ((ctrl->data_pos + len) >= ctrl->data_max)
+			{
+				memcpy(&ctrl->packet_data[ctrl->data_pos], data, ctrl->data_max - ctrl->data_pos);
+YMODEM_DATA_CHECK:
+				switch(ctrl->packet_data[0])
+				{
+				case XMODEM_SOH:
+					if (ctrl->packet_data[1] != ctrl->next_sn || ctrl->packet_data[2] != (255 - ctrl->next_sn))
+					{
+						LLOGD("head %x %x %x", ctrl->packet_data[0], ctrl->packet_data[1], ctrl->packet_data[2]);
+						goto DATA_RECIEVE_ERROR;
+					}
+
+					crc16_org = ctrl->packet_data[XMODEM_SOH_DATA_LEN + 3];
+					crc16_org = (crc16_org << 8) + ctrl->packet_data[XMODEM_SOH_DATA_LEN + 4];
+					crc16 = CRC16_Cal(&ctrl->packet_data[XMODEM_DATA_POS], XMODEM_SOH_DATA_LEN, 0);
+					if (crc16 != crc16_org)
+					{
+						LLOGD("crc16 %x %x ", crc16, crc16_org);
+						goto DATA_RECIEVE_ERROR;
+					}
+					LenEnd = ((ctrl->file_size - ctrl->write_size) > XMODEM_SOH_DATA_LEN)?XMODEM_SOH_DATA_LEN:(ctrl->file_size - ctrl->write_size);
+					luat_fs_fwrite(ctrl->packet_data, LenEnd, 1, ctrl->fd);
+					ctrl->write_size += LenEnd;
+					goto DATA_RECIEVE_OK;
+					break;
+				case XMODEM_STX:
+					if (ctrl->packet_data[1] != ctrl->next_sn || (ctrl->packet_data[2] != (255 - ctrl->next_sn)))
+					{
+						LLOGD("head %x %x %x", ctrl->packet_data[0], ctrl->packet_data[1], ctrl->packet_data[2]);
+						goto DATA_RECIEVE_ERROR;
+					}
+
+					crc16_org = ctrl->packet_data[XMODEM_STX_DATA_LEN + 3];
+					crc16_org = (crc16_org << 8) + ctrl->packet_data[XMODEM_STX_DATA_LEN + 4];
+					crc16 = CRC16_Cal(&ctrl->packet_data[XMODEM_DATA_POS], XMODEM_STX_DATA_LEN, 0);
+					if (crc16 != crc16_org)
+					{
+						LLOGD("crc16 %x %x ", crc16, crc16_org);
+						goto DATA_RECIEVE_ERROR;
+					}
+					//写入
+					LenEnd = ((ctrl->file_size - ctrl->write_size) > XMODEM_STX_DATA_LEN)?XMODEM_STX_DATA_LEN:(ctrl->file_size - ctrl->write_size);
+					luat_fs_fwrite(ctrl->packet_data, LenEnd, 1, ctrl->fd);
+					ctrl->write_size += LenEnd;
+					goto DATA_RECIEVE_OK;
+					break;
+				default:
+					if (ctrl->packet_data[1] != ctrl->next_sn || ctrl->packet_data[2] != ~ctrl->next_sn)
+					{
+						LLOGD("head %x %x %x", ctrl->packet_data[0], ctrl->packet_data[1], ctrl->packet_data[2]);
+						goto DATA_RECIEVE_ERROR;
+					}
+					goto DATA_RECIEVE_OK;
+				}
+			}
+			else
+			{
+				memcpy(&ctrl->packet_data[ctrl->data_pos], data, len);
+				ctrl->data_pos += len;
+			}
+		}
+		break;
+	case 2:
+		ctrl->state++;
+		ctrl->data_pos = 0;
+		*ack = XMODEM_NAK;
+		return 0;
+
+	case 3:
+		if (data[0] == XMODEM_EOT)
+		{
+			ctrl->state = 0;
+			*flag = XMODEM_FLAG;
+			*ack = XMODEM_ACK;
+			return 0;
+		}
+		else
+		{
+			goto DATA_RECIEVE_ERROR;
+		}
+		break;
+	default:
+		return -1;
+	}
+	*ack = 0;
+	return 0;
+DATA_RECIEVE_ERROR:
+	ctrl->data_pos = 0;
+	*ack = XMODEM_NAK;
+	*flag = 0;
+	*all_done = 0;
+	return -1;
+DATA_RECIEVE_OK:
+	ctrl->data_pos = 0;
+	ctrl->next_sn++;
+	*ack = XMODEM_ACK;
+	if (ctrl->file_size && (ctrl->write_size >= ctrl->file_size))
+	{
+		luat_fs_fclose(ctrl->fd);
+		ctrl->fd = NULL;
+		ctrl->state = 2;
+		*file_ok = 1;
+	}
+	return 0;
+}
+
+void luat_ymodem_reset(void *handler)
+{
+	ymodem_ctrlstruct *ctrl = handler;
+	ctrl->state = 0;
+	ctrl->next_sn = 0;
+	ctrl->file_size = 0;
+	if (ctrl->fd) luat_fs_fclose(ctrl->fd);
+	ctrl->fd = NULL;
+}
+
+void luat_ymodem_release(void *handler)
+{
+	ymodem_ctrlstruct *ctrl = handler;
+	luat_ymodem_reset(handler);
+	luat_heap_free(ctrl->save_path);
+	luat_heap_free(handler);
+}

+ 22 - 0
components/ymodem/luat_ymodem.h

@@ -0,0 +1,22 @@
+#ifndef __LUAT_YMODEM_H__
+#define __LUAT_YMODEM_H__
+
+#include "luat_base.h"
+
+//save_path为保存文件夹路径
+//force_save_path强制保存文件路径,优先于save_path
+void *luat_ymodem_create_handler(const char *save_path, const char *force_save_path);
+//收文件
+//握手阶段,data为NULL,ack='c'
+//数据阶段,如果收完一整个包,根据解析结果ack返回成功或者失败符号,如果不完整,则ack=0
+//调用完后,如果ack不为0,则需要将ack发送出去
+//调用完后,如果flag不为0,则需要将flag发送出去
+//如果return不为0,有NAK发生
+//文件接收完成后file_ok=1
+//接收到停止帧或者取消帧后all_done=1
+int luat_ymodem_receive(void *handler, uint8_t *data, uint32_t len, uint8_t *ack, uint8_t *flag, uint8_t *file_ok, uint8_t *all_done);
+
+void luat_ymodem_reset(void *handler);
+//ymodem传输完成后,调用一下保存文件并且释放资源
+void luat_ymodem_release(void *handler);
+#endif

+ 93 - 0
luat/modules/luat_lib_uart.c

@@ -148,6 +148,48 @@ static int l_uart_write(lua_State *L)
     return 1;
 }
 
+/*
+buff形式写串口,等同于c语言uart_tx(uart_id, &buff[start], len);
+@api    uart.tx(id, buff, start, len)
+@int 串口id, uart0写0, uart1写1
+@zbuff 待写入的数据,如果是zbuff会从指针起始位置开始读
+@int 可选,要发送的数据起始位置,默认为0
+@int 可选,要发送的数据长度,默认为zbuff内有效数据,最大值不超过zbuff的最大空间
+@return int 成功的数据长度
+@usage
+uart.tx(1, buf)
+*/
+static int l_uart_tx(lua_State *L)
+{
+    size_t start, len;
+    const char *buf;
+    luat_zbuff_t *buff;
+    uint8_t id = luaL_checkinteger(L, 1);
+    if(lua_isuserdata(L, 2))
+    {
+        buff = ((luat_zbuff_t *)luaL_checkudata(L, 2, LUAT_ZBUFF_TYPE));
+    }
+    else
+    {
+    	lua_pushinteger(L, 0);
+    	return 1;
+    }
+    start = luaL_optinteger(L, 3, 0);
+    len = luaL_optinteger(L, 4, buff->used);
+    if (start >= buff->len)
+    {
+    	lua_pushinteger(L, 0);
+    	return 1;
+    }
+    if ((start + len)>= buff->len)
+    {
+    	len = buff->len - start;
+    }
+    int result = luat_uart_write(id, buff->addr + start, len);
+    lua_pushinteger(L, result);
+    return 1;
+}
+
 /*
 读串口
 @api    uart.read(id, len)
@@ -213,6 +255,53 @@ static int l_uart_read(lua_State *L)
     return 1;
 }
 
+/*
+buff形式读串口,一次读出全部数据存入buff中,如果buff空间不够会自动扩展,目前只有air105支持这个操作
+@api    uart.read(id, buff)
+@int 串口id, uart0写0, uart1写1
+@zbuff zbuff对象
+@return 返回读到的长度,并把zbuff指针后移
+@usage
+uart.read(1, buff)
+*/
+static int l_uart_rx(lua_State *L)
+{
+    uint8_t id = luaL_checkinteger(L, 1);
+
+    if(lua_isuserdata(L, 2)){//zbuff对象特殊处理
+    	luat_zbuff_t *buff = ((luat_zbuff_t *)luaL_checkudata(L, 2, LUAT_ZBUFF_TYPE));
+        int result = luat_uart_read(id, NULL, 0);	//读出当前缓存的长度,目前只有105支持这个操作
+        if (result > (buff->len - buff->used))
+        {
+        	__zbuff_resize(buff, buff->len + result);
+        }
+        luat_uart_read(id, buff->addr + buff->used, result);
+        lua_pushinteger(L, result);
+        buff->used += result;
+        return 1;
+    }
+    else
+    {
+        lua_pushinteger(L, 0);
+        return 1;
+    }
+    return 1;
+}
+
+/*
+读串口Rx缓存中剩余数据量,目前只有air105支持这个操作
+@api    uart.rx_size(id)
+@int 串口id, uart0写0, uart1写1
+@return 返回读到的长度
+@usage
+local size = uart.rx_size(1)
+*/
+static int l_uart_rx_size(lua_State *L)
+{
+    uint8_t id = luaL_checkinteger(L, 1);
+    lua_pushinteger(L, luat_uart_read(id, NULL, 0));//读出当前缓存的长度,目前只有105支持这个操作
+    return 1;
+}
 /*
 关闭串口
 @api    uart.close(id)
@@ -290,6 +379,10 @@ static const rotable_Reg_t reg_uart[] =
     //高低位顺序
     { "LSB",        ROREG_INT(LUAT_BIT_ORDER_LSB)},
     { "MSB",        ROREG_INT(LUAT_BIT_ORDER_MSB)},
+
+    { "tx",      ROREG_FUNC(l_uart_tx)},
+    { "rx",       ROREG_FUNC(l_uart_rx)},
+	{ "rx_size",	ROREG_FUNC(l_uart_rx_size)},
     { NULL,         {}}
 };