From c07a78ae005b9e41801f1d7f8e90a37d4d7f4449 Mon Sep 17 00:00:00 2001 From: prife Date: Sat, 11 Jan 2014 14:57:02 +0800 Subject: [PATCH 01/59] nfs: fix bug I have to mention that this bug is introduced by myself, in the last commit to dfs_nfs.c --- components/dfs/filesystems/nfs/dfs_nfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/dfs/filesystems/nfs/dfs_nfs.c b/components/dfs/filesystems/nfs/dfs_nfs.c index 3709cc33fe..0f40fa4292 100644 --- a/components/dfs/filesystems/nfs/dfs_nfs.c +++ b/components/dfs/filesystems/nfs/dfs_nfs.c @@ -233,7 +233,7 @@ static nfs_fh3 *get_dir_handle(struct nfs_filesystem *nfs, const char *name) copy_handle(handle, &nfs->current_handle); } - while ((file = strtok_r(RT_NULL, "/", &path)) != RT_NULL && path != RT_NULL) + while ((file = strtok_r(RT_NULL, "/", &path)) != RT_NULL && path[0] != 0) { LOOKUP3args args; LOOKUP3res res; From b9c660587680fc503ddec6717bd228630dd2d527 Mon Sep 17 00:00:00 2001 From: RTsien Date: Sat, 11 Jan 2014 15:04:19 +0800 Subject: [PATCH 02/59] add operating definitions of UART0 to UART5 --- bsp/beaglebone/drivers/serial.c | 231 ++++++++++++++++++++++++++++---- 1 file changed, 202 insertions(+), 29 deletions(-) diff --git a/bsp/beaglebone/drivers/serial.c b/bsp/beaglebone/drivers/serial.c index b29ffc9963..077f78ea3b 100644 --- a/bsp/beaglebone/drivers/serial.c +++ b/bsp/beaglebone/drivers/serial.c @@ -10,6 +10,7 @@ * Change Logs: * Date Author Notes * 2013-07-06 Bernard the first version + * 2014-01-11 RTsien add definitions of UART0 to UART5 */ #include @@ -162,14 +163,18 @@ static const struct rt_uart_ops am33xx_uart_ops = am33xx_getc, }; -/* UART1 device driver structure */ -struct serial_ringbuffer uart1_int_rx; -struct am33xx_uart uart1 = +/* UART device driver structure */ +struct serial_ringbuffer uart_int_rx[6]; +struct am33xx_uart uart[6] = { - UART0_BASE, - UART0_INT, + {UART0_BASE,UART0_INT}, + {UART1_BASE,UART1_INT}, + {UART2_BASE,UART2_INT}, + {UART3_BASE,UART3_INT}, + {UART4_BASE,UART4_INT}, + {UART5_BASE,UART5_INT} }; -struct rt_serial_device serial1; +struct rt_serial_device serial[6]; #define write_reg(base, value) *(int*)(base) = value #define read_reg(base) *(int*)(base) @@ -219,11 +224,46 @@ static void start_uart_clk(void) ; /* enable uart1 */ +#ifdef RT_USING_UART1 CM_PER_UART1_CLKCTRL_REG(prcm_base) |= 0x2; /* wait for uart1 clk */ while ((CM_PER_UART1_CLKCTRL_REG(prcm_base) & (0x3<<16)) != 0) ; +#endif + +#ifdef RT_USING_UART2 + CM_PER_UART2_CLKCTRL_REG(prcm_base) |= 0x2; + + /* wait for uart2 clk */ + while ((CM_PER_UART2_CLKCTRL_REG(prcm_base) & (0x3<<16)) != 0) + ; +#endif + +#ifdef RT_USING_UART3 + CM_PER_UART3_CLKCTRL_REG(prcm_base) |= 0x2; + + /* wait for uart3 clk */ + while ((CM_PER_UART3_CLKCTRL_REG(prcm_base) & (0x3<<16)) != 0) + ; +#endif + +#ifdef RT_USING_UART4 + CM_PER_UART4_CLKCTRL_REG(prcm_base) |= 0x2; + + /* wait for uart4 clk */ + while ((CM_PER_UART4_CLKCTRL_REG(prcm_base) & (0x3<<16)) != 0) + ; +#endif + +#ifdef RT_USING_UART5 + CM_PER_UART5_CLKCTRL_REG(prcm_base) |= 0x2; + + /* wait for uart5 clk */ + while ((CM_PER_UART5_CLKCTRL_REG(prcm_base) & (0x3<<16)) != 0) + ; +#endif + /* Waiting for the L4LS UART clock */ while (!(CM_PER_L4LS_CLKSTCTRL_REG(prcm_base) & (1<<10))) ; @@ -236,44 +276,177 @@ static void config_pinmux(void) ctlm_base = AM33XX_CTLM_REGS; /* make sure the pin mux is OK for uart */ +#ifdef RT_USING_UART1 REG32(ctlm_base + 0x800 + 0x180) = 0x20; REG32(ctlm_base + 0x800 + 0x184) = 0x00; +#endif + +#ifdef RT_USING_UART2 + REG32(ctlm_base + 0x800 + 0x150) = 0x20; + REG32(ctlm_base + 0x800 + 0x154) = 0x00; +#endif + +#ifdef RT_USING_UART3 + REG32(ctlm_base + 0x800 + 0x164) = 0x01; +#endif + +#ifdef RT_USING_UART4 + REG32(ctlm_base + 0x800 + 0x070) = 0x26; + REG32(ctlm_base + 0x800 + 0x074) = 0x06; +#endif + +#ifdef RT_USING_UART5 + REG32(ctlm_base + 0x800 + 0x0C4) = 0x24; + REG32(ctlm_base + 0x800 + 0x0C0) = 0x04; +#endif + + } int rt_hw_serial_init(void) { - struct am33xx_uart* uart; - struct serial_configure config; - - uart = &uart1; - uart->base = UART1_BASE; + struct serial_configure config[6]; poweron_per_domain(); start_uart_clk(); config_pinmux(); - config.baud_rate = BAUD_RATE_115200; - config.bit_order = BIT_ORDER_LSB; - config.data_bits = DATA_BITS_8; - config.parity = PARITY_NONE; - config.stop_bits = STOP_BITS_1; - config.invert = NRZ_NORMAL; - - serial1.ops = &am33xx_uart_ops; - serial1.int_rx = &uart1_int_rx; - serial1.config = config; +#ifdef RT_USING_UART0 + config[0].baud_rate = BAUD_RATE_115200; + config[0].bit_order = BIT_ORDER_LSB; + config[0].data_bits = DATA_BITS_8; + config[0].parity = PARITY_NONE; + config[0].stop_bits = STOP_BITS_1; + config[0].invert = NRZ_NORMAL; + serial[0].ops = &am33xx_uart_ops; + serial[0].int_rx = &uart_int_rx[0]; + serial[0].config = config[0]; /* enable RX interrupt */ - UART_IER_REG(uart->base) = 0x01; + UART_IER_REG(uart[0].base) = 0x01; /* install ISR */ - rt_hw_interrupt_install(uart->irq, am33xx_uart_isr, &serial1, "uart1"); - rt_hw_interrupt_control(uart->irq, 0, 0); - rt_hw_interrupt_mask(uart->irq); - - /* register UART1 device */ - rt_hw_serial_register(&serial1, "uart1", + rt_hw_interrupt_install(uart[0].irq, am33xx_uart_isr, &serial[0], "uart0"); + rt_hw_interrupt_control(uart[0].irq, 0, 0); + rt_hw_interrupt_mask(uart[0].irq); + /* register UART0 device */ + rt_hw_serial_register(&serial[0], "uart0", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, - uart); + &uart[0]); +#endif + +#ifdef RT_USING_UART1 + config[1].baud_rate = BAUD_RATE_115200; + config[1].bit_order = BIT_ORDER_LSB; + config[1].data_bits = DATA_BITS_8; + config[1].parity = PARITY_NONE; + config[1].stop_bits = STOP_BITS_1; + config[1].invert = NRZ_NORMAL; + + serial[1].ops = &am33xx_uart_ops; + serial[1].int_rx = &uart_int_rx[1]; + serial[1].config = config[1]; + /* enable RX interrupt */ + UART_IER_REG(uart[1].base) = 0x01; + /* install ISR */ + rt_hw_interrupt_install(uart[1].irq, am33xx_uart_isr, &serial[1], "uart1"); + rt_hw_interrupt_control(uart[1].irq, 0, 0); + rt_hw_interrupt_mask(uart[1].irq); + /* register UART0 device */ + rt_hw_serial_register(&serial[1], "uart1", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, + &uart[1]); +#endif + +#ifdef RT_USING_UART2 + config[2].baud_rate = BAUD_RATE_115200; + config[2].bit_order = BIT_ORDER_LSB; + config[2].data_bits = DATA_BITS_8; + config[2].parity = PARITY_NONE; + config[2].stop_bits = STOP_BITS_1; + config[2].invert = NRZ_NORMAL; + + serial[2].ops = &am33xx_uart_ops; + serial[2].int_rx = &uart_int_rx[2]; + serial[2].config = config[2]; + /* enable RX interrupt */ + UART_IER_REG(uart[2].base) = 0x01; + /* install ISR */ + rt_hw_interrupt_install(uart[2].irq, am33xx_uart_isr, &serial[2], "uart2"); + rt_hw_interrupt_control(uart[2].irq, 0, 0); + rt_hw_interrupt_mask(uart[2].irq); + /* register UART2 device */ + rt_hw_serial_register(&serial[2], "uart2", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, + &uart[2]); +#endif + +#ifdef RT_USING_UART3 + config[3].baud_rate = BAUD_RATE_115200; + config[3].bit_order = BIT_ORDER_LSB; + config[3].data_bits = DATA_BITS_8; + config[3].parity = PARITY_NONE; + config[3].stop_bits = STOP_BITS_1; + config[3].invert = NRZ_NORMAL; + serial[3].ops = &am33xx_uart_ops; + serial[3].int_rx = &uart_int_rx[3]; + serial[3].config = config[3]; + /* enable RX interrupt */ + UART_IER_REG(uart[3].base) = 0x01; + /* install ISR */ + rt_hw_interrupt_install(uart[3].irq, am33xx_uart_isr, &serial[3], "uart3"); + rt_hw_interrupt_control(uart[3].irq, 0, 0); + rt_hw_interrupt_mask(uart[3].irq); + /* register UART3 device */ + rt_hw_serial_register(&serial[3], "uart3", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, + &uart[3]); +#endif + +#ifdef RT_USING_UART4 + config[4].baud_rate = BAUD_RATE_115200; + config[4].bit_order = BIT_ORDER_LSB; + config[4].data_bits = DATA_BITS_8; + config[4].parity = PARITY_NONE; + config[4].stop_bits = STOP_BITS_1; + config[4].invert = NRZ_NORMAL; + + serial[4].ops = &am33xx_uart_ops; + serial[4].int_rx = &uart_int_rx[4]; + serial[4].config = config[4]; + /* enable RX interrupt */ + UART_IER_REG(uart[4].base) = 0x01; + /* install ISR */ + rt_hw_interrupt_install(uart[4].irq, am33xx_uart_isr, &serial[4], "uart4"); + rt_hw_interrupt_control(uart[4].irq, 0, 0); + rt_hw_interrupt_mask(uart[4].irq); + /* register UART4 device */ + rt_hw_serial_register(&serial[4], "uart4", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, + &uart[4]); +#endif + +#ifdef RT_USING_UART5 + config[5].baud_rate = BAUD_RATE_115200; + config[5].bit_order = BIT_ORDER_LSB; + config[5].data_bits = DATA_BITS_8; + config[5].parity = PARITY_NONE; + config[5].stop_bits = STOP_BITS_1; + config[5].invert = NRZ_NORMAL; + + serial[5].ops = &am33xx_uart_ops; + serial[5].int_rx = &uart_int_rx[5]; + serial[5].config = config[5]; + /* enable RX interrupt */ + UART_IER_REG(uart[5].base) = 0x01; + /* install ISR */ + rt_hw_interrupt_install(uart[5].irq, am33xx_uart_isr, &serial[5], "uart5"); + rt_hw_interrupt_control(uart[5].irq, 0, 0); + rt_hw_interrupt_mask(uart[5].irq); + /* register UART4 device */ + rt_hw_serial_register(&serial[5], "uart5", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, + &uart[5]); +#endif return 0; } From faf3515e6bcbd049ca2a0eaea339fc687de7f8e0 Mon Sep 17 00:00:00 2001 From: RTsien Date: Sat, 11 Jan 2014 15:05:51 +0800 Subject: [PATCH 03/59] support UART0 to UART5 straightly --- bsp/beaglebone/drivers/serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bsp/beaglebone/drivers/serial.c b/bsp/beaglebone/drivers/serial.c index 077f78ea3b..af93048ac9 100644 --- a/bsp/beaglebone/drivers/serial.c +++ b/bsp/beaglebone/drivers/serial.c @@ -10,7 +10,7 @@ * Change Logs: * Date Author Notes * 2013-07-06 Bernard the first version - * 2014-01-11 RTsien add definitions of UART0 to UART5 + * 2014-01-11 RTsien support UART0 to UART5 straightly */ #include From ef09b822b71795759a9bfbf5903e069b7b2668d6 Mon Sep 17 00:00:00 2001 From: RTsien Date: Sat, 11 Jan 2014 15:09:43 +0800 Subject: [PATCH 04/59] add RT_USING_UARTx and set console via uart0 --- bsp/beaglebone/rtconfig.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/bsp/beaglebone/rtconfig.h b/bsp/beaglebone/rtconfig.h index 27992c84cd..15326d74cf 100644 --- a/bsp/beaglebone/rtconfig.h +++ b/bsp/beaglebone/rtconfig.h @@ -73,6 +73,18 @@ #define RT_USING_DEVICE_IPC // #define RT_USING_SERIAL +// +#define RT_USING_UART0 +// +#define RT_USING_UART1 +// +#define RT_USING_UART2 +// +//#define RT_USING_UART3 +// +#define RT_USING_UART4 +// +#define RT_USING_UART5 // #define RT_UART_RX_BUFFER_SIZE 64 // @@ -84,7 +96,7 @@ // #define RT_CONSOLEBUF_SIZE 128 // -#define RT_CONSOLE_DEVICE_NAME "uart1" +#define RT_CONSOLE_DEVICE_NAME "uart0" // // From 9382a7105f9e14bd74398983aa0c526b4e3dd0dd Mon Sep 17 00:00:00 2001 From: RTsien Date: Sat, 11 Jan 2014 15:14:36 +0800 Subject: [PATCH 05/59] add CM_PER_UARTx_CLKCTRL --- libcpu/arm/am335x/am33xx.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libcpu/arm/am335x/am33xx.h b/libcpu/arm/am335x/am33xx.h index 86ed82750a..68ea4478d3 100644 --- a/libcpu/arm/am335x/am33xx.h +++ b/libcpu/arm/am335x/am33xx.h @@ -84,7 +84,11 @@ #define CM_PER(base) ((base) + 0) #define CM_PER_L4LS_CLKSTCTRL(base) (CM_PER(base) + 0) -#define CM_PER_UART1_CLKCTRL(base) (CM_PER(base) + 0x06C) +#define CM_PER_UART1_CLKCTRL(base) (CM_PER(base) + 0x6C) +#define CM_PER_UART2_CLKCTRL(base) (CM_PER(base) + 0x70) +#define CM_PER_UART3_CLKCTRL(base) (CM_PER(base) + 0x74) +#define CM_PER_UART4_CLKCTRL(base) (CM_PER(base) + 0x78) +#define CM_PER_UART5_CLKCTRL(base) (CM_PER(base) + 0x38) #define CM_WKUP(base) ((base) + 0x400) #define CM_DPLL(base) ((base) + 0x500) #define CM_MPU(base) ((base) + 0x600) @@ -171,6 +175,10 @@ /* PRCM registers */ #define CM_PER_L4LS_CLKSTCTRL_REG(base) REG32((base) + 0x0) #define CM_PER_UART1_CLKCTRL_REG(base) REG32(CM_PER_UART1_CLKCTRL(base)) +#define CM_PER_UART2_CLKCTRL_REG(base) REG32(CM_PER_UART2_CLKCTRL(base)) +#define CM_PER_UART3_CLKCTRL_REG(base) REG32(CM_PER_UART3_CLKCTRL(base)) +#define CM_PER_UART4_CLKCTRL_REG(base) REG32(CM_PER_UART4_CLKCTRL(base)) +#define CM_PER_UART5_CLKCTRL_REG(base) REG32(CM_PER_UART5_CLKCTRL(base)) #define CM_PER_TIMER7_CLKCTRL(base) REG32((base) + 0x7C) #define CM_PER_TIMER2_CLKCTRL(base) REG32((base) + 0x80) From 31446eab4c01fc7382ad7cd6363c253852ec1235 Mon Sep 17 00:00:00 2001 From: bernard Date: Sat, 11 Jan 2014 16:33:31 +0800 Subject: [PATCH 06/59] [Kernel] application module can support arguments --- components/finsh/msh.c | 64 +++-- components/net/lwip-1.4.1/src/arch/sys_arch.c | 8 + include/rtdef.h | 15 +- include/rtthread.h | 1 + src/module.c | 261 +++++++++++++++++- 5 files changed, 304 insertions(+), 45 deletions(-) diff --git a/components/finsh/msh.c b/components/finsh/msh.c index b6ebdf2ac9..8da80fad5b 100644 --- a/components/finsh/msh.c +++ b/components/finsh/msh.c @@ -155,7 +155,7 @@ static int msh_split(char* cmd, rt_size_t length, char* argv[RT_FINSH_ARG_MAX]) return argc; } -static cmd_function_t msh_get_cmd(char *cmd) +static cmd_function_t msh_get_cmd(char *cmd, int size) { struct finsh_syscall *index; cmd_function_t cmd_func = RT_NULL; @@ -166,7 +166,7 @@ static cmd_function_t msh_get_cmd(char *cmd) { if (strncmp(index->name, "__cmd_", 6) != 0) continue; - if (strcmp(&index->name[6], cmd) == 0) + if (strncmp(&index->name[6], cmd, size) == 0) { cmd_func = (cmd_function_t)index->func; break; @@ -177,33 +177,40 @@ static cmd_function_t msh_get_cmd(char *cmd) } #if defined(RT_USING_MODULE) && defined(RT_USING_DFS) -int msh_exec_module(int argc, char** argv) +int msh_exec_module(char* cmd_line, int size) { int fd = -1; char *pg_name; - int length, cmd_length; + int length, cmd_length = 0; - if (argc == 0) return -RT_ERROR; /* no command */ + if (size == 0) return -RT_ERROR; /* no command */ + /* get the length of command0 */ + while ((cmd_line[cmd_length] != ' ' && cmd_line[cmd_length] != '\t') && cmd_length < size) + cmd_length ++; /* get name length */ - cmd_length = rt_strlen(argv[0]); length = cmd_length + 32; + length = cmd_length + 32; + /* allocate program name memory */ pg_name = (char*) rt_malloc(length); if (pg_name == RT_NULL) return -RT_ENOMEM; /* no memory */ - if (strstr(argv[0], ".mo") != RT_NULL || strstr(argv[0], ".MO") != RT_NULL) + /* copy command0 */ + memcpy(pg_name, cmd_line, cmd_length); + pg_name[cmd_length] = '\0'; + + if (strstr(pg_name, ".mo") != RT_NULL || strstr(pg_name, ".MO") != RT_NULL) { /* try to open program */ if (fd < 0) { - rt_snprintf(pg_name, length - 1, "%s", argv[0]); fd = open(pg_name, O_RDONLY, 0); } /* search in /bin path */ if (fd < 0) { - rt_snprintf(pg_name, length - 1, "/bin/%s", argv[0]); + rt_snprintf(pg_name, length - 1, "/bin/%.*s", cmd_length, cmd_line); fd = open(pg_name, O_RDONLY, 0); } } @@ -214,27 +221,27 @@ int msh_exec_module(int argc, char** argv) /* try to open program */ if (fd < 0) { - rt_snprintf(pg_name, length - 1, "%s.mo", argv[0]); + strcat(pg_name, ".mo"); fd = open(pg_name, O_RDONLY, 0); } /* search in /bin path */ if (fd < 0) { - rt_snprintf(pg_name, length - 1, "/bin/%s.mo", argv[0]); + rt_snprintf(pg_name, length - 1, "/bin/%.*s.mo", cmd_length, cmd_line); fd = open(pg_name, O_RDONLY, 0); } } - + if (fd >= 0) { /* found program */ close(fd); - rt_module_open(pg_name); + rt_module_exec_cmd(pg_name, cmd_line, size); } else { - rt_kprintf("%s: program not found.\n", argv[0]); + rt_kprintf("%s: program not found.\n", pg_name); } rt_free(pg_name); @@ -247,24 +254,29 @@ int msh_exec(char* cmd, rt_size_t length) int argc; char *argv[RT_FINSH_ARG_MAX]; + int cmd0_size = 0; cmd_function_t cmd_func; + while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length) + cmd0_size ++; + + /* try to get built-in command */ + cmd_func = msh_get_cmd(cmd, cmd0_size); + if (cmd_func == RT_NULL) + { +#ifdef RT_USING_MODULE + msh_exec_module(cmd, length); +#else + rt_kprintf("%s: command not found.\n", argv[0]); +#endif + return -1; + } + + /* split arguments */ memset(argv, 0x00, sizeof(argv)); argc = msh_split(cmd, length, argv); if (argc == 0) return -1; - /* get command in internal commands */ - cmd_func = msh_get_cmd(argv[0]); - if (cmd_func == RT_NULL) - { -#ifdef RT_USING_MODULE - msh_exec_module(argc, argv); -#else - rt_kprintf("%s: command not found.\n", argv[0]); -#endif - return -1; - } - /* exec this command */ return cmd_func(argc, argv); } diff --git a/components/net/lwip-1.4.1/src/arch/sys_arch.c b/components/net/lwip-1.4.1/src/arch/sys_arch.c index 958803f156..ee1d952410 100644 --- a/components/net/lwip-1.4.1/src/arch/sys_arch.c +++ b/components/net/lwip-1.4.1/src/arch/sys_arch.c @@ -622,6 +622,14 @@ RTM_EXPORT(lwip_select); RTM_EXPORT(lwip_ioctl); RTM_EXPORT(lwip_fcntl); +RTM_EXPORT(lwip_htons); +RTM_EXPORT(lwip_ntohs); +RTM_EXPORT(lwip_htonl); +RTM_EXPORT(lwip_ntohl); + +RTM_EXPORT(ipaddr_aton); +RTM_EXPORT(ipaddr_ntoa); + #if LWIP_DNS #include RTM_EXPORT(lwip_gethostbyname); diff --git a/include/rtdef.h b/include/rtdef.h index e21bc4eb41..3c91ae7d8d 100644 --- a/include/rtdef.h +++ b/include/rtdef.h @@ -952,10 +952,11 @@ struct rt_module rt_uint8_t *module_space; /**< module memory space */ - void *module_entry; /**< entry address of module's thread */ - rt_thread_t module_thread; /**< stack size of module's thread */ - rt_uint32_t stack_size; /**< priority of module's thread */ - rt_uint32_t thread_priority; + void *module_entry; /**< the entry address of module */ + rt_thread_t module_thread; /**< the main thread of module */ + + rt_uint8_t* module_cmd_line; /**< module command line */ + rt_uint32_t module_cmd_size; /**< the size of module command line */ #ifdef RT_USING_SLAB /* module memory allocator */ @@ -964,10 +965,10 @@ struct rt_module rt_uint32_t page_cnt; /**< module's using pages count */ #endif - rt_uint32_t nsym; /**< number of symbol in the module */ - struct rt_module_symtab *symtab; /**< module symbol table */ + rt_uint16_t nref; /**< reference count */ - rt_uint32_t nref; /**< reference count */ + rt_uint16_t nsym; /**< number of symbol in the module */ + struct rt_module_symtab *symtab; /**< module symbol table */ /* object in this module, module object is the last basic object type */ struct rt_object_information module_object[RT_Object_Class_Unknown]; diff --git a/include/rtthread.h b/include/rtthread.h index 0891ed9bcc..7704abf208 100644 --- a/include/rtthread.h +++ b/include/rtthread.h @@ -420,6 +420,7 @@ rt_module_t rt_module_load(const char *name, void *module_ptr); rt_err_t rt_module_unload(rt_module_t module); #ifdef RT_USING_DFS rt_module_t rt_module_open(const char *filename); +rt_module_t rt_module_exec_cmd(const char *path, char* cmd_line, int size); #endif void *rt_module_malloc(rt_size_t size); void *rt_module_realloc(void *ptr, rt_size_t size); diff --git a/src/module.c b/src/module.c index ac689dbade..ec5ed3f7d0 100644 --- a/src/module.c +++ b/src/module.c @@ -801,6 +801,10 @@ rt_module_t rt_module_load(const char *name, void *module_ptr) /* init module object container */ rt_module_init_object_container(module); + /* initialize an empty command */ + module->module_cmd_line = RT_NULL; + module->module_cmd_size = 0; + /* increase module reference count */ module->nref ++; @@ -816,18 +820,10 @@ rt_module_t rt_module_load(const char *name, void *module_ptr) module->page_cnt = 0; #endif - /* get the main thread stack size */ - module->stack_size = 2048; - module->thread_priority = RT_THREAD_PRIORITY_MAX - 2; - /* create module thread */ - module->module_thread = - rt_thread_create(name, - (void(*)(void *))module->module_entry, - RT_NULL, - module->stack_size, - module->thread_priority, - 10); + module->module_thread = rt_thread_create(name, + (void(*)(void *))module->module_entry, RT_NULL, + 2048, RT_THREAD_PRIORITY_MAX - 2, 10); RT_DEBUG_LOG(RT_DEBUG_MODULE, ("thread entry 0x%x\n", module->module_entry)); @@ -855,6 +851,168 @@ rt_module_t rt_module_load(const char *name, void *module_ptr) return module; } +#define RT_MODULE_ARG_MAX 8 +static int _rt_module_split_arg(char* cmd, rt_size_t length, char* argv[]) +{ + int argc = 0; + char *ptr = cmd; + + while ((ptr - cmd) < length) + { + /* strip bank and tab */ + while ((*ptr == ' ' || *ptr == '\t') && (ptr -cmd)< length) + *ptr++ = '\0'; + /* check whether it's the end of line */ + if ((ptr - cmd)>= length) break; + + /* handle string with quote */ + if (*ptr == '"') + { + argv[argc++] = ++ptr; + + /* skip this string */ + while (*ptr != '"' && (ptr-cmd) < length) + if (*ptr ++ == '\\') ptr ++; + if ((ptr - cmd) >= length) break; + + /* skip '"' */ + *ptr ++ = '\0'; + } + else + { + argv[argc++] = ptr; + while ((*ptr != ' ' && *ptr != '\t') && (ptr - cmd) < length) + ptr ++; + } + + if (argc >= RT_MODULE_ARG_MAX) break; + } + + return argc; +} +/* module main thread entry */ +static void module_main_entry(void* parameter) +{ + int argc; + char *argv[RT_MODULE_ARG_MAX]; + typedef int (*main_func_t)(int argc, char** argv); + + rt_module_t module = (rt_module_t) parameter; + if (module == RT_NULL || module->module_cmd_line == RT_NULL) return; + + rt_memset(argv, 0x00, sizeof(argv)); + argc = _rt_module_split_arg((char*)module->module_cmd_line, module->module_cmd_size, argv); + if (argc == 0) return ; + + /* do the main function */ + ((main_func_t)module->module_entry)(argc, argv); + return; +} + +/** + * This function will load a module with a main function from memory and create a + * main thread for it + * + * @param name the name of module, which shall be unique + * @param module_ptr the memory address of module image + * @argc the count of argument + * @argd the argument data, which should be a + * + * @return the module object + */ +rt_module_t rt_module_do_main(const char *name, void *module_ptr, char* cmd_line, int line_size) +{ + rt_module_t module; + + RT_DEBUG_NOT_IN_INTERRUPT; + + RT_DEBUG_LOG(RT_DEBUG_MODULE, ("rt_module_load: %s ,", name)); + + /* check ELF header */ + if (rt_memcmp(elf_module->e_ident, RTMMAG, SELFMAG) != 0 && + rt_memcmp(elf_module->e_ident, ELFMAG, SELFMAG) != 0) + { + rt_kprintf("Module: magic error\n"); + + return RT_NULL; + } + + /* check ELF class */ + if (elf_module->e_ident[EI_CLASS] != ELFCLASS32) + { + rt_kprintf("Module: ELF class error\n"); + return RT_NULL; + } + + if (elf_module->e_type == ET_REL) + { + module = _load_relocated_object(name, module_ptr); + } + else if (elf_module->e_type == ET_DYN) + { + module = _load_shared_object(name, module_ptr); + } + else + { + rt_kprintf("Module: unsupported excutable program\n"); + return RT_NULL; + } + + if (module == RT_NULL) + return RT_NULL; + + /* init module object container */ + rt_module_init_object_container(module); + + /* increase module reference count */ + module->nref ++; + + if (elf_module->e_entry != 0) + { +#ifdef RT_USING_SLAB + /* init module memory allocator */ + module->mem_list = RT_NULL; + + /* create page array */ + module->page_array = + (void *)rt_malloc(PAGE_COUNT_MAX * sizeof(struct rt_page_info)); + module->page_cnt = 0; +#endif + + /* set module argument */ + module->module_cmd_line = (rt_uint8_t*)rt_malloc(line_size + 1); + rt_memcpy(module->module_cmd_line, cmd_line, line_size); + module->module_cmd_line[line_size] = '\0'; + module->module_cmd_size = line_size; + + /* create module thread */ + module->module_thread = rt_thread_create(name, + module_main_entry, module, + 2048, RT_THREAD_PRIORITY_MAX - 2, 10); + + /* set module id */ + module->module_thread->module_id = (void *)module; + module->parent.flag = RT_MODULE_FLAG_WITHENTRY; + + /* startup main thread */ + rt_thread_startup(module->module_thread); + } + else + { + /* without entry point */ + module->parent.flag |= RT_MODULE_FLAG_WITHOUTENTRY; + } + +#ifdef RT_USING_HOOK + if (rt_module_load_hook != RT_NULL) + { + rt_module_load_hook(module); + } +#endif + + return module; +} + #ifdef RT_USING_DFS #include @@ -958,9 +1116,82 @@ rt_module_t rt_module_open(const char *path) return module; } +/** + * This function will do a excutable program with main function and parameters. + * + * @param path the full path of application module + * @cmd_line the command line of program + * @size the size of command line of program + * + * @return the module object + */ +rt_module_t rt_module_exec_cmd(const char *path, char* cmd_line, int size) +{ + struct stat s; + int fd, length; + char *name, *buffer, *offset_ptr; + struct rt_module *module = RT_NULL; + + name = buffer = RT_NULL; + + RT_DEBUG_NOT_IN_INTERRUPT; + + /* check parameters */ + RT_ASSERT(path != RT_NULL); + + /* get file size */ + if (stat(path, &s) !=0) + { + rt_kprintf("Module: access %s failed\n", path); + goto __exit; + } + + /* allocate buffer to save program */ + offset_ptr = buffer = (char *)rt_malloc(s.st_size); + if (buffer == RT_NULL) + { + rt_kprintf("Module: out of memory\n"); + goto __exit; + } + + fd = open(path, O_RDONLY, 0); + if (fd < 0) + { + rt_kprintf("Module: open %s failed\n", path); + goto __exit; + } + + do + { + length = read(fd, offset_ptr, 4096); + if (length > 0) + { + offset_ptr += length; + } + }while (length > 0); + /* close fd */ + close(fd); + + if ((rt_uint32_t)offset_ptr - (rt_uint32_t)buffer != s.st_size) + { + rt_kprintf("Module: read file failed\n"); + goto __exit; + } + + /* get module */ + name = _module_name(path); + /* execute module */ + module = rt_module_do_main(name, (void *)buffer, cmd_line, size); + +__exit: + rt_free(buffer); + rt_free(name); + + return module; +} + #if defined(RT_USING_FINSH) #include - FINSH_FUNCTION_EXPORT_ALIAS(rt_module_open, exec, exec module from a file); #endif @@ -1131,6 +1362,12 @@ rt_err_t rt_module_destroy(rt_module_t module) rt_timer_delete((rt_timer_t)object); } } + + /* delete command line */ + if (module->module_cmd_line != RT_NULL) + { + rt_free(module->module_cmd_line); + } } #ifdef RT_USING_SLAB From 2188d0600331ccd4478e8fcab527329c0b071165 Mon Sep 17 00:00:00 2001 From: bernard Date: Sat, 11 Jan 2014 16:34:15 +0800 Subject: [PATCH 07/59] [DFS] remove a compiling warning --- components/dfs/filesystems/nfs/dfs_nfs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/dfs/filesystems/nfs/dfs_nfs.c b/components/dfs/filesystems/nfs/dfs_nfs.c index 0f40fa4292..43d2845aa0 100644 --- a/components/dfs/filesystems/nfs/dfs_nfs.c +++ b/components/dfs/filesystems/nfs/dfs_nfs.c @@ -1092,8 +1092,6 @@ int nfs_getdents(struct dfs_fd *file, struct dirent *dirp, rt_uint32_t count) index = 0; while (1) { - char *fn; - d = dirp + index; name = nfs_readdir(nfs, dir); From 86cdc22043d4f765aa2ad289fac09aca518fe525 Mon Sep 17 00:00:00 2001 From: prife Date: Sat, 11 Jan 2014 16:37:13 +0800 Subject: [PATCH 08/59] kernel: rearrange the header file include order There are some CONFIG OPTIONS in rtdebug.h, which may influence the rtdef.h, so rtdebug.h should be head of the rtdef.h --- include/rtdebug.h | 4 +--- include/rtdef.h | 2 -- include/rtthread.h | 3 ++- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/include/rtdebug.h b/include/rtdebug.h index 6ef04f6bf9..2d93e88b94 100644 --- a/include/rtdebug.h +++ b/include/rtdebug.h @@ -21,8 +21,6 @@ #ifndef __RTDEBUG_H__ #define __RTDEBUG_H__ -#include - /* Using this macro to control all kernel debug features. */ #ifdef RT_DEBUG @@ -64,7 +62,7 @@ #endif #ifndef RT_DEBUG_INIT -#define RT_DEBUG_INIT 0 +#define RT_DEBUG_INIT 0 #endif /* Turn on this to enable context check */ diff --git a/include/rtdef.h b/include/rtdef.h index e21bc4eb41..f5b59fa7e8 100644 --- a/include/rtdef.h +++ b/include/rtdef.h @@ -34,8 +34,6 @@ #ifndef __RT_DEF_H__ #define __RT_DEF_H__ -#include - #ifdef __cplusplus extern "C" { #endif diff --git a/include/rtthread.h b/include/rtthread.h index 0891ed9bcc..f201f3d9d7 100644 --- a/include/rtthread.h +++ b/include/rtthread.h @@ -31,8 +31,9 @@ #ifndef __RT_THREAD_H__ #define __RT_THREAD_H__ -#include +#include #include +#include #include #include From d71b86c750d99ea2cb98b3e657f4f3baf104d3ea Mon Sep 17 00:00:00 2001 From: RTsien Date: Sat, 11 Jan 2014 22:03:51 +0800 Subject: [PATCH 09/59] friendly for uart count under 6 --- bsp/beaglebone/drivers/serial.c | 263 ++++++++++++++++++-------------- 1 file changed, 150 insertions(+), 113 deletions(-) diff --git a/bsp/beaglebone/drivers/serial.c b/bsp/beaglebone/drivers/serial.c index af93048ac9..d07621080b 100644 --- a/bsp/beaglebone/drivers/serial.c +++ b/bsp/beaglebone/drivers/serial.c @@ -39,7 +39,7 @@ static void am33xx_uart_isr(int irqno, void* param) iir = UART_IIR_REG(uart->base); - if ((iir & (0x02 << 1)) || (iir & (0x6 << 1))) + if ((iir & (0x02 << 1)) || (iir & (0x6 << 1))) { rt_hw_serial_isr(serial); } @@ -164,17 +164,65 @@ static const struct rt_uart_ops am33xx_uart_ops = }; /* UART device driver structure */ -struct serial_ringbuffer uart_int_rx[6]; -struct am33xx_uart uart[6] = +#ifdef RT_USING_UART0 +struct serial_ringbuffer uart0_int_rx; +struct am33xx_uart uart0 = { - {UART0_BASE,UART0_INT}, - {UART1_BASE,UART1_INT}, - {UART2_BASE,UART2_INT}, - {UART3_BASE,UART3_INT}, - {UART4_BASE,UART4_INT}, - {UART5_BASE,UART5_INT} + UART0_BASE, + UART0_INT, }; -struct rt_serial_device serial[6]; +struct rt_serial_device serial0; +#endif + +#ifdef RT_USING_UART1 +struct serial_ringbuffer uart1_int_rx; +struct am33xx_uart uart1 = +{ + UART1_BASE, + UART1_INT, +}; +struct rt_serial_device serial1; +#endif + +#ifdef RT_USING_UART2 +struct serial_ringbuffer uart2_int_rx; +struct am33xx_uart uart2 = +{ + UART2_BASE, + UART2_INT, +}; +struct rt_serial_device serial2; +#endif + +#ifdef RT_USING_UART3 +struct serial_ringbuffer uart3_int_rx; +struct am33xx_uart uart3 = +{ + UART3_BASE, + UART3_INT, +}; +struct rt_serial_device serial3; +#endif + +#ifdef RT_USING_UART4 +struct serial_ringbuffer uart4_int_rx; +struct am33xx_uart uart4 = +{ + UART4_BASE, + UART4_INT, +}; +struct rt_serial_device serial4; +#endif + +#ifdef RT_USING_UART5 +struct serial_ringbuffer uart5_int_rx; +struct am33xx_uart uart5 = +{ + UART5_BASE, + UART5_INT, +}; +struct rt_serial_device serial5; +#endif #define write_reg(base, value) *(int*)(base) = value #define read_reg(base) *(int*)(base) @@ -226,7 +274,6 @@ static void start_uart_clk(void) /* enable uart1 */ #ifdef RT_USING_UART1 CM_PER_UART1_CLKCTRL_REG(prcm_base) |= 0x2; - /* wait for uart1 clk */ while ((CM_PER_UART1_CLKCTRL_REG(prcm_base) & (0x3<<16)) != 0) ; @@ -234,7 +281,6 @@ static void start_uart_clk(void) #ifdef RT_USING_UART2 CM_PER_UART2_CLKCTRL_REG(prcm_base) |= 0x2; - /* wait for uart2 clk */ while ((CM_PER_UART2_CLKCTRL_REG(prcm_base) & (0x3<<16)) != 0) ; @@ -242,7 +288,6 @@ static void start_uart_clk(void) #ifdef RT_USING_UART3 CM_PER_UART3_CLKCTRL_REG(prcm_base) |= 0x2; - /* wait for uart3 clk */ while ((CM_PER_UART3_CLKCTRL_REG(prcm_base) & (0x3<<16)) != 0) ; @@ -250,7 +295,6 @@ static void start_uart_clk(void) #ifdef RT_USING_UART4 CM_PER_UART4_CLKCTRL_REG(prcm_base) |= 0x2; - /* wait for uart4 clk */ while ((CM_PER_UART4_CLKCTRL_REG(prcm_base) & (0x3<<16)) != 0) ; @@ -258,7 +302,6 @@ static void start_uart_clk(void) #ifdef RT_USING_UART5 CM_PER_UART5_CLKCTRL_REG(prcm_base) |= 0x2; - /* wait for uart5 clk */ while ((CM_PER_UART5_CLKCTRL_REG(prcm_base) & (0x3<<16)) != 0) ; @@ -299,156 +342,150 @@ static void config_pinmux(void) REG32(ctlm_base + 0x800 + 0x0C4) = 0x24; REG32(ctlm_base + 0x800 + 0x0C0) = 0x04; #endif - - } int rt_hw_serial_init(void) { - struct serial_configure config[6]; + struct serial_configure config; poweron_per_domain(); start_uart_clk(); config_pinmux(); #ifdef RT_USING_UART0 - config[0].baud_rate = BAUD_RATE_115200; - config[0].bit_order = BIT_ORDER_LSB; - config[0].data_bits = DATA_BITS_8; - config[0].parity = PARITY_NONE; - config[0].stop_bits = STOP_BITS_1; - config[0].invert = NRZ_NORMAL; - - serial[0].ops = &am33xx_uart_ops; - serial[0].int_rx = &uart_int_rx[0]; - serial[0].config = config[0]; + config.baud_rate = BAUD_RATE_115200; + config.bit_order = BIT_ORDER_LSB; + config.data_bits = DATA_BITS_8; + config.parity = PARITY_NONE; + config.stop_bits = STOP_BITS_1; + config.invert = NRZ_NORMAL; + serial0.ops = &am33xx_uart_ops; + serial0.int_rx = &uart0_int_rx; + serial0.config = config; /* enable RX interrupt */ - UART_IER_REG(uart[0].base) = 0x01; + UART_IER_REG(uart0.base) = 0x01; /* install ISR */ - rt_hw_interrupt_install(uart[0].irq, am33xx_uart_isr, &serial[0], "uart0"); - rt_hw_interrupt_control(uart[0].irq, 0, 0); - rt_hw_interrupt_mask(uart[0].irq); + rt_hw_interrupt_install(uart0.irq, am33xx_uart_isr, &serial0, "uart0"); + rt_hw_interrupt_control(uart0.irq, 0, 0); + rt_hw_interrupt_mask(uart0.irq); /* register UART0 device */ - rt_hw_serial_register(&serial[0], "uart0", + rt_hw_serial_register(&serial0, "uart0", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, - &uart[0]); + &uart0); #endif #ifdef RT_USING_UART1 - config[1].baud_rate = BAUD_RATE_115200; - config[1].bit_order = BIT_ORDER_LSB; - config[1].data_bits = DATA_BITS_8; - config[1].parity = PARITY_NONE; - config[1].stop_bits = STOP_BITS_1; - config[1].invert = NRZ_NORMAL; - - serial[1].ops = &am33xx_uart_ops; - serial[1].int_rx = &uart_int_rx[1]; - serial[1].config = config[1]; + config.baud_rate = BAUD_RATE_115200; + config.bit_order = BIT_ORDER_LSB; + config.data_bits = DATA_BITS_8; + config.parity = PARITY_NONE; + config.stop_bits = STOP_BITS_1; + config.invert = NRZ_NORMAL; + serial1.ops = &am33xx_uart_ops; + serial1.int_rx = &uart1_int_rx; + serial1.config = config; /* enable RX interrupt */ - UART_IER_REG(uart[1].base) = 0x01; + UART_IER_REG(uart1.base) = 0x01; /* install ISR */ - rt_hw_interrupt_install(uart[1].irq, am33xx_uart_isr, &serial[1], "uart1"); - rt_hw_interrupt_control(uart[1].irq, 0, 0); - rt_hw_interrupt_mask(uart[1].irq); + rt_hw_interrupt_install(uart1.irq, am33xx_uart_isr, &serial1, "uart1"); + rt_hw_interrupt_control(uart1.irq, 0, 0); + rt_hw_interrupt_mask(uart1.irq); /* register UART0 device */ - rt_hw_serial_register(&serial[1], "uart1", + rt_hw_serial_register(&serial1, "uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, - &uart[1]); + &uart1); #endif #ifdef RT_USING_UART2 - config[2].baud_rate = BAUD_RATE_115200; - config[2].bit_order = BIT_ORDER_LSB; - config[2].data_bits = DATA_BITS_8; - config[2].parity = PARITY_NONE; - config[2].stop_bits = STOP_BITS_1; - config[2].invert = NRZ_NORMAL; - - serial[2].ops = &am33xx_uart_ops; - serial[2].int_rx = &uart_int_rx[2]; - serial[2].config = config[2]; + config.baud_rate = BAUD_RATE_115200; + config.bit_order = BIT_ORDER_LSB; + config.data_bits = DATA_BITS_8; + config.parity = PARITY_NONE; + config.stop_bits = STOP_BITS_1; + config.invert = NRZ_NORMAL; + serial2.ops = &am33xx_uart_ops; + serial2.int_rx = &uart2_int_rx; + serial2.config = config; /* enable RX interrupt */ - UART_IER_REG(uart[2].base) = 0x01; + UART_IER_REG(uart2.base) = 0x01; /* install ISR */ - rt_hw_interrupt_install(uart[2].irq, am33xx_uart_isr, &serial[2], "uart2"); - rt_hw_interrupt_control(uart[2].irq, 0, 0); - rt_hw_interrupt_mask(uart[2].irq); + rt_hw_interrupt_install(uart2.irq, am33xx_uart_isr, &serial2, "uart2"); + rt_hw_interrupt_control(uart2.irq, 0, 0); + rt_hw_interrupt_mask(uart2.irq); /* register UART2 device */ - rt_hw_serial_register(&serial[2], "uart2", + rt_hw_serial_register(&serial2, "uart2", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, - &uart[2]); + &uart2); #endif #ifdef RT_USING_UART3 - config[3].baud_rate = BAUD_RATE_115200; - config[3].bit_order = BIT_ORDER_LSB; - config[3].data_bits = DATA_BITS_8; - config[3].parity = PARITY_NONE; - config[3].stop_bits = STOP_BITS_1; - config[3].invert = NRZ_NORMAL; - serial[3].ops = &am33xx_uart_ops; - serial[3].int_rx = &uart_int_rx[3]; - serial[3].config = config[3]; + config.baud_rate = BAUD_RATE_115200; + config.bit_order = BIT_ORDER_LSB; + config.data_bits = DATA_BITS_8; + config.parity = PARITY_NONE; + config.stop_bits = STOP_BITS_1; + config.invert = NRZ_NORMAL; + serial3.ops = &am33xx_uart_ops; + serial3.int_rx = &uart_3_int_rx; + serial3.config = config; /* enable RX interrupt */ - UART_IER_REG(uart[3].base) = 0x01; + UART_IER_REG(uart3.base) = 0x01; /* install ISR */ - rt_hw_interrupt_install(uart[3].irq, am33xx_uart_isr, &serial[3], "uart3"); - rt_hw_interrupt_control(uart[3].irq, 0, 0); - rt_hw_interrupt_mask(uart[3].irq); + rt_hw_interrupt_install(uart3.irq, am33xx_uart_isr, &serial3, "uart3"); + rt_hw_interrupt_control(uart3.irq, 0, 0); + rt_hw_interrupt_mask(uart3.irq); /* register UART3 device */ - rt_hw_serial_register(&serial[3], "uart3", + rt_hw_serial_register(&serial3, "uart3", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, - &uart[3]); + &uart3); #endif #ifdef RT_USING_UART4 - config[4].baud_rate = BAUD_RATE_115200; - config[4].bit_order = BIT_ORDER_LSB; - config[4].data_bits = DATA_BITS_8; - config[4].parity = PARITY_NONE; - config[4].stop_bits = STOP_BITS_1; - config[4].invert = NRZ_NORMAL; - - serial[4].ops = &am33xx_uart_ops; - serial[4].int_rx = &uart_int_rx[4]; - serial[4].config = config[4]; + config.baud_rate = BAUD_RATE_115200; + config.bit_order = BIT_ORDER_LSB; + config.data_bits = DATA_BITS_8; + config.parity = PARITY_NONE; + config.stop_bits = STOP_BITS_1; + config.invert = NRZ_NORMAL; + + serial4.ops = &am33xx_uart_ops; + serial4.int_rx = &uart4_int_rx; + serial4.config = config; /* enable RX interrupt */ - UART_IER_REG(uart[4].base) = 0x01; + UART_IER_REG(uart4.base) = 0x01; /* install ISR */ - rt_hw_interrupt_install(uart[4].irq, am33xx_uart_isr, &serial[4], "uart4"); - rt_hw_interrupt_control(uart[4].irq, 0, 0); - rt_hw_interrupt_mask(uart[4].irq); + rt_hw_interrupt_install(uart4.irq, am33xx_uart_isr, &serial4, "uart4"); + rt_hw_interrupt_control(uart4.irq, 0, 0); + rt_hw_interrupt_mask(uart4.irq); /* register UART4 device */ - rt_hw_serial_register(&serial[4], "uart4", + rt_hw_serial_register(&serial4, "uart4", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, - &uart[4]); + &uart4); #endif #ifdef RT_USING_UART5 - config[5].baud_rate = BAUD_RATE_115200; - config[5].bit_order = BIT_ORDER_LSB; - config[5].data_bits = DATA_BITS_8; - config[5].parity = PARITY_NONE; - config[5].stop_bits = STOP_BITS_1; - config[5].invert = NRZ_NORMAL; + config.baud_rate = BAUD_RATE_115200; + config.bit_order = BIT_ORDER_LSB; + config.data_bits = DATA_BITS_8; + config.parity = PARITY_NONE; + config.stop_bits = STOP_BITS_1; + config.invert = NRZ_NORMAL; - serial[5].ops = &am33xx_uart_ops; - serial[5].int_rx = &uart_int_rx[5]; - serial[5].config = config[5]; + serial5.ops = &am33xx_uart_ops; + serial5.int_rx = &uart5_int_rx; + serial5.config = config; /* enable RX interrupt */ - UART_IER_REG(uart[5].base) = 0x01; + UART_IER_REG(uart5.base) = 0x01; /* install ISR */ - rt_hw_interrupt_install(uart[5].irq, am33xx_uart_isr, &serial[5], "uart5"); - rt_hw_interrupt_control(uart[5].irq, 0, 0); - rt_hw_interrupt_mask(uart[5].irq); + rt_hw_interrupt_install(uart5.irq, am33xx_uart_isr, &serial5, "uart5"); + rt_hw_interrupt_control(uart5.irq, 0, 0); + rt_hw_interrupt_mask(uart5.irq); /* register UART4 device */ - rt_hw_serial_register(&serial[5], "uart5", + rt_hw_serial_register(&serial5, "uart5", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, - &uart[5]); + &uart5); #endif return 0; } INIT_BOARD_EXPORT(rt_hw_serial_init); - From 849130da2c7128d88a1b5516cf1b955461718601 Mon Sep 17 00:00:00 2001 From: roamboy <0yfj0@163.com> Date: Mon, 13 Jan 2014 15:52:23 +0800 Subject: [PATCH 10/59] Update msh.c fix msh_exec(char* cmd, rt_size_t length) bug --- components/finsh/msh.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/components/finsh/msh.c b/components/finsh/msh.c index 8da80fad5b..98c34c1de8 100644 --- a/components/finsh/msh.c +++ b/components/finsh/msh.c @@ -257,16 +257,29 @@ int msh_exec(char* cmd, rt_size_t length) int cmd0_size = 0; cmd_function_t cmd_func; + while(*cmd == ' ') + { + cmd++; + length--; + } while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length) cmd0_size ++; - + /* try to get built-in command */ + if (cmd0_size == 0) return -1; cmd_func = msh_get_cmd(cmd, cmd0_size); if (cmd_func == RT_NULL) { #ifdef RT_USING_MODULE msh_exec_module(cmd, length); #else + argv[0] = cmd; + while(*cmd != ' ') + { + if (*cmd == 0) break; + cmd++; + } + if (*cmd == ' ') *cmd = 0; rt_kprintf("%s: command not found.\n", argv[0]); #endif return -1; From 1df4c1b9629269a4e5374f44873026b122eeb0ab Mon Sep 17 00:00:00 2001 From: roamboy <0yfj0@163.com> Date: Mon, 13 Jan 2014 15:56:20 +0800 Subject: [PATCH 11/59] Update msh.c --- components/finsh/msh.c | 51 +++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/components/finsh/msh.c b/components/finsh/msh.c index 98c34c1de8..8d2a51e920 100644 --- a/components/finsh/msh.c +++ b/components/finsh/msh.c @@ -253,39 +253,38 @@ int msh_exec(char* cmd, rt_size_t length) { int argc; char *argv[RT_FINSH_ARG_MAX]; - - int cmd0_size = 0; + int cmd0_size = 0; cmd_function_t cmd_func; - while(*cmd == ' ') - { - cmd++; - length--; - } - while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length) - cmd0_size ++; + while(*cmd == ' ') + { + cmd++; + length--; + } + while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length) + cmd0_size ++; - /* try to get built-in command */ - if (cmd0_size == 0) return -1; - cmd_func = msh_get_cmd(cmd, cmd0_size); - if (cmd_func == RT_NULL) - { + /* try to get built-in command */ + if (cmd0_size == 0) return -1; + cmd_func = msh_get_cmd(cmd, cmd0_size); + if (cmd_func == RT_NULL) + { #ifdef RT_USING_MODULE - msh_exec_module(cmd, length); + msh_exec_module(cmd, length); #else - argv[0] = cmd; - while(*cmd != ' ') - { - if (*cmd == 0) break; - cmd++; - } - if (*cmd == ' ') *cmd = 0; - rt_kprintf("%s: command not found.\n", argv[0]); + argv[0] = cmd; + while(*cmd != ' ') + { + if (*cmd == 0) break; + cmd++; + } + if (*cmd == ' ') *cmd = 0; + rt_kprintf("%s: command not found.\n", argv[0]); #endif - return -1; - } + return -1; + } - /* split arguments */ + /* split arguments */ memset(argv, 0x00, sizeof(argv)); argc = msh_split(cmd, length, argv); if (argc == 0) return -1; From 1c8693c87eb4636df0edeb0dfeb36551df6f5e75 Mon Sep 17 00:00:00 2001 From: roamboy <0yfj0@163.com> Date: Mon, 13 Jan 2014 15:57:13 +0800 Subject: [PATCH 12/59] Update msh.c --- components/finsh/msh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/finsh/msh.c b/components/finsh/msh.c index 8d2a51e920..35ebb4b559 100644 --- a/components/finsh/msh.c +++ b/components/finsh/msh.c @@ -276,7 +276,7 @@ int msh_exec(char* cmd, rt_size_t length) while(*cmd != ' ') { if (*cmd == 0) break; - cmd++; + cmd++; } if (*cmd == ' ') *cmd = 0; rt_kprintf("%s: command not found.\n", argv[0]); From ae891e201124c7937dad301739f83cbb296ead9a Mon Sep 17 00:00:00 2001 From: bernard Date: Thu, 16 Jan 2014 22:22:23 +0800 Subject: [PATCH 13/59] [Finsh] fix strncmp issue in command search --- components/finsh/msh.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/components/finsh/msh.c b/components/finsh/msh.c index 35ebb4b559..794fcb83e8 100644 --- a/components/finsh/msh.c +++ b/components/finsh/msh.c @@ -166,7 +166,8 @@ static cmd_function_t msh_get_cmd(char *cmd, int size) { if (strncmp(index->name, "__cmd_", 6) != 0) continue; - if (strncmp(&index->name[6], cmd, size) == 0) + if (strncmp(&index->name[6], cmd, size) == 0 && + index->name[6 + size] == '\0') { cmd_func = (cmd_function_t)index->func; break; @@ -256,16 +257,14 @@ int msh_exec(char* cmd, rt_size_t length) int cmd0_size = 0; cmd_function_t cmd_func; - while(*cmd == ' ') - { - cmd++; - length--; - } + /* strim the beginning of command */ + while(*cmd == ' ' || *cmd == '\t'){cmd++; length--;} + /* find the size of first command */ while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length) cmd0_size ++; - + if (cmd0_size == 0) return -1; /* no command found */ + /* try to get built-in command */ - if (cmd0_size == 0) return -1; cmd_func = msh_get_cmd(cmd, cmd0_size); if (cmd_func == RT_NULL) { From 8fdbb7c92b1f398668a280923f02a0355a6f7dcc Mon Sep 17 00:00:00 2001 From: bernard Date: Fri, 17 Jan 2014 22:32:32 +0800 Subject: [PATCH 14/59] [Kernel] Fix the compiling issue for not including rtconfig.h file in rtdebug.h/rtdef.h --- include/rtdebug.h | 2 ++ include/rtdef.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/include/rtdebug.h b/include/rtdebug.h index 2d93e88b94..8fd07b5b76 100644 --- a/include/rtdebug.h +++ b/include/rtdebug.h @@ -21,6 +21,8 @@ #ifndef __RTDEBUG_H__ #define __RTDEBUG_H__ +#include + /* Using this macro to control all kernel debug features. */ #ifdef RT_DEBUG diff --git a/include/rtdef.h b/include/rtdef.h index 7cd35c7f8c..3c91ae7d8d 100644 --- a/include/rtdef.h +++ b/include/rtdef.h @@ -34,6 +34,8 @@ #ifndef __RT_DEF_H__ #define __RT_DEF_H__ +#include + #ifdef __cplusplus extern "C" { #endif From 9367bba6d17058073c31717a971cfce68fa65c42 Mon Sep 17 00:00:00 2001 From: aozima Date: Wed, 22 Jan 2014 17:26:52 +0800 Subject: [PATCH 15/59] update CMSIS version to 3.20 --- components/CMSIS/Include/arm_common_tables.h | 97 +- components/CMSIS/Include/arm_math.h | 1463 ++++++++---------- components/CMSIS/Include/core_cm0.h | 55 +- components/CMSIS/Include/core_cm0plus.h | 59 +- components/CMSIS/Include/core_cm3.h | 57 +- components/CMSIS/Include/core_cm4.h | 57 +- components/CMSIS/Include/core_cm4_simd.h | 54 +- components/CMSIS/Include/core_cmFunc.h | 72 +- components/CMSIS/Include/core_cmInstr.h | 134 +- components/CMSIS/Include/core_sc000.h | 55 +- components/CMSIS/Include/core_sc300.h | 57 +- 11 files changed, 1084 insertions(+), 1076 deletions(-) diff --git a/components/CMSIS/Include/arm_common_tables.h b/components/CMSIS/Include/arm_common_tables.h index 8c35ef2bd5..7a59b5923e 100644 --- a/components/CMSIS/Include/arm_common_tables.h +++ b/components/CMSIS/Include/arm_common_tables.h @@ -1,24 +1,41 @@ -/* ---------------------------------------------------------------------- -* Copyright (C) 2010 ARM Limited. All rights reserved. -* -* $Date: 11. November 2010 -* $Revision: V1.0.2 -* -* Project: CMSIS DSP Library -* Title: arm_common_tables.h -* -* Description: This file has extern declaration for common tables like Bitreverse, reciprocal etc which are used across different functions -* +/* ---------------------------------------------------------------------- +* Copyright (C) 2010-2013 ARM Limited. All rights reserved. +* +* $Date: 17. January 2013 +* $Revision: V1.4.1 +* +* Project: CMSIS DSP Library +* Title: arm_common_tables.h +* +* Description: This file has extern declaration for common tables like Bitreverse, reciprocal etc which are used across different functions +* * Target Processor: Cortex-M4/Cortex-M3 -* -* Version 1.0.2 2010/11/11 -* Documentation updated. -* -* Version 1.0.1 2010/10/05 -* Production release and review comments incorporated. -* -* Version 1.0.0 2010/09/20 -* Production release and review comments incorporated. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* - Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* - Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* - Neither the name of ARM LIMITED nor the names of its contributors +* may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------- */ #ifndef _ARM_COMMON_TABLES_H @@ -31,8 +48,46 @@ extern const q15_t armRecipTableQ15[64]; extern const q31_t armRecipTableQ31[64]; extern const q31_t realCoefAQ31[1024]; extern const q31_t realCoefBQ31[1024]; -extern const float32_t twiddleCoef[6144]; +extern const float32_t twiddleCoef_16[32]; +extern const float32_t twiddleCoef_32[64]; +extern const float32_t twiddleCoef_64[128]; +extern const float32_t twiddleCoef_128[256]; +extern const float32_t twiddleCoef_256[512]; +extern const float32_t twiddleCoef_512[1024]; +extern const float32_t twiddleCoef_1024[2048]; +extern const float32_t twiddleCoef_2048[4096]; +extern const float32_t twiddleCoef_4096[8192]; +#define twiddleCoef twiddleCoef_4096 extern const q31_t twiddleCoefQ31[6144]; extern const q15_t twiddleCoefQ15[6144]; +extern const float32_t twiddleCoef_rfft_32[32]; +extern const float32_t twiddleCoef_rfft_64[64]; +extern const float32_t twiddleCoef_rfft_128[128]; +extern const float32_t twiddleCoef_rfft_256[256]; +extern const float32_t twiddleCoef_rfft_512[512]; +extern const float32_t twiddleCoef_rfft_1024[1024]; +extern const float32_t twiddleCoef_rfft_2048[2048]; +extern const float32_t twiddleCoef_rfft_4096[4096]; + + +#define ARMBITREVINDEXTABLE__16_TABLE_LENGTH ((uint16_t)20 ) +#define ARMBITREVINDEXTABLE__32_TABLE_LENGTH ((uint16_t)48 ) +#define ARMBITREVINDEXTABLE__64_TABLE_LENGTH ((uint16_t)56 ) +#define ARMBITREVINDEXTABLE_128_TABLE_LENGTH ((uint16_t)208 ) +#define ARMBITREVINDEXTABLE_256_TABLE_LENGTH ((uint16_t)440 ) +#define ARMBITREVINDEXTABLE_512_TABLE_LENGTH ((uint16_t)448 ) +#define ARMBITREVINDEXTABLE1024_TABLE_LENGTH ((uint16_t)1800) +#define ARMBITREVINDEXTABLE2048_TABLE_LENGTH ((uint16_t)3808) +#define ARMBITREVINDEXTABLE4096_TABLE_LENGTH ((uint16_t)4032) + +extern const uint16_t armBitRevIndexTable16[ARMBITREVINDEXTABLE__16_TABLE_LENGTH]; +extern const uint16_t armBitRevIndexTable32[ARMBITREVINDEXTABLE__32_TABLE_LENGTH]; +extern const uint16_t armBitRevIndexTable64[ARMBITREVINDEXTABLE__64_TABLE_LENGTH]; +extern const uint16_t armBitRevIndexTable128[ARMBITREVINDEXTABLE_128_TABLE_LENGTH]; +extern const uint16_t armBitRevIndexTable256[ARMBITREVINDEXTABLE_256_TABLE_LENGTH]; +extern const uint16_t armBitRevIndexTable512[ARMBITREVINDEXTABLE_512_TABLE_LENGTH]; +extern const uint16_t armBitRevIndexTable1024[ARMBITREVINDEXTABLE1024_TABLE_LENGTH]; +extern const uint16_t armBitRevIndexTable2048[ARMBITREVINDEXTABLE2048_TABLE_LENGTH]; +extern const uint16_t armBitRevIndexTable4096[ARMBITREVINDEXTABLE4096_TABLE_LENGTH]; #endif /* ARM_COMMON_TABLES_H */ diff --git a/components/CMSIS/Include/arm_math.h b/components/CMSIS/Include/arm_math.h index 7266c3efb3..65304c127d 100644 --- a/components/CMSIS/Include/arm_math.h +++ b/components/CMSIS/Include/arm_math.h @@ -1,33 +1,41 @@ -/* ---------------------------------------------------------------------- - * Copyright (C) 2010-2011 ARM Limited. All rights reserved. - * - * $Date: 15. February 2012 - * $Revision: V1.1.0 - * - * Project: CMSIS DSP Library - * Title: arm_math.h - * - * Description: Public header file for CMSIS DSP Library - * - * Target Processor: Cortex-M4/Cortex-M3/Cortex-M0 - * - * Version 1.1.0 2012/02/15 - * Updated with more optimizations, bug fixes and minor API changes. - * - * Version 1.0.10 2011/7/15 - * Big Endian support added and Merged M0 and M3/M4 Source code. - * - * Version 1.0.3 2010/11/29 - * Re-organized the CMSIS folders and updated documentation. - * - * Version 1.0.2 2010/11/11 - * Documentation updated. - * - * Version 1.0.1 2010/10/05 - * Production release and review comments incorporated. - * - * Version 1.0.0 2010/09/20 - * Production release and review comments incorporated. +/* ---------------------------------------------------------------------- +* Copyright (C) 2010-2013 ARM Limited. All rights reserved. +* +* $Date: 17. January 2013 +* $Revision: V1.4.1 +* +* Project: CMSIS DSP Library +* Title: arm_math.h +* +* Description: Public header file for CMSIS DSP Library +* +* Target Processor: Cortex-M4/Cortex-M3/Cortex-M0 +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* - Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* - Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* - Neither the name of ARM LIMITED nor the names of its contributors +* may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. * -------------------------------------------------------------------- */ /** @@ -35,10 +43,10 @@ * * Introduction * - * This user manual describes the CMSIS DSP software library, + * This user manual describes the CMSIS DSP software library, * a suite of common signal processing functions for use on Cortex-M processor based devices. * - * The library is divided into a number of functions each covering a specific category: + * The library is divided into a number of functions each covering a specific category: * - Basic math functions * - Fast math functions * - Complex math functions @@ -51,41 +59,7 @@ * - Interpolation functions * * The library has separate functions for operating on 8-bit integers, 16-bit integers, - * 32-bit integer and 32-bit floating-point values. - * - * Pre-processor Macros - * - * Each library project have differant pre-processor macros. - * - * - UNALIGNED_SUPPORT_DISABLE: - * - * Define macro UNALIGNED_SUPPORT_DISABLE, If the silicon does not support unaligned memory access - * - * - ARM_MATH_BIG_ENDIAN: - * - * Define macro ARM_MATH_BIG_ENDIAN to build the library for big endian targets. By default library builds for little endian targets. - * - * - ARM_MATH_MATRIX_CHECK: - * - * Define macro ARM_MATH_MATRIX_CHECK for checking on the input and output sizes of matrices - * - * - ARM_MATH_ROUNDING: - * - * Define macro ARM_MATH_ROUNDING for rounding on support functions - * - * - ARM_MATH_CMx: - * - * Define macro ARM_MATH_CM4 for building the library on Cortex-M4 target, ARM_MATH_CM3 for building library on Cortex-M3 target - * and ARM_MATH_CM0 for building library on cortex-M0 target. - * - * - __FPU_PRESENT: - * - * Initialize macro __FPU_PRESENT = 1 when building on FPU supported Targets. Enable this macro for M4bf and M4lf libraries - * - * Toolchain Support - * - * The library has been developed and tested with MDK-ARM version 4.23. - * The library is being tested in GCC and IAR toolchains and updates on this activity will be made available shortly. + * 32-bit integer and 32-bit floating-point values. * * Using the Library * @@ -100,33 +74,67 @@ * - arm_cortexM0b_math.lib (Big endian on Cortex-M3) * * The library functions are declared in the public file arm_math.h which is placed in the Include folder. - * Simply include this file and link the appropriate library in the application and begin calling the library functions. The Library supports single - * public header file arm_math.h for Cortex-M4/M3/M0 with little endian and big endian. Same header file will be used for floating point unit(FPU) variants. - * Define the appropriate pre processor MACRO ARM_MATH_CM4 or ARM_MATH_CM3 or - * ARM_MATH_CM0 depending on the target processor in the application. + * Simply include this file and link the appropriate library in the application and begin calling the library functions. The Library supports single + * public header file arm_math.h for Cortex-M4/M3/M0 with little endian and big endian. Same header file will be used for floating point unit(FPU) variants. + * Define the appropriate pre processor MACRO ARM_MATH_CM4 or ARM_MATH_CM3 or + * ARM_MATH_CM0 or ARM_MATH_CM0PLUS depending on the target processor in the application. * * Examples * * The library ships with a number of examples which demonstrate how to use the library functions. * + * Toolchain Support + * + * The library has been developed and tested with MDK-ARM version 4.60. + * The library is being tested in GCC and IAR toolchains and updates on this activity will be made available shortly. + * * Building the Library * * The library installer contains project files to re build libraries on MDK Tool chain in the CMSIS\\DSP_Lib\\Source\\ARM folder. * - arm_cortexM0b_math.uvproj * - arm_cortexM0l_math.uvproj * - arm_cortexM3b_math.uvproj - * - arm_cortexM3l_math.uvproj + * - arm_cortexM3l_math.uvproj * - arm_cortexM4b_math.uvproj * - arm_cortexM4l_math.uvproj * - arm_cortexM4bf_math.uvproj * - arm_cortexM4lf_math.uvproj * * - * The project can be built by opening the appropriate project in MDK-ARM 4.23 chain and defining the optional pre processor MACROs detailed above. + * The project can be built by opening the appropriate project in MDK-ARM 4.60 chain and defining the optional pre processor MACROs detailed above. + * + * Pre-processor Macros + * + * Each library project have differant pre-processor macros. + * + * - UNALIGNED_SUPPORT_DISABLE: + * + * Define macro UNALIGNED_SUPPORT_DISABLE, If the silicon does not support unaligned memory access + * + * - ARM_MATH_BIG_ENDIAN: + * + * Define macro ARM_MATH_BIG_ENDIAN to build the library for big endian targets. By default library builds for little endian targets. + * + * - ARM_MATH_MATRIX_CHECK: + * + * Define macro ARM_MATH_MATRIX_CHECK for checking on the input and output sizes of matrices + * + * - ARM_MATH_ROUNDING: + * + * Define macro ARM_MATH_ROUNDING for rounding on support functions + * + * - ARM_MATH_CMx: + * + * Define macro ARM_MATH_CM4 for building the library on Cortex-M4 target, ARM_MATH_CM3 for building library on Cortex-M3 target + * and ARM_MATH_CM0 for building library on cortex-M0 target, ARM_MATH_CM0PLUS for building library on cortex-M0+ target. + * + * - __FPU_PRESENT: + * + * Initialize macro __FPU_PRESENT = 1 when building on FPU supported Targets. Enable this macro for M4bf and M4lf libraries * * Copyright Notice * - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2013 ARM Limited. All rights reserved. */ @@ -264,6 +272,10 @@ #include "core_cm3.h" #elif defined (ARM_MATH_CM0) #include "core_cm0.h" +#define ARM_MATH_CM0_FAMILY +#elif defined (ARM_MATH_CM0PLUS) +#include "core_cm0plus.h" +#define ARM_MATH_CM0_FAMILY #else #include "ARMCM4.h" #warning "Define either ARM_MATH_CM4 OR ARM_MATH_CM3...By Default building on ARM_MATH_CM4....." @@ -365,17 +377,27 @@ extern "C" /** * @brief definition to read/write two 16 bit values. */ -#if defined (__GNUC__) - #define __SIMD32(addr) (*( int32_t **) & (addr)) - #define _SIMD32_OFFSET(addr) (*( int32_t * ) (addr)) +#if defined __CC_ARM +#define __SIMD32_TYPE int32_t __packed +#define CMSIS_UNUSED __attribute__((unused)) +#elif defined __ICCARM__ +#define CMSIS_UNUSED +#define __SIMD32_TYPE int32_t __packed +#elif defined __GNUC__ +#define __SIMD32_TYPE int32_t +#define CMSIS_UNUSED __attribute__((unused)) #else - #define __SIMD32(addr) (*(__packed int32_t **) & (addr)) - #define _SIMD32_OFFSET(addr) (*(__packed int32_t * ) (addr)) -#endif +#error Unknown compiler +#endif - #define __SIMD64(addr) (*(int64_t **) & (addr)) +#define __SIMD32(addr) (*(__SIMD32_TYPE **) & (addr)) +#define __SIMD32_CONST(addr) ((__SIMD32_TYPE *)(addr)) -#if defined (ARM_MATH_CM3) || defined (ARM_MATH_CM0) +#define _SIMD32_OFFSET(addr) (*(__SIMD32_TYPE *) (addr)) + +#define __SIMD64(addr) (*(int64_t **) & (addr)) + +#if defined (ARM_MATH_CM3) || defined (ARM_MATH_CM0_FAMILY) /** * @brief definition to pack two 16 bit values. */ @@ -409,7 +431,7 @@ extern "C" /** * @brief Clips Q63 to Q31 values. */ - __STATIC_INLINE q31_t clip_q63_to_q31( + static __INLINE q31_t clip_q63_to_q31( q63_t x) { return ((q31_t) (x >> 32) != ((q31_t) x >> 31)) ? @@ -419,7 +441,7 @@ extern "C" /** * @brief Clips Q63 to Q15 values. */ - __STATIC_INLINE q15_t clip_q63_to_q15( + static __INLINE q15_t clip_q63_to_q15( q63_t x) { return ((q31_t) (x >> 32) != ((q31_t) x >> 31)) ? @@ -429,7 +451,7 @@ extern "C" /** * @brief Clips Q31 to Q7 values. */ - __STATIC_INLINE q7_t clip_q31_to_q7( + static __INLINE q7_t clip_q31_to_q7( q31_t x) { return ((q31_t) (x >> 24) != ((q31_t) x >> 23)) ? @@ -439,7 +461,7 @@ extern "C" /** * @brief Clips Q31 to Q15 values. */ - __STATIC_INLINE q15_t clip_q31_to_q15( + static __INLINE q15_t clip_q31_to_q15( q31_t x) { return ((q31_t) (x >> 16) != ((q31_t) x >> 15)) ? @@ -450,7 +472,7 @@ extern "C" * @brief Multiplies 32 X 64 and returns 32 bit result in 2.30 format. */ - __STATIC_INLINE q63_t mult32x64( + static __INLINE q63_t mult32x64( q63_t x, q31_t y) { @@ -459,20 +481,18 @@ extern "C" } -#if defined (ARM_MATH_CM0) && defined ( __CC_ARM ) +#if defined (ARM_MATH_CM0_FAMILY) && defined ( __CC_ARM ) #define __CLZ __clz #endif -#if defined (ARM_MATH_CM0) && defined ( __TASKING__ ) -/* No need to redefine __CLZ */ -#endif +#if defined (ARM_MATH_CM0_FAMILY) && ((defined (__ICCARM__)) ||(defined (__GNUC__)) || defined (__TASKING__) ) -#if defined (ARM_MATH_CM0) && ((defined (__ICCARM__)) ||(defined (__GNUC__)) ) - - __STATIC_INLINE uint32_t __CLZ(q31_t data); + static __INLINE uint32_t __CLZ( + q31_t data); - __STATIC_INLINE uint32_t __CLZ(q31_t data) + static __INLINE uint32_t __CLZ( + q31_t data) { uint32_t count = 0; uint32_t mask = 0x80000000; @@ -490,10 +510,10 @@ extern "C" #endif /** - * @brief Function to Calculates 1/in(reciprocal) value of Q31 Data type. + * @brief Function to Calculates 1/in (reciprocal) value of Q31 Data type. */ - __STATIC_INLINE uint32_t arm_recip_q31( + static __INLINE uint32_t arm_recip_q31( q31_t in, q31_t * dst, q31_t * pRecipTable) @@ -542,9 +562,9 @@ extern "C" } /** - * @brief Function to Calculates 1/in(reciprocal) value of Q15 Data type. + * @brief Function to Calculates 1/in (reciprocal) value of Q15 Data type. */ - __STATIC_INLINE uint32_t arm_recip_q15( + static __INLINE uint32_t arm_recip_q15( q15_t in, q15_t * dst, q15_t * pRecipTable) @@ -595,9 +615,9 @@ extern "C" /* * @brief C custom defined intrinisic function for only M0 processors */ -#if defined(ARM_MATH_CM0) +#if defined(ARM_MATH_CM0_FAMILY) - __STATIC_INLINE q31_t __SSAT( + static __INLINE q31_t __SSAT( q31_t x, uint32_t y) { @@ -633,19 +653,19 @@ extern "C" } -#endif /* end of ARM_MATH_CM0 */ +#endif /* end of ARM_MATH_CM0_FAMILY */ /* * @brief C custom defined intrinsic function for M3 and M0 processors */ -#if defined (ARM_MATH_CM3) || defined (ARM_MATH_CM0) +#if defined (ARM_MATH_CM3) || defined (ARM_MATH_CM0_FAMILY) /* * @brief C custom defined QADD8 for M3 and M0 processors */ - __STATIC_INLINE q31_t __QADD8( + static __INLINE q31_t __QADD8( q31_t x, q31_t y) { @@ -672,7 +692,7 @@ extern "C" /* * @brief C custom defined QSUB8 for M3 and M0 processors */ - __STATIC_INLINE q31_t __QSUB8( + static __INLINE q31_t __QSUB8( q31_t x, q31_t y) { @@ -702,7 +722,7 @@ extern "C" /* * @brief C custom defined QADD16 for M3 and M0 processors */ - __STATIC_INLINE q31_t __QADD16( + static __INLINE q31_t __QADD16( q31_t x, q31_t y) { @@ -725,7 +745,7 @@ extern "C" /* * @brief C custom defined SHADD16 for M3 and M0 processors */ - __STATIC_INLINE q31_t __SHADD16( + static __INLINE q31_t __SHADD16( q31_t x, q31_t y) { @@ -748,7 +768,7 @@ extern "C" /* * @brief C custom defined QSUB16 for M3 and M0 processors */ - __STATIC_INLINE q31_t __QSUB16( + static __INLINE q31_t __QSUB16( q31_t x, q31_t y) { @@ -770,7 +790,7 @@ extern "C" /* * @brief C custom defined SHSUB16 for M3 and M0 processors */ - __STATIC_INLINE q31_t __SHSUB16( + static __INLINE q31_t __SHSUB16( q31_t x, q31_t y) { @@ -792,7 +812,7 @@ extern "C" /* * @brief C custom defined QASX for M3 and M0 processors */ - __STATIC_INLINE q31_t __QASX( + static __INLINE q31_t __QASX( q31_t x, q31_t y) { @@ -810,7 +830,7 @@ extern "C" /* * @brief C custom defined SHASX for M3 and M0 processors */ - __STATIC_INLINE q31_t __SHASX( + static __INLINE q31_t __SHASX( q31_t x, q31_t y) { @@ -833,7 +853,7 @@ extern "C" /* * @brief C custom defined QSAX for M3 and M0 processors */ - __STATIC_INLINE q31_t __QSAX( + static __INLINE q31_t __QSAX( q31_t x, q31_t y) { @@ -851,7 +871,7 @@ extern "C" /* * @brief C custom defined SHSAX for M3 and M0 processors */ - __STATIC_INLINE q31_t __SHSAX( + static __INLINE q31_t __SHSAX( q31_t x, q31_t y) { @@ -873,7 +893,7 @@ extern "C" /* * @brief C custom defined SMUSDX for M3 and M0 processors */ - __STATIC_INLINE q31_t __SMUSDX( + static __INLINE q31_t __SMUSDX( q31_t x, q31_t y) { @@ -885,7 +905,7 @@ extern "C" /* * @brief C custom defined SMUADX for M3 and M0 processors */ - __STATIC_INLINE q31_t __SMUADX( + static __INLINE q31_t __SMUADX( q31_t x, q31_t y) { @@ -897,7 +917,7 @@ extern "C" /* * @brief C custom defined QADD for M3 and M0 processors */ - __STATIC_INLINE q31_t __QADD( + static __INLINE q31_t __QADD( q31_t x, q31_t y) { @@ -907,7 +927,7 @@ extern "C" /* * @brief C custom defined QSUB for M3 and M0 processors */ - __STATIC_INLINE q31_t __QSUB( + static __INLINE q31_t __QSUB( q31_t x, q31_t y) { @@ -917,7 +937,7 @@ extern "C" /* * @brief C custom defined SMLAD for M3 and M0 processors */ - __STATIC_INLINE q31_t __SMLAD( + static __INLINE q31_t __SMLAD( q31_t x, q31_t y, q31_t sum) @@ -930,7 +950,7 @@ extern "C" /* * @brief C custom defined SMLADX for M3 and M0 processors */ - __STATIC_INLINE q31_t __SMLADX( + static __INLINE q31_t __SMLADX( q31_t x, q31_t y, q31_t sum) @@ -943,7 +963,7 @@ extern "C" /* * @brief C custom defined SMLSDX for M3 and M0 processors */ - __STATIC_INLINE q31_t __SMLSDX( + static __INLINE q31_t __SMLSDX( q31_t x, q31_t y, q31_t sum) @@ -956,7 +976,7 @@ extern "C" /* * @brief C custom defined SMLALD for M3 and M0 processors */ - __STATIC_INLINE q63_t __SMLALD( + static __INLINE q63_t __SMLALD( q31_t x, q31_t y, q63_t sum) @@ -969,7 +989,7 @@ extern "C" /* * @brief C custom defined SMLALDX for M3 and M0 processors */ - __STATIC_INLINE q63_t __SMLALDX( + static __INLINE q63_t __SMLALDX( q31_t x, q31_t y, q63_t sum) @@ -982,7 +1002,7 @@ extern "C" /* * @brief C custom defined SMUAD for M3 and M0 processors */ - __STATIC_INLINE q31_t __SMUAD( + static __INLINE q31_t __SMUAD( q31_t x, q31_t y) { @@ -994,7 +1014,7 @@ extern "C" /* * @brief C custom defined SMUSD for M3 and M0 processors */ - __STATIC_INLINE q31_t __SMUSD( + static __INLINE q31_t __SMUSD( q31_t x, q31_t y) { @@ -1007,7 +1027,7 @@ extern "C" /* * @brief C custom defined SXTB16 for M3 and M0 processors */ - __STATIC_INLINE q31_t __SXTB16( + static __INLINE q31_t __SXTB16( q31_t x) { @@ -1016,7 +1036,7 @@ extern "C" } -#endif /* defined (ARM_MATH_CM3) || defined (ARM_MATH_CM0) */ +#endif /* defined (ARM_MATH_CM3) || defined (ARM_MATH_CM0_FAMILY) */ /** @@ -1516,6 +1536,7 @@ extern "C" * @param[in] *pSrcA points to the first input matrix structure * @param[in] *pSrcB points to the second input matrix structure * @param[out] *pDst points to output matrix structure + * @param[in] *pState points to the array for storing intermediate results * @return The function returns either * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. */ @@ -1531,7 +1552,7 @@ extern "C" * @param[in] *pSrcA points to the first input matrix structure * @param[in] *pSrcB points to the second input matrix structure * @param[out] *pDst points to output matrix structure - * @param[in] *pState points to the array for storing intermediate results + * @param[in] *pState points to the array for storing intermediate results * @return The function returns either * ARM_MATH_SIZE_MISMATCH or ARM_MATH_SUCCESS based on the outcome of size checking. */ @@ -1713,7 +1734,7 @@ extern "C" typedef struct { q15_t A0; /**< The derived gain, A0 = Kp + Ki + Kd . */ -#ifdef ARM_MATH_CM0 +#ifdef ARM_MATH_CM0_FAMILY q15_t A1; q15_t A2; #else @@ -1931,52 +1952,8 @@ extern "C" uint32_t blockSize); - /** - * @brief Instance structure for the Q15 CFFT/CIFFT function. - */ - - typedef struct - { - uint16_t fftLen; /**< length of the FFT. */ - uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ - uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ - q15_t *pTwiddle; /**< points to the twiddle factor table. */ - uint16_t *pBitRevTable; /**< points to the bit reversal table. */ - uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ - uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ - } arm_cfft_radix4_instance_q15; - - /** - * @brief Instance structure for the Q31 CFFT/CIFFT function. - */ - - typedef struct - { - uint16_t fftLen; /**< length of the FFT. */ - uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ - uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ - q31_t *pTwiddle; /**< points to the twiddle factor table. */ - uint16_t *pBitRevTable; /**< points to the bit reversal table. */ - uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ - uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ - } arm_cfft_radix4_instance_q31; - /** - * @brief Instance structure for the floating-point CFFT/CIFFT function. - */ - - typedef struct - { - uint16_t fftLen; /**< length of the FFT. */ - uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ - uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ - float32_t *pTwiddle; /**< points to the twiddle factor table. */ - uint16_t *pBitRevTable; /**< points to the bit reversal table. */ - uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ - uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ - float32_t onebyfftLen; /**< value of 1/fftLen. */ - } arm_cfft_radix4_instance_f32; /** @@ -1994,6 +1971,43 @@ extern "C" uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ } arm_cfft_radix2_instance_q15; + arm_status arm_cfft_radix2_init_q15( + arm_cfft_radix2_instance_q15 * S, + uint16_t fftLen, + uint8_t ifftFlag, + uint8_t bitReverseFlag); + + void arm_cfft_radix2_q15( + const arm_cfft_radix2_instance_q15 * S, + q15_t * pSrc); + + + + /** + * @brief Instance structure for the Q15 CFFT/CIFFT function. + */ + + typedef struct + { + uint16_t fftLen; /**< length of the FFT. */ + uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ + uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ + q15_t *pTwiddle; /**< points to the twiddle factor table. */ + uint16_t *pBitRevTable; /**< points to the bit reversal table. */ + uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ + uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ + } arm_cfft_radix4_instance_q15; + + arm_status arm_cfft_radix4_init_q15( + arm_cfft_radix4_instance_q15 * S, + uint16_t fftLen, + uint8_t ifftFlag, + uint8_t bitReverseFlag); + + void arm_cfft_radix4_q15( + const arm_cfft_radix4_instance_q15 * S, + q15_t * pSrc); + /** * @brief Instance structure for the Radix-2 Q31 CFFT/CIFFT function. */ @@ -2009,6 +2023,42 @@ extern "C" uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ } arm_cfft_radix2_instance_q31; + arm_status arm_cfft_radix2_init_q31( + arm_cfft_radix2_instance_q31 * S, + uint16_t fftLen, + uint8_t ifftFlag, + uint8_t bitReverseFlag); + + void arm_cfft_radix2_q31( + const arm_cfft_radix2_instance_q31 * S, + q31_t * pSrc); + + /** + * @brief Instance structure for the Q31 CFFT/CIFFT function. + */ + + typedef struct + { + uint16_t fftLen; /**< length of the FFT. */ + uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ + uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ + q31_t *pTwiddle; /**< points to the twiddle factor table. */ + uint16_t *pBitRevTable; /**< points to the bit reversal table. */ + uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ + uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ + } arm_cfft_radix4_instance_q31; + + + void arm_cfft_radix4_q31( + const arm_cfft_radix4_instance_q31 * S, + q31_t * pSrc); + + arm_status arm_cfft_radix4_init_q31( + arm_cfft_radix4_instance_q31 * S, + uint16_t fftLen, + uint8_t ifftFlag, + uint8_t bitReverseFlag); + /** * @brief Instance structure for the floating-point CFFT/CIFFT function. */ @@ -2025,401 +2075,63 @@ extern "C" float32_t onebyfftLen; /**< value of 1/fftLen. */ } arm_cfft_radix2_instance_f32; - - /** - * @brief Processing function for the Q15 CFFT/CIFFT. - * @param[in] *S points to an instance of the Q15 CFFT/CIFFT structure. - * @param[in, out] *pSrc points to the complex data buffer. Processing occurs in-place. - * @return none. - */ - - void arm_cfft_radix4_q15( - const arm_cfft_radix4_instance_q15 * S, - q15_t * pSrc); - - /** - * @brief Processing function for the Q15 CFFT/CIFFT. - * @param[in] *S points to an instance of the Q15 CFFT/CIFFT structure. - * @param[in, out] *pSrc points to the complex data buffer. Processing occurs in-place. - * @return none. - */ - - void arm_cfft_radix2_q15( - const arm_cfft_radix2_instance_q15 * S, - q15_t * pSrc); - - /** - * @brief Initialization function for the Q15 CFFT/CIFFT. - * @param[in,out] *S points to an instance of the Q15 CFFT/CIFFT structure. - * @param[in] fftLen length of the FFT. - * @param[in] ifftFlag flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. - * @param[in] bitReverseFlag flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. - * @return arm_status function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_ARGUMENT_ERROR if fftLen is not a supported value. - */ - - arm_status arm_cfft_radix4_init_q15( - arm_cfft_radix4_instance_q15 * S, - uint16_t fftLen, - uint8_t ifftFlag, - uint8_t bitReverseFlag); - - /** - * @brief Initialization function for the Q15 CFFT/CIFFT. - * @param[in,out] *S points to an instance of the Q15 CFFT/CIFFT structure. - * @param[in] fftLen length of the FFT. - * @param[in] ifftFlag flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. - * @param[in] bitReverseFlag flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. - * @return arm_status function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_ARGUMENT_ERROR if fftLen is not a supported value. - */ - - arm_status arm_cfft_radix2_init_q15( - arm_cfft_radix2_instance_q15 * S, - uint16_t fftLen, - uint8_t ifftFlag, - uint8_t bitReverseFlag); - - /** - * @brief Processing function for the Q31 CFFT/CIFFT. - * @param[in] *S points to an instance of the Q31 CFFT/CIFFT structure. - * @param[in, out] *pSrc points to the complex data buffer. Processing occurs in-place. - * @return none. - */ - - void arm_cfft_radix4_q31( - const arm_cfft_radix4_instance_q31 * S, - q31_t * pSrc); - - /** - * @brief Initialization function for the Q31 CFFT/CIFFT. - * @param[in,out] *S points to an instance of the Q31 CFFT/CIFFT structure. - * @param[in] fftLen length of the FFT. - * @param[in] ifftFlag flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. - * @param[in] bitReverseFlag flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. - * @return arm_status function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_ARGUMENT_ERROR if fftLen is not a supported value. - */ - - arm_status arm_cfft_radix4_init_q31( - arm_cfft_radix4_instance_q31 * S, - uint16_t fftLen, - uint8_t ifftFlag, - uint8_t bitReverseFlag); - - /** - * @brief Processing function for the Radix-2 Q31 CFFT/CIFFT. - * @param[in] *S points to an instance of the Radix-2 Q31 CFFT/CIFFT structure. - * @param[in, out] *pSrc points to the complex data buffer. Processing occurs in-place. - * @return none. - */ - - void arm_cfft_radix2_q31( - const arm_cfft_radix2_instance_q31 * S, - q31_t * pSrc); - - /** - * @brief Initialization function for the Radix-2 Q31 CFFT/CIFFT. - * @param[in,out] *S points to an instance of the Radix-2 Q31 CFFT/CIFFT structure. - * @param[in] fftLen length of the FFT. - * @param[in] ifftFlag flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. - * @param[in] bitReverseFlag flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. - * @return arm_status function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_ARGUMENT_ERROR if fftLen is not a supported value. - */ - - arm_status arm_cfft_radix2_init_q31( - arm_cfft_radix2_instance_q31 * S, - uint16_t fftLen, - uint8_t ifftFlag, - uint8_t bitReverseFlag); - - - - /** - * @brief Processing function for the floating-point CFFT/CIFFT. - * @param[in] *S points to an instance of the floating-point CFFT/CIFFT structure. - * @param[in, out] *pSrc points to the complex data buffer. Processing occurs in-place. - * @return none. - */ - - void arm_cfft_radix2_f32( - const arm_cfft_radix2_instance_f32 * S, - float32_t * pSrc); - - /** - * @brief Initialization function for the floating-point CFFT/CIFFT. - * @param[in,out] *S points to an instance of the floating-point CFFT/CIFFT structure. - * @param[in] fftLen length of the FFT. - * @param[in] ifftFlag flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. - * @param[in] bitReverseFlag flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. - * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_ARGUMENT_ERROR if fftLen is not a supported value. - */ - +/* Deprecated */ arm_status arm_cfft_radix2_init_f32( arm_cfft_radix2_instance_f32 * S, uint16_t fftLen, uint8_t ifftFlag, uint8_t bitReverseFlag); - /** - * @brief Processing function for the floating-point CFFT/CIFFT. - * @param[in] *S points to an instance of the floating-point CFFT/CIFFT structure. - * @param[in, out] *pSrc points to the complex data buffer. Processing occurs in-place. - * @return none. - */ - - void arm_cfft_radix4_f32( - const arm_cfft_radix4_instance_f32 * S, +/* Deprecated */ + void arm_cfft_radix2_f32( + const arm_cfft_radix2_instance_f32 * S, float32_t * pSrc); /** - * @brief Initialization function for the floating-point CFFT/CIFFT. - * @param[in,out] *S points to an instance of the floating-point CFFT/CIFFT structure. - * @param[in] fftLen length of the FFT. - * @param[in] ifftFlag flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. - * @param[in] bitReverseFlag flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. - * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_ARGUMENT_ERROR if fftLen is not a supported value. + * @brief Instance structure for the floating-point CFFT/CIFFT function. */ + typedef struct + { + uint16_t fftLen; /**< length of the FFT. */ + uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ + uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ + float32_t *pTwiddle; /**< points to the Twiddle factor table. */ + uint16_t *pBitRevTable; /**< points to the bit reversal table. */ + uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ + uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ + float32_t onebyfftLen; /**< value of 1/fftLen. */ + } arm_cfft_radix4_instance_f32; + +/* Deprecated */ arm_status arm_cfft_radix4_init_f32( arm_cfft_radix4_instance_f32 * S, uint16_t fftLen, uint8_t ifftFlag, uint8_t bitReverseFlag); - - - /*---------------------------------------------------------------------- - * Internal functions prototypes FFT function - ----------------------------------------------------------------------*/ +/* Deprecated */ + void arm_cfft_radix4_f32( + const arm_cfft_radix4_instance_f32 * S, + float32_t * pSrc); /** - * @brief Core function for the floating-point CFFT butterfly process. - * @param[in, out] *pSrc points to the in-place buffer of floating-point data type. - * @param[in] fftLen length of the FFT. - * @param[in] *pCoef points to the twiddle coefficient buffer. - * @param[in] twidCoefModifier twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. - * @return none. + * @brief Instance structure for the floating-point CFFT/CIFFT function. */ - void arm_radix4_butterfly_f32( - float32_t * pSrc, - uint16_t fftLen, - float32_t * pCoef, - uint16_t twidCoefModifier); - - /** - * @brief Core function for the floating-point CIFFT butterfly process. - * @param[in, out] *pSrc points to the in-place buffer of floating-point data type. - * @param[in] fftLen length of the FFT. - * @param[in] *pCoef points to twiddle coefficient buffer. - * @param[in] twidCoefModifier twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. - * @param[in] onebyfftLen value of 1/fftLen. - * @return none. - */ - - void arm_radix4_butterfly_inverse_f32( - float32_t * pSrc, - uint16_t fftLen, - float32_t * pCoef, - uint16_t twidCoefModifier, - float32_t onebyfftLen); - - /** - * @brief In-place bit reversal function. - * @param[in, out] *pSrc points to the in-place buffer of floating-point data type. - * @param[in] fftSize length of the FFT. - * @param[in] bitRevFactor bit reversal modifier that supports different size FFTs with the same bit reversal table. - * @param[in] *pBitRevTab points to the bit reversal table. - * @return none. - */ - - void arm_bitreversal_f32( - float32_t * pSrc, - uint16_t fftSize, - uint16_t bitRevFactor, - uint16_t * pBitRevTab); - - /** - * @brief Core function for the Q31 CFFT butterfly process. - * @param[in, out] *pSrc points to the in-place buffer of Q31 data type. - * @param[in] fftLen length of the FFT. - * @param[in] *pCoef points to Twiddle coefficient buffer. - * @param[in] twidCoefModifier twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. - * @return none. - */ - - void arm_radix4_butterfly_q31( - q31_t * pSrc, - uint32_t fftLen, - q31_t * pCoef, - uint32_t twidCoefModifier); - - /** - * @brief Core function for the f32 FFT butterfly process. - * @param[in, out] *pSrc points to the in-place buffer of f32 data type. - * @param[in] fftLen length of the FFT. - * @param[in] *pCoef points to Twiddle coefficient buffer. - * @param[in] twidCoefModifier twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. - * @return none. - */ - - void arm_radix2_butterfly_f32( - float32_t * pSrc, - uint32_t fftLen, - float32_t * pCoef, - uint16_t twidCoefModifier); - - /** - * @brief Core function for the Radix-2 Q31 CFFT butterfly process. - * @param[in, out] *pSrc points to the in-place buffer of Q31 data type. - * @param[in] fftLen length of the FFT. - * @param[in] *pCoef points to Twiddle coefficient buffer. - * @param[in] twidCoefModifier twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. - * @return none. - */ - - void arm_radix2_butterfly_q31( - q31_t * pSrc, - uint32_t fftLen, - q31_t * pCoef, - uint16_t twidCoefModifier); - - /** - * @brief Core function for the Radix-2 Q15 CFFT butterfly process. - * @param[in, out] *pSrc points to the in-place buffer of Q15 data type. - * @param[in] fftLen length of the FFT. - * @param[in] *pCoef points to Twiddle coefficient buffer. - * @param[in] twidCoefModifier twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. - * @return none. - */ - - void arm_radix2_butterfly_q15( - q15_t * pSrc, - uint32_t fftLen, - q15_t * pCoef, - uint16_t twidCoefModifier); - - /** - * @brief Core function for the Radix-2 Q15 CFFT Inverse butterfly process. - * @param[in, out] *pSrc points to the in-place buffer of Q15 data type. - * @param[in] fftLen length of the FFT. - * @param[in] *pCoef points to Twiddle coefficient buffer. - * @param[in] twidCoefModifier twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. - * @return none. - */ - - void arm_radix2_butterfly_inverse_q15( - q15_t * pSrc, - uint32_t fftLen, - q15_t * pCoef, - uint16_t twidCoefModifier); - - /** - * @brief Core function for the Radix-2 Q31 CFFT Inverse butterfly process. - * @param[in, out] *pSrc points to the in-place buffer of Q31 data type. - * @param[in] fftLen length of the FFT. - * @param[in] *pCoef points to Twiddle coefficient buffer. - * @param[in] twidCoefModifier twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. - * @return none. - */ - - void arm_radix2_butterfly_inverse_q31( - q31_t * pSrc, - uint32_t fftLen, - q31_t * pCoef, - uint16_t twidCoefModifier); - - /** - * @brief Core function for the f32 IFFT butterfly process. - * @param[in, out] *pSrc points to the in-place buffer of f32 data type. - * @param[in] fftLen length of the FFT. - * @param[in] *pCoef points to Twiddle coefficient buffer. - * @param[in] twidCoefModifier twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. - * @param[in] onebyfftLen 1/fftLenfth - * @return none. - */ - - void arm_radix2_butterfly_inverse_f32( - float32_t * pSrc, - uint32_t fftLen, - float32_t * pCoef, - uint16_t twidCoefModifier, - float32_t onebyfftLen); - - /** - * @brief Core function for the Q31 CIFFT butterfly process. - * @param[in, out] *pSrc points to the in-place buffer of Q31 data type. - * @param[in] fftLen length of the FFT. - * @param[in] *pCoef points to twiddle coefficient buffer. - * @param[in] twidCoefModifier twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. - * @return none. - */ - - void arm_radix4_butterfly_inverse_q31( - q31_t * pSrc, - uint32_t fftLen, - q31_t * pCoef, - uint32_t twidCoefModifier); - - /** - * @brief In-place bit reversal function. - * @param[in, out] *pSrc points to the in-place buffer of Q31 data type. - * @param[in] fftLen length of the FFT. - * @param[in] bitRevFactor bit reversal modifier that supports different size FFTs with the same bit reversal table - * @param[in] *pBitRevTab points to bit reversal table. - * @return none. - */ - - void arm_bitreversal_q31( - q31_t * pSrc, - uint32_t fftLen, - uint16_t bitRevFactor, - uint16_t * pBitRevTab); - - /** - * @brief Core function for the Q15 CFFT butterfly process. - * @param[in, out] *pSrc16 points to the in-place buffer of Q15 data type. - * @param[in] fftLen length of the FFT. - * @param[in] *pCoef16 points to twiddle coefficient buffer. - * @param[in] twidCoefModifier twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. - * @return none. - */ - - void arm_radix4_butterfly_q15( - q15_t * pSrc16, - uint32_t fftLen, - q15_t * pCoef16, - uint32_t twidCoefModifier); - - - /** - * @brief Core function for the Q15 CIFFT butterfly process. - * @param[in, out] *pSrc16 points to the in-place buffer of Q15 data type. - * @param[in] fftLen length of the FFT. - * @param[in] *pCoef16 points to twiddle coefficient buffer. - * @param[in] twidCoefModifier twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. - * @return none. - */ - - void arm_radix4_butterfly_inverse_q15( - q15_t * pSrc16, - uint32_t fftLen, - q15_t * pCoef16, - uint32_t twidCoefModifier); - - /** - * @brief In-place bit reversal function. - * @param[in, out] *pSrc points to the in-place buffer of Q15 data type. - * @param[in] fftLen length of the FFT. - * @param[in] bitRevFactor bit reversal modifier that supports different size FFTs with the same bit reversal table - * @param[in] *pBitRevTab points to bit reversal table. - * @return none. - */ - - void arm_bitreversal_q15( - q15_t * pSrc, - uint32_t fftLen, - uint16_t bitRevFactor, - uint16_t * pBitRevTab); + typedef struct + { + uint16_t fftLen; /**< length of the FFT. */ + const float32_t *pTwiddle; /**< points to the Twiddle factor table. */ + const uint16_t *pBitRevTable; /**< points to the bit reversal table. */ + uint16_t bitRevLength; /**< bit reversal table length. */ + } arm_cfft_instance_f32; + void arm_cfft_f32( + const arm_cfft_instance_f32 * S, + float32_t * p1, + uint8_t ifftFlag, + uint8_t bitReverseFlag); /** * @brief Instance structure for the Q15 RFFT/RIFFT function. @@ -2437,6 +2149,18 @@ extern "C" arm_cfft_radix4_instance_q15 *pCfft; /**< points to the complex FFT instance. */ } arm_rfft_instance_q15; + arm_status arm_rfft_init_q15( + arm_rfft_instance_q15 * S, + arm_cfft_radix4_instance_q15 * S_CFFT, + uint32_t fftLenReal, + uint32_t ifftFlagR, + uint32_t bitReverseFlag); + + void arm_rfft_q15( + const arm_rfft_instance_q15 * S, + q15_t * pSrc, + q15_t * pDst); + /** * @brief Instance structure for the Q31 RFFT/RIFFT function. */ @@ -2453,6 +2177,18 @@ extern "C" arm_cfft_radix4_instance_q31 *pCfft; /**< points to the complex FFT instance. */ } arm_rfft_instance_q31; + arm_status arm_rfft_init_q31( + arm_rfft_instance_q31 * S, + arm_cfft_radix4_instance_q31 * S_CFFT, + uint32_t fftLenReal, + uint32_t ifftFlagR, + uint32_t bitReverseFlag); + + void arm_rfft_q31( + const arm_rfft_instance_q31 * S, + q31_t * pSrc, + q31_t * pDst); + /** * @brief Instance structure for the floating-point RFFT/RIFFT function. */ @@ -2469,76 +2205,6 @@ extern "C" arm_cfft_radix4_instance_f32 *pCfft; /**< points to the complex FFT instance. */ } arm_rfft_instance_f32; - /** - * @brief Processing function for the Q15 RFFT/RIFFT. - * @param[in] *S points to an instance of the Q15 RFFT/RIFFT structure. - * @param[in] *pSrc points to the input buffer. - * @param[out] *pDst points to the output buffer. - * @return none. - */ - - void arm_rfft_q15( - const arm_rfft_instance_q15 * S, - q15_t * pSrc, - q15_t * pDst); - - /** - * @brief Initialization function for the Q15 RFFT/RIFFT. - * @param[in, out] *S points to an instance of the Q15 RFFT/RIFFT structure. - * @param[in] *S_CFFT points to an instance of the Q15 CFFT/CIFFT structure. - * @param[in] fftLenReal length of the FFT. - * @param[in] ifftFlagR flag that selects forward (ifftFlagR=0) or inverse (ifftFlagR=1) transform. - * @param[in] bitReverseFlag flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. - * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_ARGUMENT_ERROR if fftLenReal is not a supported value. - */ - - arm_status arm_rfft_init_q15( - arm_rfft_instance_q15 * S, - arm_cfft_radix4_instance_q15 * S_CFFT, - uint32_t fftLenReal, - uint32_t ifftFlagR, - uint32_t bitReverseFlag); - - /** - * @brief Processing function for the Q31 RFFT/RIFFT. - * @param[in] *S points to an instance of the Q31 RFFT/RIFFT structure. - * @param[in] *pSrc points to the input buffer. - * @param[out] *pDst points to the output buffer. - * @return none. - */ - - void arm_rfft_q31( - const arm_rfft_instance_q31 * S, - q31_t * pSrc, - q31_t * pDst); - - /** - * @brief Initialization function for the Q31 RFFT/RIFFT. - * @param[in, out] *S points to an instance of the Q31 RFFT/RIFFT structure. - * @param[in, out] *S_CFFT points to an instance of the Q31 CFFT/CIFFT structure. - * @param[in] fftLenReal length of the FFT. - * @param[in] ifftFlagR flag that selects forward (ifftFlagR=0) or inverse (ifftFlagR=1) transform. - * @param[in] bitReverseFlag flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. - * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_ARGUMENT_ERROR if fftLenReal is not a supported value. - */ - - arm_status arm_rfft_init_q31( - arm_rfft_instance_q31 * S, - arm_cfft_radix4_instance_q31 * S_CFFT, - uint32_t fftLenReal, - uint32_t ifftFlagR, - uint32_t bitReverseFlag); - - /** - * @brief Initialization function for the floating-point RFFT/RIFFT. - * @param[in,out] *S points to an instance of the floating-point RFFT/RIFFT structure. - * @param[in,out] *S_CFFT points to an instance of the floating-point CFFT/CIFFT structure. - * @param[in] fftLenReal length of the FFT. - * @param[in] ifftFlagR flag that selects forward (ifftFlagR=0) or inverse (ifftFlagR=1) transform. - * @param[in] bitReverseFlag flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. - * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_ARGUMENT_ERROR if fftLenReal is not a supported value. - */ - arm_status arm_rfft_init_f32( arm_rfft_instance_f32 * S, arm_cfft_radix4_instance_f32 * S_CFFT, @@ -2546,19 +2212,31 @@ extern "C" uint32_t ifftFlagR, uint32_t bitReverseFlag); - /** - * @brief Processing function for the floating-point RFFT/RIFFT. - * @param[in] *S points to an instance of the floating-point RFFT/RIFFT structure. - * @param[in] *pSrc points to the input buffer. - * @param[out] *pDst points to the output buffer. - * @return none. - */ - void arm_rfft_f32( const arm_rfft_instance_f32 * S, float32_t * pSrc, float32_t * pDst); + /** + * @brief Instance structure for the floating-point RFFT/RIFFT function. + */ + +typedef struct + { + arm_cfft_instance_f32 Sint; /**< Internal CFFT structure. */ + uint16_t fftLenRFFT; /**< length of the real sequence */ + float32_t * pTwiddleRFFT; /**< Twiddle factors real stage */ + } arm_rfft_fast_instance_f32 ; + +arm_status arm_rfft_fast_init_f32 ( + arm_rfft_fast_instance_f32 * S, + uint16_t fftLen); + +void arm_rfft_fast_f32( + arm_rfft_fast_instance_f32 * S, + float32_t * p, float32_t * pOut, + uint8_t ifftFlag); + /** * @brief Instance structure for the floating-point DCT4/IDCT4 function. */ @@ -3155,7 +2833,7 @@ extern "C" q31_t * pDst, uint32_t blockSize); /** - * @brief Copies the elements of a floating-point vector. + * @brief Copies the elements of a floating-point vector. * @param[in] *pSrc input pointer * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process @@ -3167,7 +2845,7 @@ extern "C" uint32_t blockSize); /** - * @brief Copies the elements of a Q7 vector. + * @brief Copies the elements of a Q7 vector. * @param[in] *pSrc input pointer * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process @@ -3179,7 +2857,7 @@ extern "C" uint32_t blockSize); /** - * @brief Copies the elements of a Q15 vector. + * @brief Copies the elements of a Q15 vector. * @param[in] *pSrc input pointer * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process @@ -3191,7 +2869,7 @@ extern "C" uint32_t blockSize); /** - * @brief Copies the elements of a Q31 vector. + * @brief Copies the elements of a Q31 vector. * @param[in] *pSrc input pointer * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process @@ -3202,7 +2880,7 @@ extern "C" q31_t * pDst, uint32_t blockSize); /** - * @brief Fills a constant value into a floating-point vector. + * @brief Fills a constant value into a floating-point vector. * @param[in] value input value to be filled * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process @@ -3214,7 +2892,7 @@ extern "C" uint32_t blockSize); /** - * @brief Fills a constant value into a Q7 vector. + * @brief Fills a constant value into a Q7 vector. * @param[in] value input value to be filled * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process @@ -3226,7 +2904,7 @@ extern "C" uint32_t blockSize); /** - * @brief Fills a constant value into a Q15 vector. + * @brief Fills a constant value into a Q15 vector. * @param[in] value input value to be filled * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process @@ -3238,7 +2916,7 @@ extern "C" uint32_t blockSize); /** - * @brief Fills a constant value into a Q31 vector. + * @brief Fills a constant value into a Q31 vector. * @param[in] value input value to be filled * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process @@ -3249,14 +2927,14 @@ extern "C" q31_t * pDst, uint32_t blockSize); -/** - * @brief Convolution of floating-point sequences. - * @param[in] *pSrcA points to the first input sequence. - * @param[in] srcALen length of the first input sequence. - * @param[in] *pSrcB points to the second input sequence. - * @param[in] srcBLen length of the second input sequence. - * @param[out] *pDst points to the location where the output result is written. Length srcALen+srcBLen-1. - * @return none. +/** + * @brief Convolution of floating-point sequences. + * @param[in] *pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] *pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] *pDst points to the location where the output result is written. Length srcALen+srcBLen-1. + * @return none. */ void arm_conv_f32( @@ -3266,17 +2944,17 @@ extern "C" uint32_t srcBLen, float32_t * pDst); - - /** - * @brief Convolution of Q15 sequences. - * @param[in] *pSrcA points to the first input sequence. - * @param[in] srcALen length of the first input sequence. - * @param[in] *pSrcB points to the second input sequence. - * @param[in] srcBLen length of the second input sequence. - * @param[out] *pDst points to the block of output data Length srcALen+srcBLen-1. - * @param[in] *pScratch1 points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. - * @param[in] *pScratch2 points to scratch buffer of size min(srcALen, srcBLen). - * @return none. + + /** + * @brief Convolution of Q15 sequences. + * @param[in] *pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] *pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] *pDst points to the block of output data Length srcALen+srcBLen-1. + * @param[in] *pScratch1 points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + * @param[in] *pScratch2 points to scratch buffer of size min(srcALen, srcBLen). + * @return none. */ @@ -3290,14 +2968,14 @@ extern "C" q15_t * pScratch2); -/** - * @brief Convolution of Q15 sequences. - * @param[in] *pSrcA points to the first input sequence. - * @param[in] srcALen length of the first input sequence. - * @param[in] *pSrcB points to the second input sequence. - * @param[in] srcBLen length of the second input sequence. - * @param[out] *pDst points to the location where the output result is written. Length srcALen+srcBLen-1. - * @return none. +/** + * @brief Convolution of Q15 sequences. + * @param[in] *pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] *pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] *pDst points to the location where the output result is written. Length srcALen+srcBLen-1. + * @return none. */ void arm_conv_q15( @@ -3331,9 +3009,9 @@ extern "C" * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length srcALen+srcBLen-1. - * @param[in] *pScratch1 points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. - * @param[in] *pScratch2 points to scratch buffer of size min(srcALen, srcBLen). - * @return none. + * @param[in] *pScratch1 points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + * @param[in] *pScratch2 points to scratch buffer of size min(srcALen, srcBLen). + * @return none. */ void arm_conv_fast_opt_q15( @@ -3382,16 +3060,16 @@ extern "C" q31_t * pDst); - /** - * @brief Convolution of Q7 sequences. - * @param[in] *pSrcA points to the first input sequence. - * @param[in] srcALen length of the first input sequence. - * @param[in] *pSrcB points to the second input sequence. - * @param[in] srcBLen length of the second input sequence. - * @param[out] *pDst points to the block of output data Length srcALen+srcBLen-1. - * @param[in] *pScratch1 points to scratch buffer(of type q15_t) of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. - * @param[in] *pScratch2 points to scratch buffer (of type q15_t) of size min(srcALen, srcBLen). - * @return none. + /** + * @brief Convolution of Q7 sequences. + * @param[in] *pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] *pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] *pDst points to the block of output data Length srcALen+srcBLen-1. + * @param[in] *pScratch1 points to scratch buffer(of type q15_t) of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + * @param[in] *pScratch2 points to scratch buffer (of type q15_t) of size min(srcALen, srcBLen). + * @return none. */ void arm_conv_opt_q7( @@ -3444,18 +3122,18 @@ extern "C" uint32_t firstIndex, uint32_t numPoints); - /** - * @brief Partial convolution of Q15 sequences. - * @param[in] *pSrcA points to the first input sequence. - * @param[in] srcALen length of the first input sequence. - * @param[in] *pSrcB points to the second input sequence. - * @param[in] srcBLen length of the second input sequence. - * @param[out] *pDst points to the block of output data - * @param[in] firstIndex is the first output sample to start with. - * @param[in] numPoints is the number of output points to be computed. - * @param[in] * pScratch1 points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. - * @param[in] * pScratch2 points to scratch buffer of size min(srcALen, srcBLen). - * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. + /** + * @brief Partial convolution of Q15 sequences. + * @param[in] *pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] *pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] *pDst points to the block of output data + * @param[in] firstIndex is the first output sample to start with. + * @param[in] numPoints is the number of output points to be computed. + * @param[in] * pScratch1 points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + * @param[in] * pScratch2 points to scratch buffer of size min(srcALen, srcBLen). + * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. */ arm_status arm_conv_partial_opt_q15( @@ -3522,9 +3200,9 @@ extern "C" * @param[out] *pDst points to the block of output data * @param[in] firstIndex is the first output sample to start with. * @param[in] numPoints is the number of output points to be computed. - * @param[in] * pScratch1 points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. - * @param[in] * pScratch2 points to scratch buffer of size min(srcALen, srcBLen). - * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. + * @param[in] * pScratch1 points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + * @param[in] * pScratch2 points to scratch buffer of size min(srcALen, srcBLen). + * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. */ arm_status arm_conv_partial_fast_opt_q15( @@ -3583,18 +3261,18 @@ extern "C" uint32_t numPoints); - /** - * @brief Partial convolution of Q7 sequences - * @param[in] *pSrcA points to the first input sequence. - * @param[in] srcALen length of the first input sequence. - * @param[in] *pSrcB points to the second input sequence. - * @param[in] srcBLen length of the second input sequence. - * @param[out] *pDst points to the block of output data - * @param[in] firstIndex is the first output sample to start with. - * @param[in] numPoints is the number of output points to be computed. - * @param[in] *pScratch1 points to scratch buffer(of type q15_t) of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. - * @param[in] *pScratch2 points to scratch buffer (of type q15_t) of size min(srcALen, srcBLen). - * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. + /** + * @brief Partial convolution of Q7 sequences + * @param[in] *pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] *pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] *pDst points to the block of output data + * @param[in] firstIndex is the first output sample to start with. + * @param[in] numPoints is the number of output points to be computed. + * @param[in] *pScratch1 points to scratch buffer(of type q15_t) of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + * @param[in] *pScratch2 points to scratch buffer (of type q15_t) of size min(srcALen, srcBLen). + * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. */ arm_status arm_conv_partial_opt_q7( @@ -4086,8 +3764,8 @@ extern "C" * @brief Initialization function for the Q15 FIR lattice filter. * @param[in] *S points to an instance of the Q15 FIR lattice structure. * @param[in] numStages number of filter stages. - * @param[in] *pCoeffs points to the coefficient buffer. The array is of length numStages. - * @param[in] *pState points to the state buffer. The array is of length numStages. + * @param[in] *pCoeffs points to the coefficient buffer. The array is of length numStages. + * @param[in] *pState points to the state buffer. The array is of length numStages. * @return none. */ @@ -4654,15 +4332,15 @@ extern "C" float32_t * pDst); - /** - * @brief Correlation of Q15 sequences - * @param[in] *pSrcA points to the first input sequence. - * @param[in] srcALen length of the first input sequence. - * @param[in] *pSrcB points to the second input sequence. - * @param[in] srcBLen length of the second input sequence. - * @param[out] *pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. - * @param[in] *pScratch points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. - * @return none. + /** + * @brief Correlation of Q15 sequences + * @param[in] *pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] *pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] *pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. + * @param[in] *pScratch points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + * @return none. */ void arm_correlate_opt_q15( q15_t * pSrcA, @@ -4716,7 +4394,7 @@ extern "C" * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. - * @param[in] *pScratch points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + * @param[in] *pScratch points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. * @return none. */ @@ -4764,16 +4442,16 @@ extern "C" - /** - * @brief Correlation of Q7 sequences. - * @param[in] *pSrcA points to the first input sequence. - * @param[in] srcALen length of the first input sequence. - * @param[in] *pSrcB points to the second input sequence. - * @param[in] srcBLen length of the second input sequence. - * @param[out] *pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. - * @param[in] *pScratch1 points to scratch buffer(of type q15_t) of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. - * @param[in] *pScratch2 points to scratch buffer (of type q15_t) of size min(srcALen, srcBLen). - * @return none. + /** + * @brief Correlation of Q7 sequences. + * @param[in] *pSrcA points to the first input sequence. + * @param[in] srcALen length of the first input sequence. + * @param[in] *pSrcB points to the second input sequence. + * @param[in] srcBLen length of the second input sequence. + * @param[out] *pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. + * @param[in] *pScratch1 points to scratch buffer(of type q15_t) of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. + * @param[in] *pScratch2 points to scratch buffer (of type q15_t) of size min(srcALen, srcBLen). + * @return none. */ void arm_correlate_opt_q7( @@ -5019,9 +4697,9 @@ extern "C" /* * @brief Floating-point sin_cos function. - * @param[in] theta input value in degrees - * @param[out] *pSinVal points to the processed sine output. - * @param[out] *pCosVal points to the processed cos output. + * @param[in] theta input value in degrees + * @param[out] *pSinVal points to the processed sine output. + * @param[out] *pCosVal points to the processed cos output. * @return none. */ @@ -5032,9 +4710,9 @@ extern "C" /* * @brief Q31 sin_cos function. - * @param[in] theta scaled input value in degrees - * @param[out] *pSinVal points to the processed sine output. - * @param[out] *pCosVal points to the processed cosine output. + * @param[in] theta scaled input value in degrees + * @param[out] *pSinVal points to the processed sine output. + * @param[out] *pCosVal points to the processed cosine output. * @return none. */ @@ -5132,7 +4810,7 @@ extern "C" /** * @defgroup PID PID Motor Control * - * A Proportional Integral Derivative (PID) controller is a generic feedback control + * A Proportional Integral Derivative (PID) controller is a generic feedback control * loop mechanism widely used in industrial control systems. * A PID controller is the most commonly used type of feedback controller. * @@ -5151,39 +4829,39 @@ extern "C" * * \par * where \c Kp is proportional constant, \c Ki is Integral constant and \c Kd is Derivative constant - * - * \par - * \image html PID.gif "Proportional Integral Derivative Controller" + * + * \par + * \image html PID.gif "Proportional Integral Derivative Controller" * * \par * The PID controller calculates an "error" value as the difference between * the measured output and the reference input. - * The controller attempts to minimize the error by adjusting the process control inputs. - * The proportional value determines the reaction to the current error, - * the integral value determines the reaction based on the sum of recent errors, + * The controller attempts to minimize the error by adjusting the process control inputs. + * The proportional value determines the reaction to the current error, + * the integral value determines the reaction based on the sum of recent errors, * and the derivative value determines the reaction based on the rate at which the error has been changing. * - * \par Instance Structure - * The Gains A0, A1, A2 and state variables for a PID controller are stored together in an instance data structure. - * A separate instance structure must be defined for each PID Controller. - * There are separate instance structure declarations for each of the 3 supported data types. - * - * \par Reset Functions - * There is also an associated reset function for each data type which clears the state array. + * \par Instance Structure + * The Gains A0, A1, A2 and state variables for a PID controller are stored together in an instance data structure. + * A separate instance structure must be defined for each PID Controller. + * There are separate instance structure declarations for each of the 3 supported data types. * - * \par Initialization Functions - * There is also an associated initialization function for each data type. - * The initialization function performs the following operations: + * \par Reset Functions + * There is also an associated reset function for each data type which clears the state array. + * + * \par Initialization Functions + * There is also an associated initialization function for each data type. + * The initialization function performs the following operations: * - Initializes the Gains A0, A1, A2 from Kp,Ki, Kd gains. - * - Zeros out the values in the state buffer. - * - * \par - * Instance structure cannot be placed into a const data section and it is recommended to use the initialization function. + * - Zeros out the values in the state buffer. * - * \par Fixed-Point Behavior - * Care must be taken when using the fixed-point versions of the PID Controller functions. - * In particular, the overflow and saturation behavior of the accumulator used in each function must be considered. - * Refer to the function specific documentation below for usage guidelines. + * \par + * Instance structure cannot be placed into a const data section and it is recommended to use the initialization function. + * + * \par Fixed-Point Behavior + * Care must be taken when using the fixed-point versions of the PID Controller functions. + * In particular, the overflow and saturation behavior of the accumulator used in each function must be considered. + * Refer to the function specific documentation below for usage guidelines. */ /** @@ -5199,7 +4877,7 @@ extern "C" */ - __STATIC_INLINE float32_t arm_pid_f32( + static __INLINE float32_t arm_pid_f32( arm_pid_instance_f32 * S, float32_t in) { @@ -5225,16 +4903,16 @@ extern "C" * @param[in] in input sample to process * @return out processed output sample. * - * Scaling and Overflow Behavior: - * \par - * The function is implemented using an internal 64-bit accumulator. - * The accumulator has a 2.62 format and maintains full precision of the intermediate multiplication results but provides only a single guard bit. - * Thus, if the accumulator result overflows it wraps around rather than clip. - * In order to avoid overflows completely the input signal must be scaled down by 2 bits as there are four additions. - * After all multiply-accumulates are performed, the 2.62 accumulator is truncated to 1.32 format and then saturated to 1.31 format. + * Scaling and Overflow Behavior: + * \par + * The function is implemented using an internal 64-bit accumulator. + * The accumulator has a 2.62 format and maintains full precision of the intermediate multiplication results but provides only a single guard bit. + * Thus, if the accumulator result overflows it wraps around rather than clip. + * In order to avoid overflows completely the input signal must be scaled down by 2 bits as there are four additions. + * After all multiply-accumulates are performed, the 2.62 accumulator is truncated to 1.32 format and then saturated to 1.31 format. */ - __STATIC_INLINE q31_t arm_pid_q31( + static __INLINE q31_t arm_pid_q31( arm_pid_instance_q31 * S, q31_t in) { @@ -5272,48 +4950,43 @@ extern "C" * @param[in] in input sample to process * @return out processed output sample. * - * Scaling and Overflow Behavior: - * \par - * The function is implemented using a 64-bit internal accumulator. - * Both Gains and state variables are represented in 1.15 format and multiplications yield a 2.30 result. - * The 2.30 intermediate results are accumulated in a 64-bit accumulator in 34.30 format. - * There is no risk of internal overflow with this approach and the full precision of intermediate multiplications is preserved. - * After all additions have been performed, the accumulator is truncated to 34.15 format by discarding low 15 bits. + * Scaling and Overflow Behavior: + * \par + * The function is implemented using a 64-bit internal accumulator. + * Both Gains and state variables are represented in 1.15 format and multiplications yield a 2.30 result. + * The 2.30 intermediate results are accumulated in a 64-bit accumulator in 34.30 format. + * There is no risk of internal overflow with this approach and the full precision of intermediate multiplications is preserved. + * After all additions have been performed, the accumulator is truncated to 34.15 format by discarding low 15 bits. * Lastly, the accumulator is saturated to yield a result in 1.15 format. */ - __STATIC_INLINE q15_t arm_pid_q15( + static __INLINE q15_t arm_pid_q15( arm_pid_instance_q15 * S, q15_t in) { q63_t acc; q15_t out; +#ifndef ARM_MATH_CM0_FAMILY + __SIMD32_TYPE *vstate; + /* Implementation of PID controller */ -#ifdef ARM_MATH_CM0 - - /* acc = A0 * x[n] */ - acc = ((q31_t) S->A0) * in; - -#else - /* acc = A0 * x[n] */ acc = (q31_t) __SMUAD(S->A0, in); -#endif + /* acc += A1 * x[n-1] + A2 * x[n-2] */ + vstate = __SIMD32_CONST(S->state); + acc = __SMLALD(S->A1, (q31_t) *vstate, acc); -#ifdef ARM_MATH_CM0 +#else + /* acc = A0 * x[n] */ + acc = ((q31_t) S->A0) * in; /* acc += A1 * x[n-1] + A2 * x[n-2] */ acc += (q31_t) S->A1 * S->state[0]; acc += (q31_t) S->A2 * S->state[1]; -#else - - /* acc += A1 * x[n-1] + A2 * x[n-2] */ - acc = __SMLALD(S->A1, (q31_t) __SIMD32(S->state), acc); - #endif /* acc += y[n-1] */ @@ -5366,7 +5039,7 @@ extern "C" * and Ia + Ib + Ic = 0, in this condition Ialpha and Ibeta * can be calculated using only Ia and Ib. * - * The function operates on a single sample of data and each call to the function returns the processed output. + * The function operates on a single sample of data and each call to the function returns the processed output. * The library provides separate functions for Q31 and floating-point data types. * \par Algorithm * \image html clarkeFormula.gif @@ -5393,7 +5066,7 @@ extern "C" * @return none. */ - __STATIC_INLINE void arm_clarke_f32( + static __INLINE void arm_clarke_f32( float32_t Ia, float32_t Ib, float32_t * pIalpha, @@ -5423,7 +5096,7 @@ extern "C" * There is saturation on the addition, hence there is no risk of overflow. */ - __STATIC_INLINE void arm_clarke_q31( + static __INLINE void arm_clarke_q31( q31_t Ia, q31_t Ib, q31_t * pIalpha, @@ -5470,8 +5143,8 @@ extern "C" /** * @defgroup inv_clarke Vector Inverse Clarke Transform * Inverse Clarke transform converts the two-coordinate time invariant vector into instantaneous stator phases. - * - * The function operates on a single sample of data and each call to the function returns the processed output. + * + * The function operates on a single sample of data and each call to the function returns the processed output. * The library provides separate functions for Q31 and floating-point data types. * \par Algorithm * \image html clarkeInvFormula.gif @@ -5498,7 +5171,7 @@ extern "C" */ - __STATIC_INLINE void arm_inv_clarke_f32( + static __INLINE void arm_inv_clarke_f32( float32_t Ialpha, float32_t Ibeta, float32_t * pIa, @@ -5513,7 +5186,7 @@ extern "C" } /** - * @brief Inverse Clarke transform for Q31 version + * @brief Inverse Clarke transform for Q31 version * @param[in] Ialpha input two-phase orthogonal vector axis alpha * @param[in] Ibeta input two-phase orthogonal vector axis beta * @param[out] *pIa points to output three-phase coordinate a @@ -5527,7 +5200,7 @@ extern "C" * There is saturation on the subtraction, hence there is no risk of overflow. */ - __STATIC_INLINE void arm_inv_clarke_q31( + static __INLINE void arm_inv_clarke_q31( q31_t Ialpha, q31_t Ibeta, q31_t * pIa, @@ -5575,19 +5248,19 @@ extern "C" * @defgroup park Vector Park Transform * * Forward Park transform converts the input two-coordinate vector to flux and torque components. - * The Park transform can be used to realize the transformation of the Ialpha and the Ibeta currents - * from the stationary to the moving reference frame and control the spatial relationship between + * The Park transform can be used to realize the transformation of the Ialpha and the Ibeta currents + * from the stationary to the moving reference frame and control the spatial relationship between * the stator vector current and rotor flux vector. - * If we consider the d axis aligned with the rotor flux, the diagram below shows the + * If we consider the d axis aligned with the rotor flux, the diagram below shows the * current vector and the relationship from the two reference frames: * \image html park.gif "Stator current space vector and its component in (a,b) and in the d,q rotating reference frame" * - * The function operates on a single sample of data and each call to the function returns the processed output. + * The function operates on a single sample of data and each call to the function returns the processed output. * The library provides separate functions for Q31 and floating-point data types. * \par Algorithm * \image html parkFormula.gif - * where Ialpha and Ibeta are the stator vector components, - * pId and pIq are rotor vector components and cosVal and sinVal are the + * where Ialpha and Ibeta are the stator vector components, + * pId and pIq are rotor vector components and cosVal and sinVal are the * cosine and sine values of theta (rotor flux position). * \par Fixed-Point Behavior * Care must be taken when using the Q31 version of the Park transform. @@ -5614,7 +5287,7 @@ extern "C" * */ - __STATIC_INLINE void arm_park_f32( + static __INLINE void arm_park_f32( float32_t Ialpha, float32_t Ibeta, float32_t * pId, @@ -5631,7 +5304,7 @@ extern "C" } /** - * @brief Park transform for Q31 version + * @brief Park transform for Q31 version * @param[in] Ialpha input two-phase vector coordinate alpha * @param[in] Ibeta input two-phase vector coordinate beta * @param[out] *pId points to output rotor reference frame d @@ -5648,7 +5321,7 @@ extern "C" */ - __STATIC_INLINE void arm_park_q31( + static __INLINE void arm_park_q31( q31_t Ialpha, q31_t Ibeta, q31_t * pId, @@ -5704,12 +5377,12 @@ extern "C" * @defgroup inv_park Vector Inverse Park transform * Inverse Park transform converts the input flux and torque components to two-coordinate vector. * - * The function operates on a single sample of data and each call to the function returns the processed output. + * The function operates on a single sample of data and each call to the function returns the processed output. * The library provides separate functions for Q31 and floating-point data types. * \par Algorithm * \image html parkInvFormula.gif - * where pIalpha and pIbeta are the stator vector components, - * Id and Iq are rotor vector components and cosVal and sinVal are the + * where pIalpha and pIbeta are the stator vector components, + * Id and Iq are rotor vector components and cosVal and sinVal are the * cosine and sine values of theta (rotor flux position). * \par Fixed-Point Behavior * Care must be taken when using the Q31 version of the Park transform. @@ -5733,7 +5406,7 @@ extern "C" * @return none. */ - __STATIC_INLINE void arm_inv_park_f32( + static __INLINE void arm_inv_park_f32( float32_t Id, float32_t Iq, float32_t * pIalpha, @@ -5751,7 +5424,7 @@ extern "C" /** - * @brief Inverse Park transform for Q31 version + * @brief Inverse Park transform for Q31 version * @param[in] Id input coordinate of rotor reference frame d * @param[in] Iq input coordinate of rotor reference frame q * @param[out] *pIalpha points to output two-phase orthogonal vector axis alpha @@ -5768,7 +5441,7 @@ extern "C" */ - __STATIC_INLINE void arm_inv_park_q31( + static __INLINE void arm_inv_park_q31( q31_t Id, q31_t Iq, q31_t * pIalpha, @@ -5827,7 +5500,7 @@ extern "C" * Linear interpolation is a method of curve fitting using linear polynomials. * Linear interpolation works by effectively drawing a straight line between two neighboring samples and returning the appropriate point along that line * - * \par + * \par * \image html LinearInterp.gif "Linear interpolation" * * \par @@ -5847,10 +5520,10 @@ extern "C" * sample of data and each call to the function returns a single processed value. * S points to an instance of the Linear Interpolate function data structure. * x is the input sample value. The functions returns the output value. - * + * * \par - * if x is outside of the table boundary, Linear interpolation returns first value of the table - * if x is below input range and returns last value of table if x is above range. + * if x is outside of the table boundary, Linear interpolation returns first value of the table + * if x is below input range and returns last value of table if x is above range. */ /** @@ -5866,7 +5539,7 @@ extern "C" * */ - __STATIC_INLINE float32_t arm_linear_interp_f32( + static __INLINE float32_t arm_linear_interp_f32( arm_linear_interp_instance_f32 * S, float32_t x) { @@ -5879,14 +5552,14 @@ extern "C" float32_t *pYData = S->pYData; /* pointer to output table */ /* Calculation of index */ - i = (x - S->x1) / xSpacing; + i = (int32_t) ((x - S->x1) / xSpacing); if(i < 0) { /* Iniatilize output for below specified range as least output value of table */ y = pYData[0]; } - else if(i >= S->nValues) + else if((uint32_t)i >= S->nValues) { /* Iniatilize output for above specified range as last output value of table */ y = pYData[S->nValues - 1]; @@ -5925,7 +5598,7 @@ extern "C" */ - __STATIC_INLINE q31_t arm_linear_interp_q31( + static __INLINE q31_t arm_linear_interp_q31( q31_t * pYData, q31_t x, uint32_t nValues) @@ -5940,7 +5613,7 @@ extern "C" /* Index value calculation */ index = ((x & 0xFFF00000) >> 20); - if(index >= (nValues - 1)) + if(index >= (int32_t)(nValues - 1)) { return (pYData[nValues - 1]); } @@ -5982,12 +5655,12 @@ extern "C" * * \par * Input sample x is in 12.20 format which contains 12 bits for table index and 20 bits for fractional part. - * This function can support maximum of table size 2^12. + * This function can support maximum of table size 2^12. * */ - __STATIC_INLINE q15_t arm_linear_interp_q15( + static __INLINE q15_t arm_linear_interp_q15( q15_t * pYData, q31_t x, uint32_t nValues) @@ -6002,7 +5675,7 @@ extern "C" /* Index value calculation */ index = ((x & 0xFFF00000) >> 20u); - if(index >= (nValues - 1)) + if(index >= (int32_t)(nValues - 1)) { return (pYData[nValues - 1]); } @@ -6047,7 +5720,7 @@ extern "C" */ - __STATIC_INLINE q7_t arm_linear_interp_q7( + static __INLINE q7_t arm_linear_interp_q7( q7_t * pYData, q31_t x, uint32_t nValues) @@ -6055,22 +5728,22 @@ extern "C" q31_t y; /* output */ q7_t y0, y1; /* Nearest output values */ q31_t fract; /* fractional part */ - int32_t index; /* Index to read nearest output values */ + uint32_t index; /* Index to read nearest output values */ /* Input is in 12.20 format */ /* 12 bits for the table index */ /* Index value calculation */ - index = ((x & 0xFFF00000) >> 20u); + if (x < 0) + { + return (pYData[0]); + } + index = (x >> 20) & 0xfff; if(index >= (nValues - 1)) { return (pYData[nValues - 1]); } - else if(index < 0) - { - return (pYData[0]); - } else { @@ -6162,14 +5835,14 @@ extern "C" * @defgroup SQRT Square Root * * Computes the square root of a number. - * There are separate functions for Q15, Q31, and floating-point data types. + * There are separate functions for Q15, Q31, and floating-point data types. * The square root function is computed using the Newton-Raphson algorithm. * This is an iterative algorithm of the form: *
    *      x1 = x0 - f(x0)/f'(x0)
    * 
* where x1 is the current estimate, - * x0 is the previous estimate and + * x0 is the previous estimate, and * f'(x0) is the derivative of f() evaluated at x0. * For the square root function, the algorithm reduces to: *
@@ -6192,21 +5865,19 @@ extern "C"
    * in is negative value and returns zero output for negative values.
    */
 
-  __STATIC_INLINE arm_status arm_sqrt_f32(
+  static __INLINE arm_status arm_sqrt_f32(
   float32_t in,
   float32_t * pOut)
   {
     if(in > 0)
     {
 
-//    #if __FPU_USED
-    #if (__FPU_USED == 1) && defined ( __CC_ARM   )
-        *pOut = __sqrtf(in);
-    #elif (__FPU_USED == 1) && defined ( __TMS_740 )
-        *pOut = __builtin_sqrtf(in);
-    #else
-        *pOut = sqrtf(in);
-    #endif
+//      #if __FPU_USED
+#if (__FPU_USED == 1) && defined ( __CC_ARM   )
+      *pOut = __sqrtf(in);
+#else
+      *pOut = sqrtf(in);
+#endif
 
       return (ARM_MATH_SUCCESS);
     }
@@ -6254,7 +5925,7 @@ extern "C"
    * @brief floating-point Circular write function.
    */
 
-  __STATIC_INLINE void arm_circularWrite_f32(
+  static __INLINE void arm_circularWrite_f32(
   int32_t * circBuffer,
   int32_t L,
   uint16_t * writeOffset,
@@ -6299,7 +5970,7 @@ extern "C"
   /**
    * @brief floating-point Circular Read function.
    */
-  __STATIC_INLINE void arm_circularRead_f32(
+  static __INLINE void arm_circularRead_f32(
   int32_t * circBuffer,
   int32_t L,
   int32_t * readOffset,
@@ -6354,7 +6025,7 @@ extern "C"
    * @brief Q15 Circular write function.
    */
 
-  __STATIC_INLINE void arm_circularWrite_q15(
+  static __INLINE void arm_circularWrite_q15(
   q15_t * circBuffer,
   int32_t L,
   uint16_t * writeOffset,
@@ -6399,7 +6070,7 @@ extern "C"
   /**
    * @brief Q15 Circular Read function.
    */
-  __STATIC_INLINE void arm_circularRead_q15(
+  static __INLINE void arm_circularRead_q15(
   q15_t * circBuffer,
   int32_t L,
   int32_t * readOffset,
@@ -6456,7 +6127,7 @@ extern "C"
    * @brief Q7 Circular write function.
    */
 
-  __STATIC_INLINE void arm_circularWrite_q7(
+  static __INLINE void arm_circularWrite_q7(
   q7_t * circBuffer,
   int32_t L,
   uint16_t * writeOffset,
@@ -6501,7 +6172,7 @@ extern "C"
   /**
    * @brief Q7 Circular Read function.
    */
-  __STATIC_INLINE void arm_circularRead_q7(
+  static __INLINE void arm_circularRead_q7(
   q7_t * circBuffer,
   int32_t L,
   int32_t * readOffset,
@@ -7072,11 +6743,11 @@ extern "C"
   uint32_t numSamples);
 
   /**
-   * @brief Converts the elements of the floating-point vector to Q31 vector. 
-   * @param[in]       *pSrc points to the floating-point input vector 
+   * @brief Converts the elements of the floating-point vector to Q31 vector.
+   * @param[in]       *pSrc points to the floating-point input vector
    * @param[out]      *pDst points to the Q31 output vector
-   * @param[in]       blockSize length of the input vector 
-   * @return none. 
+   * @param[in]       blockSize length of the input vector
+   * @return none.
    */
   void arm_float_to_q31(
   float32_t * pSrc,
@@ -7084,10 +6755,10 @@ extern "C"
   uint32_t blockSize);
 
   /**
-   * @brief Converts the elements of the floating-point vector to Q15 vector. 
-   * @param[in]       *pSrc points to the floating-point input vector 
+   * @brief Converts the elements of the floating-point vector to Q15 vector.
+   * @param[in]       *pSrc points to the floating-point input vector
    * @param[out]      *pDst points to the Q15 output vector
-   * @param[in]       blockSize length of the input vector 
+   * @param[in]       blockSize length of the input vector
    * @return          none
    */
   void arm_float_to_q15(
@@ -7096,10 +6767,10 @@ extern "C"
   uint32_t blockSize);
 
   /**
-   * @brief Converts the elements of the floating-point vector to Q7 vector. 
-   * @param[in]       *pSrc points to the floating-point input vector 
+   * @brief Converts the elements of the floating-point vector to Q7 vector.
+   * @param[in]       *pSrc points to the floating-point input vector
    * @param[out]      *pDst points to the Q7 output vector
-   * @param[in]       blockSize length of the input vector 
+   * @param[in]       blockSize length of the input vector
    * @return          none
    */
   void arm_float_to_q7(
@@ -7219,12 +6890,12 @@ extern "C"
    *           + f(XF, YF+1) * (1-(x-XF))*(y-YF)
    *           + f(XF+1, YF+1) * (x-XF)*(y-YF)
    * 
- * Note that the coordinates (x, y) contain integer and fractional components. + * Note that the coordinates (x, y) contain integer and fractional components. * The integer components specify which portion of the table to use while the * fractional components control the interpolation processor. * * \par - * if (x,y) are outside of the table boundary, Bilinear interpolation returns zero output. + * if (x,y) are outside of the table boundary, Bilinear interpolation returns zero output. */ /** @@ -7242,7 +6913,7 @@ extern "C" */ - __STATIC_INLINE float32_t arm_bilinear_interp_f32( + static __INLINE float32_t arm_bilinear_interp_f32( const arm_bilinear_interp_instance_f32 * S, float32_t X, float32_t Y) @@ -7310,7 +6981,7 @@ extern "C" * @return out interpolated value. */ - __STATIC_INLINE q31_t arm_bilinear_interp_q31( + static __INLINE q31_t arm_bilinear_interp_q31( arm_bilinear_interp_instance_q31 * S, q31_t X, q31_t Y) @@ -7386,7 +7057,7 @@ extern "C" * @return out interpolated value. */ - __STATIC_INLINE q15_t arm_bilinear_interp_q15( + static __INLINE q15_t arm_bilinear_interp_q15( arm_bilinear_interp_instance_q15 * S, q31_t X, q31_t Y) @@ -7466,7 +7137,7 @@ extern "C" * @return out interpolated value. */ - __STATIC_INLINE q7_t arm_bilinear_interp_q7( + static __INLINE q7_t arm_bilinear_interp_q7( arm_bilinear_interp_instance_q7 * S, q31_t X, q31_t Y) @@ -7539,6 +7210,84 @@ extern "C" */ +#if defined ( __CC_ARM ) //Keil +//SMMLAR + #define multAcc_32x32_keep32_R(a, x, y) \ + a = (q31_t) (((((q63_t) a) << 32) + ((q63_t) x * y) + 0x80000000LL ) >> 32) + +//SMMLSR + #define multSub_32x32_keep32_R(a, x, y) \ + a = (q31_t) (((((q63_t) a) << 32) - ((q63_t) x * y) + 0x80000000LL ) >> 32) + +//SMMULR + #define mult_32x32_keep32_R(a, x, y) \ + a = (q31_t) (((q63_t) x * y + 0x80000000LL ) >> 32) + +//Enter low optimization region - place directly above function definition + #define LOW_OPTIMIZATION_ENTER \ + _Pragma ("push") \ + _Pragma ("O1") + +//Exit low optimization region - place directly after end of function definition + #define LOW_OPTIMIZATION_EXIT \ + _Pragma ("pop") + +//Enter low optimization region - place directly above function definition + #define IAR_ONLY_LOW_OPTIMIZATION_ENTER + +//Exit low optimization region - place directly after end of function definition + #define IAR_ONLY_LOW_OPTIMIZATION_EXIT + +#elif defined(__ICCARM__) //IAR + //SMMLA + #define multAcc_32x32_keep32_R(a, x, y) \ + a += (q31_t) (((q63_t) x * y) >> 32) + + //SMMLS + #define multSub_32x32_keep32_R(a, x, y) \ + a -= (q31_t) (((q63_t) x * y) >> 32) + +//SMMUL + #define mult_32x32_keep32_R(a, x, y) \ + a = (q31_t) (((q63_t) x * y ) >> 32) + +//Enter low optimization region - place directly above function definition + #define LOW_OPTIMIZATION_ENTER \ + _Pragma ("optimize=low") + +//Exit low optimization region - place directly after end of function definition + #define LOW_OPTIMIZATION_EXIT + +//Enter low optimization region - place directly above function definition + #define IAR_ONLY_LOW_OPTIMIZATION_ENTER \ + _Pragma ("optimize=low") + +//Exit low optimization region - place directly after end of function definition + #define IAR_ONLY_LOW_OPTIMIZATION_EXIT + +#elif defined(__GNUC__) + //SMMLA + #define multAcc_32x32_keep32_R(a, x, y) \ + a += (q31_t) (((q63_t) x * y) >> 32) + + //SMMLS + #define multSub_32x32_keep32_R(a, x, y) \ + a -= (q31_t) (((q63_t) x * y) >> 32) + +//SMMUL + #define mult_32x32_keep32_R(a, x, y) \ + a = (q31_t) (((q63_t) x * y ) >> 32) + + #define LOW_OPTIMIZATION_ENTER __attribute__(( optimize("-O1") )) + + #define LOW_OPTIMIZATION_EXIT + + #define IAR_ONLY_LOW_OPTIMIZATION_ENTER + + #define IAR_ONLY_LOW_OPTIMIZATION_EXIT + +#endif + diff --git a/components/CMSIS/Include/core_cm0.h b/components/CMSIS/Include/core_cm0.h index 19bad5ebeb..ab31de0ee8 100644 --- a/components/CMSIS/Include/core_cm0.h +++ b/components/CMSIS/Include/core_cm0.h @@ -1,25 +1,40 @@ /**************************************************************************//** * @file core_cm0.h * @brief CMSIS Cortex-M0 Core Peripheral Access Layer Header File - * @version V3.01 - * @date 13. March 2012 + * @version V3.20 + * @date 25. February 2013 * * @note - * Copyright (C) 2009-2012 ARM Limited. All rights reserved. - * - * @par - * ARM Limited (ARM) is supplying this software for use with Cortex-M - * processor based microcontrollers. This file can be freely distributed - * within development tools that are supporting such ARM based processors. - * - * @par - * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED - * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. - * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * ******************************************************************************/ +/* Copyright (c) 2009 - 2013 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of ARM nor the names of its contributors may be used + to endorse or promote products derived from this software without + specific prior written permission. + * + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------------------------------*/ + + #if defined ( __ICCARM__ ) #pragma system_include /* treat file as system include file for MISRA check */ #endif @@ -54,7 +69,7 @@ /* CMSIS CM0 definitions */ #define __CM0_CMSIS_VERSION_MAIN (0x03) /*!< [31:16] CMSIS HAL main version */ -#define __CM0_CMSIS_VERSION_SUB (0x01) /*!< [15:0] CMSIS HAL sub version */ +#define __CM0_CMSIS_VERSION_SUB (0x20) /*!< [15:0] CMSIS HAL sub version */ #define __CM0_CMSIS_VERSION ((__CM0_CMSIS_VERSION_MAIN << 16) | \ __CM0_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ @@ -590,9 +605,9 @@ __STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) { if(IRQn < 0) { - return((uint32_t)((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) >> (8 - __NVIC_PRIO_BITS))); } /* get priority for Cortex-M0 system interrupts */ + return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & 0xFF) >> (8 - __NVIC_PRIO_BITS))); } /* get priority for Cortex-M0 system interrupts */ else { - return((uint32_t)((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) >> (8 - __NVIC_PRIO_BITS))); } /* get priority for device specific interrupts */ + return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & 0xFF) >> (8 - __NVIC_PRIO_BITS))); } /* get priority for device specific interrupts */ } @@ -640,9 +655,9 @@ __STATIC_INLINE void NVIC_SystemReset(void) */ __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) { - if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ + if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ - SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */ + SysTick->LOAD = ticks - 1; /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Systick Interrupt */ SysTick->VAL = 0; /* Load the SysTick Counter Value */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | diff --git a/components/CMSIS/Include/core_cm0plus.h b/components/CMSIS/Include/core_cm0plus.h index aa20e6879f..5cea74e9af 100644 --- a/components/CMSIS/Include/core_cm0plus.h +++ b/components/CMSIS/Include/core_cm0plus.h @@ -1,25 +1,40 @@ /**************************************************************************//** * @file core_cm0plus.h * @brief CMSIS Cortex-M0+ Core Peripheral Access Layer Header File - * @version V3.01 - * @date 22. March 2012 + * @version V3.20 + * @date 25. February 2013 * * @note - * Copyright (C) 2009-2012 ARM Limited. All rights reserved. - * - * @par - * ARM Limited (ARM) is supplying this software for use with Cortex-M - * processor based microcontrollers. This file can be freely distributed - * within development tools that are supporting such ARM based processors. - * - * @par - * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED - * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. - * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * ******************************************************************************/ +/* Copyright (c) 2009 - 2013 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of ARM nor the names of its contributors may be used + to endorse or promote products derived from this software without + specific prior written permission. + * + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------------------------------*/ + + #if defined ( __ICCARM__ ) #pragma system_include /* treat file as system include file for MISRA check */ #endif @@ -54,7 +69,7 @@ /* CMSIS CM0P definitions */ #define __CM0PLUS_CMSIS_VERSION_MAIN (0x03) /*!< [31:16] CMSIS HAL main version */ -#define __CM0PLUS_CMSIS_VERSION_SUB (0x01) /*!< [15:0] CMSIS HAL sub version */ +#define __CM0PLUS_CMSIS_VERSION_SUB (0x20) /*!< [15:0] CMSIS HAL sub version */ #define __CM0PLUS_CMSIS_VERSION ((__CM0PLUS_CMSIS_VERSION_MAIN << 16) | \ __CM0PLUS_CMSIS_VERSION_SUB) /*!< CMSIS HAL version number */ @@ -361,8 +376,8 @@ typedef struct #if (__VTOR_PRESENT == 1) /* SCB Interrupt Control State Register Definitions */ -#define SCB_VTOR_TBLOFF_Pos 7 /*!< SCB VTOR: TBLOFF Position */ -#define SCB_VTOR_TBLOFF_Msk (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ +#define SCB_VTOR_TBLOFF_Pos 8 /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0xFFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ #endif /* SCB Application Interrupt and Reset Control Register Definitions */ @@ -701,9 +716,9 @@ __STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) { if(IRQn < 0) { - return((uint32_t)((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) >> (8 - __NVIC_PRIO_BITS))); } /* get priority for Cortex-M0+ system interrupts */ + return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & 0xFF) >> (8 - __NVIC_PRIO_BITS))); } /* get priority for Cortex-M0 system interrupts */ else { - return((uint32_t)((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) >> (8 - __NVIC_PRIO_BITS))); } /* get priority for device specific interrupts */ + return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & 0xFF) >> (8 - __NVIC_PRIO_BITS))); } /* get priority for device specific interrupts */ } @@ -751,9 +766,9 @@ __STATIC_INLINE void NVIC_SystemReset(void) */ __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) { - if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ + if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ - SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */ + SysTick->LOAD = ticks - 1; /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Systick Interrupt */ SysTick->VAL = 0; /* Load the SysTick Counter Value */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | diff --git a/components/CMSIS/Include/core_cm3.h b/components/CMSIS/Include/core_cm3.h index 0173893fbd..122c9aa4a8 100644 --- a/components/CMSIS/Include/core_cm3.h +++ b/components/CMSIS/Include/core_cm3.h @@ -1,25 +1,40 @@ /**************************************************************************//** * @file core_cm3.h * @brief CMSIS Cortex-M3 Core Peripheral Access Layer Header File - * @version V3.01 - * @date 22. March 2012 + * @version V3.20 + * @date 25. February 2013 * * @note - * Copyright (C) 2009-2012 ARM Limited. All rights reserved. - * - * @par - * ARM Limited (ARM) is supplying this software for use with Cortex-M - * processor based microcontrollers. This file can be freely distributed - * within development tools that are supporting such ARM based processors. - * - * @par - * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED - * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. - * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * ******************************************************************************/ +/* Copyright (c) 2009 - 2013 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of ARM nor the names of its contributors may be used + to endorse or promote products derived from this software without + specific prior written permission. + * + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------------------------------*/ + + #if defined ( __ICCARM__ ) #pragma system_include /* treat file as system include file for MISRA check */ #endif @@ -54,7 +69,7 @@ /* CMSIS CM3 definitions */ #define __CM3_CMSIS_VERSION_MAIN (0x03) /*!< [31:16] CMSIS HAL main version */ -#define __CM3_CMSIS_VERSION_SUB (0x01) /*!< [15:0] CMSIS HAL sub version */ +#define __CM3_CMSIS_VERSION_SUB (0x20) /*!< [15:0] CMSIS HAL sub version */ #define __CM3_CMSIS_VERSION ((__CM3_CMSIS_VERSION_MAIN << 16) | \ __CM3_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ @@ -636,14 +651,14 @@ typedef struct __IO uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ uint32_t RESERVED2[15]; __IO uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ - uint32_t RESERVED3[29]; + uint32_t RESERVED3[29]; __O uint32_t IWR; /*!< Offset: 0xEF8 ( /W) ITM Integration Write Register */ __I uint32_t IRR; /*!< Offset: 0xEFC (R/ ) ITM Integration Read Register */ __IO uint32_t IMCR; /*!< Offset: 0xF00 (R/W) ITM Integration Mode Control Register */ - uint32_t RESERVED4[43]; + uint32_t RESERVED4[43]; __O uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ __I uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ - uint32_t RESERVED5[6]; + uint32_t RESERVED5[6]; __I uint32_t PID4; /*!< Offset: 0xFD0 (R/ ) ITM Peripheral Identification Register #4 */ __I uint32_t PID5; /*!< Offset: 0xFD4 (R/ ) ITM Peripheral Identification Register #5 */ __I uint32_t PID6; /*!< Offset: 0xFD8 (R/ ) ITM Peripheral Identification Register #6 */ @@ -1516,9 +1531,9 @@ __STATIC_INLINE void NVIC_SystemReset(void) */ __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) { - if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ + if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ - SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */ + SysTick->LOAD = ticks - 1; /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Systick Interrupt */ SysTick->VAL = 0; /* Load the SysTick Counter Value */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | diff --git a/components/CMSIS/Include/core_cm4.h b/components/CMSIS/Include/core_cm4.h index a965537402..d65016c714 100644 --- a/components/CMSIS/Include/core_cm4.h +++ b/components/CMSIS/Include/core_cm4.h @@ -1,25 +1,40 @@ /**************************************************************************//** * @file core_cm4.h * @brief CMSIS Cortex-M4 Core Peripheral Access Layer Header File - * @version V3.01 - * @date 22. March 2012 + * @version V3.20 + * @date 25. February 2013 * * @note - * Copyright (C) 2009-2012 ARM Limited. All rights reserved. - * - * @par - * ARM Limited (ARM) is supplying this software for use with Cortex-M - * processor based microcontrollers. This file can be freely distributed - * within development tools that are supporting such ARM based processors. - * - * @par - * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED - * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. - * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * ******************************************************************************/ +/* Copyright (c) 2009 - 2013 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of ARM nor the names of its contributors may be used + to endorse or promote products derived from this software without + specific prior written permission. + * + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------------------------------*/ + + #if defined ( __ICCARM__ ) #pragma system_include /* treat file as system include file for MISRA check */ #endif @@ -54,7 +69,7 @@ /* CMSIS CM4 definitions */ #define __CM4_CMSIS_VERSION_MAIN (0x03) /*!< [31:16] CMSIS HAL main version */ -#define __CM4_CMSIS_VERSION_SUB (0x01) /*!< [15:0] CMSIS HAL sub version */ +#define __CM4_CMSIS_VERSION_SUB (0x20) /*!< [15:0] CMSIS HAL sub version */ #define __CM4_CMSIS_VERSION ((__CM4_CMSIS_VERSION_MAIN << 16) | \ __CM4_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ @@ -669,14 +684,14 @@ typedef struct __IO uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ uint32_t RESERVED2[15]; __IO uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ - uint32_t RESERVED3[29]; + uint32_t RESERVED3[29]; __O uint32_t IWR; /*!< Offset: 0xEF8 ( /W) ITM Integration Write Register */ __I uint32_t IRR; /*!< Offset: 0xEFC (R/ ) ITM Integration Read Register */ __IO uint32_t IMCR; /*!< Offset: 0xF00 (R/W) ITM Integration Mode Control Register */ - uint32_t RESERVED4[43]; + uint32_t RESERVED4[43]; __O uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ __I uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ - uint32_t RESERVED5[6]; + uint32_t RESERVED5[6]; __I uint32_t PID4; /*!< Offset: 0xFD0 (R/ ) ITM Peripheral Identification Register #4 */ __I uint32_t PID5; /*!< Offset: 0xFD4 (R/ ) ITM Peripheral Identification Register #5 */ __I uint32_t PID6; /*!< Offset: 0xFD8 (R/ ) ITM Peripheral Identification Register #6 */ @@ -1661,9 +1676,9 @@ __STATIC_INLINE void NVIC_SystemReset(void) */ __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) { - if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ + if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ - SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */ + SysTick->LOAD = ticks - 1; /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Systick Interrupt */ SysTick->VAL = 0; /* Load the SysTick Counter Value */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | diff --git a/components/CMSIS/Include/core_cm4_simd.h b/components/CMSIS/Include/core_cm4_simd.h index 3bc7906152..83db95b5f1 100644 --- a/components/CMSIS/Include/core_cm4_simd.h +++ b/components/CMSIS/Include/core_cm4_simd.h @@ -1,25 +1,39 @@ /**************************************************************************//** * @file core_cm4_simd.h * @brief CMSIS Cortex-M4 SIMD Header File - * @version V3.01 - * @date 06. March 2012 + * @version V3.20 + * @date 25. February 2013 * * @note - * Copyright (C) 2010-2012 ARM Limited. All rights reserved. - * - * @par - * ARM Limited (ARM) is supplying this software for use with Cortex-M - * processor based microcontrollers. This file can be freely distributed - * within development tools that are supporting such ARM based processors. - * - * @par - * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED - * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. - * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * ******************************************************************************/ +/* Copyright (c) 2009 - 2013 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of ARM nor the names of its contributors may be used + to endorse or promote products derived from this software without + specific prior written permission. + * + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------------------------------*/ + #ifdef __cplusplus extern "C" { @@ -110,6 +124,8 @@ #define __PKHTB(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0xFFFF0000UL) | \ ((((uint32_t)(ARG2)) >> (ARG3)) & 0x0000FFFFUL) ) +#define __SMMLA(ARG1,ARG2,ARG3) ( (int32_t)((((int64_t)(ARG1) * (ARG2)) + \ + ((int64_t)(ARG3) << 32) ) >> 32)) /*-- End CM4 SIMD Intrinsics -----------------------------------------------------*/ @@ -624,6 +640,14 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QSUB(uint32_t op1, __RES; \ }) +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) +{ + int32_t result; + + __ASM volatile ("smmla %0, %1, %2, %3" : "=r" (result): "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + /*-- End CM4 SIMD Intrinsics -----------------------------------------------------*/ diff --git a/components/CMSIS/Include/core_cmFunc.h b/components/CMSIS/Include/core_cmFunc.h index 3c932e0d6e..0a18fafc30 100644 --- a/components/CMSIS/Include/core_cmFunc.h +++ b/components/CMSIS/Include/core_cmFunc.h @@ -1,25 +1,39 @@ /**************************************************************************//** * @file core_cmFunc.h * @brief CMSIS Cortex-M Core Function Access Header File - * @version V3.01 - * @date 06. March 2012 + * @version V3.20 + * @date 25. February 2013 * * @note - * Copyright (C) 2009-2012 ARM Limited. All rights reserved. - * - * @par - * ARM Limited (ARM) is supplying this software for use with Cortex-M - * processor based microcontrollers. This file can be freely distributed - * within development tools that are supporting such ARM based processors. - * - * @par - * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED - * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. - * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * ******************************************************************************/ +/* Copyright (c) 2009 - 2013 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of ARM nor the names of its contributors may be used + to endorse or promote products derived from this software without + specific prior written permission. + * + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------------------------------*/ + #ifndef __CORE_CMFUNC_H #define __CORE_CMFUNC_H @@ -314,7 +328,7 @@ __STATIC_INLINE void __set_FPSCR(uint32_t fpscr) */ __attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_irq(void) { - __ASM volatile ("cpsie i"); + __ASM volatile ("cpsie i" : : : "memory"); } @@ -325,7 +339,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_irq(void) */ __attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_irq(void) { - __ASM volatile ("cpsid i"); + __ASM volatile ("cpsid i" : : : "memory"); } @@ -352,7 +366,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_CONTROL(void) */ __attribute__( ( always_inline ) ) __STATIC_INLINE void __set_CONTROL(uint32_t control) { - __ASM volatile ("MSR control, %0" : : "r" (control) ); + __ASM volatile ("MSR control, %0" : : "r" (control) : "memory"); } @@ -424,7 +438,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PSP(void) */ __attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PSP(uint32_t topOfProcStack) { - __ASM volatile ("MSR psp, %0\n" : : "r" (topOfProcStack) ); + __ASM volatile ("MSR psp, %0\n" : : "r" (topOfProcStack) : "sp"); } @@ -451,7 +465,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_MSP(void) */ __attribute__( ( always_inline ) ) __STATIC_INLINE void __set_MSP(uint32_t topOfMainStack) { - __ASM volatile ("MSR msp, %0\n" : : "r" (topOfMainStack) ); + __ASM volatile ("MSR msp, %0\n" : : "r" (topOfMainStack) : "sp"); } @@ -478,7 +492,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PRIMASK(void) */ __attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PRIMASK(uint32_t priMask) { - __ASM volatile ("MSR primask, %0" : : "r" (priMask) ); + __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); } @@ -491,7 +505,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PRIMASK(uint32_t p */ __attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_fault_irq(void) { - __ASM volatile ("cpsie f"); + __ASM volatile ("cpsie f" : : : "memory"); } @@ -502,7 +516,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_fault_irq(void) */ __attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_fault_irq(void) { - __ASM volatile ("cpsid f"); + __ASM volatile ("cpsid f" : : : "memory"); } @@ -529,7 +543,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_BASEPRI(void) */ __attribute__( ( always_inline ) ) __STATIC_INLINE void __set_BASEPRI(uint32_t value) { - __ASM volatile ("MSR basepri, %0" : : "r" (value) ); + __ASM volatile ("MSR basepri, %0" : : "r" (value) : "memory"); } @@ -556,7 +570,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FAULTMASK(void */ __attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask) { - __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) ); + __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory"); } #endif /* (__CORTEX_M >= 0x03) */ @@ -575,7 +589,10 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FPSCR(void) #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) uint32_t result; + /* Empty asm statement works as a scheduling barrier */ + __ASM volatile (""); __ASM volatile ("VMRS %0, fpscr" : "=r" (result) ); + __ASM volatile (""); return(result); #else return(0); @@ -592,7 +609,10 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FPSCR(void) __attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FPSCR(uint32_t fpscr) { #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) - __ASM volatile ("VMSR fpscr, %0" : : "r" (fpscr) ); + /* Empty asm statement works as a scheduling barrier */ + __ASM volatile (""); + __ASM volatile ("VMSR fpscr, %0" : : "r" (fpscr) : "vfpcc"); + __ASM volatile (""); #endif } diff --git a/components/CMSIS/Include/core_cmInstr.h b/components/CMSIS/Include/core_cmInstr.h index 597e64df04..d213f0eed7 100644 --- a/components/CMSIS/Include/core_cmInstr.h +++ b/components/CMSIS/Include/core_cmInstr.h @@ -1,25 +1,39 @@ /**************************************************************************//** * @file core_cmInstr.h * @brief CMSIS Cortex-M Core Instruction Access Header File - * @version V3.01 - * @date 06. March 2012 + * @version V3.20 + * @date 05. March 2013 * * @note - * Copyright (C) 2009-2012 ARM Limited. All rights reserved. - * - * @par - * ARM Limited (ARM) is supplying this software for use with Cortex-M - * processor based microcontrollers. This file can be freely distributed - * within development tools that are supporting such ARM based processors. - * - * @par - * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED - * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. - * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * ******************************************************************************/ +/* Copyright (c) 2009 - 2013 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of ARM nor the names of its contributors may be used + to endorse or promote products derived from this software without + specific prior written permission. + * + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------------------------------*/ + #ifndef __CORE_CMINSTR_H #define __CORE_CMINSTR_H @@ -111,12 +125,13 @@ \param [in] value Value to reverse \return Reversed value */ +#ifndef __NO_EMBEDDED_ASM __attribute__((section(".rev16_text"))) __STATIC_INLINE __ASM uint32_t __REV16(uint32_t value) { rev16 r0, r0 bx lr } - +#endif /** \brief Reverse byte order in signed short value @@ -125,11 +140,13 @@ __attribute__((section(".rev16_text"))) __STATIC_INLINE __ASM uint32_t __REV16(u \param [in] value Value to reverse \return Reversed value */ +#ifndef __NO_EMBEDDED_ASM __attribute__((section(".revsh_text"))) __STATIC_INLINE __ASM int32_t __REVSH(int32_t value) { revsh r0, r0 bx lr } +#endif /** \brief Rotate Right in unsigned value (32 bit) @@ -143,6 +160,17 @@ __attribute__((section(".revsh_text"))) __STATIC_INLINE __ASM int32_t __REVSH(in #define __ROR __ror +/** \brief Breakpoint + + This function causes the processor to enter Debug state. + Debug tools can use this to investigate system state when the instruction at a particular address is reached. + + \param [in] value is ignored by the processor. + If required, a debugger can use it to store additional information about the breakpoint. + */ +#define __BKPT(value) __breakpoint(value) + + #if (__CORTEX_M >= 0x03) /** \brief Reverse bit order of value @@ -279,6 +307,17 @@ __attribute__((section(".revsh_text"))) __STATIC_INLINE __ASM int32_t __REVSH(in #elif defined ( __GNUC__ ) /*------------------ GNU Compiler ---------------------*/ /* GNU gcc specific functions */ +/* Define macros for porting to both thumb1 and thumb2. + * For thumb1, use low register (r0-r7), specified by constrant "l" + * Otherwise, use general registers, specified by constrant "r" */ +#if defined (__thumb__) && !defined (__thumb2__) +#define __CMSIS_GCC_OUT_REG(r) "=l" (r) +#define __CMSIS_GCC_USE_REG(r) "l" (r) +#else +#define __CMSIS_GCC_OUT_REG(r) "=r" (r) +#define __CMSIS_GCC_USE_REG(r) "r" (r) +#endif + /** \brief No Operation No Operation does nothing. This instruction can be used for code alignment purposes. @@ -364,10 +403,14 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE void __DMB(void) */ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __REV(uint32_t value) { +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) + return __builtin_bswap32(value); +#else uint32_t result; - __ASM volatile ("rev %0, %1" : "=r" (result) : "r" (value) ); + __ASM volatile ("rev %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); return(result); +#endif } @@ -382,7 +425,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __REV16(uint32_t val { uint32_t result; - __ASM volatile ("rev16 %0, %1" : "=r" (result) : "r" (value) ); + __ASM volatile ("rev16 %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); return(result); } @@ -396,10 +439,14 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __REV16(uint32_t val */ __attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __REVSH(int32_t value) { +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + return (short)__builtin_bswap16(value); +#else uint32_t result; - __ASM volatile ("revsh %0, %1" : "=r" (result) : "r" (value) ); + __ASM volatile ("revsh %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); return(result); +#endif } @@ -413,12 +460,21 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __REVSH(int32_t value */ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __ROR(uint32_t op1, uint32_t op2) { - - __ASM volatile ("ror %0, %0, %1" : "+r" (op1) : "r" (op2) ); - return(op1); + return (op1 >> op2) | (op1 << (32 - op2)); } +/** \brief Breakpoint + + This function causes the processor to enter Debug state. + Debug tools can use this to investigate system state when the instruction at a particular address is reached. + + \param [in] value is ignored by the processor. + If required, a debugger can use it to store additional information about the breakpoint. + */ +#define __BKPT(value) __ASM volatile ("bkpt "#value) + + #if (__CORTEX_M >= 0x03) /** \brief Reverse bit order of value @@ -446,9 +502,16 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __RBIT(uint32_t valu */ __attribute__( ( always_inline ) ) __STATIC_INLINE uint8_t __LDREXB(volatile uint8_t *addr) { - uint8_t result; + uint32_t result; - __ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) ); +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrexb %0, %1" : "=r" (result) : "Q" (*addr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); +#endif return(result); } @@ -462,9 +525,16 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint8_t __LDREXB(volatile uin */ __attribute__( ( always_inline ) ) __STATIC_INLINE uint16_t __LDREXH(volatile uint16_t *addr) { - uint16_t result; + uint32_t result; - __ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) ); +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrexh %0, %1" : "=r" (result) : "Q" (*addr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); +#endif return(result); } @@ -480,7 +550,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __LDREXW(volatile ui { uint32_t result; - __ASM volatile ("ldrex %0, [%1]" : "=r" (result) : "r" (addr) ); + __ASM volatile ("ldrex %0, %1" : "=r" (result) : "Q" (*addr) ); return(result); } @@ -498,7 +568,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __STREXB(uint8_t val { uint32_t result; - __ASM volatile ("strexb %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) ); + __ASM volatile ("strexb %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) ); return(result); } @@ -516,7 +586,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __STREXH(uint16_t va { uint32_t result; - __ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) ); + __ASM volatile ("strexh %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) ); return(result); } @@ -534,7 +604,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __STREXW(uint32_t va { uint32_t result; - __ASM volatile ("strex %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) ); + __ASM volatile ("strex %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) ); return(result); } @@ -546,7 +616,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __STREXW(uint32_t va */ __attribute__( ( always_inline ) ) __STATIC_INLINE void __CLREX(void) { - __ASM volatile ("clrex"); + __ASM volatile ("clrex" ::: "memory"); } @@ -591,7 +661,7 @@ __attribute__( ( always_inline ) ) __STATIC_INLINE void __CLREX(void) */ __attribute__( ( always_inline ) ) __STATIC_INLINE uint8_t __CLZ(uint32_t value) { - uint8_t result; + uint32_t result; __ASM volatile ("clz %0, %1" : "=r" (result) : "r" (value) ); return(result); diff --git a/components/CMSIS/Include/core_sc000.h b/components/CMSIS/Include/core_sc000.h index 39ee60c5e5..1a2a0f2e30 100644 --- a/components/CMSIS/Include/core_sc000.h +++ b/components/CMSIS/Include/core_sc000.h @@ -1,25 +1,40 @@ /**************************************************************************//** * @file core_sc000.h * @brief CMSIS SC000 Core Peripheral Access Layer Header File - * @version V3.01 - * @date 22. March 2012 + * @version V3.20 + * @date 25. February 2013 * * @note - * Copyright (C) 2009-2012 ARM Limited. All rights reserved. - * - * @par - * ARM Limited (ARM) is supplying this software for use with Cortex-M - * processor based microcontrollers. This file can be freely distributed - * within development tools that are supporting such ARM based processors. - * - * @par - * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED - * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. - * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * ******************************************************************************/ +/* Copyright (c) 2009 - 2013 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of ARM nor the names of its contributors may be used + to endorse or promote products derived from this software without + specific prior written permission. + * + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------------------------------*/ + + #if defined ( __ICCARM__ ) #pragma system_include /* treat file as system include file for MISRA check */ #endif @@ -54,7 +69,7 @@ /* CMSIS SC000 definitions */ #define __SC000_CMSIS_VERSION_MAIN (0x03) /*!< [31:16] CMSIS HAL main version */ -#define __SC000_CMSIS_VERSION_SUB (0x01) /*!< [15:0] CMSIS HAL sub version */ +#define __SC000_CMSIS_VERSION_SUB (0x20) /*!< [15:0] CMSIS HAL sub version */ #define __SC000_CMSIS_VERSION ((__SC000_CMSIS_VERSION_MAIN << 16) | \ __SC000_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ @@ -721,9 +736,9 @@ __STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) { if(IRQn < 0) { - return((uint32_t)((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) >> (8 - __NVIC_PRIO_BITS))); } /* get priority for SC000 system interrupts */ + return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & 0xFF) >> (8 - __NVIC_PRIO_BITS))); } /* get priority for Cortex-M0 system interrupts */ else { - return((uint32_t)((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) >> (8 - __NVIC_PRIO_BITS))); } /* get priority for device specific interrupts */ + return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & 0xFF) >> (8 - __NVIC_PRIO_BITS))); } /* get priority for device specific interrupts */ } @@ -771,9 +786,9 @@ __STATIC_INLINE void NVIC_SystemReset(void) */ __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) { - if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ + if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ - SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */ + SysTick->LOAD = ticks - 1; /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Systick Interrupt */ SysTick->VAL = 0; /* Load the SysTick Counter Value */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | diff --git a/components/CMSIS/Include/core_sc300.h b/components/CMSIS/Include/core_sc300.h index 7e56b0f332..cc34d6fc0e 100644 --- a/components/CMSIS/Include/core_sc300.h +++ b/components/CMSIS/Include/core_sc300.h @@ -1,25 +1,40 @@ /**************************************************************************//** * @file core_sc300.h * @brief CMSIS SC300 Core Peripheral Access Layer Header File - * @version V3.01 - * @date 22. March 2012 + * @version V3.20 + * @date 25. February 2013 * * @note - * Copyright (C) 2009-2012 ARM Limited. All rights reserved. - * - * @par - * ARM Limited (ARM) is supplying this software for use with Cortex-M - * processor based microcontrollers. This file can be freely distributed - * within development tools that are supporting such ARM based processors. - * - * @par - * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED - * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. - * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. * ******************************************************************************/ +/* Copyright (c) 2009 - 2013 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + - Neither the name of ARM nor the names of its contributors may be used + to endorse or promote products derived from this software without + specific prior written permission. + * + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + ---------------------------------------------------------------------------*/ + + #if defined ( __ICCARM__ ) #pragma system_include /* treat file as system include file for MISRA check */ #endif @@ -54,7 +69,7 @@ /* CMSIS SC300 definitions */ #define __SC300_CMSIS_VERSION_MAIN (0x03) /*!< [31:16] CMSIS HAL main version */ -#define __SC300_CMSIS_VERSION_SUB (0x01) /*!< [15:0] CMSIS HAL sub version */ +#define __SC300_CMSIS_VERSION_SUB (0x20) /*!< [15:0] CMSIS HAL sub version */ #define __SC300_CMSIS_VERSION ((__SC300_CMSIS_VERSION_MAIN << 16) | \ __SC300_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ @@ -607,14 +622,14 @@ typedef struct __IO uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ uint32_t RESERVED2[15]; __IO uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ - uint32_t RESERVED3[29]; + uint32_t RESERVED3[29]; __O uint32_t IWR; /*!< Offset: 0xEF8 ( /W) ITM Integration Write Register */ __I uint32_t IRR; /*!< Offset: 0xEFC (R/ ) ITM Integration Read Register */ __IO uint32_t IMCR; /*!< Offset: 0xF00 (R/W) ITM Integration Mode Control Register */ - uint32_t RESERVED4[43]; + uint32_t RESERVED4[43]; __O uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ __I uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ - uint32_t RESERVED5[6]; + uint32_t RESERVED5[6]; __I uint32_t PID4; /*!< Offset: 0xFD0 (R/ ) ITM Peripheral Identification Register #4 */ __I uint32_t PID5; /*!< Offset: 0xFD4 (R/ ) ITM Peripheral Identification Register #5 */ __I uint32_t PID6; /*!< Offset: 0xFD8 (R/ ) ITM Peripheral Identification Register #6 */ @@ -1487,9 +1502,9 @@ __STATIC_INLINE void NVIC_SystemReset(void) */ __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) { - if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ + if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ - SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */ + SysTick->LOAD = ticks - 1; /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Systick Interrupt */ SysTick->VAL = 0; /* Load the SysTick Counter Value */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | From e601c2a6ed1968517acf080b7d6cdc57b5a14070 Mon Sep 17 00:00:00 2001 From: bernard Date: Sun, 26 Jan 2014 20:30:37 +0800 Subject: [PATCH 16/59] Add sector size check when mounting a FAT file system. --- components/dfs/filesystems/elmfat/dfs_elm.c | 16 +++++++++++++--- include/rtdef.h | 3 +++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/components/dfs/filesystems/elmfat/dfs_elm.c b/components/dfs/filesystems/elmfat/dfs_elm.c index 0d7f9b781c..4495bd9b3e 100644 --- a/components/dfs/filesystems/elmfat/dfs_elm.c +++ b/components/dfs/filesystems/elmfat/dfs_elm.c @@ -110,20 +110,30 @@ int dfs_elm_mount(struct dfs_filesystem *fs, unsigned long rwflag, const void *d FATFS *fat; FRESULT result; int index; + struct rt_device_blk_geometry geometry; /* get an empty position */ index = get_disk(RT_NULL); if (index == -1) - return -DFS_STATUS_ENOSPC; + return -DFS_STATUS_ENOENT; /* save device */ disk[index] = fs->dev_id; - + /* check sector size */ + if (rt_device_control(fs->dev_id, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry) == RT_EOK) + { + if (geometry.block_size > _MAX_SS) + { + rt_kprintf("Block size of device is great than sector size of FAT.\n"); + return -DFS_STATUS_EINVAL; + } + } + fat = (FATFS *)rt_malloc(sizeof(FATFS)); if (fat == RT_NULL) { disk[index] = RT_NULL; - return -1; + return -DFS_STATUS_ENOMEM; } /* mount fatfs, always 0 logic driver */ diff --git a/include/rtdef.h b/include/rtdef.h index 7cd35c7f8c..e24c2fa85b 100644 --- a/include/rtdef.h +++ b/include/rtdef.h @@ -34,6 +34,9 @@ #ifndef __RT_DEF_H__ #define __RT_DEF_H__ +/* include rtconfig header to import configuration */ +#include + #ifdef __cplusplus extern "C" { #endif From 5a6ec7dcae9c92e06f6c6e129c2f9340cef93f09 Mon Sep 17 00:00:00 2001 From: bernard Date: Sun, 26 Jan 2014 22:43:12 +0800 Subject: [PATCH 17/59] [DFS] fix the wrong field comparison in FAT mount. --- components/dfs/filesystems/elmfat/dfs_elm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/dfs/filesystems/elmfat/dfs_elm.c b/components/dfs/filesystems/elmfat/dfs_elm.c index 4495bd9b3e..3658a5dc80 100644 --- a/components/dfs/filesystems/elmfat/dfs_elm.c +++ b/components/dfs/filesystems/elmfat/dfs_elm.c @@ -25,6 +25,7 @@ * 2012-07-26 aozima implement ff_memalloc and ff_memfree. * 2012-12-19 Bernard fixed the O_APPEND and lseek issue. * 2013-03-01 aozima fixed the stat(st_mtime) issue. + * 2014-01-26 Bernard Check the sector size before mount. */ #include @@ -122,9 +123,9 @@ int dfs_elm_mount(struct dfs_filesystem *fs, unsigned long rwflag, const void *d /* check sector size */ if (rt_device_control(fs->dev_id, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry) == RT_EOK) { - if (geometry.block_size > _MAX_SS) + if (geometry.bytes_per_sector > _MAX_SS) { - rt_kprintf("Block size of device is great than sector size of FAT.\n"); + rt_kprintf("The sector size of device is greater than the sector size of FAT.\n"); return -DFS_STATUS_EINVAL; } } From 201d11bb2ff715e10e99508a54c187ee76ca6363 Mon Sep 17 00:00:00 2001 From: bernard Date: Sat, 1 Feb 2014 21:35:23 +0800 Subject: [PATCH 18/59] [DFS] Fix file size issue This issue causes fstat & lseek not correct. --- components/dfs/filesystems/nfs/dfs_nfs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/dfs/filesystems/nfs/dfs_nfs.c b/components/dfs/filesystems/nfs/dfs_nfs.c index 43d2845aa0..5f03314309 100644 --- a/components/dfs/filesystems/nfs/dfs_nfs.c +++ b/components/dfs/filesystems/nfs/dfs_nfs.c @@ -678,7 +678,9 @@ int nfs_write(struct dfs_fd *file, const void *buf, rt_size_t count) total += bytes; /* update current position */ file->pos = fd->offset; - /* todo: update file size */ + /* update file size */ + if (fd->size < fd->offset) fd->size = fd->offset; + file->size = fd->size; } xdr_free((xdrproc_t)xdr_WRITE3res, (char *)&res); } while (count > 0); @@ -796,6 +798,7 @@ int nfs_open(struct dfs_fd *file) /* set private file */ file->data = fp; + file->size = fp->size; } return 0; From 8778e39c9f8f3d6cc4c6a7bf1230e924ea10b8b2 Mon Sep 17 00:00:00 2001 From: bernard Date: Sat, 1 Feb 2014 21:35:46 +0800 Subject: [PATCH 19/59] [Finsh] Add ifconfig command implementation. --- components/finsh/msh_cmd.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/components/finsh/msh_cmd.c b/components/finsh/msh_cmd.c index a5a5b79f15..c11873dc91 100644 --- a/components/finsh/msh_cmd.c +++ b/components/finsh/msh_cmd.c @@ -179,6 +179,18 @@ FINSH_FUNCTION_EXPORT_ALIAS(cmd_mkdir, __cmd_mkdir, Create the DIRECTORY.); #endif +#ifdef RT_USING_LWIP +int cmd_ifconfig(int argc, char** argv) +{ + extern void list_if(void); + + list_if(); + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(cmd_ifconfig, __cmd_ifconfig, list the information of network interfaces); + +#endif + int cmd_ps(int argc, char** argv) { extern long list_thread(void); From be2ff57198d12f0b88276f3e930de3441c26b806 Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Thu, 6 Feb 2014 15:49:47 +0800 Subject: [PATCH 20/59] Add directory and SConscript for Espruino. --- components/external/espruino/SConscript | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 components/external/espruino/SConscript diff --git a/components/external/espruino/SConscript b/components/external/espruino/SConscript new file mode 100644 index 0000000000..3d5c775064 --- /dev/null +++ b/components/external/espruino/SConscript @@ -0,0 +1,19 @@ +from building import * +import os + +cwd = GetCurrentDir() +# source files +src = Split(''' +''') + +ESPRUINO_SRC_PATH = cwd + '/src' +if GetDepend('RT_USING_JS') and not os.path.exists(ESPRUINO_SRC_PATH): + print '================ERROR============================' + print 'Please get espruino source files and put them under espruino folder' + print '=================================================' + exit(0) + +CPPPATH = [cwd + '/src', cwd + '/gen', cwd + '/libs', cwd + '/targets/rtthread'] +group = DefineGroup('Espruino', src, depend = ['RT_USING_JS'], CPPPATH = CPPPATH) + +Return('group') From 07f837578320577dc63395f4db3a476aa8954d69 Mon Sep 17 00:00:00 2001 From: bernard Date: Fri, 7 Feb 2014 23:23:44 +0800 Subject: [PATCH 21/59] Add more feature on buildlib --- tools/building.py | 57 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/tools/building.py b/tools/building.py index acc3a8a213..a063ddb91d 100644 --- a/tools/building.py +++ b/tools/building.py @@ -54,6 +54,12 @@ def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = [ env['ARCOM'] = '$AR --create $TARGET $SOURCES' env['LIBPREFIX'] = '' env['LIBSUFFIX'] = '_rvds.lib' + env['LIBLINKPREFIX'] = '' + env['LIBLINKSUFFIX'] = '_rvds.lib' + env['LIBDIRPREFIX'] = '--userlibpath ' + elif rtconfig.PLATFORM == 'gcc': + env['LIBSUFFIX'] = '_gcc.a' + env['LIBLINKSUFFIX'] = '_gcc' # patch for win32 spawn if env['PLATFORM'] == 'win32' and rtconfig.PLATFORM == 'gcc': @@ -69,6 +75,11 @@ def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = [ # add program path env.PrependENVPath('PATH', rtconfig.EXEC_PATH) + # add library build action + act = SCons.Action.Action(BuildLibInstallAction, 'Install compiled library... $TARGET') + bld = Builder(action = act) + Env.Append(BUILDERS = {'BuildLib': bld}) + # parse rtconfig.h to get used component PreProcessor = SCons.cpp.PreProcessor() f = file('rtconfig.h', 'r') @@ -127,12 +138,17 @@ def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = [ dest='buildlib', type='string', help='building library of a component') + AddOption('--cleanlib', + dest='cleanlib', + action='store_true', + default=False, + help='clean up the library by --buildlib') # add target option AddOption('--target', dest='target', type='string', - help='set target project: mdk') + help='set target project: mdk/iar/vs') #{target_name:(CROSS_TOOL, PLATFORM)} tgt_dict = {'mdk':('keil', 'armcc'), @@ -279,7 +295,7 @@ def DefineGroup(name, src, depend, **parameters): group = parameters group['name'] = name group['path'] = GetCurrentDir() - if type(src) == type(['src1', 'str2']): + if type(src) == type(['src1']): group['src'] = File(src) else: group['src'] = src @@ -292,13 +308,25 @@ def DefineGroup(name, src, depend, **parameters): Env.Append(CPPDEFINES = group['CPPDEFINES']) if group.has_key('LINKFLAGS'): Env.Append(LINKFLAGS = group['LINKFLAGS']) + + # check whether to clean up library + if GetOption('cleanlib') and os.path.exists(os.path.join(group['path'], GroupLibName(name, Env))): + if group['src'] != []: + print 'Remove library:', GroupLibName(name, Env) + do_rm_file(os.path.join(group['path'], GroupLibName(name, Env))) + + # check whether exist group library + if not GetOption('buildlib') and os.path.exists(os.path.join(group['path'], GroupLibName(name, Env))): + Env.Append(LIBS = [name]) + group['src'] = [] + Env.Append(LIBPATH = [GetCurrentDir()]) + if group.has_key('LIBS'): Env.Append(LIBS = group['LIBS']) if group.has_key('LIBPATH'): Env.Append(LIBPATH = group['LIBPATH']) objs = Env.Object(group['src']) - if group.has_key('LIBRARY'): objs = Env.Library(name, objs) @@ -332,6 +360,20 @@ def PreBuilding(): for a in PREBUILDING: a() +def GroupLibName(name, env): + return env['LIBPREFIX'] + name + env['LIBSUFFIX'] + +def BuildLibInstallAction(target, source, env): + lib_name = GetOption('buildlib') + for Group in Projects: + if Group['name'] == lib_name: + lib_name = str(target[0]) + lib_name = GroupLibName(lib_name, env) + dst_name = os.path.join(Group['path'], lib_name) + print 'Copy %s => %s' % (lib_name, dst_name) + do_copy_file(lib_name, dst_name) + break + def DoBuilding(target, objects): program = None # check whether special buildlib option @@ -342,13 +384,16 @@ def DoBuilding(target, objects): if Group['name'] == lib_name: objects = Env.Object(Group['src']) program = Env.Library(lib_name, objects) + + # add library copy action + Env.BuildLib(lib_name, program) + break else: program = Env.Program(target, objects) EndBuilding(target, program) - def EndBuilding(target, program = None): import rtconfig from keil import MDKProject @@ -449,6 +494,10 @@ def GlobSubDir(sub_dir, ext_name): dst.append(os.path.relpath(item, sub_dir)) return dst +def do_rm_file(src): + if os.path.exists(src): + os.unlink(src) + def do_copy_file(src, dst): import shutil # check source file From a6fa98f1ee806cac963352b1ddb88a560e1d6f9c Mon Sep 17 00:00:00 2001 From: prife Date: Sun, 9 Feb 2014 11:24:36 +0800 Subject: [PATCH 22/59] simulator: fix exit issue when close RTGUI window --- bsp/simulator/drivers/sdl_fb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bsp/simulator/drivers/sdl_fb.c b/bsp/simulator/drivers/sdl_fb.c index 78bca6f07f..84076b757f 100755 --- a/bsp/simulator/drivers/sdl_fb.c +++ b/bsp/simulator/drivers/sdl_fb.c @@ -11,6 +11,8 @@ #define SDL_SCREEN_WIDTH 800 #define SDL_SCREEN_HEIGHT 480 +extern void rt_hw_exit(void); + struct sdlfb_device { struct rt_device parent; @@ -307,7 +309,7 @@ static void *sdl_loop(void *lpParam) if (quit) break; } - //exit(0); + rt_hw_exit(); return 0; } From f015f36d050c099a319c5a7b435827b3774d7b9c Mon Sep 17 00:00:00 2001 From: prife Date: Sun, 9 Feb 2014 15:03:02 +0800 Subject: [PATCH 23/59] dfs: support copy directory --- components/dfs/src/dfs_file.c | 168 +++++++++++++++++++++++++++++++++- 1 file changed, 166 insertions(+), 2 deletions(-) diff --git a/components/dfs/src/dfs_file.c b/components/dfs/src/dfs_file.c index 3ec9b5b5b0..32198371d7 100644 --- a/components/dfs/src/dfs_file.c +++ b/components/dfs/src/dfs_file.c @@ -593,7 +593,7 @@ void cat(const char* filename) FINSH_FUNCTION_EXPORT(cat, print file) #define BUF_SZ 4096 -void copy(const char *src, const char *dst) +static void copyfile(const char *src, const char *dst) { struct dfs_fd src_fd; rt_uint8_t *block_ptr; @@ -637,7 +637,171 @@ void copy(const char *src, const char *dst) dfs_file_close(&fd); rt_free(block_ptr); } -FINSH_FUNCTION_EXPORT(copy, copy source file to destination file) + +extern int mkdir(const char *path, mode_t mode); +static void copydir(const char * src, const char * dst) +{ + struct dfs_fd fd; + struct dirent dirent; + struct stat stat; + int length; + + if (dfs_file_open(&fd, src, DFS_O_DIRECTORY) < 0) + { + rt_kprintf("open %s failed\n", src); + return ; + } + + do + { + rt_memset(&dirent, 0, sizeof(struct dirent)); + length = dfs_file_getdents(&fd, &dirent, sizeof(struct dirent)); + if (length > 0) + { + char * src_entry_full = RT_NULL; + char * dst_entry_full = RT_NULL; + + if (strcmp(dirent.d_name, "..") == 0 || strcmp(dirent.d_name, ".") == 0) + continue; + + /* build full path for each file */ + if ((src_entry_full = dfs_normalize_path(src, dirent.d_name)) == RT_NULL) + { + rt_kprintf("out of memory!\n"); + break; + } + if ((dst_entry_full = dfs_normalize_path(dst, dirent.d_name)) == RT_NULL) + { + rt_kprintf("out of memory!\n"); + rt_free(src_entry_full); + break; + } + + rt_memset(&stat, 0, sizeof(struct stat)); + if (dfs_file_stat(src_entry_full, &stat) != 0) + { + rt_kprintf("open file: %s failed\n", dirent.d_name); + continue; + } + + if (DFS_S_ISDIR(stat.st_mode)) + { + mkdir(dst_entry_full, 0); + copydir(src_entry_full, dst_entry_full); + } + else + { + copyfile(src_entry_full, dst_entry_full); + } + rt_free(src_entry_full); + rt_free(dst_entry_full); + } + }while(length > 0); + + dfs_file_close(&fd); +} + +static const char *_get_path_lastname(const char *path) +{ + char * ptr; + if ((ptr = strrchr(path, '/')) == RT_NULL) + return path; + + /* skip the '/' then return */ + return ++ptr; +} +void copy(const char *src, const char *dst) +{ +#define FLAG_SRC_TYPE 0x03 +#define FLAG_SRC_IS_DIR 0x01 +#define FLAG_SRC_IS_FILE 0x02 +#define FLAG_SRC_NON_EXSIT 0x00 + +#define FLAG_DST_TYPE 0x0C +#define FLAG_DST_IS_DIR 0x04 +#define FLAG_DST_IS_FILE 0x08 +#define FLAG_DST_NON_EXSIT 0x00 + + struct stat stat; + rt_uint32_t flag = 0; + + /* check the staus of src and dst */ + if (dfs_file_stat(src, &stat) < 0) + { + rt_kprintf("copy failed, bad %s\n", src); + return; + } + if (DFS_S_ISDIR(stat.st_mode)) + flag |= FLAG_SRC_IS_DIR; + else + flag |= FLAG_SRC_IS_FILE; + + if (dfs_file_stat(dst, &stat) < 0) + { + flag |= FLAG_DST_NON_EXSIT; + } + else + { + if (DFS_S_ISDIR(stat.st_mode)) + flag |= FLAG_DST_IS_DIR; + else + flag |= FLAG_DST_IS_FILE; + } + + //2. check status + if ((flag & FLAG_SRC_IS_DIR) && (flag & FLAG_DST_IS_FILE)) + { + rt_kprintf("cp faild, cp dir to file is not permitted!\n"); + return ; + } + + //3. do copy + if (flag & FLAG_SRC_IS_FILE) + { + if (flag & FLAG_DST_IS_DIR) + { + char * fdst; + fdst = dfs_normalize_path(dst, _get_path_lastname(src)); + if (fdst == NULL) + { + rt_kprintf("out of memory\n"); + return; + } + copyfile(src, fdst); + rt_free(fdst); + } + else + { + copyfile(src, dst); + } + } + else //flag & FLAG_SRC_IS_DIR + { + if (flag & FLAG_DST_IS_DIR) + { + char * fdst; + fdst = dfs_normalize_path(dst, _get_path_lastname(src)); + if (fdst == NULL) + { + rt_kprintf("out of memory\n"); + return; + } + mkdir(fdst, 0); + copydir(src, fdst); + rt_free(fdst); + } + else if ((flag & FLAG_DST_TYPE) == FLAG_DST_NON_EXSIT) + { + mkdir(dst, 0); + copydir(src, dst); + } + else + { + copydir(src, dst); + } + } +} +FINSH_FUNCTION_EXPORT(copy, copy file or dir) #endif /* @} */ From 32a6f5b730ea6dc0ba5984acc7ca43ecbf1bfb43 Mon Sep 17 00:00:00 2001 From: bernard Date: Sat, 15 Feb 2014 10:28:38 +0800 Subject: [PATCH 24/59] [Finsh] remove the .mo display when command is not found. --- components/finsh/msh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/finsh/msh.c b/components/finsh/msh.c index 794fcb83e8..ff3d92f359 100644 --- a/components/finsh/msh.c +++ b/components/finsh/msh.c @@ -242,7 +242,7 @@ int msh_exec_module(char* cmd_line, int size) } else { - rt_kprintf("%s: program not found.\n", pg_name); + rt_kprintf("%s: program not found.\n", cmd_line); } rt_free(pg_name); From fb6b1c2520c5275da9f2ca2859be53cb1da89f66 Mon Sep 17 00:00:00 2001 From: bernard Date: Sat, 15 Feb 2014 10:29:35 +0800 Subject: [PATCH 25/59] [scons] fix library suffix issue. --- tools/building.py | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/tools/building.py b/tools/building.py index a063ddb91d..ff75e6f339 100644 --- a/tools/building.py +++ b/tools/building.py @@ -53,13 +53,10 @@ def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = [ # reset AR command flags env['ARCOM'] = '$AR --create $TARGET $SOURCES' env['LIBPREFIX'] = '' - env['LIBSUFFIX'] = '_rvds.lib' + env['LIBSUFFIX'] = '.lib' env['LIBLINKPREFIX'] = '' - env['LIBLINKSUFFIX'] = '_rvds.lib' + env['LIBLINKSUFFIX'] = '.lib' env['LIBDIRPREFIX'] = '--userlibpath ' - elif rtconfig.PLATFORM == 'gcc': - env['LIBSUFFIX'] = '_gcc.a' - env['LIBLINKSUFFIX'] = '_gcc' # patch for win32 spawn if env['PLATFORM'] == 'win32' and rtconfig.PLATFORM == 'gcc': @@ -310,14 +307,14 @@ def DefineGroup(name, src, depend, **parameters): Env.Append(LINKFLAGS = group['LINKFLAGS']) # check whether to clean up library - if GetOption('cleanlib') and os.path.exists(os.path.join(group['path'], GroupLibName(name, Env))): + if GetOption('cleanlib') and os.path.exists(os.path.join(group['path'], GroupLibFullName(name, Env))): if group['src'] != []: - print 'Remove library:', GroupLibName(name, Env) - do_rm_file(os.path.join(group['path'], GroupLibName(name, Env))) + print 'Remove library:', GroupLibFullName(name, Env) + do_rm_file(os.path.join(group['path'], GroupLibFullName(name, Env))) # check whether exist group library - if not GetOption('buildlib') and os.path.exists(os.path.join(group['path'], GroupLibName(name, Env))): - Env.Append(LIBS = [name]) + if not GetOption('buildlib') and os.path.exists(os.path.join(group['path'], GroupLibFullName(name, Env))): + Env.Append(LIBS = [GroupLibName(name, Env)]) group['src'] = [] Env.Append(LIBPATH = [GetCurrentDir()]) @@ -361,14 +358,22 @@ def PreBuilding(): a() def GroupLibName(name, env): - return env['LIBPREFIX'] + name + env['LIBSUFFIX'] + import rtconfig + if rtconfig.PLATFORM == 'armcc': + return name + '_rvds' + elif rtconfig.PLATFORM == 'gcc': + return name + '_gcc' + + return name + +def GroupLibFullName(name, env): + return env['LIBPREFIX'] + GroupLibName(name, env) + env['LIBSUFFIX'] def BuildLibInstallAction(target, source, env): lib_name = GetOption('buildlib') for Group in Projects: if Group['name'] == lib_name: - lib_name = str(target[0]) - lib_name = GroupLibName(lib_name, env) + lib_name = GroupLibFullName(Group['name'], env) dst_name = os.path.join(Group['path'], lib_name) print 'Copy %s => %s' % (lib_name, dst_name) do_copy_file(lib_name, dst_name) @@ -382,6 +387,7 @@ def DoBuilding(target, objects): # build library with special component for Group in Projects: if Group['name'] == lib_name: + lib_name = GroupLibName(Group['name'], Env) objects = Env.Object(Group['src']) program = Env.Library(lib_name, objects) From d8f06c8542a727998d38274c7461224cfc427971 Mon Sep 17 00:00:00 2001 From: prife Date: Sun, 16 Feb 2014 14:30:24 +0800 Subject: [PATCH 26/59] simulator: fix compile errors in nand driver(512+16) --- bsp/simulator/drivers/nanddrv_file.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bsp/simulator/drivers/nanddrv_file.c b/bsp/simulator/drivers/nanddrv_file.c index 770751ac79..075ed7f5d8 100644 --- a/bsp/simulator/drivers/nanddrv_file.c +++ b/bsp/simulator/drivers/nanddrv_file.c @@ -4,23 +4,23 @@ #include #define NAND_SIM "nand.bin" + #if 1 #define OOB_SIZE 64 #define PAGE_DATA_SIZE 2048 -#define PAGE_SIZE (2048 + 64) #define PAGE_PER_BLOCK 64 -#define BLOCK_SIZE (PAGE_SIZE * PAGE_PER_BLOCK) +#define ECC_SIZE ((PAGE_DATA_SIZE) * 3 / 256) #define BLOCK_NUM 512 -// #define BLOCK_NUM 2048 #else #define OOB_SIZE 16 -#define PAGE_SIZE (512 + OOB_SIZE) +#define PAGE_DATA_SIZE 512 #define PAGE_PER_BLOCK 32 -#define BLOCK_SIZE (PAGE_SIZE * PAGE_PER_BLOCK) +#define ECC_SIZE ((PAGE_DATA_SIZE) * 3 / 256) #define BLOCK_NUM 512 #endif -#define ECC_SIZE ((PAGE_DATA_SIZE) * 3 / 256) +#define BLOCK_SIZE (PAGE_SIZE * PAGE_PER_BLOCK) +#define PAGE_SIZE (PAGE_DATA_SIZE + OOB_SIZE) static unsigned char block_data[BLOCK_SIZE]; static struct rt_mtd_nand_device _nanddrv_file_device; From 6cfb1098e4410134c9060a49a071a429af811a6f Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Sun, 16 Feb 2014 16:23:18 +0800 Subject: [PATCH 27/59] [ci-skip] --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 4b232a9048..228ad1cae5 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ RT-Thread RTOS can support many architectures: * ARM Cortex-R4 * ARM Cortex-A8/A9 * ARM920T/ARM926 etc - * MIPS * x86 * PowerPC From fd4554392a6f8011c681a56e44dc116d0906d927 Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Sun, 16 Feb 2014 16:36:54 +0800 Subject: [PATCH 28/59] [scons] Use a single path for group (ci build) --- tools/building.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tools/building.py b/tools/building.py index ff75e6f339..00ef97c4b0 100644 --- a/tools/building.py +++ b/tools/building.py @@ -284,14 +284,27 @@ def MergeGroup(src_group, group): else: src_group['LIBPATH'] = group['LIBPATH'] + if src_group.has_key('LIBS'): + print src_group['LIBS'] + if src_group.has_key('LIBS'): + print src_group['LIBPATH'] + def DefineGroup(name, src, depend, **parameters): global Env if not GetDepend(depend): return [] + # find exist group and get path of group + group_path = '' + for g in Projects: + if g['name'] == name: + group_path = g['path'] + if group_path == '': + group_path = GetCurrentDir() + group = parameters group['name'] = name - group['path'] = GetCurrentDir() + group['path'] = group_path if type(src) == type(['src1']): group['src'] = File(src) else: @@ -396,6 +409,12 @@ def DoBuilding(target, objects): break else: + # merge the repeated items in the Env + if Env.has_key('CPPPATH') : Env['CPPPATH'] = list(set(Env['CPPPATH'])) + if Env.has_key('CPPDEFINES'): Env['CPPDEFINES'] = list(set(Env['CPPDEFINES'])) + if Env.has_key('LIBPATH') : Env['LIBPATH'] = list(set(Env['LIBPATH'])) + if Env.has_key('LIBS') : Env['LIBS'] = list(set(Env['LIBS'])) + program = Env.Program(target, objects) EndBuilding(target, program) @@ -500,6 +519,9 @@ def GlobSubDir(sub_dir, ext_name): dst.append(os.path.relpath(item, sub_dir)) return dst +def file_path_exist(path, *args): + return os.path.exists(os.path.join(path, *args)) + def do_rm_file(src): if os.path.exists(src): os.unlink(src) From 5ccbef26e49b8a04a34afaed845197ecfe6bfd63 Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Sun, 16 Feb 2014 16:37:40 +0800 Subject: [PATCH 29/59] [scons] Change attribution for wizard.py (ci build) --- tools/wizard.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tools/wizard.py diff --git a/tools/wizard.py b/tools/wizard.py old mode 100644 new mode 100755 From db02f56283d17125917254e470997c63492b6862 Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Sun, 16 Feb 2014 16:39:25 +0800 Subject: [PATCH 30/59] [git] Add *.lib/*.a into git ignore list (ci build) --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 9e2a6e8fc5..0f50154a67 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,9 @@ *.ilk build *~ +*.o +*.bak +*.dep +*.lib +*.a + From 8fd0a7f9c61dde28d90ec4c3661e9e0e8327f7fc Mon Sep 17 00:00:00 2001 From: shaolin Date: Sun, 16 Feb 2014 17:42:35 +0800 Subject: [PATCH 31/59] Update USB Device Stack to support more device controllers; Pass USB CV test verification; Code cleanup; --- .../drivers/include/drivers/usb_common.h | 63 +- .../drivers/include/drivers/usb_device.h | 337 +++-- components/drivers/usb/usbdevice/SConscript | 3 - .../drivers/usb/usbdevice/class/cdc_vcom.c | 559 ++++---- .../drivers/usb/usbdevice/class/mstorage.c | 1057 ++++++++++----- .../drivers/usb/usbdevice/class/mstorage.h | 7 - components/drivers/usb/usbdevice/core/core.c | 1146 ++++++++++++----- .../drivers/usb/usbdevice/core/usbdevice.c | 66 +- 8 files changed, 2188 insertions(+), 1050 deletions(-) diff --git a/components/drivers/include/drivers/usb_common.h b/components/drivers/include/drivers/usb_common.h index 979deb4732..cd6f0432f3 100644 --- a/components/drivers/include/drivers/usb_common.h +++ b/components/drivers/include/drivers/usb_common.h @@ -20,6 +20,7 @@ * Change Logs: * Date Author Notes * 2012-10-01 Yi Qiu first version + * 2013-04-26 aozima add DEVICEQUALIFIER support. */ #ifndef __USB_COMMON_H__ @@ -148,13 +149,22 @@ extern "C" { #define USB_EPNO_MASK 0x7f #define USB_DIR_OUT 0x00 #define USB_DIR_IN 0x80 +#define USB_DIR_INOUT 0x40 #define USB_DIR_MASK 0x80 +#define ID_UNASSIGNED 0 +#define ID_ASSIGNED 1 + #define RH_GET_PORT_STATUS 0 #define RH_SET_PORT_STATUS 1 #define RH_CLEAR_PORT_FEATURE 2 #define RH_SET_PORT_FEATURE 3 +#define USB_BUS_POWERED 0 +#define USB_SELF_POWERED 1 +#define USB_REMOTE_WAKEUP 1 +#define USB_EP_HALT 0 + /* * Port feature numbers */ @@ -205,6 +215,7 @@ extern "C" { #define USB_EP_ATTR(attr) (attr & USB_EP_ATTR_TYPE_MASK) #define USB_EP_DESC_NUM(addr) (addr & USB_EP_DESC_NUM_MASK) +#define USB_EP_DIR(addr) ((addr & USB_DIR_MASK)>>7) #define uswap_32(x) \ ((((x) & 0xff000000) >> 24) | \ @@ -239,7 +250,7 @@ struct usb_descriptor }; typedef struct usb_descriptor* udesc_t; -struct udevice_descriptor +struct udevice_descriptor { rt_uint8_t bLength; rt_uint8_t type; @@ -258,7 +269,7 @@ struct udevice_descriptor }; typedef struct udevice_descriptor* udev_desc_t; -struct uconfig_descriptor +struct uconfig_descriptor { rt_uint8_t bLength; rt_uint8_t type; @@ -272,7 +283,7 @@ struct uconfig_descriptor }; typedef struct uconfig_descriptor* ucfg_desc_t; -struct uinterface_descriptor +struct uinterface_descriptor { rt_uint8_t bLength; rt_uint8_t type; @@ -287,7 +298,7 @@ struct uinterface_descriptor typedef struct uinterface_descriptor* uintf_desc_t; /* Interface Association Descriptor (IAD) */ -struct uiad_descriptor +struct uiad_descriptor { rt_uint8_t bLength; rt_uint8_t bDescriptorType; @@ -300,7 +311,7 @@ struct uiad_descriptor }; typedef struct uiad_descriptor* uiad_desc_t; -struct uendpoint_descriptor +struct uendpoint_descriptor { rt_uint8_t bLength; rt_uint8_t type; @@ -311,7 +322,7 @@ struct uendpoint_descriptor }; typedef struct uendpoint_descriptor* uep_desc_t; -struct ustring_descriptor +struct ustring_descriptor { rt_uint8_t bLength; rt_uint8_t type; @@ -319,19 +330,34 @@ struct ustring_descriptor }; typedef struct ustring_descriptor* ustr_desc_t; -struct uhub_descriptor +struct uhub_descriptor { rt_uint8_t length; rt_uint8_t type; rt_uint8_t num_ports; - rt_uint16_t characteristics; + rt_uint16_t characteristics; rt_uint8_t pwron_to_good; /* power on to power good */ - rt_uint8_t current; + rt_uint8_t current; rt_uint8_t removable[8]; rt_uint8_t pwr_ctl[8]; }; typedef struct uhub_descriptor* uhub_desc_t; +/* USB_DESC_TYPE_DEVICEQUALIFIER: Device Qualifier descriptor */ +struct usb_qualifier_descriptor +{ + rt_uint8_t bLength; + rt_uint8_t bDescriptorType; + + rt_uint16_t bcdUSB; // TODO: big-endian. + rt_uint8_t bDeviceClass; + rt_uint8_t bDeviceSubClass; + rt_uint8_t bDeviceProtocol; + rt_uint8_t bMaxPacketSize0; + rt_uint8_t bNumConfigurations; + rt_uint8_t bRESERVED; +} __attribute__ ((packed)); + struct uhid_descriptor { rt_uint8_t bLength; @@ -352,15 +378,17 @@ struct ureqest rt_uint8_t request_type; rt_uint8_t request; rt_uint16_t value; - rt_uint16_t index; + rt_uint16_t index; rt_uint16_t length; }; typedef struct ureqest* ureq_t; +#ifndef MIN #define MIN(a, b) (a < b ? a : b) #define MAX(a, b) (a > b ? a : b) +#endif -/* +/* * the define related to mass storage */ #define USBREQ_GET_MAX_LUN 0xfe @@ -368,6 +396,11 @@ typedef struct ureqest* ureq_t; #define SIZEOF_CSW 0x0d #define SIZEOF_CBW 0x1f +#define SIZEOF_INQUIRY_CMD 0x24 +#define SIZEOF_MODE_SENSE_6 0x4 +#define SIZEOF_READ_CAPACITIES 0xc +#define SIZEOF_READ_CAPACITY 0x8 +#define SIZEOF_REQUEST_SENSE 0x12 #define CBWFLAGS_DIR_M 0x80 #define CBWFLAGS_DIR_IN 0x80 @@ -376,7 +409,7 @@ typedef struct ureqest* ureq_t; #define SCSI_TEST_UNIT_READY 0x00 #define SCSI_REQUEST_SENSE 0x03 #define SCSI_INQUIRY_CMD 0x12 -#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1e +#define SCSI_ALLOW_REMOVAL 0x1e #define SCSI_MODE_SENSE_6 0x1a #define SCSI_START_STOP 0x1b #define SCSI_READ_CAPACITIES 0x23 @@ -389,7 +422,7 @@ typedef struct ureqest* ureq_t; #define CSW_SIGNATURE 0x53425355 #define CBW_TAG_VALUE 0x12345678 -struct ustorage_cbw +struct ustorage_cbw { rt_uint32_t signature; rt_uint32_t tag; @@ -401,11 +434,11 @@ struct ustorage_cbw }; typedef struct ustorage_cbw* ustorage_cbw_t; -struct ustorage_csw +struct ustorage_csw { rt_uint32_t signature; rt_uint32_t tag; - rt_uint32_t data_reside; + rt_int32_t data_reside; rt_uint8_t status; }; typedef struct ustorage_csw* ustorage_csw_t; diff --git a/components/drivers/include/drivers/usb_device.h b/components/drivers/include/drivers/usb_device.h index db03ee36ef..722251c82a 100644 --- a/components/drivers/include/drivers/usb_device.h +++ b/components/drivers/include/drivers/usb_device.h @@ -20,7 +20,8 @@ * Change Logs: * Date Author Notes * 2012-10-01 Yi Qiu first version - * 2012-12-12 heyuanjie87 change endpoint and class handler + * 2012-12-12 heyuanjie87 change endpoint and function handler + * 2013-04-26 aozima add DEVICEQUALIFIER support. */ #ifndef __USB_DEVICE_H__ @@ -31,59 +32,115 @@ /* Vendor ID */ #ifdef USB_VENDOR_ID -#define _VENDOR_ID USB_VENDOR_ID +#define _VENDOR_ID USB_VENDOR_ID #else -#define _VENDOR_ID 0x0EFF +#define _VENDOR_ID 0x0EFF #endif /* Product ID */ #ifdef USB_PRODUCT_ID -#define _PRODUCT_ID USB_PRODUCT_ID +#define _PRODUCT_ID USB_PRODUCT_ID #else -#define _PRODUCT_ID 0x0001 +#define _PRODUCT_ID 0x0001 #endif -#define USB_BCD_DEVICE 0x0200 /* USB Specification Release Number in Binary-Coded Decimal */ -#define USB_BCD_VERSION 0x0200 /* USB 2.0 */ +#define USB_BCD_DEVICE 0x0200 /* USB Specification Release Number in Binary-Coded Decimal */ +#define USB_BCD_VERSION 0x0200 /* USB 2.0 */ +#define EP0_IN_ADDR 0x80 +#define EP0_OUT_ADDR 0x00 +#define EP_HANDLER(ep, func, size) RT_ASSERT(ep != RT_NULL); ep->handler(func, size) +#define EP_ADDRESS(ep) ep->ep_desc->bEndpointAddress +#define EP_MAXPACKET(ep) ep->ep_desc->wMaxPacketSize +#define FUNC_ENABLE(func) do{ \ + if(func->ops->enable != RT_NULL && \ + func->enabled == RT_FALSE) \ + { \ + if(func->ops->enable(func) == RT_EOK) \ + func->enabled = RT_TRUE; \ + } \ + }while(0) +#define FUNC_DISABLE(func) do{ \ + if(func->ops->disable != RT_NULL && \ + func->enabled == RT_TRUE) \ + { \ + func->enabled = RT_FALSE; \ + func->ops->disable(func); \ + } \ + }while(0) -struct uclass; +struct ufunction; struct udevice; struct uendpoint; +typedef enum +{ + /* request to read full count */ + UIO_REQUEST_READ_FULL, + /* request to read any count */ + UIO_REQUEST_READ_BEST, + /* request to write full count */ + UIO_REQUEST_WRITE, +}UIO_REQUEST_TYPE; + struct udcd_ops { - rt_err_t (*set_address)(rt_uint8_t value); - rt_err_t (*clear_feature)(rt_uint16_t value, rt_uint16_t index); - rt_err_t (*set_feature)(rt_uint16_t value, rt_uint16_t index); - rt_err_t (*ep_alloc)(struct uendpoint* ep); - rt_err_t (*ep_free)(struct uendpoint* ep); - rt_err_t (*ep_stall)(struct uendpoint* ep); - rt_err_t (*ep_run)(struct uendpoint* ep); - rt_err_t (*ep_stop)(struct uendpoint* ep); - rt_err_t (*ep_read)(struct uendpoint* ep, void *buffer, rt_size_t size); - rt_size_t (*ep_write)(struct uendpoint* ep, void *buffer, rt_size_t size); - rt_err_t (*send_status)(void); + rt_err_t (*set_address)(rt_uint8_t address); + rt_err_t (*set_config)(rt_uint8_t address); + rt_err_t (*ep_set_stall)(rt_uint8_t address); + rt_err_t (*ep_clear_stall)(rt_uint8_t address); + rt_err_t (*ep_enable)(struct uendpoint* ep); + rt_err_t (*ep_disable)(struct uendpoint* ep); + rt_size_t (*ep_read_prepare)(rt_uint8_t address, void *buffer, rt_size_t size); + rt_size_t (*ep_read)(rt_uint8_t address, void *buffer); + rt_size_t (*ep_write)(rt_uint8_t address, void *buffer, rt_size_t size); + rt_err_t (*ep0_send_status)(void); + rt_err_t (*suspend)(void); + rt_err_t (*wakeup)(void); }; -struct udcd +struct ep_id { - struct rt_device parent; - struct udcd_ops* ops; - struct rt_completion completion; + rt_uint8_t addr; + rt_uint8_t type; + rt_uint8_t dir; + rt_uint8_t maxpacket; + rt_uint8_t status; }; -typedef struct udcd* udcd_t; -typedef rt_err_t (*udep_handler_t)(struct udevice* device, struct uclass* cls, rt_size_t size); +typedef rt_err_t (*udep_handler_t)(struct ufunction* func, rt_size_t size); + +struct uio_request +{ + rt_list_t list; + UIO_REQUEST_TYPE req_type; + rt_uint8_t* buffer; + rt_size_t size; + rt_size_t remain_size; +}; +typedef struct uio_request* uio_request_t; struct uendpoint { rt_list_t list; - rt_uint8_t* buffer; uep_desc_t ep_desc; + rt_list_t request_list; + struct uio_request request; + rt_uint8_t* buffer; + rt_bool_t stalled; + struct ep_id* id; udep_handler_t handler; - rt_bool_t is_stall; + rt_err_t (*rx_indicate)(struct udevice* dev, rt_size_t size); }; typedef struct uendpoint* uep_t; +struct udcd +{ + struct rt_device parent; + const struct udcd_ops* ops; + struct uendpoint ep0; + struct ep_id* ep_pool; +}; +typedef struct udcd* udcd_t; + struct ualtsetting { rt_list_t list; @@ -94,7 +151,7 @@ struct ualtsetting }; typedef struct ualtsetting* ualtsetting_t; -typedef rt_err_t (*uintf_handler_t)(struct udevice* device, struct uclass* cls, ureq_t setup); +typedef rt_err_t (*uintf_handler_t)(struct ufunction* func, ureq_t setup); struct uinterface { @@ -106,32 +163,32 @@ struct uinterface }; typedef struct uinterface* uintf_t; -struct uclass_ops +struct ufunction_ops { - rt_err_t (*run)(struct udevice* device, struct uclass* cls); - rt_err_t (*stop)(struct udevice* device, struct uclass* cls); - rt_err_t (*sof_handler)(struct udevice* device, struct uclass* cls); + rt_err_t (*enable)(struct ufunction* func); + rt_err_t (*disable)(struct ufunction* func); + rt_err_t (*sof_handler)(struct ufunction* func); }; -typedef struct uclass_ops* uclass_ops_t; +typedef struct ufunction_ops* ufunction_ops_t; -struct uclass +struct ufunction { rt_list_t list; - uclass_ops_t ops; - void* eps; + ufunction_ops_t ops; struct udevice* device; udev_desc_t dev_desc; void* user_data; + rt_bool_t enabled; rt_list_t intf_list; }; -typedef struct uclass* uclass_t; +typedef struct ufunction* ufunction_t; struct uconfig { rt_list_t list; struct uconfig_descriptor cfg_desc; - rt_list_t cls_list; + rt_list_t func_list; }; typedef struct uconfig* uconfig_t; @@ -139,6 +196,8 @@ struct udevice { rt_list_t list; struct udevice_descriptor dev_desc; + + struct usb_qualifier_descriptor * dev_qualifier; const char** str; udevice_state_t state; @@ -154,8 +213,11 @@ enum udev_msg_type { USB_MSG_SETUP_NOTIFY, USB_MSG_DATA_NOTIFY, + USB_MSG_EP0_OUT, + USB_MSG_EP_CLEAR_FEATURE, USB_MSG_SOF, USB_MSG_RESET, + USB_MSG_PLUG_IN, /* we don't need to add a "PLUG_IN" event because after the cable is * plugged in(before any SETUP) the classed have nothing to do. If the host * is ready, it will send RESET and we will have USB_MSG_RESET. So, a RESET @@ -164,153 +226,184 @@ enum udev_msg_type }; typedef enum udev_msg_type udev_msg_type; +struct ep_msg +{ + rt_size_t size; + rt_uint8_t ep_addr; +}; + struct udev_msg { udev_msg_type type; udcd_t dcd; union { - struct - { - rt_size_t size; - rt_uint8_t ep_addr; - } ep_msg; - struct - { - rt_uint32_t* packet; - } setup_msg; + struct ep_msg ep_msg; + struct ureqest setup; } content; }; typedef struct udev_msg* udev_msg_t; -udevice_t rt_usbd_device_create(void); -uconfig_t rt_usbd_config_create(void); -uclass_t rt_usbd_class_create(udevice_t device, - udev_desc_t dev_desc, - uclass_ops_t ops); -uintf_t rt_usbd_interface_create(udevice_t device, uintf_handler_t handler); -uep_t rt_usbd_endpoint_create(uep_desc_t ep_desc, udep_handler_t handler); -ualtsetting_t rt_usbd_altsetting_create(rt_size_t desc_size); +udevice_t rt_usbd_device_new(void); +uconfig_t rt_usbd_config_new(void); +ufunction_t rt_usbd_function_new(udevice_t device, udev_desc_t dev_desc, + ufunction_ops_t ops); +uintf_t rt_usbd_interface_new(udevice_t device, uintf_handler_t handler); +uep_t rt_usbd_endpoint_new(uep_desc_t ep_desc, udep_handler_t handler); +ualtsetting_t rt_usbd_altsetting_new(rt_size_t desc_size); rt_err_t rt_usbd_core_init(void); -rt_err_t rt_usb_device_init(const char *udc_name); -rt_err_t rt_usbd_post_event(struct udev_msg *msg, rt_size_t size); -rt_err_t rt_usbd_free_device(udevice_t device); +rt_err_t rt_usb_device_init(void); +rt_err_t rt_usbd_event_signal(struct udev_msg* msg); rt_err_t rt_usbd_device_set_controller(udevice_t device, udcd_t dcd); rt_err_t rt_usbd_device_set_descriptor(udevice_t device, udev_desc_t dev_desc); rt_err_t rt_usbd_device_set_string(udevice_t device, const char** ustring); +rt_err_t rt_usbd_device_set_qualifier(udevice_t device, struct usb_qualifier_descriptor* qualifier); rt_err_t rt_usbd_device_add_config(udevice_t device, uconfig_t cfg); -rt_err_t rt_usbd_config_add_class(uconfig_t cfg, uclass_t cls); -rt_err_t rt_usbd_class_add_interface(uclass_t cls, uintf_t intf); +rt_err_t rt_usbd_config_add_function(uconfig_t cfg, ufunction_t func); +rt_err_t rt_usbd_function_add_interface(ufunction_t func, uintf_t intf); rt_err_t rt_usbd_interface_add_altsetting(uintf_t intf, ualtsetting_t setting); rt_err_t rt_usbd_altsetting_add_endpoint(ualtsetting_t setting, uep_t ep); -rt_err_t rt_usbd_altsetting_config_descriptor(ualtsetting_t setting, - const void *desc, - rt_off_t intf_pos); +rt_err_t rt_usbd_altsetting_config_descriptor(ualtsetting_t setting, const void* desc, rt_off_t intf_pos); rt_err_t rt_usbd_set_config(udevice_t device, rt_uint8_t value); rt_err_t rt_usbd_set_altsetting(uintf_t intf, rt_uint8_t value); udevice_t rt_usbd_find_device(udcd_t dcd); uconfig_t rt_usbd_find_config(udevice_t device, rt_uint8_t value); -uintf_t rt_usbd_find_interface(udevice_t device, - rt_uint8_t value, - uclass_t *pcls); -uep_t rt_usbd_find_endpoint(udevice_t device, - uclass_t *pcls, - rt_uint8_t ep_addr); +uintf_t rt_usbd_find_interface(udevice_t device, rt_uint8_t value, ufunction_t *pfunc); +uep_t rt_usbd_find_endpoint(udevice_t device, ufunction_t* pfunc, rt_uint8_t ep_addr); +rt_size_t rt_usbd_io_request(udevice_t device, uep_t ep, uio_request_t req); +rt_size_t rt_usbd_ep0_write(udevice_t device, void *buffer, rt_size_t size); +rt_size_t rt_usbd_ep0_read(udevice_t device, void *buffer, rt_size_t size, + rt_err_t (*rx_ind)(udevice_t device, rt_size_t size)); -uclass_t rt_usbd_class_mstorage_create(udevice_t device); -uclass_t rt_usbd_class_cdc_create(udevice_t device); -uclass_t rt_usbd_class_rndis_create(udevice_t device); -uclass_t rt_usbd_class_dap_create(udevice_t device); +ufunction_t rt_usbd_function_mstorage_create(udevice_t device); +ufunction_t rt_usbd_function_cdc_create(udevice_t device); +ufunction_t rt_usbd_function_rndis_create(udevice_t device); +ufunction_t rt_usbd_function_dap_create(udevice_t device); #ifdef RT_USB_DEVICE_COMPOSITE -rt_err_t rt_usbd_class_set_iad(uclass_t cls, uiad_desc_t iad_desc); +rt_err_t rt_usbd_function_set_iad(ufunction_t func, uiad_desc_t iad_desc); #endif -rt_inline rt_err_t dcd_set_address(udcd_t dcd, rt_uint8_t value) +rt_err_t rt_usbd_set_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index); +rt_err_t rt_usbd_clear_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index); +rt_err_t rt_usbd_ep_set_stall(udevice_t device, uep_t ep); +rt_err_t rt_usbd_ep_clear_stall(udevice_t device, uep_t ep); +rt_err_t rt_usbd_ep0_set_stall(udevice_t device); +rt_err_t rt_usbd_ep0_clear_stall(udevice_t device); +rt_err_t rt_usbd_ep0_setup_handler(udcd_t dcd, struct ureqest* setup); +rt_err_t rt_usbd_ep0_in_handler(udcd_t dcd); +rt_err_t rt_usbd_ep0_out_handler(udcd_t dcd, rt_size_t size); +rt_err_t rt_usbd_ep_in_handler(udcd_t dcd, rt_uint8_t address); +rt_err_t rt_usbd_ep_out_handler(udcd_t dcd, rt_uint8_t address, rt_size_t size); +rt_err_t rt_usbd_reset_handler(udcd_t dcd); +rt_err_t rt_usbd_connect_handler(udcd_t dcd); +rt_err_t rt_usbd_disconnect_handler(udcd_t dcd); +rt_err_t rt_usbd_sof_handler(udcd_t dcd); + +rt_inline rt_err_t dcd_set_address(udcd_t dcd, rt_uint8_t address) { RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + RT_ASSERT(dcd->ops->set_address != RT_NULL); - return dcd->ops->set_address(value); + return dcd->ops->set_address(address); } -rt_inline rt_err_t dcd_clear_feature(udcd_t dcd, - rt_uint16_t value, - rt_uint16_t index) +rt_inline rt_err_t dcd_set_config(udcd_t dcd, rt_uint8_t address) { RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + RT_ASSERT(dcd->ops->set_config != RT_NULL); - return dcd->ops->clear_feature(value, index); + return dcd->ops->set_config(address); } -rt_inline rt_err_t dcd_set_feature(udcd_t dcd, - rt_uint8_t value, - rt_uint16_t index) +rt_inline rt_err_t dcd_ep_enable(udcd_t dcd, uep_t ep) { RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + RT_ASSERT(dcd->ops->ep_enable != RT_NULL); - return dcd->ops->set_feature(value, index); + return dcd->ops->ep_enable(ep); } -rt_inline rt_err_t dcd_ep_stall(udcd_t dcd, uep_t ep) +rt_inline rt_err_t dcd_ep_disable(udcd_t dcd, uep_t ep) { RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + RT_ASSERT(dcd->ops->ep_disable != RT_NULL); - return dcd->ops->ep_stall(ep); + return dcd->ops->ep_disable(ep); } -rt_inline rt_uint8_t dcd_ep_alloc(udcd_t dcd, uep_t ep) -{ - RT_ASSERT(dcd != RT_NULL); - - return dcd->ops->ep_alloc(ep); -} - -rt_inline rt_err_t dcd_ep_free(udcd_t dcd, uep_t ep) -{ - RT_ASSERT(dcd != RT_NULL); - - return dcd->ops->ep_free(ep); -} - -rt_inline rt_err_t dcd_ep_run(udcd_t dcd, uep_t ep) -{ - RT_ASSERT(dcd != RT_NULL); - - return dcd->ops->ep_run(ep); -} - -rt_inline rt_err_t dcd_ep_stop(udcd_t dcd, uep_t ep) -{ - RT_ASSERT(dcd != RT_NULL); - - return dcd->ops->ep_stop(ep); -} - -rt_inline rt_err_t dcd_ep_read(udcd_t dcd, uep_t ep, void *buffer, +rt_inline rt_size_t dcd_ep_read_prepare(udcd_t dcd, rt_uint8_t address, void *buffer, rt_size_t size) { RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); - return dcd->ops->ep_read(ep, buffer, size); + if(dcd->ops->ep_read_prepare != RT_NULL) + { + return dcd->ops->ep_read_prepare(address, buffer, size); + } + else + { + return 0; + } } -rt_inline rt_size_t dcd_ep_write(udcd_t dcd, - uep_t ep, - void *buffer, +rt_inline rt_size_t dcd_ep_read(udcd_t dcd, rt_uint8_t address, void *buffer) +{ + RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + + if(dcd->ops->ep_read != RT_NULL) + { + return dcd->ops->ep_read(address, buffer); + } + else + { + return 0; + } +} + +rt_inline rt_size_t dcd_ep_write(udcd_t dcd, rt_uint8_t address, void *buffer, rt_size_t size) { RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + RT_ASSERT(dcd->ops->ep_write != RT_NULL); - return dcd->ops->ep_write(ep, buffer, size); + return dcd->ops->ep_write(address, buffer, size); } -rt_inline rt_err_t dcd_send_status(udcd_t dcd) +rt_inline rt_err_t dcd_ep0_send_status(udcd_t dcd) { RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + RT_ASSERT(dcd->ops->ep0_send_status != RT_NULL); - return dcd->ops->send_status(); + return dcd->ops->ep0_send_status(); +} + +rt_inline rt_err_t dcd_ep_set_stall(udcd_t dcd, rt_uint8_t address) +{ + RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + RT_ASSERT(dcd->ops->ep_set_stall != RT_NULL); + + return dcd->ops->ep_set_stall(address); +} + +rt_inline rt_err_t dcd_ep_clear_stall(udcd_t dcd, rt_uint8_t address) +{ + RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + RT_ASSERT(dcd->ops->ep_clear_stall != RT_NULL); + + return dcd->ops->ep_clear_stall(address); } #endif diff --git a/components/drivers/usb/usbdevice/SConscript b/components/drivers/usb/usbdevice/SConscript index d46ec3db59..1ee9467410 100644 --- a/components/drivers/usb/usbdevice/SConscript +++ b/components/drivers/usb/usbdevice/SConscript @@ -13,9 +13,6 @@ if GetDepend('RT_USB_DEVICE_CDC'): if GetDepend('RT_USB_DEVICE_MSTORAGE'): src += Glob('class/mstorage.c') -if GetDepend('RT_USB_DEVICE_RNDIS'): - src += Glob('class/rndis.c') - CPPPATH = [cwd] group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_USB_DEVICE'], CPPPATH = CPPPATH) diff --git a/components/drivers/usb/usbdevice/class/cdc_vcom.c b/components/drivers/usb/usbdevice/class/cdc_vcom.c index 5f284b0294..33f9f7abef 100644 --- a/components/drivers/usb/usbdevice/class/cdc_vcom.c +++ b/components/drivers/usb/usbdevice/class/cdc_vcom.c @@ -20,34 +20,56 @@ * Change Logs: * Date Author Notes * 2012-10-02 Yi Qiu first version - * 2012-12-12 heyuanjie87 change endpoints and class handler + * 2012-12-12 heyuanjie87 change endpoints and function handler + * 2013-06-25 heyuanjie87 remove SOF mechinism + * 2013-07-20 Yi Qiu do more test */ #include +#include #include #include #include "cdc.h" #ifdef RT_USB_DEVICE_CDC +#define TX_TIMEOUT 100 #define CDC_RX_BUFSIZE 2048 -#define CDC_TX_BUFSIZE 2048 -static rt_uint8_t rx_rbp[CDC_RX_BUFSIZE]; -static rt_uint8_t tx_rbp[CDC_TX_BUFSIZE]; -static struct rt_ringbuffer rx_ringbuffer; -static struct rt_ringbuffer tx_ringbuffer; -static struct serial_ringbuffer vcom_int_rx; +#define CDC_MAX_PACKET_SIZE 64 +#define VCOM_DEVICE "vcom" -static struct rt_serial_device vcom_serial; - -#define CDC_MaxPacketSize 64 ALIGN(RT_ALIGN_SIZE) -static rt_uint8_t rx_buf[CDC_RX_BUFSIZE]; -ALIGN(RT_ALIGN_SIZE) -static rt_uint8_t tx_buf[CDC_TX_BUFSIZE]; +static rt_uint8_t vcom_thread_stack[512]; +static struct rt_thread vcom_thread; +#define VCOM_MQ_MSG_SZ 16 +#define VCOM_MQ_MAX_MSG 4 +/* internal of the message queue: every message is associated with a pointer, + * so in order to recveive VCOM_MQ_MAX_MSG messages, we have to allocate more + * than VCOM_MQ_MSG_SZ*VCOM_MQ_MAX_MSG memery. */ +static rt_uint8_t vcom_tx_thread_mq_pool[(VCOM_MQ_MSG_SZ+sizeof(void*))*VCOM_MQ_MAX_MSG]; +static struct rt_messagequeue vcom_tx_thread_mq; +static struct ucdc_line_coding line_coding; -volatile static rt_bool_t vcom_connected = RT_FALSE; -volatile static rt_bool_t vcom_in_sending = RT_FALSE; +struct vcom +{ + struct rt_serial_device serial; + uep_t ep_out; + uep_t ep_in; + uep_t ep_cmd; + rt_bool_t connected; + rt_bool_t in_sending; + struct rt_completion wait; + rt_uint8_t rx_rbp[CDC_RX_BUFSIZE]; + struct rt_ringbuffer rx_ringbuffer; + struct serial_ringbuffer vcom_int_rx; +}; + +struct vcom_tx_msg +{ + struct rt_serial_device * serial; + const char *buf; + rt_size_t size; +}; static struct udevice_descriptor dev_desc = { @@ -57,7 +79,7 @@ static struct udevice_descriptor dev_desc = USB_CLASS_CDC, //bDeviceClass; 0x00, //bDeviceSubClass; 0x00, //bDeviceProtocol; - CDC_MaxPacketSize, //bMaxPacketSize0; + CDC_MAX_PACKET_SIZE, //bMaxPacketSize0; _VENDOR_ID, //idVendor; _PRODUCT_ID, //idProduct; USB_BCD_DEVICE, //bcdDevice; @@ -67,6 +89,18 @@ static struct udevice_descriptor dev_desc = USB_DYNAMIC, //bNumConfigurations; }; +static struct usb_qualifier_descriptor dev_qualifier = +{ + sizeof(dev_qualifier), + USB_DESC_TYPE_DEVICEQUALIFIER, + 0x0200, + USB_CLASS_CDC, + 0x00, + 64, + 0x01, + 0, +}; + /* communcation interface descriptor */ const static struct ucdc_comm_descriptor _comm_desc = { @@ -85,19 +119,19 @@ const static struct ucdc_comm_descriptor _comm_desc = USB_DESC_LENGTH_INTERFACE, USB_DESC_TYPE_INTERFACE, USB_DYNAMIC, - 0x00, + 0x00, 0x01, USB_CDC_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_PROTOCOL_V25TER, 0x00, - /* Header Functional Descriptor */ - 0x05, + /* Header Functional Descriptor */ + 0x05, USB_CDC_CS_INTERFACE, USB_CDC_SCS_HEADER, 0x0110, - /* Call Management Functional Descriptor */ - 0x05, + /* Call Management Functional Descriptor */ + 0x05, USB_CDC_CS_INTERFACE, USB_CDC_SCS_CALL_MGMT, 0x00, @@ -107,13 +141,13 @@ const static struct ucdc_comm_descriptor _comm_desc = USB_CDC_CS_INTERFACE, USB_CDC_SCS_ACM, 0x02, - /* Union Functional Descriptor */ + /* Union Functional Descriptor */ 0x05, USB_CDC_CS_INTERFACE, USB_CDC_SCS_UNION, USB_DYNAMIC, USB_DYNAMIC, - /* Endpoint Descriptor */ + /* Endpoint Descriptor */ USB_DESC_LENGTH_ENDPOINT, USB_DESC_TYPE_ENDPOINT, USB_DYNAMIC | USB_DIR_IN, @@ -130,23 +164,23 @@ const static struct ucdc_data_descriptor _data_desc = USB_DESC_TYPE_INTERFACE, USB_DYNAMIC, 0x00, - 0x02, + 0x02, USB_CDC_CLASS_DATA, - 0x00, - 0x00, - 0x00, + 0x00, + 0x00, + 0x00, /* endpoint, bulk out */ - USB_DESC_LENGTH_ENDPOINT, + USB_DESC_LENGTH_ENDPOINT, USB_DESC_TYPE_ENDPOINT, USB_DYNAMIC | USB_DIR_OUT, - USB_EP_ATTR_BULK, + USB_EP_ATTR_BULK, USB_CDC_BUFSIZE, - 0x00, + 0x00, /* endpoint, bulk in */ USB_DESC_LENGTH_ENDPOINT, USB_DESC_TYPE_ENDPOINT, USB_DYNAMIC | USB_DIR_IN, - USB_EP_ATTR_BULK, + USB_EP_ATTR_BULK, USB_CDC_BUFSIZE, 0x00, }; @@ -156,18 +190,24 @@ const static char* _ustring[] = "Language", "RT-Thread Team.", "RTT Virtual Serial", - "1.1.0", + "32021919830108", "Configuration", "Interface", }; +static void rt_usb_vcom_init(struct ufunction *func); -static void _vcom_reset_state(void) +static void _vcom_reset_state(ufunction_t func) { - int lvl = rt_hw_interrupt_disable(); - tx_ringbuffer.read_mirror = tx_ringbuffer.read_index = 0; - tx_ringbuffer.write_mirror = tx_ringbuffer.write_index = 0; - vcom_connected = RT_FALSE; - vcom_in_sending = RT_FALSE; + struct vcom* data; + int lvl; + + RT_ASSERT(func != RT_NULL) + + data = (struct vcom*)func->user_data; + + lvl = rt_hw_interrupt_disable(); + data->connected = RT_FALSE; + data->in_sending = RT_FALSE; /*rt_kprintf("reset USB serial\n", cnt);*/ rt_hw_interrupt_enable(lvl); } @@ -175,95 +215,73 @@ static void _vcom_reset_state(void) /** * This function will handle cdc bulk in endpoint request. * - * @param device the usb device object. + * @param func the usb function object. * @param size request size. * * @return RT_EOK. */ -static rt_err_t _ep_in_handler(udevice_t device, uclass_t cls, rt_size_t size) +static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size) { - rt_uint32_t level; - rt_uint32_t remain; - cdc_eps_t eps; + struct vcom *data; - eps = (cdc_eps_t)cls->eps; - level = rt_hw_interrupt_disable(); - remain = rt_ringbuffer_data_len(&tx_ringbuffer); - if (remain != 0) - { - /* although vcom_in_sending is set in SOF handler in the very - * beginning, we have to guarantee the state is right when start - * sending. There is at least one extreme case where we have finished the - * last IN transaction but the vcom_in_sending is RT_FALSE. - * - * Ok, what the extreme case is: pour data into vcom in loop. Open - * terminal on the PC, you will see the data. Then close it. So the - * data will be sent to the PC in the back. When the buffer of the PC - * driver is full. It will not send IN packet to the board and you will - * have no chance to clear vcom_in_sending in this function. The data - * will fill into the ringbuffer until it is full, and we will reset - * the state machine and clear vcom_in_sending. When you open the - * terminal on the PC again. The IN packet will appear on the line and - * we will, eventually, reach here with vcom_in_sending is clear. - */ - vcom_in_sending = RT_TRUE; - rt_ringbuffer_get(&tx_ringbuffer, eps->ep_in->buffer, remain); - rt_hw_interrupt_enable(level); + RT_ASSERT(func != RT_NULL); - /* send data to host */ - dcd_ep_write(device->dcd, eps->ep_in, eps->ep_in->buffer, remain); + RT_DEBUG_LOG(RT_DEBUG_USB, ("_ep_in_handler %d\n", size)); - return RT_EOK; - } - - if (size != 0 && - (size % CDC_MaxPacketSize) == 0) + data = (struct vcom*)func->user_data; + if ((size != 0) && (size % CDC_MAX_PACKET_SIZE == 0)) { /* don't have data right now. Send a zero-length-packet to * terminate the transaction. * * FIXME: actually, this might not be the right place to send zlp. * Only the rt_device_write could know how much data is sending. */ - vcom_in_sending = RT_TRUE; - rt_hw_interrupt_enable(level); - dcd_ep_write(device->dcd, eps->ep_in, RT_NULL, 0); - return RT_EOK; - } - else - { - vcom_in_sending = RT_FALSE; - rt_hw_interrupt_enable(level); + data->in_sending = RT_TRUE; + + data->ep_in->request.buffer = RT_NULL; + data->ep_in->request.size = 0; + data->ep_in->request.req_type = UIO_REQUEST_WRITE; + rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request); + return RT_EOK; } + + rt_completion_done(&data->wait); + + return RT_EOK; } /** * This function will handle cdc bulk out endpoint request. * - * @param device the usb device object. + * @param func the usb function object. * @param size request size. * * @return RT_EOK. */ -static rt_err_t _ep_out_handler(udevice_t device, uclass_t cls, rt_size_t size) +static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size) { rt_uint32_t level; - cdc_eps_t eps; + struct vcom *data; - RT_ASSERT(device != RT_NULL); + RT_ASSERT(func != RT_NULL); - eps = (cdc_eps_t)cls->eps; + RT_DEBUG_LOG(RT_DEBUG_USB, ("_ep_out_handler %d\n", size)); + + data = (struct vcom*)func->user_data; /* receive data from USB VCOM */ level = rt_hw_interrupt_disable(); - rt_ringbuffer_put(&rx_ringbuffer, eps->ep_out->buffer, size); + rt_ringbuffer_put(&data->rx_ringbuffer, data->ep_out->buffer, size); rt_hw_interrupt_enable(level); /* notify receive data */ - rt_hw_serial_isr(&vcom_serial); + rt_hw_serial_isr(&data->serial); - dcd_ep_read(device->dcd, eps->ep_out, eps->ep_out->buffer, - eps->ep_out->ep_desc->wMaxPacketSize); + data->ep_out->request.buffer = data->ep_out->buffer; + data->ep_out->request.size = EP_MAXPACKET(data->ep_out); + data->ep_out->request.req_type = UIO_REQUEST_READ_BEST; + rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request); return RT_EOK; } @@ -276,9 +294,9 @@ static rt_err_t _ep_out_handler(udevice_t device, uclass_t cls, rt_size_t size) * * @return RT_EOK. */ -static rt_err_t _ep_cmd_handler(udevice_t device, uclass_t cls, rt_size_t size) +static rt_err_t _ep_cmd_handler(ufunction_t func, rt_size_t size) { - RT_ASSERT(device != RT_NULL); + RT_ASSERT(func != RT_NULL); RT_DEBUG_LOG(RT_DEBUG_USB, ("_ep_cmd_handler\n")); @@ -301,17 +319,28 @@ static rt_err_t _cdc_get_line_coding(udevice_t device, ureq_t setup) RT_ASSERT(device != RT_NULL); RT_ASSERT(setup != RT_NULL); + RT_DEBUG_LOG(RT_DEBUG_USB, ("_cdc_get_line_coding\n")); + data.dwDTERate = 115200; data.bCharFormat = 0; data.bDataBits = 8; data.bParityType = 0; size = setup->length > 7 ? 7 : setup->length; - dcd_ep_write(device->dcd, 0, (void*)&data, size); + rt_usbd_ep0_write(device, (void*)&data, size); return RT_EOK; } +static rt_err_t _cdc_set_line_coding_callback(udevice_t device, rt_size_t size) +{ + RT_DEBUG_LOG(RT_DEBUG_USB, ("_cdc_set_line_coding_callback\n")); + + dcd_ep0_send_status(device->dcd); + + return RT_EOK; +} + /** * This function will handle cdc_set_line_coding request. * @@ -322,21 +351,13 @@ static rt_err_t _cdc_get_line_coding(udevice_t device, ureq_t setup) */ static rt_err_t _cdc_set_line_coding(udevice_t device, ureq_t setup) { - struct ucdc_line_coding data; - rt_err_t ret; - RT_ASSERT(device != RT_NULL); RT_ASSERT(setup != RT_NULL); - rt_completion_init(&device->dcd->completion); + RT_DEBUG_LOG(RT_DEBUG_USB, ("_cdc_set_line_coding\n")); - dcd_ep_read(device->dcd, 0, (void*)&data, setup->length); - - ret = rt_completion_wait(&device->dcd->completion, 100); - if(ret != RT_EOK) - { - rt_kprintf("_cdc_set_line_coding timeout\n"); - } + rt_usbd_ep0_read(device, (void*)&line_coding, sizeof(struct ucdc_line_coding), + _cdc_set_line_coding_callback); return RT_EOK; } @@ -349,11 +370,16 @@ static rt_err_t _cdc_set_line_coding(udevice_t device, ureq_t setup) * * @return RT_EOK on successful. */ -static rt_err_t _interface_handler(udevice_t device, uclass_t cls, ureq_t setup) +static rt_err_t _interface_handler(ufunction_t func, ureq_t setup) { - RT_ASSERT(device != RT_NULL); + struct vcom *data; + + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); RT_ASSERT(setup != RT_NULL); + data = (struct vcom*)func->user_data; + switch(setup->request) { case CDC_SEND_ENCAPSULATED_COMMAND: @@ -367,14 +393,14 @@ static rt_err_t _interface_handler(udevice_t device, uclass_t cls, ureq_t setup) case CDC_CLEAR_COMM_FEATURE: break; case CDC_SET_LINE_CODING: - _cdc_set_line_coding(device, setup); - vcom_connected = RT_TRUE; + _cdc_set_line_coding(func->device, setup); + data->connected = RT_TRUE; break; case CDC_GET_LINE_CODING: - _cdc_get_line_coding(device, setup); + _cdc_get_line_coding(func->device, setup); break; case CDC_SET_CONTROL_LINE_STATE: - dcd_send_status(device->dcd); + dcd_ep0_send_status(func->device->dcd); break; case CDC_SEND_BREAK: break; @@ -387,92 +413,66 @@ static rt_err_t _interface_handler(udevice_t device, uclass_t cls, ureq_t setup) } /** - * This function will run cdc class, it will be called on handle set configuration request. + * This function will run cdc function, it will be called on handle set configuration request. * - * @param device the usb device object. + * @param func the usb function object. * * @return RT_EOK on successful. */ -static rt_err_t _class_run(udevice_t device, uclass_t cls) +static rt_err_t _function_enable(ufunction_t func) { - cdc_eps_t eps; - RT_ASSERT(device != RT_NULL); + struct vcom *data; - RT_DEBUG_LOG(RT_DEBUG_USB, ("cdc class run\n")); - eps = (cdc_eps_t)cls->eps; + RT_ASSERT(func != RT_NULL); - eps->ep_in->buffer = tx_buf; - eps->ep_out->buffer = rx_buf; + RT_DEBUG_LOG(RT_DEBUG_USB, ("cdc function enable\n")); - _vcom_reset_state(); - - dcd_ep_read(device->dcd, eps->ep_out, eps->ep_out->buffer, - eps->ep_out->ep_desc->wMaxPacketSize); + _vcom_reset_state(func); + + data = (struct vcom*)func->user_data; + data->ep_out->buffer = rt_malloc(CDC_RX_BUFSIZE); + data->ep_out->request.buffer = data->ep_out->buffer; + data->ep_out->request.size = EP_MAXPACKET(data->ep_out); + + data->ep_out->request.req_type = UIO_REQUEST_READ_BEST; + rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request); + return RT_EOK; } /** - * This function will stop cdc class, it will be called on handle set configuration request. + * This function will stop cdc function, it will be called on handle set configuration request. * - * @param device the usb device object. + * @param func the usb function object. * * @return RT_EOK on successful. */ -static rt_err_t _class_stop(udevice_t device, uclass_t cls) +static rt_err_t _function_disable(ufunction_t func) { - RT_ASSERT(device != RT_NULL); + struct vcom *data; - RT_DEBUG_LOG(RT_DEBUG_USB, ("cdc class stop\n")); + RT_ASSERT(func != RT_NULL); - _vcom_reset_state(); + RT_DEBUG_LOG(RT_DEBUG_USB, ("cdc function disable\n")); - return RT_EOK; -} + _vcom_reset_state(func); -/** - * This function will handle system sof event. - * - * @param device the usb device object. - * - * @return RT_EOK on successful. - */ -static rt_err_t _class_sof_handler(udevice_t device, uclass_t cls) -{ - rt_uint32_t level; - rt_size_t size; - cdc_eps_t eps; - - if (vcom_connected != RT_TRUE) - return -RT_ERROR; - - if (vcom_in_sending) + data = (struct vcom*)func->user_data; + if(data->ep_out->buffer != RT_NULL) { - return RT_EOK; + rt_free(data->ep_out->buffer); + data->ep_out->buffer = RT_NULL; } - eps = (cdc_eps_t)cls->eps; - - size = rt_ringbuffer_data_len(&tx_ringbuffer); - if (size == 0) - return -RT_EFULL; - - level = rt_hw_interrupt_disable(); - rt_ringbuffer_get(&tx_ringbuffer, eps->ep_in->buffer, size); - rt_hw_interrupt_enable(level); - - /* send data to host */ - vcom_in_sending = RT_TRUE; - dcd_ep_write(device->dcd, eps->ep_in, eps->ep_in->buffer, size); - return RT_EOK; } -static struct uclass_ops ops = +static struct ufunction_ops ops = { - _class_run, - _class_stop, - _class_sof_handler, + _function_enable, + _function_disable, + RT_NULL, }; /** @@ -483,7 +483,8 @@ static struct uclass_ops ops = * * @return RT_EOK on successful. */ -static rt_err_t _cdc_descriptor_config(ucdc_comm_desc_t comm, rt_uint8_t cintf_nr, ucdc_data_desc_t data, rt_uint8_t dintf_nr) +static rt_err_t _cdc_descriptor_config(ucdc_comm_desc_t comm, + rt_uint8_t cintf_nr, ucdc_data_desc_t data, rt_uint8_t dintf_nr) { comm->call_mgmt_desc.data_interface = dintf_nr; comm->union_desc.master_interface = cintf_nr; @@ -496,16 +497,16 @@ static rt_err_t _cdc_descriptor_config(ucdc_comm_desc_t comm, rt_uint8_t cintf_n } /** - * This function will create a cdc class instance. + * This function will create a cdc function instance. * * @param device the usb device object. * * @return RT_EOK on successful. */ -uclass_t rt_usbd_class_cdc_create(udevice_t device) +ufunction_t rt_usbd_function_cdc_create(udevice_t device) { - uclass_t cdc; - cdc_eps_t eps; + ufunction_t func; + struct vcom* data; uintf_t intf_comm, intf_data; ualtsetting_t comm_setting, data_setting; ucdc_data_desc_t data_desc; @@ -516,19 +517,26 @@ uclass_t rt_usbd_class_cdc_create(udevice_t device) /* set usb device string description */ rt_usbd_device_set_string(device, _ustring); - /* create a cdc class */ - cdc = rt_usbd_class_create(device, &dev_desc, &ops); - /* create a cdc class endpoints collection */ - eps = rt_malloc(sizeof(struct cdc_eps)); - cdc->eps = (void*)eps; + + /* create a cdc function */ + func = rt_usbd_function_new(device, &dev_desc, &ops); + rt_usbd_device_set_qualifier(device, &dev_qualifier); + + /* allocate memory for cdc vcom data */ + data = (struct vcom*)rt_malloc(sizeof(struct vcom)); + rt_memset(data, 0, sizeof(struct vcom)); + func->user_data = (void*)data; + + /* initilize vcom */ + rt_usb_vcom_init(func); /* create a cdc communication interface and a cdc data interface */ - intf_comm = rt_usbd_interface_create(device, _interface_handler); - intf_data = rt_usbd_interface_create(device, _interface_handler); + intf_comm = rt_usbd_interface_new(device, _interface_handler); + intf_data = rt_usbd_interface_new(device, _interface_handler); /* create a communication alternate setting and a data alternate setting */ - comm_setting = rt_usbd_altsetting_create(sizeof(struct ucdc_comm_descriptor)); - data_setting = rt_usbd_altsetting_create(sizeof(struct ucdc_data_descriptor)); + comm_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_comm_descriptor)); + data_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_data_descriptor)); /* config desc in alternate setting */ rt_usbd_altsetting_config_descriptor(comm_setting, &_comm_desc, @@ -537,39 +545,39 @@ uclass_t rt_usbd_class_cdc_create(udevice_t device) /* configure the cdc interface descriptor */ _cdc_descriptor_config(comm_setting->desc, intf_comm->intf_num, data_setting->desc, intf_data->intf_num); - /* create a bulk in and a bulk endpoint */ - data_desc = (ucdc_data_desc_t)data_setting->desc; - eps->ep_out = rt_usbd_endpoint_create(&data_desc->ep_out_desc, _ep_out_handler); - eps->ep_in = rt_usbd_endpoint_create(&data_desc->ep_in_desc, _ep_in_handler); - - /* add the bulk out and bulk in endpoints to the data alternate setting */ - rt_usbd_altsetting_add_endpoint(data_setting, eps->ep_in); - rt_usbd_altsetting_add_endpoint(data_setting, eps->ep_out); - - /* add the data alternate setting to the data interface - then set default setting of the interface */ - rt_usbd_interface_add_altsetting(intf_data, data_setting); - rt_usbd_set_altsetting(intf_data, 0); - - /* add the cdc data interface to cdc class */ - rt_usbd_class_add_interface(cdc, intf_data); - /* create a command endpoint */ comm_desc = (ucdc_comm_desc_t)comm_setting->desc; - eps->ep_cmd = rt_usbd_endpoint_create(&comm_desc->ep_desc, _ep_cmd_handler); + data->ep_cmd = rt_usbd_endpoint_new(&comm_desc->ep_desc, _ep_cmd_handler); /* add the command endpoint to the cdc communication interface */ - rt_usbd_altsetting_add_endpoint(comm_setting, eps->ep_cmd); + rt_usbd_altsetting_add_endpoint(comm_setting, data->ep_cmd); /* add the communication alternate setting to the communication interface, then set default setting of the interface */ rt_usbd_interface_add_altsetting(intf_comm, comm_setting); rt_usbd_set_altsetting(intf_comm, 0); - /* add the communication interface to the cdc class */ - rt_usbd_class_add_interface(cdc, intf_comm); + /* add the communication interface to the cdc function */ + rt_usbd_function_add_interface(func, intf_comm); - return cdc; + /* create a bulk in and a bulk endpoint */ + data_desc = (ucdc_data_desc_t)data_setting->desc; + data->ep_out = rt_usbd_endpoint_new(&data_desc->ep_out_desc, _ep_out_handler); + data->ep_in = rt_usbd_endpoint_new(&data_desc->ep_in_desc, _ep_in_handler); + + /* add the bulk out and bulk in endpoints to the data alternate setting */ + rt_usbd_altsetting_add_endpoint(data_setting, data->ep_in); + rt_usbd_altsetting_add_endpoint(data_setting, data->ep_out); + + /* add the data alternate setting to the data interface + then set default setting of the interface */ + rt_usbd_interface_add_altsetting(intf_data, data_setting); + rt_usbd_set_altsetting(intf_data, 0); + + /* add the cdc data interface to cdc function */ + rt_usbd_function_add_interface(func, intf_data); + + return func; } /** @@ -597,80 +605,106 @@ static rt_err_t _vcom_control(struct rt_serial_device *serial, return RT_EOK; } -static int _vcom_putc(struct rt_serial_device *serial, char c) -{ - rt_uint32_t level; - int cnt; - - if (vcom_connected != RT_TRUE) - { - return 0; - } - - /* if the buffer is full, there is a chance that the host would pull some - * data out soon. But we cannot rely on that and if we wait to long, just - * return. */ - for (cnt = 500; - rt_ringbuffer_space_len(&tx_ringbuffer) == 0 && cnt; - cnt--) - { - /*rt_kprintf("wait for %d\n", cnt);*/ - if (vcom_connected != RT_TRUE) - return 0; - } - if (cnt == 0) - { - /* OK, we believe that the connection is lost. So don't send any more - * data and act as the USB cable is not plugged in. Reset the VCOM - * state machine */ - _vcom_reset_state(); - return 0; - } - - level = rt_hw_interrupt_disable(); - if (rt_ringbuffer_space_len(&tx_ringbuffer)) - { - rt_ringbuffer_putchar(&tx_ringbuffer, c); - } - rt_hw_interrupt_enable(level); - - return 1; -} - static int _vcom_getc(struct rt_serial_device *serial) { int result; rt_uint8_t ch; rt_uint32_t level; + struct ufunction *func; + struct vcom *data; + + func = (struct ufunction*)serial->parent.user_data; + data = (struct vcom*)func->user_data; result = -1; level = rt_hw_interrupt_disable(); - if (rt_ringbuffer_data_len(&rx_ringbuffer)) + + if(rt_ringbuffer_getchar(&data->rx_ringbuffer, &ch) != 0) { - rt_ringbuffer_getchar(&rx_ringbuffer, &ch); result = ch; } + rt_hw_interrupt_enable(level); return result; } +static rt_size_t _vcom_tx(struct rt_serial_device *serial, + const char *buf, rt_size_t size) +{ + struct vcom_tx_msg msg; + + RT_ASSERT(serial != RT_NULL); + RT_ASSERT(buf != RT_NULL); + + msg.buf = buf; + msg.serial = serial; + msg.size = size; + + if (rt_mq_send(&vcom_tx_thread_mq, (void*)&msg, + sizeof(struct vcom_tx_msg)) != RT_EOK) + { + rt_kprintf("vcom send msg fail\n"); + return 0; + } + + return size; +} + static const struct rt_uart_ops usb_vcom_ops = { _vcom_configure, _vcom_control, - _vcom_putc, + RT_NULL, _vcom_getc, + RT_NULL, + //_vcom_tx, }; -void rt_usb_vcom_init(void) +/* Vcom Tx Thread */ +static void vcom_tx_thread_entry(void* parameter) { - struct serial_configure config; + struct vcom_tx_msg msg; + while (1) + { + if (rt_mq_recv(&vcom_tx_thread_mq, (void*)&msg, + sizeof(struct vcom_tx_msg), RT_WAITING_FOREVER) == RT_EOK) + { + struct ufunction *func; + struct vcom *data; + + func = (struct ufunction*)msg.serial->parent.user_data; + data = (struct vcom*)func->user_data; + if (!data->connected) + { + continue; + } + + rt_completion_init(&data->wait); + + data->ep_in->request.buffer = (void*)msg.buf; + data->ep_in->request.size = msg.size; + data->ep_in->request.req_type = UIO_REQUEST_WRITE; + rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request); + + if (rt_completion_wait(&data->wait, TX_TIMEOUT) != RT_EOK) + { + rt_kprintf("vcom tx timeout\n"); + } + } + } +} + +static void rt_usb_vcom_init(struct ufunction *func) +{ + rt_err_t result = RT_EOK; + struct serial_configure config; + struct vcom *data = (struct vcom*)func->user_data; + /* initialize ring buffer */ - rt_ringbuffer_init(&rx_ringbuffer, rx_rbp, CDC_RX_BUFSIZE); - rt_ringbuffer_init(&tx_ringbuffer, tx_rbp, CDC_TX_BUFSIZE); + rt_ringbuffer_init(&data->rx_ringbuffer, data->rx_rbp, CDC_RX_BUFSIZE); config.baud_rate = BAUD_RATE_115200; config.bit_order = BIT_ORDER_LSB; @@ -679,14 +713,25 @@ void rt_usb_vcom_init(void) config.stop_bits = STOP_BITS_1; config.invert = NRZ_NORMAL; - vcom_serial.ops = &usb_vcom_ops; - vcom_serial.int_rx = &vcom_int_rx; - vcom_serial.config = config; + data->serial.ops = &usb_vcom_ops; + data->serial.int_rx = &data->vcom_int_rx; + data->serial.config = config; /* register vcom device */ - rt_hw_serial_register(&vcom_serial, "vcom", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, - RT_NULL); + rt_hw_serial_register(&data->serial, VCOM_DEVICE, + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX, + func); + + /* create an vcom message queue */ + rt_mq_init(&vcom_tx_thread_mq, "vcomq", vcom_tx_thread_mq_pool, VCOM_MQ_MSG_SZ, + sizeof(vcom_tx_thread_mq_pool), RT_IPC_FLAG_FIFO); + + /* init usb device thread */ + rt_thread_init(&vcom_thread, "vcom", vcom_tx_thread_entry, RT_NULL, + vcom_thread_stack, 512, 8, 20); + result = rt_thread_startup(&vcom_thread); + RT_ASSERT(result == RT_EOK); } #endif + diff --git a/components/drivers/usb/usbdevice/class/mstorage.c b/components/drivers/usb/usbdevice/class/mstorage.c index b0351f63e5..4ee45189f8 100644 --- a/components/drivers/usb/usbdevice/class/mstorage.c +++ b/components/drivers/usb/usbdevice/class/mstorage.c @@ -21,7 +21,8 @@ * Date Author Notes * 2012-10-01 Yi Qiu first version * 2012-11-25 Heyuanjie87 reduce the memory consumption - * 2012-12-09 Heyuanjie87 change class and endpoint handler + * 2012-12-09 Heyuanjie87 change function and endpoint handler + * 2013-07-25 Yi Qiu update for USB CV test */ #include @@ -31,19 +32,55 @@ #ifdef RT_USB_DEVICE_MSTORAGE -#define STATUS_CBW 0x00 -#define STATUS_CSW 0x01 -#define STATUS_RECEIVE 0x02 -#define STATUS_SEND 0x03 +enum STAT +{ + STAT_CBW, + STAT_CMD, + STAT_CSW, + STAT_RECEIVE, + STAT_SEND, +}; -static int status = STATUS_CBW; -ALIGN(RT_ALIGN_SIZE) -static struct ustorage_csw csw; -static rt_device_t disk; -static rt_uint32_t _block; -static rt_uint32_t _count, _size; -static struct rt_device_blk_geometry geometry; -static rt_uint32_t _removed = 0; +typedef enum +{ + FIXED, + COUNT, + BLOCK_COUNT, +}CB_SIZE_TYPE; + +typedef enum +{ + DIR_IN, + DIR_OUT, + DIR_NONE, +}CB_DIR; + +typedef rt_size_t (*cbw_handler)(ufunction_t func, ustorage_cbw_t cbw); + +struct scsi_cmd +{ + rt_uint16_t cmd; + cbw_handler handler; + rt_size_t cmd_len; + CB_SIZE_TYPE type; + rt_size_t data_size; + CB_DIR dir; +}; + +struct mstorage +{ + struct ustorage_csw csw_response; + uep_t ep_in; + uep_t ep_out; + int status; + rt_uint32_t cb_data_size; + rt_device_t disk; + rt_uint32_t block; + rt_int32_t count; + rt_int32_t size; + struct scsi_cmd* processing; + struct rt_device_blk_geometry geometry; +}; static struct udevice_descriptor dev_desc = { @@ -63,6 +100,18 @@ static struct udevice_descriptor dev_desc = USB_DYNAMIC, //bNumConfigurations; }; +static struct usb_qualifier_descriptor dev_qualifier = +{ + sizeof(dev_qualifier), + USB_DESC_TYPE_DEVICEQUALIFIER, + 0x0200, + USB_CLASS_MASS_STORAGE, + 0x00, + 64, + 0x01, + 0, +}; + const static struct umass_descriptor _mass_desc = { USB_DESC_LENGTH_INTERFACE, //bLength; @@ -95,270 +144,489 @@ const static char* _ustring[] = "Language", "RT-Thread Team.", "RTT Mass Storage", - "1.1.0", + "320219198301", "Configuration", "Interface", }; -/** - * This function will allocate an usb device instance from system. - * - * @param parent the hub instance to which the new allocated device attached. - * @param port the hub port. - * - * @return the allocate instance on successful, or RT_NULL on failure. - */ -static rt_err_t _inquiry_cmd(udevice_t device, uep_t ep_in) +static rt_size_t _test_unit_ready(ufunction_t func, ustorage_cbw_t cbw); +static rt_size_t _request_sense(ufunction_t func, ustorage_cbw_t cbw); +static rt_size_t _inquiry_cmd(ufunction_t func, ustorage_cbw_t cbw); +static rt_size_t _allow_removal(ufunction_t func, ustorage_cbw_t cbw); +static rt_size_t _start_stop(ufunction_t func, ustorage_cbw_t cbw); +static rt_size_t _mode_sense_6(ufunction_t func, ustorage_cbw_t cbw); +static rt_size_t _read_capacities(ufunction_t func, ustorage_cbw_t cbw); +static rt_size_t _read_capacity(ufunction_t func, ustorage_cbw_t cbw); +static rt_size_t _read_10(ufunction_t func, ustorage_cbw_t cbw); +static rt_size_t _write_10(ufunction_t func, ustorage_cbw_t cbw); +static rt_size_t _verify_10(ufunction_t func, ustorage_cbw_t cbw); + +static struct scsi_cmd cmd_data[] = { - rt_uint8_t data[36]; + {SCSI_TEST_UNIT_READY, _test_unit_ready, 6, FIXED, 0, DIR_NONE}, + {SCSI_REQUEST_SENSE, _request_sense, 6, COUNT, 0, DIR_IN}, + {SCSI_INQUIRY_CMD, _inquiry_cmd, 6, COUNT, 0, DIR_IN}, + {SCSI_ALLOW_REMOVAL, _allow_removal, 6, FIXED, 0, DIR_NONE}, + {SCSI_MODE_SENSE_6, _mode_sense_6, 6, COUNT, 0, DIR_IN}, + {SCSI_START_STOP, _start_stop, 6, FIXED, 0, DIR_NONE}, + {SCSI_READ_CAPACITIES, _read_capacities, 10, COUNT, 0, DIR_NONE}, + {SCSI_READ_CAPACITY, _read_capacity, 10, FIXED, 8, DIR_IN}, + {SCSI_READ_10, _read_10, 10, BLOCK_COUNT, 0, DIR_IN}, + {SCSI_WRITE_10, _write_10, 10, BLOCK_COUNT, 0, DIR_OUT}, + {SCSI_VERIFY_10, _verify_10, 10, FIXED, 0, DIR_NONE}, +}; - *(rt_uint32_t*)&data[0] = 0x0 | (0x80 << 8); - *(rt_uint32_t*)&data[4] = 31; +static void _send_status(ufunction_t func) +{ + struct mstorage *data; - rt_memset(&data[8], 0x20, 28); - rt_memcpy(&data[8], "RTT", 3); - rt_memcpy(&data[16], "USB Disk", 8); + RT_ASSERT(func != RT_NULL); - dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 36); + RT_DEBUG_LOG(RT_DEBUG_USB, ("_send_status\n")); - return RT_EOK; + data = (struct mstorage*)func->user_data; + data->ep_in->request.buffer = (rt_uint8_t*)&data->csw_response; + data->ep_in->request.size = SIZEOF_CSW; + data->ep_in->request.req_type = UIO_REQUEST_WRITE; + rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request); + data->status = STAT_CSW; +} + +static rt_size_t _test_unit_ready(ufunction_t func, ustorage_cbw_t cbw) +{ + struct mstorage *data; + + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_test_unit_ready\n")); + + data = (struct mstorage*)func->user_data; + data->csw_response.status = 0; + + return 0; +} + +static rt_size_t _allow_removal(ufunction_t func, ustorage_cbw_t cbw) +{ + struct mstorage *data; + + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_allow_removal\n")); + + data = (struct mstorage*)func->user_data; + data->csw_response.status = 0; + + return 0; +} + +/** + * This function will handle inquiry command request. + * + * @param func the usb function object. + * @param cbw the command block wrapper. + * + * @return RT_EOK on successful. + */ + +static rt_size_t _inquiry_cmd(ufunction_t func, ustorage_cbw_t cbw) +{ + struct mstorage *data; + rt_uint8_t *buf; + + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); + RT_ASSERT(cbw != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_inquiry_cmd\n")); + + data = (struct mstorage*)func->user_data; + buf = data->ep_in->buffer; + + *(rt_uint32_t*)&buf[0] = 0x0 | (0x80 << 8); + *(rt_uint32_t*)&buf[4] = 31; + + rt_memset(&buf[8], 0x20, 28); + rt_memcpy(&buf[8], "RTT", 3); + rt_memcpy(&buf[16], "USB Disk", 8); + + data->cb_data_size = MIN(data->cb_data_size, SIZEOF_INQUIRY_CMD); + data->ep_in->request.buffer = buf; + data->ep_in->request.size = data->cb_data_size; + data->ep_in->request.req_type = UIO_REQUEST_WRITE; + rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request); + data->status = STAT_CMD; + + return data->cb_data_size; } /** * This function will handle sense request. * - * @param device the usb device object. + * @param func the usb function object. + * @param cbw the command block wrapper. * * @return RT_EOK on successful. */ -static rt_err_t _request_sense(udevice_t device, uep_t ep_in) +static rt_size_t _request_sense(ufunction_t func, ustorage_cbw_t cbw) { - struct request_sense_data data; + struct mstorage *data; + struct request_sense_data *buf; - data.ErrorCode = 0x70; - data.Valid = 0; - data.SenseKey = 2; //TODO - data.Information[0] = 0; - data.Information[1] = 0; - data.Information[2] = 0; - data.Information[3] = 0; - data.AdditionalSenseLength = 0x0a; - data.AdditionalSenseCode = 0x3a; //TODO - data.AdditionalSenseCodeQualifier =0; + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); + RT_ASSERT(cbw != RT_NULL); - dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, sizeof(struct request_sense_data)); + RT_DEBUG_LOG(RT_DEBUG_USB, ("_request_sense\n")); + + data = (struct mstorage*)func->user_data; + buf = (struct request_sense_data *)data->ep_in->buffer; - return RT_EOK; + buf->ErrorCode = 0x70; + buf->Valid = 0; + buf->SenseKey = 2; + buf->Information[0] = 0; + buf->Information[1] = 0; + buf->Information[2] = 0; + buf->Information[3] = 0; + buf->AdditionalSenseLength = 0x0a; + buf->AdditionalSenseCode = 0x3a; + buf->AdditionalSenseCodeQualifier = 0; + + data->cb_data_size = MIN(data->cb_data_size, SIZEOF_REQUEST_SENSE); + data->ep_in->request.buffer = (rt_uint8_t*)data->ep_in->buffer; + data->ep_in->request.size = data->cb_data_size; + data->ep_in->request.req_type = UIO_REQUEST_WRITE; + rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request); + data->status = STAT_CMD; + + return data->cb_data_size; } /** * This function will handle mode_sense_6 request. * - * @param device the usb device object. + * @param func the usb function object. + * @param cbw the command block wrapper. * * @return RT_EOK on successful. */ -static rt_err_t _mode_sense_6(udevice_t device, uep_t ep_in) +static rt_size_t _mode_sense_6(ufunction_t func, ustorage_cbw_t cbw) { - rt_uint8_t data[4]; + struct mstorage *data; + rt_uint8_t *buf; - data[0]=3; - data[1]=0; - data[2]=0; - data[3]=0; + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); + RT_ASSERT(cbw != RT_NULL); - dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 4); + RT_DEBUG_LOG(RT_DEBUG_USB, ("_mode_sense_6\n")); - return RT_EOK; + data = (struct mstorage*)func->user_data; + buf = data->ep_in->buffer; + buf[0] = 3; + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + + data->cb_data_size = MIN(data->cb_data_size, SIZEOF_MODE_SENSE_6); + data->ep_in->request.buffer = buf; + data->ep_in->request.size = data->cb_data_size; + data->ep_in->request.req_type = UIO_REQUEST_WRITE; + rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request); + data->status = STAT_CMD; + + return data->cb_data_size; } /** * This function will handle read_capacities request. * - * @param device the usb device object. + * @param func the usb function object. + * @param cbw the command block wrapper. * * @return RT_EOK on successful. */ -static rt_err_t _read_capacities(udevice_t device, uep_t ep_in) +static rt_size_t _read_capacities(ufunction_t func, ustorage_cbw_t cbw) { - rt_uint8_t data[12]; + struct mstorage *data; + rt_uint8_t *buf; rt_uint32_t sector_count, sector_size; - RT_ASSERT(device != RT_NULL); + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); + RT_ASSERT(cbw != RT_NULL); - sector_count = geometry.sector_count; - sector_size = geometry.bytes_per_sector; + RT_DEBUG_LOG(RT_DEBUG_USB, ("_read_capacities\n")); - *(rt_uint32_t*)&data[0] = 0x08000000; - data[4] = sector_count >> 24; - data[5] = 0xff & (sector_count >> 16); - data[6] = 0xff & (sector_count >> 8); - data[7] = 0xff & (sector_count); - data[8] = 0x02; - data[9] = 0xff & (sector_size >> 16); - data[10] = 0xff & (sector_size >> 8); - data[11] = 0xff & sector_size; + data = (struct mstorage*)func->user_data; + buf = data->ep_in->buffer; + sector_count = data->geometry.sector_count; + sector_size = data->geometry.bytes_per_sector; - dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 12); + *(rt_uint32_t*)&buf[0] = 0x08000000; + buf[4] = sector_count >> 24; + buf[5] = 0xff & (sector_count >> 16); + buf[6] = 0xff & (sector_count >> 8); + buf[7] = 0xff & (sector_count); + buf[8] = 0x02; + buf[9] = 0xff & (sector_size >> 16); + buf[10] = 0xff & (sector_size >> 8); + buf[11] = 0xff & sector_size; - return RT_EOK; + data->cb_data_size = MIN(data->cb_data_size, SIZEOF_READ_CAPACITIES); + data->ep_in->request.buffer = buf; + data->ep_in->request.size = data->cb_data_size; + data->ep_in->request.req_type = UIO_REQUEST_WRITE; + rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request); + data->status = STAT_CMD; + + return data->cb_data_size; } /** * This function will handle read_capacity request. * - * @param device the usb device object. + * @param func the usb function object. + * @param cbw the command block wapper. * * @return RT_EOK on successful. */ -static rt_err_t _read_capacity(udevice_t device, uep_t ep_in) +static rt_size_t _read_capacity(ufunction_t func, ustorage_cbw_t cbw) { - rt_uint8_t data[8]; + struct mstorage *data; + + rt_uint8_t *buf; rt_uint32_t sector_count, sector_size; - RT_ASSERT(device != RT_NULL); + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); + RT_ASSERT(cbw != RT_NULL); - sector_count = geometry.sector_count; - sector_size = geometry.bytes_per_sector; + RT_DEBUG_LOG(RT_DEBUG_USB, ("_read_capacity\n")); - data[0] = sector_count >> 24; - data[1] = 0xff & (sector_count >> 16); - data[2] = 0xff & (sector_count >> 8); - data[3] = 0xff & (sector_count); - data[4] = 0x0; - data[5] = 0xff & (sector_size >> 16); - data[6] = 0xff & (sector_size >> 8); - data[7] = 0xff & sector_size; + data = (struct mstorage*)func->user_data; + buf = data->ep_in->buffer; + sector_count = data->geometry.sector_count; + sector_size = data->geometry.bytes_per_sector; - dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 8); + buf[0] = sector_count >> 24; + buf[1] = 0xff & (sector_count >> 16); + buf[2] = 0xff & (sector_count >> 8); + buf[3] = 0xff & (sector_count); + buf[4] = 0x0; + buf[5] = 0xff & (sector_size >> 16); + buf[6] = 0xff & (sector_size >> 8); + buf[7] = 0xff & sector_size; - return RT_EOK; + data->cb_data_size = MIN(data->cb_data_size, SIZEOF_READ_CAPACITY); + data->ep_in->request.buffer = buf; + data->ep_in->request.size = data->cb_data_size; + data->ep_in->request.req_type = UIO_REQUEST_WRITE; + rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request); + data->status = STAT_CMD; + + return data->cb_data_size; } /** * This function will handle read_10 request. * - * @param device the usb device object. + * @param func the usb function object. * @param cbw the command block wrapper. * * @return RT_EOK on successful. */ -static rt_err_t _read_10(udevice_t device, ustorage_cbw_t cbw, uep_t ep_in) +static rt_size_t _read_10(ufunction_t func, ustorage_cbw_t cbw) { - RT_ASSERT(device != RT_NULL); + struct mstorage *data; + rt_size_t size; + + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); RT_ASSERT(cbw != RT_NULL); - _block = cbw->cb[2]<<24 | cbw->cb[3]<<16 | cbw->cb[4]<<8 | - cbw->cb[5]<<0 ; + data = (struct mstorage*)func->user_data; + data->block = cbw->cb[2]<<24 | cbw->cb[3]<<16 | cbw->cb[4]<<8 | + cbw->cb[5]<<0; + data->count = cbw->cb[7]<<8 | cbw->cb[8]<<0; - _count = cbw->cb[7]<<8 | cbw->cb[8]<<0 ; + RT_ASSERT(data->count < data->geometry.sector_count); - RT_ASSERT(_count < geometry.sector_count); - - rt_device_read(disk, _block, ep_in->buffer, 1); - dcd_ep_write(device->dcd, ep_in, ep_in->buffer, geometry.bytes_per_sector); - _count --; - if (_count) + data->csw_response.data_reside = data->cb_data_size; + size = rt_device_read(data->disk, data->block, data->ep_in->buffer, 1); + if(size == 0) { - _block ++; - status = STATUS_SEND; - } - else - { - status = STATUS_CSW; + rt_kprintf("read data error\n"); } - return RT_EOK; + data->ep_in->request.buffer = data->ep_in->buffer; + data->ep_in->request.size = data->geometry.bytes_per_sector; + data->ep_in->request.req_type = UIO_REQUEST_WRITE; + rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request); + data->status = STAT_SEND; + + return data->geometry.bytes_per_sector; } /** * This function will handle write_10 request. * - * @param device the usb device object. + * @param func the usb function object. * @param cbw the command block wrapper. * * @return RT_EOK on successful. */ -static rt_err_t _write_10(udevice_t device, ustorage_cbw_t cbw, uep_t ep_out) +static rt_size_t _write_10(ufunction_t func, ustorage_cbw_t cbw) { - RT_ASSERT(device != RT_NULL); + struct mstorage *data; + + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); RT_ASSERT(cbw != RT_NULL); - _block = cbw->cb[2]<<24 | cbw->cb[3]<<16 | cbw->cb[4]<<8 | - cbw->cb[5]<<0 ; - _count = cbw->cb[7]<<8 | cbw->cb[8]<<0; - csw.data_reside = cbw->xfer_len; - _size = _count * geometry.bytes_per_sector; + data = (struct mstorage*)func->user_data; - RT_DEBUG_LOG(RT_DEBUG_USB, ("_write_10 count 0x%x 0x%x\n", - _count, geometry.sector_count)); + data->block = cbw->cb[2]<<24 | cbw->cb[3]<<16 | cbw->cb[4]<<8 | + cbw->cb[5]<<0; + data->count = cbw->cb[7]<<8 | cbw->cb[8]; + data->csw_response.data_reside = cbw->xfer_len; + data->size = data->count * data->geometry.bytes_per_sector; - dcd_ep_read(device->dcd, ep_out, ep_out->buffer, geometry.bytes_per_sector); + RT_DEBUG_LOG(RT_DEBUG_USB, ("_write_10 count 0x%x block 0x%x 0x%x\n", + data->count, data->block, data->geometry.sector_count)); - return RT_EOK; + data->csw_response.data_reside = data->cb_data_size; + + data->ep_out->request.buffer = data->ep_out->buffer; + data->ep_out->request.size = data->geometry.bytes_per_sector; + data->ep_out->request.req_type = UIO_REQUEST_READ_FULL; + rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request); + data->status = STAT_RECEIVE; + + return data->geometry.bytes_per_sector; } /** * This function will handle verify_10 request. * - * @param device the usb device object. + * @param func the usb function object. * * @return RT_EOK on successful. */ -static rt_err_t _verify_10(udevice_t device) +static rt_size_t _verify_10(ufunction_t func, ustorage_cbw_t cbw) { - return RT_EOK; + struct mstorage *data; + + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_verify_10\n")); + + data = (struct mstorage*)func->user_data; + data->csw_response.status = 0; + + return 0; } -static void _send_status(udevice_t device, mass_eps_t eps, ustorage_csw_t csw) +static rt_size_t _start_stop(ufunction_t func, + ustorage_cbw_t cbw) { - dcd_ep_write(device->dcd, eps->ep_in, (rt_uint8_t*)csw, SIZEOF_CSW); - dcd_ep_read(device->dcd, eps->ep_out, eps->ep_out->buffer, SIZEOF_CBW); - status = STATUS_CBW; + struct mstorage *data; + + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_start_stop\n")); + + data = (struct mstorage*)func->user_data; + data->csw_response.status = 0; + + return 0; } -static void _start_stop(ustorage_cbw_t cbw) +static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size) { - //TODO - _removed = 1; -} + struct mstorage *data; + + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); -/** - * This function will handle mass storage bulk in endpoint request. - * - * @param device the usb device object. - * @param size request size. - * - * @return RT_EOK. - */ -static rt_err_t _ep_in_handler(udevice_t device, uclass_t cls, rt_size_t size) -{ - mass_eps_t eps; - RT_ASSERT(device != RT_NULL); + RT_DEBUG_LOG(RT_DEBUG_USB, ("_ep_in_handler\n")); + + data = (struct mstorage*)func->user_data; - eps = cls->eps; - if (status == STATUS_CSW) + switch(data->status) { - _send_status(device, eps, &csw); - } - else if (status == STATUS_SEND) - { - rt_device_read(disk, _block, eps->ep_in->buffer, 1); - dcd_ep_write(device->dcd, eps->ep_in, eps->ep_in->buffer, - geometry.bytes_per_sector); - _count --; - if (_count) + case STAT_CSW: + if(data->ep_in->request.size != SIZEOF_CSW) { - _block ++; - status = STATUS_SEND; + rt_kprintf("Size of csw command error\n"); + rt_usbd_ep_set_stall(func->device, data->ep_in); } else { - status = STATUS_CSW; + RT_DEBUG_LOG(RT_DEBUG_USB, ("return to cbw status\n")); + data->ep_out->request.buffer = data->ep_out->buffer; + data->ep_out->request.size = SIZEOF_CBW; + data->ep_out->request.req_type = UIO_REQUEST_READ_FULL; + rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request); + data->status = STAT_CBW; } - } + break; + case STAT_CMD: + if(data->csw_response.data_reside == 0xFF) + { + data->csw_response.data_reside = 0; + } + else + { + data->csw_response.data_reside -= data->ep_in->request.size; + if(data->csw_response.data_reside != 0) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("data_reside %d, request %d\n", + data->csw_response.data_reside, data->ep_in->request.size)); + if(data->processing->dir == DIR_OUT) + { + rt_usbd_ep_set_stall(func->device, data->ep_out); + } + else + { + rt_usbd_ep_set_stall(func->device, data->ep_in); + } + data->csw_response.data_reside = 0; + } + } + _send_status(func); + break; + case STAT_SEND: + data->csw_response.data_reside -= data->ep_in->request.size; + data->count--; + data->block++; + if(data->count > 0 && data->csw_response.data_reside > 0) + { + if(rt_device_read(data->disk, data->block, data->ep_in->buffer, 1) == 0) + { + rt_kprintf("disk read error\n"); + rt_usbd_ep_set_stall(func->device, data->ep_in); + return -RT_ERROR; + } - return RT_EOK; + data->ep_in->request.buffer = data->ep_in->buffer; + data->ep_in->request.size = data->geometry.bytes_per_sector; + data->ep_in->request.req_type = UIO_REQUEST_WRITE; + rt_usbd_io_request(func->device, data->ep_in, &data->ep_in->request); + } + else + { + _send_status(func); + } + break; + } + + return RT_EOK; } #ifdef MASS_CBW_DUMP @@ -376,134 +644,283 @@ static void cbw_dump(struct ustorage_cbw* cbw) } #endif -/** - * This function will handle mass storage bulk out endpoint request. - * - * @param device the usb device object. - * @param size request size. - * - * @return RT_EOK. - */ -static rt_err_t _ep_out_handler(udevice_t device, uclass_t cls, rt_size_t size) +static struct scsi_cmd* _find_cbw_command(rt_uint16_t cmd) { - mass_eps_t eps; - RT_ASSERT(device != RT_NULL); + int i; - eps = (mass_eps_t)cls->eps; - if(status == STATUS_CBW) + for(i=0; iep_out->buffer; + return RT_NULL; +} - if(cbw->signature == CBW_SIGNATURE) +static void _cb_len_calc(ufunction_t func, struct scsi_cmd* cmd, + ustorage_cbw_t cbw) +{ + struct mstorage *data; + + RT_ASSERT(func != RT_NULL); + RT_ASSERT(cmd != RT_NULL); + RT_ASSERT(cbw != RT_NULL); + + data = (struct mstorage*)func->user_data; + if(cmd->cmd_len == 6) + { + switch(cmd->type) { - csw.signature = CSW_SIGNATURE; - csw.tag = cbw->tag; - csw.data_reside = 0; - csw.status = 0; - } - else - return -RT_ERROR; - - switch(cbw->cb[0]) - { - case SCSI_TEST_UNIT_READY: - csw.status = _removed; - _send_status(device, eps, &csw); + case COUNT: + data->cb_data_size = cbw->cb[4]; break; - case SCSI_REQUEST_SENSE: - _request_sense(device, eps->ep_in); - status = STATUS_CSW; + case BLOCK_COUNT: + data->cb_data_size = cbw->cb[4] * data->geometry.bytes_per_sector; break; - case SCSI_INQUIRY_CMD: - _inquiry_cmd(device, eps->ep_in); - status = STATUS_CSW; + case FIXED: + data->cb_data_size = cmd->data_size; break; - case SCSI_MODE_SENSE_6: - _mode_sense_6(device, eps->ep_in); - status = STATUS_CSW; + default: break; - case SCSI_ALLOW_MEDIUM_REMOVAL: - _send_status(device, eps, &csw); - break; - case SCSI_READ_CAPACITIES: - _read_capacities(device, eps->ep_in); - status = STATUS_CSW; - break; - case SCSI_READ_CAPACITY: - _read_capacity(device, eps->ep_in); - status = STATUS_CSW; - break; - case SCSI_READ_10: - _read_10(device, cbw, eps->ep_in); - break; - case SCSI_WRITE_10: - _write_10(device, cbw, eps->ep_out); - status = STATUS_RECEIVE; - break; - case SCSI_VERIFY_10: - _verify_10(device); - break; - case SCSI_START_STOP: - _start_stop(cbw); - _send_status(device, eps, &csw); - break; - } + } } - else if(status == STATUS_RECEIVE) + else if(cmd->cmd_len == 10) { - RT_DEBUG_LOG(RT_DEBUG_USB, ("write size 0x%x block 0x%x oount 0x%x\n", - size, _block, _size)); - - _size -= size; - csw.data_reside -= size; - - rt_device_write(disk, _block, eps->ep_in->buffer, 1); - _block ++; - if(_size == 0) + switch(cmd->type) { - _send_status(device, eps, &csw); - } - else - { - dcd_ep_read(device->dcd, eps->ep_out, eps->ep_out->buffer, - geometry.bytes_per_sector); + case COUNT: + data->cb_data_size = cbw->cb[7]<<8 | cbw->cb[8]; + break; + case BLOCK_COUNT: + data->cb_data_size = (cbw->cb[7]<<8 | cbw->cb[8]) * + data->geometry.bytes_per_sector; + break; + case FIXED: + data->cb_data_size = cmd->data_size; + break; + default: + break; } } else { - rt_kprintf("none cbw status\n"); + rt_kprintf("cmd_len error %d\n", cmd->cmd_len); } - - return RT_EOK; } +static rt_bool_t _cbw_verify(ufunction_t func, struct scsi_cmd* cmd, + ustorage_cbw_t cbw) +{ + struct mstorage *data; + + RT_ASSERT(cmd != RT_NULL); + RT_ASSERT(cbw != RT_NULL); + RT_ASSERT(func != RT_NULL); + + data = (struct mstorage*)func->user_data; + if(cmd->cmd_len != cbw->cb_len) + { + rt_kprintf("cb_len error\n"); + cmd->cmd_len = cbw->cb_len; + } + + if(cbw->xfer_len > 0 && data->cb_data_size == 0) + { + rt_kprintf("xfer_len > 0 && data_size == 0\n"); + return RT_FALSE; + } + + if(cbw->xfer_len == 0 && data->cb_data_size > 0) + { + rt_kprintf("xfer_len == 0 && data_size > 0"); + return RT_FALSE; + } + + if((cbw->dflags & USB_DIR_IN) && cmd->dir == DIR_OUT || + !(cbw->dflags & USB_DIR_IN) && cmd->dir == DIR_IN) + { + rt_kprintf("dir error\n"); + return RT_FALSE; + } + + if(cbw->xfer_len > data->cb_data_size) + { + rt_kprintf("xfer_len > data_size\n"); + return RT_FALSE; + } + + if(cbw->xfer_len < data->cb_data_size) + { + rt_kprintf("xfer_len < data_size\n"); + data->cb_data_size = cbw->xfer_len; + data->csw_response.status = 1; + } + + return RT_TRUE; +} + +static rt_size_t _cbw_handler(ufunction_t func, struct scsi_cmd* cmd, + ustorage_cbw_t cbw) +{ + struct mstorage *data; + + RT_ASSERT(func != RT_NULL); + RT_ASSERT(cbw != RT_NULL); + RT_ASSERT(cmd->handler != RT_NULL); + + data = (struct mstorage*)func->user_data; + data->processing = cmd; + return cmd->handler(func, cbw); +} + +/** + * This function will handle mass storage bulk out endpoint request. + * + * @param func the usb function object. + * @param size request size. + * + * @return RT_EOK. + */ +static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size) +{ + struct mstorage *data; + struct scsi_cmd* cmd; + rt_size_t len; + struct ustorage_cbw* cbw; + + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_ep_out_handler %d\n", size)); + + data = (struct mstorage*)func->user_data; + cbw = (struct ustorage_cbw*)data->ep_out->buffer; + if(data->status == STAT_CBW) + { + /* dump cbw information */ + if(cbw->signature != CBW_SIGNATURE || size != SIZEOF_CBW) + { + goto exit; + } + + data->csw_response.signature = CSW_SIGNATURE; + data->csw_response.tag = cbw->tag; + data->csw_response.data_reside = cbw->xfer_len; + data->csw_response.status = 0; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("ep_out reside %d\n", data->csw_response.data_reside)); + + cmd = _find_cbw_command(cbw->cb[0]); + if(cmd == RT_NULL) + { + rt_kprintf("can't find cbw command\n"); + goto exit; + } + + _cb_len_calc(func, cmd, cbw); + if(!_cbw_verify(func, cmd, cbw)) + { + goto exit; + } + + len = _cbw_handler(func, cmd, cbw); + if(len == 0) + { + _send_status(func); + } + + return RT_EOK; + } + else if(data->status == STAT_RECEIVE) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("\nwrite size %d block 0x%x oount 0x%x\n", + size, data->block, data->size)); + + data->size -= size; + data->csw_response.data_reside -= size; + + rt_device_write(data->disk, data->block, data->ep_out->buffer, 1); + + if(data->csw_response.data_reside != 0) + { + data->ep_out->request.buffer = data->ep_out->buffer; + data->ep_out->request.size = data->geometry.bytes_per_sector; + data->ep_out->request.req_type = UIO_REQUEST_READ_FULL; + rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request); + data->block ++; + } + else + { + _send_status(func); + } + + return RT_EOK; + } + +exit: + if(data->csw_response.data_reside) + { + if(cbw->dflags & USB_DIR_IN) + { + rt_usbd_ep_set_stall(func->device, data->ep_in); + } + else + { + rt_usbd_ep_set_stall(func->device, data->ep_in); + rt_usbd_ep_set_stall(func->device, data->ep_out); + } + } + data->csw_response.status = 1; + _send_status(func); + + return -RT_ERROR; +} /** * This function will handle mass storage interface request. * - * @param device the usb device object. + * @param func the usb function object. * @param setup the setup request. * * @return RT_EOK on successful. */ -static rt_err_t _interface_handler(udevice_t device, uclass_t cls, ureq_t setup) +static rt_err_t _interface_handler(ufunction_t func, ureq_t setup) { rt_uint8_t lun = 0; - - RT_ASSERT(device != RT_NULL); + + RT_ASSERT(func != RT_NULL); + RT_ASSERT(func->device != RT_NULL); RT_ASSERT(setup != RT_NULL); - RT_DEBUG_LOG(RT_DEBUG_USB, ("_interface_handler\n")); + RT_DEBUG_LOG(RT_DEBUG_USB, ("mstorage_interface_handler\n")); switch(setup->request) { - case USBREQ_GET_MAX_LUN: - dcd_ep_write(device->dcd, 0, &lun, 1); + case USBREQ_GET_MAX_LUN: + + RT_DEBUG_LOG(RT_DEBUG_USB, ("USBREQ_GET_MAX_LUN\n")); + + if(setup->value || setup->length != 1) + { + rt_usbd_ep0_set_stall(func->device); + } + else + { + rt_usbd_ep0_write(func->device, &lun, 1); + } break; case USBREQ_MASS_STORAGE_RESET: + + RT_DEBUG_LOG(RT_DEBUG_USB, ("USBREQ_MASS_STORAGE_RESET\n")); + + if(setup->value || setup->length != 0) + { + rt_usbd_ep0_set_stall(func->device); + } + else + { + rt_usbd_ep0_write(func->device, RT_NULL, 0); + } break; default: rt_kprintf("unknown interface request\n"); @@ -514,81 +931,114 @@ static rt_err_t _interface_handler(udevice_t device, uclass_t cls, ureq_t setup) } /** - * This function will run mass storage class, it will be called on handle set configuration request. + * This function will run mass storage function, it will be called on handle set configuration request. * - * @param device the usb device object. + * @param func the usb function object. * * @return RT_EOK on successful. */ -static rt_err_t _class_run(udevice_t device, uclass_t cls) +static rt_err_t _function_enable(ufunction_t func) { - mass_eps_t eps; - rt_uint8_t *buffer; - RT_ASSERT(device != RT_NULL); + struct mstorage *data; + RT_ASSERT(func != RT_NULL); - RT_DEBUG_LOG(RT_DEBUG_USB, ("mass storage run\n")); - eps = (mass_eps_t)cls->eps; + RT_DEBUG_LOG(RT_DEBUG_USB, ("Mass storage function enabled\n")); + data = (struct mstorage*)func->user_data; - disk = rt_device_find(RT_USB_MSTORAGE_DISK_NAME); - if(disk == RT_NULL) + data->disk = rt_device_find(RT_USB_MSTORAGE_DISK_NAME); + if(data->disk == RT_NULL) { - rt_kprintf("no disk named %s\n", RT_USB_MSTORAGE_DISK_NAME); + rt_kprintf("no data->disk named %s\n", RT_USB_MSTORAGE_DISK_NAME); return -RT_ERROR; } - if(rt_device_control(disk, RT_DEVICE_CTRL_BLK_GETGEOME, (void*)&geometry) != RT_EOK) + + if(rt_device_open(data->disk, RT_DEVICE_OFLAG_RDWR) != RT_EOK) + { + rt_kprintf("disk open error\n"); return -RT_ERROR; - - buffer = (rt_uint8_t*)rt_malloc(geometry.bytes_per_sector); - if(buffer == RT_NULL) + } + + if(rt_device_control(data->disk, RT_DEVICE_CTRL_BLK_GETGEOME, + (void*)&data->geometry) != RT_EOK) + { + rt_kprintf("get disk info error\n"); + return -RT_ERROR; + } + + data->ep_in->buffer = (rt_uint8_t*)rt_malloc(data->geometry.bytes_per_sector); + if(data->ep_in->buffer == RT_NULL) + { + rt_kprintf("no memory\n"); return -RT_ENOMEM; - eps->ep_out->buffer = buffer; - eps->ep_in->buffer = buffer; - - dcd_ep_read(device->dcd, eps->ep_out, eps->ep_out->buffer, SIZEOF_CBW); - + } + data->ep_out->buffer = (rt_uint8_t*)rt_malloc(data->geometry.bytes_per_sector); + if(data->ep_out->buffer == RT_NULL) + { + rt_free(data->ep_in->buffer); + rt_kprintf("no memory\n"); + return -RT_ENOMEM; + } + + /* prepare to read CBW request */ + data->ep_out->request.buffer = data->ep_out->buffer; + data->ep_out->request.size = SIZEOF_CBW; + data->ep_out->request.req_type = UIO_REQUEST_READ_FULL; + rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request); + return RT_EOK; } /** - * This function will stop mass storage class, it will be called on handle set configuration request. + * This function will stop mass storage function, it will be called on handle set configuration request. * * @param device the usb device object. * * @return RT_EOK on successful. */ -static rt_err_t _class_stop(udevice_t device, uclass_t cls) +static rt_err_t _function_disable(ufunction_t func) { - mass_eps_t eps; - RT_ASSERT(device != RT_NULL); + struct mstorage *data; + RT_ASSERT(func != RT_NULL); - RT_DEBUG_LOG(RT_DEBUG_USB, ("mass storage stop\n")); - eps = (mass_eps_t)cls->eps; - rt_free(eps->ep_in->buffer); - eps->ep_out->buffer = RT_NULL; - eps->ep_in->buffer = RT_NULL; + RT_DEBUG_LOG(RT_DEBUG_USB, ("Mass storage function disabled\n")); + data = (struct mstorage*)func->user_data; + if(data->ep_in->buffer != RT_NULL) + { + rt_free(data->ep_in->buffer); + data->ep_in->buffer = RT_NULL; + } + + if(data->ep_out->buffer != RT_NULL) + { + rt_free(data->ep_out->buffer); + data->ep_out->buffer = RT_NULL; + } + + data->status = STAT_CBW; + return RT_EOK; } -static struct uclass_ops ops = +static struct ufunction_ops ops = { - _class_run, - _class_stop, + _function_enable, + _function_disable, RT_NULL, }; /** - * This function will create a mass storage class instance. + * This function will create a mass storage function instance. * * @param device the usb device object. * * @return RT_EOK on successful. */ -uclass_t rt_usbd_class_mstorage_create(udevice_t device) +ufunction_t rt_usbd_function_mstorage_create(udevice_t device) { uintf_t intf; - mass_eps_t eps; - uclass_t mstorage; + struct mstorage *data; + ufunction_t func; ualtsetting_t setting; umass_desc_t mass_desc; @@ -597,37 +1047,42 @@ uclass_t rt_usbd_class_mstorage_create(udevice_t device) /* set usb device string description */ rt_usbd_device_set_string(device, _ustring); - /* create a mass storage class */ - mstorage = rt_usbd_class_create(device, &dev_desc, &ops); - /* create a mass storage endpoints collection */ - eps = (mass_eps_t)rt_malloc(sizeof(struct mass_eps)); - mstorage->eps = (void*)eps; + + /* create a mass storage function */ + func = rt_usbd_function_new(device, &dev_desc, &ops); + device->dev_qualifier = &dev_qualifier; + + /* allocate memory for mass storage function data */ + data = (struct mstorage*)rt_malloc(sizeof(struct mstorage)); + rt_memset(data, 0, sizeof(struct mstorage)); + func->user_data = (void*)data; - /* create an interface */ - intf = rt_usbd_interface_create(device, _interface_handler); + /* create an interface object */ + intf = rt_usbd_interface_new(device, _interface_handler); - /* create an alternate setting */ - setting = rt_usbd_altsetting_create(sizeof(struct umass_descriptor)); + /* create an alternate setting object */ + setting = rt_usbd_altsetting_new(sizeof(struct umass_descriptor)); + /* config desc in alternate setting */ rt_usbd_altsetting_config_descriptor(setting, &_mass_desc, 0); /* create a bulk out and a bulk in endpoint */ mass_desc = (umass_desc_t)setting->desc; - eps->ep_in = rt_usbd_endpoint_create(&mass_desc->ep_in_desc, _ep_in_handler); - eps->ep_out = rt_usbd_endpoint_create(&mass_desc->ep_out_desc, _ep_out_handler); + data->ep_in = rt_usbd_endpoint_new(&mass_desc->ep_in_desc, _ep_in_handler); + data->ep_out = rt_usbd_endpoint_new(&mass_desc->ep_out_desc, _ep_out_handler); /* add the bulk out and bulk in endpoint to the alternate setting */ - rt_usbd_altsetting_add_endpoint(setting, eps->ep_out); - rt_usbd_altsetting_add_endpoint(setting, eps->ep_in); + rt_usbd_altsetting_add_endpoint(setting, data->ep_out); + rt_usbd_altsetting_add_endpoint(setting, data->ep_in); /* add the alternate setting to the interface, then set default setting */ rt_usbd_interface_add_altsetting(intf, setting); rt_usbd_set_altsetting(intf, 0); - /* add the interface to the mass storage class */ - rt_usbd_class_add_interface(mstorage, intf); + /* add the interface to the mass storage function */ + rt_usbd_function_add_interface(func, intf); - return mstorage; + return func; } #endif diff --git a/components/drivers/usb/usbdevice/class/mstorage.h b/components/drivers/usb/usbdevice/class/mstorage.h index 4d53222a00..0f448a07d5 100644 --- a/components/drivers/usb/usbdevice/class/mstorage.h +++ b/components/drivers/usb/usbdevice/class/mstorage.h @@ -59,13 +59,6 @@ struct request_sense_data rt_uint8_t Reserved4[4]; }request_sense_data_t; -struct mass_eps -{ - uep_t ep_in; - uep_t ep_out; -}; -typedef struct mass_eps* mass_eps_t; - #pragma pack() #endif diff --git a/components/drivers/usb/usbdevice/core/core.c b/components/drivers/usb/usbdevice/core/core.c index f29ee26c2e..14deb316aa 100644 --- a/components/drivers/usb/usbdevice/core/core.c +++ b/components/drivers/usb/usbdevice/core/core.c @@ -20,8 +20,10 @@ * Change Logs: * Date Author Notes * 2012-10-01 Yi Qiu first version - * 2012-12-12 heyuanjie87 change endpoint and class handler + * 2012-12-12 heyuanjie87 change endpoint and function handler * 2012-12-30 heyuanjie87 change inferface handler + * 2013-04-26 aozima add DEVICEQUALIFIER support. + * 2013-07-25 Yi Qiu update for USB CV test */ #include @@ -29,6 +31,11 @@ static rt_list_t device_list; +static rt_size_t rt_usbd_ep_write(udevice_t device, uep_t ep, void *buffer, rt_size_t size); +static rt_size_t rt_usbd_ep_read_prepare(udevice_t device, uep_t ep, void *buffer, rt_size_t size); +static rt_err_t rt_usbd_ep_assign(udevice_t device, uep_t ep); +static rt_err_t rt_usbd_ep_unassign(udevice_t device, uep_t ep); + /** * This function will handle get_device_descriptor request. * @@ -37,7 +44,7 @@ static rt_list_t device_list; * * @return RT_EOK on successful. */ -static rt_err_t _get_device_descriptor(struct udevice *device, ureq_t setup) +static rt_err_t _get_device_descriptor(struct udevice* device, ureq_t setup) { rt_size_t size; @@ -52,7 +59,8 @@ static rt_err_t _get_device_descriptor(struct udevice *device, ureq_t setup) USB_DESC_LENGTH_DEVICE : setup->length; /* send device descriptor to endpoint 0 */ - dcd_ep_write(device->dcd, 0, (rt_uint8_t *)&device->dev_desc, size); + rt_usbd_ep0_write(device, (rt_uint8_t*)&device->dev_desc, + size); return RT_EOK; } @@ -65,7 +73,7 @@ static rt_err_t _get_device_descriptor(struct udevice *device, ureq_t setup) * * @return RT_EOK on successful. */ -static rt_err_t _get_config_descriptor(struct udevice *device, ureq_t setup) +static rt_err_t _get_config_descriptor(struct udevice* device, ureq_t setup) { rt_size_t size; ucfg_desc_t cfg_desc; @@ -81,7 +89,7 @@ static rt_err_t _get_config_descriptor(struct udevice *device, ureq_t setup) cfg_desc->wTotalLength : setup->length; /* send configuration descriptor to endpoint 0 */ - dcd_ep_write(device->dcd, 0, (rt_uint8_t *)cfg_desc, size); + rt_usbd_ep0_write(device, (rt_uint8_t*)cfg_desc, size); return RT_EOK; } @@ -94,7 +102,7 @@ static rt_err_t _get_config_descriptor(struct udevice *device, ureq_t setup) * * @return RT_EOK on successful, -RT_ERROR on invalid request. */ -static rt_err_t _get_string_descriptor(struct udevice *device, ureq_t setup) +static rt_err_t _get_string_descriptor(struct udevice* device, ureq_t setup) { struct ustring_descriptor str_desc; rt_uint8_t index, i; @@ -109,14 +117,13 @@ static rt_err_t _get_string_descriptor(struct udevice *device, ureq_t setup) str_desc.type = USB_DESC_TYPE_STRING; index = setup->value & 0xFF; - if (index > USB_STRING_INTERFACE_INDEX) + if(index > USB_STRING_INTERFACE_INDEX) { rt_kprintf("unknown string index\n"); - dcd_ep_stall(device->dcd, 0); - + rt_usbd_ep0_set_stall(device); return -RT_ERROR; } - if (index == 0) + if(index == 0) { str_desc.bLength = 4; str_desc.String[0] = 0x09; @@ -127,7 +134,7 @@ static rt_err_t _get_string_descriptor(struct udevice *device, ureq_t setup) len = rt_strlen(device->str[index]); str_desc.bLength = len*2 + 2; - for (i=0; istr[index][i]; str_desc.String[i*2 + 1] = 0; @@ -140,7 +147,29 @@ static rt_err_t _get_string_descriptor(struct udevice *device, ureq_t setup) len = setup->length; /* send string descriptor to endpoint 0 */ - dcd_ep_write(device->dcd, 0, (rt_uint8_t *)&str_desc, len); + rt_usbd_ep0_write(device, (rt_uint8_t*)&str_desc, len); + + return RT_EOK; +} + +static rt_err_t _get_qualifier_descriptor(struct udevice* device, ureq_t setup) +{ + RT_DEBUG_LOG(RT_DEBUG_USB, ("_get_qualifier_descriptor\n")); + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(setup != RT_NULL); + + if(device->dev_qualifier) + { + /* send device qualifier descriptor to endpoint 0 */ + rt_usbd_ep0_write(device, (rt_uint8_t*)device->dev_qualifier, + sizeof(struct usb_qualifier_descriptor)); + } + else + { + rt_usbd_ep0_set_stall(device); + } return RT_EOK; } @@ -153,15 +182,15 @@ static rt_err_t _get_string_descriptor(struct udevice *device, ureq_t setup) * * @return RT_EOK on successful. */ -static rt_err_t _get_descriptor(struct udevice *device, ureq_t setup) +static rt_err_t _get_descriptor(struct udevice* device, ureq_t setup) { /* parameter check */ RT_ASSERT(device != RT_NULL); RT_ASSERT(setup != RT_NULL); - if (setup->request_type == USB_REQ_TYPE_DIR_IN) + if(setup->request_type == USB_REQ_TYPE_DIR_IN) { - switch (setup->value >> 8) + switch(setup->value >> 8) { case USB_DESC_TYPE_DEVICE: _get_device_descriptor(device, setup); @@ -173,18 +202,18 @@ static rt_err_t _get_descriptor(struct udevice *device, ureq_t setup) _get_string_descriptor(device, setup); break; case USB_DESC_TYPE_DEVICEQUALIFIER: - dcd_ep_stall(device->dcd, 0); + _get_qualifier_descriptor(device, setup); break; default: rt_kprintf("unsupported descriptor request\n"); - dcd_ep_stall(device->dcd, 0); + rt_usbd_ep0_set_stall(device); break; } } else { rt_kprintf("request direction error\n"); - dcd_ep_stall(device->dcd, 0); + rt_usbd_ep0_set_stall(device); } return RT_EOK; @@ -198,7 +227,7 @@ static rt_err_t _get_descriptor(struct udevice *device, ureq_t setup) * * @return RT_EOK on successful. */ -static rt_err_t _get_interface(struct udevice *device, ureq_t setup) +static rt_err_t _get_interface(struct udevice* device, ureq_t setup) { rt_uint8_t value; uintf_t intf; @@ -211,8 +240,7 @@ static rt_err_t _get_interface(struct udevice *device, ureq_t setup) if (device->state != USB_STATE_CONFIGURED) { - dcd_ep_stall(device->dcd, 0); - + rt_usbd_ep0_set_stall(device); return -RT_ERROR; } @@ -221,7 +249,7 @@ static rt_err_t _get_interface(struct udevice *device, ureq_t setup) value = intf->curr_setting->intf_desc->bAlternateSetting; /* send the interface alternate setting to endpoint 0*/ - dcd_ep_write(device->dcd, 0, &value, 1); + rt_usbd_ep0_write(device, &value, 1); return RT_EOK; } @@ -234,11 +262,11 @@ static rt_err_t _get_interface(struct udevice *device, ureq_t setup) * * @return RT_EOK on successful. */ -static rt_err_t _set_interface(struct udevice *device, ureq_t setup) +static rt_err_t _set_interface(struct udevice* device, ureq_t setup) { uintf_t intf; uep_t ep; - struct rt_list_node *i; + struct rt_list_node* i; ualtsetting_t setting; /* parameter check */ @@ -249,11 +277,10 @@ static rt_err_t _set_interface(struct udevice *device, ureq_t setup) if (device->state != USB_STATE_CONFIGURED) { - dcd_ep_stall(device->dcd, 0); - + rt_usbd_ep0_set_stall(device); return -RT_ERROR; } - + /* find the specified interface */ intf = rt_usbd_find_interface(device, setup->index & 0xFF, RT_NULL); @@ -262,13 +289,13 @@ static rt_err_t _set_interface(struct udevice *device, ureq_t setup) setting = intf->curr_setting; /* start all endpoints of the interface alternate setting */ - for (i=setting->ep_list.next; i != &setting->ep_list; i=i->next) + for(i=setting->ep_list.next; i != &setting->ep_list; i=i->next) { ep = (uep_t)rt_list_entry(i, struct uendpoint, list); - dcd_ep_stop(device->dcd, ep); - dcd_ep_run(device->dcd, ep); + dcd_ep_disable(device->dcd, ep); + dcd_ep_enable(device->dcd, ep); } - dcd_send_status(device->dcd); + dcd_ep0_send_status(device->dcd); return RT_EOK; } @@ -281,7 +308,7 @@ static rt_err_t _set_interface(struct udevice *device, ureq_t setup) * * @return RT_EOK on successful. */ -static rt_err_t _get_config(struct udevice *device, ureq_t setup) +static rt_err_t _get_config(struct udevice* device, ureq_t setup) { rt_uint8_t value; @@ -291,7 +318,7 @@ static rt_err_t _get_config(struct udevice *device, ureq_t setup) RT_ASSERT(device->curr_cfg != RT_NULL); RT_DEBUG_LOG(RT_DEBUG_USB, ("_get_config\n")); - + if (device->state == USB_STATE_CONFIGURED) { /* get current configuration */ @@ -302,7 +329,7 @@ static rt_err_t _get_config(struct udevice *device, ureq_t setup) value = 0; } /* write the current configuration to endpoint 0 */ - dcd_ep_write(device->dcd, 0, &value, 1); + rt_usbd_ep0_write(device, &value, 1); return RT_EOK; } @@ -315,7 +342,7 @@ static rt_err_t _get_config(struct udevice *device, ureq_t setup) * * @return RT_EOK on successful. */ -static rt_err_t _set_config(struct udevice *device, ureq_t setup) +static rt_err_t _set_config(struct udevice* device, ureq_t setup) { struct rt_list_node *i, *j, *k; uconfig_t cfg; @@ -331,8 +358,7 @@ static rt_err_t _set_config(struct udevice *device, ureq_t setup) if (setup->value > device->dev_desc.bNumConfigurations) { - dcd_ep_stall(device->dcd, 0); - + rt_usbd_ep0_set_stall(device); return -RT_ERROR; } @@ -348,33 +374,32 @@ static rt_err_t _set_config(struct udevice *device, ureq_t setup) rt_usbd_set_config(device, setup->value); cfg = device->curr_cfg; - for (i=cfg->cls_list.next; i!=&cfg->cls_list; i=i->next) + for (i=cfg->func_list.next; i!=&cfg->func_list; i=i->next) { - /* run all classes and their endpoints in the configuration */ - uclass_t cls = (uclass_t)rt_list_entry(i, struct uclass, list); - for (j=cls->intf_list.next; j!=&cls->intf_list; j=j->next) + /* run all functiones and their endpoints in the configuration */ + ufunction_t func = (ufunction_t)rt_list_entry(i, struct ufunction, list); + for(j=func->intf_list.next; j!=&func->intf_list; j=j->next) { intf = (uintf_t)rt_list_entry(j, struct uinterface, list); setting = intf->curr_setting; - for (k=setting->ep_list.next; k != &setting->ep_list; k=k->next) + for(k=setting->ep_list.next; k != &setting->ep_list; k=k->next) { ep = (uep_t)rt_list_entry(k, struct uendpoint, list); - /* first stop then start endpoint */ - dcd_ep_stop(device->dcd, ep); - dcd_ep_run(device->dcd, ep); + /* first disable then enable an endpoint */ + dcd_ep_disable(device->dcd, ep); + dcd_ep_enable(device->dcd, ep); } } - /* after running all endpoints, then run class */ - if (cls->ops->run != RT_NULL) - cls->ops->run(device, cls); + /* after enabled endpoints, then enable function */ + FUNC_ENABLE(func); } device->state = USB_STATE_CONFIGURED; _exit: /* issue status stage */ - dcd_send_status(device->dcd); + dcd_ep0_send_status(device->dcd); return RT_EOK; } @@ -387,38 +412,38 @@ _exit: * * @return RT_EOK on successful. */ -static rt_err_t _set_address(struct udevice *device, ureq_t setup) +static rt_err_t _set_address(struct udevice* device, ureq_t setup) { /* parameter check */ RT_ASSERT(device != RT_NULL); RT_ASSERT(setup != RT_NULL); - RT_DEBUG_LOG(RT_DEBUG_USB, ("_set_address\n")); + /* issue status stage */ + dcd_ep0_send_status(device->dcd); /* set address in device control driver */ dcd_set_address(device->dcd, setup->value); + RT_DEBUG_LOG(RT_DEBUG_USB, ("_set_address\n")); + device->state = USB_STATE_ADDRESS; - /* issue status stage */ - dcd_send_status(device->dcd); - return RT_EOK; } /** - * This function will handle standard request to - * interface that defined in class-specifics + * This function will handle standard request to + * interface that defined in function-specifics * * @param device the usb device object. * @param setup the setup request. * - * @return RT_EOK on successful. + * @return RT_EOK on successful. */ -static rt_err_t _request_interface(struct udevice *device, ureq_t setup) +static rt_err_t _request_interface(struct udevice* device, ureq_t setup) { uintf_t intf; - uclass_t cls; + ufunction_t func; rt_err_t ret; /* parameter check */ @@ -427,16 +452,16 @@ static rt_err_t _request_interface(struct udevice *device, ureq_t setup) RT_DEBUG_LOG(RT_DEBUG_USB, ("_request_interface\n")); - intf = rt_usbd_find_interface(device, setup->index & 0xFF, &cls); + intf = rt_usbd_find_interface(device, setup->index & 0xFF, &func); if (intf != RT_NULL) { - ret = intf->handler(device, cls, setup); + ret = intf->handler(func, setup); } else { ret = -RT_ERROR; } - + return ret; } @@ -448,7 +473,7 @@ static rt_err_t _request_interface(struct udevice *device, ureq_t setup) * * @return RT_EOK on successful. */ -static rt_err_t _standard_request(struct udevice *device, ureq_t setup) +static rt_err_t _standard_request(struct udevice* device, ureq_t setup) { udcd_t dcd; rt_uint16_t value = 0; @@ -459,20 +484,20 @@ static rt_err_t _standard_request(struct udevice *device, ureq_t setup) dcd = device->dcd; - switch (setup->request_type & USB_REQ_TYPE_RECIPIENT_MASK) + switch(setup->request_type & USB_REQ_TYPE_RECIPIENT_MASK) { case USB_REQ_TYPE_DEVICE: - switch (setup->request) + switch(setup->request) { case USB_REQ_GET_STATUS: - dcd_ep_write(device->dcd, 0, &value, 2); + rt_usbd_ep0_write(device, &value, 2); break; case USB_REQ_CLEAR_FEATURE: - dcd_clear_feature(dcd, setup->value, setup->index); - dcd_send_status(dcd); + rt_usbd_clear_feature(device, setup->value, setup->index); + dcd_ep0_send_status(dcd); break; case USB_REQ_SET_FEATURE: - dcd_set_feature(dcd, setup->value, setup->index); + rt_usbd_set_feature(device, setup->value, setup->index); break; case USB_REQ_SET_ADDRESS: _set_address(device, setup); @@ -481,7 +506,7 @@ static rt_err_t _standard_request(struct udevice *device, ureq_t setup) _get_descriptor(device, setup); break; case USB_REQ_SET_DESCRIPTOR: - dcd_ep_stall(dcd, 0); + rt_usbd_ep0_set_stall(device); break; case USB_REQ_GET_CONFIGURATION: _get_config(device, setup); @@ -491,12 +516,12 @@ static rt_err_t _standard_request(struct udevice *device, ureq_t setup) break; default: rt_kprintf("unknown device request\n"); - dcd_ep_stall(device->dcd, 0); + rt_usbd_ep0_set_stall(device); break; } break; case USB_REQ_TYPE_INTERFACE: - switch (setup->request) + switch(setup->request) { case USB_REQ_GET_INTERFACE: _get_interface(device, setup); @@ -508,8 +533,7 @@ static rt_err_t _standard_request(struct udevice *device, ureq_t setup) if (_request_interface(device, setup) != RT_EOK) { rt_kprintf("unknown interface request\n"); - dcd_ep_stall(device->dcd, 0); - + rt_usbd_ep0_set_stall(device); return - RT_ERROR; } else @@ -517,53 +541,69 @@ static rt_err_t _standard_request(struct udevice *device, ureq_t setup) } break; case USB_REQ_TYPE_ENDPOINT: - switch (setup->request) + switch(setup->request) { case USB_REQ_GET_STATUS: { - /* TODO */ uep_t ep; ep = rt_usbd_find_endpoint(device, RT_NULL, setup->index); - value = ep->is_stall; - dcd_ep_write(dcd, 0, &value, 2); + value = ep->stalled; + rt_usbd_ep0_write(device, &value, 2); } break; case USB_REQ_CLEAR_FEATURE: { uep_t ep; - + uio_request_t req; + struct rt_list_node *node; + ep = rt_usbd_find_endpoint(device, RT_NULL, setup->index); - ep->is_stall = 0; - dcd_clear_feature(dcd, setup->value, setup->index); - dcd_send_status(dcd); + if(USB_EP_HALT == setup->value && ep->stalled == RT_TRUE) + { + rt_usbd_clear_feature(device, setup->value, setup->index); + dcd_ep0_send_status(dcd); + ep->stalled = RT_FALSE; + + for (node = ep->request_list.next; node != &ep->request_list; node = node->next) + { + req = (uio_request_t)rt_list_entry(node, struct uio_request, list); + rt_usbd_io_request(device, ep, req); + RT_DEBUG_LOG(RT_DEBUG_USB, ("fired a request\n")); + } + + rt_list_init(&ep->request_list); + } } break; case USB_REQ_SET_FEATURE: { uep_t ep; - - ep = rt_usbd_find_endpoint(device, RT_NULL, setup->index); - ep->is_stall = 1; - dcd_set_feature(dcd, setup->value, setup->index); - dcd_send_status(dcd); + + if(USB_EP_HALT == setup->value) + { + ep = rt_usbd_find_endpoint(device, RT_NULL, setup->index); + ep->stalled = RT_TRUE; + rt_usbd_set_feature(device, setup->value, setup->index); + dcd_ep0_send_status(dcd); + } } break; case USB_REQ_SYNCH_FRAME: break; default: rt_kprintf("unknown endpoint request\n"); - dcd_ep_stall(device->dcd, 0); + rt_usbd_ep0_set_stall(device); break; } break; case USB_REQ_TYPE_OTHER: rt_kprintf("unknown other type request\n"); - dcd_ep_stall(device->dcd, 0); + rt_usbd_ep0_set_stall(device); break; default: rt_kprintf("unknown type request\n"); - dcd_ep_stall(device->dcd, 0); + rt_usbd_ep0_set_stall(device); break; } @@ -571,47 +611,68 @@ static rt_err_t _standard_request(struct udevice *device, ureq_t setup) } /** - * This function will handle class request. + * This function will handle function request. * * @param device the usb device object. * @param setup the setup request. * * @return RT_EOK on successful, -RT_ERROR on invalid request. */ -static rt_err_t _class_request(udevice_t device, ureq_t setup) +static rt_err_t _function_request(udevice_t device, ureq_t setup) { uintf_t intf; - uclass_t cls; + ufunction_t func; /* parameter check */ RT_ASSERT(device != RT_NULL); RT_ASSERT(setup != RT_NULL); /* verify request value */ - if (setup->index > device->curr_cfg->cfg_desc.bNumInterfaces) + if(setup->index > device->curr_cfg->cfg_desc.bNumInterfaces) { - dcd_ep_stall(device->dcd, 0); - + rt_usbd_ep0_set_stall(device); return -RT_ERROR; } - switch (setup->request_type & USB_REQ_TYPE_RECIPIENT_MASK) + switch(setup->request_type & USB_REQ_TYPE_RECIPIENT_MASK) { case USB_REQ_TYPE_INTERFACE: - intf = rt_usbd_find_interface(device, setup->index & 0xFF, &cls); - intf->handler(device, cls, setup); + intf = rt_usbd_find_interface(device, setup->index & 0xFF, &func); + if(intf == RT_NULL) + { + rt_kprintf("unkwown interface request\n"); + rt_usbd_ep0_set_stall(device); + } + else + { + intf->handler(func, setup); + } break; case USB_REQ_TYPE_ENDPOINT: break; default: - rt_kprintf("unknown class request type\n"); - dcd_ep_stall(device->dcd, 0); + rt_kprintf("unknown function request type\n"); + rt_usbd_ep0_set_stall(device); break; } return RT_EOK; } +static rt_err_t _dump_setup_packet(ureq_t setup) +{ + RT_DEBUG_LOG(RT_DEBUG_USB, ("[\n")); + RT_DEBUG_LOG(RT_DEBUG_USB, ("setup_request 0x%x\n", + setup->request_type)); + RT_DEBUG_LOG(RT_DEBUG_USB, ("value 0x%x\n", setup->value)); + RT_DEBUG_LOG(RT_DEBUG_USB, ("length 0x%x\n", setup->length)); + RT_DEBUG_LOG(RT_DEBUG_USB, ("index 0x%x\n", setup->index)); + RT_DEBUG_LOG(RT_DEBUG_USB, ("request 0x%x\n", setup->request)); + RT_DEBUG_LOG(RT_DEBUG_USB, ("]\n")); + + return RT_EOK; +} + /** * This function will handle setup request. * @@ -626,29 +687,22 @@ static rt_err_t _setup_request(udevice_t device, ureq_t setup) RT_ASSERT(device != RT_NULL); RT_ASSERT(setup != RT_NULL); - RT_DEBUG_LOG(RT_DEBUG_USB, ("[\n")); - RT_DEBUG_LOG(RT_DEBUG_USB, ("setup_request_handler 0x%x\n", - setup->request_type)); - RT_DEBUG_LOG(RT_DEBUG_USB, ("value 0x%x\n", setup->value)); - RT_DEBUG_LOG(RT_DEBUG_USB, ("length 0x%x\n", setup->length)); - RT_DEBUG_LOG(RT_DEBUG_USB, ("index 0x%x\n", setup->index)); - RT_DEBUG_LOG(RT_DEBUG_USB, ("request 0x%x\n", setup->request)); - RT_DEBUG_LOG(RT_DEBUG_USB, ("]\n")); + _dump_setup_packet(setup); - switch ((setup->request_type & USB_REQ_TYPE_MASK)) + switch((setup->request_type & USB_REQ_TYPE_MASK)) { case USB_REQ_TYPE_STANDARD: _standard_request(device, setup); break; case USB_REQ_TYPE_CLASS: - _class_request(device, setup); + _function_request(device, setup); break; case USB_REQ_TYPE_VENDOR: rt_kprintf("vendor type request\n"); break; default: rt_kprintf("unknown setup request type\n"); - dcd_ep_stall(device->dcd, 0); + rt_usbd_ep0_set_stall(device); return -RT_ERROR; } @@ -656,104 +710,207 @@ static rt_err_t _setup_request(udevice_t device, ureq_t setup) } /** - * This function will notity sof event to all of class. + * This function will hanle data notify event. * - * @param device the usb device object. + * @param device the usb device object. + * @param ep_msg the endpoint message. * * @return RT_EOK. */ -rt_err_t _sof_notify(udevice_t device) +static rt_err_t _data_notify(udevice_t device, struct ep_msg* ep_msg) { - struct rt_list_node *i; - uclass_t cls; - + uep_t ep; + ufunction_t func; + rt_size_t size = 0; + RT_ASSERT(device != RT_NULL); - - /* to notity every class that sof event comes */ - for (i = device->curr_cfg->cls_list.next; - i != &device->curr_cfg->cls_list; - i = i->next) + RT_ASSERT(ep_msg != RT_NULL); + + if (device->state != USB_STATE_CONFIGURED) { - cls = (uclass_t)rt_list_entry(i, struct uclass, list); - if (cls->ops->sof_handler != RT_NULL) - cls->ops->sof_handler(device, cls); + return -RT_ERROR; + } + + ep = rt_usbd_find_endpoint(device, &func, ep_msg->ep_addr); + if(ep == RT_NULL) + { + rt_kprintf("invalid endpoint\n"); + return -RT_ERROR; + } + + if(EP_ADDRESS(ep) & USB_DIR_IN) + { + if(ep->request.remain_size >= EP_MAXPACKET(ep)) + { + dcd_ep_write(device->dcd, EP_ADDRESS(ep), + ep->request.buffer, EP_MAXPACKET(ep)); + ep->request.remain_size -= EP_MAXPACKET(ep); + ep->request.buffer += EP_MAXPACKET(ep); + } + else if(ep->request.remain_size > 0) + { + dcd_ep_write(device->dcd, EP_ADDRESS(ep), + ep->request.buffer, ep->request.remain_size); + ep->request.remain_size = 0; + } + else + { + EP_HANDLER(ep, func, size); + } + } + else + { + size = ep_msg->size; + if(ep->request.remain_size == 0) + { + return RT_EOK; + } + + if(size == 0) + { + size = dcd_ep_read(device->dcd, EP_ADDRESS(ep), + ep->request.buffer); + } + ep->request.remain_size -= size; + ep->request.buffer += size; + + if(ep->request.req_type == UIO_REQUEST_READ_BEST) + { + EP_HANDLER(ep, func, size); + } + else if(ep->request.remain_size == 0) + { + EP_HANDLER(ep, func, ep->request.size); + } + } + + return RT_EOK; +} + +static rt_err_t _ep0_out_notify(udevice_t device, struct ep_msg* ep_msg) +{ + uep_t ep0; + rt_size_t size; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(ep_msg != RT_NULL); + RT_ASSERT(device->dcd != RT_NULL); + + ep0 = &device->dcd->ep0; + size = ep_msg->size; + if(ep0->request.remain_size == 0) + { + return RT_EOK; + } + if(size == 0) + { + size = dcd_ep_read(device->dcd, EP0_OUT_ADDR, ep0->request.buffer); + if(size == 0) + { + return RT_EOK; + } + } + + ep0->request.remain_size -= size; + ep0->request.buffer += size; + if(ep0->request.remain_size == 0) + { + /* invoke callback */ + if(ep0->rx_indicate != RT_NULL) + { + ep0->rx_indicate(device, size); + } } return RT_EOK; } /** - * This function will stop all class. + * This function will notity sof event to all of function. * * @param device the usb device object. * * @return RT_EOK. */ -rt_err_t _stop_notify(udevice_t device) +static rt_err_t _sof_notify(udevice_t device) { struct rt_list_node *i; - uclass_t cls; + ufunction_t func; RT_ASSERT(device != RT_NULL); - /* to notity every class that sof event comes */ - for (i = device->curr_cfg->cls_list.next; - i != &device->curr_cfg->cls_list; - i = i->next) + /* to notity every function that sof event comes */ + for (i=device->curr_cfg->func_list.next; + i!=&device->curr_cfg->func_list; i=i->next) { - cls = (uclass_t)rt_list_entry(i, struct uclass, list); - if (cls->ops->stop != RT_NULL) - cls->ops->stop(device, cls); + func = (ufunction_t)rt_list_entry(i, struct ufunction, list); + if(func->ops->sof_handler != RT_NULL) + func->ops->sof_handler(func); } return RT_EOK; } /** - * This function will run all class. + * This function will disable all USB functions. * * @param device the usb device object. * * @return RT_EOK. */ -rt_err_t _run_notify(udevice_t device) +static rt_err_t _stop_notify(udevice_t device) { struct rt_list_node *i; - uclass_t cls; + ufunction_t func; RT_ASSERT(device != RT_NULL); - /* to notity every class that sof event comes */ - for (i = device->curr_cfg->cls_list.next; - i != &device->curr_cfg->cls_list; + /* to notity every function */ + for (i = device->curr_cfg->func_list.next; + i != &device->curr_cfg->func_list; i = i->next) { - cls = (uclass_t)rt_list_entry(i, struct uclass, list); - if (cls->ops->run != RT_NULL) - cls->ops->run(device, cls); + func = (ufunction_t)rt_list_entry(i, struct ufunction, list); + FUNC_DISABLE(func); } return RT_EOK; } -/** - * This function will reset all class. - * - * @param device the usb device object. - * - * @return RT_EOK. - */ -rt_err_t _reset_notify(udevice_t device) +static rt_size_t rt_usbd_ep_write(udevice_t device, uep_t ep, void *buffer, rt_size_t size) { - struct rt_list_node *i; - uclass_t cls; + rt_uint16_t maxpacket; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(device->dcd != RT_NULL); + RT_ASSERT(ep != RT_NULL); - RT_ASSERT(device != RT_NULL); + maxpacket = EP_MAXPACKET(ep); + if(ep->request.remain_size >= maxpacket) + { + dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, maxpacket); + ep->request.remain_size -= maxpacket; + ep->request.buffer += maxpacket; + } + else + { + dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, + ep->request.remain_size); + ep->request.remain_size = 0; + } - _stop_notify(device); - _run_notify(device); + return size; +} - return RT_EOK; +static rt_size_t rt_usbd_ep_read_prepare(udevice_t device, uep_t ep, void *buffer, rt_size_t size) +{ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(device->dcd != RT_NULL); + RT_ASSERT(ep != RT_NULL); + RT_ASSERT(buffer != RT_NULL); + RT_ASSERT(ep->ep_desc != RT_NULL); + + return dcd_ep_read_prepare(device->dcd, EP_ADDRESS(ep), buffer, size); } /** @@ -763,18 +920,17 @@ rt_err_t _reset_notify(udevice_t device) * * @return an usb device object on success, RT_NULL on fail. */ -udevice_t rt_usbd_device_create(void) +udevice_t rt_usbd_device_new(void) { udevice_t udevice; - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_device_create\n")); + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_device_new\n")); /* allocate memory for the object */ udevice = rt_malloc(sizeof(struct udevice)); - if (udevice == RT_NULL) + if(udevice == RT_NULL) { rt_kprintf("alloc memery failed\n"); - return RT_NULL; } rt_memset(udevice, 0, sizeof(struct udevice)); @@ -783,7 +939,7 @@ udevice_t rt_usbd_device_create(void) rt_list_init(&udevice->cfg_list); /* insert the device object to device list */ - rt_list_insert_after(&device_list, &udevice->list); + rt_list_insert_before(&device_list, &udevice->list); return udevice; } @@ -791,7 +947,7 @@ udevice_t rt_usbd_device_create(void) /** * This function will set usb device string description. * - * @param device the usb device object. + * @param device the usb device object. * @param ustring pointer to string pointer array. * * @return RT_EOK. @@ -808,6 +964,17 @@ rt_err_t rt_usbd_device_set_string(udevice_t device, const char** ustring) return RT_EOK; } +rt_err_t rt_usbd_device_set_qualifier(udevice_t device, struct usb_qualifier_descriptor* qualifier) +{ + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(qualifier != RT_NULL); + + device->dev_qualifier = qualifier; + + return RT_EOK; +} + /** * This function will set an usb controller driver to a device. * @@ -855,31 +1022,30 @@ rt_err_t rt_usbd_device_set_descriptor(udevice_t device, udev_desc_t dev_desc) * * @return an usb configuration object. */ -uconfig_t rt_usbd_config_create(void) +uconfig_t rt_usbd_config_new(void) { uconfig_t cfg; - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_config_create\n")); + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_config_new\n")); /* allocate memory for the object */ cfg = rt_malloc(sizeof(struct uconfig)); - if (cfg == RT_NULL) + if(cfg == RT_NULL) { rt_kprintf("alloc memery failed\n"); - return RT_NULL; } rt_memset(cfg, 0, sizeof(struct uconfig)); /* set default value */ - cfg->cfg_desc.bLength = USB_DESC_LENGTH_CONFIG; - cfg->cfg_desc.type = USB_DESC_TYPE_CONFIGURATION; + cfg->cfg_desc.bLength = USB_DESC_LENGTH_CONFIG; + cfg->cfg_desc.type = USB_DESC_TYPE_CONFIGURATION; cfg->cfg_desc.wTotalLength = USB_DESC_LENGTH_CONFIG; cfg->cfg_desc.bmAttributes = 0xC0; - cfg->cfg_desc.MaxPower = 0x32; + cfg->cfg_desc.MaxPower = 0x32; - /* to initialize class object list */ - rt_list_init(&cfg->cls_list); + /* to initialize function object list */ + rt_list_init(&cfg->func_list); return cfg; } @@ -892,21 +1058,20 @@ uconfig_t rt_usbd_config_create(void) * * @return an usb interface object on success, RT_NULL on fail. */ -uintf_t rt_usbd_interface_create(udevice_t device, uintf_handler_t handler) +uintf_t rt_usbd_interface_new(udevice_t device, uintf_handler_t handler) { uintf_t intf; - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_interface_create\n")); + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_interface_new\n")); /* parameter check */ RT_ASSERT(device != RT_NULL); /* allocate memory for the object */ intf = (uintf_t)rt_malloc(sizeof(struct uinterface)); - if (intf == RT_NULL) + if(intf == RT_NULL) { rt_kprintf("alloc memery failed\n"); - return RT_NULL; } intf->intf_num = device->nr_intf; @@ -928,21 +1093,20 @@ uintf_t rt_usbd_interface_create(udevice_t device, uintf_handler_t handler) * * @return an usb alternate setting object on success, RT_NULL on fail. */ -ualtsetting_t rt_usbd_altsetting_create(rt_size_t desc_size) +ualtsetting_t rt_usbd_altsetting_new(rt_size_t desc_size) { ualtsetting_t setting; - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_altsetting_create\n")); + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_altsetting_new\n")); /* parameter check */ RT_ASSERT(desc_size > 0); /* allocate memory for the object */ setting = (ualtsetting_t)rt_malloc(sizeof(struct ualtsetting)); - if (setting == RT_NULL) + if(setting == RT_NULL) { rt_kprintf("alloc memery failed\n"); - return RT_NULL; } /* allocate memory for the desc */ @@ -951,7 +1115,6 @@ ualtsetting_t rt_usbd_altsetting_create(rt_size_t desc_size) { rt_kprintf("alloc desc memery failed\n"); rt_free(setting); - return RT_NULL; } @@ -973,56 +1136,53 @@ ualtsetting_t rt_usbd_altsetting_create(rt_size_t desc_size) * * @return RT_EOK. */ -rt_err_t rt_usbd_altsetting_config_descriptor(ualtsetting_t setting, - const void *desc, - rt_off_t intf_pos) +rt_err_t rt_usbd_altsetting_config_descriptor(ualtsetting_t setting, const void* desc, rt_off_t intf_pos) { RT_ASSERT(setting != RT_NULL); RT_ASSERT(setting->desc !=RT_NULL); rt_memcpy(setting->desc, desc, setting->desc_size); - setting->intf_desc = (uintf_desc_t)((char *)setting->desc + intf_pos); + setting->intf_desc = (uintf_desc_t)((char*)setting->desc + intf_pos); return RT_EOK; } /** - * This function will create an usb class object. + * This function will create an usb function object. * * @param device the usb device object. * @param dev_desc the device descriptor. * @param ops the operation set. * - * @return an usb class object on success, RT_NULL on fail. + * @return an usb function object on success, RT_NULL on fail. */ -uclass_t rt_usbd_class_create(udevice_t device, - udev_desc_t dev_desc, - uclass_ops_t ops) +ufunction_t rt_usbd_function_new(udevice_t device, udev_desc_t dev_desc, + ufunction_ops_t ops) { - uclass_t cls; + ufunction_t func; - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_class_create\n")); + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_function_new\n")); /* parameter check */ RT_ASSERT(device != RT_NULL); RT_ASSERT(dev_desc != RT_NULL); /* allocate memory for the object */ - cls = (uclass_t)rt_malloc(sizeof(struct uclass)); - if (cls == RT_NULL) + func = (ufunction_t)rt_malloc(sizeof(struct ufunction)); + if(func == RT_NULL) { rt_kprintf("alloc memery failed\n"); - return RT_NULL; } - cls->dev_desc = dev_desc; - cls->ops = ops; - cls->device = device; + func->dev_desc = dev_desc; + func->ops = ops; + func->device = device; + func->enabled = RT_FALSE; /* to initialize interface list */ - rt_list_init(&cls->intf_list); + rt_list_init(&func->intf_list); - return cls; + return func; } /** @@ -1033,26 +1193,27 @@ uclass_t rt_usbd_class_create(udevice_t device, * * @return an usb endpoint object on success, RT_NULL on fail. */ -uep_t rt_usbd_endpoint_create(uep_desc_t ep_desc, udep_handler_t handler) +uep_t rt_usbd_endpoint_new(uep_desc_t ep_desc, udep_handler_t handler) { uep_t ep; - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_endpoint_create\n")); + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_endpoint_new\n")); /* parameter check */ RT_ASSERT(ep_desc != RT_NULL); /* allocate memory for the object */ ep = (uep_t)rt_malloc(sizeof(struct uendpoint)); - if (ep == RT_NULL) + if(ep == RT_NULL) { rt_kprintf("alloc memery failed\n"); - return RT_NULL; } ep->ep_desc = ep_desc; ep->handler = handler; ep->buffer = RT_NULL; + ep->stalled = RT_FALSE; + rt_list_init(&ep->request_list); return ep; } @@ -1066,7 +1227,7 @@ uep_t rt_usbd_endpoint_create(uep_desc_t ep_desc, udep_handler_t handler) */ udevice_t rt_usbd_find_device(udcd_t dcd) { - struct rt_list_node *node; + struct rt_list_node* node; udevice_t device; /* parameter check */ @@ -1076,12 +1237,10 @@ udevice_t rt_usbd_find_device(udcd_t dcd) for (node = device_list.next; node != &device_list; node = node->next) { device = (udevice_t)rt_list_entry(node, struct udevice, list); - if (device->dcd == dcd) - return device; + if(device->dcd == dcd) return device; } rt_kprintf("can't find device\n"); - return RT_NULL; } @@ -1095,7 +1254,7 @@ udevice_t rt_usbd_find_device(udcd_t dcd) */ uconfig_t rt_usbd_find_config(udevice_t device, rt_uint8_t value) { - struct rt_list_node *node; + struct rt_list_node* node; uconfig_t cfg = RT_NULL; RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_find_config\n")); @@ -1105,17 +1264,16 @@ uconfig_t rt_usbd_find_config(udevice_t device, rt_uint8_t value) RT_ASSERT(value <= device->dev_desc.bNumConfigurations); /* search a configration in the the device */ - for (node = device->cfg_list.next; - node != &device->cfg_list; - node = node->next) + for (node = device->cfg_list.next; node != &device->cfg_list; node = node->next) { cfg = (uconfig_t)rt_list_entry(node, struct udevice, list); - if (cfg->cfg_desc.bConfigurationValue == value) + if(cfg->cfg_desc.bConfigurationValue == value) + { return cfg; + } } rt_kprintf("can't find configuration %d\n", value); - return RT_NULL; } @@ -1127,12 +1285,10 @@ uconfig_t rt_usbd_find_config(udevice_t device, rt_uint8_t value) * * @return an usb configuration object on found or RT_NULL on not found. */ -uintf_t rt_usbd_find_interface(udevice_t device, - rt_uint8_t value, - uclass_t *pcls) +uintf_t rt_usbd_find_interface(udevice_t device, rt_uint8_t value, ufunction_t *pfunc) { struct rt_list_node *i, *j; - uclass_t cls; + ufunction_t func; uintf_t intf; RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_find_interface\n")); @@ -1142,26 +1298,23 @@ uintf_t rt_usbd_find_interface(udevice_t device, RT_ASSERT(value < device->nr_intf); /* search an interface in the current configuration */ - for (i = device->curr_cfg->cls_list.next; - i != &device->curr_cfg->cls_list; - i = i->next) + for (i=device->curr_cfg->func_list.next; + i!=&device->curr_cfg->func_list; i=i->next) { - cls = (uclass_t)rt_list_entry(i, struct uclass, list); - for (j=cls->intf_list.next; j!=&cls->intf_list; j=j->next) + func = (ufunction_t)rt_list_entry(i, struct ufunction, list); + for(j=func->intf_list.next; j!=&func->intf_list; j=j->next) { intf = (uintf_t)rt_list_entry(j, struct uinterface, list); - if (intf->intf_num == value) + if(intf->intf_num == value) { - if (pcls != RT_NULL) - *pcls = cls; - + if (pfunc != RT_NULL) + *pfunc = func; return intf; } } } rt_kprintf("can't find interface %d\n", value); - return RT_NULL; } @@ -1183,23 +1336,22 @@ ualtsetting_t rt_usbd_find_altsetting(uintf_t intf, rt_uint8_t value) /* parameter check */ RT_ASSERT(intf != RT_NULL); - if (intf->curr_setting != RT_NULL) + if(intf->curr_setting != RT_NULL) { /* if the value equal to the current alternate setting, then do not search */ - if (intf->curr_setting->intf_desc->bAlternateSetting == value) + if(intf->curr_setting->intf_desc->bAlternateSetting == value) return intf->curr_setting; } /* search a setting in the alternate setting list */ - for (i=intf->setting_list.next; i!=&intf->setting_list; i=i->next) + for(i=intf->setting_list.next; i!=&intf->setting_list; i=i->next) { setting =(ualtsetting_t)rt_list_entry(i, struct ualtsetting, list); - if (setting->intf_desc->bAlternateSetting == value) + if(setting->intf_desc->bAlternateSetting == value) return setting; } rt_kprintf("can't find alternate setting %d\n", value); - return RT_NULL; } @@ -1211,37 +1363,32 @@ ualtsetting_t rt_usbd_find_altsetting(uintf_t intf, rt_uint8_t value) * * @return an usb endpoint object on found or RT_NULL on not found. */ -uep_t rt_usbd_find_endpoint(udevice_t device, - uclass_t *pcls, - rt_uint8_t ep_addr) +uep_t rt_usbd_find_endpoint(udevice_t device, ufunction_t* pfunc, rt_uint8_t ep_addr) { uep_t ep; struct rt_list_node *i, *j, *k; - uclass_t cls; + ufunction_t func; uintf_t intf; /* parameter check */ RT_ASSERT(device != RT_NULL); /* search a endpoint in the current configuration */ - for (i = device->curr_cfg->cls_list.next; - i != &device->curr_cfg->cls_list; - i = i->next) + for (i=device->curr_cfg->func_list.next; + i!=&device->curr_cfg->func_list; i=i->next) { - cls = (uclass_t)rt_list_entry(i, struct uclass, list); - for (j=cls->intf_list.next; j!=&cls->intf_list; j=j->next) + func = (ufunction_t)rt_list_entry(i, struct ufunction, list); + for(j=func->intf_list.next; j!=&func->intf_list; j=j->next) { intf = (uintf_t)rt_list_entry(j, struct uinterface, list); - for (k = intf->curr_setting->ep_list.next; - k != &intf->curr_setting->ep_list; - k = k->next) + for(k=intf->curr_setting->ep_list.next; + k!=&intf->curr_setting->ep_list; k=k->next) { ep = (uep_t)rt_list_entry(k, struct uendpoint, list); - if (ep->ep_desc->bEndpointAddress == ep_addr) + if(EP_ADDRESS(ep) == ep_addr) { - if (pcls != RT_NULL) - *pcls = cls; - + if (pfunc != RT_NULL) + *pfunc = func; return ep; } } @@ -1249,7 +1396,6 @@ uep_t rt_usbd_find_endpoint(udevice_t device, } rt_kprintf("can't find endpoint 0x%x\n", ep_addr); - return RT_NULL; } @@ -1264,7 +1410,7 @@ uep_t rt_usbd_find_endpoint(udevice_t device, rt_err_t rt_usbd_device_add_config(udevice_t device, uconfig_t cfg) { struct rt_list_node *i, *j, *k; - uclass_t cls; + ufunction_t func; uintf_t intf; uep_t ep; @@ -1278,79 +1424,81 @@ rt_err_t rt_usbd_device_add_config(udevice_t device, uconfig_t cfg) cfg->cfg_desc.bConfigurationValue = device->dev_desc.bNumConfigurations + 1; device->dev_desc.bNumConfigurations++; - for (i=cfg->cls_list.next; i!=&cfg->cls_list; i=i->next) + for (i=cfg->func_list.next; i!=&cfg->func_list; i=i->next) { - cls = (uclass_t)rt_list_entry(i, struct uclass, list); + func = (ufunction_t)rt_list_entry(i, struct ufunction, list); - for (j=cls->intf_list.next; j!=&cls->intf_list; j=j->next) + for(j=func->intf_list.next; j!=&func->intf_list; j=j->next) { intf = (uintf_t)rt_list_entry(j, struct uinterface, list); cfg->cfg_desc.bNumInterfaces++; /* allocate address for every endpoint in the interface alternate setting */ - for (k = intf->curr_setting->ep_list.next; - k != &intf->curr_setting->ep_list; - k = k->next) + for(k=intf->curr_setting->ep_list.next; + k!=&intf->curr_setting->ep_list; k=k->next) { ep = (uep_t)rt_list_entry(k, struct uendpoint, list); - dcd_ep_alloc(device->dcd, ep); + if(rt_usbd_ep_assign(device, ep) != RT_EOK) + { + rt_kprintf("endpoint assign error\n"); + } } /* construct complete configuration descriptor */ - rt_memcpy((void *)&cfg->cfg_desc.data[cfg->cfg_desc.wTotalLength - USB_DESC_LENGTH_CONFIG], - (void *)intf->curr_setting->desc, - intf->curr_setting->desc_size); + rt_memcpy((void*)&cfg->cfg_desc.data[cfg->cfg_desc.wTotalLength - USB_DESC_LENGTH_CONFIG], + (void*)intf->curr_setting->desc, + intf->curr_setting->desc_size); cfg->cfg_desc.wTotalLength += intf->curr_setting->desc_size; } } /* insert the configuration to the list */ - rt_list_insert_after(&device->cfg_list, &cfg->list); + rt_list_insert_before(&device->cfg_list, &cfg->list); return RT_EOK; } /** - * This function will add a class to a configuration. + * This function will add a function to a configuration. * * @param cfg the configuration object. - * @param cls the class object. + * @param func the function object. * * @return RT_EOK. */ -rt_err_t rt_usbd_config_add_class(uconfig_t cfg, uclass_t cls) +rt_err_t rt_usbd_config_add_function(uconfig_t cfg, ufunction_t func) { - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_config_add_class\n")); + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_config_add_function\n")); /* parameter check */ RT_ASSERT(cfg != RT_NULL); - RT_ASSERT(cls != RT_NULL); + RT_ASSERT(func != RT_NULL); - /* insert the class to the list */ - rt_list_insert_after(&cfg->cls_list, &cls->list); + /* insert the function to the list */ + rt_list_insert_before(&cfg->func_list, &func->list); return RT_EOK; } /** - * This function will add an interface to a class. + * This function will add an interface to a function. * - * @param cls the class object. + * @param func the function object. * @param intf the interface object. * * @return RT_EOK. */ -rt_err_t rt_usbd_class_add_interface(uclass_t cls, uintf_t intf) +rt_err_t rt_usbd_function_add_interface(ufunction_t func, uintf_t intf) { - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_class_add_interface\n")); + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_function_add_interface\n")); /* parameter check */ - RT_ASSERT(cls != RT_NULL); + RT_ASSERT(func != RT_NULL); RT_ASSERT(intf != RT_NULL); /* insert the interface to the list */ - rt_list_insert_after(&cls->intf_list, &intf->list); + rt_list_insert_before(&func->intf_list, &intf->list); return RT_EOK; } @@ -1374,7 +1522,7 @@ rt_err_t rt_usbd_interface_add_altsetting(uintf_t intf, ualtsetting_t setting) setting->intf_desc->bInterfaceNumber = intf->intf_num; /* insert the alternate setting to the list */ - rt_list_insert_after(&intf->setting_list, &setting->list); + rt_list_insert_before(&intf->setting_list, &setting->list); return RT_EOK; } @@ -1396,7 +1544,7 @@ rt_err_t rt_usbd_altsetting_add_endpoint(ualtsetting_t setting, uep_t ep) RT_ASSERT(ep != RT_NULL); /* insert the endpoint to the list */ - rt_list_insert_after(&setting->ep_list, &ep->list); + rt_list_insert_before(&setting->ep_list, &ep->list); return RT_EOK; } @@ -1451,9 +1599,387 @@ rt_err_t rt_usbd_set_config(udevice_t device, rt_uint8_t value) /* set as current configuration */ device->curr_cfg = cfg; + dcd_set_config(device->dcd, value); + return RT_TRUE; } +/** + * This function will request an IO transaction. + * + * @param device the usb device object. + * @param ep the endpoint object. + * @param req IO request. + * + * @return RT_EOK. + */ +rt_size_t rt_usbd_io_request(udevice_t device, uep_t ep, uio_request_t req) +{ + rt_size_t size = 0; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(req != RT_NULL); + + if(ep->stalled == RT_FALSE) + { + switch(req->req_type) + { + case UIO_REQUEST_READ_BEST: + case UIO_REQUEST_READ_FULL: + ep->request.remain_size = ep->request.size; + size = rt_usbd_ep_read_prepare(device, ep, req->buffer, req->size); + break; + case UIO_REQUEST_WRITE: + ep->request.remain_size = ep->request.size; + size = rt_usbd_ep_write(device, ep, req->buffer, req->size); + break; + default: + rt_kprintf("unknown request type\n"); + break; + } + } + else + { + rt_list_insert_before(&ep->request_list, &req->list); + RT_DEBUG_LOG(RT_DEBUG_USB, ("suspend a request\n")); + } + + return size; +} + +/** + * This function will set feature for an usb device. + * + * @param device the usb device object. + * @param value the configuration number. + * + * @return RT_EOK. + */ +rt_err_t rt_usbd_set_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index) +{ + RT_ASSERT(device != RT_NULL); + + if (value == USB_FEATURE_DEV_REMOTE_WAKEUP) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("set feature remote wakeup\n")); + } + else if (value == USB_FEATURE_ENDPOINT_HALT) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("set feature stall\n")); + dcd_ep_set_stall(device->dcd, (rt_uint32_t)(index & 0xFF)); + } + + return RT_EOK; +} + +/** + * This function will clear feature for an usb device. + * + * @param device the usb device object. + * @param value the configuration number. + * + * @return RT_EOK. + */ +rt_err_t rt_usbd_clear_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index) +{ + RT_ASSERT(device != RT_NULL); + + if (value == USB_FEATURE_DEV_REMOTE_WAKEUP) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("clear feature remote wakeup\n")); + } + else if (value == USB_FEATURE_ENDPOINT_HALT) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("clear feature stall\n")); + dcd_ep_clear_stall(device->dcd, (rt_uint32_t)(index & 0xFF)); + } + + return RT_EOK; +} + +rt_err_t rt_usbd_ep0_set_stall(udevice_t device) +{ + RT_ASSERT(device != RT_NULL); + + return dcd_ep_set_stall(device->dcd, 0); +} + +rt_err_t rt_usbd_ep0_clear_stall(udevice_t device) +{ + RT_ASSERT(device != RT_NULL); + + return dcd_ep_clear_stall(device->dcd, 0); +} + +rt_err_t rt_usbd_ep_set_stall(udevice_t device, uep_t ep) +{ + rt_err_t ret; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(ep != RT_NULL); + RT_ASSERT(ep->ep_desc != RT_NULL); + + ret = dcd_ep_set_stall(device->dcd, EP_ADDRESS(ep)); + if(ret == RT_EOK) + { + ep->stalled = RT_TRUE; + } + + return ret; +} + +rt_err_t rt_usbd_ep_clear_stall(udevice_t device, uep_t ep) +{ + rt_err_t ret; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(ep != RT_NULL); + RT_ASSERT(ep->ep_desc != RT_NULL); + + ret = dcd_ep_clear_stall(device->dcd, EP_ADDRESS(ep)); + if(ret == RT_EOK) + { + ep->stalled = RT_FALSE; + } + + return ret; +} + +static rt_err_t rt_usbd_ep_assign(udevice_t device, uep_t ep) +{ + int i = 0; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(device->dcd != RT_NULL); + RT_ASSERT(device->dcd->ep_pool != RT_NULL); + RT_ASSERT(ep != RT_NULL); + RT_ASSERT(ep->ep_desc != RT_NULL); + + while(device->dcd->ep_pool[i].addr != 0xFF) + { + if(device->dcd->ep_pool[i].status == ID_UNASSIGNED && + ep->ep_desc->bmAttributes == device->dcd->ep_pool[i].type) + { + EP_ADDRESS(ep) |= device->dcd->ep_pool[i].addr; + ep->id = &device->dcd->ep_pool[i]; + device->dcd->ep_pool[i].status = ID_ASSIGNED; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("assigned %d\n", device->dcd->ep_pool[i].addr)); + return RT_EOK; + } + + i++; + } + + return -RT_ERROR; +} + +static rt_err_t rt_usbd_ep_unassign(udevice_t device, uep_t ep) +{ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(device->dcd != RT_NULL); + RT_ASSERT(device->dcd->ep_pool != RT_NULL); + RT_ASSERT(ep != RT_NULL); + RT_ASSERT(ep->ep_desc != RT_NULL); + + ep->id->status = ID_UNASSIGNED; + + return RT_EOK; +} + +rt_err_t rt_usbd_ep0_setup_handler(udcd_t dcd, struct ureqest* setup) +{ + struct udev_msg msg; + rt_size_t size; + + RT_ASSERT(dcd != RT_NULL); + + if(setup == RT_NULL) + { + size = dcd_ep_read(dcd, EP0_OUT_ADDR, (void*)&msg.content.setup); + if(size != sizeof(struct ureqest)) + { + rt_kprintf("read setup packet error\n"); + return -RT_ERROR; + } + } + else + { + rt_memcpy((void*)&msg.content.setup, (void*)setup, sizeof(struct ureqest)); + } + + msg.type = USB_MSG_SETUP_NOTIFY; + msg.dcd = dcd; + rt_usbd_event_signal(&msg); + + return RT_EOK; +} + +rt_err_t rt_usbd_ep0_in_handler(udcd_t dcd) +{ + RT_ASSERT(dcd != RT_NULL); + + if(dcd->ep0.request.remain_size >= dcd->ep0.id->maxpacket) + { + dcd_ep_write(dcd, EP0_IN_ADDR, dcd->ep0.request.buffer, dcd->ep0.id->maxpacket); + dcd->ep0.request.remain_size -= dcd->ep0.id->maxpacket; + } + else if(dcd->ep0.request.remain_size > 0) + { + dcd_ep_write(dcd, EP0_IN_ADDR, dcd->ep0.request.buffer, dcd->ep0.request.remain_size); + dcd->ep0.request.remain_size = 0; + } + else + { + dcd_ep_write(dcd, EP0_IN_ADDR, RT_NULL, 0); + } + + return RT_EOK; +} + +rt_err_t rt_usbd_ep0_out_handler(udcd_t dcd, rt_size_t size) +{ + struct udev_msg msg; + + RT_ASSERT(dcd != RT_NULL); + + msg.type = USB_MSG_EP0_OUT; + msg.dcd = dcd; + msg.content.ep_msg.size = size; + rt_usbd_event_signal(&msg); + + return RT_EOK; +} + +rt_err_t rt_usbd_ep_in_handler(udcd_t dcd, rt_uint8_t address) +{ + struct udev_msg msg; + + RT_ASSERT(dcd != RT_NULL); + + msg.type = USB_MSG_DATA_NOTIFY; + msg.dcd = dcd; + msg.content.ep_msg.ep_addr = address; + msg.content.ep_msg.size = 0; + rt_usbd_event_signal(&msg); + + return RT_EOK; +} + +rt_err_t rt_usbd_ep_out_handler(udcd_t dcd, rt_uint8_t address, rt_size_t size) +{ + struct udev_msg msg; + + RT_ASSERT(dcd != RT_NULL); + + msg.type = USB_MSG_DATA_NOTIFY; + msg.dcd = dcd; + msg.content.ep_msg.ep_addr = address; + msg.content.ep_msg.size = size; + rt_usbd_event_signal(&msg); + + return RT_EOK; +} + +rt_err_t rt_usbd_reset_handler(udcd_t dcd) +{ + struct udev_msg msg; + + RT_ASSERT(dcd != RT_NULL); + + msg.type = USB_MSG_RESET; + msg.dcd = dcd; + rt_usbd_event_signal(&msg); + + return RT_EOK; +} + +rt_err_t rt_usbd_connect_handler(udcd_t dcd) +{ + struct udev_msg msg; + + RT_ASSERT(dcd != RT_NULL); + + msg.type = USB_MSG_PLUG_IN; + msg.dcd = dcd; + rt_usbd_event_signal(&msg); + + return RT_EOK; +} + +rt_err_t rt_usbd_disconnect_handler(udcd_t dcd) +{ + struct udev_msg msg; + + RT_ASSERT(dcd != RT_NULL); + + msg.type = USB_MSG_PLUG_OUT; + msg.dcd = dcd; + rt_usbd_event_signal(&msg); + + return RT_EOK; +} + +rt_err_t rt_usbd_sof_handler(udcd_t dcd) +{ + struct udev_msg msg; + + RT_ASSERT(dcd != RT_NULL); + + msg.type = USB_MSG_SOF; + msg.dcd = dcd; + rt_usbd_event_signal(&msg); + + return RT_EOK; +} + +rt_size_t rt_usbd_ep0_write(udevice_t device, void *buffer, rt_size_t size) +{ + uep_t ep0; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(device->dcd != RT_NULL); + RT_ASSERT(buffer != RT_NULL); + RT_ASSERT(size > 0); + + ep0 = &device->dcd->ep0; + ep0->request.size = size; + ep0->request.buffer = buffer; + ep0->request.remain_size = size; + if(ep0->request.remain_size >= ep0->id->maxpacket) + { + dcd_ep_write(device->dcd, EP0_IN_ADDR, ep0->request.buffer, ep0->id->maxpacket); + ep0->request.remain_size -= ep0->id->maxpacket; + ep0->request.buffer += ep0->id->maxpacket; + } + else + { + dcd_ep_write(device->dcd, EP0_IN_ADDR, ep0->request.buffer, ep0->request.remain_size); + ep0->request.remain_size = 0; + } + + return size; +} + +rt_size_t rt_usbd_ep0_read(udevice_t device, void *buffer, rt_size_t size, + rt_err_t (*rx_ind)(udevice_t device, rt_size_t size)) +{ + uep_t ep0; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(device->dcd != RT_NULL); + RT_ASSERT(buffer != RT_NULL); + + ep0 = &device->dcd->ep0; + ep0->request.size = size; + ep0->request.buffer = buffer; + ep0->request.remain_size = size; + ep0->rx_indicate = rx_ind; + dcd_ep_read_prepare(device->dcd, EP0_OUT_ADDR, buffer, size); + + return size; +} + static struct rt_messagequeue usb_mq; /** @@ -1464,26 +1990,27 @@ static struct rt_messagequeue usb_mq; * * @return none. */ -static void rt_usbd_thread_entry(void *parameter) +static void rt_usbd_thread_entry(void* parameter) { - while (1) + while(1) { struct udev_msg msg; udevice_t device; - uclass_t cls; - uep_t ep; /* receive message */ - if (rt_mq_recv(&usb_mq, &msg, sizeof(struct udev_msg), RT_WAITING_FOREVER) != RT_EOK) + if(rt_mq_recv(&usb_mq, &msg, sizeof(struct udev_msg), + RT_WAITING_FOREVER) != RT_EOK ) continue; device = rt_usbd_find_device(msg.dcd); - if (device == RT_NULL) + if(device == RT_NULL) { rt_kprintf("invalid usb device\n"); continue; } + RT_DEBUG_LOG(RT_DEBUG_USB, ("message type %d\n", msg.type)); + switch (msg.type) { case USB_MSG_SOF: @@ -1492,26 +2019,28 @@ static void rt_usbd_thread_entry(void *parameter) case USB_MSG_DATA_NOTIFY: /* some buggy drivers will have USB_MSG_DATA_NOTIFY before the core * got configured. */ - if (device->state != USB_STATE_CONFIGURED) - break; - ep = rt_usbd_find_endpoint(device, &cls, msg.content.ep_msg.ep_addr); - if (ep != RT_NULL) - ep->handler(device, cls, msg.content.ep_msg.size); - else - rt_kprintf("invalid endpoint\n"); + _data_notify(device, &msg.content.ep_msg); break; case USB_MSG_SETUP_NOTIFY: - _setup_request(device, (ureq_t)msg.content.setup_msg.packet); + _setup_request(device, &msg.content.setup); break; - case USB_MSG_RESET: + case USB_MSG_EP0_OUT: + _ep0_out_notify(device, &msg.content.ep_msg); + break; + case USB_MSG_RESET: + RT_DEBUG_LOG(RT_DEBUG_USB, ("reset %d\n", device->state)); if (device->state == USB_STATE_ADDRESS) - _reset_notify(device); + _stop_notify(device); + break; + case USB_MSG_PLUG_IN: + device->state = USB_STATE_ATTACHED; break; case USB_MSG_PLUG_OUT: + device->state = USB_STATE_NOTATTACHED; _stop_notify(device); break; default: - rt_kprintf("unknown msg type\n"); + rt_kprintf("unknown msg type %d\n", msg.type); break; } } @@ -1525,12 +2054,12 @@ static void rt_usbd_thread_entry(void *parameter) * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usbd_post_event(struct udev_msg *msg, rt_size_t size) +rt_err_t rt_usbd_event_signal(struct udev_msg* msg) { RT_ASSERT(msg != RT_NULL); /* send message to usb message queue */ - return rt_mq_send(&usb_mq, (void *)msg, size); + return rt_mq_send(&usb_mq, (void*)msg, sizeof(struct udev_msg)); } @@ -1548,30 +2077,21 @@ static rt_uint8_t usb_mq_pool[(USBD_MQ_MSG_SZ+sizeof(void*))*USBD_MQ_MAX_MSG]; * This function will initialize usb device thread. * * @return none. + * */ rt_err_t rt_usbd_core_init(void) { rt_list_init(&device_list); /* create an usb message queue */ - rt_mq_init(&usb_mq, - "usbd", - usb_mq_pool, - USBD_MQ_MSG_SZ, - sizeof(usb_mq_pool), - RT_IPC_FLAG_FIFO); + rt_mq_init(&usb_mq, "usbd", usb_mq_pool, USBD_MQ_MSG_SZ, + sizeof(usb_mq_pool), RT_IPC_FLAG_FIFO); /* init usb device thread */ - rt_thread_init(&usb_thread, - "usbd", - rt_usbd_thread_entry, - RT_NULL, - usb_thread_stack, - RT_USBD_THREAD_STACK_SZ, - RT_USBD_THREAD_PRIO, - 20); + rt_thread_init(&usb_thread, "usbd", rt_usbd_thread_entry, RT_NULL, + usb_thread_stack, RT_USBD_THREAD_STACK_SZ, RT_USBD_THREAD_PRIO, 20); /* rt_thread_init should always be OK, so start the thread without further * checking. */ - return rt_thread_startup(&usb_thread); } + diff --git a/components/drivers/usb/usbdevice/core/usbdevice.c b/components/drivers/usb/usbdevice/core/usbdevice.c index f5b2b9beac..adef1db2a0 100644 --- a/components/drivers/usb/usbdevice/core/usbdevice.c +++ b/components/drivers/usb/usbdevice/core/usbdevice.c @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * + * * Change Logs: * Date Author Notes * 2012-10-02 Yi Qiu first version @@ -28,13 +28,15 @@ #ifdef RT_USING_USB_DEVICE +#define USB_DEVICE_CONTROLLER_NAME "usbd" + #ifdef RT_USB_DEVICE_COMPOSITE const static char* ustring[] = { "Language", "RT-Thread Team.", "RTT Composite Device", - "1.1.0", + "320219198301", "Configuration", "Interface", }; @@ -60,54 +62,54 @@ static struct udevice_descriptor compsit_desc = }; #endif -rt_err_t rt_usb_device_init(const char* udc_name) +rt_err_t rt_usb_device_init(void) { rt_device_t udc; udevice_t udevice; uconfig_t cfg; - uclass_t cls; - - RT_ASSERT(udc_name != RT_NULL); - - udc = rt_device_find(udc_name); - if(udc == RT_NULL) - { - rt_kprintf("can't find usb device controller %s\n", udc_name); - return -RT_ERROR; - } + ufunction_t func; /* create and startup usb device thread */ rt_usbd_core_init(); /* create a device object */ - udevice = rt_usbd_device_create(); + udevice = rt_usbd_device_new(); + + udc = rt_device_find(USB_DEVICE_CONTROLLER_NAME); + if(udc == RT_NULL) + { + rt_kprintf("can't find usb device controller %s\n", USB_DEVICE_CONTROLLER_NAME); + return -RT_ERROR; + } /* set usb controller driver to the device */ rt_usbd_device_set_controller(udevice, (udcd_t)udc); /* create a configuration object */ - cfg = rt_usbd_config_create(); + cfg = rt_usbd_config_new(); #ifdef RT_USB_DEVICE_MSTORAGE - /* create a mass storage class object */ - cls = rt_usbd_class_mstorage_create(udevice); + /* create a mass storage function object */ + func = rt_usbd_function_mstorage_create(udevice); - /* add the class to the configuration */ - rt_usbd_config_add_class(cfg, cls); + /* add the function to the configuration */ + rt_usbd_config_add_function(cfg, func); #endif + #ifdef RT_USB_DEVICE_CDC - /* create a cdc class object */ - cls = rt_usbd_class_cdc_create(udevice); + /* create a cdc function object */ + func = rt_usbd_function_cdc_create(udevice); - /* add the class to the configuration */ - rt_usbd_config_add_class(cfg, cls); + /* add the function to the configuration */ + rt_usbd_config_add_function(cfg, func); #endif -#ifdef RT_USB_DEVICE_RNDIS - /* create a rndis class object */ - cls = rt_usbd_class_rndis_create(udevice); - /* add the class to the configuration */ - rt_usbd_config_add_class(cfg, cls); +#ifdef RT_USB_DEVICE_RNDIS + /* create a rndis function object */ + func = rt_usbd_function_rndis_create(udevice); + + /* add the function to the configuration */ + rt_usbd_config_add_function(cfg, func); #endif /* set device descriptor to the device */ @@ -115,18 +117,18 @@ rt_err_t rt_usb_device_init(const char* udc_name) rt_usbd_device_set_descriptor(udevice, &compsit_desc); rt_usbd_device_set_string(udevice, ustring); #else - rt_usbd_device_set_descriptor(udevice, cls->dev_desc); + rt_usbd_device_set_descriptor(udevice, func->dev_desc); #endif /* add the configuration to the device */ rt_usbd_device_add_config(udevice, cfg); - /* set default configuration to 1 */ - rt_usbd_set_config(udevice, 1); - /* initialize usb device controller */ rt_device_init(udc); + /* set default configuration to 1 */ + rt_usbd_set_config(udevice, 1); + return RT_EOK; } From 0468f0c87ed05cb6966bda66e2a9b8a3b3bfd698 Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Thu, 20 Feb 2014 22:06:59 +0800 Subject: [PATCH 32/59] Add INIT_FS_EXPORT for RAM file system --- components/dfs/filesystems/ramfs/dfs_ramfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/dfs/filesystems/ramfs/dfs_ramfs.c b/components/dfs/filesystems/ramfs/dfs_ramfs.c index 117528c1e2..fecebe4688 100644 --- a/components/dfs/filesystems/ramfs/dfs_ramfs.c +++ b/components/dfs/filesystems/ramfs/dfs_ramfs.c @@ -414,6 +414,7 @@ int dfs_ramfs_init(void) return 0; } +INIT_FS_EXPORT(dfs_ramfs_init); struct dfs_ramfs* dfs_ramfs_create(rt_uint8_t *pool, rt_size_t size) { From 5ce39b8ad833d129616ac888fc27208e62e39cc1 Mon Sep 17 00:00:00 2001 From: bernard Date: Sun, 23 Feb 2014 00:08:38 +0800 Subject: [PATCH 33/59] [scons] Add the library to the group when used buildlib building --- tools/building.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/building.py b/tools/building.py index 00ef97c4b0..372d93f06f 100644 --- a/tools/building.py +++ b/tools/building.py @@ -327,9 +327,11 @@ def DefineGroup(name, src, depend, **parameters): # check whether exist group library if not GetOption('buildlib') and os.path.exists(os.path.join(group['path'], GroupLibFullName(name, Env))): - Env.Append(LIBS = [GroupLibName(name, Env)]) group['src'] = [] - Env.Append(LIBPATH = [GetCurrentDir()]) + if group.has_key('LIBS'): group['LIBS'] = group['LIBS'] + [GroupLibName(name, Env)] + else : group['LIBS'] = [GroupLibName(name, Env)] + if group.has_key('LIBPATH'): group['LIBPATH'] = group['LIBPATH'] + [GetCurrentDir()] + else : group['LIBPATH'] = [GetCurrentDir()] if group.has_key('LIBS'): Env.Append(LIBS = group['LIBS']) From 7255137b0a8cc1bda57d24d3cf1942550252f7ea Mon Sep 17 00:00:00 2001 From: bernard Date: Sun, 23 Feb 2014 00:10:09 +0800 Subject: [PATCH 34/59] [DFS] Add ramfs initialization in components initialization procedure --- components/init/components.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/init/components.c b/components/init/components.c index 44ff11361a..2c507e12f8 100644 --- a/components/init/components.c +++ b/components/init/components.c @@ -148,6 +148,10 @@ void rt_components_init(void) dfs_romfs_init(); #endif +#ifdef RT_USING_DFS_RAMFS + dfs_ramfs_init(); +#endif + #ifdef RT_USING_DFS_DEVFS devfs_init(); #endif From 121bb5fcdfb3bc5f3586a0937e1b24885236b53d Mon Sep 17 00:00:00 2001 From: geniusgogo Date: Tue, 25 Feb 2014 01:47:49 +0800 Subject: [PATCH 35/59] add JavaScript Interpreter --- components/external/espruino/CONTRIBUTING.md | 46 + components/external/espruino/ChangeLog | 515 ++++ components/external/espruino/LICENSE | 378 +++ components/external/espruino/Makefile | 969 +++++++ components/external/espruino/README.md | 161 ++ components/external/espruino/README_cn.md | 2 + components/external/espruino/SConscript | 65 +- .../external/espruino/dist_licences.txt | 109 + components/external/espruino/dist_readme.txt | 57 + components/external/espruino/gen/README | 1 + components/external/espruino/gen/jspininfo.c | 7 + components/external/espruino/gen/jspininfo.h | 39 + components/external/espruino/gen/jswrapper.c | 1203 ++++++++ .../external/espruino/gen/platform_config.h | 53 + .../external/espruino/libs/jswrap_math.c | 233 ++ .../external/espruino/libs/jswrap_math.h | 28 + components/external/espruino/libs/math/README | 32 + .../external/espruino/libs/math/acosh.c | 167 ++ components/external/espruino/libs/math/asin.c | 324 +++ .../external/espruino/libs/math/asinh.c | 165 ++ components/external/espruino/libs/math/atan.c | 393 +++ .../external/espruino/libs/math/atanh.c | 156 + components/external/espruino/libs/math/cbrt.c | 142 + .../external/espruino/libs/math/chbevl.c | 82 + components/external/espruino/libs/math/clog.c | 1043 +++++++ .../external/espruino/libs/math/cmplx.c | 461 +++ .../external/espruino/libs/math/const.c | 252 ++ components/external/espruino/libs/math/cosh.c | 83 + .../external/espruino/libs/math/descrip.mms | 99 + .../external/espruino/libs/math/drand.c | 161 ++ .../external/espruino/libs/math/dtestvec.c | 543 ++++ components/external/espruino/libs/math/exp.c | 203 ++ .../external/espruino/libs/math/exp10.c | 223 ++ components/external/espruino/libs/math/exp2.c | 183 ++ components/external/espruino/libs/math/fabs.c | 56 + .../external/espruino/libs/math/floor.c | 453 +++ .../external/espruino/libs/math/ftilib.mak | 289 ++ .../external/espruino/libs/math/ftilib.rsp | 17 + .../external/espruino/libs/math/isnan.c | 237 ++ components/external/espruino/libs/math/log.c | 341 +++ .../external/espruino/libs/math/log10.c | 250 ++ components/external/espruino/libs/math/log2.c | 348 +++ .../external/espruino/libs/math/mconf.h | 199 ++ .../external/espruino/libs/math/mod2pi.c | 122 + .../external/espruino/libs/math/mtherr.c | 103 + components/external/espruino/libs/math/mtst.c | 518 ++++ .../external/espruino/libs/math/mtst.opt | 30 + .../external/espruino/libs/math/polevl.asm | 116 + .../external/espruino/libs/math/polevl.c | 97 + components/external/espruino/libs/math/pow.c | 756 +++++ components/external/espruino/libs/math/powi.c | 186 ++ .../external/espruino/libs/math/protos.h | 184 ++ .../external/espruino/libs/math/round.c | 70 + .../external/espruino/libs/math/setprbor.asm | 207 ++ .../external/espruino/libs/math/setprec.387 | 87 + .../external/espruino/libs/math/setprec.688 | 35 + .../external/espruino/libs/math/setprec.87 | 208 ++ .../external/espruino/libs/math/setprec.c | 10 + .../external/espruino/libs/math/setprelf.387 | 83 + components/external/espruino/libs/math/sin.c | 387 +++ .../external/espruino/libs/math/sincos.c | 358 +++ .../external/espruino/libs/math/sindg.c | 308 ++ components/external/espruino/libs/math/sinh.c | 148 + components/external/espruino/libs/math/sqrt.c | 178 ++ components/external/espruino/libs/math/tan.c | 304 ++ .../external/espruino/libs/math/tandg.c | 267 ++ components/external/espruino/libs/math/tanh.c | 141 + .../external/espruino/libs/math/unity.c | 138 + .../external/espruino/libs/math/unix.mak | 109 + components/external/espruino/src/jsdevices.c | 336 +++ components/external/espruino/src/jsdevices.h | 127 + components/external/espruino/src/jshardware.h | 223 ++ .../external/espruino/src/jsinteractive.c | 1686 +++++++++++ .../external/espruino/src/jsinteractive.h | 105 + components/external/espruino/src/jslex.c | 501 ++++ components/external/espruino/src/jslex.h | 59 + components/external/espruino/src/jsparse.c | 2213 ++++++++++++++ components/external/espruino/src/jsparse.h | 126 + components/external/espruino/src/jspin.c | 150 + components/external/espruino/src/jspin.h | 228 ++ components/external/espruino/src/jsutils.c | 439 +++ components/external/espruino/src/jsutils.h | 374 +++ components/external/espruino/src/jsvar.c | 2542 +++++++++++++++++ components/external/espruino/src/jsvar.h | 612 ++++ .../external/espruino/src/jswrap_array.c | 328 +++ .../external/espruino/src/jswrap_array.h | 23 + .../espruino/src/jswrap_arraybuffer.c | 315 ++ .../espruino/src/jswrap_arraybuffer.h | 19 + .../external/espruino/src/jswrap_functions.c | 102 + .../external/espruino/src/jswrap_functions.h | 19 + .../espruino/src/jswrap_interactive.c | 203 ++ .../espruino/src/jswrap_interactive.h | 24 + components/external/espruino/src/jswrap_io.c | 437 +++ components/external/espruino/src/jswrap_io.h | 29 + .../external/espruino/src/jswrap_json.c | 167 ++ .../external/espruino/src/jswrap_json.h | 33 + .../external/espruino/src/jswrap_modules.c | 195 ++ .../external/espruino/src/jswrap_modules.h | 21 + .../external/espruino/src/jswrap_object.c | 332 +++ .../external/espruino/src/jswrap_object.h | 27 + .../external/espruino/src/jswrap_onewire.c | 332 +++ .../external/espruino/src/jswrap_onewire.h | 23 + components/external/espruino/src/jswrap_pin.c | 73 + components/external/espruino/src/jswrap_pin.h | 21 + .../external/espruino/src/jswrap_process.c | 94 + .../external/espruino/src/jswrap_process.h | 19 + .../external/espruino/src/jswrap_serial.c | 197 ++ .../external/espruino/src/jswrap_serial.h | 21 + .../external/espruino/src/jswrap_spi_i2c.c | 455 +++ .../external/espruino/src/jswrap_spi_i2c.h | 24 + .../external/espruino/src/jswrap_string.c | 173 ++ .../external/espruino/src/jswrap_string.h | 23 + components/external/espruino/src/jswrapper.h | 36 + .../espruino/targets/rtthread/espruino.c | 301 ++ .../espruino/targets/rtthread/jshardware.c | 255 ++ 115 files changed, 29947 insertions(+), 13 deletions(-) create mode 100644 components/external/espruino/CONTRIBUTING.md create mode 100644 components/external/espruino/ChangeLog create mode 100644 components/external/espruino/LICENSE create mode 100644 components/external/espruino/Makefile create mode 100644 components/external/espruino/README.md create mode 100644 components/external/espruino/README_cn.md create mode 100644 components/external/espruino/dist_licences.txt create mode 100644 components/external/espruino/dist_readme.txt create mode 100644 components/external/espruino/gen/README create mode 100644 components/external/espruino/gen/jspininfo.c create mode 100644 components/external/espruino/gen/jspininfo.h create mode 100644 components/external/espruino/gen/jswrapper.c create mode 100644 components/external/espruino/gen/platform_config.h create mode 100644 components/external/espruino/libs/jswrap_math.c create mode 100644 components/external/espruino/libs/jswrap_math.h create mode 100644 components/external/espruino/libs/math/README create mode 100644 components/external/espruino/libs/math/acosh.c create mode 100644 components/external/espruino/libs/math/asin.c create mode 100644 components/external/espruino/libs/math/asinh.c create mode 100644 components/external/espruino/libs/math/atan.c create mode 100644 components/external/espruino/libs/math/atanh.c create mode 100644 components/external/espruino/libs/math/cbrt.c create mode 100644 components/external/espruino/libs/math/chbevl.c create mode 100644 components/external/espruino/libs/math/clog.c create mode 100644 components/external/espruino/libs/math/cmplx.c create mode 100644 components/external/espruino/libs/math/const.c create mode 100644 components/external/espruino/libs/math/cosh.c create mode 100644 components/external/espruino/libs/math/descrip.mms create mode 100644 components/external/espruino/libs/math/drand.c create mode 100644 components/external/espruino/libs/math/dtestvec.c create mode 100644 components/external/espruino/libs/math/exp.c create mode 100644 components/external/espruino/libs/math/exp10.c create mode 100644 components/external/espruino/libs/math/exp2.c create mode 100644 components/external/espruino/libs/math/fabs.c create mode 100644 components/external/espruino/libs/math/floor.c create mode 100644 components/external/espruino/libs/math/ftilib.mak create mode 100644 components/external/espruino/libs/math/ftilib.rsp create mode 100644 components/external/espruino/libs/math/isnan.c create mode 100644 components/external/espruino/libs/math/log.c create mode 100644 components/external/espruino/libs/math/log10.c create mode 100644 components/external/espruino/libs/math/log2.c create mode 100644 components/external/espruino/libs/math/mconf.h create mode 100644 components/external/espruino/libs/math/mod2pi.c create mode 100644 components/external/espruino/libs/math/mtherr.c create mode 100644 components/external/espruino/libs/math/mtst.c create mode 100644 components/external/espruino/libs/math/mtst.opt create mode 100644 components/external/espruino/libs/math/polevl.asm create mode 100644 components/external/espruino/libs/math/polevl.c create mode 100644 components/external/espruino/libs/math/pow.c create mode 100644 components/external/espruino/libs/math/powi.c create mode 100644 components/external/espruino/libs/math/protos.h create mode 100644 components/external/espruino/libs/math/round.c create mode 100644 components/external/espruino/libs/math/setprbor.asm create mode 100644 components/external/espruino/libs/math/setprec.387 create mode 100644 components/external/espruino/libs/math/setprec.688 create mode 100644 components/external/espruino/libs/math/setprec.87 create mode 100644 components/external/espruino/libs/math/setprec.c create mode 100644 components/external/espruino/libs/math/setprelf.387 create mode 100644 components/external/espruino/libs/math/sin.c create mode 100644 components/external/espruino/libs/math/sincos.c create mode 100644 components/external/espruino/libs/math/sindg.c create mode 100644 components/external/espruino/libs/math/sinh.c create mode 100644 components/external/espruino/libs/math/sqrt.c create mode 100644 components/external/espruino/libs/math/tan.c create mode 100644 components/external/espruino/libs/math/tandg.c create mode 100644 components/external/espruino/libs/math/tanh.c create mode 100644 components/external/espruino/libs/math/unity.c create mode 100644 components/external/espruino/libs/math/unix.mak create mode 100644 components/external/espruino/src/jsdevices.c create mode 100644 components/external/espruino/src/jsdevices.h create mode 100644 components/external/espruino/src/jshardware.h create mode 100644 components/external/espruino/src/jsinteractive.c create mode 100644 components/external/espruino/src/jsinteractive.h create mode 100644 components/external/espruino/src/jslex.c create mode 100644 components/external/espruino/src/jslex.h create mode 100644 components/external/espruino/src/jsparse.c create mode 100644 components/external/espruino/src/jsparse.h create mode 100644 components/external/espruino/src/jspin.c create mode 100644 components/external/espruino/src/jspin.h create mode 100644 components/external/espruino/src/jsutils.c create mode 100644 components/external/espruino/src/jsutils.h create mode 100644 components/external/espruino/src/jsvar.c create mode 100644 components/external/espruino/src/jsvar.h create mode 100644 components/external/espruino/src/jswrap_array.c create mode 100644 components/external/espruino/src/jswrap_array.h create mode 100644 components/external/espruino/src/jswrap_arraybuffer.c create mode 100644 components/external/espruino/src/jswrap_arraybuffer.h create mode 100644 components/external/espruino/src/jswrap_functions.c create mode 100644 components/external/espruino/src/jswrap_functions.h create mode 100644 components/external/espruino/src/jswrap_interactive.c create mode 100644 components/external/espruino/src/jswrap_interactive.h create mode 100644 components/external/espruino/src/jswrap_io.c create mode 100644 components/external/espruino/src/jswrap_io.h create mode 100644 components/external/espruino/src/jswrap_json.c create mode 100644 components/external/espruino/src/jswrap_json.h create mode 100644 components/external/espruino/src/jswrap_modules.c create mode 100644 components/external/espruino/src/jswrap_modules.h create mode 100644 components/external/espruino/src/jswrap_object.c create mode 100644 components/external/espruino/src/jswrap_object.h create mode 100644 components/external/espruino/src/jswrap_onewire.c create mode 100644 components/external/espruino/src/jswrap_onewire.h create mode 100644 components/external/espruino/src/jswrap_pin.c create mode 100644 components/external/espruino/src/jswrap_pin.h create mode 100644 components/external/espruino/src/jswrap_process.c create mode 100644 components/external/espruino/src/jswrap_process.h create mode 100644 components/external/espruino/src/jswrap_serial.c create mode 100644 components/external/espruino/src/jswrap_serial.h create mode 100644 components/external/espruino/src/jswrap_spi_i2c.c create mode 100644 components/external/espruino/src/jswrap_spi_i2c.h create mode 100644 components/external/espruino/src/jswrap_string.c create mode 100644 components/external/espruino/src/jswrap_string.h create mode 100644 components/external/espruino/src/jswrapper.h create mode 100644 components/external/espruino/targets/rtthread/espruino.c create mode 100644 components/external/espruino/targets/rtthread/jshardware.c diff --git a/components/external/espruino/CONTRIBUTING.md b/components/external/espruino/CONTRIBUTING.md new file mode 100644 index 0000000000..946656b37c --- /dev/null +++ b/components/external/espruino/CONTRIBUTING.md @@ -0,0 +1,46 @@ +Contributing +=========== + +Thanks for thinking about contributing to Espruino! Anything you can add is hugely appreciated, but please can you follow a few simple rules: + +* Keep the same coding style (See **Coding Style** below) +* Ensure that you are not contributing someone else's code, and that you are willing to add your code under Espruino's MPL Licence +* Make sure that what you do doesn't break the Espruino board or the other boards we build for. We can't check all the boards for every commit, so if you break something you'll annoy a whole bunch of people. +* Be aware that Espruino is designed for Microcontrollers - with very low amounts of flash and memory. Both are at a premium so don't statically allocate variables or do other stuff that will use up memory. +* Avoid randomly adding newlines, spaces, refactoring everything or renaming things to your own personal style (some things really could do with renaming, but please check first or we may reject your pull request) +* Don't add a whole bunch of indirection/abstraction for the sake of it - it'll probably just use of more of our precious memory. +* If you add a new API, try and make it familiar to Arduino/JavaScript users. + +Target Areas +----------- + +We'll keep the outstanding issues in GitHub's issue list, but general stuff that would really help us is: + +* Tests. If something doesn't work, please make a test for it. Even if you don't fix it it'll help others greatly. Bonus points if it's in a pull request :) +* Documentation. Improving the documentation (either the EspruinoDocs project, or the auto-generated reference) would be fantastic. +* Duplication. If the same code is used for multiple platforms, try and make sure it's shared, not duplicated. +* Remove hard-coded stuff. Various things like the SPI filesystem are still hard-coded with ifdefs for each board - we want all that stuff to be generated from build_platform_info.py +* Speed. There are a few areas this could be improved - but please benchmark what you're doing both before and afterwards on the Espruino board to check that what you've done helps +* Memory Usage. Both RAM and Flash are at a premium. Ways of reducing this (including stack usage) and making usage more efficient are really appreciated. +* JavaScript compliance (without affecting speed or memory usage too much). + +Contributing +----------- + +* Please RUN THE TESTS to check that there are no regressions +* Issue us a pull request to [www.github.com/espruino] via GitHub +* Please keep each request small (just include one fix per request) + +Coding Style +----------- + +The rough coding style is as follows, but you should get a good idea from the code. If we've missed anything obvious please let us know! + +* 2 Spaces for indents +* Open curly braces on the same line +* No Tabs used +* Use bool for booleans - not int +* ```//``` comments for single lines, ```/* ... */``` for multiple lines +* Half-hearted Doxygen compatibility: use ```///<``` for function declaration documentation (if on same line), and ```/** ... */``` if doing it right before a function +* Use new lines sparingly (only where it really makes sense) + diff --git a/components/external/espruino/ChangeLog b/components/external/espruino/ChangeLog new file mode 100644 index 0000000000..40beec975f --- /dev/null +++ b/components/external/espruino/ChangeLog @@ -0,0 +1,515 @@ + 1v46 : ... + + 1v45 : Fix parseFloat("foo") not returning NaN (and assert) - fix #149 + Remove Integer.parseInt + Fix parseInt("bar") - fix #150 + Ensure that maths ops with null do treat it as 0 rather than a string - fix #156 + Fix digitalPulse length (properly!) - fix #154 + Making sure that undefined gets cast to NaN + Fix Array.indexOf() returns undefined instead of -1 - fix #155 + Moved memory() to process.memory() - added more info too + Try and improve handling of PWM timer speeds + Fixed varying SPI baud rates depending on device + Makefile changes for OSX compile + + 1v44 : Modified build system to store binary names in the python definition + Fix nasty regression involving losing code at the end of Strings + Fix segfault when pinMode is called on an invalid pin + Now disable interrupts during 4 bit SPI send - it's just too much otherwise + Detect unfinished block comments in console (fix #138) + Fix flash write on most 10XxB boards + Fix PWM output on all STM32 boards + General hardware tidy in prep for more intelligent device management + Run initialisation code before setWatch, to make sure pullup/down is set beforehand + Change 'Pin' datatype to be an unsigned char - makes tests easier + Now use the hardware RTC for keeping system time. Allows proper deep sleep on Espruino board + FINALLY - fix the USB VCP lost characters issue (#94) + + 1v43 : Added 'Modules' object with support for adding/removing cached modules + Allow product ID to be changed via Makefile + Fix documentation (and old-fashined Parsing style) for JSON + build_jswrapper now outputs errors to stderr (more compatible with default (silent) build process) + Fix issue when parsing quotes in strings + Added void operator for closure minification compatibility + Ensure that return takes the comma operator + Fix issue where printing Infinity would crash Espruino (fix #129) + Finally some working (extremely beta) cc3000 code + Added jsvObjectGet/SetChild to simplify some wrappers + 'http' now uses JsVars for storage (so is suitable for non-linux devices) + Turned 'http' into a library + Added process.version and process.env (fix #131) + Changed handling of 2nd arg of << so that precedence is correct + Fixed handling of 'for (;;)' + Fix lock leak in Module handling + Update ST's library for the STM32F1 + Update ST's VCP implementation + Added prefix operator (fix #130) + Allow espruino for linux to be run with '#!' in scripts + Fix indexOf on final element of strings (fix #133) + Remove JSV_PARENTINFO, as it turns out JS doesn't keep track of function scopes anyway (fix #109) + Make 'this' a keyword (now faster, more memory efficient) + Make 'Hardware' (root) the default value of 'this' + Add jsvArrayPushAndUnLock and modified code to use it (fix #135) + Now remember I2C state (partial fix for #13) + Replace 'pow' function with a smaller version - save ~2kb + Shaved another 1200 bytes off jslTokenAsString + Now store Pin state (fix for #13 on F1 parts, F4 still looks broken) + Added Graphics.stringWidth + Added internal Printf function + Misc speed and code size improvements + This version has gone to Seeed for use on the KickStarter boards + + 1v42 : [ebirger] allowing 'new' with no brackets + Allow built-in functions with variable numbers of arguments (fix #83) + Implement 'String' constructor in the normal way (fix #110) + Fix regression with parsing constructors while not executing + Allow multiple arguments to print and console.log (fix #92) + Make 'arguments' array available in functions (fix #100) + Fix an assert fail, and handle some potential memory leaks + Don't show __proto__ and constructor with for..in, keys(), or JSON.stringify + Make 'trace()' output more readable debug data for complex structures + Fix memory leak whe parsing functions iwht variable numbers of arguments - fix #115 + Defined NaN + Stop 'new undefined()' crashing Espruino - fix #120 + Get A13/A14 working on Espruino board (these were JTAG) + Get bootloader size direct from Python (remove hard-coding) + Fix '~' operator when acting on variables + Made bootloader a bit more error tolerate (CRC on write) + Added %=, /=, and *= operators (fix #121) + Allowed Object.toString() to take a radix argument for integers (fix #125) + Fix error message issue - broken strncat (fix #124) + Add comma operator (fix #122) + Added some basic code for STM32F429IDISCOVERY - not currently working though + This version is the one sent off on the Test Harness (so will probably appear on boards) + + 1v41 : Fix Olimexino compile (https://github.com/espruino/Espruino/issues/6) + [ebirger] Member constructors (eg. new a.b() ) + [ebirger] Ensuring integers with radix specifiers can still be parsed if a radix is specified + Fix for tests/test_json_arraybuffer_001.js - iteration of arraybuffers of length==1 + Add Object.keys(...) + More arraybuffer iteration fixes + On linux, use built-in stringToFloat to aid debugging. Handle exponentials, fix #31 + 'make serialflash' is now works correctly for Espruino Boards with bootloader + setWatch(..A0);setWatch(..A0);clearWatch(1) does not now kill the other watch, fix #25 + One-based setTimeout/setWatch, fix #3 + Added Function.call and Function.apply, fix #54 + 'http' and 'fs' are now libraries that need to be 'require'd, fix #8 + Updated pin info for STM32F103xC/D/E chips, fix #84 + Fixed linker script for STM32F4 (discovery board now works) + Object prototypes are now Objects, fix #101 + Board docs now specify '3.3v' only pins fix #104 + Add Array.forEach + Fix searching down >1 prototype to find functions (one more issue posted in #99) + Fix "12345"/5 type issues (fix #90) + 'Consting' some string functions + Fixing arrays with string indices that are actually numbers \o/ (fix #19) + Released onto website + + 1v40 : Ensure that LCD.prototype.setPixel = function actually works + Refactor LCD driver code to allow lcdInit (and start of making it non-platform-specific) + Built 'LCD' support into linux/raspi/carambola + Add initial SPI.send(ArrayBuffer) support - even if NO VALUES RETURNED + Start of built-in Nokia 5110 LCD support + Remove GPIO clock removal on sleep for now (it kills setWatch) + Fix (sub)ArrayBuffer problems (test100.js) + Added setDeepSleep - still beta put power consumption drops to 1mA + Fix broken name for httpCRq.write + Changed LCD to Graphics - added ability to render to ArrayBuffer + Fix 8 char built-in class names + Adding preliminary Sony SmartWatch support + Adding preliminary support for completely bare 36 pin chip + Fixing pin defs for Espruino board rev 1v1 + Added proper SDL/ArrayBuffer and JS Callback graphics support + Added "ifdef" ability in build_jswrapper + Take JSVAR_CACHE_SIZE out of jsutils and put it in the board config file + Added JSV_PARENTINFO which will allow us to do things like setTimeout(foo.bar,10) + Fixed arrays in non-executes streams - 'if (0) print([1,2,3]);' + Added 'require' function loading modules from node_modules on SD card + Added module cache to stop modules being re-loaded + Renamed internal vars to start with '>' - much easier to distinguish for 'dump'/etc + Only use parentInfo on functions + Load all tests in test dir - don't do them by number + Added 'zigzag' ordering for ArrayBuffer Graphics + Added 'vertical_byte' ordering for ArrayBuffer Graphics + toJSON now ignores 'hidden' object elements + Special-case jsvArrayBufferIteratorSetIntegerValue + Make SPI output an ArrayBuffer + Use best out of 3 for DelayMicroseconds calibration - something seems flaky right after bootup + Lines now drawn from p1 to p2 inclusive + Events now use jshPushIOWatchEvent (should cut down on code) also fixed bug with watching pin #11 + Now remember if pinMode was set or not + Transform ```code``` in JSON into a code tag in the documentation + Graphics now supports FSMC for HY boards again + Drawing vector fonts is now roughly the right size and position (still not 100%) + Remove registration code + Adding MPL licence + Remove Arduino bit manipulation functions - nobody seems to use them anyway + # of flash pages/etc now comes from board info + [ebirger] Supply the correct arguments to Array.map + [ebirger] Method calls and membership evaluation should be done on all factors (ee. [1,2,3].foo()) + [ebirger] When running multiple tests, only set up terminal once or it breaks the terminal window on exit + Added STM32-style USB CDC bootloader for Espruino Boards + Added scripts/create_espruino_image.sh to package up bootloader and espruino into one binary + SHIPPED on Impatient developer boards + + 1v39 : Added Bitwise NOT operator + Added Raspberry Pi version to ZIP (with HTTP support) + Fixed load/save on Linux Devices + Added pinMode function (to allow pull-ups/pull-downs to be turned on) + SPI.send4bit/send8bit will now not mess up the final element + changeInterval now clears up stored up callbacks (eg, setInterval(.., 0.01)...wait...changeInterval(...,20) + Ctrl-C no longer prints anything, which avoids lockups + No longer print "Execution Interrupted" if nothing was interrupted! + Added >>>= >>= and <<= + When entering text interactively, ensure that there are no trailing spaces + + 1v38 : Tweaks for Arduino IDE compile + Removed '(char #)' from stack trace, as a bit pointless now + Added better reporting of execution location when Ctrl-C pressed + Urgent fix for non-working Olimexino since 1v33 + Fix string comparison when strings contain "\0" + Added LED1/2/OSC/SD/etc to Olimexino Board docs + + 1v37 : Urgent fix - power saving code made it difficult to re-flash Espruino (now only apply this to Espruino Board) + + 1v36 : Fix documentation for Array.pop() + Added some much better board documentation + Fixed DAC output on F3 + Fixed DAC output on devices where PWM is also available and the alternate function is less than the DAC's + + 1v35 : Attempt to reduce power consumption when sleeping by turning off GPIO, and setting GPIOs to AIN on reset + Fix F3 issue where ADC/DAC weren't picked up properly + Tidy up register text and add KickStarter mention + var a = {}; a[LED1]=0; - not converted to String + JSON (and hence dump()) now dumps ArrayBuffer correctly + + 1v34 : Faster jshFromDeviceString + Preliminary support for flow control on Serial receive + Speed improvements by removing jsvGetRef from jsvUnLock + fast 4 byte pre-check in jsvFindChildFromString + Skip lock/unlock in FindChildFromString to help increase speed + When we unplug USB, only go to the default console device IF that is the device we're currently on + Support for custom Espruino board + Added ArrayBufferView.interpolate + 16 bit SPI send for send4bit/sevrnd8bit (better reliability on low-end chips) + Fix JSON dump of typed array + Added Math.clip(x, min, max) + When saving on flash, don't do jslTokenAsString properly + B3/B4 move from alternate fn + Fix incorrect reporting of analog pins + Fix I2C.readFrom on STM32F1/4 + Make 1/2 == 0.5 (was being sensible before, but now follow JS spec) + Ctrl-C while in timer fn clears timers (but not outside it) + Fixed broken clearInterval from within setInterval + Hopefully fixed issue on SSD1289 LCD controller + Trigger wheel handler to use interrupts + 2D arraybuffer interpolation + Added Math.wrap, fixed a lot of trigger issues + Fixed SysTick priority/preempt problems + Slowed the SysTick timer back down for everything + Fix Int8Array signedness on F4 boards + Refactored source code tree + + 1v33 : fix character encoding issue of "\16"+"1" != "\161" + Refactoring of ArrayBuffer into iterator, and addition of a general purpose iterator + Fancier assert for debugging + jsvArrayJoin to use new iterator + for (i in ...) to use new iterator + I2C and SPI use new iterator + Serial.write() - to allow single ints to easily be written + changeInterval assert fail when given a function by accident + added peek8/poke8/peek16/poke16 + memory() now takes account of command history size + memory() on ARM reports the end address of the stack - so it can be used as a scratchpad with peek and poke + Try and reduce code size by not inlining several functions + No refs for StringExts - so we get one more byte per JsVar (~5%) more storage efficiency + Move from jsvIsBuiltInFunction to computer-generated jswIsBuiltInFunction + When creating Objects, check for built-in function BEFORE creating an Object class for it + Built process now checks that flash usage is under the allowed value + Added short compare to jswHandleFunctionCall to reduce code size + Added 3 byte compare (4 byte read and AND off top byte) - faster, less code + Auto-generate jsvGetBasicObjectName from docs + No longer using refs for storing whether free or not - use flags with JSV_UNUSED and get one extra var with 8 bit refs + Switch to using STRING_0...STRING_MAX in flags, rather than specific bits in JsVarFlags - allows more that 15 chars to be used per JsVar + Make ArrayBuffers actually be ArrayBufferViews - saves on extra string-handling code at expense of one var + Make sure Uint8Array,etc inherits from ArrayBufferView + Fix issue where a '\0' coming in from serial was not put in e.data properly + Don't inline some functions when we're trying to save on flash + Re-use sin for cos, pow for sqrt to reduce code size + + 1v32 : Fixed embarassing issue with 0.999=="0.A" + Added and checked Pin.writeAtTime on STM32 + Now don't allocate events array - just allocate directly, which saves memory and is faster (although slighty out of order) + Docs: now Alphabetically sorted, and class instances not listed by accident + Fix issue where Ctrl-C on ANY Serial port caused execution to be interrupted + Updated busy indicator to cope with recent change to not allocate events in an array + Fixed I2C on HY 2.4 board - I2C needed hard reset + Added basic ArrayBuffers/TypedArray support + Fix memory leak when error created with [] on a non-array/object + Improved hyperlinking in documentation + Fix I2C receive bug on F4 + Increased VL board's input buffer size + + 1v31 : Fix PWM output on TIMER1/8 pins of the STM32F4 + Fix PWM output for negated timers + memory() now runs a GC pass + Fixed multiple occurrence of functions in reference + + 1v30 : STM32F1: fixed AF issue meant peripherals would never return from AF mode + STM32F1: When given an invalid pin, now reports if pins are 'af' or not + Updated SPI.setup docs to mention that you can't mix AF and non-AF + If one SPI pin is specified but others aren't, only that pin will be set up + Added Olimexino hack so SPI1.setup works as expected + Allow using [] on a function + Fix precedence issue, so var a = function() { return 1; }(); works + Update SPI documentation + for (i in f) can now iterate over functions + Optional argument to trace() for object to start tracing from + Small steps towards ArrayBuffers + Added smart edit that checks for internal functions, and uses Function.replaceWith + Added Function.replaceWith to replace the internals of a function while keeping the scope + + 1v29 : Some hacky sysfs-based IO for running on Linux + HTTP Callbacks are now stored as names so they can be changed on the fly (Linux only) + Successful compile for Carambola + Filesystem support on Linux + Switch to variable size ref counter (marginally more efficient on very small devices, safe on Linux) + Linux now has unlimited memory available + Added linux/sysfs 'setWatch' (non-irq driven, so very noddy) + Checked jswrapper check from using multi-char constants to a #define + Improve pin suggestions for SPI/I2C/USART + Auto-initialise USART with default values when setConsole is used + Support for new Graphics LCD types + 3.2" VCT6 board support + + 1v28 : Faster LCD fillrect for HY 2.8 + Fix for multi-byte SPI writes on HY board at 1Mhz (touchscreen control bug) + Fix issue with delayMicrosecond calibration on HY (and hence OneWire) + Fixed digitalPulse on STM32VLDISCOVERY + + 1v27 : Fixed problem with OneWire constructor execution + Added |=, &= and ^= + Added Array.splice() + Faster, more ROM-efficient built-in symbol table + Fix for potential issue when using field accessor on an undefined var + + 1v26 : I2C Support on STM32F1 and STM32F4 boards too + Emergency cut in variables for Olimexino with bootloader (as flash usage has got too high for save to flash!) + + 1v25 : http.writeHead to accept an empty header + Fixed issue finding methods on built in classes (0 termination) + make sure http server with no data still sends headers... + Start of MINI-HY-2.8" support (all ok, but no SD card yet) + Reduce RAM usage by consting some arrays that are not modified + Vector fonts now use polys - 8kb less ROM, and faster rendering + Start of LCD 'driver' code + Standard way of handling events, Object.on/emit/removeAllListeners - like Node.js's EventEmitter + Self-calibrating Microsecond delay (for intermal OneWire/etc) + OneWire class + Correct handling of built-in class constructors + Fix error when parsing a zero-argument function that has been given arguments + I2C support - currently ONLY tested on STM32F3 board + + 1v24 : SDIO-based fat driver on the HY STM32 board + Added DAC to the HY boards (103xE-based) + Re-named the fileSystem functions to make them more compatible with node.js (readFile/writeFile/etc) + Added fs.appendFile + Removed HTTP from the reference until it is included in some boards + + 1v23 : Fix 'ERROR: INTERNAL: stmADCChannel' on STM32VLDISCOVERY/F1 boards when accessing PA0 + Reference now mentions which Espruino version it is for + + 1v22 : Important fix - Events got executed in the wrong order if they got queued up + + 1v21 : Ensure SPI clock does not stop between bytes + Added SPI.send4bit and SPI.send8bit + Made sure the VL board's code fits into available flash + Smart += that can append to a string rather than cloning it + dump() prints functions properly, rather than 'var f = function() {}' + Pageup/down move the cursor to the beginning/end of input + LCD draw/fill with negative x and y + + 1v20 : Add console.log + Fix automatic usleep for Linux + Added node.js-style HTTP server for Linux version + Fixed null-pointer issue when accessing something that doesn't exist on an object + Added node.js-style HTTP client for Linux version + Start of bit bashing functionality + for (i in "ABCD") console.log(i) -> 0,1,2,3 + String array access (but not for writing - doesn't work in JS anyway) + String String.fromCharCode / charCodeAt + Added SPI baud rate setting + Vector font chars 'a' and '4' now work ok + Fix numeric exception when rendering a poly that has some identical points + Better digitalPulse (uses timer + interrupts) + analogWrite can now take an object with a 'frequency' argument for PWM + + 1v19 : Fixed issue where var M=Math;M.random() failed + Fixed issue with var U=USB;U.print("Hello"); + Remove loop iteration limit + Fix memory leak when a syntax error is in for '(i in arr)' + Save state of pin on setWatch interrupt (e.state) + Change setWatch to allow only on rise or fall as an option + clearWatch() clears all watches + + 1v18 : DAC support on F3/F4 + Serial.setup() can also take a second parameter of an object {tx,rx} + Better support for dump() with echo/setBusyIndicator/etc + Better dumping of prototypes on built-in vars + Don't add chars<32 (Except tab) to the input line + SPI1/2/3/4.setup() to take an object {baud,sck,miso,mosi} + Better hardware initialisation code (not UARTS auto-init if they are used) + Fix issues with prototypes + Peek/poke instructions + Start of I2C support (not usable yet) + Added Math. ceil/floor/exp/log + + 1v17 : Support for running alongside the Maple bootloader + Fix parsing of numbers beginning with 0 when forceRadix!=8 + Fixed USART1 on Maple/Olimexino devices + + 1v16 : Inlining of jsvLock/UnLock in jsvar.h to improve speed + Move non-hardware-dependent stuff into jsdevices + Move jshardware.c into targets/stm32/jshardware.c, create 'targets/linux' and use a single makefile + For + While loops work without reallocating lex + Fix AddNativeFunction when function already exists (and tests + saved state) + Change jsvFindChildFromX to use JsVar* from JsVarRef - saves a lot of lock/unlock + Handle new Foo() as per spec (return value + init of this+prototype) - still does not cope with non-object prototype + Beginning of SD card support (works on Olimexino, but not very flexible) + Fix for parse/eval when given non-strings + Strings can now contain '\0' + Jumptable-friendly reserved word check + Jumptable-friendly builtin functions (massive refactor) + SPI support + HY board support, and graphics LCD + Added fillPoly, and Vector fonts + Added Registration code + Fixed some undefined function/array warnings + Much better HTML function documentation + Fixed edit() function + STM32F3 support, and now peripheral stuff is done with a script + explain what pins are available if a pin is not capable of requested fn + power on ADCs only when needed + LCD fillPoly speed improvements, + drawLine + Add datatype for Pin, so pins written to console by pin name rather than integer value. + Added Pin.set/Pin.reset + Change warning about 'undefined.' into an error (foo.reset() had unexpected consequences!) + Fix parsing of '1.0/-3'! + Add typeof and instanceof operators + Ensure that Serial1/SPI1/etc are objects of type 'Serial'/'SPI' - so prototypes can be added + + 1v15 : Escaping JSON strings + Fix parsing of octal numbers in strings (so don't have to be 3 chars long) + Drastically improved stack usage using small stub functions (at expense of a bit of speed) + dump() also dumps out prototypes for functions + + 1v14 : Fix complaint about pins during setBusyIndicator() + Increase available memory on OLIMEXINO + Added function memory() to return memory usage + setWatch now links to function names (rather than just functions) + dump() also handles Serial.onData(...) + Fix issue with JSON printing functions with arguments to console + prefix builtin variables with '_' + fix ArrayIndexOf when array contains undefineds + move all devices into one git repository + USB on F4 + call onInit function/string if it exists when Espruino powers on + Compile F4 with -O2 - as we have the program memory for it + Serial3/4/5/6 on F4 + Serial3 on Olimexino + Make Serial.onData() clear onData handler + + 1v13 : Operations like + on Object/Array convert them to strings rather than error + var now doesn't error if there is no semi-colon + Allow new line or line delete in multi-line editing + add edit(functionName) - which copies function definition into inputline so it can be updated + When printing lines, delete current inputline and then put it back in idle loop (only if echo=1) + Support *,/ etc on numpad + + 1v12 : Issue when printing lots of data and then disconnect USB + Hide USB/Serial in Dump() + add Array.map(fn(x), thisArg) + For newline, count [] and () (as well as {}) - also knows about comments/strings/etc + Fix assert fail is setTimeout with non-function + If space at end of input line, enter still executes + Removed some hard-coded arrays in favour of JsVar strings + Fix confusion with jsvIsName/jsvIsString + Handle numpad end key + Add code to check stack and stop stack overflow if too much recursion + Ensure that setTimeout/setWatch store the link to a function, not the function + Fix nasty ref loop in ref loop GC issue + Add dotty output + Fix memory leak when error in jspParseSingleFunction + Now run Garbage collection if we're idle, and we know we have a few ms spare + Added setSleepIndicator + Fix line/col indicator in errors/warnings + Fix JSON parsing and printing when 'undefined' encountered + Rewritten object handling code to be way more standard JavaScript compliant + Array initialisation with 'new Array()', also for Strings + Added a few more built in functions + Nice error reporting with line + pointer + fixed Math.random + Binary style ops on doubles now work - they are just converted to ints + Added boolean datatype + + 1v11 : Add Math functions + Add command history (and dynamic history free if low memory) + Fix broken jsvArrayPop + Add tests for and fix Array.indexOf + In-line editing for commands + Fix bug in basicVarEquals for big strings + More fixes for low memory conditions + Multi-line edit for commands (but no newline or line delete yet) + Handle Home, End + reverse delete keys + Fix nested for loops not handling interrupts correctly + Fix AppendString issue when given start value greater than string + Add 'changeInterval' to allow things created with setInterval to have the frequency changed (eg. stepper motor control) + Now puts itself to sleep to save power, when it knows nothing is required and it'll be woken up by SysTick before + Change Math library to avoid putting constants in RAM + + 1v10 : Increase FIFO size for VL + Marginally decrease amount of F4 vars to ensure they all fit in one flash sector + Allow strings to be longer than the max token size + '"key" in obj' syntax + Detect if in FOR or WHILE loop, and if not, disallow break and continue + Change min setInterval time to 0.1ms - F4 can get close to this + Better analog pin error message + USB support on Olimexino/Maple + Start of multiple COM port support (ioEvent queue) + Ctrl-C now clears the input line + Save state of 'echo' into flash with save() + Add 'setBusyIndicator(pin)' to set pin high when Espruino is busy + Inbuilt function handling speed improvements + Allow Serial comms via other UARTS. Serial1/2.onData and print/println + now inserts elements into arrays in the correct order (GetLength can be (is) now much faster) + Faster code to work out pins from strings + Automatically convert IDs in form A#,A##,B#,B## etc into numbers. + Built-in constants for LED1/BTN/etc. + + 1v09 : Enabled 'abs' by default + Added flash programming to STM32F4 + analogWrite now working! + + 1v08 : Add preliminary STM32F4 support + Allowed test cases to test timers - eg. code in jsinteractive.c + Fix memory leak for timer + Fix memory leak for digitalWrite + + 1v07 : Fix string charAt + Fix watch on different pin + Pass arguments to event handlers - eg. time + digitalWrite/Read to take arrays of pins, and int for value + + 1v06 : Add break + continue + Add switch statement + Handle /r, /r/n or just /n for newlines - phone compatible + Handle different type of delete + + 1v05 : Allow setWatch/setTimeout/setInterval with a string + Handle adding Open bracket then deleting it + When calling a NAMED function, zero the scopes - this stops scope table overflow + + 1v04 : Renamed to Espruino + Fixed issue with event add when out of memory + If out of memory happens during a timer, kill all timers + diff --git a/components/external/espruino/LICENSE b/components/external/espruino/LICENSE new file mode 100644 index 0000000000..913dcba13b --- /dev/null +++ b/components/external/espruino/LICENSE @@ -0,0 +1,378 @@ +All files in this package are Copyright 2013 Gordon Williams, Pur3 Ltd unless +otherwise noted. + +------------------------------------------------------------------------------- + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/components/external/espruino/Makefile b/components/external/espruino/Makefile new file mode 100644 index 0000000000..d9c6f62079 --- /dev/null +++ b/components/external/espruino/Makefile @@ -0,0 +1,969 @@ +# This file is part of Espruino, a JavaScript interpreter for Microcontrollers +# +# Copyright (C) 2013 Gordon Williams +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# ----------------------------------------------------------------------------- +# Makefile for Espruino +# ----------------------------------------------------------------------------- +# Set ONE of the following environment variables to compile for that board: +# +# ESPRUINO_1V0=1 # Espruino board rev 1.0 +# ESPRUINO_1V1=1 # Espruino board rev 1.1 and 1.2 +# ESPRUINO_1V3=1 # Espruino board rev 1.3 +# OLIMEXINO_STM32=1 # Olimexino STM32 +# OLIMEXINO_STM32_BOOTLOADER=1 # Olimexino STM32 with bootloader +# EMBEDDED_PI=1 # COOCOX STM32 Embedded Pi boards +# HYSTM32_24=1 # HY STM32 2.4 Ebay boards +# HYSTM32_28=1 # HY STM32 2.8 Ebay boards +# HYSTM32_32=1 # HY STM32 3.2 VCT6 Ebay boards +# STM32VLDISCOVERY=1 +# STM32F3DISCOVERY=1 +# STM32F4DISCOVERY=1 +# STM32F429IDISCOVERY=1 +# CARAMBOLA=1 +# RASPBERRYPI=1 +# LPC1768=1 # beta +# LCTECH_STM32F103RBT6=1 # LC Technology STM32F103RBT6 Ebay boards +# Or nothing for standard linux compile +# +# Also: +# +# DEBUG=1 # add debug symbols (-g) +# RELEASE=1 # Force release-style compile (no asserts, etc) +# SINGLETHREAD=1 # Compile single-threaded to make compilation errors easier to find +# BOOTLOADER=1 # make the bootloader (not Espruino) +# PROFILE=1 # Compile with gprof profiling info + +ifndef SINGLETHREAD +MAKEFLAGS=-j5 # multicore +endif + +INCLUDE=-I$(ROOT) -I$(ROOT)/targets -I$(ROOT)/src -I$(ROOT)/gen +LIBS= +DEFINES= +CFLAGS=-Wall -Wextra -Wconversion -Werror=implicit-function-declaration -fdiagnostics-show-option +OPTIMIZEFLAGS= +#-fdiagnostics-show-option - shows which flags can be used with -Werror + +# Espruino flags... +USE_MATH=1 + +ifeq ($(shell uname -m),armv6l) +RASPBERRYPI=1 # just a guess +endif + +ifeq ($(shell uname),Darwin) +MACOSX=1 +endif + +# Gordon's car ECU (extremely beta!) +ifdef ECU +STM32F4DISCOVERY=1 +#HYSTM32_32=1 +USE_TRIGGER=1 +DEFINES += -DECU +endif + +ifdef RELEASE +# force no asserts to be compiled in +DEFINES += -DNO_ASSERT +endif + +CWD = $(shell pwd) +ROOT = $(CWD) +PRECOMPILED_OBJS= +PLATFORM_CONFIG_FILE=gen/platform_config.h +BASEADDRESS=0x08000000 + +################################################### +# When adding stuff here, also remember build_pininfo, platform_config.h, jshardware.c +ifdef ESPRUINO_1V0 +USB=1 +#USE_NET=1 +#USE_CC3000=1 +USE_GRAPHICS=1 +USE_FILESYSTEM=1 +FAMILY=STM32F1 +CHIP=STM32F103RG +BOARD=ESPRUINOBOARD_R1_0 +DEFINES+=-DESPRUINOBOARD +STLIB=STM32F10X_XL +PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f1/lib/startup_stm32f10x_hd.o +OPTIMIZEFLAGS+=-O3 +else ifdef ESPRUINO_1V1 +DEFINES+=-DESPRUINO_1V1 +USE_BOOTLOADER=1 +BOOTLOADER_PROJ_NAME=bootloader_espruino_1v1 +USB=1 +USE_NET=1 +USE_CC3000=1 +USE_GRAPHICS=1 +USE_FILESYSTEM=1 +FAMILY=STM32F1 +CHIP=STM32F103RC +BOARD=ESPRUINOBOARD_R1_1 +DEFINES+=-DESPRUINOBOARD +STLIB=STM32F10X_XL +PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f1/lib/startup_stm32f10x_hd.o +OPTIMIZEFLAGS+=-Os # not that short on memory, but Travis compiler is old and uses more +else ifdef ESPRUINO_1V3 +DEFINES+=-DESPRUINO_1V3 +USE_BOOTLOADER=1 +BOOTLOADER_PROJ_NAME=bootloader_espruino_1v3 +USB=1 +USE_NET=1 +USE_CC3000=1 +USE_GRAPHICS=1 +USE_FILESYSTEM=1 +FAMILY=STM32F1 +CHIP=STM32F103RC +BOARD=ESPRUINOBOARD +STLIB=STM32F10X_XL +PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f1/lib/startup_stm32f10x_hd.o +OPTIMIZEFLAGS+=-O3 +else ifdef OLIMEXINO_STM32 +USB=1 +USE_FILESYSTEM=1 +FAMILY=STM32F1 +CHIP=STM32F103RB +BOARD=OLIMEXINO_STM32 +STLIB=STM32F10X_MD +PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f1/lib/startup_stm32f10x_md.o +OPTIMIZEFLAGS+=-Os # short on program memory +else ifdef OLIMEXINO_STM32_BOOTLOADER +USB=1 +USE_FILESYSTEM=1 +FAMILY=STM32F1 +CHIP=STM32F103RB_MAPLE +DEFINES += -DSTM32F103RB +SAVE_ON_FLASH=1 +BOARD=OLIMEXINO_STM32_BOOTLOADER +STLIB=STM32F10X_MD +PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f1/lib/startup_stm32f10x_md.o +OPTIMIZEFLAGS+=-Os # short on program memory +else ifdef EMBEDDED_PI +USB=1 +# USE_FILESYSTEM=1 # no SD-CARD READER +FAMILY=STM32F1 +CHIP=STM32F103RB +BOARD=EMBEDDED_PI +STLIB=STM32F10X_MD +PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f1/lib/startup_stm32f10x_md.o +OPTIMIZEFLAGS+=-Os # short on program memory +else ifdef HYSTM32_24 +USB=1 +USE_GRAPHICS=1 +USE_LCD_FSMC=1 +USE_FILESYSTEM=1 +USE_FILESYSTEM_SDIO=1 +FAMILY=STM32F1 +CHIP=STM32F103VE +BOARD=HYSTM32_24 +STLIB=STM32F10X_HD +PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f1/lib/startup_stm32f10x_hd.o +OPTIMIZEFLAGS+=-O3 +else ifdef HYSTM32_28 +USB=1 +USE_GRAPHICS=1 +USE_LCD_FSMC=1 +DEFINES+=-DILI9325_BITBANG # bit-bang the LCD driver +SAVE_ON_FLASH=1 +#USE_FILESYSTEM=1 # just normal SPI +FAMILY=STM32F1 +CHIP=STM32F103RB +BOARD=HYSTM32_28 +STLIB=STM32F10X_MD +PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f1/lib/startup_stm32f10x_md.o +OPTIMIZEFLAGS+=-Os +else ifdef HYSTM32_32 +USB=1 +USE_GRAPHICS=1 +USE_LCD_FSMC=1 +USE_FILESYSTEM=1 +USE_FILESYSTEM_SDIO=1 +FAMILY=STM32F1 +CHIP=STM32F103VC +BOARD=HYSTM32_32 +STLIB=STM32F10X_HD +PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f1/lib/startup_stm32f10x_hd.o +OPTIMIZEFLAGS+=-O3 +else ifdef STM32F4DISCOVERY +USB=1 +#USE_NET=1 +#USE_CC3000=1 +USE_GRAPHICS=1 +DEFINES += -DUSE_USB_OTG_FS=1 +FAMILY=STM32F4 +CHIP=STM32F407 +BOARD=STM32F4DISCOVERY +STLIB=STM32F4XX +PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f4/lib/startup_stm32f4xx.o +OPTIMIZEFLAGS+=-O3 +else ifdef STM32F429IDISCOVERY +USB=1 +USE_GRAPHICS=1 +#USE_LCD_FSMC=1 +DEFINES += -DUSE_USB_OTG_FS=1 +FAMILY=STM32F4 +CHIP=STM32F429 +BOARD=STM32F429IDISCOVERY +STLIB=STM32F4XX +PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f4/lib/startup_stm32f4xx.o +OPTIMIZEFLAGS+=-O3 +else ifdef SMARTWATCH +DEFINES+=-DHSE_VALUE=26000000UL +USB=1 +FAMILY=STM32F2 +CHIP=STM32F205RG +BOARD=SMARTWATCH +STLIB=STM32F2XX +PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f2/lib/startup_stm32f2xx.o +OPTIMIZEFLAGS+=-O3 +else ifdef STM32F3DISCOVERY +#USE_BOOTLOADER=1 +#BOOTLOADER_PROJ_NAME=bootloader_espruino_stm32f3discovery +USB=1 +FAMILY=STM32F3 +CHIP=STM32F303 +BOARD=STM32F3DISCOVERY +STLIB=STM32F3XX +PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f3/lib/startup_stm32f30x.o +OPTIMIZEFLAGS+=-O3 +else ifdef STM32VLDISCOVERY +FAMILY=STM32F1 +CHIP=STM32F100RB +BOARD=STM32VLDISCOVERY +STLIB=STM32F10X_MD_VL +PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f1/lib/startup_stm32f10x_md_vl.o +OPTIMIZEFLAGS+=-Os # short on program memory +else ifdef TINYCHIP +FAMILY=STM32F1 +CHIP=STM32F103TB +BOARD=TINYCHIP +STLIB=STM32F10X_MD +PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f1/lib/startup_stm32f10x_md.o +OPTIMIZEFLAGS+=-Os # short on program memory +else ifdef LPC1768 +MBED=1 +FAMILY=LPC1768 +CHIP=LPC1768 +BOARD=LPC1768 +MBED_GCC_CS_DIR=$(ROOT)/targets/libmbed/LPC1768/GCC_CS +PRECOMPILED_OBJS+=$(MBED_GCC_CS_DIR)/sys.o $(MBED_GCC_CS_DIR)/cmsis_nvic.o $(MBED_GCC_CS_DIR)/system_LPC17xx.o $(MBED_GCC_CS_DIR)/core_cm3.o $(MBED_GCC_CS_DIR)/startup_LPC17xx.o +LIBS+=-L$(MBED_GCC_CS_DIR) -lmbed +OPTIMIZEFLAGS+=-O3 +else ifdef CARAMBOLA +BOARD=CARAMBOLA +DEFINES += -DCARAMBOLA -DSYSFS_GPIO_DIR="\"/sys/class/gpio\"" +LINUX=1 +USE_FILESYSTEM=1 +USB=1 +USE_GRAPHICS=1 +USE_NET=1 +else ifdef RASPBERRYPI +BOARD=RASPBERRYPI +DEFINES += -DRASPBERRYPI -DSYSFS_GPIO_DIR="\"/sys/class/gpio\"" +LINUX=1 +USE_FILESYSTEM=1 +USB=1 +USE_GRAPHICS=1 +#USE_LCD_SDL=1 +USE_NET=1 +else ifdef LCTECH_STM32F103RBT6 +USB=1 +SAVE_ON_FLASH=1 +FAMILY=STM32F1 +CHIP=STM32F103RB +BOARD=LCTECH_STM32F103RBT6 +STLIB=STM32F10X_MD +PRECOMPILED_OBJS+=$(ROOT)/targetlibs/stm32f1/lib/startup_stm32f10x_md.o +OPTIMIZEFLAGS+=-Os +else +BOARD=LINUX +LINUX=1 +USE_FILESYSTEM=1 +USB=1 +USE_GRAPHICS=1 +#USE_LCD_SDL=1 +ifndef MACOSX +# http libs need some tweaks before net can compile +USE_NET=1 +endif +endif + +PROJ_NAME=$(shell python scripts/get_binary_name.py $(BOARD) | sed -e "s/.bin$$//") +ifeq ($(PROJ_NAME),) +$(error Unable to work out binary name (PROJ_NAME)) +endif +ifeq ($(BOARD),LINUX) +PROJ_NAME=espruino +endif + + + +ifdef DEBUG +#OPTIMIZEFLAGS=-Os -g +OPTIMIZEFLAGS=-g +endif + +ifdef PROFILE +OPTIMIZEFLAGS+=-pg +endif + +WRAPPERFILE=gen/jswrapper.c +WRAPPERSOURCES = \ +src/jswrap_pin.c \ +src/jswrap_functions.c \ +src/jswrap_modules.c \ +src/jswrap_process.c \ +src/jswrap_interactive.c \ +src/jswrap_json.c \ +src/jswrap_object.c \ +src/jswrap_string.c \ +src/jswrap_array.c \ +src/jswrap_arraybuffer.c \ +src/jswrap_serial.c \ +src/jswrap_spi_i2c.c \ +src/jswrap_onewire.c \ +src/jswrap_io.c +# it is important that _pin comes before stuff which uses +# integers (as the check for int *includes* the chek for pin) + +SOURCES = \ +src/jslex.c \ +src/jsvar.c \ +src/jsutils.c \ +src/jsparse.c \ +src/jspin.c \ +src/jsinteractive.c \ +src/jsdevices.c \ +$(WRAPPERFILE) +CPPSOURCES = + +ifdef BOOTLOADER +ifndef USE_BOOTLOADER +$(error Using bootloader on device that is not expecting one) +endif +BUILD_LINKER_FLAGS+=--bootloader +PROJ_NAME=$(BOOTLOADER_PROJ_NAME) +WRAPPERSOURCES = +SOURCES = \ +targets/stm32_boot/main.c \ +targets/stm32_boot/utils.c + ifndef DEBUG + OPTIMIZEFLAGS=-Os + endif +else # !BOOTLOADER + ifdef USE_BOOTLOADER + BUILD_LINKER_FLAGS+=--using_bootloader + STM32LOADER_FLAGS+=-p /dev/ttyACM0 + BASEADDRESS=$(shell python -c "import sys;sys.path.append('scripts');import common;print hex(0x08000000+common.get_bootloader_size())") + endif +endif + +ifdef USB_PRODUCT_ID +DEFINES+=-DUSB_PRODUCT_ID=$(USB_PRODUCT_ID) +endif + +ifdef SAVE_ON_FLASH +DEFINES+=-DSAVE_ON_FLASH +endif + +ifdef USE_FILESYSTEM +DEFINES += -DUSE_FILESYSTEM +WRAPPERSOURCES += libs/jswrap_fat.c +ifndef LINUX +INCLUDE += -I$(ROOT)/libs/fat_sd +SOURCES += \ +libs/fat_sd/fattime.c \ +libs/fat_sd/ff.c +#libs/fat_sd/option/ccsbcs.c # for LFN support (see _USE_LFN in ff.h) + +ifdef USE_FILESYSTEM_SDIO +DEFINES += -DUSE_FILESYSTEM_SDIO +SOURCES += \ +libs/fat_sd/sdio_diskio.c \ +libs/fat_sd/sdio_sdcard.c +else #USE_FILESYSTEM_SDIO +SOURCES += \ +libs/fat_sd/spi_diskio.c +endif #USE_FILESYSTEM_SDIO +endif #!LINUX +endif #USE_FILESYSTEM + +ifdef USE_MATH +DEFINES += -DUSE_MATH +WRAPPERSOURCES += libs/jswrap_math.c + +ifndef LINUX +INCLUDE += -I$(ROOT)/libs/math +SOURCES += \ +libs/math/acosh.c \ +libs/math/asin.c \ +libs/math/asinh.c \ +libs/math/atan.c \ +libs/math/atanh.c \ +libs/math/cbrt.c \ +libs/math/chbevl.c \ +libs/math/clog.c \ +libs/math/cmplx.c \ +libs/math/const.c \ +libs/math/cosh.c \ +libs/math/drand.c \ +libs/math/exp10.c \ +libs/math/exp2.c \ +libs/math/exp.c \ +libs/math/fabs.c \ +libs/math/floor.c \ +libs/math/isnan.c \ +libs/math/log10.c \ +libs/math/log2.c \ +libs/math/log.c \ +libs/math/mtherr.c \ +libs/math/polevl.c \ +libs/math/pow.c \ +libs/math/powi.c \ +libs/math/round.c \ +libs/math/setprec.c \ +libs/math/sin.c \ +libs/math/sincos.c \ +libs/math/sindg.c \ +libs/math/sinh.c \ +libs/math/sqrt.c \ +libs/math/tan.c \ +libs/math/tandg.c \ +libs/math/tanh.c \ +libs/math/unity.c +#libs/math/mod2pi.c +#libs/math/mtst.c +#libs/math/dtestvec.c +endif +endif + +ifdef USE_GRAPHICS +DEFINES += -DUSE_GRAPHICS +WRAPPERSOURCES += libs/graphics/jswrap_graphics.c +INCLUDE += -I$(ROOT)/libs/graphics +SOURCES += \ +libs/graphics/bitmap_font_8x8.c \ +libs/graphics/graphics.c \ +libs/graphics/lcd_arraybuffer.c \ +libs/graphics/lcd_js.c + +ifdef USE_LCD_SDL +DEFINES += -DUSE_LCD_SDL +SOURCES += libs/graphics/lcd_sdl.c +LIBS += -lSDL +INCLUDE += -I/usr/include/SDL +endif + +ifdef USE_LCD_FSMC +DEFINES += -DUSE_LCD_FSMC +SOURCES += libs/graphics/lcd_fsmc.c +endif + +endif + +ifdef USE_NET +DEFINES += -DUSE_NET +WRAPPERSOURCES += libs/network/http/jswrap_http.c +INCLUDE += -I$(ROOT)/libs/network/http +SOURCES += \ +libs/network/http/httpserver.c +ifdef LINUX +#LIBS += -l... +#INCLUDE += -I... +endif +endif + +ifdef USE_CC3000 +DEFINES += -DUSE_CC3000 -DSEND_NON_BLOCKING +WRAPPERSOURCES += libs/network/cc3000/jswrap_cc3000.c +INCLUDE += -I$(ROOT)/libs/network/cc3000 +SOURCES += \ +libs/network/cc3000/board_spi.c \ +libs/network/cc3000/cc3000_common.c \ +libs/network/cc3000/evnt_handler.c \ +libs/network/cc3000/hci.c \ +libs/network/cc3000/netapp.c \ +libs/network/cc3000/nvmem.c \ +libs/network/cc3000/security.c \ +libs/network/cc3000/socket.c \ +libs/network/cc3000/wlan.c +endif + +ifdef USE_TRIGGER +DEFINES += -DUSE_TRIGGER +WRAPPERSOURCES += libs/trigger/jswrap_trigger.c +INCLUDE += -I$(ROOT)/libs/trigger +SOURCES += \ +./libs/trigger/trigger.c +endif + +ifdef USB +DEFINES += -DUSB +endif + +ifeq ($(FAMILY), STM32F1) +ARCHFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m3 -mfix-cortex-m3-ldrd -mthumb-interwork -mfloat-abi=soft +ARM=1 +STM32=1 +INCLUDE += -I$(ROOT)/targetlibs/stm32f1 -I$(ROOT)/targetlibs/stm32f1/lib +DEFINES += -DSTM32F1 +SOURCES += \ +targetlibs/stm32f1/lib/misc.c \ +targetlibs/stm32f1/lib/stm32f10x_adc.c \ +targetlibs/stm32f1/lib/stm32f10x_bkp.c \ +targetlibs/stm32f1/lib/stm32f10x_can.c \ +targetlibs/stm32f1/lib/stm32f10x_cec.c \ +targetlibs/stm32f1/lib/stm32f10x_crc.c \ +targetlibs/stm32f1/lib/stm32f10x_dac.c \ +targetlibs/stm32f1/lib/stm32f10x_dbgmcu.c \ +targetlibs/stm32f1/lib/stm32f10x_dma.c \ +targetlibs/stm32f1/lib/stm32f10x_exti.c \ +targetlibs/stm32f1/lib/stm32f10x_flash.c \ +targetlibs/stm32f1/lib/stm32f10x_fsmc.c \ +targetlibs/stm32f1/lib/stm32f10x_gpio.c \ +targetlibs/stm32f1/lib/stm32f10x_i2c.c \ +targetlibs/stm32f1/lib/stm32f10x_iwdg.c \ +targetlibs/stm32f1/lib/stm32f10x_pwr.c \ +targetlibs/stm32f1/lib/stm32f10x_rcc.c \ +targetlibs/stm32f1/lib/stm32f10x_rtc.c \ +targetlibs/stm32f1/lib/stm32f10x_sdio.c \ +targetlibs/stm32f1/lib/stm32f10x_spi.c \ +targetlibs/stm32f1/lib/stm32f10x_tim.c \ +targetlibs/stm32f1/lib/stm32f10x_usart.c \ +targetlibs/stm32f1/lib/stm32f10x_wwdg.c \ +targetlibs/stm32f1/lib/system_stm32f10x.c + +ifdef USB +INCLUDE += -I$(ROOT)/targetlibs/stm32f1/usblib -I$(ROOT)/targetlibs/stm32f1/usb +SOURCES += \ +targetlibs/stm32f1/usblib/otgd_fs_cal.c \ +targetlibs/stm32f1/usblib/otgd_fs_dev.c \ +targetlibs/stm32f1/usblib/otgd_fs_int.c \ +targetlibs/stm32f1/usblib/otgd_fs_pcd.c \ +targetlibs/stm32f1/usblib/usb_core.c \ +targetlibs/stm32f1/usblib/usb_init.c \ +targetlibs/stm32f1/usblib/usb_int.c \ +targetlibs/stm32f1/usblib/usb_mem.c \ +targetlibs/stm32f1/usblib/usb_regs.c \ +targetlibs/stm32f1/usblib/usb_sil.c \ +targetlibs/stm32f1/usb/usb_desc.c \ +targetlibs/stm32f1/usb/usb_endp.c \ +targetlibs/stm32f1/usb/usb_istr.c \ +targetlibs/stm32f1/usb/usb_prop.c \ +targetlibs/stm32f1/usb/usb_pwr.c \ +targetlibs/stm32f1/usb/usb_utils.c +endif #USB + +endif #STM32F1 + +ifeq ($(FAMILY), STM32F2) +ARCHFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m3 -mthumb-interwork -mfpu=fpv4-sp-d16 -mfloat-abi=softfp +ARM=1 +STM32=1 +INCLUDE += -I$(ROOT)/targetlibs/stm32f2 -I$(ROOT)/targetlibs/stm32f2/lib +DEFINES += -DSTM32F2 +SOURCES += \ +targetlibs/stm32f2/lib/misc.c \ +targetlibs/stm32f2/lib/stm32f2xx_adc.c \ +targetlibs/stm32f2/lib/stm32f2xx_can.c \ +targetlibs/stm32f2/lib/stm32f2xx_crc.c \ +targetlibs/stm32f2/lib/stm32f2xx_cryp_aes.c\ +targetlibs/stm32f2/lib/stm32f2xx_cryp.c \ +targetlibs/stm32f2/lib/stm32f2xx_cryp_des.c\ +targetlibs/stm32f2/lib/stm32f2xx_cryp_tdes.c\ +targetlibs/stm32f2/lib/stm32f2xx_dac.c \ +targetlibs/stm32f2/lib/stm32f2xx_dbgmcu.c \ +targetlibs/stm32f2/lib/stm32f2xx_dcmi.c \ +targetlibs/stm32f2/lib/stm32f2xx_dma.c \ +targetlibs/stm32f2/lib/stm32f2xx_exti.c \ +targetlibs/stm32f2/lib/stm32f2xx_flash.c \ +targetlibs/stm32f2/lib/stm32f2xx_fsmc.c \ +targetlibs/stm32f2/lib/stm32f2xx_gpio.c \ +targetlibs/stm32f2/lib/stm32f2xx_hash.c \ +targetlibs/stm32f2/lib/stm32f2xx_hash_md5.c \ +targetlibs/stm32f2/lib/stm32f2xx_hash_sha1.c \ +targetlibs/stm32f2/lib/stm32f2xx_i2c.c \ +targetlibs/stm32f2/lib/stm32f2xx_iwdg.c \ +targetlibs/stm32f2/lib/stm32f2xx_pwr.c \ +targetlibs/stm32f2/lib/stm32f2xx_rcc.c \ +targetlibs/stm32f2/lib/stm32f2xx_rng.c \ +targetlibs/stm32f2/lib/stm32f2xx_rtc.c \ +targetlibs/stm32f2/lib/stm32f2xx_sdio.c \ +targetlibs/stm32f2/lib/stm32f2xx_spi.c \ +targetlibs/stm32f2/lib/stm32f2xx_syscfg.c \ +targetlibs/stm32f2/lib/stm32f2xx_tim.c \ +targetlibs/stm32f2/lib/stm32f2xx_usart.c \ +targetlibs/stm32f2/lib/stm32f2xx_wwdg.c \ +targetlibs/stm32f2/lib/system_stm32f2xx.c + + +ifdef USB +INCLUDE += -I$(ROOT)/targetlibs/stm32f2/usblib -I$(ROOT)/targetlibs/stm32f2/usb +SOURCES += \ +targetlibs/stm32f2/usb/usbd_cdc_vcp.c \ +targetlibs/stm32f2/usb/usb_irq_handlers.c \ +targetlibs/stm32f2/usb/usbd_desc.c \ +targetlibs/stm32f2/usb/usbd_usr.c \ +targetlibs/stm32f2/usb/usb_bsp.c \ +targetlibs/stm32f2/usblib/usbd_req.c \ +targetlibs/stm32f2/usblib/usb_dcd_int.c \ +targetlibs/stm32f2/usblib/usbd_core.c \ +targetlibs/stm32f2/usblib/usbd_cdc_core.c \ +targetlibs/stm32f2/usblib/usbd_ioreq.c \ +targetlibs/stm32f2/usblib/usb_core.c \ +targetlibs/stm32f2/usblib/usb_dcd.c +#targetlibs/stm32f2/usblib/usb_otg.c \ +#targetlibs/stm32f2/usblib/usb_bsp_template.c \ +#targetlibs/stm32f2/usblib/usbd_cdc_if_template.c \ +#targetlibs/stm32f2/usblib/usb_hcd.c \ +#targetlibs/stm32f2/usblib/usb_hcd_int.c +endif #USB +endif #STM32F2 + +ifeq ($(FAMILY), STM32F3) +ARCHFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfpu=fpv4-sp-d16 -mfloat-abi=softfp +ARM=1 +STM32=1 +INCLUDE += -I$(ROOT)/targetlibs/stm32f3 -I$(ROOT)/targetlibs/stm32f3/lib +DEFINES += -DSTM32F3 +SOURCES += \ +targetlibs/stm32f3/lib/stm32f30x_adc.c \ +targetlibs/stm32f3/lib/stm32f30x_can.c \ +targetlibs/stm32f3/lib/stm32f30x_comp.c \ +targetlibs/stm32f3/lib/stm32f30x_crc.c \ +targetlibs/stm32f3/lib/stm32f30x_dac.c \ +targetlibs/stm32f3/lib/stm32f30x_dbgmcu.c \ +targetlibs/stm32f3/lib/stm32f30x_dma.c \ +targetlibs/stm32f3/lib/stm32f30x_exti.c \ +targetlibs/stm32f3/lib/stm32f30x_flash.c \ +targetlibs/stm32f3/lib/stm32f30x_gpio.c \ +targetlibs/stm32f3/lib/stm32f30x_i2c.c \ +targetlibs/stm32f3/lib/stm32f30x_iwdg.c \ +targetlibs/stm32f3/lib/stm32f30x_misc.c \ +targetlibs/stm32f3/lib/stm32f30x_opamp.c \ +targetlibs/stm32f3/lib/stm32f30x_pwr.c \ +targetlibs/stm32f3/lib/stm32f30x_rcc.c \ +targetlibs/stm32f3/lib/stm32f30x_rtc.c \ +targetlibs/stm32f3/lib/stm32f30x_spi.c \ +targetlibs/stm32f3/lib/stm32f30x_syscfg.c \ +targetlibs/stm32f3/lib/stm32f30x_tim.c \ +targetlibs/stm32f3/lib/stm32f30x_usart.c \ +targetlibs/stm32f3/lib/stm32f30x_wwdg.c \ +targetlibs/stm32f3/lib/system_stm32f30x.c + +ifdef USB +INCLUDE += -I$(ROOT)/targetlibs/stm32f3/usblib -I$(ROOT)/targetlibs/stm32f3/usb +SOURCES += \ +targetlibs/stm32f3/usblib/usb_core.c \ +targetlibs/stm32f3/usblib/usb_init.c \ +targetlibs/stm32f3/usblib/usb_int.c \ +targetlibs/stm32f3/usblib/usb_mem.c \ +targetlibs/stm32f3/usblib/usb_regs.c \ +targetlibs/stm32f3/usblib/usb_sil.c \ +targetlibs/stm32f3/usb/usb_desc.c \ +targetlibs/stm32f3/usb/usb_endp.c \ +targetlibs/stm32f3/usb/usb_istr.c \ +targetlibs/stm32f3/usb/usb_prop.c \ +targetlibs/stm32f3/usb/usb_pwr.c \ +targetlibs/stm32f3/usb/usb_utils.c +endif #USB +endif #STM32F3 + +ifeq ($(FAMILY), STM32F4) +ARCHFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfpu=fpv4-sp-d16 -mfloat-abi=softfp +ARM=1 +STM32=1 +INCLUDE += -I$(ROOT)/targetlibs/stm32f4 -I$(ROOT)/targetlibs/stm32f4/lib +DEFINES += -DSTM32F4 +SOURCES += \ +targetlibs/stm32f4/lib/misc.c \ +targetlibs/stm32f4/lib/stm32f4xx_adc.c \ +targetlibs/stm32f4/lib/stm32f4xx_can.c \ +targetlibs/stm32f4/lib/stm32f4xx_crc.c \ +targetlibs/stm32f4/lib/stm32f4xx_cryp_aes.c \ +targetlibs/stm32f4/lib/stm32f4xx_cryp.c \ +targetlibs/stm32f4/lib/stm32f4xx_cryp_des.c \ +targetlibs/stm32f4/lib/stm32f4xx_cryp_tdes.c \ +targetlibs/stm32f4/lib/stm32f4xx_dac.c \ +targetlibs/stm32f4/lib/stm32f4xx_dbgmcu.c \ +targetlibs/stm32f4/lib/stm32f4xx_dcmi.c \ +targetlibs/stm32f4/lib/stm32f4xx_dma.c \ +targetlibs/stm32f4/lib/stm32f4xx_exti.c \ +targetlibs/stm32f4/lib/stm32f4xx_flash.c \ +targetlibs/stm32f4/lib/stm32f4xx_fsmc.c \ +targetlibs/stm32f4/lib/stm32f4xx_gpio.c \ +targetlibs/stm32f4/lib/stm32f4xx_hash.c \ +targetlibs/stm32f4/lib/stm32f4xx_hash_md5.c \ +targetlibs/stm32f4/lib/stm32f4xx_hash_sha1.c \ +targetlibs/stm32f4/lib/stm32f4xx_i2c.c \ +targetlibs/stm32f4/lib/stm32f4xx_iwdg.c \ +targetlibs/stm32f4/lib/stm32f4xx_pwr.c \ +targetlibs/stm32f4/lib/stm32f4xx_rcc.c \ +targetlibs/stm32f4/lib/stm32f4xx_rng.c \ +targetlibs/stm32f4/lib/stm32f4xx_rtc.c \ +targetlibs/stm32f4/lib/stm32f4xx_sdio.c \ +targetlibs/stm32f4/lib/stm32f4xx_spi.c \ +targetlibs/stm32f4/lib/stm32f4xx_syscfg.c \ +targetlibs/stm32f4/lib/stm32f4xx_tim.c \ +targetlibs/stm32f4/lib/stm32f4xx_usart.c \ +targetlibs/stm32f4/lib/stm32f4xx_wwdg.c \ +targetlibs/stm32f4/lib/system_stm32f4xx.c + +ifdef USB +INCLUDE += -I$(ROOT)/targetlibs/stm32f4/usblib -I$(ROOT)/targetlibs/stm32f4/usb +SOURCES += \ +targetlibs/stm32f4/usblib/usb_core.c \ +targetlibs/stm32f4/usblib/usbd_cdc_core.c \ +targetlibs/stm32f4/usblib/usb_dcd.c \ +targetlibs/stm32f4/usblib/usb_dcd_int.c \ +targetlibs/stm32f4/usblib/usbd_core.c \ +targetlibs/stm32f4/usblib/usbd_ioreq.c \ +targetlibs/stm32f4/usblib/usbd_req.c \ +targetlibs/stm32f4/usb/usb_bsp.c \ +targetlibs/stm32f4/usb/usbd_cdc_vcp.c \ +targetlibs/stm32f4/usb/usbd_desc.c \ +targetlibs/stm32f4/usb/usbd_usr.c +#targetlibs/stm32f4/usblib/usb_hcd.c +#targetlibs/stm32f4/usblib/usb_hcd_int.c +#targetlibs/stm32f4/usblib/usb_otg.c +endif #USB +endif #STM32F4 + + +ifdef MBED +ARCHFLAGS += -mcpu=cortex-m3 -mthumb +ARM=1 +INCLUDE+=-I$(ROOT)/targetlibs/libmbed -I$(ROOT)/targetlibs/libmbed/$(CHIP) -I$(ROOT)/targetlibs/libmbed/$(CHIP)/GCC_CS +DEFINES += -DMBED +INCLUDE += -I$(ROOT)/targetlibs/mbed +SOURCES += targets/mbed/main.c +CPPSOURCES += targets/mbed/jshardware.cpp +endif + +ifdef ARM +LINKER_FILE = gen/linker.ld +DEFINES += -DARM +INCLUDE += -I$(ROOT)/targetlibs/arm +OPTIMIZEFLAGS += -fno-common -fno-exceptions -fdata-sections -ffunction-sections +# -flto -fuse-linker-plugin +# -flto - link time optimisation - could be good for ST's libs +# GCC suggests use of -fuse-linker-plugin with flto +# Does not work - get errors like : `sqrt' referenced in section `.text.asin' of /tmp/ccJheOub.ltrans9.ltrans.o: defined in discarded section `.text' of libs/math/sqrt.o (symbol from plugin) + + +# 4.6 +#export CCPREFIX=arm-linux-gnueabi- +# 4.5 +#export CCPREFIX=~/sat/bin/arm-none-eabi- +# 4.4 +export CCPREFIX=arm-none-eabi- +endif # ARM + +PININFOFILE=$(ROOT)/gen/jspininfo +ifdef PININFOFILE +SOURCES += $(PININFOFILE).c +endif + +ifdef CARAMBOLA +TOOLCHAIN_DIR=$(shell cd ~/workspace/carambola/staging_dir/toolchain-*/bin;pwd) +export STAGING_DIR=$(TOOLCHAIN_DIR) +export CCPREFIX=$(TOOLCHAIN_DIR)/mipsel-openwrt-linux- +endif + +ifdef RASPBERRYPI + ifneq ($(shell uname -m),armv6l) + # eep. let's cross compile + export CCPREFIX=targetlibs/raspberrypi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf- + else + # compiling in-place, so give it a normal name + PROJ_NAME=espruino + endif +endif + + +ifdef STM32 +DEFINES += -DFAKE_STDLIB +# FAKE_STDLIB is for Espruino - it uses its own standard library so we don't have to link in the normal one + get bloated +DEFINES += -DSTM32 -DUSE_STDPERIPH_DRIVER=1 -D$(CHIP) -D$(BOARD) -D$(STLIB) +INCLUDE += -I$(ROOT)/targets/stm32 +ifndef BOOTLOADER +SOURCES += \ +targets/stm32/main.c \ +targets/stm32/jshardware.c \ +targets/stm32/stm32_it.c +endif +endif + +ifdef LINUX +DEFINES += -DLINUX +INCLUDE += -I$(ROOT)/targets/linux +SOURCES += \ +targets/linux/main.c \ +targets/linux/jshardware.c +LIBS += -lm # maths lib +endif + +SOURCES += $(WRAPPERSOURCES) +SOURCEOBJS = $(SOURCES:.c=.o) $(CPPSOURCES:.cpp=.o) +OBJS = $(SOURCEOBJS) $(PRECOMPILED_OBJS) + + +# -ffreestanding -nodefaultlibs -nostdlib -fno-common +# -nodefaultlibs -nostdlib -nostartfiles + +# -fdata-sections -ffunction-sections are to help remove unused code +CFLAGS += $(OPTIMIZEFLAGS) -c $(ARCHFLAGS) $(DEFINES) $(INCLUDE) + +# -Wl,--gc-sections helps remove unused code +# -Wl,--whole-archive checks for duplicates +LDFLAGS += $(OPTIMIZEFLAGS) $(ARCHFLAGS) +ifndef MACOSX +LDFLAGS += -Wl,--gc-sections +endif + +ifdef LINKER_FILE +LDFLAGS += -T$(LINKER_FILE) +endif + +export CC=$(CCPREFIX)gcc +export LD=$(CCPREFIX)gcc +export AR=$(CCPREFIX)ar +export AS=$(CCPREFIX)as +export OBJCOPY=$(CCPREFIX)objcopy +export OBJDUMP=$(CCPREFIX)objdump +export GDB=$(CCPREFIX)gdb + + +.PHONY: proj + +all: proj + +ifeq ($(V),1) + quiet_= + Q= +else + quiet_=quiet_ + Q=@ + export SILENT=1 +endif + + +$(WRAPPERFILE): scripts/build_jswrapper.py $(WRAPPERSOURCES) + @echo Generating JS wrappers + $(Q)echo WRAPPERSOURCES = $(WRAPPERSOURCES) + $(Q)echo DEFINES = $(DEFINES) + $(Q)python scripts/build_jswrapper.py $(WRAPPERSOURCES) $(DEFINES) + +ifdef PININFOFILE +$(PININFOFILE).c $(PININFOFILE).h: scripts/build_pininfo.py + @echo Generating pin info + $(Q)python scripts/build_pininfo.py $(BOARD) $(PININFOFILE).c $(PININFOFILE).h +endif + +$(LINKER_FILE): scripts/build_linker.py + @echo Generating linker scripts + $(Q)python scripts/build_linker.py $(BOARD) $(LINKER_FILE) $(BUILD_LINKER_FLAGS) + +$(PLATFORM_CONFIG_FILE): boards/$(BOARD).py scripts/build_platform_config.py + @echo Generating platform configs + $(Q)python scripts/build_platform_config.py $(BOARD) + +compile=$(CC) $(CFLAGS) $(DEFINES) $< -o $@ +link=$(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) +obj_dump=$(OBJDUMP) -x -S $(PROJ_NAME).elf > $(PROJ_NAME).lst +obj_to_bin=$(OBJCOPY) -O $1 $(PROJ_NAME).elf $(PROJ_NAME).$2 + +quiet_compile= CC $@ +quiet_link= LD $@ +quiet_obj_dump= GEN $(PROJ_NAME).lst +quiet_obj_to_bin= GEN $(PROJ_NAME).$2 + +%.o: %.c $(PLATFORM_CONFIG_FILE) $(PININFOFILE).h + @echo $($(quiet_)compile) + @$(call compile) + +.cpp.o: $(PLATFORM_CONFIG_FILE) $(PININFOFILE).h + @echo $($(quiet_)compile) + @$(call compile) + +.s.o: + @echo $($(quiet_)compile) + @$(call compile) + +ifdef LINUX # --------------------------------------------------- +proj: $(PLATFORM_CONFIG_FILE) $(PROJ_NAME) + +$(PROJ_NAME): $(OBJS) + @echo $($(quiet_)link) + @$(call link) + +else # embedded, so generate bin, etc --------------------------- + +$(PROJ_NAME).elf: $(OBJS) $(LINKER_FILE) + @echo $($(quiet_)link) + @$(call link) + +$(PROJ_NAME).lst : $(PROJ_NAME).elf + @echo $($(quiet_)obj_dump) + @$(call obj_dump) + +$(PROJ_NAME).hex: $(PROJ_NAME).elf + @echo $(call $(quiet_)obj_to_bin,ihex,hex) + @$(call obj_to_bin,ihex,hex) + +$(PROJ_NAME).srec : $(PROJ_NAME).elf + @echo $(call $(quiet_)obj_to_bin,srec,srec) + @$(call obj_to_bin,srec,srec) + +$(PROJ_NAME).bin : $(PROJ_NAME).elf + @echo $(call $(quiet_)obj_to_bin,binary,bin) + @$(call obj_to_bin,binary,bin) + bash scripts/check_size.sh $(PROJ_NAME).bin + +proj: $(PROJ_NAME).lst $(PROJ_NAME).bin +#proj: $(PROJ_NAME).lst $(PROJ_NAME).hex $(PROJ_NAME).srec $(PROJ_NAME).bin + +flash: all +ifdef OLIMEXINO_STM32_BOOTLOADER + echo Olimexino Serial bootloader + dfu-util -a1 -d 0x1EAF:0x0003 -D $(PROJ_NAME).bin +else +ifdef MBED + cp $(PROJ_NAME).bin /media/MBED;sync +else + echo ST-LINK flash + ~/bin/st-flash write $(PROJ_NAME).bin $(BASEADDRESS) +endif +endif + +serialflash: all + echo STM32 inbuilt serial bootloader, set BOOT0=1, BOOT1=0 + python scripts/stm32loader.py -b 460800 -a $(BASEADDRESS) -ew $(STM32LOADER_FLAGS) $(PROJ_NAME).bin +# python scripts/stm32loader.py -b 460800 -a $(BASEADDRESS) -ewv $(STM32LOADER_FLAGS) $(PROJ_NAME).bin + +gdb: + echo "target extended-remote :4242" > gdbinit + echo "file $(PROJ_NAME).elf" >> gdbinit + #echo "load" >> gdbinit + echo "break main" >> gdbinit + echo "break HardFault_Handler" >> gdbinit + $(GDB) -x gdbinit + rm gdbinit +endif # --------------------------------------------------- + +clean: + @echo Cleaning targets + $(Q)find . -name *.o | grep -v libmbed | grep -v arm-bcm2708 | xargs rm -f + $(Q)rm -f $(ROOT)/gen/*.c $(ROOT)/gen/*.h $(ROOT)/gen/*.ld + $(Q)rm -f $(PROJ_NAME).elf + $(Q)rm -f $(PROJ_NAME).hex + $(Q)rm -f $(PROJ_NAME).bin + $(Q)rm -f $(PROJ_NAME).srec + $(Q)rm -f $(PROJ_NAME).lst diff --git a/components/external/espruino/README.md b/components/external/espruino/README.md new file mode 100644 index 0000000000..7b0b7ecabe --- /dev/null +++ b/components/external/espruino/README.md @@ -0,0 +1,161 @@ +Espruino JavaScript for Microcontrollers +======================================== +
+ _____                 _
+|   __|___ ___ ___ _ _|_|___ ___
+|   __|_ -| . |  _| | | |   | . |
+|_____|___|  _|_| |___|_|_|_|___|
+          |_|      
+
+http://www.espruino.com + +**NOTE:** This software is beta and is provided as-is, and won't be considered even remotely final until we've released the Espruino Board. As such, don't expect support, and do expect it to change rapidly and without warning. Build your own documentation (see **Building**), as the API may be different from the one described on the Espruino website. + +The KickStarter campaign said the Espruino Board will have some things which this repository does not yet have (like working CC3000 support). These are works in progress and should be done by the time you get your board (or will be available as a software update). + + +About +----- + +It'd probably help to read the [FAQ](http://www.espruino.com/FAQ), and specifically the page about [Performance](http://www.espruino.com/Performance) as it contains information about how Espruino itself works. + +There's also the auto-generated [Reference](http://www.espruino.com/Reference) for JavaScript commands as well as the [Tutorials](http://www.espruino.com/Tutorials) on the website. However please note that this repository is under heavy development, and the documentation on the Espruino website will match the version [available for download](http://www.espruino.com/Download) but **not** the latest version from Git. + + +License +------- + +Please see the [LICENSE](LICENSE) file + + +Found a Bug? +------------ + +Please check that: +* It hasn't [already been found](https://github.com/espruino/Espruino/issues) or [been covered on our forum](www.espruino.com/Forum) +* You're not just looking at outdated documentation (See the [Building](#Building) section to see how to build documentation) + +Please [submit bugs](https://github.com/espruino/Espruino/issues) with clear steps to reproduce them (and ideally a test case for the ```tests``` directory), and if at all possible try and include a patch to fix them. Please be aware that we have a whole bunch of outstanding issues (some quite large), so if you report something (especially if it doesn't contain a test or a pull request) it may not be fixed for quite some time. + + +Contributing +------------ + +Please see [CONTRIBUTING.md](CONTRIBUTING.md) + +Current State +------------- + +You can download binaries from http://www.espruino.com/Download (these aren't the latest, but are more likely to work with your board) + +Please note that this is BETA. We've been working hard on the Espruino Board support but we haven't had time to check the other boards properly. + +* Espruino Board - working +* Linux - working +* STM32VLDISCOVERY - WORKING +* STM32F3DISCOVERY - WORKING +* STM32F4DISCOVERY - WORKING +* STM32F429IDISCOVERY - not working, currently no LCD support +* HY STM32 2.4" - NOT WORKING - appears to crash after startup +* HY STM32 2.8" - WORKING, but screen is not black at startup +* HY STM32 3.2" - WORKING +* Olimexino - WORKING +* Carambola - ? +* Raspberry Pi - WORKING +* Sony SmartWatch - USB VCP support still needed +* MBed platforms - have not worked for a while - hardware wrapper still needed +* Arduino - has never worked. Compiles but doesn't even get past init +* LC-TECH STM32F103RBT6 - WORKING, but with some issues (LED inverted logic, BTN needs pullup to work) + +Using +----- + +If you're using Espruino for your own personal projects - go ahead, we hope you have fun - and please let us know what you do with it on http://www.espruino.com/Forum! + +However if you're planning on selling the Espruino software on your own board, please talk to us: + +* Read the terms of the MPLv2 Licence that Espruino is distributed under, and make sure you comply with it +* You won't be able to call your board 'Espruino' but you must explain clearly that it uses 'Espruino' internally (we own the trademark) +* If you're profiting from Espruino without contributing anything back, we won't support you (or your users) + + +Building +-------- + +Espruino is easy to build under Linux, and it is possible to build under MacOS. We'd strongly suggest that you DO NOT TRY AND BUILD UNDER WINDOWS, and instead use a Virtual Machine. There's a good post on this here: http://forum.espruino.com/conversations/151 + +We suggest that you use the CodeSourcery GCC compiler, but paths in Makefile may need changing... + +``` BOARDNAME=1 RELEASE=1 make``` + +* See the top of Makefile for board names +* Without `RELEASE=1`, assertions are kept in the code (which is good for debugging, bad for performance + code size) +* `BOARDNAME=1 RELEASE=1 make serialflash` will flash to /dev/ttyUSB0 using the STM32 serial bootloader (what's needed for Espruino + HY boards) +* `BOARDNAME=1 RELEASE=1 make flash` will flash using st-flash if discovery, or maple bootloader if using that board + +You can build documentation by running: + +``` python scripts/build_docs.py ``` + +This will create a file called ```functions.html``` + +Directories and Files +--------------------- + +* `ChangeLog`: What's new +* `TODO`: List of things to do +* `boards/`: Information on boards, used to auto-generate a lot of the code +* `code/`: Example JavaScript code +* `gen/`: Auto-Generated Source Files +* `libs/`: Optional libraries to include in Espruino (Math, Filesystem, Graphics, etc) +* `linker/`: Linker files for various processors +* `misc/`: random other stuff +* `scripts/`: Scripts for generating files in gen, and for analysing code/compilation/etc +* `src/`: Main source code +* `targetlibs/`: Libraries for targeted architectures +* `targets/`: Specific code for targeted architectures +* `tests/`: JavaScript Testcases +* `benchmark/`: JavaScript Benchmarks +* `dist_*`: files to be copied into distribution zip file + +Adding more devices +------------------- + +Currently there are a bunch of different files to modify. Eventually the plan is to fit everything into boards/BOARDNAME.py and to auto-generate the rest of the config files. + +* Most build options handled in `Makefile` +* Extra libraries like USB/LCD/filesystem in `Makefile` +* Linker Scripts are in `linker/` +* `boards/*.py` files handle loading the list of available pins so the relevant headers + docs can be created +* Processor-specific code in `targets/stm32`, `targets/linux`, etc. +* Processor-specific libs in `targetlibs/foo` +* `src/jshardware.h` is effectively a simple abstraction layer for SPI/I2C/etc +* `targets/stm32/jshardware.c` also has flash-size-specific defines +* `libs/fat_sd` and `libs/lcd` still have some device-specific defines in too + +Adding libraries +------------------- + +* Create `jswrap_mylib.c/h` in `libs/` +* Create library functions (see examples in other jswrap files, also the comments in `scripts/common.py`) + + +Arduino Compile (beta) +---------------------- +* Ensure that `targets/arduino/utility` is symlinked to `src` +* Symlink `...arduino_workspace/libraries/Espruino` to `targets/arduino` + +Cross Compile for Raspberry Pi +------------------------------ +``` +cd targetlibs +mkdir raspberrypi +cd raspberrypi +git clone git://github.com/raspberrypi/tools.git +sudo apt-get install ia32-libs +``` + +Cross Compile for Carambola (OpenWRT) +------------------------------------- +* Follow instructions at to set toolchain up in ```~/workspace/carambola``` +* Run ```CARAMBOLA=1 make``` diff --git a/components/external/espruino/README_cn.md b/components/external/espruino/README_cn.md new file mode 100644 index 0000000000..77f78ce82c --- /dev/null +++ b/components/external/espruino/README_cn.md @@ -0,0 +1,2 @@ +ÕâÊÇ´ÓEspruinoÒÆÖ²¹ýÀ´µÄjavascript½âÊÍÆ÷¡£ +Õâ¸ö×é¼þÒÀÀµnewlib¡£ÐèÒªÔÚrtconfig.hÖпªÆôRT_USING_JSºêÀ´¿ªÆô´Ë×é¼þ¡£ \ No newline at end of file diff --git a/components/external/espruino/SConscript b/components/external/espruino/SConscript index 3d5c775064..ca4f32b403 100644 --- a/components/external/espruino/SConscript +++ b/components/external/espruino/SConscript @@ -1,19 +1,58 @@ +import rtconfig +Import('RTT_ROOT') from building import * -import os -cwd = GetCurrentDir() -# source files -src = Split(''' -''') +path = [RTT_ROOT + r'/components/external/Espruino'] +path = path + [RTT_ROOT + r'/components/external/Espruino/src/'] +path = path + [RTT_ROOT + r'/components/external/Espruino/gen/'] +path = path + [RTT_ROOT + r'/components/external/Espruino/libs/'] +path = path + [RTT_ROOT + r'/components/external/Espruino/targets/rtthread/'] -ESPRUINO_SRC_PATH = cwd + '/src' -if GetDepend('RT_USING_JS') and not os.path.exists(ESPRUINO_SRC_PATH): - print '================ERROR============================' - print 'Please get espruino source files and put them under espruino folder' - print '=================================================' - exit(0) +src = Split(""" +src/jsdevices.c +src/jslex.c +src/jswrap_array.c +src/jswrap_json.c +src/jswrap_process.c +src/jsutils.c +src/jswrap_interactive.c +src/jswrap_onewire.c +src/jswrap_string.c +src/jsparse.c +src/jswrap_arraybuffer.c +src/jswrap_modules.c +src/jswrap_serial.c +src/jsinteractive.c +src/jsvar.c +src/jswrap_io.c +src/jswrap_pin.c +src/jspin.c +src/jswrap_functions.c +src/jswrap_object.c +src/jswrap_spi_i2c.c +""" +) -CPPPATH = [cwd + '/src', cwd + '/gen', cwd + '/libs', cwd + '/targets/rtthread'] -group = DefineGroup('Espruino', src, depend = ['RT_USING_JS'], CPPPATH = CPPPATH) +gen = Split(""" +gen/jspininfo.c +gen/jswrapper.c +""" +) + +target = Split(""" +targets/rtthread/espruino.c +targets/rtthread/jshardware.c +""" +) + +libs = Split( +""" +libs/jswrap_math.c +""" +) + +src += gen + target + libs + +group = DefineGroup('Espruino', src, depend = ['RT_USING_JS', 'RT_USING_NEWLIB'], CPPPATH = path) Return('group') diff --git a/components/external/espruino/dist_licences.txt b/components/external/espruino/dist_licences.txt new file mode 100644 index 0000000000..3a51e14a6f --- /dev/null +++ b/components/external/espruino/dist_licences.txt @@ -0,0 +1,109 @@ +Espruino uses a few libraries of code that have been generously given away for +free. Their licences are included below. + +------------------------------------------------------------------------- + FATFS +------------------------------------------------------------------------- + +/*---------------------------------------------------------------------------/ +/ FatFs - FAT file system module include file R0.07c (C)ChaN, 2009 +/----------------------------------------------------------------------------/ +/ FatFs module is an open source software to implement FAT file system to +/ small embedded systems. This is a free software and is opened for education, +/ research and commercial developments under license policy of following terms. +/ +/ Copyright (C) 2009, ChaN, all right reserved. +/ +/ * The FatFs module is a free software and there is NO WARRANTY. +/ * No restriction on use. You can use, modify and redistribute it for +/ personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY. +/ * Redistributions of source code must retain the above copyright notice.*/ + + +------------------------------------------------------------------------- + FATFS to SPI bridge +------------------------------------------------------------------------- + +/* Copyright (c) 2009, Martin Thomas, ChaN + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. */ + +------------------------------------------------------------------------- + FATFS to SDIO bridge +------------------------------------------------------------------------- + +/* author: ickle */ - No details given with source code. If you have +anything you'd like to include, pleas e-mail us and let us know. + +------------------------------------------------------------------------- + 8x8 LCD Font +------------------------------------------------------------------------- + +/* +http://forum.osdev.org/viewtopic.php?f=2&t=22033 + +Created Sunday, May 23, 2010 by Quinn Evans +Renamed and updated Monday 24, 2010 + +This font (Vincent) is released by me into the public domain. I claim no +copyright, and hereby make this software available to the public for any use, +at any time, free of restrictions, legal or otherwise. +*/ + +------------------------------------------------------------------------- + CC3000 Host Driver Implementation. +------------------------------------------------------------------------- + + Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. + + Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/components/external/espruino/dist_readme.txt b/components/external/espruino/dist_readme.txt new file mode 100644 index 0000000000..0c1092a165 --- /dev/null +++ b/components/external/espruino/dist_readme.txt @@ -0,0 +1,57 @@ + _____ _ +| __|___ ___ ___ _ _|_|___ ___ +| __|_ -| . | _| | | | | . | +|_____|___| _|_| |___|_|_|_|___| + |_| + Copyright 2013 Gordon Williams + +http://www.espruino.com + +-------------------------------------------------------------- + +There are a few different binaries in this ZIP file, for different +types of Microcontroller: + +espruino_#v##_hystm32_24_ve.bin + - 'HY'STM32F103VET6 ARM with 2.4" LCD display + This is available from eBay + +espruino_#v##_hystm32_28_rb.bin + - 'HY'STM32F103RBT6 ARM with 2.8" LCD display + This is available from eBay + +espruino_#v##_hystm32_32_vc.bin + - 'HY'STM32F103VCT6 ARM with 3.2" LCD display + This is available from eBay + +espruino_#v##_olimexino_stm32.bin + - You will need to overwrite the Maple bootloader to install this. + Espruino is now too large to fit in flash alongside it. + - Olimexino-STM32 Arduino form factor board + - Leaf Labs Maple Arduino form factor board + +espruino_#v##_stm32vldiscovery.bin + - STM32VLDISCOVERY board + +espruino_#v##_stm32f3discovery.bin + - STM32F3DISCOVERY board + +espruino_#v##_stm32f4discovery.bin + - STM32F4DISCOVERY board + +espruino_#v##_raspberrypi + - Raspberry Pi executable (just copy it to the device and run it) + NOTE: There is GPIO support (which requires you to run Espruino as root) + however there is no Serial, SPI, OneWire or I2C support at the moment so + you're pretty limited! + +For information on devices, and on how to flash these binary files on to +each device, please see our website, http://www.espruino.com + +NOTES: + +* On the STM32F4DISCOVERY the default USART is USART2 (because +USART1 shares some pins with USB). This means you must connect +serial connections to PA2/PA3 NOT PA9/PA10 as you would for +the STM32VLDISCOVERY. + diff --git a/components/external/espruino/gen/README b/components/external/espruino/gen/README new file mode 100644 index 0000000000..f6654dec69 --- /dev/null +++ b/components/external/espruino/gen/README @@ -0,0 +1 @@ +This directory contains auto-generated files diff --git a/components/external/espruino/gen/jspininfo.c b/components/external/espruino/gen/jspininfo.c new file mode 100644 index 0000000000..5a39372dac --- /dev/null +++ b/components/external/espruino/gen/jspininfo.c @@ -0,0 +1,7 @@ +// auto-generated pin info file +// for board LINUX +#include "jspininfo.h" + +const JshPinInfo pinInfo[JSH_PIN_COUNT] = { +}; + diff --git a/components/external/espruino/gen/jspininfo.h b/components/external/espruino/gen/jspininfo.h new file mode 100644 index 0000000000..f98abd8883 --- /dev/null +++ b/components/external/espruino/gen/jspininfo.h @@ -0,0 +1,39 @@ +// auto-generated pin info file +// for board LINUX +#ifndef __JSPININFO_H_ +#define __JSPININFO_H_ + +#include "jspin.h" + +#define JSH_PIN_COUNT 0 + +#define JSH_PORTA_COUNT 0 +#define JSH_PORTB_COUNT 0 +#define JSH_PORTC_COUNT 0 +#define JSH_PORTD_COUNT 0 +#define JSH_PORTE_COUNT 0 +#define JSH_PORTF_COUNT 0 +#define JSH_PORTG_COUNT 0 +#define JSH_PORTH_COUNT 0 +#define JSH_PORTA_OFFSET -1 +#define JSH_PORTB_OFFSET -1 +#define JSH_PORTC_OFFSET -1 +#define JSH_PORTD_OFFSET -1 +#define JSH_PORTE_OFFSET -1 +#define JSH_PORTF_OFFSET -1 +#define JSH_PORTG_OFFSET -1 +#define JSH_PORTH_OFFSET -1 + +#define JSH_PININFO_FUNCTIONS 0 + +typedef struct JshPinInfo { + JsvPinInfoPort port; + JsvPinInfoPin pin; + JsvPinInfoAnalog analog; // TODO: maybe we don't need to store analogs separately + JshPinFunction functions[JSH_PININFO_FUNCTIONS]; +} PACKED_FLAGS JshPinInfo; + +extern const JshPinInfo pinInfo[JSH_PIN_COUNT]; + +#endif + diff --git a/components/external/espruino/gen/jswrapper.c b/components/external/espruino/gen/jswrapper.c new file mode 100644 index 0000000000..8693e7e985 --- /dev/null +++ b/components/external/espruino/gen/jswrapper.c @@ -0,0 +1,1203 @@ +// Automatically generated wrapper file +// Generated by scripts/build_jsfunctions.py + +#include "jswrapper.h" +#include "src/jswrap_pin.h" +#include "src/jswrap_functions.h" +#include "src/jswrap_modules.h" +#include "src/jswrap_process.h" +#include "src/jswrap_interactive.h" +#include "src/jswrap_json.h" +#include "src/jswrap_object.h" +#include "src/jswrap_string.h" +#include "src/jswrap_array.h" +#include "src/jswrap_arraybuffer.h" +#include "src/jswrap_serial.h" +#include "src/jswrap_spi_i2c.h" +#include "src/jswrap_onewire.h" +#include "src/jswrap_io.h" +#include "libs/jswrap_math.h" + +#if( 'q\0\0\0' & 'q' ) + #error( "architecture is big-endian. need to test and make sure this still works" ) +#endif +// beware big endian! +#define CH2(a,b) ( ((b)<<8) | (a) ) +#define CH4(a,b,c,d) ( ((d)<<24) | ((c)<<16) | ((b)<<8) | (a) ) +#define CMP2(var, a,b) ((*(unsigned short*)&var)==CH2(a,b)) +#define CMP3(var, a,b,c) (((*(unsigned int*)&var)&0x00FFFFFF)==CH4(a,b,c,0)) +#define CMP4(var, a,b,c,d) ((*(unsigned int*)&var)==CH4(a,b,c,d)) + +JsVar *jswHandleFunctionCall(JsVar *parent, JsVar *parentName, const char *name) { + if (parent) { + // ------------------------------------------ METHODS ON OBJECT + if (CMP4(name[0],'c','l','o','n') && CMP2(name[4],'e','\0')) { + // Object.clone (src/jswrap_object.c) + jspParseEmptyFunction(); + JsVar *_r = jswrap_object_clone(parent); + return _r; + } else if (CMP4(name[0],'e','m','i','t') && name[4]=='\0') { + // Object.emit (src/jswrap_object.c) + JsVar *event, *v1, *v2; + jspParseFunction(0, &event, &v1, &v2, 0); + jswrap_object_emit(parent, event, v1, v2); + jsvUnLock(event); + jsvUnLock(v1); + jsvUnLock(v2); + return 0; + } else if (CMP4(name[0],'l','e','n','g') && CMP3(name[4],'t','h','\0')) { + // Object.length (src/jswrap_object.c) + jspParseVariableName(); + JsVar *_r = jswrap_object_length(parent); + return _r; + } else if (CMP3(name[0],'o','n','\0')) { + // Object.on (src/jswrap_object.c) + JsVar *event, *listener; + jspParseFunction(0, &event, &listener, 0, 0); + jswrap_object_on(parent, event, listener); + jsvUnLock(event); + jsvUnLock(listener); + return 0; + } else if (CMP4(name[0],'r','e','m','o') && CMP4(name[4],'v','e','A','l') && CMP4(name[8],'l','L','i','s') && CMP4(name[12],'t','e','n','e') && CMP3(name[16],'r','s','\0')) { + // Object.removeAllListeners (src/jswrap_object.c) + JsVar *event = jspParseSingleFunction(); + jswrap_object_removeAllListeners(parent, event); + jsvUnLock(event); + return 0; + } else if (CMP4(name[0],'t','o','S','t') && CMP4(name[4],'r','i','n','g') && name[8]=='\0') { + // Object.toString (src/jswrap_object.c) + JsVar *radix = jspParseSingleFunction(); + JsVar *_r = jswrap_object_toString(parent, radix); + jsvUnLock(radix); + return _r; + } + // ------------------------------------------ INSTANCE + STATIC METHODS + if (CMP4(parent->varData.str[0],'p','r','o','c') && CMP4(parent->varData.str[4],'e','s','s','\0')) { + if (CMP4(name[0],'m','e','m','o') && CMP3(name[4],'r','y','\0')) { + // process.memory (src/jswrap_process.c) + jspParseEmptyFunction(); + JsVar *_r = jswrap_process_memory(); + return _r; + } else if (CMP4(name[0],'e','n','v','\0')) { + // process.env (src/jswrap_process.c) + jspParseVariableName(); + JsVar *_r = jswrap_process_env(); + return _r; + } else if (CMP4(name[0],'v','e','r','s') && CMP4(name[4],'i','o','n','\0')) { + // process.version (src/jswrap_process.c) + jspParseVariableName(); + JsVar *_r = jsvNewFromString(JS_VERSION); + return _r; + } + } + if (CMP4(parent->varData.str[0],'O','b','j','e') && CMP3(parent->varData.str[4],'c','t','\0')) { + if (CMP4(name[0],'k','e','y','s') && name[4]=='\0') { + // Object.keys (src/jswrap_object.c) + JsVar *object = jspParseSingleFunction(); + JsVar *_r = jswrap_object_keys(object); + jsvUnLock(object); + return _r; + } + } + if (jsvIsFunction(parent)) { + if (CMP4(name[0],'a','p','p','l') && CMP2(name[4],'y','\0')) { + // Function.apply (src/jswrap_object.c) + JsVar *this, *args; + jspParseFunction(0, &this, &args, 0, 0); + JsVar *_r = jswrap_function_apply(parent, this, args); + jsvUnLock(this); + jsvUnLock(args); + return _r; + } else if (CMP4(name[0],'c','a','l','l') && name[4]=='\0') { + // Function.call (src/jswrap_object.c) + JsVar *this, *a, *b, *c, *d; + jspParseFunction8(0, &this, &a, &b, &c, &d, 0, 0, 0); + JsVar *_r = jswrap_function_call(parent, this, a, b, c, d); + jsvUnLock(this); + jsvUnLock(a); + jsvUnLock(b); + jsvUnLock(c); + jsvUnLock(d); + return _r; + } else if (CMP4(name[0],'r','e','p','l') && CMP4(name[4],'a','c','e','W') && CMP4(name[8],'i','t','h','\0')) { + // Function.replaceWith (src/jswrap_object.c) + JsVar *newFunc = jspParseSingleFunction(); + jswrap_function_replaceWith(parent, newFunc); + jsvUnLock(newFunc); + return 0; + } + } + if (CMP4(parent->varData.str[0],'M','o','d','u') && CMP4(parent->varData.str[4],'l','e','s','\0')) { + if (CMP4(name[0],'a','d','d','C') && CMP4(name[4],'a','c','h','e') && CMP2(name[8],'d','\0')) { + // Modules.addCached (src/jswrap_modules.c) + JsVar *id, *sourcecode; + jspParseFunction(0, &id, &sourcecode, 0, 0); + jswrap_modules_addCached(id, sourcecode); + jsvUnLock(id); + jsvUnLock(sourcecode); + return 0; + } else if (CMP4(name[0],'r','e','m','o') && CMP2(name[4],'v','e')) { + if (CMP4(name[6],'A','l','l','C') && CMP4(name[10],'a','c','h','e') && CMP2(name[14],'d','\0')) { + // Modules.removeAllCached (src/jswrap_modules.c) + jspParseEmptyFunction(); + jswrap_modules_removeAllCached(); + return 0; + } else if (CMP4(name[6],'C','a','c','h') && CMP3(name[10],'e','d','\0')) { + // Modules.removeCached (src/jswrap_modules.c) + JsVar *id = jspParseSingleFunction(); + jswrap_modules_removeCached(id); + jsvUnLock(id); + return 0; + } + } else if (CMP4(name[0],'g','e','t','C') && CMP4(name[4],'a','c','h','e') && CMP2(name[8],'d','\0')) { + // Modules.getCached (src/jswrap_modules.c) + jspParseEmptyFunction(); + JsVar *_r = jswrap_modules_getCached(); + return _r; + } + } + if (jsvIsArrayBuffer(parent) && parent->varData.arraybuffer.type!=ARRAYBUFFERVIEW_ARRAYBUFFER) { + if (CMP4(name[0],'i','n','t','e') && CMP4(name[4],'r','p','o','l') && CMP3(name[8],'a','t','e')) { + if (CMP3(name[11],'2','d','\0')) { + // ArrayBufferView.interpolate2d (src/jswrap_arraybuffer.c) + JsVar *width, *x, *y; + jspParseFunction(0, &width, &x, &y, 0); + JsVar *_r = jsvNewFromFloat(jswrap_arraybufferview_interpolate2d(parent, jsvGetIntegerAndUnLock(width), jsvGetFloatAndUnLock(x), jsvGetFloatAndUnLock(y))); + return _r; + } else if (name[11]==0) { + // ArrayBufferView.interpolate (src/jswrap_arraybuffer.c) + JsVar *index = jspParseSingleFunction(); + JsVar *_r = jsvNewFromFloat(jswrap_arraybufferview_interpolate(parent, jsvGetFloatAndUnLock(index))); + return _r; + } + } else if (name[0]=='b') { + if (CMP3(name[1],'y','t','e')) { + if (CMP4(name[4],'L','e','n','g') && CMP3(name[8],'t','h','\0')) { + // ArrayBufferView.byteLength (src/jswrap_arraybuffer.c) + jspParseVariableName(); + JsVar *_r = jsvNewFromInteger(parent->varData.arraybuffer.length * JSV_ARRAYBUFFER_GET_SIZE(parent->varData.arraybuffer.type)); + return _r; + } else if (CMP4(name[4],'O','f','f','s') && CMP3(name[8],'e','t','\0')) { + // ArrayBufferView.byteOffset (src/jswrap_arraybuffer.c) + jspParseVariableName(); + JsVar *_r = jsvNewFromInteger(parent->varData.arraybuffer.byteOffset); + return _r; + } + } else if (CMP4(name[1],'u','f','f','e') && CMP2(name[5],'r','\0')) { + // ArrayBufferView.buffer (src/jswrap_arraybuffer.c) + jspParseVariableName(); + JsVar *_r = jsvLock(parent->firstChild); + return _r; + } + } + } + if (jsvIsPin(parent)) { + if (CMP4(name[0],'s','e','t','\0')) { + // Pin.set (src/jswrap_pin.c) + jspParseEmptyFunction(); + jswrap_pin_set(parent); + return 0; + } else if (CMP2(name[0],'r','e')) { + if (CMP3(name[2],'a','d','\0')) { + // Pin.read (src/jswrap_pin.c) + jspParseEmptyFunction(); + JsVar *_r = jsvNewFromBool(jswrap_pin_read(parent)); + return _r; + } else if (CMP4(name[2],'s','e','t','\0')) { + // Pin.reset (src/jswrap_pin.c) + jspParseEmptyFunction(); + jswrap_pin_reset(parent); + return 0; + } + } else if (CMP4(name[0],'w','r','i','t') && name[4]=='e') { + if (CMP4(name[5],'A','t','T','i') && CMP3(name[9],'m','e','\0')) { + // Pin.writeAtTime (src/jswrap_pin.c) + JsVar *value, *time; + jspParseFunction(0, &value, &time, 0, 0); + jswrap_pin_writeAtTime(parent, jsvGetBoolAndUnLock(value), jsvGetFloatAndUnLock(time)); + return 0; + } else if (name[5]==0) { + // Pin.write (src/jswrap_pin.c) + JsVar *value = jspParseSingleFunction(); + jswrap_pin_write(parent, jsvGetBoolAndUnLock(value)); + return 0; + } + } + } + if (jsvIsString(parent)) { + if (CMP4(name[0],'i','n','d','e') && CMP4(name[4],'x','O','f','\0')) { + // String.indexOf (src/jswrap_string.c) + JsVar *substring = jspParseSingleFunction(); + JsVar *_r = jsvNewFromInteger(jswrap_string_indexOf(parent, substring)); + jsvUnLock(substring); + return _r; + } else if (CMP4(name[0],'c','h','a','r')) { + if (CMP3(name[4],'A','t','\0')) { + // String.charAt (src/jswrap_string.c) + JsVar *pos = jspParseSingleFunction(); + JsVar *_r = jswrap_string_charAt(parent, jsvGetIntegerAndUnLock(pos)); + return _r; + } else if (CMP4(name[4],'C','o','d','e') && CMP3(name[8],'A','t','\0')) { + // String.charCodeAt (src/jswrap_string.c) + JsVar *pos = jspParseSingleFunction(); + JsVar *_r = jsvNewFromInteger(jswrap_string_charCodeAt(parent, jsvGetIntegerAndUnLock(pos))); + return _r; + } + } else if (name[0]=='s') { + if (CMP4(name[1],'p','l','i','t') && name[5]=='\0') { + // String.split (src/jswrap_string.c) + JsVar *separator = jspParseSingleFunction(); + JsVar *_r = jswrap_string_split(parent, separator); + jsvUnLock(separator); + return _r; + } else if (CMP4(name[1],'u','b','s','t') && name[5]=='r') { + if (CMP4(name[6],'i','n','g','\0')) { + // String.substring (src/jswrap_string.c) + JsVar *start, *end; + jspParseFunction(0, &start, &end, 0, 0); + JsVar *_r = jswrap_string_substring(parent, jsvGetIntegerAndUnLock(start), end); + jsvUnLock(end); + return _r; + } else if (name[6]==0) { + // String.substr (src/jswrap_string.c) + JsVar *start, *len; + jspParseFunction(0, &start, &len, 0, 0); + JsVar *_r = jswrap_string_substr(parent, jsvGetIntegerAndUnLock(start), len); + jsvUnLock(len); + return _r; + } + } + } + } + if (CMP4(parent->varData.str[0],'M','a','t','h') && parent->varData.str[4]=='\0') { + if (name[0]=='a') { + if (CMP4(name[1],'c','o','s','\0')) { + // Math.acos (libs/jswrap_math.c) + JsVar *x = jspParseSingleFunction(); + JsVar *_r = jsvNewFromFloat(acos(jsvGetFloatAndUnLock(x))); + return _r; + } else if (CMP3(name[1],'b','s','\0')) { + // Math.abs (libs/jswrap_math.c) + JsVar *x = jspParseSingleFunction(); + JsVar *_r = jsvNewFromFloat(jswrap_math_abs(jsvGetFloatAndUnLock(x))); + return _r; + } else if (CMP4(name[1],'s','i','n','\0')) { + // Math.asin (libs/jswrap_math.c) + JsVar *x = jspParseSingleFunction(); + JsVar *_r = jsvNewFromFloat(asin(jsvGetFloatAndUnLock(x))); + return _r; + } else if (CMP3(name[1],'t','a','n')) { + if (CMP2(name[4],'2','\0')) { + // Math.atan2 (libs/jswrap_math.c) + JsVar *y, *x; + jspParseFunction(0, &y, &x, 0, 0); + JsVar *_r = jsvNewFromFloat(atan2(jsvGetFloatAndUnLock(y), jsvGetFloatAndUnLock(x))); + return _r; + } else if (name[4]==0) { + // Math.atan (libs/jswrap_math.c) + JsVar *x = jspParseSingleFunction(); + JsVar *_r = jsvNewFromFloat(atan(jsvGetFloatAndUnLock(x))); + return _r; + } + } + } else if (name[0]=='c') { + if (CMP4(name[1],'e','i','l','\0')) { + // Math.ceil (libs/jswrap_math.c) + JsVar *x = jspParseSingleFunction(); + JsVar *_r = jsvNewFromFloat(ceil(jsvGetFloatAndUnLock(x))); + return _r; + } else if (CMP4(name[1],'l','i','p','\0')) { + // Math.clip (libs/jswrap_math.c) + JsVar *x, *min, *max; + jspParseFunction(0, &x, &min, &max, 0); + JsVar *_r = jsvNewFromFloat(jswrap_math_clip(jsvGetFloatAndUnLock(x), jsvGetFloatAndUnLock(min), jsvGetFloatAndUnLock(max))); + return _r; + } else if (CMP3(name[1],'o','s','\0')) { + // Math.cos (libs/jswrap_math.c) + JsVar *theta = jspParseSingleFunction(); + JsVar *_r = jsvNewFromFloat(sin(jsvGetFloat(theta) + (3.14159265359/2.0))); + jsvUnLock(theta); + return _r; + } + } else if (CMP2(name[0],'E','\0')) { + // Math.E (libs/jswrap_math.c) + jspParseVariableName(); + JsVar *_r = jsvNewFromFloat(2.71828182846); + return _r; + } else if (CMP4(name[0],'p','o','w','\0')) { + // Math.pow (libs/jswrap_math.c) + JsVar *x, *y; + jspParseFunction(0, &x, &y, 0, 0); + JsVar *_r = jsvNewFromFloat(jswrap_math_pow(jsvGetFloatAndUnLock(x), jsvGetFloatAndUnLock(y))); + return _r; + } else if (CMP4(name[0],'f','l','o','o') && CMP2(name[4],'r','\0')) { + // Math.floor (libs/jswrap_math.c) + JsVar *x = jspParseSingleFunction(); + JsVar *_r = jsvNewFromFloat(floor(jsvGetFloatAndUnLock(x))); + return _r; + } else if (CMP4(name[0],'l','o','g','\0')) { + // Math.log (libs/jswrap_math.c) + JsVar *x = jspParseSingleFunction(); + JsVar *_r = jsvNewFromFloat(log(jsvGetFloatAndUnLock(x))); + return _r; + } else if (CMP3(name[0],'P','I','\0')) { + // Math.PI (libs/jswrap_math.c) + jspParseVariableName(); + JsVar *_r = jsvNewFromFloat(3.14159265359); + return _r; + } else if (name[0]=='s') { + if (CMP3(name[1],'i','n','\0')) { + // Math.sin (libs/jswrap_math.c) + JsVar *theta = jspParseSingleFunction(); + JsVar *_r = jsvNewFromFloat(sin(jsvGetFloatAndUnLock(theta))); + return _r; + } else if (CMP4(name[1],'q','r','t','\0')) { + // Math.sqrt (libs/jswrap_math.c) + JsVar *x = jspParseSingleFunction(); + JsVar *_r = jsvNewFromFloat(jswrap_math_pow(jsvGetFloat(x),0.5)); + jsvUnLock(x); + return _r; + } + } else if (name[0]=='r') { + if (CMP4(name[1],'a','n','d','o') && CMP2(name[5],'m','\0')) { + // Math.random (libs/jswrap_math.c) + jspParseEmptyFunction(); + JsVar *_r = jsvNewFromFloat((JsVarFloat)rand() / (JsVarFloat)RAND_MAX); + return _r; + } else if (CMP4(name[1],'o','u','n','d') && name[5]=='\0') { + // Math.round (libs/jswrap_math.c) + JsVar *x = jspParseSingleFunction(); + JsVar *_r = jsvNewFromInteger((JsVarInt)round(jsvGetFloatAndUnLock(x))); + return _r; + } + } else if (CMP4(name[0],'w','r','a','p') && name[4]=='\0') { + // Math.wrap (libs/jswrap_math.c) + JsVar *x, *max; + jspParseFunction(0, &x, &max, 0, 0); + JsVar *_r = jsvNewFromFloat(wrapAround(jsvGetFloatAndUnLock(x), jsvGetFloatAndUnLock(max))); + return _r; + } else if (CMP4(name[0],'e','x','p','\0')) { + // Math.exp (libs/jswrap_math.c) + JsVar *x = jspParseSingleFunction(); + JsVar *_r = jsvNewFromFloat(exp(jsvGetFloatAndUnLock(x))); + return _r; + } + } + if (CMP4(parent->varData.str[0],'D','o','u','b') && CMP3(parent->varData.str[4],'l','e','\0')) { + if (CMP4(name[0],'d','o','u','b') && CMP4(name[4],'l','e','T','o') && CMP4(name[8],'I','n','t','B') && CMP4(name[12],'i','t','s','\0')) { + // Double.doubleToIntBits (libs/jswrap_math.c) + JsVar *x = jspParseSingleFunction(); + JsVar *_r = jsvNewFromInteger(*(JsVarInt*)&x); + jsvUnLock(x); + return _r; + } + } + if (jsvIsArray(parent)) { + if (CMP4(name[0],'c','o','n','t') && CMP4(name[4],'a','i','n','s') && name[8]=='\0') { + // Array.contains (src/jswrap_array.c) + JsVar *value = jspParseSingleFunction(); + JsVar *_r = jsvNewFromBool(jswrap_array_contains(parent, value)); + jsvUnLock(value); + return _r; + } else if (CMP4(name[0],'f','o','r','E') && CMP4(name[4],'a','c','h','\0')) { + // Array.forEach (src/jswrap_array.c) + JsVar *function, *thisArg; + jspParseFunction(0, &function, &thisArg, 0, 0); + jswrap_array_forEach(parent, function, thisArg); + jsvUnLock(function); + jsvUnLock(thisArg); + return 0; + } else if (CMP4(name[0],'i','n','d','e') && CMP4(name[4],'x','O','f','\0')) { + // Array.indexOf (src/jswrap_array.c) + JsVar *value = jspParseSingleFunction(); + JsVar *_r = jswrap_array_indexOf(parent, value); + jsvUnLock(value); + return _r; + } else if (CMP4(name[0],'j','o','i','n') && name[4]=='\0') { + // Array.join (src/jswrap_array.c) + JsVar *separator = jspParseSingleFunction(); + JsVar *_r = jswrap_array_join(parent, separator); + jsvUnLock(separator); + return _r; + } else if (CMP4(name[0],'m','a','p','\0')) { + // Array.map (src/jswrap_array.c) + JsVar *function, *thisArg; + jspParseFunction(0, &function, &thisArg, 0, 0); + JsVar *_r = jswrap_array_map(parent, function, thisArg); + jsvUnLock(function); + jsvUnLock(thisArg); + return _r; + } else if (name[0]=='p') { + if (CMP4(name[1],'u','s','h','\0')) { + // Array.push (src/jswrap_array.c) + JsVar *value = jspParseSingleFunction(); + JsVar *_r = jsvNewFromInteger(jsvArrayPush(parent, value)); + jsvUnLock(value); + return _r; + } else if (CMP3(name[1],'o','p','\0')) { + // Array.pop (src/jswrap_array.c) + jspParseEmptyFunction(); + JsVar *_r = jsvArrayPop(parent); + return _r; + } + } else if (name[0]=='s') { + if (CMP4(name[1],'p','l','i','c') && CMP2(name[5],'e','\0')) { + // Array.splice (src/jswrap_array.c) + JsVar *index, *howMany, *element1, *element2, *element3, *element4, *element5, *element6; + jspParseFunction8(0, &index, &howMany, &element1, &element2, &element3, &element4, &element5, &element6); + JsVar *_r = jswrap_array_splice(parent, jsvGetIntegerAndUnLock(index), howMany, element1, element2, element3, element4, element5, element6); + jsvUnLock(howMany); + jsvUnLock(element1); + jsvUnLock(element2); + jsvUnLock(element3); + jsvUnLock(element4); + jsvUnLock(element5); + jsvUnLock(element6); + return _r; + } else if (CMP4(name[1],'l','i','c','e') && name[5]=='\0') { + // Array.slice (src/jswrap_array.c) + JsVar *start, *end; + jspParseFunction(0, &start, &end, 0, 0); + JsVar *_r = jswrap_array_slice(parent, start, end); + jsvUnLock(start); + jsvUnLock(end); + return _r; + } + } + } + if (CMP4(parent->varData.str[0],'c','o','n','s') && CMP4(parent->varData.str[4],'o','l','e','\0')) { + if (CMP4(name[0],'l','o','g','\0')) { + // console.log (src/jswrap_interactive.c) + JsVar *text = jspParseFunctionAsArray(); + if (!text) return 0; // if parse error + jswrap_interface_print(text); + jsvUnLock(text); + return 0; + } + } + if (CMP4(parent->varData.str[0],'J','S','O','N') && parent->varData.str[4]=='\0') { + if (CMP4(name[0],'p','a','r','s') && CMP2(name[4],'e','\0')) { + // JSON.parse (src/jswrap_json.c) + JsVar *string = jspParseSingleFunction(); + JsVar *_r = jswrap_json_parse(string); + jsvUnLock(string); + return _r; + } else if (CMP4(name[0],'s','t','r','i') && CMP4(name[4],'n','g','i','f') && CMP2(name[8],'y','\0')) { + // JSON.stringify (src/jswrap_json.c) + JsVar *data = jspParseSingleFunction(); + JsVar *_r = jswrap_json_stringify(data); + jsvUnLock(data); + return _r; + } + } + if (CMP4(parent->varData.str[0],'S','t','r','i') && CMP3(parent->varData.str[4],'n','g','\0')) { + if (CMP4(name[0],'f','r','o','m') && CMP4(name[4],'C','h','a','r') && CMP4(name[8],'C','o','d','e') && name[12]=='\0') { + // String.fromCharCode (src/jswrap_string.c) + JsVar *code = jspParseSingleFunction(); + JsVar *_r = jswrap_string_fromCharCode(jsvGetIntegerAndUnLock(code)); + return _r; + } + } + if (CMP4(parent->varData.str[0],'I','n','t','e') && CMP4(parent->varData.str[4],'g','e','r','\0')) { + if (CMP4(name[0],'v','a','l','u') && CMP4(name[4],'e','O','f','\0')) { + // Integer.valueOf (libs/jswrap_math.c) + JsVar *character = jspParseSingleFunction(); + JsVar *_r = jsvNewFromInteger(jswrap_integer_valueOf(character)); + jsvUnLock(character); + return _r; + } + } + // ------------------------------------------ INSTANCE METHODS WE MUST CHECK CONSTRUCTOR FOR + JsVar *constructorName = jsvIsObject(parent)?jsvSkipOneNameAndUnLock(jsvFindChildFromString(parent, JSPARSE_CONSTRUCTOR_VAR, false)):0; + if (constructorName && jsvIsName(constructorName)) { + if (CMP4(constructorName->varData.str[0],'S','e','r','i') && CMP3(constructorName->varData.str[4],'a','l','\0')) { + jsvUnLock(constructorName);constructorName=0; + if (CMP4(name[0],'p','r','i','n') && name[4]=='t') { + if (CMP3(name[5],'l','n','\0')) { + // Serial.println (src/jswrap_serial.c) + JsVar *string = jspParseSingleFunction(); + jswrap_serial_println(parent, string); + jsvUnLock(string); + return 0; + } else if (name[5]==0) { + // Serial.print (src/jswrap_serial.c) + JsVar *string = jspParseSingleFunction(); + jswrap_serial_print(parent, string); + jsvUnLock(string); + return 0; + } + } else if (CMP3(name[0],'s','e','t')) { + if (CMP4(name[3],'C','o','n','s') && CMP4(name[7],'o','l','e','\0')) { + // Serial.setConsole (src/jswrap_serial.c) + jspParseEmptyFunction(); + jsiSetConsoleDevice(jsiGetDeviceFromClass(parent)); + return 0; + } else if (CMP3(name[3],'u','p','\0')) { + // Serial.setup (src/jswrap_serial.c) + JsVar *baudrate, *options; + jspParseFunction(0, &baudrate, &options, 0, 0); + jswrap_serial_setup(parent, jsvGetIntegerAndUnLock(baudrate), options); + jsvUnLock(options); + return 0; + } + } else if (CMP4(name[0],'o','n','D','a') && CMP3(name[4],'t','a','\0')) { + // Serial.onData (src/jswrap_serial.c) + JsVar *function; + jspParseFunction(0|JSP_NOSKIP_A, &function, 0, 0, 0); + jswrap_serial_onData(parent, function); + jsvUnLock(function); + return 0; + } else if (CMP4(name[0],'w','r','i','t') && CMP2(name[4],'e','\0')) { + // Serial.write (src/jswrap_serial.c) + JsVar *data = jspParseSingleFunction(); + jswrap_serial_write(parent, data); + jsvUnLock(data); + return 0; + } + } else if (CMP4(constructorName->varData.str[0],'O','n','e','W') && CMP4(constructorName->varData.str[4],'i','r','e','\0')) { + jsvUnLock(constructorName);constructorName=0; + if (name[0]=='s') { + if (CMP4(name[1],'k','i','p','\0')) { + // OneWire.skip (src/jswrap_onewire.c) + jspParseEmptyFunction(); + jswrap_onewire_skip(parent); + return 0; + } else if (name[1]=='e') { + if (CMP4(name[2],'a','r','c','h') && name[6]=='\0') { + // OneWire.search (src/jswrap_onewire.c) + jspParseEmptyFunction(); + JsVar *_r = jswrap_onewire_search(parent); + return _r; + } else if (CMP4(name[2],'l','e','c','t') && name[6]=='\0') { + // OneWire.select (src/jswrap_onewire.c) + JsVar *rom = jspParseSingleFunction(); + jswrap_onewire_select(parent, jsvGetIntegerAndUnLock(rom)); + return 0; + } + } + } else if (CMP2(name[0],'r','e')) { + if (CMP3(name[2],'a','d','\0')) { + // OneWire.read (src/jswrap_onewire.c) + jspParseEmptyFunction(); + JsVar *_r = jsvNewFromInteger(jswrap_onewire_read(parent)); + return _r; + } else if (CMP4(name[2],'s','e','t','\0')) { + // OneWire.reset (src/jswrap_onewire.c) + jspParseEmptyFunction(); + JsVar *_r = jsvNewFromBool(jswrap_onewire_reset(parent)); + return _r; + } + } else if (CMP4(name[0],'w','r','i','t') && CMP2(name[4],'e','\0')) { + // OneWire.write (src/jswrap_onewire.c) + JsVar *data, *power; + jspParseFunction(0, &data, &power, 0, 0); + jswrap_onewire_write(parent, jsvGetIntegerAndUnLock(data), jsvGetBoolAndUnLock(power)); + return 0; + } + } else if (CMP4(constructorName->varData.str[0],'I','2','C','\0')) { + jsvUnLock(constructorName);constructorName=0; + if (CMP4(name[0],'s','e','t','u') && CMP2(name[4],'p','\0')) { + // I2C.setup (src/jswrap_spi_i2c.c) + JsVar *options = jspParseSingleFunction(); + jswrap_i2c_setup(parent, options); + jsvUnLock(options); + return 0; + } else if (CMP4(name[0],'r','e','a','d') && CMP4(name[4],'F','r','o','m') && name[8]=='\0') { + // I2C.readFrom (src/jswrap_spi_i2c.c) + JsVar *address, *quantity; + jspParseFunction(0, &address, &quantity, 0, 0); + JsVar *_r = jswrap_i2c_readFrom(parent, jsvGetIntegerAndUnLock(address), jsvGetIntegerAndUnLock(quantity)); + return _r; + } else if (CMP4(name[0],'w','r','i','t') && CMP4(name[4],'e','T','o','\0')) { + // I2C.writeTo (src/jswrap_spi_i2c.c) + JsVar *address, *data; + jspParseFunction(0, &address, &data, 0, 0); + jswrap_i2c_writeTo(parent, jsvGetIntegerAndUnLock(address), data); + jsvUnLock(data); + return 0; + } + } else if (CMP4(constructorName->varData.str[0],'S','P','I','\0')) { + jsvUnLock(constructorName);constructorName=0; + if (CMP2(name[0],'s','e')) { + if (CMP4(name[2],'t','u','p','\0')) { + // SPI.setup (src/jswrap_spi_i2c.c) + JsVar *options = jspParseSingleFunction(); + jswrap_spi_setup(parent, options); + jsvUnLock(options); + return 0; + } else if (CMP2(name[2],'n','d')) { + if (CMP4(name[4],'8','b','i','t') && name[8]=='\0') { + // SPI.send8bit (src/jswrap_spi_i2c.c) + JsVar *data, *bit0, *bit1, *nss_pin; + jspParseFunction(0, &data, &bit0, &bit1, &nss_pin); + jswrap_spi_send8bit(parent, data, jsvGetIntegerAndUnLock(bit0), jsvGetIntegerAndUnLock(bit1), jshGetPinFromVarAndUnLock(nss_pin)); + jsvUnLock(data); + return 0; + } else if (CMP4(name[4],'4','b','i','t') && name[8]=='\0') { + // SPI.send4bit (src/jswrap_spi_i2c.c) + JsVar *data, *bit0, *bit1, *nss_pin; + jspParseFunction(0, &data, &bit0, &bit1, &nss_pin); + jswrap_spi_send4bit(parent, data, jsvGetIntegerAndUnLock(bit0), jsvGetIntegerAndUnLock(bit1), jshGetPinFromVarAndUnLock(nss_pin)); + jsvUnLock(data); + return 0; + } else if (name[4]==0) { + // SPI.send (src/jswrap_spi_i2c.c) + JsVar *data, *nss_pin; + jspParseFunction(0, &data, &nss_pin, 0, 0); + JsVar *_r = jswrap_spi_send(parent, data, jshGetPinFromVarAndUnLock(nss_pin)); + jsvUnLock(data); + return _r; + } + } + } + } else + jsvUnLock(constructorName); + } + } else { /* if (!parent) */ + // ------------------------------------------ FUNCTIONS + // Handle pin names - eg LED1 or D5 (this is hardcoded in build_jsfunctions.py) + Pin pin = jshGetPinFromString(name); + if (pin != PIN_UNDEFINED) { + jspParseVariableName(); + return jsvNewFromPin(pin); + } + if (name[0]=='a') { + if (CMP4(name[1],'r','g','u','m') && CMP4(name[5],'e','n','t','s') && name[9]=='\0') { + // arguments (src/jswrap_functions.c) + jspParseVariableName(); + JsVar *_r = jswrap_arguments(); + return _r; + } else if (CMP4(name[1],'n','a','l','o') && name[5]=='g') { + if (CMP4(name[6],'R','e','a','d') && name[10]=='\0') { + // analogRead (src/jswrap_io.c) + JsVar *pin = jspParseSingleFunction(); + JsVar *_r = jsvNewFromFloat(jshPinAnalog(jshGetPinFromVarAndUnLock(pin))); + return _r; + } else if (CMP4(name[6],'W','r','i','t') && CMP2(name[10],'e','\0')) { + // analogWrite (src/jswrap_io.c) + JsVar *pin, *value, *options; + jspParseFunction(0, &pin, &value, &options, 0); + jswrap_io_analogWrite(jshGetPinFromVarAndUnLock(pin), jsvGetFloatAndUnLock(value), options); + jsvUnLock(options); + return 0; + } + } + } else if (CMP4(name[0],'A','r','r','a') && name[4]=='y') { + if (CMP4(name[5],'B','u','f','f') && CMP3(name[9],'e','r','\0')) { + // ArrayBuffer.ArrayBuffer (src/jswrap_arraybuffer.c) + JsVar *byteLength = jspParseSingleFunction(); + JsVar *_r = jswrap_arraybuffer_constructor(jsvGetIntegerAndUnLock(byteLength)); + return _r; + } else if (name[5]==0) { + // Array.Array (src/jswrap_array.c) + JsVar *args = jspParseFunctionAsArray(); + if (!args) return 0; // if parse error + JsVar *_r = jswrap_array_constructor(args); + jsvUnLock(args); + return _r; + } + } else if (name[0]=='c') { + if (CMP4(name[1],'h','a','n','g') && CMP4(name[5],'e','I','n','t') && CMP4(name[9],'e','r','v','a') && CMP2(name[13],'l','\0')) { + // changeInterval (src/jswrap_io.c) + JsVar *id, *time; + jspParseFunction(0, &id, &time, 0, 0); + jswrap_interface_changeInterval(id, jsvGetFloatAndUnLock(time)); + jsvUnLock(id); + return 0; + } else if (CMP4(name[1],'l','e','a','r')) { + if (CMP4(name[5],'I','n','t','e') && CMP4(name[9],'r','v','a','l') && name[13]=='\0') { + // clearInterval (src/jswrap_io.c) + JsVar *id = jspParseSingleFunction(); + jswrap_interface_clearInterval(id); + jsvUnLock(id); + return 0; + } else if (CMP4(name[5],'T','i','m','e') && CMP4(name[9],'o','u','t','\0')) { + // clearTimeout (src/jswrap_io.c) + JsVar *id = jspParseSingleFunction(); + jswrap_interface_clearTimeout(id); + jsvUnLock(id); + return 0; + } else if (CMP4(name[5],'W','a','t','c') && CMP2(name[9],'h','\0')) { + // clearWatch (src/jswrap_io.c) + JsVar *id = jspParseSingleFunction(); + jswrap_interface_clearWatch(id); + jsvUnLock(id); + return 0; + } + } + } else if (name[0]=='e') { + if (CMP4(name[1],'c','h','o','\0')) { + // echo (src/jswrap_interactive.c) + JsVar *echoOn = jspParseSingleFunction(); + jswrap_interface_echo(jsvGetBoolAndUnLock(echoOn)); + return 0; + } else if (CMP4(name[1],'d','i','t','\0')) { + // edit (src/jswrap_interactive.c) + JsVar *funcName; + jspParseFunction(0|JSP_NOSKIP_A, &funcName, 0, 0, 0); + jswrap_interface_edit(funcName); + jsvUnLock(funcName); + return 0; + } else if (CMP4(name[1],'v','a','l','\0')) { + // eval (src/jswrap_functions.c) + JsVar *code = jspParseSingleFunction(); + JsVar *_r = jswrap_eval(code); + jsvUnLock(code); + return _r; + } + } else if (name[0]=='d') { + if (CMP4(name[1],'i','g','i','t') && CMP2(name[5],'a','l')) { + if (CMP4(name[7],'P','u','l','s') && CMP2(name[11],'e','\0')) { + // digitalPulse (src/jswrap_io.c) + JsVar *pin, *value, *time; + jspParseFunction(0, &pin, &value, &time, 0); + jswrap_io_digitalPulse(jshGetPinFromVarAndUnLock(pin), jsvGetBoolAndUnLock(value), jsvGetFloatAndUnLock(time)); + return 0; + } else if (CMP4(name[7],'R','e','a','d') && name[11]=='\0') { + // digitalRead (src/jswrap_io.c) + JsVar *pin = jspParseSingleFunction(); + JsVar *_r = jsvNewFromInteger(jswrap_io_digitalRead(pin)); + jsvUnLock(pin); + return _r; + } else if (CMP4(name[7],'W','r','i','t') && CMP2(name[11],'e','\0')) { + // digitalWrite (src/jswrap_io.c) + JsVar *pin, *value; + jspParseFunction(0, &pin, &value, 0, 0); + jswrap_io_digitalWrite(pin, jsvGetIntegerAndUnLock(value)); + jsvUnLock(pin); + return 0; + } + } else if (CMP4(name[1],'u','m','p','\0')) { + // dump (src/jswrap_interactive.c) + jspParseEmptyFunction(); + jsiDumpState(); + return 0; + } + } else if (CMP3(name[0],'g','e','t')) { + if (CMP4(name[3],'S','e','r','i') && CMP3(name[7],'a','l','\0')) { + // getSerial (src/jswrap_interactive.c) + jspParseEmptyFunction(); + JsVar *_r = jswrap_interface_getSerial(); + return _r; + } else if (CMP4(name[3],'T','i','m','e') && name[7]=='\0') { + // getTime (src/jswrap_interactive.c) + jspParseEmptyFunction(); + JsVar *_r = jsvNewFromFloat((JsVarFloat)jshGetSystemTime() / (JsVarFloat)jshGetTimeFromMilliseconds(1000)); + return _r; + } + } else if (CMP4(name[0],'F','l','o','a') && name[4]=='t') { + if (CMP4(name[5],'3','2','A','r') && CMP4(name[9],'r','a','y','\0')) { + // Float32Array.Float32Array (src/jswrap_arraybuffer.c) + JsVar *arr, *byteOffset, *length; + jspParseFunction(0, &arr, &byteOffset, &length, 0); + JsVar *_r = jswrap_typedarray_constructor(ARRAYBUFFERVIEW_FLOAT32, arr, jsvGetInteger(byteOffset), jsvGetInteger(length)); + jsvUnLock(arr); + jsvUnLock(byteOffset); + jsvUnLock(length); + return _r; + } else if (CMP4(name[5],'6','4','A','r') && CMP4(name[9],'r','a','y','\0')) { + // Float64Array.Float64Array (src/jswrap_arraybuffer.c) + JsVar *arr, *byteOffset, *length; + jspParseFunction(0, &arr, &byteOffset, &length, 0); + JsVar *_r = jswrap_typedarray_constructor(ARRAYBUFFERVIEW_FLOAT64, arr, jsvGetInteger(byteOffset), jsvGetInteger(length)); + jsvUnLock(arr); + jsvUnLock(byteOffset); + jsvUnLock(length); + return _r; + } + } else if (name[0]=='S') { + if (CMP2(name[1],'P','I')) { + if (CMP2(name[3],'1','\0')) { + // Object SPI1 (src/jswrap_spi_i2c.c) + #if SPIS>=1 + jspParseVariableName(); + return jspNewObject(jsiGetParser(), "SPI1", "SPI"); + #endif //SPIS>=1 + } else if (CMP2(name[3],'3','\0')) { + // Object SPI3 (src/jswrap_spi_i2c.c) + #if SPIS>=3 + jspParseVariableName(); + return jspNewObject(jsiGetParser(), "SPI3", "SPI"); + #endif //SPIS>=3 + } else if (CMP2(name[3],'2','\0')) { + // Object SPI2 (src/jswrap_spi_i2c.c) + #if SPIS>=2 + jspParseVariableName(); + return jspNewObject(jsiGetParser(), "SPI2", "SPI"); + #endif //SPIS>=2 + } + } else if (CMP4(name[1],'e','r','i','a') && name[5]=='l') { + if (CMP2(name[6],'1','\0')) { + // Object Serial1 (src/jswrap_serial.c) + #if USARTS>=1 + jspParseVariableName(); + return jspNewObject(jsiGetParser(), "Serial1", "Serial"); + #endif //USARTS>=1 + } else if (CMP2(name[6],'3','\0')) { + // Object Serial3 (src/jswrap_serial.c) + #if USARTS>=3 + jspParseVariableName(); + return jspNewObject(jsiGetParser(), "Serial3", "Serial"); + #endif //USARTS>=3 + } else if (CMP2(name[6],'2','\0')) { + // Object Serial2 (src/jswrap_serial.c) + #if USARTS>=2 + jspParseVariableName(); + return jspNewObject(jsiGetParser(), "Serial2", "Serial"); + #endif //USARTS>=2 + } else if (CMP2(name[6],'5','\0')) { + // Object Serial5 (src/jswrap_serial.c) + #if USARTS>=5 + jspParseVariableName(); + return jspNewObject(jsiGetParser(), "Serial5", "Serial"); + #endif //USARTS>=5 + } else if (CMP2(name[6],'4','\0')) { + // Object Serial4 (src/jswrap_serial.c) + #if USARTS>=4 + jspParseVariableName(); + return jspNewObject(jsiGetParser(), "Serial4", "Serial"); + #endif //USARTS>=4 + } else if (CMP2(name[6],'6','\0')) { + // Object Serial6 (src/jswrap_serial.c) + #if USARTS>=6 + jspParseVariableName(); + return jspNewObject(jsiGetParser(), "Serial6", "Serial"); + #endif //USARTS>=6 + } + } else if (CMP4(name[1],'t','r','i','n') && CMP2(name[5],'g','\0')) { + // String.String (src/jswrap_string.c) + JsVar *str = jspParseSingleFunction(); + JsVar *_r = jswrap_string_constructor(str); + jsvUnLock(str); + return _r; + } + } else if (CMP4(name[0],'l','o','a','d') && name[4]=='\0') { + // load (src/jswrap_interactive.c) + jspParseEmptyFunction(); + jsiSetTodo(TODO_FLASH_LOAD); + return 0; + } else if (CMP4(name[0],'O','n','e','W') && CMP4(name[4],'i','r','e','\0')) { + // OneWire.OneWire (src/jswrap_onewire.c) + JsVar *pin = jspParseSingleFunction(); + JsVar *_r = jswrap_onewire_constructor(jshGetPinFromVarAndUnLock(pin)); + return _r; + } else if (CMP4(name[0],'N','a','N','\0')) { + // NaN (libs/jswrap_math.c) + jspParseVariableName(); + JsVar *_r = jsvNewFromFloat(NAN); + return _r; + } else if (name[0]=='p') { + if (CMP4(name[1],'a','r','s','e')) { + if (CMP4(name[5],'I','n','t','\0')) { + // parseInt (src/jswrap_functions.c) + JsVar *string, *radix; + jspParseFunction(0, &string, &radix, 0, 0); + JsVar *_r = jswrap_parseInt(string, radix); + jsvUnLock(string); + jsvUnLock(radix); + return _r; + } else if (CMP4(name[5],'F','l','o','a') && CMP2(name[9],'t','\0')) { + // parseFloat (src/jswrap_functions.c) + JsVar *string = jspParseSingleFunction(); + JsVar *_r = jsvNewFromFloat(jswrap_parseFloat(string)); + jsvUnLock(string); + return _r; + } + } else if (CMP4(name[1],'i','n','M','o') && CMP3(name[5],'d','e','\0')) { + // pinMode (src/jswrap_io.c) + JsVar *pin, *mode; + jspParseFunction(0, &pin, &mode, 0, 0); + jswrap_io_pinMode(jshGetPinFromVarAndUnLock(pin), mode); + jsvUnLock(mode); + return 0; + } else if (CMP4(name[1],'r','i','n','t') && name[5]=='\0') { + // print (src/jswrap_interactive.c) + JsVar *text = jspParseFunctionAsArray(); + if (!text) return 0; // if parse error + jswrap_interface_print(text); + jsvUnLock(text); + return 0; + } else if (CMP3(name[1],'e','e','k')) { + if (CMP3(name[4],'1','6','\0')) { + // peek16 (src/jswrap_io.c) + JsVar *addr = jspParseSingleFunction(); + JsVar *_r = jsvNewFromInteger((JsVarInt)*(unsigned short*)jsvGetInteger(addr)); + jsvUnLock(addr); + return _r; + } else if (CMP2(name[4],'8','\0')) { + // peek8 (src/jswrap_io.c) + JsVar *addr = jspParseSingleFunction(); + JsVar *_r = jsvNewFromInteger((JsVarInt)*(unsigned char*)jsvGetInteger(addr)); + jsvUnLock(addr); + return _r; + } else if (CMP3(name[4],'3','2','\0')) { + // peek32 (src/jswrap_io.c) + JsVar *addr = jspParseSingleFunction(); + JsVar *_r = jsvNewFromInteger((JsVarInt)*(unsigned int*)jsvGetInteger(addr)); + jsvUnLock(addr); + return _r; + } + } else if (CMP3(name[1],'o','k','e')) { + if (CMP3(name[4],'1','6','\0')) { + // poke16 (src/jswrap_io.c) + JsVar *addr, *value; + jspParseFunction(0, &addr, &value, 0, 0); + (*(unsigned short*)jsvGetInteger(addr)) = (unsigned short)jsvGetInteger(value); + jsvUnLock(addr); + jsvUnLock(value); + return 0; + } else if (CMP2(name[4],'8','\0')) { + // poke8 (src/jswrap_io.c) + JsVar *addr, *value; + jspParseFunction(0, &addr, &value, 0, 0); + (*(unsigned char*)jsvGetInteger(addr)) = (unsigned char)jsvGetInteger(value); + jsvUnLock(addr); + jsvUnLock(value); + return 0; + } else if (CMP3(name[4],'3','2','\0')) { + // poke32 (src/jswrap_io.c) + JsVar *addr, *value; + jspParseFunction(0, &addr, &value, 0, 0); + (*(unsigned int*)jsvGetInteger(addr)) = (unsigned int)jsvGetInteger(value); + jsvUnLock(addr); + jsvUnLock(value); + return 0; + } + } + } else if (name[0]=='s') { + if (CMP4(name[1],'a','v','e','\0')) { + // save (src/jswrap_interactive.c) + jspParseEmptyFunction(); + jsiSetTodo(TODO_FLASH_SAVE); + return 0; + } else if (CMP2(name[1],'e','t')) { + if (CMP4(name[3],'B','u','s','y') && CMP4(name[7],'I','n','d','i') && CMP4(name[11],'c','a','t','o') && CMP2(name[15],'r','\0')) { + // setBusyIndicator (src/jswrap_interactive.c) + JsVar *pin = jspParseSingleFunction(); + jswrap_interface_setBusyIndicator(pin); + jsvUnLock(pin); + return 0; + } else if (CMP4(name[3],'D','e','e','p') && CMP4(name[7],'S','l','e','e') && CMP2(name[11],'p','\0')) { + // setDeepSleep (src/jswrap_interactive.c) + JsVar *sleep = jspParseSingleFunction(); + jswrap_interface_setDeepSleep(jsvGetBoolAndUnLock(sleep)); + return 0; + } else if (CMP4(name[3],'I','n','t','e') && CMP4(name[7],'r','v','a','l') && name[11]=='\0') { + // setInterval (src/jswrap_io.c) + JsVar *function, *timeout; + jspParseFunction(0|JSP_NOSKIP_A, &function, &timeout, 0, 0); + JsVar *_r = jswrap_interface_setInterval(function, jsvGetFloatAndUnLock(timeout)); + jsvUnLock(function); + return _r; + } else if (CMP4(name[3],'S','l','e','e') && CMP4(name[7],'p','I','n','d') && CMP4(name[11],'i','c','a','t') && CMP3(name[15],'o','r','\0')) { + // setSleepIndicator (src/jswrap_interactive.c) + JsVar *pin = jspParseSingleFunction(); + jswrap_interface_setSleepIndicator(pin); + jsvUnLock(pin); + return 0; + } else if (CMP4(name[3],'T','i','m','e') && CMP4(name[7],'o','u','t','\0')) { + // setTimeout (src/jswrap_io.c) + JsVar *function, *timeout; + jspParseFunction(0|JSP_NOSKIP_A, &function, &timeout, 0, 0); + JsVar *_r = jswrap_interface_setTimeout(function, jsvGetFloatAndUnLock(timeout)); + jsvUnLock(function); + return _r; + } else if (CMP4(name[3],'W','a','t','c') && CMP2(name[7],'h','\0')) { + // setWatch (src/jswrap_io.c) + JsVar *function, *pin, *options; + jspParseFunction(0|JSP_NOSKIP_A, &function, &pin, &options, 0); + JsVar *_r = jswrap_interface_setWatch(function, jshGetPinFromVarAndUnLock(pin), options); + jsvUnLock(function); + jsvUnLock(options); + return _r; + } + } + } else if (CMP2(name[0],'r','e')) { + if (CMP4(name[2],'q','u','i','r') && CMP2(name[6],'e','\0')) { + // require (src/jswrap_modules.c) + JsVar *moduleName = jspParseSingleFunction(); + JsVar *_r = jswrap_require(moduleName); + jsvUnLock(moduleName); + return _r; + } else if (CMP4(name[2],'s','e','t','\0')) { + // reset (src/jswrap_interactive.c) + jspParseEmptyFunction(); + jsiSetTodo(TODO_RESET); + return 0; + } + } else if (name[0]=='U') { + if (CMP3(name[1],'i','n','t')) { + if (CMP4(name[4],'1','6','A','r') && CMP4(name[8],'r','a','y','\0')) { + // Uint16Array.Uint16Array (src/jswrap_arraybuffer.c) + JsVar *arr, *byteOffset, *length; + jspParseFunction(0, &arr, &byteOffset, &length, 0); + JsVar *_r = jswrap_typedarray_constructor(ARRAYBUFFERVIEW_UINT16, arr, jsvGetInteger(byteOffset), jsvGetInteger(length)); + jsvUnLock(arr); + jsvUnLock(byteOffset); + jsvUnLock(length); + return _r; + } else if (CMP4(name[4],'8','A','r','r') && CMP3(name[8],'a','y','\0')) { + // Uint8Array.Uint8Array (src/jswrap_arraybuffer.c) + JsVar *arr, *byteOffset, *length; + jspParseFunction(0, &arr, &byteOffset, &length, 0); + JsVar *_r = jswrap_typedarray_constructor(ARRAYBUFFERVIEW_UINT8, arr, jsvGetInteger(byteOffset), jsvGetInteger(length)); + jsvUnLock(arr); + jsvUnLock(byteOffset); + jsvUnLock(length); + return _r; + } else if (CMP4(name[4],'3','2','A','r') && CMP4(name[8],'r','a','y','\0')) { + // Uint32Array.Uint32Array (src/jswrap_arraybuffer.c) + JsVar *arr, *byteOffset, *length; + jspParseFunction(0, &arr, &byteOffset, &length, 0); + JsVar *_r = jswrap_typedarray_constructor(ARRAYBUFFERVIEW_UINT32, arr, jsvGetInteger(byteOffset), jsvGetInteger(length)); + jsvUnLock(arr); + jsvUnLock(byteOffset); + jsvUnLock(length); + return _r; + } + } else if (CMP3(name[1],'S','B','\0')) { + // Object USB (src/jswrap_serial.c) + #if defined(USB) + jspParseVariableName(); + return jspNewObject(jsiGetParser(), "USB", "Serial"); + #endif //defined(USB) + } + } else if (CMP4(name[0],'t','r','a','c') && CMP2(name[4],'e','\0')) { + // trace (src/jswrap_interactive.c) + JsVar *root; + jspParseFunction(0|JSP_NOSKIP_A, &root, 0, 0, 0); + jswrap_interface_trace(root); + jsvUnLock(root); + return 0; + } else if (name[0]=='I') { + if (CMP2(name[1],'2','C')) { + if (CMP2(name[3],'1','\0')) { + // Object I2C1 (src/jswrap_spi_i2c.c) + #if I2CS>=1 + jspParseVariableName(); + return jspNewObject(jsiGetParser(), "I2C1", "I2C"); + #endif //I2CS>=1 + } else if (CMP2(name[3],'3','\0')) { + // Object I2C3 (src/jswrap_spi_i2c.c) + #if I2CS>=3 + jspParseVariableName(); + return jspNewObject(jsiGetParser(), "I2C3", "I2C"); + #endif //I2CS>=3 + } else if (CMP2(name[3],'2','\0')) { + // Object I2C2 (src/jswrap_spi_i2c.c) + #if I2CS>=2 + jspParseVariableName(); + return jspNewObject(jsiGetParser(), "I2C2", "I2C"); + #endif //I2CS>=2 + } + } else if (CMP2(name[1],'n','t')) { + if (CMP4(name[3],'1','6','A','r') && CMP4(name[7],'r','a','y','\0')) { + // Int16Array.Int16Array (src/jswrap_arraybuffer.c) + JsVar *arr, *byteOffset, *length; + jspParseFunction(0, &arr, &byteOffset, &length, 0); + JsVar *_r = jswrap_typedarray_constructor(ARRAYBUFFERVIEW_INT16, arr, jsvGetInteger(byteOffset), jsvGetInteger(length)); + jsvUnLock(arr); + jsvUnLock(byteOffset); + jsvUnLock(length); + return _r; + } else if (CMP4(name[3],'8','A','r','r') && CMP3(name[7],'a','y','\0')) { + // Int8Array.Int8Array (src/jswrap_arraybuffer.c) + JsVar *arr, *byteOffset, *length; + jspParseFunction(0, &arr, &byteOffset, &length, 0); + JsVar *_r = jswrap_typedarray_constructor(ARRAYBUFFERVIEW_INT8, arr, jsvGetInteger(byteOffset), jsvGetInteger(length)); + jsvUnLock(arr); + jsvUnLock(byteOffset); + jsvUnLock(length); + return _r; + } else if (CMP4(name[3],'3','2','A','r') && CMP4(name[7],'r','a','y','\0')) { + // Int32Array.Int32Array (src/jswrap_arraybuffer.c) + JsVar *arr, *byteOffset, *length; + jspParseFunction(0, &arr, &byteOffset, &length, 0); + JsVar *_r = jswrap_typedarray_constructor(ARRAYBUFFERVIEW_INT32, arr, jsvGetInteger(byteOffset), jsvGetInteger(length)); + jsvUnLock(arr); + jsvUnLock(byteOffset); + jsvUnLock(length); + return _r; + } + } + } + } + return JSW_HANDLEFUNCTIONCALL_UNHANDLED; +} + + +bool jswIsBuiltInObject(const char *name) { + return +strcmp(name, "Pin")==0 || + strcmp(name, "Modules")==0 || + strcmp(name, "process")==0 || + strcmp(name, "console")==0 || + strcmp(name, "JSON")==0 || + strcmp(name, "Hardware")==0 || + strcmp(name, "Object")==0 || + strcmp(name, "Function")==0 || + strcmp(name, "Integer")==0 || + strcmp(name, "Double")==0 || + strcmp(name, "String")==0 || + strcmp(name, "Array")==0 || + strcmp(name, "ArrayBuffer")==0 || + strcmp(name, "ArrayBufferView")==0 || + strcmp(name, "Uint8Array")==0 || + strcmp(name, "Int8Array")==0 || + strcmp(name, "Uint16Array")==0 || + strcmp(name, "Int16Array")==0 || + strcmp(name, "Uint32Array")==0 || + strcmp(name, "Int32Array")==0 || + strcmp(name, "Float32Array")==0 || + strcmp(name, "Float64Array")==0 || + strcmp(name, "Serial")==0 || + strcmp(name, "SPI")==0 || + strcmp(name, "I2C")==0 || + strcmp(name, "OneWire")==0 || + strcmp(name, "Math")==0; +} + + +bool jswIsBuiltInLibrary(const char *name) { + return +; +} + + +/** Given a variable, return the basic object name of it */ +const char *jswGetBasicObjectName(JsVar *var) { + if (jsvIsFunction(var)) return "Function"; + if (jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_INT32) return "Int32Array"; + if (jsvIsString(var)) return "String"; + if (jsvIsPin(var)) return "Pin"; + if (jsvIsFloat(var)) return "Double"; + if (jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_ARRAYBUFFER) return "ArrayBuffer"; + if (jsvIsObject(var)) return "Object"; + if (jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_UINT8) return "Uint8Array"; + if (jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_UINT16) return "Uint16Array"; + if (jsvIsRoot(var)) return "Hardware"; + if (jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_FLOAT64) return "Float64Array"; + if (jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_INT8) return "Int8Array"; + if (jsvIsInt(var)) return "Integer"; + if (jsvIsArray(var)) return "Array"; + if (jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_INT16) return "Int16Array"; + if (jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_FLOAT32) return "Float32Array"; + if (jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_UINT32) return "Uint32Array"; + return 0; +} + + +/** Given the name of a Basic Object, eg, Uint8Array, String, etc. Return the prototype object's name - or 0. */ +const char *jswGetBasicObjectPrototypeName(const char *objectName) { + if (!strcmp(objectName, "Uint8Array")) return "ArrayBufferView"; + if (!strcmp(objectName, "Int8Array")) return "ArrayBufferView"; + if (!strcmp(objectName, "Uint16Array")) return "ArrayBufferView"; + if (!strcmp(objectName, "Int16Array")) return "ArrayBufferView"; + if (!strcmp(objectName, "Uint32Array")) return "ArrayBufferView"; + if (!strcmp(objectName, "Int32Array")) return "ArrayBufferView"; + if (!strcmp(objectName, "Float32Array")) return "ArrayBufferView"; + if (!strcmp(objectName, "Float64Array")) return "ArrayBufferView"; + return strcmp(objectName,"Object") ? "Object" : 0; +} + + diff --git a/components/external/espruino/gen/platform_config.h b/components/external/espruino/gen/platform_config.h new file mode 100644 index 0000000000..dabe6c3ab1 --- /dev/null +++ b/components/external/espruino/gen/platform_config.h @@ -0,0 +1,53 @@ + +// Automatically generated header file for LINUX +// Generated by scripts/build_platform_config.py + +#ifndef _PLATFORM_CONFIG_H +#define _PLATFORM_CONFIG_H +#include + +#define PC_BOARD_ID "LINUX" +#define PC_BOARD_CHIP "LINUX" +#define PC_BOARD_CHIP_FAMILY "LINUX" + + + +// SYSTICK is the counter that counts up and that we use as the real-time clock +// The smaller this is, the longer we spend in interrupts, but also the more we can sleep! +#define SYSTICK_RANGE 0x1000000 // the Maximum (it is a 24 bit counter) - on Olimexino this is about 0.6 sec +#define SYSTICKS_BEFORE_USB_DISCONNECT 2 + +#define DEFAULT_BUSY_PIN_INDICATOR (Pin)-1 // no indicator +#define DEFAULT_SLEEP_PIN_INDICATOR (Pin)-1 // no indicator + +// When to send the message that the IO buffer is getting full +#define IOBUFFER_XOFF ((TXBUFFERMASK)*6/8) +// When to send the message that we can start receiving again +#define IOBUFFER_XON ((TXBUFFERMASK)*3/8) + + + +#define RAM_TOTAL (-1*1024) +#define FLASH_TOTAL (-1*1024) + +#define RESIZABLE_JSVARS // Allocate variables in blocks using malloc + +#define USARTS 0 +#define SPIS 1 +#define I2CS 0 +#define ADCS 0 +#define DACS 0 + +#define DEFAULT_CONSOLE_DEVICE EV_USBSERIAL + +#define IOBUFFERMASK 31 // (max 255) amount of items in event buffer - events take ~9 bytes each +#define TXBUFFERMASK 31 // (max 255) + + +// definition to avoid compilation when Pin/platform config is not defined +#define IS_PIN_USED_INTERNALLY(PIN) ((false)) +#define IS_PIN_A_LED(PIN) ((false)) +#define IS_PIN_A_BUTTON(PIN) ((false)) + +#endif // _PLATFORM_CONFIG_H + diff --git a/components/external/espruino/libs/jswrap_math.c b/components/external/espruino/libs/jswrap_math.c new file mode 100644 index 0000000000..b5c1522d28 --- /dev/null +++ b/components/external/espruino/libs/jswrap_math.c @@ -0,0 +1,233 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * This file is designed to be parsed during the build process + * + * Contains built-in functions for Maths + * ---------------------------------------------------------------------------- + */ +#include "jswrap_math.h" + +/*JSON{ "type":"class", + "class" : "Math", + "description" : "This is a standard JavaScript class that contains useful Maths routines" +}*/ + +// -------------------------------------------------------------------- Integer +/*JSON{ "type":"staticmethod", + "class" : "Integer", "name" : "valueOf", + "generate" : "jswrap_integer_valueOf", + "description" : "Given a string containing a single character, return the numeric value of it", + "params" : [ [ "character" ,"JsVar", "A string containing a single character"] ], + "return" : ["int", "The integer value of char"] +}*/ +JsVarInt jswrap_integer_valueOf(JsVar *v) { + if (!jsvIsString(v) || jsvGetStringLength(v)!=1) + return 0; + return (int)v->varData.str[0]; +} +/*JSON{ "type":"variable", "name" : "NaN", + "generate_full" : "NAN", + "return" : ["float", "Not a Number"] +}*/ + // -------------------------------------------------------------------- Double +/*JSON{ "type":"staticmethod", + "class" : "Double", "name" : "doubleToIntBits", + "generate_full" : "*(JsVarInt*)&x", + "description" : " Convert the floating point value given into an integer representing the bits contained in it", + "params" : [ [ "x", "float", "A floating point number"] ], + "return" : ["int", "The integer representation of x"] +}*/ +// -------------------------------------------------------------------- Math +/*JSON{ "type":"staticproperty", + "class" : "Math", "name" : "E", + "generate_full" : "2.71828182846", + "return" : ["float", "The value of E - 2.71828182846"] +}*/ +/*JSON{ "type":"staticproperty", + "class" : "Math", "name" : "PI", + "generate_full" : "3.14159265359", + "return" : ["float", "The value of PI - 3.14159265359"] +}*/ +/*JSON{ "type":"staticmethod", + "class" : "Math", "name" : "abs", + "generate" : "jswrap_math_abs", + "params" : [ [ "x", "float", "A floating point value"] ], + "return" : ["float", "The absolute value of x (eg, ```Math.abs(2)==2```, but also ```Math.abs(-2)==2```)"] +}*/ +JsVarFloat jswrap_math_abs(JsVarFloat x) { + return (x<0)?-x:x; +} +/*JSON{ "type":"staticmethod", + "class" : "Math", "name" : "acos", + "generate" : "acos", + "params" : [ [ "x", "float", "The value to get the arc cosine of"] ], + "return" : ["float", "The arc cosine of x, between 0 and PI"] +}*/ +/*JSON{ "type":"staticmethod", + "class" : "Math", "name" : "asin", + "generate" : "asin", + "params" : [ [ "x", "float", "The value to get the arc sine of"] ], + "return" : ["float", "The arc sine of x, between -PI/2 and PI/2"] +}*/ +/*JSON{ "type":"staticmethod", + "class" : "Math", "name" : "atan", + "generate" : "atan", + "params" : [ [ "x", "float", "The value to get the arc tangent of"] ], + "return" : ["float", "The arc tangent of x, between -PI/2 and PI/2"] +}*/ +/*JSON{ "type":"staticmethod", + "class" : "Math", "name" : "atan2", + "generate" : "atan2", + "params" : [ [ "y", "float", "The Y-part of the angle to get the arc tangent of"], + [ "x", "float", "The X-part of the angle to get the arc tangent of"] ], + "return" : ["float", "The arctangent of Y/X, between -PI and PI"] +}*/ + +/* we use sin here, not cos, to try and save a bit of code space */ +/*JSON{ "type":"staticmethod", + "class" : "Math", "name" : "cos", + "generate_full" : "sin(jsvGetFloat(theta) + (3.14159265359/2.0))", + "params" : [ [ "theta", "float", "The angle to get the cosine of"] ], + "return" : ["float", "The cosine of theta"] +}*/ + +#define DBL_MAX 1.7976931348623157E+308 + +double fs_fmod(double x, double y) +{ + double a, b; + const double c = x; + + if (0 > c) { + x = -x; + } + if (0 > y) { + y = -y; + } + if (y != 0 && DBL_MAX >= y && DBL_MAX >= x) { + while (x >= y) { + a = x / 2; + b = y; + while (a >= b) { + b *= 2; + } + x -= b; + } + } else { + x = 0; + } + return 0 > c ? -x : x; +} + +double jswrap_math_pow(double x, double y) +{ + double p; + if (0 > x && fs_fmod(y, 1) == 0) { + if (fs_fmod(y, 2) == 0) { + p = exp(log(-x) * y); + } else { + p = -exp(log(-x) * y); + } + } else { + if (x != 0 || 0 >= y) { + p = exp(log( x) * y); + } else { + p = 0; + } + } + return p; +} + + +/*JSON{ "type":"staticmethod", + "class" : "Math", "name" : "pow", + "generate" : "jswrap_math_pow", + "params" : [ [ "x", "float", "The value to raise to the power"], + [ "y", "float", "The power x should be raised to"] ], + "return" : ["float", "x raised to the power y (x^y)"] +}*/ +/*JSON{ "type":"staticmethod", + "class" : "Math", "name" : "random", + "generate_full" : "(JsVarFloat)rand() / (JsVarFloat)RAND_MAX", + "return" : ["float", "A random number between 0 and 1"] +}*/ +/*JSON{ "type":"staticmethod", + "class" : "Math", "name" : "round", + "generate" : "(JsVarInt)round", + "params" : [ [ "x", "float", "The value to round"] ], + "return" : ["int", "x, rounded to the nearest integer"] +}*/ +/*JSON{ "type":"staticmethod", + "class" : "Math", "name" : "sin", + "generate" : "sin", + "params" : [ [ "theta", "float", "The angle to get the sine of"] ], + "return" : ["float", "The sine of theta"] +}*/ + +/* we could use the real sqrt - but re-use pow to save on code space */ +/*JSON{ "type":"staticmethod", + "class" : "Math", "name" : "sqrt", + "generate_full" : "jswrap_math_pow(jsvGetFloat(x),0.5)", + "params" : [ [ "x", "float", "The value to take the square root of"] ], + "return" : ["float", "The square root of x"] +}*/ + +/*JSON{ "type":"staticmethod", + "class" : "Math", "name" : "ceil", + "generate" : "ceil", + "params" : [ [ "x", "float", "The value to round up"] ], + "return" : ["float", "x, rounded upwards to the nearest integer"] +}*/ +/*JSON{ "type":"staticmethod", + "class" : "Math", "name" : "floor", + "generate" : "floor", + "params" : [ [ "x", "float", "The value to round down"] ], + "return" : ["float", "x, rounded downwards to the nearest integer"] +}*/ + +/*JSON{ "type":"staticmethod", + "class" : "Math", "name" : "exp", + "generate" : "exp", + "params" : [ [ "x", "float", "The value raise E to the power of"] ], + "return" : ["float", "E^x"] +}*/ +/*JSON{ "type":"staticmethod", + "class" : "Math", "name" : "log", + "generate" : "log", + "params" : [ [ "x", "float", "The value to take the logarithm (base E) root of"] ], + "return" : ["float", "The log (base E) of x"] +}*/ + +/*JSON{ "type":"staticmethod", "ifndef" : "SAVE_ON_FLASH", + "class" : "Math", "name" : "clip", + "generate" : "jswrap_math_clip", + "description" : "Clip a number to be between min and max (inclusive)", + "params" : [ [ "x", "float", "A floating point value to clip"], + [ "min", "float", "The smallest the value should be"], + [ "max", "float", "The largest the value should be"] ], + "return" : ["float", "The value of x, clipped so as not to be below min or above max."] +}*/ +JsVarFloat jswrap_math_clip(JsVarFloat x, JsVarFloat min, JsVarFloat max) { + if (xmax) x=max; + return x; +} + +/*JSON{ "type":"staticmethod", "ifndef" : "SAVE_ON_FLASH", + "class" : "Math", "name" : "wrap", + "generate" : "wrapAround", + "description" : "Wrap a number around if it is less than 0 or greater than or equal to max. For instance you might do: ```Math.wrap(angleInDegrees, 360)```", + "params" : [ [ "x", "float", "A floating point value to wrap"], + [ "max", "float", "The largest the value should be"] ], + "return" : ["float", "The value of x, wrapped so as not to be below min or above max."] +}*/ + + diff --git a/components/external/espruino/libs/jswrap_math.h b/components/external/espruino/libs/jswrap_math.h new file mode 100644 index 0000000000..b5dff095a5 --- /dev/null +++ b/components/external/espruino/libs/jswrap_math.h @@ -0,0 +1,28 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Contains built-in functions for Maths + * ---------------------------------------------------------------------------- + */ +#include "jsutils.h" +#include "jsvar.h" + +#ifdef ARM +#include "mconf.h" +#include "protos.h" +#else +#include +#endif + + +JsVarInt jswrap_integer_valueOf(JsVar *v); +JsVarFloat jswrap_math_abs(JsVarFloat x); +double jswrap_math_pow(double x, double y); +JsVarFloat jswrap_math_clip(JsVarFloat x, JsVarFloat min, JsVarFloat max); diff --git a/components/external/espruino/libs/math/README b/components/external/espruino/libs/math/README new file mode 100644 index 0000000000..97f3586c52 --- /dev/null +++ b/components/external/espruino/libs/math/README @@ -0,0 +1,32 @@ + +This suite of C language elementary functions offers support for +not-a-number (NaN) and infinity rules, subnormal numbers, and minus +zero as described by IEEE standard 754 and the Numerical C Extensions +Group (NCEG). For a variety of reasons, many computers cannot take +advantage of these features. You can disable any or all of them by +removing the corresponding preprocessor macros. Check the files +mconf.h and const.c carefully to be sure they are appropriate for your +system. + + + +------------------------------------------ + +http://www.netlib.org/cephes/readme + + Some software in this archive may be from the book _Methods and +Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster +International, 1989) or from the Cephes Mathematical Library, a +commercial product. In either event, it is copyrighted by the author. +What you see here may be used freely but it comes with no support or +guarantee. + + The two known misprints in the book are repaired here in the +source listings for the gamma function and the incomplete beta +integral. + + + Stephen L. Moshier + moshier@na-net.ornl.gov + + diff --git a/components/external/espruino/libs/math/acosh.c b/components/external/espruino/libs/math/acosh.c new file mode 100644 index 0000000000..216e00d60b --- /dev/null +++ b/components/external/espruino/libs/math/acosh.c @@ -0,0 +1,167 @@ +/* acosh.c + * + * Inverse hyperbolic cosine + * + * + * + * SYNOPSIS: + * + * double x, y, acosh(); + * + * y = acosh( x ); + * + * + * + * DESCRIPTION: + * + * Returns inverse hyperbolic cosine of argument. + * + * If 1 <= x < 1.5, a rational approximation + * + * sqrt(z) * P(z)/Q(z) + * + * where z = x-1, is used. Otherwise, + * + * acosh(x) = log( x + sqrt( (x-1)(x+1) ). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC 1,3 30000 4.2e-17 1.1e-17 + * IEEE 1,3 30000 4.6e-16 8.7e-17 + * + * + * ERROR MESSAGES: + * + * message condition value returned + * acosh domain |x| < 1 NAN + * + */ + +/* acosh.c */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + + +/* acosh(z) = sqrt(x) * R(x), z = x + 1, interval 0 < x < 0.5 */ + +#include "mconf.h" + +#ifdef UNK +const static double P[] = { + 1.18801130533544501356E2, + 3.94726656571334401102E3, + 3.43989375926195455866E4, + 1.08102874834699867335E5, + 1.10855947270161294369E5 +}; +const static double Q[] = { +/* 1.00000000000000000000E0,*/ + 1.86145380837903397292E2, + 4.15352677227719831579E3, + 2.97683430363289370382E4, + 8.29725251988426222434E4, + 7.83869920495893927727E4 +}; +#endif + +#ifdef DEC +static unsigned short P[] = { +0041755,0115055,0144002,0146444, +0043166,0132103,0155150,0150302, +0044006,0057360,0003021,0162753, +0044323,0021557,0175225,0056253, +0044330,0101771,0040046,0006636 +}; +static unsigned short Q[] = { +/*0040200,0000000,0000000,0000000,*/ +0042072,0022467,0126670,0041232, +0043201,0146066,0152142,0034015, +0043750,0110257,0121165,0026100, +0044242,0007103,0034667,0033173, +0044231,0014576,0175573,0017472 +}; +#endif + +#ifdef IBMPC +static unsigned short P[] = { +0x59a4,0xb900,0xb345,0x405d, +0x1a18,0x7b4d,0xd688,0x40ae, +0x3cbd,0x00c2,0xcbde,0x40e0, +0xab95,0xff52,0x646d,0x40fa, +0xc1b4,0x2804,0x107f,0x40fb +}; +static unsigned short Q[] = { +/*0x0000,0x0000,0x0000,0x3ff0,*/ +0x0853,0xf5b7,0x44a6,0x4067, +0x4702,0xda8c,0x3986,0x40b0, +0xa588,0xf44e,0x1215,0x40dd, +0xe6cf,0x6736,0x41c8,0x40f4, +0x63e7,0xdf6f,0x232f,0x40f3 +}; +#endif + +#ifdef MIEEE +static unsigned short P[] = { +0x405d,0xb345,0xb900,0x59a4, +0x40ae,0xd688,0x7b4d,0x1a18, +0x40e0,0xcbde,0x00c2,0x3cbd, +0x40fa,0x646d,0xff52,0xab95, +0x40fb,0x107f,0x2804,0xc1b4 +}; +static unsigned short Q[] = { +0x4067,0x44a6,0xf5b7,0x0853, +0x40b0,0x3986,0xda8c,0x4702, +0x40dd,0x1215,0xf44e,0xa588, +0x40f4,0x41c8,0x6736,0xe6cf, +0x40f3,0x232f,0xdf6f,0x63e7, +}; +#endif + +#ifdef ANSIPROT +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern double log ( double ); +extern double sqrt ( double ); +#else +double log(), sqrt(), polevl(), p1evl(); +#endif +extern double LOGE2, INFINITY, NAN; + +double acosh(x) +double x; +{ +double a, z; + +if( x < 1.0 ) + { + mtherr( "acosh", DOMAIN ); + return(NAN); + } + +if( x > 1.0e8 ) + { +#ifdef INFINITIES + if( x == INFINITY ) + return( INFINITY ); +#endif + return( log(x) + LOGE2 ); + } + +z = x - 1.0; + +if( z < 0.5 ) + { + a = sqrt(z) * (polevl(z, P, 4) / p1evl(z, Q, 5) ); + return( a ); + } + +a = sqrt( z*(x+1.0) ); +return( log(x + a) ); +} diff --git a/components/external/espruino/libs/math/asin.c b/components/external/espruino/libs/math/asin.c new file mode 100644 index 0000000000..1a4cea33e0 --- /dev/null +++ b/components/external/espruino/libs/math/asin.c @@ -0,0 +1,324 @@ +/* asin.c + * + * Inverse circular sine + * + * + * + * SYNOPSIS: + * + * double x, y, asin(); + * + * y = asin( x ); + * + * + * + * DESCRIPTION: + * + * Returns radian angle between -pi/2 and +pi/2 whose sine is x. + * + * A rational function of the form x + x**3 P(x**2)/Q(x**2) + * is used for |x| in the interval [0, 0.5]. If |x| > 0.5 it is + * transformed by the identity + * + * asin(x) = pi/2 - 2 asin( sqrt( (1-x)/2 ) ). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -1, 1 40000 2.6e-17 7.1e-18 + * IEEE -1, 1 10^6 1.9e-16 5.4e-17 + * + * + * ERROR MESSAGES: + * + * message condition value returned + * asin domain |x| > 1 NAN + * + */ + /* acos() + * + * Inverse circular cosine + * + * + * + * SYNOPSIS: + * + * double x, y, acos(); + * + * y = acos( x ); + * + * + * + * DESCRIPTION: + * + * Returns radian angle between 0 and pi whose cosine + * is x. + * + * Analytically, acos(x) = pi/2 - asin(x). However if |x| is + * near 1, there is cancellation error in subtracting asin(x) + * from pi/2. Hence if x < -0.5, + * + * acos(x) = pi - 2.0 * asin( sqrt((1+x)/2) ); + * + * or if x > +0.5, + * + * acos(x) = 2.0 * asin( sqrt((1-x)/2) ). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -1, 1 50000 3.3e-17 8.2e-18 + * IEEE -1, 1 10^6 2.2e-16 6.5e-17 + * + * + * ERROR MESSAGES: + * + * message condition value returned + * asin domain |x| > 1 NAN + */ + +/* asin.c */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + +#include "mconf.h" + +/* arcsin(x) = x + x^3 P(x^2)/Q(x^2) + 0 <= x <= 0.625 + Peak relative error = 1.2e-18 */ +#if UNK +const static double P[6] = { + 4.253011369004428248960E-3, +-6.019598008014123785661E-1, + 5.444622390564711410273E0, +-1.626247967210700244449E1, + 1.956261983317594739197E1, +-8.198089802484824371615E0, +}; +const static double Q[5] = { +/* 1.000000000000000000000E0, */ +-1.474091372988853791896E1, + 7.049610280856842141659E1, +-1.471791292232726029859E2, + 1.395105614657485689735E2, +-4.918853881490881290097E1, +}; +#endif +#if DEC +static short P[24] = { +0036213,0056330,0057244,0053234, +0140032,0015011,0114762,0160255, +0040656,0035130,0136121,0067313, +0141202,0014616,0170474,0101731, +0041234,0100076,0151674,0111310, +0141003,0025540,0033165,0077246, +}; +static short Q[20] = { +/* 0040200,0000000,0000000,0000000, */ +0141153,0155310,0055360,0072530, +0041614,0177001,0027764,0101237, +0142023,0026733,0064653,0133266, +0042013,0101264,0023775,0176351, +0141504,0140420,0050660,0036543, +}; +#endif +#if IBMPC +static short P[24] = { +0x8ad3,0x0bd4,0x6b9b,0x3f71, +0x5c16,0x333e,0x4341,0xbfe3, +0x2dd9,0x178a,0xc74b,0x4015, +0x907b,0xde27,0x4331,0xc030, +0x9259,0xda77,0x9007,0x4033, +0xafd5,0x06ce,0x656c,0xc020, +}; +static short Q[20] = { +/* 0x0000,0x0000,0x0000,0x3ff0, */ +0x0eab,0x0b5e,0x7b59,0xc02d, +0x9054,0x25fe,0x9fc0,0x4051, +0x76d7,0x6d35,0x65bb,0xc062, +0xbf9d,0x84ff,0x7056,0x4061, +0x07ac,0x0a36,0x9822,0xc048, +}; +#endif +#if MIEEE +static short P[24] = { +0x3f71,0x6b9b,0x0bd4,0x8ad3, +0xbfe3,0x4341,0x333e,0x5c16, +0x4015,0xc74b,0x178a,0x2dd9, +0xc030,0x4331,0xde27,0x907b, +0x4033,0x9007,0xda77,0x9259, +0xc020,0x656c,0x06ce,0xafd5, +}; +static short Q[20] = { +/* 0x3ff0,0x0000,0x0000,0x0000, */ +0xc02d,0x7b59,0x0b5e,0x0eab, +0x4051,0x9fc0,0x25fe,0x9054, +0xc062,0x65bb,0x6d35,0x76d7, +0x4061,0x7056,0x84ff,0xbf9d, +0xc048,0x9822,0x0a36,0x07ac, +}; +#endif + +/* arcsin(1-x) = pi/2 - sqrt(2x)(1+R(x)) + 0 <= x <= 0.5 + Peak relative error = 4.2e-18 */ +#if UNK +const static double R[5] = { + 2.967721961301243206100E-3, +-5.634242780008963776856E-1, + 6.968710824104713396794E0, +-2.556901049652824852289E1, + 2.853665548261061424989E1, +}; +const static double S[4] = { +/* 1.000000000000000000000E0, */ +-2.194779531642920639778E1, + 1.470656354026814941758E2, +-3.838770957603691357202E2, + 3.424398657913078477438E2, +}; +#endif +#if DEC +static short R[20] = { +0036102,0077034,0142164,0174103, +0140020,0036222,0147711,0044173, +0040736,0177655,0153631,0171523, +0141314,0106525,0060015,0055474, +0041344,0045422,0003630,0040344, +}; +static short S[16] = { +/* 0040200,0000000,0000000,0000000, */ +0141257,0112425,0132772,0166136, +0042023,0010315,0075523,0175020, +0142277,0170104,0126203,0017563, +0042253,0034115,0102662,0022757, +}; +#endif +#if IBMPC +static short R[20] = { +0x9f08,0x988e,0x4fc3,0x3f68, +0x290f,0x59f9,0x0792,0xbfe2, +0x3e6a,0xbaf3,0xdff5,0x401b, +0xab68,0xac01,0x91aa,0xc039, +0x081d,0x40f3,0x8962,0x403c, +}; +static short S[16] = { +/* 0x0000,0x0000,0x0000,0x3ff0, */ +0x5d8c,0xb6bf,0xf2a2,0xc035, +0x7f42,0xaf6a,0x6219,0x4062, +0x63ee,0x9590,0xfe08,0xc077, +0x44be,0xb0b6,0x6709,0x4075, +}; +#endif +#if MIEEE +static short R[20] = { +0x3f68,0x4fc3,0x988e,0x9f08, +0xbfe2,0x0792,0x59f9,0x290f, +0x401b,0xdff5,0xbaf3,0x3e6a, +0xc039,0x91aa,0xac01,0xab68, +0x403c,0x8962,0x40f3,0x081d, +}; +static short S[16] = { +/* 0x3ff0,0x0000,0x0000,0x0000, */ +0xc035,0xf2a2,0xb6bf,0x5d8c, +0x4062,0x6219,0xaf6a,0x7f42, +0xc077,0xfe08,0x9590,0x63ee, +0x4075,0x6709,0xb0b6,0x44be, +}; +#endif + +/* pi/2 = PIO2 + MOREBITS. */ +#ifdef DEC +#define MOREBITS 5.721188726109831840122E-18 +#else +#define MOREBITS 6.123233995736765886130E-17 +#endif + +#ifdef ANSIPROT +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern double sqrt ( double ); +double asin ( double ); +#else +double sqrt(), polevl(), p1evl(); +double asin(); +#endif +extern double PIO2, PIO4, NAN; + +double asin(x) +double x; +{ +double a, p, z, zz; +short sign; + +if( x > 0 ) + { + sign = 1; + a = x; + } +else + { + sign = -1; + a = -x; + } + +if( a > 1.0 ) + { + mtherr( "asin", DOMAIN ); + return( NAN ); + } + +if( a > 0.625 ) + { + /* arcsin(1-x) = pi/2 - sqrt(2x)(1+R(x)) */ + zz = 1.0 - a; + p = zz * polevl( zz, R, 4)/p1evl( zz, S, 4); + zz = sqrt(zz+zz); + z = PIO4 - zz; + zz = zz * p - MOREBITS; + z = z - zz; + z = z + PIO4; + } +else + { + if( a < 1.0e-8 ) + { + return(x); + } + zz = a * a; + z = zz * polevl( zz, P, 5)/p1evl( zz, Q, 5); + z = a * z + a; + } +if( sign < 0 ) + z = -z; +return(z); +} + + + +double acos(x) +double x; +{ +double z; + +if( (x < -1.0) || (x > 1.0) ) + { + mtherr( "acos", DOMAIN ); + return( NAN ); + } +if( x > 0.5 ) + { + return( 2.0 * asin( sqrt(0.5 - 0.5*x) ) ); + } +z = PIO4 - asin(x); +z = z + MOREBITS; +z = z + PIO4; +return( z ); +} diff --git a/components/external/espruino/libs/math/asinh.c b/components/external/espruino/libs/math/asinh.c new file mode 100644 index 0000000000..e0caecab70 --- /dev/null +++ b/components/external/espruino/libs/math/asinh.c @@ -0,0 +1,165 @@ +/* asinh.c + * + * Inverse hyperbolic sine + * + * + * + * SYNOPSIS: + * + * double x, y, asinh(); + * + * y = asinh( x ); + * + * + * + * DESCRIPTION: + * + * Returns inverse hyperbolic sine of argument. + * + * If |x| < 0.5, the function is approximated by a rational + * form x + x**3 P(x)/Q(x). Otherwise, + * + * asinh(x) = log( x + sqrt(1 + x*x) ). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -3,3 75000 4.6e-17 1.1e-17 + * IEEE -1,1 30000 3.7e-16 7.8e-17 + * IEEE 1,3 30000 2.5e-16 6.7e-17 + * + */ + +/* asinh.c */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + + +#include "mconf.h" + +#ifdef UNK +const static double P[] = { +-4.33231683752342103572E-3, +-5.91750212056387121207E-1, +-4.37390226194356683570E0, +-9.09030533308377316566E0, +-5.56682227230859640450E0 +}; +const static double Q[] = { +/* 1.00000000000000000000E0,*/ + 1.28757002067426453537E1, + 4.86042483805291788324E1, + 6.95722521337257608734E1, + 3.34009336338516356383E1 +}; +#endif + +#ifdef DEC +static unsigned short P[] = { +0136215,0173033,0110410,0105475, +0140027,0076361,0020056,0164520, +0140613,0173401,0160136,0053142, +0141021,0070744,0000503,0176261, +0140662,0021550,0073106,0133351 +}; +static unsigned short Q[] = { +/* 0040200,0000000,0000000,0000000,*/ +0041116,0001336,0034120,0173054, +0041502,0065300,0013144,0021231, +0041613,0022376,0035516,0153063, +0041405,0115216,0054265,0004557 +}; +#endif + +#ifdef IBMPC +static unsigned short P[] = { +0x1168,0x7221,0xbec3,0xbf71, +0xdd2a,0x2405,0xef9e,0xbfe2, +0xcacc,0x3c0b,0x7ee0,0xc011, +0x7f96,0x8028,0x2e3c,0xc022, +0xd6dd,0x0ec8,0x446d,0xc016 +}; +static unsigned short Q[] = { +/* 0x0000,0x0000,0x0000,0x3ff0,*/ +0x1ec5,0xc70a,0xc05b,0x4029, +0x8453,0x02cc,0x4d58,0x4048, +0xdac6,0xc769,0x649f,0x4051, +0xa12e,0xcb16,0xb351,0x4040 +}; +#endif + +#ifdef MIEEE +static unsigned short P[] = { +0xbf71,0xbec3,0x7221,0x1168, +0xbfe2,0xef9e,0x2405,0xdd2a, +0xc011,0x7ee0,0x3c0b,0xcacc, +0xc022,0x2e3c,0x8028,0x7f96, +0xc016,0x446d,0x0ec8,0xd6dd +}; +static unsigned short Q[] = { +0x4029,0xc05b,0xc70a,0x1ec5, +0x4048,0x4d58,0x02cc,0x8453, +0x4051,0x649f,0xc769,0xdac6, +0x4040,0xb351,0xcb16,0xa12e +}; +#endif + +#ifdef ANSIPROT +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern double sqrt ( double ); +extern double log ( double ); +#else +double log(), sqrt(), polevl(), p1evl(); +#endif +extern double LOGE2, INFINITY; + +double asinh(xx) +double xx; +{ +double a, z, x; +int sign; + +#ifdef MINUSZERO +if( xx == 0.0 ) + return(xx); +#endif +if( xx < 0.0 ) + { + sign = -1; + x = -xx; + } +else + { + sign = 1; + x = xx; + } + +if( x > 1.0e8 ) + { +#ifdef INFINITIES + if( x == INFINITY ) + return(xx); +#endif + return( sign * (log(x) + LOGE2) ); + } + +z = x * x; +if( x < 0.5 ) + { + a = ( polevl(z, P, 4)/p1evl(z, Q, 4) ) * z; + a = a * x + x; + if( sign < 0 ) + a = -a; + return(a); + } + +a = sqrt( z + 1.0 ); +return( sign * log(x + a) ); +} diff --git a/components/external/espruino/libs/math/atan.c b/components/external/espruino/libs/math/atan.c new file mode 100644 index 0000000000..4d5a5db4a6 --- /dev/null +++ b/components/external/espruino/libs/math/atan.c @@ -0,0 +1,393 @@ +/* atan.c + * + * Inverse circular tangent + * (arctangent) + * + * + * + * SYNOPSIS: + * + * double x, y, atan(); + * + * y = atan( x ); + * + * + * + * DESCRIPTION: + * + * Returns radian angle between -pi/2 and +pi/2 whose tangent + * is x. + * + * Range reduction is from three intervals into the interval + * from zero to 0.66. The approximant uses a rational + * function of degree 4/5 of the form x + x**3 P(x)/Q(x). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10, 10 50000 2.4e-17 8.3e-18 + * IEEE -10, 10 10^6 1.8e-16 5.0e-17 + * + */ + /* atan2() + * + * Quadrant correct inverse circular tangent + * + * + * + * SYNOPSIS: + * + * double x, y, z, atan2(); + * + * z = atan2( y, x ); + * + * + * + * DESCRIPTION: + * + * Returns radian angle whose tangent is y/x. + * Define compile time symbol ANSIC = 1 for ANSI standard, + * range -PI < z <= +PI, args (y,x); else ANSIC = 0 for range + * 0 to 2PI, args (x,y). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10, 10 10^6 2.5e-16 6.9e-17 + * See atan.c. + * + */ + +/* atan.c */ + + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + + +#include "mconf.h" + +/* arctan(x) = x + x^3 P(x^2)/Q(x^2) + 0 <= x <= 0.66 + Peak relative error = 2.6e-18 */ +#ifdef UNK +const static double P[5] = { +-8.750608600031904122785E-1, +-1.615753718733365076637E1, +-7.500855792314704667340E1, +-1.228866684490136173410E2, +-6.485021904942025371773E1, +}; +const static double Q[5] = { +/* 1.000000000000000000000E0, */ + 2.485846490142306297962E1, + 1.650270098316988542046E2, + 4.328810604912902668951E2, + 4.853903996359136964868E2, + 1.945506571482613964425E2, +}; + +/* tan( 3*pi/8 ) */ +const static double T3P8 = 2.41421356237309504880; +#endif + +#ifdef DEC +static short P[20] = { +0140140,0001775,0007671,0026242, +0141201,0041242,0155534,0001715, +0141626,0002141,0132100,0011625, +0141765,0142771,0064055,0150453, +0141601,0131517,0164507,0062164, +}; +static short Q[20] = { +/* 0040200,0000000,0000000,0000000, */ +0041306,0157042,0154243,0000742, +0042045,0003352,0016707,0150452, +0042330,0070306,0113425,0170730, +0042362,0130770,0116602,0047520, +0042102,0106367,0156753,0013541, +}; + +/* tan( 3*pi/8 ) = 2.41421356237309504880 */ +static unsigned short T3P8A[] = {040432,0101171,0114774,0167462,}; +#define T3P8 *(double *)T3P8A +#endif + +#ifdef IBMPC +static short P[20] = { +0x2594,0xa1f7,0x007f,0xbfec, +0x807a,0x5b6b,0x2854,0xc030, +0x0273,0x3688,0xc08c,0xc052, +0xba25,0x2d05,0xb8bf,0xc05e, +0xec8e,0xfd28,0x3669,0xc050, +}; +static short Q[20] = { +/* 0x0000,0x0000,0x0000,0x3ff0, */ +0x603c,0x5b14,0xdbc4,0x4038, +0xfa25,0x43b8,0xa0dd,0x4064, +0xbe3b,0xd2e2,0x0e18,0x407b, +0x49ea,0x13b0,0x563f,0x407e, +0x62ec,0xfbbd,0x519e,0x4068, +}; + +/* tan( 3*pi/8 ) = 2.41421356237309504880 */ +static unsigned short T3P8A[] = {0x9de6,0x333f,0x504f,0x4003}; +#define T3P8 *(double *)T3P8A +#endif + +#ifdef MIEEE +static short P[20] = { +0xbfec,0x007f,0xa1f7,0x2594, +0xc030,0x2854,0x5b6b,0x807a, +0xc052,0xc08c,0x3688,0x0273, +0xc05e,0xb8bf,0x2d05,0xba25, +0xc050,0x3669,0xfd28,0xec8e, +}; +static short Q[20] = { +/* 0x3ff0,0x0000,0x0000,0x0000, */ +0x4038,0xdbc4,0x5b14,0x603c, +0x4064,0xa0dd,0x43b8,0xfa25, +0x407b,0x0e18,0xd2e2,0xbe3b, +0x407e,0x563f,0x13b0,0x49ea, +0x4068,0x519e,0xfbbd,0x62ec, +}; + +/* tan( 3*pi/8 ) = 2.41421356237309504880 */ +static unsigned short T3P8A[] = { +0x4003,0x504f,0x333f,0x9de6 +}; +#define T3P8 *(double *)T3P8A +#endif + +#ifdef ANSIPROT +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern double atan ( double ); +extern double fabs ( double ); +extern int signbit ( double ); +extern int isnan ( double ); +#else +double polevl(), p1evl(), atan(), fabs(); +int signbit(), isnan(); +#endif +extern double PI, PIO2, PIO4, INFINITY, NEGZERO, MAXNUM; + +/* pi/2 = PIO2 + MOREBITS. */ +#ifdef DEC +#define MOREBITS 5.721188726109831840122E-18 +#else +#define MOREBITS 6.123233995736765886130E-17 +#endif + + +double atan(x) +double x; +{ +double y, z; +short sign, flag; + +#ifdef MINUSZERO +if( x == 0.0 ) + return(x); +#endif +#ifdef INFINITIES +if(x == INFINITY) + return(PIO2); +if(x == -INFINITY) + return(-PIO2); +#endif +/* make argument positive and save the sign */ +sign = 1; +if( x < 0.0 ) + { + sign = -1; + x = -x; + } +/* range reduction */ +flag = 0; +if( x > T3P8 ) + { + y = PIO2; + flag = 1; + x = -( 1.0/x ); + } +else if( x <= 0.66 ) + { + y = 0.0; + } +else + { + y = PIO4; + flag = 2; + x = (x-1.0)/(x+1.0); + } +z = x * x; +z = z * polevl( z, P, 4 ) / p1evl( z, Q, 5 ); +z = x * z + x; +if( flag == 2 ) + z += 0.5 * MOREBITS; +else if( flag == 1 ) + z += MOREBITS; +y = y + z; +if( sign < 0 ) + y = -y; +return(y); +} + +/* atan2 */ + +#ifdef ANSIC +double atan2( y, x ) +#else +double atan2( x, y ) +#endif +double x, y; +{ +double z, w; +short code; + +code = 0; + +#ifdef NANS +if( isnan(x) ) + return(x); +if( isnan(y) ) + return(y); +#endif +#ifdef MINUSZERO +if( y == 0.0 ) + { + if( signbit(y) ) + { + if( x > 0.0 ) + z = y; + else if( x < 0.0 ) + z = -PI; + else + { + if( signbit(x) ) + z = -PI; + else + z = y; + } + } + else /* y is +0 */ + { + if( x == 0.0 ) + { + if( signbit(x) ) + z = PI; + else + z = 0.0; + } + else if( x > 0.0 ) + z = 0.0; + else + z = PI; + } + return z; + } +if( x == 0.0 ) + { + if( y > 0.0 ) + z = PIO2; + else + z = -PIO2; + return z; + } +#endif /* MINUSZERO */ +#ifdef INFINITIES +if( x == INFINITY ) + { + if( y == INFINITY ) + z = 0.25 * PI; + else if( y == -INFINITY ) + z = -0.25 * PI; + else if( y < 0.0 ) + z = NEGZERO; + else + z = 0.0; + return z; + } +if( x == -INFINITY ) + { + if( y == INFINITY ) + z = 0.75 * PI; + else if( y <= -INFINITY ) + z = -0.75 * PI; + else if( y >= 0.0 ) + z = PI; + else + z = -PI; + return z; + } +if( y == INFINITY ) + return( PIO2 ); +if( y == -INFINITY ) + return( -PIO2 ); +#endif + +if( x < 0.0 ) + code = 2; +if( y < 0.0 ) + code |= 1; + +#ifdef INFINITIES +if( x == 0.0 ) +#else +if( fabs(x) <= (fabs(y) / MAXNUM) ) +#endif + { + if( code & 1 ) + { +#if ANSIC + return( -PIO2 ); +#else + return( 3.0*PIO2 ); +#endif + } + if( y == 0.0 ) + return( 0.0 ); + return( PIO2 ); + } + +if( y == 0.0 ) + { + if( code & 2 ) + return( PI ); + return( 0.0 ); + } + + +switch( code ) + { +#if ANSIC + default: + case 0: + case 1: w = 0.0; break; + case 2: w = PI; break; + case 3: w = -PI; break; +#else + default: + case 0: w = 0.0; break; + case 1: w = 2.0 * PI; break; + case 2: + case 3: w = PI; break; +#endif + } + +z = w + atan( y/x ); +#ifdef MINUSZERO +if( z == 0.0 && y < 0 ) + z = NEGZERO; +#endif +return( z ); +} diff --git a/components/external/espruino/libs/math/atanh.c b/components/external/espruino/libs/math/atanh.c new file mode 100644 index 0000000000..9b0cf4c266 --- /dev/null +++ b/components/external/espruino/libs/math/atanh.c @@ -0,0 +1,156 @@ +/* atanh.c + * + * Inverse hyperbolic tangent + * + * + * + * SYNOPSIS: + * + * double x, y, atanh(); + * + * y = atanh( x ); + * + * + * + * DESCRIPTION: + * + * Returns inverse hyperbolic tangent of argument in the range + * MINLOG to MAXLOG. + * + * If |x| < 0.5, the rational form x + x**3 P(x)/Q(x) is + * employed. Otherwise, + * atanh(x) = 0.5 * log( (1+x)/(1-x) ). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -1,1 50000 2.4e-17 6.4e-18 + * IEEE -1,1 30000 1.9e-16 5.2e-17 + * + */ + +/* atanh.c */ + + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright (C) 1987, 1995, 2000 by Stephen L. Moshier +*/ + +#include "mconf.h" + +#ifdef UNK +const static double P[] = { +-8.54074331929669305196E-1, + 1.20426861384072379242E1, +-4.61252884198732692637E1, + 6.54566728676544377376E1, +-3.09092539379866942570E1 +}; +const static double Q[] = { +/* 1.00000000000000000000E0,*/ +-1.95638849376911654834E1, + 1.08938092147140262656E2, +-2.49839401325893582852E2, + 2.52006675691344555838E2, +-9.27277618139601130017E1 +}; +#endif +#ifdef DEC +static unsigned short P[] = { +0140132,0122235,0105775,0130300, +0041100,0127327,0124407,0034722, +0141470,0100113,0115607,0130535, +0041602,0164721,0003257,0013673, +0141367,0043046,0166673,0045750 +}; +static unsigned short Q[] = { +/*0040200,0000000,0000000,0000000,*/ +0141234,0101326,0015460,0134564, +0041731,0160115,0116451,0032045, +0142171,0153343,0000532,0167226, +0042174,0000665,0077604,0000310, +0141671,0072235,0031114,0074377 +}; +#endif + +#ifdef IBMPC +static unsigned short P[] = { +0xb618,0xb17f,0x5493,0xbfeb, +0xe73a,0xf520,0x15da,0x4028, +0xf62c,0x7370,0x1009,0xc047, +0xe2f7,0x20d5,0x5d3a,0x4050, +0x697d,0xddb7,0xe8c4,0xc03e +}; +static unsigned short Q[] = { +/*0x0000,0x0000,0x0000,0x3ff0,*/ +0x172f,0xc366,0x905a,0xc033, +0x2685,0xb3a5,0x3c09,0x405b, +0x5dd3,0x602b,0x3adc,0xc06f, +0x8019,0xaff0,0x8036,0x406f, +0x8f20,0xa649,0x2e93,0xc057 +}; +#endif + +#ifdef MIEEE +static unsigned short P[] = { +0xbfeb,0x5493,0xb17f,0xb618, +0x4028,0x15da,0xf520,0xe73a, +0xc047,0x1009,0x7370,0xf62c, +0x4050,0x5d3a,0x20d5,0xe2f7, +0xc03e,0xe8c4,0xddb7,0x697d +}; +static unsigned short Q[] = { +0xc033,0x905a,0xc366,0x172f, +0x405b,0x3c09,0xb3a5,0x2685, +0xc06f,0x3adc,0x602b,0x5dd3, +0x406f,0x8036,0xaff0,0x8019, +0xc057,0x2e93,0xa649,0x8f20 +}; +#endif + +#ifdef ANSIPROT +extern double fabs ( double ); +extern double log ( double x ); +extern double polevl ( double x, void *P, int N ); +extern double p1evl ( double x, void *P, int N ); +#else +double fabs(), log(), polevl(), p1evl(); +#endif +extern double INFINITY, NAN; + +double atanh(x) +double x; +{ +double s, z; + +#ifdef MINUSZERO +if( x == 0.0 ) + return(x); +#endif +z = fabs(x); +if( z >= 1.0 ) + { + if( x == 1.0 ) + return( INFINITY ); + if( x == -1.0 ) + return( -INFINITY ); + mtherr( "atanh", DOMAIN ); + return( NAN ); + } + +if( z < 1.0e-7 ) + return(x); + +if( z < 0.5 ) + { + z = x * x; + s = x + x * z * (polevl(z, P, 4) / p1evl(z, Q, 5)); + return(s); + } + +return( 0.5 * log((1.0+x)/(1.0-x)) ); +} diff --git a/components/external/espruino/libs/math/cbrt.c b/components/external/espruino/libs/math/cbrt.c new file mode 100644 index 0000000000..82c02e6862 --- /dev/null +++ b/components/external/espruino/libs/math/cbrt.c @@ -0,0 +1,142 @@ +/* cbrt.c + * + * Cube root + * + * + * + * SYNOPSIS: + * + * double x, y, cbrt(); + * + * y = cbrt( x ); + * + * + * + * DESCRIPTION: + * + * Returns the cube root of the argument, which may be negative. + * + * Range reduction involves determining the power of 2 of + * the argument. A polynomial of degree 2 applied to the + * mantissa, and multiplication by the cube root of 1, 2, or 4 + * approximates the root to within about 0.1%. Then Newton's + * iteration is used three times to converge to an accurate + * result. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,10 200000 1.8e-17 6.2e-18 + * IEEE 0,1e308 30000 1.5e-16 5.0e-17 + * + */ + /* cbrt.c */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1991, 2000 by Stephen L. Moshier +*/ + + +#include "mconf.h" + +const static double CBRT2 = 1.2599210498948731647672; +const static double CBRT4 = 1.5874010519681994747517; +const static double CBRT2I = 0.79370052598409973737585; +const static double CBRT4I = 0.62996052494743658238361; + +#ifdef ANSIPROT +extern double frexp ( double, int * ); +extern double ldexp ( double, int ); +extern int isnan ( double ); +extern int isfinite ( double ); +#else +double frexp(), ldexp(); +int isnan(), isfinite(); +#endif + +double cbrt(x) +double x; +{ +int e, rem, sign; +double z; + +#ifdef NANS +if( isnan(x) ) + return x; +#endif +#ifdef INFINITIES +if( !isfinite(x) ) + return x; +#endif +if( x == 0 ) + return( x ); +if( x > 0 ) + sign = 1; +else + { + sign = -1; + x = -x; + } + +z = x; +/* extract power of 2, leaving + * mantissa between 0.5 and 1 + */ +x = frexp( x, &e ); + +/* Approximate cube root of number between .5 and 1, + * peak relative error = 9.2e-6 + */ +x = (((-1.3466110473359520655053e-1 * x + + 5.4664601366395524503440e-1) * x + - 9.5438224771509446525043e-1) * x + + 1.1399983354717293273738e0 ) * x + + 4.0238979564544752126924e-1; + +/* exponent divided by 3 */ +if( e >= 0 ) + { + rem = e; + e /= 3; + rem -= 3*e; + if( rem == 1 ) + x *= CBRT2; + else if( rem == 2 ) + x *= CBRT4; + } + + +/* argument less than 1 */ + +else + { + e = -e; + rem = e; + e /= 3; + rem -= 3*e; + if( rem == 1 ) + x *= CBRT2I; + else if( rem == 2 ) + x *= CBRT4I; + e = -e; + } + +/* multiply by power of 2 */ +x = ldexp( x, e ); + +/* Newton iteration */ +x -= ( x - (z/(x*x)) )*0.33333333333333333333; +#ifdef DEC +x -= ( x - (z/(x*x)) )/3.0; +#else +x -= ( x - (z/(x*x)) )*0.33333333333333333333; +#endif + +if( sign < 0 ) + x = -x; +return(x); +} diff --git a/components/external/espruino/libs/math/chbevl.c b/components/external/espruino/libs/math/chbevl.c new file mode 100644 index 0000000000..5393881649 --- /dev/null +++ b/components/external/espruino/libs/math/chbevl.c @@ -0,0 +1,82 @@ +/* chbevl.c + * + * Evaluate Chebyshev series + * + * + * + * SYNOPSIS: + * + * int N; + * double x, y, coef[N], chebevl(); + * + * y = chbevl( x, coef, N ); + * + * + * + * DESCRIPTION: + * + * Evaluates the series + * + * N-1 + * - ' + * y = > coef[i] T (x/2) + * - i + * i=0 + * + * of Chebyshev polynomials Ti at argument x/2. + * + * Coefficients are stored in reverse order, i.e. the zero + * order term is last in the array. Note N is the number of + * coefficients, not the order. + * + * If coefficients are for the interval a to b, x must + * have been transformed to x -> 2(2x - b - a)/(b-a) before + * entering the routine. This maps x from (a, b) to (-1, 1), + * over which the Chebyshev polynomials are defined. + * + * If the coefficients are for the inverted interval, in + * which (a, b) is mapped to (1/b, 1/a), the transformation + * required is x -> 2(2ab/x - b - a)/(b-a). If b is infinity, + * this becomes x -> 4a/x - 1. + * + * + * + * SPEED: + * + * Taking advantage of the recurrence properties of the + * Chebyshev polynomials, the routine requires one more + * addition per loop than evaluating a nested polynomial of + * the same degree. + * + */ + /* chbevl.c */ + +/* +Cephes Math Library Release 2.0: April, 1987 +Copyright 1985, 1987 by Stephen L. Moshier +Direct inquiries to 30 Frost Street, Cambridge, MA 02140 +*/ + +double chbevl( x, array, n ) +double x; +double array[]; +int n; +{ +double b0, b1, b2, *p; +int i; + +p = array; +b0 = *p++; +b1 = 0.0; +i = n - 1; + +do + { + b2 = b1; + b1 = b0; + b0 = x * b1 - b2 + *p++; + } +while( --i ); + +return( 0.5*(b0-b2) ); +} diff --git a/components/external/espruino/libs/math/clog.c b/components/external/espruino/libs/math/clog.c new file mode 100644 index 0000000000..1f5e77611d --- /dev/null +++ b/components/external/espruino/libs/math/clog.c @@ -0,0 +1,1043 @@ +/* clog.c + * + * Complex natural logarithm + * + * + * + * SYNOPSIS: + * + * void clog(); + * cmplx z, w; + * + * clog( &z, &w ); + * + * + * + * DESCRIPTION: + * + * Returns complex logarithm to the base e (2.718...) of + * the complex argument x. + * + * If z = x + iy, r = sqrt( x**2 + y**2 ), + * then + * w = log(r) + i arctan(y/x). + * + * The arctangent ranges from -PI to +PI. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 7000 8.5e-17 1.9e-17 + * IEEE -10,+10 30000 5.0e-15 1.1e-16 + * + * Larger relative error can be observed for z near 1 +i0. + * In IEEE arithmetic the peak absolute error is 5.2e-16, rms + * absolute error 1.0e-16. + */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ +#include "mconf.h" +#ifdef ANSIPROT +static void cchsh ( double x, double *c, double *s ); +const static double redupi ( double x ); +const static double ctans ( cmplx *z ); +/* These are supposed to be in some standard place. */ +double fabs (double); +double sqrt (double); +double pow (double, double); +double log (double); +double exp (double); +double atan2 (double, double); +double cosh (double); +double sinh (double); +double asin (double); +double sin (double); +double cos (double); +double cabs (cmplx *); +void cadd ( cmplx *, cmplx *, cmplx * ); +void cmul ( cmplx *, cmplx *, cmplx * ); +void csqrt ( cmplx *, cmplx * ); +static void cchsh ( double, double *, double * ); +const static double redupi ( double ); +const static double ctans ( cmplx * ); +void clog ( cmplx *, cmplx * ); +void casin ( cmplx *, cmplx * ); +void cacos ( cmplx *, cmplx * ); +void catan ( cmplx *, cmplx * ); +#else +static void cchsh(); +const static double redupi(); +const static double ctans(); +double cabs(), fabs(), sqrt(), pow(); +double log(), exp(), atan2(), cosh(), sinh(); +double asin(), sin(), cos(); +void cadd(), cmul(), csqrt(); +void clog(), casin(), cacos(), catan(); +#endif + + +extern double MAXNUM, MACHEP, PI, PIO2; + +void clog( z, w ) +register cmplx *z, *w; +{ +double p, rr; + +/*rr = sqrt( z->r * z->r + z->i * z->i );*/ +rr = cabs(z); +p = log(rr); +#if ANSIC +rr = atan2( z->i, z->r ); +#else +rr = atan2( z->r, z->i ); +if( rr > PI ) + rr -= PI + PI; +#endif +w->i = rr; +w->r = p; +} + /* cexp() + * + * Complex exponential function + * + * + * + * SYNOPSIS: + * + * void cexp(); + * cmplx z, w; + * + * cexp( &z, &w ); + * + * + * + * DESCRIPTION: + * + * Returns the exponential of the complex argument z + * into the complex result w. + * + * If + * z = x + iy, + * r = exp(x), + * + * then + * + * w = r cos y + i r sin y. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 8700 3.7e-17 1.1e-17 + * IEEE -10,+10 30000 3.0e-16 8.7e-17 + * + */ + +void cexp( z, w ) +register cmplx *z, *w; +{ +double r; + +r = exp( z->r ); +w->r = r * cos( z->i ); +w->i = r * sin( z->i ); +} + /* csin() + * + * Complex circular sine + * + * + * + * SYNOPSIS: + * + * void csin(); + * cmplx z, w; + * + * csin( &z, &w ); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * + * w = sin x cosh y + i cos x sinh y. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 8400 5.3e-17 1.3e-17 + * IEEE -10,+10 30000 3.8e-16 1.0e-16 + * Also tested by csin(casin(z)) = z. + * + */ + +void csin( z, w ) +register cmplx *z, *w; +{ +double ch, sh; + +cchsh( z->i, &ch, &sh ); +w->r = sin( z->r ) * ch; +w->i = cos( z->r ) * sh; +} + + + +/* calculate cosh and sinh */ + +static void cchsh( x, c, s ) +double x, *c, *s; +{ +double e, ei; + +if( fabs(x) <= 0.5 ) + { + *c = cosh(x); + *s = sinh(x); + } +else + { + e = exp(x); + ei = 0.5/e; + e = 0.5 * e; + *s = e - ei; + *c = e + ei; + } +} + + /* ccos() + * + * Complex circular cosine + * + * + * + * SYNOPSIS: + * + * void ccos(); + * cmplx z, w; + * + * ccos( &z, &w ); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * + * w = cos x cosh y - i sin x sinh y. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 8400 4.5e-17 1.3e-17 + * IEEE -10,+10 30000 3.8e-16 1.0e-16 + */ + +void ccos( z, w ) +register cmplx *z, *w; +{ +double ch, sh; + +cchsh( z->i, &ch, &sh ); +w->r = cos( z->r ) * ch; +w->i = -sin( z->r ) * sh; +} + /* ctan() + * + * Complex circular tangent + * + * + * + * SYNOPSIS: + * + * void ctan(); + * cmplx z, w; + * + * ctan( &z, &w ); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * + * sin 2x + i sinh 2y + * w = --------------------. + * cos 2x + cosh 2y + * + * On the real axis the denominator is zero at odd multiples + * of PI/2. The denominator is evaluated by its Taylor + * series near these points. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 5200 7.1e-17 1.6e-17 + * IEEE -10,+10 30000 7.2e-16 1.2e-16 + * Also tested by ctan * ccot = 1 and catan(ctan(z)) = z. + */ + +void ctan( z, w ) +register cmplx *z, *w; +{ +double d; + +d = cos( 2.0 * z->r ) + cosh( 2.0 * z->i ); + +if( fabs(d) < 0.25 ) + d = ctans(z); + +if( d == 0.0 ) + { + mtherr( "ctan", OVERFLOW ); + w->r = MAXNUM; + w->i = MAXNUM; + return; + } + +w->r = sin( 2.0 * z->r ) / d; +w->i = sinh( 2.0 * z->i ) / d; +} + /* ccot() + * + * Complex circular cotangent + * + * + * + * SYNOPSIS: + * + * void ccot(); + * cmplx z, w; + * + * ccot( &z, &w ); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * + * sin 2x - i sinh 2y + * w = --------------------. + * cosh 2y - cos 2x + * + * On the real axis, the denominator has zeros at even + * multiples of PI/2. Near these points it is evaluated + * by a Taylor series. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 3000 6.5e-17 1.6e-17 + * IEEE -10,+10 30000 9.2e-16 1.2e-16 + * Also tested by ctan * ccot = 1 + i0. + */ + +void ccot( z, w ) +register cmplx *z, *w; +{ +double d; + +d = cosh(2.0 * z->i) - cos(2.0 * z->r); + +if( fabs(d) < 0.25 ) + d = ctans(z); + +if( d == 0.0 ) + { + mtherr( "ccot", OVERFLOW ); + w->r = MAXNUM; + w->i = MAXNUM; + return; + } + +w->r = sin( 2.0 * z->r ) / d; +w->i = -sinh( 2.0 * z->i ) / d; +} + +/* Program to subtract nearest integer multiple of PI */ +/* extended precision value of PI: */ +#ifdef UNK +const static double DP1 = 3.14159265160560607910E0; +const static double DP2 = 1.98418714791870343106E-9; +const static double DP3 = 1.14423774522196636802E-17; +#endif + +#ifdef DEC +static unsigned short P1[] = {0040511,0007732,0120000,0000000,}; +static unsigned short P2[] = {0031010,0055060,0100000,0000000,}; +static unsigned short P3[] = {0022123,0011431,0105056,0001560,}; +#define DP1 *(double *)P1 +#define DP2 *(double *)P2 +#define DP3 *(double *)P3 +#endif + +#ifdef IBMPC +static unsigned short P1[] = {0x0000,0x5400,0x21fb,0x4009}; +static unsigned short P2[] = {0x0000,0x1000,0x0b46,0x3e21}; +static unsigned short P3[] = {0xc06e,0x3145,0x6263,0x3c6a}; +#define DP1 *(double *)P1 +#define DP2 *(double *)P2 +#define DP3 *(double *)P3 +#endif + +#ifdef MIEEE +static unsigned short P1[] = { +0x4009,0x21fb,0x5400,0x0000 +}; +static unsigned short P2[] = { +0x3e21,0x0b46,0x1000,0x0000 +}; +static unsigned short P3[] = { +0x3c6a,0x6263,0x3145,0xc06e +}; +#define DP1 *(double *)P1 +#define DP2 *(double *)P2 +#define DP3 *(double *)P3 +#endif + +const static double redupi(x) +double x; +{ +double t; +long i; + +t = x/PI; +if( t >= 0.0 ) + t += 0.5; +else + t -= 0.5; + +i = t; /* the multiple */ +t = i; +t = ((x - t * DP1) - t * DP2) - t * DP3; +return(t); +} + +/* Taylor series expansion for cosh(2y) - cos(2x) */ + +const static double ctans(z) +cmplx *z; +{ +double f, x, x2, y, y2, rn, t; +double d; + +x = fabs( 2.0 * z->r ); +y = fabs( 2.0 * z->i ); + +x = redupi(x); + +x = x * x; +y = y * y; +x2 = 1.0; +y2 = 1.0; +f = 1.0; +rn = 0.0; +d = 0.0; +do + { + rn += 1.0; + f *= rn; + rn += 1.0; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 + x2; + t /= f; + d += t; + + rn += 1.0; + f *= rn; + rn += 1.0; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 - x2; + t /= f; + d += t; + } +while( fabs(t/d) > MACHEP ); +return(d); +} + /* casin() + * + * Complex circular arc sine + * + * + * + * SYNOPSIS: + * + * void casin(); + * cmplx z, w; + * + * casin( &z, &w ); + * + * + * + * DESCRIPTION: + * + * Inverse complex sine: + * + * 2 + * w = -i clog( iz + csqrt( 1 - z ) ). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 10100 2.1e-15 3.4e-16 + * IEEE -10,+10 30000 2.2e-14 2.7e-15 + * Larger relative error can be observed for z near zero. + * Also tested by csin(casin(z)) = z. + */ + +void casin( z, w ) +cmplx *z, *w; +{ +static cmplx ca, ct, zz, z2; +double x, y; + +x = z->r; +y = z->i; + +if( y == 0.0 ) + { + if( fabs(x) > 1.0 ) + { + w->r = PIO2; + w->i = 0.0; + mtherr( "casin", DOMAIN ); + } + else + { + w->r = asin(x); + w->i = 0.0; + } + return; + } + +/* Power series expansion */ +/* +b = cabs(z); +if( b < 0.125 ) +{ +z2.r = (x - y) * (x + y); +z2.i = 2.0 * x * y; + +cn = 1.0; +n = 1.0; +ca.r = x; +ca.i = y; +sum.r = x; +sum.i = y; +do + { + ct.r = z2.r * ca.r - z2.i * ca.i; + ct.i = z2.r * ca.i + z2.i * ca.r; + ca.r = ct.r; + ca.i = ct.i; + + cn *= n; + n += 1.0; + cn /= n; + n += 1.0; + b = cn/n; + + ct.r *= b; + ct.i *= b; + sum.r += ct.r; + sum.i += ct.i; + b = fabs(ct.r) + fabs(ct.i); + } +while( b > MACHEP ); +w->r = sum.r; +w->i = sum.i; +return; +} +*/ + + +ca.r = x; +ca.i = y; + +ct.r = -ca.i; /* iz */ +ct.i = ca.r; + + /* sqrt( 1 - z*z) */ +/* cmul( &ca, &ca, &zz ) */ +zz.r = (ca.r - ca.i) * (ca.r + ca.i); /*x * x - y * y */ +zz.i = 2.0 * ca.r * ca.i; + +zz.r = 1.0 - zz.r; +zz.i = -zz.i; +csqrt( &zz, &z2 ); + +cadd( &z2, &ct, &zz ); +clog( &zz, &zz ); +w->r = zz.i; /* mult by 1/i = -i */ +w->i = -zz.r; +return; +} + /* cacos() + * + * Complex circular arc cosine + * + * + * + * SYNOPSIS: + * + * void cacos(); + * cmplx z, w; + * + * cacos( &z, &w ); + * + * + * + * DESCRIPTION: + * + * + * w = arccos z = PI/2 - arcsin z. + * + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 5200 1.6e-15 2.8e-16 + * IEEE -10,+10 30000 1.8e-14 2.2e-15 + */ + +void cacos( z, w ) +cmplx *z, *w; +{ + +casin( z, w ); +w->r = PIO2 - w->r; +w->i = -w->i; +} + /* catan() + * + * Complex circular arc tangent + * + * + * + * SYNOPSIS: + * + * void catan(); + * cmplx z, w; + * + * catan( &z, &w ); + * + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * 1 ( 2x ) + * Re w = - arctan(-----------) + k PI + * 2 ( 2 2) + * (1 - x - y ) + * + * ( 2 2) + * 1 (x + (y+1) ) + * Im w = - log(------------) + * 4 ( 2 2) + * (x + (y-1) ) + * + * Where k is an arbitrary integer. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 5900 1.3e-16 7.8e-18 + * IEEE -10,+10 30000 2.3e-15 8.5e-17 + * The check catan( ctan(z) ) = z, with |x| and |y| < PI/2, + * had peak relative error 1.5e-16, rms relative error + * 2.9e-17. See also clog(). + */ + +void catan( z, w ) +cmplx *z, *w; +{ +double a, t, x, x2, y; + +x = z->r; +y = z->i; + +if( (x == 0.0) && (y > 1.0) ) + goto ovrf; + +x2 = x * x; +a = 1.0 - x2 - (y * y); +if( a == 0.0 ) + goto ovrf; + +#if ANSIC +t = atan2( 2.0 * x, a )/2.0; +#else +t = atan2( a, 2.0 * x )/2.0; +#endif +w->r = redupi( t ); + +t = y - 1.0; +a = x2 + (t * t); +if( a == 0.0 ) + goto ovrf; + +t = y + 1.0; +a = (x2 + (t * t))/a; +w->i = log(a)/4.0; +return; + +ovrf: +mtherr( "catan", OVERFLOW ); +w->r = MAXNUM; +w->i = MAXNUM; +} + + +/* csinh + * + * Complex hyperbolic sine + * + * + * + * SYNOPSIS: + * + * void csinh(); + * cmplx z, w; + * + * csinh( &z, &w ); + * + * + * DESCRIPTION: + * + * csinh z = (cexp(z) - cexp(-z))/2 + * = sinh x * cos y + i cosh x * sin y . + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 3.1e-16 8.2e-17 + * + */ + +void +csinh (z, w) + cmplx *z, *w; +{ + double x, y; + + x = z->r; + y = z->i; + w->r = sinh (x) * cos (y); + w->i = cosh (x) * sin (y); +} + + +/* casinh + * + * Complex inverse hyperbolic sine + * + * + * + * SYNOPSIS: + * + * void casinh(); + * cmplx z, w; + * + * casinh (&z, &w); + * + * + * + * DESCRIPTION: + * + * casinh z = -i casin iz . + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 1.8e-14 2.6e-15 + * + */ + +void +casinh (z, w) + cmplx *z, *w; +{ + cmplx u; + + u.r = 0.0; + u.i = 1.0; + cmul( z, &u, &u ); + casin( &u, w ); + u.r = 0.0; + u.i = -1.0; + cmul( &u, w, w ); +} + +/* ccosh + * + * Complex hyperbolic cosine + * + * + * + * SYNOPSIS: + * + * void ccosh(); + * cmplx z, w; + * + * ccosh (&z, &w); + * + * + * + * DESCRIPTION: + * + * ccosh(z) = cosh x cos y + i sinh x sin y . + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 2.9e-16 8.1e-17 + * + */ + +void +ccosh (z, w) + cmplx *z, *w; +{ + double x, y; + + x = z->r; + y = z->i; + w->r = cosh (x) * cos (y); + w->i = sinh (x) * sin (y); +} + + +/* cacosh + * + * Complex inverse hyperbolic cosine + * + * + * + * SYNOPSIS: + * + * void cacosh(); + * cmplx z, w; + * + * cacosh (&z, &w); + * + * + * + * DESCRIPTION: + * + * acosh z = i acos z . + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 1.6e-14 2.1e-15 + * + */ + +void +cacosh (z, w) + cmplx *z, *w; +{ + cmplx u; + + cacos( z, w ); + u.r = 0.0; + u.i = 1.0; + cmul( &u, w, w ); +} + + +/* ctanh + * + * Complex hyperbolic tangent + * + * + * + * SYNOPSIS: + * + * void ctanh(); + * cmplx z, w; + * + * ctanh (&z, &w); + * + * + * + * DESCRIPTION: + * + * tanh z = (sinh 2x + i sin 2y) / (cosh 2x + cos 2y) . + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 1.7e-14 2.4e-16 + * + */ + +/* 5.253E-02,1.550E+00 1.643E+01,6.553E+00 1.729E-14 21355 */ + +void +ctanh (z, w) + cmplx *z, *w; +{ + double x, y, d; + + x = z->r; + y = z->i; + d = cosh (2.0 * x) + cos (2.0 * y); + w->r = sinh (2.0 * x) / d; + w->i = sin (2.0 * y) / d; + return; +} + + +/* catanh + * + * Complex inverse hyperbolic tangent + * + * + * + * SYNOPSIS: + * + * void catanh(); + * cmplx z, w; + * + * catanh (&z, &w); + * + * + * + * DESCRIPTION: + * + * Inverse tanh, equal to -i catan (iz); + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 2.3e-16 6.2e-17 + * + */ + +void +catanh (z, w) + cmplx *z, *w; +{ + cmplx u; + + u.r = 0.0; + u.i = 1.0; + cmul (z, &u, &u); /* i z */ + catan (&u, w); + u.r = 0.0; + u.i = -1.0; + cmul (&u, w, w); /* -i catan iz */ + return; +} + + +/* cpow + * + * Complex power function + * + * + * + * SYNOPSIS: + * + * void cpow(); + * cmplx a, z, w; + * + * cpow (&a, &z, &w); + * + * + * + * DESCRIPTION: + * + * Raises complex A to the complex Zth power. + * Definition is per AMS55 # 4.2.8, + * analytically equivalent to cpow(a,z) = cexp(z clog(a)). + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 9.4e-15 1.5e-15 + * + */ + + +void +cpow (a, z, w) + cmplx *a, *z, *w; +{ + double x, y, r, theta, absa, arga; + + x = z->r; + y = z->i; + absa = cabs (a); + if (absa == 0.0) + { + w->r = 0.0; + w->i = 0.0; + return; + } + arga = atan2 (a->i, a->r); + r = pow (absa, x); + theta = x * arga; + if (y != 0.0) + { + r = r * exp (-y * arga); + theta = theta + y * log (absa); + } + w->r = r * cos (theta); + w->i = r * sin (theta); + return; +} diff --git a/components/external/espruino/libs/math/cmplx.c b/components/external/espruino/libs/math/cmplx.c new file mode 100644 index 0000000000..fbe70000bd --- /dev/null +++ b/components/external/espruino/libs/math/cmplx.c @@ -0,0 +1,461 @@ +/* cmplx.c + * + * Complex number arithmetic + * + * + * + * SYNOPSIS: + * + * typedef struct { + * double r; real part + * double i; imaginary part + * }cmplx; + * + * cmplx *a, *b, *c; + * + * cadd( a, b, c ); c = b + a + * csub( a, b, c ); c = b - a + * cmul( a, b, c ); c = b * a + * cdiv( a, b, c ); c = b / a + * cneg( c ); c = -c + * cmov( b, c ); c = b + * + * + * + * DESCRIPTION: + * + * Addition: + * c.r = b.r + a.r + * c.i = b.i + a.i + * + * Subtraction: + * c.r = b.r - a.r + * c.i = b.i - a.i + * + * Multiplication: + * c.r = b.r * a.r - b.i * a.i + * c.i = b.r * a.i + b.i * a.r + * + * Division: + * d = a.r * a.r + a.i * a.i + * c.r = (b.r * a.r + b.i * a.i)/d + * c.i = (b.i * a.r - b.r * a.i)/d + * ACCURACY: + * + * In DEC arithmetic, the test (1/z) * z = 1 had peak relative + * error 3.1e-17, rms 1.2e-17. The test (y/z) * (z/y) = 1 had + * peak relative error 8.3e-17, rms 2.1e-17. + * + * Tests in the rectangle {-10,+10}: + * Relative error: + * arithmetic function # trials peak rms + * DEC cadd 10000 1.4e-17 3.4e-18 + * IEEE cadd 100000 1.1e-16 2.7e-17 + * DEC csub 10000 1.4e-17 4.5e-18 + * IEEE csub 100000 1.1e-16 3.4e-17 + * DEC cmul 3000 2.3e-17 8.7e-18 + * IEEE cmul 100000 2.1e-16 6.9e-17 + * DEC cdiv 18000 4.9e-17 1.3e-17 + * IEEE cdiv 100000 3.7e-16 1.1e-16 + */ + /* cmplx.c + * complex number arithmetic + */ + + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + + +#include "mconf.h" + +#ifdef ANSIPROT +extern double fabs ( double ); +extern double cabs ( cmplx * ); +extern double sqrt ( double ); +extern double atan2 ( double, double ); +extern double cos ( double ); +extern double sin ( double ); +extern double sqrt ( double ); +extern double frexp ( double, int * ); +extern double ldexp ( double, int ); +int isnan ( double ); +void cdiv ( cmplx *, cmplx *, cmplx * ); +void cadd ( cmplx *, cmplx *, cmplx * ); +#else +double fabs(), cabs(), sqrt(), atan2(), cos(), sin(); +double sqrt(), frexp(), ldexp(); +int isnan(); +void cdiv(), cadd(); +#endif + +extern double MAXNUM, MACHEP, PI, PIO2, INFINITY, NAN; +/* +typedef struct + { + double r; + double i; + }cmplx; +*/ +cmplx czero = {0.0, 0.0}; +extern cmplx czero; +cmplx cone = {1.0, 0.0}; +extern cmplx cone; + +/* c = b + a */ + +void cadd( a, b, c ) +register cmplx *a, *b; +cmplx *c; +{ + +c->r = b->r + a->r; +c->i = b->i + a->i; +} + + +/* c = b - a */ + +void csub( a, b, c ) +register cmplx *a, *b; +cmplx *c; +{ + +c->r = b->r - a->r; +c->i = b->i - a->i; +} + +/* c = b * a */ + +void cmul( a, b, c ) +register cmplx *a, *b; +cmplx *c; +{ +double y; + +y = b->r * a->r - b->i * a->i; +c->i = b->r * a->i + b->i * a->r; +c->r = y; +} + + + +/* c = b / a */ + +void cdiv( a, b, c ) +register cmplx *a, *b; +cmplx *c; +{ +double y, p, q, w; + + +y = a->r * a->r + a->i * a->i; +p = b->r * a->r + b->i * a->i; +q = b->i * a->r - b->r * a->i; + +if( y < 1.0 ) + { + w = MAXNUM * y; + if( (fabs(p) > w) || (fabs(q) > w) || (y == 0.0) ) + { + c->r = MAXNUM; + c->i = MAXNUM; + mtherr( "cdiv", OVERFLOW ); + return; + } + } +c->r = p/y; +c->i = q/y; +} + + +/* b = a + Caution, a `short' is assumed to be 16 bits wide. */ + +void cmov( a, b ) +void *a, *b; +{ +register short *pa, *pb; +int i; + +pa = (short *) a; +pb = (short *) b; +i = 8; +do + *pb++ = *pa++; +while( --i ); +} + + +void cneg( a ) +register cmplx *a; +{ + +a->r = -a->r; +a->i = -a->i; +} + +/* cabs() + * + * Complex absolute value + * + * + * + * SYNOPSIS: + * + * double cabs(); + * cmplx z; + * double a; + * + * a = cabs( &z ); + * + * + * + * DESCRIPTION: + * + * + * If z = x + iy + * + * then + * + * a = sqrt( x**2 + y**2 ). + * + * Overflow and underflow are avoided by testing the magnitudes + * of x and y before squaring. If either is outside half of + * the floating point full scale range, both are rescaled. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -30,+30 30000 3.2e-17 9.2e-18 + * IEEE -10,+10 100000 2.7e-16 6.9e-17 + */ + + +/* +Cephes Math Library Release 2.1: January, 1989 +Copyright 1984, 1987, 1989 by Stephen L. Moshier +Direct inquiries to 30 Frost Street, Cambridge, MA 02140 +*/ + + +/* +typedef struct + { + double r; + double i; + }cmplx; +*/ + +#ifdef UNK +#define PREC 27 +#define MAXEXP 1024 +#define MINEXP -1077 +#endif +#ifdef DEC +#define PREC 29 +#define MAXEXP 128 +#define MINEXP -128 +#endif +#ifdef IBMPC +#define PREC 27 +#define MAXEXP 1024 +#define MINEXP -1077 +#endif +#ifdef MIEEE +#define PREC 27 +#define MAXEXP 1024 +#define MINEXP -1077 +#endif + + +double cabs( z ) +register cmplx *z; +{ +double x, y, b, re, im; +int ex, ey, e; + +#ifdef INFINITIES +/* Note, cabs(INFINITY,NAN) = INFINITY. */ +if( z->r == INFINITY || z->i == INFINITY + || z->r == -INFINITY || z->i == -INFINITY ) + return( INFINITY ); +#endif + +#ifdef NANS +if( isnan(z->r) ) + return(z->r); +if( isnan(z->i) ) + return(z->i); +#endif + +re = fabs( z->r ); +im = fabs( z->i ); + +if( re == 0.0 ) + return( im ); +if( im == 0.0 ) + return( re ); + +/* Get the exponents of the numbers */ +x = frexp( re, &ex ); +y = frexp( im, &ey ); + +/* Check if one number is tiny compared to the other */ +e = ex - ey; +if( e > PREC ) + return( re ); +if( e < -PREC ) + return( im ); + +/* Find approximate exponent e of the geometric mean. */ +e = (ex + ey) >> 1; + +/* Rescale so mean is about 1 */ +x = ldexp( re, -e ); +y = ldexp( im, -e ); + +/* Hypotenuse of the right triangle */ +b = sqrt( x * x + y * y ); + +/* Compute the exponent of the answer. */ +y = frexp( b, &ey ); +ey = e + ey; + +/* Check it for overflow and underflow. */ +if( ey > MAXEXP ) + { + mtherr( "cabs", OVERFLOW ); + return( INFINITY ); + } +if( ey < MINEXP ) + return(0.0); + +/* Undo the scaling */ +b = ldexp( b, e ); +return( b ); +} + /* csqrt() + * + * Complex square root + * + * + * + * SYNOPSIS: + * + * void csqrt(); + * cmplx z, w; + * + * csqrt( &z, &w ); + * + * + * + * DESCRIPTION: + * + * + * If z = x + iy, r = |z|, then + * + * 1/2 + * Im w = [ (r - x)/2 ] , + * + * Re w = y / 2 Im w. + * + * + * Note that -w is also a square root of z. The root chosen + * is always in the upper half plane. + * + * Because of the potential for cancellation error in r - x, + * the result is sharpened by doing a Heron iteration + * (see sqrt.c) in complex arithmetic. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 25000 3.2e-17 9.6e-18 + * IEEE -10,+10 100000 3.2e-16 7.7e-17 + * + * 2 + * Also tested by csqrt( z ) = z, and tested by arguments + * close to the real axis. + */ + + +void csqrt( z, w ) +cmplx *z, *w; +{ +cmplx q, s; +double x, y, r, t; + +x = z->r; +y = z->i; + +if( y == 0.0 ) + { + if( x < 0.0 ) + { + w->r = 0.0; + w->i = sqrt(-x); + return; + } + else + { + w->r = sqrt(x); + w->i = 0.0; + return; + } + } + + +if( x == 0.0 ) + { + r = fabs(y); + r = sqrt(0.5*r); + if( y > 0 ) + w->r = r; + else + w->r = -r; + w->i = r; + return; + } + +/* Approximate sqrt(x^2+y^2) - x = y^2/2x - y^4/24x^3 + ... . + * The relative error in the first term is approximately y^2/12x^2 . + */ +if( (fabs(y) < 2.e-4 * fabs(x)) + && (x > 0) ) + { + t = 0.25*y*(y/x); + } +else + { + r = cabs(z); + t = 0.5*(r - x); + } + +r = sqrt(t); +q.i = r; +q.r = y/(2.0*r); +/* Heron iteration in complex arithmetic */ +cdiv( &q, z, &s ); +cadd( &q, &s, w ); +w->r *= 0.5; +w->i *= 0.5; +} + + +double hypot( x, y ) +double x, y; +{ +cmplx z; + +z.r = x; +z.i = y; +return( cabs(&z) ); +} diff --git a/components/external/espruino/libs/math/const.c b/components/external/espruino/libs/math/const.c new file mode 100644 index 0000000000..834e106cc8 --- /dev/null +++ b/components/external/espruino/libs/math/const.c @@ -0,0 +1,252 @@ +/* const.c + * + * Globally declared constants + * + * + * + * SYNOPSIS: + * + * extern const double nameofconstant; + * + * + * + * + * DESCRIPTION: + * + * This file contains a number of mathematical constants and + * also some needed size parameters of the computer arithmetic. + * The values are supplied as arrays of hexadecimal integers + * for IEEE arithmetic; arrays of octal constants for DEC + * arithmetic; and in a normal decimal scientific notation for + * other machines. The particular notation used is determined + * by a symbol (DEC, IBMPC, or UNK) defined in the include file + * mconf.h. + * + * The default size parameters are as follows. + * + * For DEC and UNK modes: + * MACHEP = 1.38777878078144567553E-17 2**-56 + * MAXLOG = 8.8029691931113054295988E1 log(2**127) + * MINLOG = -8.872283911167299960540E1 log(2**-128) + * MAXNUM = 1.701411834604692317316873e38 2**127 + * + * For IEEE arithmetic (IBMPC): + * MACHEP = 1.11022302462515654042E-16 2**-53 + * MAXLOG = 7.09782712893383996843E2 log(2**1024) + * MINLOG = -7.08396418532264106224E2 log(2**-1022) + * MAXNUM = 1.7976931348623158E308 2**1024 + * + * The global symbols for mathematical constants are + * PI = 3.14159265358979323846 pi + * PIO2 = 1.57079632679489661923 pi/2 + * PIO4 = 7.85398163397448309616E-1 pi/4 + * SQRT2 = 1.41421356237309504880 sqrt(2) + * SQRTH = 7.07106781186547524401E-1 sqrt(2)/2 + * LOG2E = 1.4426950408889634073599 1/log(2) + * SQ2OPI = 7.9788456080286535587989E-1 sqrt( 2/pi ) + * LOGE2 = 6.93147180559945309417E-1 log(2) + * LOGSQ2 = 3.46573590279972654709E-1 log(2)/2 + * THPIO4 = 2.35619449019234492885 3*pi/4 + * TWOOPI = 6.36619772367581343075535E-1 2/pi + * + * These lists are subject to change. + */ + +/* const.c */ + +/* +Cephes Math Library Release 2.3: March, 1995 +Copyright 1984, 1995 by Stephen L. Moshier +*/ + +#include "mconf.h" + +#ifdef UNK +#if 1 +const double MACHEP = 1.11022302462515654042E-16; /* 2**-53 */ +#else +const double MACHEP = 1.38777878078144567553E-17; /* 2**-56 */ +#endif +const double UFLOWTHRESH = 2.22507385850720138309E-308; /* 2**-1022 */ +#ifdef DENORMAL +const double MAXLOG = 7.09782712893383996732E2; /* log(MAXNUM) */ +/* const double MINLOG = -7.44440071921381262314E2; */ /* log(2**-1074) */ +const double MINLOG = -7.451332191019412076235E2; /* log(2**-1075) */ +#else +const double MAXLOG = 7.08396418532264106224E2; /* log 2**1022 */ +const double MINLOG = -7.08396418532264106224E2; /* log 2**-1022 */ +#endif +const double MAXNUM = 1.79769313486231570815E308; /* 2**1024*(1-MACHEP) */ +const double PI = 3.14159265358979323846; /* pi */ +const double PIO2 = 1.57079632679489661923; /* pi/2 */ +const double PIO4 = 7.85398163397448309616E-1; /* pi/4 */ +const double SQRT2 = 1.41421356237309504880; /* sqrt(2) */ +const double SQRTH = 7.07106781186547524401E-1; /* sqrt(2)/2 */ +const double LOG2E = 1.4426950408889634073599; /* 1/log(2) */ +const double SQ2OPI = 7.9788456080286535587989E-1; /* sqrt( 2/pi ) */ +const double LOGE2 = 6.93147180559945309417E-1; /* log(2) */ +const double LOGSQ2 = 3.46573590279972654709E-1; /* log(2)/2 */ +const double THPIO4 = 2.35619449019234492885; /* 3*pi/4 */ +const double TWOOPI = 6.36619772367581343075535E-1; /* 2/pi */ +#ifdef INFINITIES +const double INFINITY = 1.0/0.0; /* 99e999; */ +#else +const double INFINITY = 1.79769313486231570815E308; /* 2**1024*(1-MACHEP) */ +#endif +#ifdef NANS +const double NAN = 1.0/0.0 - 1.0/0.0; +#else +const double NAN = 0.0; +#endif +#ifdef MINUSZERO +const double NEGZERO = -0.0; +#else +const double NEGZERO = 0.0; +#endif +#endif + +#ifdef IBMPC + /* 2**-53 = 1.11022302462515654042E-16 */ +const unsigned short MACHEP[4] = {0x0000,0x0000,0x0000,0x3ca0}; +const unsigned short UFLOWTHRESH[4] = {0x0000,0x0000,0x0000,0x0010}; +#ifdef DENORMAL + /* log(MAXNUM) = 7.09782712893383996732224E2 */ +const unsigned short MAXLOG[4] = {0x39ef,0xfefa,0x2e42,0x4086}; + /* log(2**-1074) = - -7.44440071921381262314E2 */ +/*const unsigned short MINLOG[4] = {0x71c3,0x446d,0x4385,0xc087};*/ +const unsigned short MINLOG[4] = {0x3052,0xd52d,0x4910,0xc087}; +#else + /* log(2**1022) = 7.08396418532264106224E2 */ +const unsigned short MAXLOG[4] = {0xbcd2,0xdd7a,0x232b,0x4086}; + /* log(2**-1022) = - 7.08396418532264106224E2 */ +const unsigned short MINLOG[4] = {0xbcd2,0xdd7a,0x232b,0xc086}; +#endif + /* 2**1024*(1-MACHEP) = 1.7976931348623158E308 */ +const unsigned short MAXNUM[4] = {0xffff,0xffff,0xffff,0x7fef}; +const unsigned short PI[4] = {0x2d18,0x5444,0x21fb,0x4009}; +const unsigned short PIO2[4] = {0x2d18,0x5444,0x21fb,0x3ff9}; +const unsigned short PIO4[4] = {0x2d18,0x5444,0x21fb,0x3fe9}; +const unsigned short SQRT2[4] = {0x3bcd,0x667f,0xa09e,0x3ff6}; +const unsigned short SQRTH[4] = {0x3bcd,0x667f,0xa09e,0x3fe6}; +const unsigned short LOG2E[4] = {0x82fe,0x652b,0x1547,0x3ff7}; +const unsigned short SQ2OPI[4] = {0x3651,0x33d4,0x8845,0x3fe9}; +const unsigned short LOGE2[4] = {0x39ef,0xfefa,0x2e42,0x3fe6}; +const unsigned short LOGSQ2[4] = {0x39ef,0xfefa,0x2e42,0x3fd6}; +const unsigned short THPIO4[4] = {0x21d2,0x7f33,0xd97c,0x4002}; +const unsigned short TWOOPI[4] = {0xc883,0x6dc9,0x5f30,0x3fe4}; +#ifdef INFINITIES +const unsigned short INFINITY[4] = {0x0000,0x0000,0x0000,0x7ff0}; +#else +const unsigned short INFINITY[4] = {0xffff,0xffff,0xffff,0x7fef}; +#endif +#ifdef NANS +const unsigned short NAN[4] = {0x0000,0x0000,0x0000,0x7ffc}; +#else +const unsigned short NAN[4] = {0x0000,0x0000,0x0000,0x0000}; +#endif +#ifdef MINUSZERO +const unsigned short NEGZERO[4] = {0x0000,0x0000,0x0000,0x8000}; +#else +const unsigned short NEGZERO[4] = {0x0000,0x0000,0x0000,0x0000}; +#endif +#endif + +#ifdef MIEEE + /* 2**-53 = 1.11022302462515654042E-16 */ +const unsigned short MACHEP[4] = {0x3ca0,0x0000,0x0000,0x0000}; +const unsigned short UFLOWTHRESH[4] = {0x0010,0x0000,0x0000,0x0000}; +#ifdef DENORMAL + /* log(2**1024) = 7.09782712893383996843E2 */ +const unsigned short MAXLOG[4] = {0x4086,0x2e42,0xfefa,0x39ef}; + /* log(2**-1074) = - -7.44440071921381262314E2 */ +/* const unsigned short MINLOG[4] = {0xc087,0x4385,0x446d,0x71c3}; */ +const unsigned short MINLOG[4] = {0xc087,0x4910,0xd52d,0x3052}; +#else + /* log(2**1022) = 7.08396418532264106224E2 */ +const unsigned short MAXLOG[4] = {0x4086,0x232b,0xdd7a,0xbcd2}; + /* log(2**-1022) = - 7.08396418532264106224E2 */ +const unsigned short MINLOG[4] = {0xc086,0x232b,0xdd7a,0xbcd2}; +#endif + /* 2**1024*(1-MACHEP) = 1.7976931348623158E308 */ +const unsigned short MAXNUM[4] = {0x7fef,0xffff,0xffff,0xffff}; +const unsigned short PI[4] = {0x4009,0x21fb,0x5444,0x2d18}; +const unsigned short PIO2[4] = {0x3ff9,0x21fb,0x5444,0x2d18}; +const unsigned short PIO4[4] = {0x3fe9,0x21fb,0x5444,0x2d18}; +const unsigned short SQRT2[4] = {0x3ff6,0xa09e,0x667f,0x3bcd}; +const unsigned short SQRTH[4] = {0x3fe6,0xa09e,0x667f,0x3bcd}; +const unsigned short LOG2E[4] = {0x3ff7,0x1547,0x652b,0x82fe}; +const unsigned short SQ2OPI[4] = {0x3fe9,0x8845,0x33d4,0x3651}; +const unsigned short LOGE2[4] = {0x3fe6,0x2e42,0xfefa,0x39ef}; +const unsigned short LOGSQ2[4] = {0x3fd6,0x2e42,0xfefa,0x39ef}; +const unsigned short THPIO4[4] = {0x4002,0xd97c,0x7f33,0x21d2}; +const unsigned short TWOOPI[4] = {0x3fe4,0x5f30,0x6dc9,0xc883}; +#ifdef INFINITIES +const unsigned short INFINITY[4] = {0x7ff0,0x0000,0x0000,0x0000}; +#else +const unsigned short INFINITY[4] = {0x7fef,0xffff,0xffff,0xffff}; +#endif +#ifdef NANS +const unsigned short NAN[4] = {0x7ff8,0x0000,0x0000,0x0000}; +#else +const unsigned short NAN[4] = {0x0000,0x0000,0x0000,0x0000}; +#endif +#ifdef MINUSZERO +const unsigned short NEGZERO[4] = {0x8000,0x0000,0x0000,0x0000}; +#else +const unsigned short NEGZERO[4] = {0x0000,0x0000,0x0000,0x0000}; +#endif +#endif + +#ifdef DEC + /* 2**-56 = 1.38777878078144567553E-17 */ +const unsigned short MACHEP[4] = {0022200,0000000,0000000,0000000}; +const unsigned short UFLOWTHRESH[4] = {0x0080,0x0000,0x0000,0x0000}; + /* log 2**127 = 88.029691931113054295988 */ +const unsigned short MAXLOG[4] = {041660,007463,0143742,025733,}; + /* log 2**-128 = -88.72283911167299960540 */ +const unsigned short MINLOG[4] = {0141661,071027,0173721,0147572,}; + /* 2**127 = 1.701411834604692317316873e38 */ +const unsigned short MAXNUM[4] = {077777,0177777,0177777,0177777,}; +const unsigned short PI[4] = {040511,007732,0121041,064302,}; +const unsigned short PIO2[4] = {040311,007732,0121041,064302,}; +const unsigned short PIO4[4] = {040111,007732,0121041,064302,}; +const unsigned short SQRT2[4] = {040265,002363,031771,0157145,}; +const unsigned short SQRTH[4] = {040065,002363,031771,0157144,}; +const unsigned short LOG2E[4] = {040270,0125073,024534,013761,}; +const unsigned short SQ2OPI[4] = {040114,041051,0117241,0131204,}; +const unsigned short LOGE2[4] = {040061,071027,0173721,0147572,}; +const unsigned short LOGSQ2[4] = {037661,071027,0173721,0147572,}; +const unsigned short THPIO4[4] = {040426,0145743,0174631,007222,}; +const unsigned short TWOOPI[4] = {040042,0174603,067116,042025,}; +/* Approximate infinity by MAXNUM. */ +const unsigned short INFINITY[4] = {077777,0177777,0177777,0177777,}; +const unsigned short NAN[4] = {0000000,0000000,0000000,0000000}; +#ifdef MINUSZERO +const unsigned short NEGZERO[4] = {0000000,0000000,0000000,0100000}; +#else +const unsigned short NEGZERO[4] = {0000000,0000000,0000000,0000000}; +#endif +#endif + +#ifndef UNK +extern const unsigned short MACHEP[]; +extern const unsigned short UFLOWTHRESH[]; +extern const unsigned short MAXLOG[]; +extern const unsigned short UNDLOG[]; +extern const unsigned short MINLOG[]; +extern const unsigned short MAXNUM[]; +extern const unsigned short PI[]; +extern const unsigned short PIO2[]; +extern const unsigned short PIO4[]; +extern const unsigned short SQRT2[]; +extern const unsigned short SQRTH[]; +extern const unsigned short LOG2E[]; +extern const unsigned short SQ2OPI[]; +extern const unsigned short LOGE2[]; +extern const unsigned short LOGSQ2[]; +extern const unsigned short THPIO4[]; +extern const unsigned short TWOOPI[]; +extern const unsigned short INFINITY[]; +extern const unsigned short NAN[]; +extern const unsigned short NEGZERO[]; +#endif diff --git a/components/external/espruino/libs/math/cosh.c b/components/external/espruino/libs/math/cosh.c new file mode 100644 index 0000000000..75c09d397e --- /dev/null +++ b/components/external/espruino/libs/math/cosh.c @@ -0,0 +1,83 @@ +/* cosh.c + * + * Hyperbolic cosine + * + * + * + * SYNOPSIS: + * + * double x, y, cosh(); + * + * y = cosh( x ); + * + * + * + * DESCRIPTION: + * + * Returns hyperbolic cosine of argument in the range MINLOG to + * MAXLOG. + * + * cosh(x) = ( exp(x) + exp(-x) )/2. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC +- 88 50000 4.0e-17 7.7e-18 + * IEEE +-MAXLOG 30000 2.6e-16 5.7e-17 + * + * + * ERROR MESSAGES: + * + * message condition value returned + * cosh overflow |x| > MAXLOG MAXNUM + * + * + */ + +/* cosh.c */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1985, 1995, 2000 by Stephen L. Moshier +*/ + +#include "mconf.h" +#ifdef ANSIPROT +extern double exp ( double ); +extern int isnan ( double ); +extern int isfinite ( double ); +#else +double exp(); +int isnan(), isfinite(); +#endif +extern double MAXLOG, INFINITY, LOGE2; + +double cosh(x) +double x; +{ +double y; + +#ifdef NANS +if( isnan(x) ) + return(x); +#endif +if( x < 0 ) + x = -x; +if( x > (MAXLOG + LOGE2) ) + { + mtherr( "cosh", OVERFLOW ); + return( INFINITY ); + } +if( x >= (MAXLOG - LOGE2) ) + { + y = exp(0.5 * x); + y = (0.5 * y) * y; + return(y); + } +y = exp(x); +y = 0.5 * (y + 1.0 / y); +return( y ); +} diff --git a/components/external/espruino/libs/math/descrip.mms b/components/external/espruino/libs/math/descrip.mms new file mode 100644 index 0000000000..c68f38e2e3 --- /dev/null +++ b/components/external/espruino/libs/math/descrip.mms @@ -0,0 +1,99 @@ +CFLAGS= /DEBUG/NOLIST +hfiles= mconf.h- + +ofiles= acosh.obj- + asin.obj- + asinh.obj- + atan.obj- + atanh.obj- + cbrt.obj- + chbevl.obj- + const.obj- + cosh.obj- + drand.obj- + exp.obj- + exp10.obj- + fabs.obj- + floor.obj- + log.obj- + log10.obj- + polevl.obj- + pow.obj- + powi.obj- + round.obj- + sin.obj- + sinh.obj- + tan.obj- + tanh.obj- + unity.obj- + sqrt.obj- + floor.obj- + polevl.obj- + mtherr.obj + +mtst.exe : $(ofiles) + LINK mtst/option +acosh.obj : acosh.c,$(HFILES) + CC $(CFLAGS) acosh +asin.obj : asin.c,$(HFILES) + CC $(CFLAGS) asin +asinh.obj : asinh.c,$(HFILES) + CC $(CFLAGS) asinh +atan.obj : atan.c,$(HFILES) + CC $(CFLAGS) atan +atan.obj : atan.c,$(HFILES) + CC $(CFLAGS) atan +atanh.obj : atanh.c,$(HFILES) + CC $(CFLAGS) atanh +cbrt.obj : cbrt.c,$(HFILES) + CC $(CFLAGS) cbrt +chbevl.obj : chbevl.c,$(HFILES) + CC $(CFLAGS) chbevl +const.obj : const.c,$(HFILES) + CC $(CFLAGS) const +cosh.obj : cosh.c,$(HFILES) + CC $(CFLAGS) cosh +drand.obj : drand.c,$(HFILES) + CC $(CFLAGS) drand +exp.obj : exp.c,$(HFILES) + CC $(CFLAGS) exp +exp10.obj : exp10.c,$(HFILES) + CC $(CFLAGS) exp10 +fabs.obj : fabs.c,$(HFILES) + CC $(CFLAGS) fabs +floor.obj : floor.c,$(HFILES) + CC $(CFLAGS) floor +log.obj : log.c,$(HFILES) + CC $(CFLAGS) log +log10.obj : log10.c,$(HFILES) + CC $(CFLAGS) log10 +polevl.obj : polevl.c,$(HFILES) + CC $(CFLAGS) polevl +pow.obj : pow.c,$(HFILES) + CC $(CFLAGS) pow +powi.obj : powi.c,$(HFILES) + CC $(CFLAGS) powi +round.obj : round.c,$(HFILES) + CC $(CFLAGS) round +sin.obj : sin.c,$(HFILES) + CC $(CFLAGS) sin +sinh.obj : sinh.c,$(HFILES) + CC $(CFLAGS) sinh +tan.obj : tan.c,$(HFILES) + CC $(CFLAGS) tan +tanh.obj : tanh.c,$(HFILES) + CC $(CFLAGS) tanh +unity.obj : unity.c,$(HFILES) + CC $(CFLAGS) unity +sqrt.obj : sqrt.c,$(HFILES) + CC $(CFLAGS) sqrt +mtherr.obj : mtherr.c,$(HFILES) + CC $(CFLAGS) mtherr + + + + + + + + diff --git a/components/external/espruino/libs/math/drand.c b/components/external/espruino/libs/math/drand.c new file mode 100644 index 0000000000..07bd3261b9 --- /dev/null +++ b/components/external/espruino/libs/math/drand.c @@ -0,0 +1,161 @@ +/* drand.c + * + * Pseudorandom number generator + * + * + * + * SYNOPSIS: + * + * double y, drand(); + * + * drand( &y ); + * + * + * + * DESCRIPTION: + * + * Yields a random number 1.0 <= y < 2.0. + * + * The three-generator congruential algorithm by Brian + * Wichmann and David Hill (BYTE magazine, March, 1987, + * pp 127-8) is used. The period, given by them, is + * 6953607871644. + * + * Versions invoked by the different arithmetic compile + * time options DEC, IBMPC, and MIEEE, produce + * approximately the same sequences, differing only in the + * least significant bits of the numbers. The UNK option + * implements the algorithm as recommended in the BYTE + * article. It may be used on all computers. However, + * the low order bits of a double precision number may + * not be adequately random, and may vary due to arithmetic + * implementation details on different computers. + * + * The other compile options generate an additional random + * integer that overwrites the low order bits of the double + * precision number. This reduces the period by a factor of + * two but tends to overcome the problems mentioned. + * + */ + + +/* Three-generator random number algorithm + * of Brian Wichmann and David Hill + * BYTE magazine, March, 1987 pp 127-8 + * + * The period, given by them, is (p-1)(q-1)(r-1)/4 = 6.95e12. + */ + +#include "mconf.h" +#ifdef ANSIPROT +static int ranwh ( void ); +#else +static int ranwh(); +#endif + +static int sx = 1; +static int sy = 10000; +static int sz = 3000; + +static union { + double d; + unsigned short s[4]; +} unkans; + +/* This function implements the three + * congruential generators. + */ + +static int ranwh() +{ +int r, s; + +/* sx = sx * 171 mod 30269 */ +r = sx/177; +s = sx - 177 * r; +sx = 171 * s - 2 * r; +if( sx < 0 ) + sx += 30269; + + +/* sy = sy * 172 mod 30307 */ +r = sy/176; +s = sy - 176 * r; +sy = 172 * s - 35 * r; +if( sy < 0 ) + sy += 30307; + +/* sz = 170 * sz mod 30323 */ +r = sz/178; +s = sz - 178 * r; +sz = 170 * s - 63 * r; +if( sz < 0 ) + sz += 30323; +/* The results are in static sx, sy, sz. */ +return 0; +} + +/* drand.c + * + * Random double precision floating point number between 1 and 2. + * + * C callable: + * drand( &x ); + */ + +int drand( a ) +double *a; +{ +unsigned short r; +#ifdef DEC +unsigned short s, t; +#endif + +/* This algorithm of Wichmann and Hill computes a floating point + * result: + */ +ranwh(); +unkans.d = sx/30269.0 + sy/30307.0 + sz/30323.0; +r = unkans.d; +unkans.d -= r; +unkans.d += 1.0; + +/* if UNK option, do nothing further. + * Otherwise, make a random 16 bit integer + * to overwrite the least significant word + * of unkans. + */ +#ifdef UNK +/* do nothing */ +#else +ranwh(); +r = sx * sy + sz; +#endif + +#ifdef DEC +/* To make the numbers as similar as possible + * in all arithmetics, the random integer has + * to be inserted 3 bits higher up in a DEC number. + * An alternative would be put it 3 bits lower down + * in all the other number types. + */ +s = unkans.s[2]; +t = s & 07; /* save these bits to put in at the bottom */ +s &= 0177770; +s |= (r >> 13) & 07; +unkans.s[2] = s; +t |= r << 3; +unkans.s[3] = t; +#endif + +#ifdef IBMPC +unkans.s[0] = r; +#endif + +#ifdef MIEEE +unkans.s[3] = r; +#endif + +*a = unkans.d; +return 0; +} diff --git a/components/external/espruino/libs/math/dtestvec.c b/components/external/espruino/libs/math/dtestvec.c new file mode 100644 index 0000000000..37901e3721 --- /dev/null +++ b/components/external/espruino/libs/math/dtestvec.c @@ -0,0 +1,543 @@ + +/* Test vectors for math functions. + See C9X section F.9. */ +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1998, 2000 by Stephen L. Moshier +*/ + +#include +#include +#include +int isfinite (double); + +/* C9X spells lgam lgamma. */ +#define GLIBC2 0 + +extern double PI; +const static double MPI, PIO2, MPIO2, PIO4, MPIO4, THPIO4, MTHPIO4; + +#if 0 +#define PI 3.141592653589793238463E0 +#define PIO2 1.570796326794896619231E0 +#define PIO4 7.853981633974483096157E-1 +#define THPIO4 2.35619449019234492884698 +#define SQRT2 1.414213562373095048802E0 +#define SQRTH 7.071067811865475244008E-1 +#define INF (1.0/0.0) +#define MINF (-1.0/0.0) +#endif + +extern double MACHEP, SQRTH, SQRT2; +extern double NAN, INFINITY, NEGZERO; +const static double INF, MINF; +const static double ZERO, MZERO, HALF, MHALF, ONE, MONE, TWO, MTWO, THREE, MTHREE; +/* #define NAN (1.0/0.0 - 1.0/0.0) */ + +/* Functions of one variable. */ +double log (double); +double exp ( double); +double atan (double); +double sin (double); +double cos (double); +double tan (double); +double acos (double); +double asin (double); +double acosh (double); +double asinh (double); +double atanh (double); +double sinh (double); +double cosh (double); +double tanh (double); +double exp2 (double); +double expm1 (double); +double log10 (double); +double log1p (double); +double log2 (double); +double fabs (double); +double erf (double); +double erfc (double); +double gamma (double); +double floor (double); +double ceil (double); +double cbrt (double); +#if GLIBC2 +double lgamma (double); +#else +double lgam (double); +#endif + +struct oneargument + { + char *name; /* Name of the function. */ + double (*func) (double); + double *arg1; + double *answer; + int thresh; /* Error report threshold. */ + }; + +struct oneargument test1[] = +{ + {"atan", atan, &ONE, &PIO4, 0}, + {"sin", sin, &PIO2, &ONE, 0}, +#if 0 + {"cos", cos, &PIO4, &SQRTH, 0}, + {"sin", sin, 32767., 1.8750655394138942394239E-1, 0}, + {"cos", cos, 32767., 9.8226335176928229845654E-1, 0}, + {"tan", tan, 32767., 1.9089234430221485740826E-1, 0}, + {"sin", sin, 8388607., 9.9234509376961249835628E-1, 0}, + {"cos", cos, 8388607., -1.2349580912475928183718E-1, 0}, + {"tan", tan, 8388607., -8.0354556223613614748329E0, 0}, + /* + {"sin", sin, 2147483647., -7.2491655514455639054829E-1, 0}, + {"cos", cos, 2147483647., -6.8883669187794383467976E-1, 0}, + {"tan", tan, 2147483647., 1.0523779637351339136698E0, 0}, + */ + {"cos", cos, &PIO2, 6.1232339957367574e-17, 1}, + {"sin", sin, &PIO4, &SQRTH, 1}, +#endif + {"acos", acos, &NAN, &NAN, 0}, + {"acos", acos, &ONE, &ZERO, 0}, + {"acos", acos, &TWO, &NAN, 0}, + {"acos", acos, &MTWO, &NAN, 0}, + {"asin", asin, &NAN, &NAN, 0}, + {"asin", asin, &ZERO, &ZERO, 0}, + {"asin", asin, &MZERO, &MZERO, 0}, + {"asin", asin, &TWO, &NAN, 0}, + {"asin", asin, &MTWO, &NAN, 0}, + {"atan", atan, &NAN, &NAN, 0}, + {"atan", atan, &ZERO, &ZERO, 0}, + {"atan", atan, &MZERO, &MZERO, 0}, + {"atan", atan, &INF, &PIO2, 0}, + {"atan", atan, &MINF, &MPIO2, 0}, + {"cos", cos, &NAN, &NAN, 0}, + {"cos", cos, &ZERO, &ONE, 0}, + {"cos", cos, &MZERO, &ONE, 0}, + {"cos", cos, &INF, &NAN, 0}, + {"cos", cos, &MINF, &NAN, 0}, + {"sin", sin, &NAN, &NAN, 0}, + {"sin", sin, &MZERO, &MZERO, 0}, + {"sin", sin, &ZERO, &ZERO, 0}, + {"sin", sin, &INF, &NAN, 0}, + {"sin", sin, &MINF, &NAN, 0}, + {"tan", tan, &NAN, &NAN, 0}, + {"tan", tan, &ZERO, &ZERO, 0}, + {"tan", tan, &MZERO, &MZERO, 0}, + {"tan", tan, &INF, &NAN, 0}, + {"tan", tan, &MINF, &NAN, 0}, + {"acosh", acosh, &NAN, &NAN, 0}, + {"acosh", acosh, &ONE, &ZERO, 0}, + {"acosh", acosh, &INF, &INF, 0}, + {"acosh", acosh, &HALF, &NAN, 0}, + {"acosh", acosh, &MONE, &NAN, 0}, + {"asinh", asinh, &NAN, &NAN, 0}, + {"asinh", asinh, &ZERO, &ZERO, 0}, + {"asinh", asinh, &MZERO, &MZERO, 0}, + {"asinh", asinh, &INF, &INF, 0}, + {"asinh", asinh, &MINF, &MINF, 0}, + {"atanh", atanh, &NAN, &NAN, 0}, + {"atanh", atanh, &ZERO, &ZERO, 0}, + {"atanh", atanh, &MZERO, &MZERO, 0}, + {"atanh", atanh, &ONE, &INF, 0}, + {"atanh", atanh, &MONE, &MINF, 0}, + {"atanh", atanh, &TWO, &NAN, 0}, + {"atanh", atanh, &MTWO, &NAN, 0}, + {"cosh", cosh, &NAN, &NAN, 0}, + {"cosh", cosh, &ZERO, &ONE, 0}, + {"cosh", cosh, &MZERO, &ONE, 0}, + {"cosh", cosh, &INF, &INF, 0}, + {"cosh", cosh, &MINF, &INF, 0}, + {"sinh", sinh, &NAN, &NAN, 0}, + {"sinh", sinh, &ZERO, &ZERO, 0}, + {"sinh", sinh, &MZERO, &MZERO, 0}, + {"sinh", sinh, &INF, &INF, 0}, + {"sinh", sinh, &MINF, &MINF, 0}, + {"tanh", tanh, &NAN, &NAN, 0}, + {"tanh", tanh, &ZERO, &ZERO, 0}, + {"tanh", tanh, &MZERO, &MZERO, 0}, + {"tanh", tanh, &INF, &ONE, 0}, + {"tanh", tanh, &MINF, &MONE, 0}, + {"exp", exp, &NAN, &NAN, 0}, + {"exp", exp, &ZERO, &ONE, 0}, + {"exp", exp, &MZERO, &ONE, 0}, + {"exp", exp, &INF, &INF, 0}, + {"exp", exp, &MINF, &ZERO, 0}, +#if !GLIBC2 + {"exp2", exp2, &NAN, &NAN, 0}, + {"exp2", exp2, &ZERO, &ONE, 0}, + {"exp2", exp2, &MZERO, &ONE, 0}, + {"exp2", exp2, &INF, &INF, 0}, + {"exp2", exp2, &MINF, &ZERO, 0}, +#endif + {"expm1", expm1, &NAN, &NAN, 0}, + {"expm1", expm1, &ZERO, &ZERO, 0}, + {"expm1", expm1, &MZERO, &MZERO, 0}, + {"expm1", expm1, &INF, &INF, 0}, + {"expm1", expm1, &MINF, &MONE, 0}, + {"log", log, &NAN, &NAN, 0}, + {"log", log, &ZERO, &MINF, 0}, + {"log", log, &MZERO, &MINF, 0}, + {"log", log, &ONE, &ZERO, 0}, + {"log", log, &MONE, &NAN, 0}, + {"log", log, &INF, &INF, 0}, + {"log10", log10, &NAN, &NAN, 0}, + {"log10", log10, &ZERO, &MINF, 0}, + {"log10", log10, &MZERO, &MINF, 0}, + {"log10", log10, &ONE, &ZERO, 0}, + {"log10", log10, &MONE, &NAN, 0}, + {"log10", log10, &INF, &INF, 0}, + {"log1p", log1p, &NAN, &NAN, 0}, + {"log1p", log1p, &ZERO, &ZERO, 0}, + {"log1p", log1p, &MZERO, &MZERO, 0}, + {"log1p", log1p, &MONE, &MINF, 0}, + {"log1p", log1p, &MTWO, &NAN, 0}, + {"log1p", log1p, &INF, &INF, 0}, +#if !GLIBC2 + {"log2", log2, &NAN, &NAN, 0}, + {"log2", log2, &ZERO, &MINF, 0}, + {"log2", log2, &MZERO, &MINF, 0}, + {"log2", log2, &MONE, &NAN, 0}, + {"log2", log2, &INF, &INF, 0}, +#endif + /* {"fabs", fabs, NAN, NAN, 0}, */ + {"fabs", fabs, &ONE, &ONE, 0}, + {"fabs", fabs, &MONE, &ONE, 0}, + {"fabs", fabs, &ZERO, &ZERO, 0}, + {"fabs", fabs, &MZERO, &ZERO, 0}, + {"fabs", fabs, &INF, &INF, 0}, + {"fabs", fabs, &MINF, &INF, 0}, + {"cbrt", cbrt, &NAN, &NAN, 0}, + {"cbrt", cbrt, &ZERO, &ZERO, 0}, + {"cbrt", cbrt, &MZERO, &MZERO, 0}, + {"cbrt", cbrt, &INF, &INF, 0}, + {"cbrt", cbrt, &MINF, &MINF, 0}, + {"erf", erf, &NAN, &NAN, 0}, + {"erf", erf, &ZERO, &ZERO, 0}, + {"erf", erf, &MZERO, &MZERO, 0}, + {"erf", erf, &INF, &ONE, 0}, + {"erf", erf, &MINF, &MONE, 0}, + {"erfc", erfc, &NAN, &NAN, 0}, + {"erfc", erfc, &INF, &ZERO, 0}, + {"erfc", erfc, &MINF, &TWO, 0}, + {"gamma", gamma, &NAN, &NAN, 0}, + {"gamma", gamma, &INF, &INF, 0}, + {"gamma", gamma, &MONE, &NAN, 0}, + {"gamma", gamma, &ZERO, &NAN, 0}, + {"gamma", gamma, &MINF, &NAN, 0}, +#if GLIBC2 + {"lgamma", lgamma, &NAN, &NAN, 0}, + {"lgamma", lgamma, &INF, &INF, 0}, + {"lgamma", lgamma, &MONE, &INF, 0}, + {"lgamma", lgamma, &ZERO, &INF, 0}, + {"lgamma", lgamma, &MINF, &INF, 0}, +#else + {"lgam", lgam, &NAN, &NAN, 0}, + {"lgam", lgam, &INF, &INF, 0}, + {"lgam", lgam, &MONE, &INF, 0}, + {"lgam", lgam, &ZERO, &INF, 0}, + {"lgam", lgam, &MINF, &INF, 0}, +#endif + {"ceil", ceil, &NAN, &NAN, 0}, + {"ceil", ceil, &ZERO, &ZERO, 0}, + {"ceil", ceil, &MZERO, &MZERO, 0}, + {"ceil", ceil, &INF, &INF, 0}, + {"ceil", ceil, &MINF, &MINF, 0}, + {"floor", floor, &NAN, &NAN, 0}, + {"floor", floor, &ZERO, &ZERO, 0}, + {"floor", floor, &MZERO, &MZERO, 0}, + {"floor", floor, &INF, &INF, 0}, + {"floor", floor, &MINF, &MINF, 0}, + {"null", NULL, &ZERO, &ZERO, 0}, +}; + +/* Functions of two variables. */ +double atan2 (double, double); +double pow (double, double); + +struct twoarguments + { + char *name; /* Name of the function. */ + double (*func) (double, double); + double *arg1; + double *arg2; + double *answer; + int thresh; + }; + +struct twoarguments test2[] = +{ + {"atan2", atan2, &ZERO, &ONE, &ZERO, 0}, + {"atan2", atan2, &MZERO, &ONE, &MZERO, 0}, + {"atan2", atan2, &ZERO, &ZERO, &ZERO, 0}, + {"atan2", atan2, &MZERO, &ZERO, &MZERO, 0}, + {"atan2", atan2, &ZERO, &MONE, &PI, 0}, + {"atan2", atan2, &MZERO, &MONE, &MPI, 0}, + {"atan2", atan2, &ZERO, &MZERO, &PI, 0}, + {"atan2", atan2, &MZERO, &MZERO, &MPI, 0}, + {"atan2", atan2, &ONE, &ZERO, &PIO2, 0}, + {"atan2", atan2, &ONE, &MZERO, &PIO2, 0}, + {"atan2", atan2, &MONE, &ZERO, &MPIO2, 0}, + {"atan2", atan2, &MONE, &MZERO, &MPIO2, 0}, + {"atan2", atan2, &ONE, &INF, &ZERO, 0}, + {"atan2", atan2, &MONE, &INF, &MZERO, 0}, + {"atan2", atan2, &INF, &ONE, &PIO2, 0}, + {"atan2", atan2, &INF, &MONE, &PIO2, 0}, + {"atan2", atan2, &MINF, &ONE, &MPIO2, 0}, + {"atan2", atan2, &MINF, &MONE, &MPIO2, 0}, + {"atan2", atan2, &ONE, &MINF, &PI, 0}, + {"atan2", atan2, &MONE, &MINF, &MPI, 0}, + {"atan2", atan2, &INF, &INF, &PIO4, 0}, + {"atan2", atan2, &MINF, &INF, &MPIO4, 0}, + {"atan2", atan2, &INF, &MINF, &THPIO4, 0}, + {"atan2", atan2, &MINF, &MINF, &MTHPIO4, 0}, + {"atan2", atan2, &ONE, &ONE, &PIO4, 0}, + {"atan2", atan2, &NAN, &ONE, &NAN, 0}, + {"atan2", atan2, &ONE, &NAN, &NAN, 0}, + {"atan2", atan2, &NAN, &NAN, &NAN, 0}, + {"pow", pow, &ONE, &ZERO, &ONE, 0}, + {"pow", pow, &ONE, &MZERO, &ONE, 0}, + {"pow", pow, &MONE, &ZERO, &ONE, 0}, + {"pow", pow, &MONE, &MZERO, &ONE, 0}, + {"pow", pow, &INF, &ZERO, &ONE, 0}, + {"pow", pow, &INF, &MZERO, &ONE, 0}, + {"pow", pow, &NAN, &ZERO, &ONE, 0}, + {"pow", pow, &NAN, &MZERO, &ONE, 0}, + {"pow", pow, &TWO, &INF, &INF, 0}, + {"pow", pow, &MTWO, &INF, &INF, 0}, + {"pow", pow, &HALF, &INF, &ZERO, 0}, + {"pow", pow, &MHALF, &INF, &ZERO, 0}, + {"pow", pow, &TWO, &MINF, &ZERO, 0}, + {"pow", pow, &MTWO, &MINF, &ZERO, 0}, + {"pow", pow, &HALF, &MINF, &INF, 0}, + {"pow", pow, &MHALF, &MINF, &INF, 0}, + {"pow", pow, &INF, &HALF, &INF, 0}, + {"pow", pow, &INF, &TWO, &INF, 0}, + {"pow", pow, &INF, &MHALF, &ZERO, 0}, + {"pow", pow, &INF, &MTWO, &ZERO, 0}, + {"pow", pow, &MINF, &THREE, &MINF, 0}, + {"pow", pow, &MINF, &TWO, &INF, 0}, + {"pow", pow, &MINF, &MTHREE, &MZERO, 0}, + {"pow", pow, &MINF, &MTWO, &ZERO, 0}, + {"pow", pow, &NAN, &ONE, &NAN, 0}, + {"pow", pow, &ONE, &NAN, &NAN, 0}, + {"pow", pow, &NAN, &NAN, &NAN, 0}, + {"pow", pow, &ONE, &INF, &NAN, 0}, + {"pow", pow, &MONE, &INF, &NAN, 0}, + {"pow", pow, &ONE, &MINF, &NAN, 0}, + {"pow", pow, &MONE, &MINF, &NAN, 0}, + {"pow", pow, &MTWO, &HALF, &NAN, 0}, + {"pow", pow, &ZERO, &MTHREE, &INF, 0}, + {"pow", pow, &MZERO, &MTHREE, &MINF, 0}, + {"pow", pow, &ZERO, &MHALF, &INF, 0}, + {"pow", pow, &MZERO, &MHALF, &INF, 0}, + {"pow", pow, &ZERO, &THREE, &ZERO, 0}, + {"pow", pow, &MZERO, &THREE, &MZERO, 0}, + {"pow", pow, &ZERO, &HALF, &ZERO, 0}, + {"pow", pow, &MZERO, &HALF, &ZERO, 0}, + {"null", NULL, &ZERO, &ZERO, &ZERO, 0}, +}; + +/* Integer functions of one variable. */ + +int isnan (double); +int signbit (double); + +struct intans + { + char *name; /* Name of the function. */ + int (*func) (double); + double *arg1; + int ianswer; + }; + +struct intans test3[] = +{ + {"isfinite", isfinite, &ZERO, 1}, + {"isfinite", isfinite, &INF, 0}, + {"isfinite", isfinite, &MINF, 0}, + {"isnan", isnan, &NAN, 1}, + {"isnan", isnan, &INF, 0}, + {"isnan", isnan, &ZERO, 0}, + {"isnan", isnan, &MZERO, 0}, + {"signbit", signbit, &MZERO, 1}, + {"signbit", signbit, &MONE, 1}, + {"signbit", signbit, &ZERO, 0}, + {"signbit", signbit, &ONE, 0}, + {"signbit", signbit, &MINF, 1}, + {"signbit", signbit, &INF, 0}, + {"null", NULL, &ZERO, 0}, +}; + +static volatile double x1; +static volatile double x2; +static volatile double y; +static volatile double answer; + +void +pvec(x) +double x; +{ + union + { + double d; + unsigned short s[4]; + } u; + int i; + + u.d = x; + for (i = 0; i < 4; i++) + printf ("0x%04x ", u.s[i]); + printf ("\n"); +} + + +int +main () +{ + int i, nerrors, k, ianswer, ntests; + double (*fun1) (double); + double (*fun2) (double, double); + int (*fun3) (double); + double e; + union + { + double d; + char c[8]; + } u, v; + + ZERO = 0.0; + MZERO = NEGZERO; + HALF = 0.5; + MHALF = -HALF; + ONE = 1.0; + MONE = -ONE; + TWO = 2.0; + MTWO = -TWO; + THREE = 3.0; + MTHREE = -THREE; + INF = INFINITY; + MINF = -INFINITY; + MPI = -PI; + PIO2 = 0.5 * PI; + MPIO2 = -PIO2; + PIO4 = 0.5 * PIO2; + MPIO4 = -PIO4; + THPIO4 = 3.0 * PIO4; + MTHPIO4 = -THPIO4; + + nerrors = 0; + ntests = 0; + i = 0; + for (;;) + { + fun1 = test1[i].func; + if (fun1 == NULL) + break; + x1 = *(test1[i].arg1); + y = (*(fun1)) (x1); + answer = *(test1[i].answer); + if (test1[i].thresh == 0) + { + v.d = answer; + u.d = y; + if (memcmp(u.c, v.c, 8) != 0) + { + if( isnan(v.d) && isnan(u.d) ) + goto nxttest1; + goto wrongone; + } + else + goto nxttest1; + } + if (y != answer) + { + e = y - answer; + if (answer != 0.0) + e = e / answer; + if (e < 0) + e = -e; + if (e > test1[i].thresh * MACHEP) + { +wrongone: + printf ("%s (%.16e) = %.16e\n should be %.16e\n", + test1[i].name, x1, y, answer); + nerrors += 1; + } + } +nxttest1: + ntests += 1; + i += 1; + } + + i = 0; + for (;;) + { + fun2 = test2[i].func; + if (fun2 == NULL) + break; + x1 = *(test2[i].arg1); + x2 = *(test2[i].arg2); + y = (*(fun2)) (x1, x2); + answer = *(test2[i].answer); + if (test2[i].thresh == 0) + { + v.d = answer; + u.d = y; + if (memcmp(u.c, v.c, 8) != 0) + { + if( isnan(v.d) && isnan(u.d) ) + goto nxttest2; +#if 0 + if( isnan(v.d) ) + pvec(v.d); + if( isnan(u.d) ) + pvec(u.d); +#endif + goto wrongtwo; + } + else + goto nxttest2; + } + if (y != answer) + { + e = y - answer; + if (answer != 0.0) + e = e / answer; + if (e < 0) + e = -e; + if (e > test2[i].thresh * MACHEP) + { +wrongtwo: + printf ("%s (%.16e, %.16e) = %.16e\n should be %.16e\n", + test2[i].name, x1, x2, y, answer); + nerrors += 1; + } + } +nxttest2: + ntests += 1; + i += 1; + } + + + i = 0; + for (;;) + { + fun3 = test3[i].func; + if (fun3 == NULL) + break; + x1 = *(test3[i].arg1); + k = (*(fun3)) (x1); + ianswer = test3[i].ianswer; + if (k != ianswer) + { + printf ("%s (%.16e) = %d\n should be. %d\n", + test3[i].name, x1, k, ianswer); + nerrors += 1; + } + ntests += 1; + i += 1; + } + + printf ("testvect: %d errors in %d tests\n", nerrors, ntests); + exit (0); +} diff --git a/components/external/espruino/libs/math/exp.c b/components/external/espruino/libs/math/exp.c new file mode 100644 index 0000000000..aaababd468 --- /dev/null +++ b/components/external/espruino/libs/math/exp.c @@ -0,0 +1,203 @@ +/* exp.c + * + * Exponential function + * + * + * + * SYNOPSIS: + * + * double x, y, exp(); + * + * y = exp( x ); + * + * + * + * DESCRIPTION: + * + * Returns e (2.71828...) raised to the x power. + * + * Range reduction is accomplished by separating the argument + * into an integer k and fraction f such that + * + * x k f + * e = 2 e. + * + * A Pade' form 1 + 2x P(x**2)/( Q(x**2) - P(x**2) ) + * of degree 2/3 is used to approximate exp(f) in the basic + * interval [-0.5, 0.5]. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC +- 88 50000 2.8e-17 7.0e-18 + * IEEE +- 708 40000 2.0e-16 5.6e-17 + * + * + * Error amplification in the exponential function can be + * a serious matter. The error propagation involves + * exp( X(1+delta) ) = exp(X) ( 1 + X*delta + ... ), + * which shows that a 1 lsb error in representing X produces + * a relative error of X times 1 lsb in the function. + * While the routine gives an accurate result for arguments + * that are exactly represented by a double precision + * computer number, the result contains amplified roundoff + * error for large arguments not exactly represented. + * + * + * ERROR MESSAGES: + * + * message condition value returned + * exp underflow x < MINLOG 0.0 + * exp overflow x > MAXLOG INFINITY + * + */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + + +/* Exponential function */ + +#include "mconf.h" + +#ifdef UNK + +const static double P[] = { + 1.26177193074810590878E-4, + 3.02994407707441961300E-2, + 9.99999999999999999910E-1, +}; +const static double Q[] = { + 3.00198505138664455042E-6, + 2.52448340349684104192E-3, + 2.27265548208155028766E-1, + 2.00000000000000000009E0, +}; +const static double C1 = 6.93145751953125E-1; +const static double C2 = 1.42860682030941723212E-6; +#endif + +#ifdef DEC +static unsigned short P[] = { +0035004,0047156,0127442,0057502, +0036770,0033210,0063121,0061764, +0040200,0000000,0000000,0000000, +}; +static unsigned short Q[] = { +0033511,0072665,0160662,0176377, +0036045,0070715,0124105,0132777, +0037550,0134114,0142077,0001637, +0040400,0000000,0000000,0000000, +}; +static unsigned short sc1[] = {0040061,0071000,0000000,0000000}; +#define C1 (*(double *)sc1) +static unsigned short sc2[] = {0033277,0137216,0075715,0057117}; +#define C2 (*(double *)sc2) +#endif + +#ifdef IBMPC +static unsigned short P[] = { +0x4be8,0xd5e4,0x89cd,0x3f20, +0x2c7e,0x0cca,0x06d1,0x3f9f, +0x0000,0x0000,0x0000,0x3ff0, +}; +static unsigned short Q[] = { +0x5fa0,0xbc36,0x2eb6,0x3ec9, +0xb6c0,0xb508,0xae39,0x3f64, +0xe074,0x9887,0x1709,0x3fcd, +0x0000,0x0000,0x0000,0x4000, +}; +static unsigned short sc1[] = {0x0000,0x0000,0x2e40,0x3fe6}; +#define C1 (*(double *)sc1) +static unsigned short sc2[] = {0xabca,0xcf79,0xf7d1,0x3eb7}; +#define C2 (*(double *)sc2) +#endif + +#ifdef MIEEE +static unsigned short P[] = { +0x3f20,0x89cd,0xd5e4,0x4be8, +0x3f9f,0x06d1,0x0cca,0x2c7e, +0x3ff0,0x0000,0x0000,0x0000, +}; +static unsigned short Q[] = { +0x3ec9,0x2eb6,0xbc36,0x5fa0, +0x3f64,0xae39,0xb508,0xb6c0, +0x3fcd,0x1709,0x9887,0xe074, +0x4000,0x0000,0x0000,0x0000, +}; +static unsigned short sc1[] = {0x3fe6,0x2e40,0x0000,0x0000}; +#define C1 (*(double *)sc1) +static unsigned short sc2[] = {0x3eb7,0xf7d1,0xcf79,0xabca}; +#define C2 (*(double *)sc2) +#endif + +#ifdef ANSIPROT +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern double floor ( double ); +extern double ldexp ( double, int ); +extern int isnan ( double ); +extern int isfinite ( double ); +#else +double polevl(), p1evl(), floor(), ldexp(); +int isnan(), isfinite(); +#endif +extern double LOGE2, LOG2E, MAXLOG, MINLOG, MAXNUM; +#ifdef INFINITIES +extern double INFINITY; +#endif + +double exp(x) +double x; +{ +double px, xx; +int n; + +#ifdef NANS +if( isnan(x) ) + return(x); +#endif +if( x > MAXLOG) + { +#ifdef INFINITIES + return( INFINITY ); +#else + mtherr( "exp", OVERFLOW ); + return( MAXNUM ); +#endif + } + +if( x < MINLOG ) + { +#ifndef INFINITIES + mtherr( "exp", UNDERFLOW ); +#endif + return(0.0); + } + +/* Express e**x = e**g 2**n + * = e**g e**( n loge(2) ) + * = e**( g + n loge(2) ) + */ +px = floor( LOG2E * x + 0.5 ); /* floor() truncates toward -infinity. */ +n = px; +x -= px * C1; +x -= px * C2; + +/* rational approximation for exponential + * of the fractional part: + * e**x = 1 + 2x P(x**2)/( Q(x**2) - P(x**2) ) + */ +xx = x * x; +px = x * polevl( xx, P, 2 ); +x = px/( polevl( xx, Q, 3 ) - px ); +x = 1.0 + 2.0 * x; + +/* multiply by power of 2 */ +x = ldexp( x, n ); +return(x); +} diff --git a/components/external/espruino/libs/math/exp10.c b/components/external/espruino/libs/math/exp10.c new file mode 100644 index 0000000000..955608a3ba --- /dev/null +++ b/components/external/espruino/libs/math/exp10.c @@ -0,0 +1,223 @@ +/* exp10.c + * + * Base 10 exponential function + * (Common antilogarithm) + * + * + * + * SYNOPSIS: + * + * double x, y, exp10(); + * + * y = exp10( x ); + * + * + * + * DESCRIPTION: + * + * Returns 10 raised to the x power. + * + * Range reduction is accomplished by expressing the argument + * as 10**x = 2**n 10**f, with |f| < 0.5 log10(2). + * The Pade' form + * + * 1 + 2x P(x**2)/( Q(x**2) - P(x**2) ) + * + * is used to approximate 10**f. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -307,+307 30000 2.2e-16 5.5e-17 + * Test result from an earlier version (2.1): + * DEC -38,+38 70000 3.1e-17 7.0e-18 + * + * ERROR MESSAGES: + * + * message condition value returned + * exp10 underflow x < -MAXL10 0.0 + * exp10 overflow x > MAXL10 MAXNUM + * + * DEC arithmetic: MAXL10 = 38.230809449325611792. + * IEEE arithmetic: MAXL10 = 308.2547155599167. + * + */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1991, 2000 by Stephen L. Moshier +*/ + + +#include "mconf.h" + +#ifdef UNK +const static double P[] = { + 4.09962519798587023075E-2, + 1.17452732554344059015E1, + 4.06717289936872725516E2, + 2.39423741207388267439E3, +}; +const static double Q[] = { +/* 1.00000000000000000000E0,*/ + 8.50936160849306532625E1, + 1.27209271178345121210E3, + 2.07960819286001865907E3, +}; +/* const static double LOG102 = 3.01029995663981195214e-1; */ +const static double LOG210 = 3.32192809488736234787e0; +const static double LG102A = 3.01025390625000000000E-1; +const static double LG102B = 4.60503898119521373889E-6; +/* const static double MAXL10 = 38.230809449325611792; */ +const static double MAXL10 = 308.2547155599167; +#endif + +#ifdef DEC +static unsigned short P[] = { +0037047,0165657,0114061,0067234, +0041073,0166243,0123052,0144643, +0042313,0055720,0024032,0047443, +0043025,0121714,0070232,0050007, +}; +static unsigned short Q[] = { +/*0040200,0000000,0000000,0000000,*/ +0041652,0027756,0071216,0050075, +0042637,0001367,0077263,0136017, +0043001,0174673,0024157,0133416, +}; +/* +static unsigned short L102[] = {0037632,0020232,0102373,0147770}; +#define LOG102 *(double *)L102 +*/ +static unsigned short L210[] = {0040524,0115170,0045715,0015613}; +#define LOG210 *(double *)L210 +static unsigned short L102A[] = {0037632,0020000,0000000,0000000,}; +#define LG102A *(double *)L102A +static unsigned short L102B[] = {0033632,0102373,0147767,0114220,}; +#define LG102B *(double *)L102B +static unsigned short MXL[] = {0041430,0166131,0047761,0154130,}; +#define MAXL10 ( *(double *)MXL ) +#endif + +#ifdef IBMPC +static unsigned short P[] = { +0x2dd4,0xf306,0xfd75,0x3fa4, +0x5934,0x74c5,0x7d94,0x4027, +0x49e4,0x0503,0x6b7a,0x4079, +0x4a01,0x8e13,0xb479,0x40a2, +}; +static unsigned short Q[] = { +/*0x0000,0x0000,0x0000,0x3ff0,*/ +0xca08,0xce51,0x45fd,0x4055, +0x7782,0xefd6,0xe05e,0x4093, +0xf6e2,0x650d,0x3f37,0x40a0, +}; +/* +static unsigned short L102[] = {0x79ff,0x509f,0x4413,0x3fd3}; +#define LOG102 *(double *)L102 +*/ +static unsigned short L210[] = {0xa371,0x0979,0x934f,0x400a}; +#define LOG210 *(double *)L210 +static unsigned short L102A[] = {0x0000,0x0000,0x4400,0x3fd3,}; +#define LG102A *(double *)L102A +static unsigned short L102B[] = {0xf312,0x79fe,0x509f,0x3ed3,}; +#define LG102B *(double *)L102B +const static double MAXL10 = 308.2547155599167; +#endif + +#ifdef MIEEE +static unsigned short P[] = { +0x3fa4,0xfd75,0xf306,0x2dd4, +0x4027,0x7d94,0x74c5,0x5934, +0x4079,0x6b7a,0x0503,0x49e4, +0x40a2,0xb479,0x8e13,0x4a01, +}; +static unsigned short Q[] = { +/*0x3ff0,0x0000,0x0000,0x0000,*/ +0x4055,0x45fd,0xce51,0xca08, +0x4093,0xe05e,0xefd6,0x7782, +0x40a0,0x3f37,0x650d,0xf6e2, +}; +/* +static unsigned short L102[] = {0x3fd3,0x4413,0x509f,0x79ff}; +#define LOG102 *(double *)L102 +*/ +static unsigned short L210[] = {0x400a,0x934f,0x0979,0xa371}; +#define LOG210 *(double *)L210 +static unsigned short L102A[] = {0x3fd3,0x4400,0x0000,0x0000,}; +#define LG102A *(double *)L102A +static unsigned short L102B[] = {0x3ed3,0x509f,0x79fe,0xf312,}; +#define LG102B *(double *)L102B +const static double MAXL10 = 308.2547155599167; +#endif + +#ifdef ANSIPROT +extern double floor ( double ); +extern double ldexp ( double, int ); +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern int isnan ( double ); +extern int isfinite ( double ); +#else +double floor(), ldexp(), polevl(), p1evl(); +int isnan(), isfinite(); +#endif +extern double MAXNUM; +#ifdef INFINITIES +extern double INFINITY; +#endif + +double exp10(x) +double x; +{ +double px, xx; +short n; + +#ifdef NANS +if( isnan(x) ) + return(x); +#endif +if( x > MAXL10 ) + { +#ifdef INFINITIES + return( INFINITY ); +#else + mtherr( "exp10", OVERFLOW ); + return( MAXNUM ); +#endif + } + +if( x < -MAXL10 ) /* Would like to use MINLOG but can't */ + { +#ifndef INFINITIES + mtherr( "exp10", UNDERFLOW ); +#endif + return(0.0); + } + +/* Express 10**x = 10**g 2**n + * = 10**g 10**( n log10(2) ) + * = 10**( g + n log10(2) ) + */ +px = floor( LOG210 * x + 0.5 ); +n = px; +x -= px * LG102A; +x -= px * LG102B; + +/* rational approximation for exponential + * of the fractional part: + * 10**x = 1 + 2x P(x**2)/( Q(x**2) - P(x**2) ) + */ +xx = x * x; +px = x * polevl( xx, P, 3 ); +x = px/( p1evl( xx, Q, 3 ) - px ); +x = 1.0 + ldexp( x, 1 ); + +/* multiply by power of 2 */ +x = ldexp( x, n ); + +return(x); +} diff --git a/components/external/espruino/libs/math/exp2.c b/components/external/espruino/libs/math/exp2.c new file mode 100644 index 0000000000..ad619cf82c --- /dev/null +++ b/components/external/espruino/libs/math/exp2.c @@ -0,0 +1,183 @@ +/* exp2.c + * + * Base 2 exponential function + * + * + * + * SYNOPSIS: + * + * double x, y, exp2(); + * + * y = exp2( x ); + * + * + * + * DESCRIPTION: + * + * Returns 2 raised to the x power. + * + * Range reduction is accomplished by separating the argument + * into an integer k and fraction f such that + * x k f + * 2 = 2 2. + * + * A Pade' form + * + * 1 + 2x P(x**2) / (Q(x**2) - x P(x**2) ) + * + * approximates 2**x in the basic range [-0.5, 0.5]. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -1022,+1024 30000 1.8e-16 5.4e-17 + * + * + * See exp.c for comments on error amplification. + * + * + * ERROR MESSAGES: + * + * message condition value returned + * exp underflow x < -MAXL2 0.0 + * exp overflow x > MAXL2 MAXNUM + * + * For DEC arithmetic, MAXL2 = 127. + * For IEEE arithmetic, MAXL2 = 1024. + */ + + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + + + +#include "mconf.h" + +#ifdef UNK +const static double P[] = { + 2.30933477057345225087E-2, + 2.02020656693165307700E1, + 1.51390680115615096133E3, +}; +const static double Q[] = { +/* 1.00000000000000000000E0,*/ + 2.33184211722314911771E2, + 4.36821166879210612817E3, +}; +#define MAXL2 1024.0 +#define MINL2 -1024.0 +#endif + +#ifdef DEC +static unsigned short P[] = { +0036675,0027102,0122327,0053227, +0041241,0116724,0115412,0157355, +0042675,0036404,0101733,0132226, +}; +static unsigned short Q[] = { +/*0040200,0000000,0000000,0000000,*/ +0042151,0027450,0077732,0160744, +0043210,0100661,0077550,0056560, +}; +#define MAXL2 127.0 +#define MINL2 -127.0 +#endif + +#ifdef IBMPC +static unsigned short P[] = { +0xead3,0x549a,0xa5c8,0x3f97, +0x5bde,0x9361,0x33ba,0x4034, +0x7693,0x907b,0xa7a0,0x4097, +}; +static unsigned short Q[] = { +/*0x0000,0x0000,0x0000,0x3ff0,*/ +0x5c3c,0x0ffb,0x25e5,0x406d, +0x0bae,0x2fed,0x1036,0x40b1, +}; +#define MAXL2 1024.0 +#define MINL2 -1022.0 +#endif + +#ifdef MIEEE +static unsigned short P[] = { +0x3f97,0xa5c8,0x549a,0xead3, +0x4034,0x33ba,0x9361,0x5bde, +0x4097,0xa7a0,0x907b,0x7693, +}; +static unsigned short Q[] = { +/*0x3ff0,0x0000,0x0000,0x0000,*/ +0x406d,0x25e5,0x0ffb,0x5c3c, +0x40b1,0x1036,0x2fed,0x0bae, +}; +#define MAXL2 1024.0 +#define MINL2 -1022.0 +#endif + +#ifdef ANSIPROT +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern double floor ( double ); +extern double ldexp ( double, int ); +extern int isnan ( double ); +extern int isfinite ( double ); +#else +double polevl(), p1evl(), floor(), ldexp(); +int isnan(), isfinite(); +#endif +#ifdef INFINITIES +extern double INFINITY; +#endif +extern double MAXNUM; + +double exp2(x) +double x; +{ +double px, xx; +short n; + +#ifdef NANS +if( isnan(x) ) + return(x); +#endif +if( x > MAXL2) + { +#ifdef INFINITIES + return( INFINITY ); +#else + mtherr( "exp2", OVERFLOW ); + return( MAXNUM ); +#endif + } + +if( x < MINL2 ) + { +#ifndef INFINITIES + mtherr( "exp2", UNDERFLOW ); +#endif + return(0.0); + } + +xx = x; /* save x */ +/* separate into integer and fractional parts */ +px = floor(x+0.5); +n = px; +x = x - px; + +/* rational approximation + * exp2(x) = 1 + 2xP(xx)/(Q(xx) - P(xx)) + * where xx = x**2 + */ +xx = x * x; +px = x * polevl( xx, P, 2 ); +x = px / ( p1evl( xx, Q, 2 ) - px ); +x = 1.0 + ldexp( x, 1 ); + +/* scale by power of 2 */ +x = ldexp( x, n ); +return(x); +} diff --git a/components/external/espruino/libs/math/fabs.c b/components/external/espruino/libs/math/fabs.c new file mode 100644 index 0000000000..f674c6142d --- /dev/null +++ b/components/external/espruino/libs/math/fabs.c @@ -0,0 +1,56 @@ +/* fabs.c + * + * Absolute value + * + * + * + * SYNOPSIS: + * + * double x, y; + * + * y = fabs( x ); + * + * + * + * DESCRIPTION: + * + * Returns the absolute value of the argument. + * + */ + + +#include "mconf.h" +/* Avoid using UNK if possible. */ +#ifdef UNK +#if BIGENDIAN +#define MIEEE 1 +#else +#define IBMPC 1 +#endif +#endif + +double fabs(x) +double x; +{ +union + { + double d; + short i[4]; + } u; + +u.d = x; +#ifdef IBMPC + u.i[3] &= 0x7fff; +#endif +#ifdef MIEEE + u.i[0] &= 0x7fff; +#endif +#ifdef DEC + u.i[3] &= 0x7fff; +#endif +#ifdef UNK +if( u.d < 0 ) + u.d = -u.d; +#endif +return( u.d ); +} diff --git a/components/external/espruino/libs/math/floor.c b/components/external/espruino/libs/math/floor.c new file mode 100644 index 0000000000..1df98b1e79 --- /dev/null +++ b/components/external/espruino/libs/math/floor.c @@ -0,0 +1,453 @@ +/* ceil() + * floor() + * frexp() + * ldexp() + * signbit() + * isnan() + * isfinite() + * + * Floating point numeric utilities + * + * + * + * SYNOPSIS: + * + * double ceil(), floor(), frexp(), ldexp(); + * int signbit(), isnan(), isfinite(); + * double x, y; + * int expnt, n; + * + * y = floor(x); + * y = ceil(x); + * y = frexp( x, &expnt ); + * y = ldexp( x, n ); + * n = signbit(x); + * n = isnan(x); + * n = isfinite(x); + * + * + * + * DESCRIPTION: + * + * All four routines return a double precision floating point + * result. + * + * floor() returns the largest integer less than or equal to x. + * It truncates toward minus infinity. + * + * ceil() returns the smallest integer greater than or equal + * to x. It truncates toward plus infinity. + * + * frexp() extracts the exponent from x. It returns an integer + * power of two to expnt and the significand between 0.5 and 1 + * to y. Thus x = y * 2**expn. + * + * ldexp() multiplies x by 2**n. + * + * signbit(x) returns 1 if the sign bit of x is 1, else 0. + * + * These functions are part of the standard C run time library + * for many but not all C compilers. The ones supplied are + * written in C for either DEC or IEEE arithmetic. They should + * be used only if your compiler library does not already have + * them. + * + * The IEEE versions assume that denormal numbers are implemented + * in the arithmetic. Some modifications will be required if + * the arithmetic has abrupt rather than gradual underflow. + */ + + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + + +#include "mconf.h" + +#ifdef UNK +/* ceil(), floor(), frexp(), ldexp() may need to be rewritten. */ +#undef UNK +#if BIGENDIAN +#define MIEEE 1 +#else +#define IBMPC 1 +#endif +#endif + +#ifdef DEC +#define EXPMSK 0x807f +#define MEXP 255 +#define NBITS 56 +#endif + +#ifdef IBMPC +#define EXPMSK 0x800f +#define MEXP 0x7ff +#define NBITS 53 +#endif + +#ifdef MIEEE +#define EXPMSK 0x800f +#define MEXP 0x7ff +#define NBITS 53 +#endif + +extern double MAXNUM, NEGZERO; +#ifdef ANSIPROT +double floor ( double ); +int isnan ( double ); +int isfinite ( double ); +double ldexp ( double, int ); +#else +double floor(); +int isnan(), isfinite(); +double ldexp(); +#endif + +double ceil(x) +double x; +{ +double y; + +#ifdef UNK +mtherr( "ceil", DOMAIN ); +return(0.0); +#endif +#ifdef NANS +if( isnan(x) ) + return( x ); +#endif +#ifdef INFINITIES +if(!isfinite(x)) + return(x); +#endif + +y = floor(x); +if( y < x ) + y += 1.0; +#ifdef MINUSZERO +if( y == 0.0 && x < 0.0 ) + return( NEGZERO ); +#endif +return(y); +} + + + + +/* Bit clearing masks: */ + +static unsigned short bmask[] = { +0xffff, +0xfffe, +0xfffc, +0xfff8, +0xfff0, +0xffe0, +0xffc0, +0xff80, +0xff00, +0xfe00, +0xfc00, +0xf800, +0xf000, +0xe000, +0xc000, +0x8000, +0x0000, +}; + + + + + +double floor(x) +double x; +{ +union + { + double y; + unsigned short sh[4]; + } u; +unsigned short *p; +int e; + +#ifdef UNK +mtherr( "floor", DOMAIN ); +return(0.0); +#endif +#ifdef NANS +if( isnan(x) ) + return( x ); +#endif +#ifdef INFINITIES +if(!isfinite(x)) + return(x); +#endif +#ifdef MINUSZERO +if(x == 0.0L) + return(x); +#endif +u.y = x; +/* find the exponent (power of 2) */ +#ifdef DEC +p = (unsigned short *)&u.sh[0]; +e = (( *p >> 7) & 0377) - 0201; +p += 3; +#endif + +#ifdef IBMPC +p = (unsigned short *)&u.sh[3]; +e = (( *p >> 4) & 0x7ff) - 0x3ff; +p -= 3; +#endif + +#ifdef MIEEE +p = (unsigned short *)&u.sh[0]; +e = (( *p >> 4) & 0x7ff) - 0x3ff; +p += 3; +#endif + +if( e < 0 ) + { + if( u.y < 0.0 ) + return( -1.0 ); + else + return( 0.0 ); + } + +e = (NBITS -1) - e; +/* clean out 16 bits at a time */ +while( e >= 16 ) + { +#ifdef IBMPC + *p++ = 0; +#endif + +#ifdef DEC + *p-- = 0; +#endif + +#ifdef MIEEE + *p-- = 0; +#endif + e -= 16; + } + +/* clear the remaining bits */ +if( e > 0 ) + *p &= bmask[e]; + +if( (x < 0) && (u.y != x) ) + u.y -= 1.0; + +return(u.y); +} + + + + +double frexp( x, pw2 ) +double x; +int *pw2; +{ +union + { + double y; + unsigned short sh[4]; + } u; +int i; +#ifdef DENORMAL +int k; +#endif +short *q; + +u.y = x; + +#ifdef UNK +mtherr( "frexp", DOMAIN ); +return(0.0); +#endif + +#ifdef IBMPC +q = (short *)&u.sh[3]; +#endif + +#ifdef DEC +q = (short *)&u.sh[0]; +#endif + +#ifdef MIEEE +q = (short *)&u.sh[0]; +#endif + +/* find the exponent (power of 2) */ +#ifdef DEC +i = ( *q >> 7) & 0377; +if( i == 0 ) + { + *pw2 = 0; + return(0.0); + } +i -= 0200; +*pw2 = i; +*q &= 0x807f; /* strip all exponent bits */ +*q |= 040000; /* mantissa between 0.5 and 1 */ +return(u.y); +#endif + +#ifdef IBMPC +i = ( *q >> 4) & 0x7ff; +if( i != 0 ) + goto ieeedon; +#endif + +#ifdef MIEEE +i = *q >> 4; +i &= 0x7ff; +if( i != 0 ) + goto ieeedon; +#ifdef DENORMAL + +#else +*pw2 = 0; +return(0.0); +#endif + +#endif + + +#ifndef DEC +/* Number is denormal or zero */ +#ifdef DENORMAL +if( u.y == 0.0 ) + { + *pw2 = 0; + return( 0.0 ); + } + + +/* Handle denormal number. */ +do + { + u.y *= 2.0; + i -= 1; + k = ( *q >> 4) & 0x7ff; + } +while( k == 0 ); +i = i + k; +#endif /* DENORMAL */ + +ieeedon: + +i -= 0x3fe; +*pw2 = i; +*q &= 0x800f; +*q |= 0x3fe0; +return( u.y ); +#endif +} + + + + + + + +double ldexp( x, pw2 ) +double x; +int pw2; +{ +union + { + double y; + unsigned short sh[4]; + } u; +short *q; +int e; + +#ifdef UNK +mtherr( "ldexp", DOMAIN ); +return(0.0); +#endif + +u.y = x; +#ifdef DEC +q = (short *)&u.sh[0]; +e = ( *q >> 7) & 0377; +if( e == 0 ) + return(0.0); +#else + +#ifdef IBMPC +q = (short *)&u.sh[3]; +#endif +#ifdef MIEEE +q = (short *)&u.sh[0]; +#endif +while( (e = (*q & 0x7ff0) >> 4) == 0 ) + { + if( u.y == 0.0 ) + { + return( 0.0 ); + } +/* Input is denormal. */ + if( pw2 > 0 ) + { + u.y *= 2.0; + pw2 -= 1; + } + if( pw2 < 0 ) + { + if( pw2 < -53 ) + return(0.0); + u.y /= 2.0; + pw2 += 1; + } + if( pw2 == 0 ) + return(u.y); + } +#endif /* not DEC */ + +e += pw2; + +/* Handle overflow */ +#ifdef DEC +if( e > MEXP ) + return( MAXNUM ); +#else +if( e >= MEXP ) + return( 2.0*MAXNUM ); +#endif + +/* Handle denormalized results */ +if( e < 1 ) + { +#ifdef DENORMAL + if( e < -53 ) + return(0.0); + *q &= 0x800f; + *q |= 0x10; + /* For denormals, significant bits may be lost even + when dividing by 2. Construct 2^-(1-e) so the result + is obtained with only one multiplication. */ + u.y *= ldexp(1.0, e-1); + return(u.y); +#else + return(0.0); +#endif + } +else + { +#ifdef DEC + *q &= 0x807f; /* strip all exponent bits */ + *q |= (e & 0xff) << 7; +#else + *q &= 0x800f; + *q |= (e & 0x7ff) << 4; +#endif + return(u.y); + } +} diff --git a/components/external/espruino/libs/math/ftilib.mak b/components/external/espruino/libs/math/ftilib.mak new file mode 100644 index 0000000000..80cc596572 --- /dev/null +++ b/components/external/espruino/libs/math/ftilib.mak @@ -0,0 +1,289 @@ +# MSDOS Microsoft C makefile for Cephes library +CFLAGS=/c +# For large memory model: +#CFLAGS=/c /AL +# Add /FPa to the CFLAGS if you want to use the fast software FPa arithmetic. +# +# Use the following with /FPa if you do not want to use the 80x87 coprocessor +# or software emulator. +#polevl.obj: polevl.c mconf.h +# cl /c /Ox polevl.c +# +# Use the following instead if you want to use an 80x87 chip or +# software emulator for maximum accuracy computation of the +# polynomial expansions: +polevl.obj: polevl.asm mconf.h + masm polevl.asm/r; + +floor.obj: floor.asm + masm floor.asm; + +#floor.obj: floor.c mconf.h +# cl $(CFLAGS) floor.c + +acosh.obj: acosh.c mconf.h + cl $(CFLAGS) acosh.c + +airy.obj: airy.c mconf.h + cl $(CFLAGS) airy.c + +asin.obj: asin.c mconf.h + cl $(CFLAGS) asin.c + +asinh.obj: asinh.c mconf.h + cl $(CFLAGS) asinh.c + +atan.obj: atan.c mconf.h + cl $(CFLAGS) atan.c + +atanh.obj: atanh.c mconf.h + cl $(CFLAGS) atanh.c + +asinh.obj: asinh.c mconf.h + cl $(CFLAGS) asinh.c + +bdtr.obj: bdtr.c mconf.h + cl $(CFLAGS) bdtr.c + +beta.obj: beta.c mconf.h + cl $(CFLAGS) beta.c + +btdtr.obj: btdtr.c mconf.h + cl $(CFLAGS) btdtr.c + +cbrt.obj: cbrt.c mconf.h + cl $(CFLAGS) cbrt.c + +chbevl.obj: chbevl.c mconf.h + cl $(CFLAGS) chbevl.c + +chdtr.obj: chdtr.c mconf.h + cl $(CFLAGS) chdtr.c + +clog.obj: clog.c mconf.h + cl $(CFLAGS) clog.c + +cmplx.obj: cmplx.c mconf.h + cl $(CFLAGS) cmplx.c + +const.obj: const.c mconf.h + cl $(CFLAGS) const.c + +cosh.obj: cosh.c mconf.h + cl $(CFLAGS) cosh.c + +dawsn.obj: dawsn.c mconf.h + cl $(CFLAGS) dawsn.c + +drand.obj: drand.c mconf.h + cl $(CFLAGS) drand.c + +ellie.obj: ellie.c mconf.h + cl $(CFLAGS) ellie.c + +ellik.obj: ellik.c mconf.h + cl $(CFLAGS) ellik.c + +ellpe.obj: ellpe.c mconf.h + cl $(CFLAGS) ellpe.c + +ellpj.obj: ellpj.c mconf.h + cl $(CFLAGS) ellpj.c + +ellpk.obj: ellpk.c mconf.h + cl $(CFLAGS) ellpk.c + +exp.obj: exp.c mconf.h + cl $(CFLAGS) exp.c + +exp10.obj: exp10.c mconf.h + cl $(CFLAGS) exp10.c + +exp2.obj: exp2.c mconf.h + cl $(CFLAGS) exp2.c + +expn.obj: expn.c mconf.h + cl $(CFLAGS) expn.c + +fabs.obj: fabs.c mconf.h + cl $(CFLAGS) fabs.c + +fac.obj: fac.c mconf.h + cl $(CFLAGS) fac.c + +fdtr.obj: fdtr.c mconf.h + cl $(CFLAGS) fdtr.c + +fresnl.obj: fresnl.c mconf.h + cl $(CFLAGS) fresnl.c + +gamma.obj: gamma.c mconf.h + cl $(CFLAGS) gamma.c + +gdtr.obj: gdtr.c mconf.h + cl $(CFLAGS) gdtr.c + +hyp2f1.obj: hyp2f1.c mconf.h + cl $(CFLAGS) hyp2f1.c + +hyperg.obj: hyperg.c mconf.h + cl $(CFLAGS) hyperg.c + +i0.obj: i0.c mconf.h + cl $(CFLAGS) i0.c + +i1.obj: i1.c mconf.h + cl $(CFLAGS) i1.c + +igam.obj: igam.c mconf.h + cl $(CFLAGS) igam.c + +igami.obj: igami.c mconf.h + cl $(CFLAGS) igami.c + +incbet.obj: incbet.c mconf.h + cl $(CFLAGS) incbet.c + +incbi.obj: incbi.c mconf.h + cl $(CFLAGS) incbi.c + +isnan.obj: isnan.c mconf.h + cl $(CFLAGS) isnan.c + +iv.obj: iv.c mconf.h + cl $(CFLAGS) iv.c + +j0.obj: j0.c mconf.h + cl $(CFLAGS) j0.c + +j1.obj: j1.c mconf.h + cl $(CFLAGS) j1.c + +jn.obj: jn.c mconf.h + cl $(CFLAGS) jn.c + +jv.obj: jv.c mconf.h + cl $(CFLAGS) jv.c + +k0.obj: k0.c mconf.h + cl $(CFLAGS) k0.c + +k1.obj: k1.c mconf.h + cl $(CFLAGS) k1.c + +kn.obj: kn.c mconf.h + cl $(CFLAGS) kn.c + +log.obj: log.c mconf.h + cl $(CFLAGS) log.c + +log2.obj: log2.c mconf.h + cl $(CFLAGS) log2.c + +log10.obj: log10.c mconf.h + cl $(CFLAGS) log10.c + +mtherr.obj: mtherr.c mconf.h + cl $(CFLAGS) mtherr.c + +nbdtr.obj: nbdtr.c mconf.h + cl $(CFLAGS) nbdtr.c + +ndtr.obj: ndtr.c mconf.h + cl $(CFLAGS) ndtr.c + +ndtri.obj: ndtri.c mconf.h + cl $(CFLAGS) ndtri.c + +pdtr.obj: pdtr.c mconf.h + cl $(CFLAGS) pdtr.c + +pow.obj: pow.c mconf.h + cl $(CFLAGS) pow.c + +powi.obj: powi.c mconf.h + cl $(CFLAGS) powi.c + +psi.obj: psi.c mconf.h + cl $(CFLAGS) psi.c + +rgamma.obj: rgamma.c mconf.h + cl $(CFLAGS) rgamma.c + +round.obj: round.c mconf.h + cl $(CFLAGS) round.c + +setprec.obj: setprec.87 + masm setprec.87; + +shichi.obj: shichi.c mconf.h + cl $(CFLAGS) shichi.c + +sici.obj: sici.c mconf.h + cl $(CFLAGS) sici.c + +sin.obj: sin.c mconf.h + cl $(CFLAGS) sin.c + +sindg.obj: sindg.c mconf.h + cl $(CFLAGS) sindg.c + +sinh.obj: sinh.c mconf.h + cl $(CFLAGS) sinh.c + +spence.obj: spence.c mconf.h + cl $(CFLAGS) spence.c + +sqrt.obj: sqrt.87 + masm sqrt.87; + +#sqrt.obj: sqrt.c +# cl $(CFLAGS) sqrt.c + +stdtr.obj: stdtr.c mconf.h + cl $(CFLAGS) stdtr.c + +struve.obj: struve.c mconf.h + cl $(CFLAGS) struve.c + +tan.obj: tan.c mconf.h + cl $(CFLAGS) tan.c + +tandg.obj: tandg.c mconf.h + cl $(CFLAGS) tandg.c + +tanh.obj: tanh.c mconf.h + cl $(CFLAGS) tanh.c + +yn.obj: yn.c mconf.h + cl $(CFLAGS) yn.c + +zeta.obj: zeta.c mconf.h + cl $(CFLAGS) zeta.c + +zetac.obj: zetac.c mconf.h + cl $(CFLAGS) zetac.c + +polyn.obj: polyn.c mconf.h + cl $(CFLAGS) polyn.c + +polmisc.obj: polmisc.c mconf.h + cl $(CFLAGS) polmisc.c + +unity.obj: unity.c mconf.h + cl $(CFLAGS) unity.c + +fti.lib: acosh.obj airy.obj asin.obj asinh.obj atan.obj atanh.obj bdtr.obj \ +beta.obj btdtr.obj cbrt.obj chbevl.obj chdtr.obj clog.obj \ +cmplx.obj const.obj cosh.obj dawsn.obj drand.obj ellie.obj ellik.obj \ +ellpe.obj ellpj.obj ellpk.obj exp.obj exp10.obj \ +exp2.obj expn.obj fabs.obj fac.obj fdtr.obj floor.obj fresnl.obj gamma.obj \ +gdtr.obj hyp2f1.obj hyperg.obj i0.c i1.c igam.c igami.obj incbet.obj \ +incbi.obj isnan.obj iv.obj j0.obj j1.obj jn.obj jv.obj k0.obj k1.obj \ +kn.obj log.obj log2.obj log10.obj mtherr.obj nbdtr.obj ndtr.obj ndtri.obj \ +pdtr.obj polevl.obj polmisc.obj polyn.obj pow.obj powi.obj psi.obj \ +rgamma.obj round.obj shichi.obj sici.obj sin.obj sindg.obj sinh.obj \ +spence.obj sqrt.obj stdtr.obj setprec.obj struve.obj tan.obj \ +tandg.obj tanh.obj unity.obj yn.obj zeta.obj zetac.obj \ +mconf.h + lib @ftilib.rsp diff --git a/components/external/espruino/libs/math/ftilib.rsp b/components/external/espruino/libs/math/ftilib.rsp new file mode 100644 index 0000000000..aa475164a3 --- /dev/null +++ b/components/external/espruino/libs/math/ftilib.rsp @@ -0,0 +1,17 @@ +fti +y +acosh airy asin asinh atan & +atanh bdtr beta btdtr cbrt chbevl & +chdtr clog cmplx const & +cosh dawsn drand ellie ellik ellpe ellpk & +ellpj exp exp2 exp10 expn fac & +fdtr fresnl gamma gdtr & +hyperg hyp2f1 incbet incbi igam igami isnan & +iv i0 i1 jn jv j0 j1 k0 k1 kn log log2 log10 & +mtherr nbdtr ndtr ndtri pdtr & +polmisc polyn pow powi psi & +rgamma round shichi sici sin sindg & +sinh spence sqrt stdtr struve tan tandg & +tanh unity yn zeta zetac floor fabs polevl +fti.lst +fti diff --git a/components/external/espruino/libs/math/isnan.c b/components/external/espruino/libs/math/isnan.c new file mode 100644 index 0000000000..b5341e6505 --- /dev/null +++ b/components/external/espruino/libs/math/isnan.c @@ -0,0 +1,237 @@ +/* isnan() + * signbit() + * isfinite() + * + * Floating point numeric utilities + * + * + * + * SYNOPSIS: + * + * double ceil(), floor(), frexp(), ldexp(); + * int signbit(), isnan(), isfinite(); + * double x, y; + * int expnt, n; + * + * y = floor(x); + * y = ceil(x); + * y = frexp( x, &expnt ); + * y = ldexp( x, n ); + * n = signbit(x); + * n = isnan(x); + * n = isfinite(x); + * + * + * + * DESCRIPTION: + * + * All four routines return a double precision floating point + * result. + * + * floor() returns the largest integer less than or equal to x. + * It truncates toward minus infinity. + * + * ceil() returns the smallest integer greater than or equal + * to x. It truncates toward plus infinity. + * + * frexp() extracts the exponent from x. It returns an integer + * power of two to expnt and the significand between 0.5 and 1 + * to y. Thus x = y * 2**expn. + * + * ldexp() multiplies x by 2**n. + * + * signbit(x) returns 1 if the sign bit of x is 1, else 0. + * + * These functions are part of the standard C run time library + * for many but not all C compilers. The ones supplied are + * written in C for either DEC or IEEE arithmetic. They should + * be used only if your compiler library does not already have + * them. + * + * The IEEE versions assume that denormal numbers are implemented + * in the arithmetic. Some modifications will be required if + * the arithmetic has abrupt rather than gradual underflow. + */ + + +/* +Cephes Math Library Release 2.3: March, 1995 +Copyright 1984, 1995 by Stephen L. Moshier +*/ + + +#include "mconf.h" + +#ifdef UNK +/* ceil(), floor(), frexp(), ldexp() may need to be rewritten. */ +#undef UNK +#if BIGENDIAN +#define MIEEE 1 +#else +#define IBMPC 1 +#endif +#endif + + +/* Return 1 if the sign bit of x is 1, else 0. */ + +int signbit(x) +double x; +{ +union + { + double d; + short s[4]; + int i[2]; + } u; + +u.d = x; + +if( sizeof(int) == 4 ) + { +#ifdef IBMPC + return( u.i[1] < 0 ); +#endif +#ifdef DEC + return( u.s[3] < 0 ); +#endif +#ifdef MIEEE + return( u.i[0] < 0 ); +#endif + } +else + { +#ifdef IBMPC + return( u.s[3] < 0 ); +#endif +#ifdef DEC + return( u.s[3] < 0 ); +#endif +#ifdef MIEEE + return( u.s[0] < 0 ); +#endif + } +} + + +/* Return 1 if x is a number that is Not a Number, else return 0. */ + +int isnan(x) +double x; +{ +#ifdef NANS +union + { + double d; + unsigned short s[4]; + unsigned int i[2]; + } u; + +u.d = x; + +if( sizeof(int) == 4 ) + { +#ifdef IBMPC + if( ((u.i[1] & 0x7ff00000) == 0x7ff00000) + && (((u.i[1] & 0x000fffff) != 0) || (u.i[0] != 0))) + return 1; +#endif +#ifdef DEC + if( (u.s[1] & 0x7fff) == 0) + { + if( (u.s[2] | u.s[1] | u.s[0]) != 0 ) + return(1); + } +#endif +#ifdef MIEEE + if( ((u.i[0] & 0x7ff00000) == 0x7ff00000) + && (((u.i[0] & 0x000fffff) != 0) || (u.i[1] != 0))) + return 1; +#endif + return(0); + } +else + { /* size int not 4 */ +#ifdef IBMPC + if( (u.s[3] & 0x7ff0) == 0x7ff0) + { + if( ((u.s[3] & 0x000f) | u.s[2] | u.s[1] | u.s[0]) != 0 ) + return(1); + } +#endif +#ifdef DEC + if( (u.s[3] & 0x7fff) == 0) + { + if( (u.s[2] | u.s[1] | u.s[0]) != 0 ) + return(1); + } +#endif +#ifdef MIEEE + if( (u.s[0] & 0x7ff0) == 0x7ff0) + { + if( ((u.s[0] & 0x000f) | u.s[1] | u.s[2] | u.s[3]) != 0 ) + return(1); + } +#endif + return(0); + } /* size int not 4 */ + +#else +/* No NANS. */ +return(0); +#endif +} + + +/* Return 1 if x is not infinite and is not a NaN. */ + +int isfinite(x) +double x; +{ +#ifdef INFINITIES +union + { + double d; + unsigned short s[4]; + unsigned int i[2]; + } u; + +u.d = x; + +if( sizeof(int) == 4 ) + { +#ifdef IBMPC + if( (u.i[1] & 0x7ff00000) != 0x7ff00000) + return 1; +#endif +#ifdef DEC + if( (u.s[3] & 0x7fff) != 0) + return 1; +#endif +#ifdef MIEEE + if( (u.i[0] & 0x7ff00000) != 0x7ff00000) + return 1; +#endif + return(0); + } +else + { +#ifdef IBMPC + if( (u.s[3] & 0x7ff0) != 0x7ff0) + return 1; +#endif +#ifdef DEC + if( (u.s[3] & 0x7fff) != 0) + return 1; +#endif +#ifdef MIEEE + if( (u.s[0] & 0x7ff0) != 0x7ff0) + return 1; +#endif + return(0); + } +#else +/* No INFINITY. */ +return(1); +#endif +} diff --git a/components/external/espruino/libs/math/log.c b/components/external/espruino/libs/math/log.c new file mode 100644 index 0000000000..da42a66a7c --- /dev/null +++ b/components/external/espruino/libs/math/log.c @@ -0,0 +1,341 @@ +/* log.c + * + * Natural logarithm + * + * + * + * SYNOPSIS: + * + * double x, y, log(); + * + * y = log( x ); + * + * + * + * DESCRIPTION: + * + * Returns the base e (2.718...) logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z**3 P(z)/Q(z). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 150000 1.44e-16 5.06e-17 + * IEEE +-MAXNUM 30000 1.20e-16 4.78e-17 + * DEC 0, 10 170000 1.8e-17 6.3e-18 + * + * In the tests over the interval [+-MAXNUM], the logarithms + * of the random arguments were uniformly distributed over + * [0, MAXLOG]. + * + * ERROR MESSAGES: + * + * log singularity: x = 0; returns -INFINITY + * log domain: x < 0; returns NAN + */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + +#include "mconf.h" +static char fname[] = {"log"}; + +/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + */ +#ifdef UNK +const static double P[] = { + 1.01875663804580931796E-4, + 4.97494994976747001425E-1, + 4.70579119878881725854E0, + 1.44989225341610930846E1, + 1.79368678507819816313E1, + 7.70838733755885391666E0, +}; +const static double Q[] = { +/* 1.00000000000000000000E0, */ + 1.12873587189167450590E1, + 4.52279145837532221105E1, + 8.29875266912776603211E1, + 7.11544750618563894466E1, + 2.31251620126765340583E1, +}; +#endif + +#ifdef DEC +static unsigned short P[] = { +0037777,0127270,0162547,0057274, +0041001,0054665,0164317,0005341, +0041451,0034104,0031640,0105773, +0041677,0011276,0123617,0160135, +0041701,0126603,0053215,0117250, +0041420,0115777,0135206,0030232, +}; +static unsigned short Q[] = { +/*0040200,0000000,0000000,0000000,*/ +0041220,0144332,0045272,0174241, +0041742,0164566,0035720,0130431, +0042246,0126327,0166065,0116357, +0042372,0033420,0157525,0124560, +0042271,0167002,0066537,0172303, +0041730,0164777,0113711,0044407, +}; +#endif + +#ifdef IBMPC +static unsigned short P[] = { +0x1bb0,0x93c3,0xb4c2,0x3f1a, +0x52f2,0x3f56,0xd6f5,0x3fdf, +0x6911,0xed92,0xd2ba,0x4012, +0xeb2e,0xc63e,0xff72,0x402c, +0xc84d,0x924b,0xefd6,0x4031, +0xdcf8,0x7d7e,0xd563,0x401e, +}; +static unsigned short Q[] = { +/*0x0000,0x0000,0x0000,0x3ff0,*/ +0xef8e,0xae97,0x9320,0x4026, +0xc033,0x4e19,0x9d2c,0x4046, +0xbdbd,0xa326,0xbf33,0x4054, +0xae21,0xeb5e,0xc9e2,0x4051, +0x25b2,0x9e1f,0x200a,0x4037, +}; +#endif + +#ifdef MIEEE +static unsigned short P[] = { +0x3f1a,0xb4c2,0x93c3,0x1bb0, +0x3fdf,0xd6f5,0x3f56,0x52f2, +0x4012,0xd2ba,0xed92,0x6911, +0x402c,0xff72,0xc63e,0xeb2e, +0x4031,0xefd6,0x924b,0xc84d, +0x401e,0xd563,0x7d7e,0xdcf8, +}; +static unsigned short Q[] = { +/*0x3ff0,0x0000,0x0000,0x0000,*/ +0x4026,0x9320,0xae97,0xef8e, +0x4046,0x9d2c,0x4e19,0xc033, +0x4054,0xbf33,0xa326,0xbdbd, +0x4051,0xc9e2,0xeb5e,0xae21, +0x4037,0x200a,0x9e1f,0x25b2, +}; +#endif + +/* Coefficients for log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + */ + +#ifdef UNK +const static double R[3] = { +-7.89580278884799154124E-1, + 1.63866645699558079767E1, +-6.41409952958715622951E1, +}; +const static double S[3] = { +/* 1.00000000000000000000E0,*/ +-3.56722798256324312549E1, + 3.12093766372244180303E2, +-7.69691943550460008604E2, +}; +#endif +#ifdef DEC +static unsigned short R[12] = { +0140112,0020756,0161540,0072035, +0041203,0013743,0114023,0155527, +0141600,0044060,0104421,0050400, +}; +static unsigned short S[12] = { +/*0040200,0000000,0000000,0000000,*/ +0141416,0130152,0017543,0064122, +0042234,0006000,0104527,0020155, +0142500,0066110,0146631,0174731, +}; +#endif +#ifdef IBMPC +static unsigned short R[12] = { +0x0e84,0xdc6c,0x443d,0xbfe9, +0x7b6b,0x7302,0x62fc,0x4030, +0x2a20,0x1122,0x0906,0xc050, +}; +static unsigned short S[12] = { +/*0x0000,0x0000,0x0000,0x3ff0,*/ +0x6d0a,0x43ec,0xd60d,0xc041, +0xe40e,0x112a,0x8180,0x4073, +0x3f3b,0x19b3,0x0d89,0xc088, +}; +#endif +#ifdef MIEEE +static unsigned short R[12] = { +0xbfe9,0x443d,0xdc6c,0x0e84, +0x4030,0x62fc,0x7302,0x7b6b, +0xc050,0x0906,0x1122,0x2a20, +}; +static unsigned short S[12] = { +/*0x3ff0,0x0000,0x0000,0x0000,*/ +0xc041,0xd60d,0x43ec,0x6d0a, +0x4073,0x8180,0x112a,0xe40e, +0xc088,0x0d89,0x19b3,0x3f3b, +}; +#endif + +#ifdef ANSIPROT +extern double frexp ( double, int * ); +extern double ldexp ( double, int ); +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern int isnan ( double ); +extern int isfinite ( double ); +#else +double frexp(), ldexp(), polevl(), p1evl(); +int isnan(), isfinite(); +#endif +#define SQRTH 0.70710678118654752440 +extern double INFINITY, NAN; + +double log(x) +double x; +{ +int e; +#ifdef DEC +short *q; +#endif +double y, z; + +#ifdef NANS +if( isnan(x) ) + return(x); +#endif +#ifdef INFINITIES +if( x == INFINITY ) + return(x); +#endif +/* Test for domain */ +if( x <= 0.0 ) + { + if( x == 0.0 ) + { + mtherr( fname, SING ); + return( -INFINITY ); + } + else + { + mtherr( fname, DOMAIN ); + return( NAN ); + } + } + +/* separate mantissa from exponent */ + +#ifdef DEC +q = (short *)&x; +e = *q; /* short containing exponent */ +e = ((e >> 7) & 0377) - 0200; /* the exponent */ +*q &= 0177; /* strip exponent from x */ +*q |= 040000; /* x now between 0.5 and 1 */ +#endif + +/* Note, frexp is used so that denormal numbers + * will be handled properly. + */ +#ifdef IBMPC +x = frexp( x, &e ); +/* +q = (short *)&x; +q += 3; +e = *q; +e = ((e >> 4) & 0x0fff) - 0x3fe; +*q &= 0x0f; +*q |= 0x3fe0; +*/ +#endif + +/* Equivalent C language standard library function: */ +#ifdef UNK +x = frexp( x, &e ); +#endif + +#ifdef MIEEE +x = frexp( x, &e ); +#endif + + + +/* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ + +if( (e > 2) || (e < -2) ) +{ +if( x < SQRTH ) + { /* 2( 2x-1 )/( 2x+1 ) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } +else + { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + +x = z / y; + + +/* rational form */ +z = x*x; +z = x * ( z * polevl( z, R, 2 ) / p1evl( z, S, 3 ) ); +y = e; +z = z - y * 2.121944400546905827679e-4; +z = z + x; +z = z + e * 0.693359375; +goto ldone; +} + + + +/* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + +if( x < SQRTH ) + { + e -= 1; + x = ldexp( x, 1 ) - 1.0; /* 2x - 1 */ + } +else + { + x = x - 1.0; + } + + +/* rational form */ +z = x*x; +#if DEC +y = x * ( z * polevl( x, P, 5 ) / p1evl( x, Q, 6 ) ); +#else +y = x * ( z * polevl( x, P, 5 ) / p1evl( x, Q, 5 ) ); +#endif +if( e ) + y = y - e * 2.121944400546905827679e-4; +y = y - ldexp( z, -1 ); /* y - 0.5 * z */ +z = x + y; +if( e ) + z = z + e * 0.693359375; + +ldone: + +return( z ); +} diff --git a/components/external/espruino/libs/math/log10.c b/components/external/espruino/libs/math/log10.c new file mode 100644 index 0000000000..473af4a169 --- /dev/null +++ b/components/external/espruino/libs/math/log10.c @@ -0,0 +1,250 @@ +/* log10.c + * + * Common logarithm + * + * + * + * SYNOPSIS: + * + * double x, y, log10(); + * + * y = log10( x ); + * + * + * + * DESCRIPTION: + * + * Returns logarithm to the base 10 of x. + * + * The argument is separated into its exponent and fractional + * parts. The logarithm of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 30000 1.5e-16 5.0e-17 + * IEEE 0, MAXNUM 30000 1.4e-16 4.8e-17 + * DEC 1, MAXNUM 50000 2.5e-17 6.0e-18 + * + * In the tests over the interval [1, MAXNUM], the logarithms + * of the random arguments were uniformly distributed over + * [0, MAXLOG]. + * + * ERROR MESSAGES: + * + * log10 singularity: x = 0; returns -INFINITY + * log10 domain: x < 0; returns NAN + */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + +#include "mconf.h" +static char fname[] = {"log10"}; + +/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + */ +#ifdef UNK +const static double P[] = { + 4.58482948458143443514E-5, + 4.98531067254050724270E-1, + 6.56312093769992875930E0, + 2.97877425097986925891E1, + 6.06127134467767258030E1, + 5.67349287391754285487E1, + 1.98892446572874072159E1 +}; +const static double Q[] = { +/* 1.00000000000000000000E0, */ + 1.50314182634250003249E1, + 8.27410449222435217021E1, + 2.20664384982121929218E2, + 3.07254189979530058263E2, + 2.14955586696422947765E2, + 5.96677339718622216300E1 +}; +#endif + +#ifdef DEC +static unsigned short P[] = { +0034500,0046473,0051374,0135174, +0037777,0037566,0145712,0150321, +0040722,0002426,0031543,0123107, +0041356,0046513,0170752,0004346, +0041562,0071553,0023536,0163343, +0041542,0170221,0024316,0114216, +0041237,0016454,0046611,0104602 +}; +static unsigned short Q[] = { +/*0040200,0000000,0000000,0000000,*/ +0041160,0100260,0067736,0102424, +0041645,0075552,0036563,0147072, +0042134,0125025,0021132,0025320, +0042231,0120211,0046030,0103271, +0042126,0172241,0052151,0120426, +0041556,0125702,0072116,0047103 +}; +#endif + +#ifdef IBMPC +static unsigned short P[] = { +0x974f,0x6a5f,0x09a7,0x3f08, +0x5a1a,0xd979,0xe7ee,0x3fdf, +0x74c9,0xc66c,0x40a2,0x401a, +0x411d,0x7e3d,0xc9a9,0x403d, +0xdcdc,0x64eb,0x4e6d,0x404e, +0xd312,0x2519,0x5e12,0x404c, +0x3130,0x89b1,0xe3a5,0x4033 +}; +static unsigned short Q[] = { +/*0x0000,0x0000,0x0000,0x3ff0,*/ +0xd0a2,0x0dfb,0x1016,0x402e, +0x79c7,0x47ae,0xaf6d,0x4054, +0x455a,0xa44b,0x9542,0x406b, +0x10d7,0x2983,0x3411,0x4073, +0x3423,0x2a8d,0xde94,0x406a, +0xc9c8,0x4e89,0xd578,0x404d +}; +#endif + +#ifdef MIEEE +static unsigned short P[] = { +0x3f08,0x09a7,0x6a5f,0x974f, +0x3fdf,0xe7ee,0xd979,0x5a1a, +0x401a,0x40a2,0xc66c,0x74c9, +0x403d,0xc9a9,0x7e3d,0x411d, +0x404e,0x4e6d,0x64eb,0xdcdc, +0x404c,0x5e12,0x2519,0xd312, +0x4033,0xe3a5,0x89b1,0x3130 +}; +static unsigned short Q[] = { +0x402e,0x1016,0x0dfb,0xd0a2, +0x4054,0xaf6d,0x47ae,0x79c7, +0x406b,0x9542,0xa44b,0x455a, +0x4073,0x3411,0x2983,0x10d7, +0x406a,0xde94,0x2a8d,0x3423, +0x404d,0xd578,0x4e89,0xc9c8 +}; +#endif + +#define SQRTH 0.70710678118654752440 +#define L102A 3.0078125E-1 +#define L102B 2.48745663981195213739E-4 +#define L10EA 4.3359375E-1 +#define L10EB 7.00731903251827651129E-4 + +#ifdef ANSIPROT +extern double frexp ( double, int * ); +extern double ldexp ( double, int ); +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern int isnan ( double ); +extern int isfinite ( double ); +#else +double frexp(), ldexp(), polevl(), p1evl(); +int isnan(), isfinite(); +#endif +extern double LOGE2, SQRT2, INFINITY, NAN; + +double log10(x) +double x; +{ +VOLATILE double z; +double y; +#ifdef DEC +short *q; +#endif +int e; + +#ifdef NANS +if( isnan(x) ) + return(x); +#endif +#ifdef INFINITIES +if( x == INFINITY ) + return(x); +#endif +/* Test for domain */ +if( x <= 0.0 ) + { + if( x == 0.0 ) + { + mtherr( fname, SING ); + return( -INFINITY ); + } + else + { + mtherr( fname, DOMAIN ); + return( NAN ); + } + } + +/* separate mantissa from exponent */ + +#ifdef DEC +q = (short *)&x; +e = *q; /* short containing exponent */ +e = ((e >> 7) & 0377) - 0200; /* the exponent */ +*q &= 0177; /* strip exponent from x */ +*q |= 040000; /* x now between 0.5 and 1 */ +#endif + +#ifdef IBMPC +x = frexp( x, &e ); +/* +q = (short *)&x; +q += 3; +e = *q; +e = ((e >> 4) & 0x0fff) - 0x3fe; +*q &= 0x0f; +*q |= 0x3fe0; +*/ +#endif + +/* Equivalent C language standard library function: */ +#ifdef UNK +x = frexp( x, &e ); +#endif + +#ifdef MIEEE +x = frexp( x, &e ); +#endif + +/* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + +if( x < SQRTH ) + { + e -= 1; + x = ldexp( x, 1 ) - 1.0; /* 2x - 1 */ + } +else + { + x = x - 1.0; + } + + +/* rational form */ +z = x*x; +y = x * ( z * polevl( x, P, 6 ) / p1evl( x, Q, 6 ) ); +y = y - ldexp( z, -1 ); /* y - 0.5 * x**2 */ + +/* multiply log of fraction by log10(e) + * and base 2 exponent by log10(2) + */ +z = (x + y) * L10EB; /* accumulate terms in order of size */ +z += y * L10EA; +z += x * L10EA; +z += e * L102B; +z += e * L102A; + + +return( z ); +} diff --git a/components/external/espruino/libs/math/log2.c b/components/external/espruino/libs/math/log2.c new file mode 100644 index 0000000000..5cf64a67b6 --- /dev/null +++ b/components/external/espruino/libs/math/log2.c @@ -0,0 +1,348 @@ +/* log2.c + * + * Base 2 logarithm + * + * + * + * SYNOPSIS: + * + * double x, y, log2(); + * + * y = log2( x ); + * + * + * + * DESCRIPTION: + * + * Returns the base 2 logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the base e + * logarithm of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z**3 P(z)/Q(z). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 30000 2.0e-16 5.5e-17 + * IEEE exp(+-700) 40000 1.3e-16 4.6e-17 + * + * In the tests over the interval [exp(+-700)], the logarithms + * of the random arguments were uniformly distributed. + * + * ERROR MESSAGES: + * + * log2 singularity: x = 0; returns -INFINITY + * log2 domain: x < 0; returns NAN + */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + +#include "mconf.h" +static char fname[] = {"log2"}; + +/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + */ +#ifdef UNK +const static double P[] = { + 1.01875663804580931796E-4, + 4.97494994976747001425E-1, + 4.70579119878881725854E0, + 1.44989225341610930846E1, + 1.79368678507819816313E1, + 7.70838733755885391666E0, +}; +const static double Q[] = { +/* 1.00000000000000000000E0, */ + 1.12873587189167450590E1, + 4.52279145837532221105E1, + 8.29875266912776603211E1, + 7.11544750618563894466E1, + 2.31251620126765340583E1, +}; +#define LOG2EA 0.44269504088896340735992 +#endif + +#ifdef DEC +static unsigned short P[] = { +0037777,0127270,0162547,0057274, +0041001,0054665,0164317,0005341, +0041451,0034104,0031640,0105773, +0041677,0011276,0123617,0160135, +0041701,0126603,0053215,0117250, +0041420,0115777,0135206,0030232, +}; +static unsigned short Q[] = { +/*0040200,0000000,0000000,0000000,*/ +0041220,0144332,0045272,0174241, +0041742,0164566,0035720,0130431, +0042246,0126327,0166065,0116357, +0042372,0033420,0157525,0124560, +0042271,0167002,0066537,0172303, +0041730,0164777,0113711,0044407, +}; +static unsigned short L[5] = {0037742,0124354,0122560,0057703}; +#define LOG2EA (*(double *)(&L[0])) +#endif + +#ifdef IBMPC +static unsigned short P[] = { +0x1bb0,0x93c3,0xb4c2,0x3f1a, +0x52f2,0x3f56,0xd6f5,0x3fdf, +0x6911,0xed92,0xd2ba,0x4012, +0xeb2e,0xc63e,0xff72,0x402c, +0xc84d,0x924b,0xefd6,0x4031, +0xdcf8,0x7d7e,0xd563,0x401e, +}; +static unsigned short Q[] = { +/*0x0000,0x0000,0x0000,0x3ff0,*/ +0xef8e,0xae97,0x9320,0x4026, +0xc033,0x4e19,0x9d2c,0x4046, +0xbdbd,0xa326,0xbf33,0x4054, +0xae21,0xeb5e,0xc9e2,0x4051, +0x25b2,0x9e1f,0x200a,0x4037, +}; +static unsigned short L[5] = {0x0bf8,0x94ae,0x551d,0x3fdc}; +#define LOG2EA (*(double *)(&L[0])) +#endif + +#ifdef MIEEE +static unsigned short P[] = { +0x3f1a,0xb4c2,0x93c3,0x1bb0, +0x3fdf,0xd6f5,0x3f56,0x52f2, +0x4012,0xd2ba,0xed92,0x6911, +0x402c,0xff72,0xc63e,0xeb2e, +0x4031,0xefd6,0x924b,0xc84d, +0x401e,0xd563,0x7d7e,0xdcf8, +}; +static unsigned short Q[] = { +/*0x3ff0,0x0000,0x0000,0x0000,*/ +0x4026,0x9320,0xae97,0xef8e, +0x4046,0x9d2c,0x4e19,0xc033, +0x4054,0xbf33,0xa326,0xbdbd, +0x4051,0xc9e2,0xeb5e,0xae21, +0x4037,0x200a,0x9e1f,0x25b2, +}; +static unsigned short L[5] = {0x3fdc,0x551d,0x94ae,0x0bf8}; +#define LOG2EA (*(double *)(&L[0])) +#endif + +/* Coefficients for log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + */ + +#ifdef UNK +const static double R[3] = { +-7.89580278884799154124E-1, + 1.63866645699558079767E1, +-6.41409952958715622951E1, +}; +const static double S[3] = { +/* 1.00000000000000000000E0,*/ +-3.56722798256324312549E1, + 3.12093766372244180303E2, +-7.69691943550460008604E2, +}; +/* log2(e) - 1 */ +#define LOG2EA 0.44269504088896340735992 +#endif +#ifdef DEC +static unsigned short R[12] = { +0140112,0020756,0161540,0072035, +0041203,0013743,0114023,0155527, +0141600,0044060,0104421,0050400, +}; +static unsigned short S[12] = { +/*0040200,0000000,0000000,0000000,*/ +0141416,0130152,0017543,0064122, +0042234,0006000,0104527,0020155, +0142500,0066110,0146631,0174731, +}; +/* log2(e) - 1 */ +#define LOG2EA 0.44269504088896340735992L +#endif +#ifdef IBMPC +static unsigned short R[12] = { +0x0e84,0xdc6c,0x443d,0xbfe9, +0x7b6b,0x7302,0x62fc,0x4030, +0x2a20,0x1122,0x0906,0xc050, +}; +static unsigned short S[12] = { +/*0x0000,0x0000,0x0000,0x3ff0,*/ +0x6d0a,0x43ec,0xd60d,0xc041, +0xe40e,0x112a,0x8180,0x4073, +0x3f3b,0x19b3,0x0d89,0xc088, +}; +#endif +#ifdef MIEEE +static unsigned short R[12] = { +0xbfe9,0x443d,0xdc6c,0x0e84, +0x4030,0x62fc,0x7302,0x7b6b, +0xc050,0x0906,0x1122,0x2a20, +}; +static unsigned short S[12] = { +/*0x3ff0,0x0000,0x0000,0x0000,*/ +0xc041,0xd60d,0x43ec,0x6d0a, +0x4073,0x8180,0x112a,0xe40e, +0xc088,0x0d89,0x19b3,0x3f3b, +}; +#endif + +#ifdef ANSIPROT +extern double frexp ( double, int * ); +extern double ldexp ( double, int ); +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern int isnan ( double ); +extern int isfinite ( double ); +#else +double frexp(), ldexp(), polevl(), p1evl(); +int isnan(), isfinite(); +#endif +#define SQRTH 0.70710678118654752440 +extern double LOGE2, INFINITY, NAN; + +double log2(x) +double x; +{ +int e; +double y; +VOLATILE double z; +#ifdef DEC +short *q; +#endif + +#ifdef NANS +if( isnan(x) ) + return(x); +#endif +#ifdef INFINITIES +if( x == INFINITY ) + return(x); +#endif +/* Test for domain */ +if( x <= 0.0 ) + { + if( x == 0.0 ) + { + mtherr( fname, SING ); + return( -INFINITY ); + } + else + { + mtherr( fname, DOMAIN ); + return( NAN ); + } + } + +/* separate mantissa from exponent */ + +#ifdef DEC +q = (short *)&x; +e = *q; /* short containing exponent */ +e = ((e >> 7) & 0377) - 0200; /* the exponent */ +*q &= 0177; /* strip exponent from x */ +*q |= 040000; /* x now between 0.5 and 1 */ +#endif + +/* Note, frexp is used so that denormal numbers + * will be handled properly. + */ +#ifdef IBMPC +x = frexp( x, &e ); +/* +q = (short *)&x; +q += 3; +e = *q; +e = ((e >> 4) & 0x0fff) - 0x3fe; +*q &= 0x0f; +*q |= 0x3fe0; +*/ +#endif + +/* Equivalent C language standard library function: */ +#ifdef UNK +x = frexp( x, &e ); +#endif + +#ifdef MIEEE +x = frexp( x, &e ); +#endif + + +/* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ + +if( (e > 2) || (e < -2) ) +{ +if( x < SQRTH ) + { /* 2( 2x-1 )/( 2x+1 ) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } +else + { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + +x = z / y; +z = x*x; +y = x * ( z * polevl( z, R, 2 ) / p1evl( z, S, 3 ) ); +goto ldone; +} + + + +/* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + +if( x < SQRTH ) + { + e -= 1; + x = ldexp( x, 1 ) - 1.0; /* 2x - 1 */ + } +else + { + x = x - 1.0; + } + +z = x*x; +#if DEC +y = x * ( z * polevl( x, P, 5 ) / p1evl( x, Q, 6 ) ) - ldexp( z, -1 ); +#else +y = x * ( z * polevl( x, P, 5 ) / p1evl( x, Q, 5 ) ) - ldexp( z, -1 ); +#endif + +ldone: + +/* Multiply log of fraction by log2(e) + * and base 2 exponent by 1 + * + * ***CAUTION*** + * + * This sequence of operations is critical and it may + * be horribly defeated by some compiler optimizers. + */ +z = y * LOG2EA; +z += x * LOG2EA; +z += y; +z += x; +z += e; +return( z ); +} diff --git a/components/external/espruino/libs/math/mconf.h b/components/external/espruino/libs/math/mconf.h new file mode 100644 index 0000000000..83539f9bc6 --- /dev/null +++ b/components/external/espruino/libs/math/mconf.h @@ -0,0 +1,199 @@ +/* mconf.h + * + * Common include file for math routines + * + * + * + * SYNOPSIS: + * + * #include "mconf.h" + * + * + * + * DESCRIPTION: + * + * This file contains definitions for error codes that are + * passed to the common error handling routine mtherr() + * (which see). + * + * The file also includes a conditional assembly definition + * for the type of computer arithmetic (IEEE, DEC, Motorola + * IEEE, or UNKnown). + * + * For Digital Equipment PDP-11 and VAX computers, certain + * IBM systems, and others that use numbers with a 56-bit + * significand, the symbol DEC should be defined. In this + * mode, most floating point constants are given as arrays + * of octal integers to eliminate decimal to binary conversion + * errors that might be introduced by the compiler. + * + * For little-endian computers, such as IBM PC, that follow the + * IEEE Standard for Binary Floating Point Arithmetic (ANSI/IEEE + * Std 754-1985), the symbol IBMPC should be defined. These + * numbers have 53-bit significands. In this mode, constants + * are provided as arrays of hexadecimal 16 bit integers. + * + * Big-endian IEEE format is denoted MIEEE. On some RISC + * systems such as Sun SPARC, double precision constants + * must be stored on 8-byte address boundaries. Since integer + * arrays may be aligned differently, the MIEEE configuration + * may fail on such machines. + * + * To accommodate other types of computer arithmetic, all + * constants are also provided in a normal decimal radix + * which one can hope are correctly converted to a suitable + * format by the available C language compiler. To invoke + * this mode, define the symbol UNK. + * + * An important difference among these modes is a predefined + * set of machine arithmetic constants for each. The numbers + * MACHEP (the machine roundoff error), MAXNUM (largest number + * represented), and several other parameters are preset by + * the configuration symbol. Check the file const.c to + * ensure that these values are correct for your computer. + * + * Configurations NANS, INFINITIES, MINUSZERO, and DENORMAL + * may fail on many systems. Verify that they are supposed + * to work on your computer. + */ +/* +Cephes Math Library Release 2.3: June, 1995 +Copyright 1984, 1987, 1989, 1995 by Stephen L. Moshier +*/ + + +/* Define if the `long double' type works. */ +#define HAVE_LONG_DOUBLE 1 + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define if floating point words are bigendian. */ +/* #undef FLOAT_WORDS_BIGENDIAN */ + +/* The number of bytes in a int. */ +#define SIZEOF_INT 4 + +/* Define if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Name of package */ +#define PACKAGE "cephes" + +/* Version number of package */ +#define VERSION "2.7" + +/* Constant definitions for math error conditions + */ + +#define DOMAIN 1 /* argument domain error */ +#define SING 2 /* argument singularity */ +#define OVERFLOW 3 /* overflow range error */ +#define UNDERFLOW 4 /* underflow range error */ +#define TLOSS 5 /* total loss of precision */ +#define PLOSS 6 /* partial loss of precision */ + +#define EDOM 33 +#define ERANGE 34 +/* Complex numeral. */ +typedef struct + { + double r; + double i; + } cmplx; + +#ifdef HAVE_LONG_DOUBLE +/* Long double complex numeral. */ +typedef struct + { + long double r; + long double i; + } cmplxl; +#endif + + +/* Type of computer arithmetic */ + +/* PDP-11, Pro350, VAX: + */ +/* #define DEC 1 */ + +/* Intel IEEE, low order words come first: + */ +/* #define IBMPC 1 */ + +/* Motorola IEEE, high order words come first + * (Sun 680x0 workstation): + */ +/* #define MIEEE 1 */ + +/* UNKnown arithmetic, invokes coefficients given in + * normal decimal format. Beware of range boundary + * problems (MACHEP, MAXLOG, etc. in const.c) and + * roundoff problems in pow.c: + * (Sun SPARCstation) + */ +#define UNK 1 + +/* If you define UNK, then be sure to set BIGENDIAN properly. */ +#ifdef FLOAT_WORDS_BIGENDIAN +#define BIGENDIAN 1 +#else +#define BIGENDIAN 0 +#endif +/* Define this `volatile' if your compiler thinks + * that floating point arithmetic obeys the associative + * and distributive laws. It will defeat some optimizations + * (but probably not enough of them). + * + * #define VOLATILE volatile + */ +#define VOLATILE + +/* For 12-byte long doubles on an i386, pad a 16-bit short 0 + * to the end of real constants initialized by integer arrays. + * + * #define XPD 0, + * + * Otherwise, the type is 10 bytes long and XPD should be + * defined blank (e.g., Microsoft C). + * + * #define XPD + */ +#define XPD 0, + +/* Define to support tiny denormal numbers, else undefine. */ +#define DENORMAL 1 + +/* Define to ask for infinity support, else undefine. */ +#define INFINITIES 1 + +/* Define to ask for support of numbers that are Not-a-Number, + else undefine. This may automatically define INFINITIES in some files. */ +#define NANS 1 + +/* Define to distinguish between -0.0 and +0.0. */ +#define MINUSZERO 1 + +/* Define 1 for ANSI C atan2() function + See atan.c and clog.c. */ +#define ANSIC 1 + +/* Get ANSI function prototypes, if you want them. */ +#if 1 +/* #ifdef __STDC__ */ +#define ANSIPROT 1 +int mtherr ( char *, int ); +#else +int mtherr(); +#endif + +/* Variable for error reporting. See mtherr.c. */ +extern int merror; diff --git a/components/external/espruino/libs/math/mod2pi.c b/components/external/espruino/libs/math/mod2pi.c new file mode 100644 index 0000000000..88341a68bd --- /dev/null +++ b/components/external/espruino/libs/math/mod2pi.c @@ -0,0 +1,122 @@ +/* Program to test range reduction of trigonometry functions + * + * -- Steve Moshier + */ + +#include "mconf.h" +#ifdef ANSIPROT +extern double floor ( double ); +extern double ldexp ( double, int ); +extern double sin ( double ); +#else +double floor(), ldexp(), sin(); +#endif + +#define TPI 6.283185307179586476925 + +main() +{ +char s[40]; +double a, n, t, x, y, z; +int lflg; + +x = TPI/4.0; +t = 1.0; + +loop: + +t = 2.0 * t; + +/* Stop testing at a point beyond which the integer part of + * x/2pi cannot be represented exactly by a double precision number. + * The library trigonometry functions will probably give up long before + * this point is reached. + */ +if( t > 1.0e16 ) + exit(0); + +/* Adjust the following to choose a nontrivial x + * where test function(x) has a slope of about 1 or more. + */ +x = TPI * t + 0.5; + +z = x; +lflg = 0; + +inlup: + +/* floor() returns the largest integer less than its argument. + * If you do not have this, or AINT(), then you may convert x/TPI + * to a long integer and then back to double; but in that case + * x will be limited to the largest value that will fit into a + * long integer. + */ +n = floor( z/TPI ); + +/* Carefully subtract 2 pi n from x. + * This is done by subtracting n * 2**k in such a way that there + * is no arithmetic cancellation error at any step. The k are the + * bits in the number 2 pi. + * + * If you do not have ldexp(), then you may multiply or + * divide n by an appropriate power of 2 after each step. + * For example: + * a = z - 4*n; + * a -= 2*n; + * n /= 4; + * a -= n; n/4 + * n /= 8; + * a -= n; n/32 + * etc. + * This will only work if division by a power of 2 is exact. + */ + +a = z - ldexp(n, 2); /* 4n */ +a -= ldexp( n, 1); /* 2n */ +a -= ldexp( n, -2 ); /* n/4 */ +a -= ldexp( n, -5 ); /* n/32 */ +a -= ldexp( n, -9 ); /* n/512 */ +a += ldexp( n, -15 ); /* add n/32768 */ +a -= ldexp( n, -17 ); /* n/131072 */ +a -= ldexp( n, -18 ); +a -= ldexp( n, -20 ); +a -= ldexp( n, -22 ); +a -= ldexp( n, -24 ); +a -= ldexp( n, -28 ); +a -= ldexp( n, -32 ); +a -= ldexp( n, -37 ); +a -= ldexp( n, -39 ); +a -= ldexp( n, -40 ); +a -= ldexp( n, -42 ); +a -= ldexp( n, -46 ); +a -= ldexp( n, -47 ); + +/* Subtract what is left of 2 pi n after all the above reductions. + */ +a -= 2.44929359829470635445e-16 * n; + +/* If the test is extended too far, it is possible + * to have chosen the wrong value of n. The following + * will fix that, but at some reduction in accuracy. + */ +if( (a > TPI) || (a < -1e-11) ) + { + z = a; + lflg += 1; + printf( "Warning! Reduction failed on first try.\n" ); + goto inlup; + } +if( a < 0.0 ) + { + printf( "Warning! Reduced value < 0\n" ); + a += TPI; + } + +/* Compute the test function at x and at a = x mod 2 pi. + */ +y = sin(x); +z = sin(a); +printf( "sin(%.15e) error = %.3e\n", x, y-z ); +goto loop; +} + diff --git a/components/external/espruino/libs/math/mtherr.c b/components/external/espruino/libs/math/mtherr.c new file mode 100644 index 0000000000..9f44660c7b --- /dev/null +++ b/components/external/espruino/libs/math/mtherr.c @@ -0,0 +1,103 @@ +/* mtherr.c + * + * Library common error handling routine + * + * + * + * SYNOPSIS: + * + * char *fctnam; + * int code; + * int mtherr(); + * + * mtherr( fctnam, code ); + * + * + * + * DESCRIPTION: + * + * This routine may be called to report one of the following + * error conditions (in the include file mconf.h). + * + * Mnemonic Value Significance + * + * DOMAIN 1 argument domain error + * SING 2 function singularity + * OVERFLOW 3 overflow range error + * UNDERFLOW 4 underflow range error + * TLOSS 5 total loss of precision + * PLOSS 6 partial loss of precision + * EDOM 33 Unix domain error code + * ERANGE 34 Unix range error code + * + * The default version of the file prints the function name, + * passed to it by the pointer fctnam, followed by the + * error condition. The display is directed to the standard + * output device. The routine then returns to the calling + * program. Users may wish to modify the program to abort by + * calling exit() under severe error conditions such as domain + * errors. + * + * Since all error conditions pass control to this function, + * the display may be easily changed, eliminated, or directed + * to an error logging device. + * + * SEE ALSO: + * + * mconf.h + * + */ + +/* +Cephes Math Library Release 2.0: April, 1987 +Copyright 1984, 1987 by Stephen L. Moshier +Direct inquiries to 30 Frost Street, Cambridge, MA 02140 +*/ +#if 0 +#include +#endif +#include "mconf.h" + +int merror = 0; + +/* Notice: the order of appearance of the following + * messages is bound to the error codes defined + * in mconf.h. + */ +static char *ermsg[7] = { +"unknown", /* error code 0 */ +"domain", /* error code 1 */ +"singularity", /* et seq. */ +"overflow", +"underflow", +"total loss of precision", +"partial loss of precision" +}; + + +int mtherr( name, code ) +char *name; +int code; +{ +#if 0 +/* Display string passed by calling program, + * which is supposed to be the name of the + * function in which the error occurred: + */ +printf( "\n%s ", name ); + +/* Set global error message word */ +merror = code; + +/* Display error message defined + * by the code argument. + */ +if( (code <= 0) || (code >= 7) ) + code = 0; +printf( "%s error\n", ermsg[code] ); +#endif +/* Return to calling + * program + */ +return( 0 ); +} diff --git a/components/external/espruino/libs/math/mtst.c b/components/external/espruino/libs/math/mtst.c new file mode 100644 index 0000000000..fbc392e98b --- /dev/null +++ b/components/external/espruino/libs/math/mtst.c @@ -0,0 +1,518 @@ +/* mtst.c + Consistency tests for math functions. + To get strict rounding rules on a 386 or 68000 computer, + define SETPREC to 1. + + With NTRIALS=10000, the following are typical results for + IEEE double precision arithmetic. + +Consistency test of math functions. +Max and rms relative errors for 10000 random arguments. +x = cbrt( cube(x) ): max = 0.00E+00 rms = 0.00E+00 +x = atan( tan(x) ): max = 2.21E-16 rms = 3.27E-17 +x = sin( asin(x) ): max = 2.13E-16 rms = 2.95E-17 +x = sqrt( square(x) ): max = 0.00E+00 rms = 0.00E+00 +x = log( exp(x) ): max = 1.11E-16 A rms = 4.35E-18 A +x = tanh( atanh(x) ): max = 2.22E-16 rms = 2.43E-17 +x = asinh( sinh(x) ): max = 2.05E-16 rms = 3.49E-18 +x = acosh( cosh(x) ): max = 1.43E-15 A rms = 1.54E-17 A +x = log10( exp10(x) ): max = 5.55E-17 A rms = 1.27E-18 A +x = pow( pow(x,a),1/a ): max = 7.60E-14 rms = 1.05E-15 +x = cos( acos(x) ): max = 2.22E-16 A rms = 6.90E-17 A +*/ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 2000 by Stephen L. Moshier +*/ + + +#include +#include +#include "mconf.h" + +#ifndef NTRIALS +#define NTRIALS 10000 +#endif + +/* C9X spells lgam lgamma. */ +#define GLIBC2 0 +#define GLIBC2r1 0 + +#define SETPREC 1 +#define STRTST 0 + +#define WTRIALS (NTRIALS/5) + +#if GLIBC2 +double PI = 3.141592653589793238462643; +double PIO2 = 3.141592653589793238462643 * 0.5; +double MAXLOG = 7.09782712893383996732224E2; +#else +extern double PI; +extern double PIO2; +extern double MAXLOG; +#endif + +extern double MINLOG; +/* +define MINLOG -170.0 +define MAXLOG +170.0 +define PI 3.14159265358979323846 +define PIO2 1.570796326794896619 +*/ + +#ifdef ANSIPROT +extern double fabs ( double ); +extern double sqrt ( double ); +extern double cbrt ( double ); +extern double exp ( double ); +extern double log ( double ); +extern double exp10 ( double ); +extern double log10 ( double ); +extern double tan ( double ); +extern double atan ( double ); +extern double sin ( double ); +extern double asin ( double ); +extern double cos ( double ); +extern double acos ( double ); +extern double pow ( double, double ); +extern double tanh ( double ); +extern double atanh ( double ); +extern double sinh ( double ); +extern double asinh ( double x ); +extern double cosh ( double ); +extern double acosh ( double ); +extern double gamma ( double ); +extern double lgam ( double ); +extern double jn ( int, double ); +extern double yn ( int, double ); +extern double ndtr ( double ); +extern double ndtri ( double ); +extern double stdtr ( int, double ); +extern double stdtri ( int, double ); +extern double ellpe ( double ); +extern double ellpk ( double ); +#else +double fabs(), sqrt(), cbrt(), exp(), log(); +double exp10(), log10(), tan(), atan(); +double sin(), asin(), cos(), acos(), pow(); +double tanh(), atanh(), sinh(), asinh(), cosh(), acosh(); +double gamma(), lgam(), jn(), yn(), ndtrl(), ndtril(); +double stdtrl(), stdtril(), ellpel(), ellpkl(); +#endif + +#if GLIBC2 +extern double lgamma (double); +extern double tgamma ( double ); +#endif + +#if SETPREC +int dprec(); +#endif + +int drand(); +/* void exit(); */ +/* int printf(); */ + + +/* Provide inverses for square root and cube root: */ +double square(x) +double x; +{ +return( x * x ); +} + +double cube(x) +double x; +{ +return( x * x * x ); +} + +/* lookup table for each function */ +struct fundef + { + char *nam1; /* the function */ + double (*name )(); + char *nam2; /* its inverse */ + double (*inv )(); + int nargs; /* number of function arguments */ + int tstyp; /* type code of the function */ + long ctrl; /* relative error flag */ + double arg1w; /* width of domain for 1st arg */ + double arg1l; /* lower bound domain 1st arg */ + long arg1f; /* flags, e.g. integer arg */ + double arg2w; /* same info for args 2, 3, 4 */ + double arg2l; + long arg2f; +/* + double arg3w; + double arg3l; + long arg3f; + double arg4w; + double arg4l; + long arg4f; +*/ + }; + + +/* fundef.ctrl bits: */ +#define RELERR 1 + +/* fundef.tstyp test types: */ +#define POWER 1 +#define ELLIP 2 +#define GAMMA 3 +#define WRONK1 4 +#define WRONK2 5 +#define WRONK3 6 +#define STDTR 7 + +/* fundef.argNf argument flag bits: */ +#define INT 2 +#define EXPSCAL 4 + +#if GLIBC2r1 +#define NTESTS 12 +#else +#if GLIBC2 +#define NTESTS 13 +#else +#define NTESTS 17 +#endif +#endif + +struct fundef defs[NTESTS] = { +{" cube", cube, " cbrt", cbrt, 1, 0, 1, 2002.0, -1001.0, 0, +0.0, 0.0, 0}, +{" tan", tan, " atan", atan, 1, 0, 1, 0.0, 0.0, 0, +0.0, 0.0, 0}, +{" asin", asin, " sin", sin, 1, 0, 1, 2.0, -1.0, 0, +0.0, 0.0, 0}, +{"square", square, " sqrt", sqrt, 1, 0, 1, 170.0, -85.0, EXPSCAL, +0.0, 0.0, 0}, +{" exp", exp, " log", log, 1, 0, 0, 340.0, -170.0, 0, +0.0, 0.0, 0}, +{" atanh", atanh, " tanh", tanh, 1, 0, 1, 2.0, -1.0, 0, +0.0, 0.0, 0}, +{" sinh", sinh, " asinh", asinh, 1, 0, 1, 340.0, 0.0, 0, +0.0, 0.0, 0}, +{" cosh", cosh, " acosh", acosh, 1, 0, 0, 340.0, 0.0, 0, +0.0, 0.0, 0}, +#if !GLIBC2r1 +{" exp10", exp10, " log10", log10, 1, 0, 0, 340.0, -170.0, 0, +0.0, 0.0, 0}, +#endif +{"pow", pow, "pow", pow, 2, POWER, 1, 21.0, 0.0, 0, +42.0, -21.0, 0}, +{" acos", acos, " cos", cos, 1, 0, 0, 2.0, -1.0, 0, +0.0, 0.0, 0}, +#if GLIBC2 +#if !GLIBC2r1 +{ "tgamma", tgamma, "lgamma", lgamma, 1, GAMMA, 0, 34.0, 0.0, 0, +0.0, 0.0, 0}, +#endif +#else +{ "gamma", gamma, "lgam", lgam, 1, GAMMA, 0, 34.0, 0.0, 0, +0.0, 0.0, 0}, +#endif +{ " Jn", jn, " Yn", yn, 2, WRONK1, 0, 30.0, 0.1, 0, +40.0, -20.0, INT}, +#if !GLIBC2 +{ " ndtr", ndtr, " ndtri", ndtri, 1, 0, 1, 10.0L, -10.0L, 0, +0.0, 0.0, 0}, +{ " ndtri", ndtri, " ndtr", ndtr, 1, 0, 1, 1.0L, 0.0L, 0, +0.0, 0.0, 0}, +{" ellpe", ellpe, " ellpk", ellpk, 1, ELLIP, 0, 1.0L, 0.0L, 0, +0.0, 0.0, 0}, +{ "stdtr", stdtr, "stdtri", stdtri, 2, STDTR, 1, 4.0L, -2.0L, 0, +30.0, 1.0, INT}, +#endif +}; + +static char *headrs[] = { +"x = %s( %s(x) ): ", +"x = %s( %s(x,a),1/a ): ", /* power */ +"Legendre %s, %s: ", /* ellip */ +"%s(x) = log(%s(x)): ", /* gamma */ +"Wronksian of %s, %s: ", +"Wronksian of %s, %s: ", +"Wronksian of %s, %s: ", +"x = %s(%s(k,x) ): ", /* stdtr */ +}; + +const static double yy1 = 0.0; +const static double y2 = 0.0; +const static double y3 = 0.0; +const static double y4 = 0.0; +const static double a = 0.0; +const static double x = 0.0; +const static double y = 0.0; +const static double z = 0.0; +const static double e = 0.0; +const static double max = 0.0; +const static double rmsa = 0.0; +const static double rms = 0.0; +const static double ave = 0.0; + + +int main() +{ +double (*fun )(); +double (*ifun )(); +struct fundef *d; +int i, k, itst; +int m, ntr; + +#if SETPREC +dprec(); /* set coprocessor precision */ +#endif +ntr = NTRIALS; +printf( "Consistency test of math functions.\n" ); +printf( "Max and rms relative errors for %d random arguments.\n", + ntr ); + +/* Initialize machine dependent parameters: */ +defs[1].arg1w = PI; +defs[1].arg1l = -PI/2.0; +/* Microsoft C has trouble with denormal numbers. */ +#if 0 +defs[3].arg1w = MAXLOG; +defs[3].arg1l = -MAXLOG/2.0; +defs[4].arg1w = 2*MAXLOG; +defs[4].arg1l = -MAXLOG; +#endif +defs[6].arg1w = 2.0*MAXLOG; +defs[6].arg1l = -MAXLOG; +defs[7].arg1w = MAXLOG; +defs[7].arg1l = 0.0; + + +/* Outer loop, on the test number: */ + +for( itst=STRTST; itstname; +ifun = d->inv; + +/* Absolute error criterion starts with gamma function + * (put all such at end of table) + */ +#if 0 +if( d->tstyp == GAMMA ) + printf( "Absolute error criterion (but relative if >1):\n" ); +#endif + +/* Smaller number of trials for Wronksians + * (put them at end of list) + */ +#if 0 +if( d->tstyp == WRONK1 ) + { + ntr = WTRIALS; + printf( "Absolute error and only %d trials:\n", ntr ); + } +#endif +if( d->tstyp == STDTR ) + { + ntr = NTRIALS/10; + printf( "Relative error and only %d trials:\n", ntr ); + } +printf( headrs[d->tstyp], d->nam2, d->nam1 ); + +for( i=0; inargs ) +{ + +default: +goto illegn; + +case 2: +drand( &a ); +a = d->arg2w * ( a - 1.0 ) + d->arg2l; +if( d->arg2f & EXPSCAL ) + { + a = exp(a); + drand( &y2 ); + a -= 1.0e-13 * a * y2; + } +if( d->arg2f & INT ) + { + k = a + 0.25; + a = k; + } + +case 1: +drand( &x ); +x = d->arg1w * ( x - 1.0 ) + d->arg1l; +if( d->arg1f & EXPSCAL ) + { + x = exp(x); + drand( &a ); + x += 1.0e-13 * x * a; + } +} + + +/* compute function under test */ +switch( d->nargs ) + { + case 1: + switch( d->tstyp ) + { + case ELLIP: + yy1 = ( *(fun) )(x); + y2 = ( *(fun) )(1.0-x); + y3 = ( *(ifun) )(x); + y4 = ( *(ifun) )(1.0-x); + break; + + case GAMMA: +#if GLIBC2 + y = lgamma(x); + x = log( tgamma(x) ); +#else + y = lgam(x); + x = log( gamma(x) ); +#endif + break; + + default: + z = ( *(fun) )(x); + y = ( *(ifun) )(z); + } + break; + + case 2: + if( d->arg2f & INT ) + { + switch( d->tstyp ) + { + case WRONK1: + yy1 = (*fun)( k, x ); /* jn */ + y2 = (*fun)( k+1, x ); + y3 = (*ifun)( k, x ); /* yn */ + y4 = (*ifun)( k+1, x ); + break; + + case WRONK2: + yy1 = (*fun)( a, x ); /* iv */ + y2 = (*fun)( a+1.0, x ); + y3 = (*ifun)( k, x ); /* kn */ + y4 = (*ifun)( k+1, x ); + break; + + default: + z = (*fun)( k, x ); + y = (*ifun)( k, z ); + } + } + else + { + if( d->tstyp == POWER ) + { + z = (*fun)( x, a ); + y = (*ifun)( z, 1.0/a ); + } + else + { + z = (*fun)( a, x ); + y = (*ifun)( a, z ); + } + } + break; + + + default: +illegn: + printf( "Illegal nargs= %d", d->nargs ); + exit(1); + } + +switch( d->tstyp ) + { + case WRONK1: + e = (y2*y3 - yy1*y4) - 2.0/(PI*x); /* Jn, Yn */ + break; + + case WRONK2: + e = (y2*y3 + yy1*y4) - 1.0/x; /* In, Kn */ + break; + + case ELLIP: + e = (yy1-y3)*y4 + y3*y2 - PIO2; + break; + + default: + e = y - x; + break; + } + +if( d->ctrl & RELERR ) + e /= x; +else + { + if( fabs(x) > 1.0 ) + e /= x; + } + +ave += e; +/* absolute value of error */ +if( e < 0 ) + e = -e; + +/* peak detect the error */ +if( e > max ) + { + max = e; + + if( e > 1.0e-10 ) + { + printf("x %.6E z %.6E y %.6E max %.4E\n", + x, z, y, max); + if( d->tstyp == POWER ) + { + printf( "a %.6E\n", a ); + } + if( d->tstyp >= WRONK1 ) + { + printf( "yy1 %.4E y2 %.4E y3 %.4E y4 %.4E k %d x %.4E\n", + yy1, y2, y3, y4, k, x ); + } + } + +/* + printf("%.8E %.8E %.4E %6ld \n", x, y, max, n); + printf("%d %.8E %.8E %.4E %6ld \n", k, x, y, max, n); + printf("%.6E %.6E %.6E %.4E %6ld \n", a, x, y, max, n); + printf("%.6E %.6E %.6E %.6E %.4E %6ld \n", a, b, x, y, max, n); + printf("%.4E %.4E %.4E %.4E %.4E %.4E %6ld \n", + a, b, c, x, y, max, n); +*/ + } + +/* accumulate rms error */ +e *= 1.0e16; /* adjust range */ +rmsa += e * e; /* accumulate the square of the error */ +} + +/* report after NTRIALS trials */ +rms = 1.0e-16 * sqrt( rmsa/m ); +if(d->ctrl & RELERR) + printf(" max = %.2E rms = %.2E\n", max, rms ); +else + printf(" max = %.2E A rms = %.2E A\n", max, rms ); +} /* loop on itst */ + +exit(0); +} diff --git a/components/external/espruino/libs/math/mtst.opt b/components/external/espruino/libs/math/mtst.opt new file mode 100644 index 0000000000..2276dbac6e --- /dev/null +++ b/components/external/espruino/libs/math/mtst.opt @@ -0,0 +1,30 @@ +acosh.obj,- +asin.obj,- +asinh.obj,- +atan.obj,- +atanh.obj,- +cbrt.obj,- +chbevl.obj,- +const.obj,- +cosh.obj,- +drand.obj,- +exp.obj,- +exp10.obj,- +fabs.obj,- +floor.obj,- +log.obj,- +log10.obj,- +polevl.obj,- +pow.obj,- +powi.obj,- +round.obj,- +sin.obj,- +sinh.obj,- +tan.obj,- +tanh.obj,- +unity.obj,- +sqrt.obj,- +floor.obj,- +polevl.obj,- +mtherr.obj,- +sys$library:vaxcrtl/lib diff --git a/components/external/espruino/libs/math/polevl.asm b/components/external/espruino/libs/math/polevl.asm new file mode 100644 index 0000000000..47aa7ff70a --- /dev/null +++ b/components/external/espruino/libs/math/polevl.asm @@ -0,0 +1,116 @@ +; Static Name Aliases +; + TITLE polevl + +_TEXT SEGMENT BYTE PUBLIC 'CODE' +_TEXT ENDS +CONST SEGMENT WORD PUBLIC 'CONST' +CONST ENDS +_BSS SEGMENT WORD PUBLIC 'BSS' +_BSS ENDS +_DATA SEGMENT WORD PUBLIC 'DATA' +_DATA ENDS +DGROUP GROUP CONST, _BSS, _DATA + ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP +PUBLIC _polevl +PUBLIC _p1evl +_DATA SEGMENT +EXTRN __chkstk:NEAR +EXTRN __fac:NEAR +EXTRN __fltused:NEAR +$T20001 DQ 0000000000H ; .0000000000000000 +ans DQ 0 +ctrlw DW 0 +_DATA ENDS +_TEXT SEGMENT + PUBLIC _polevl +_polevl PROC NEAR + push bp + mov bp,sp + mov ax,12 + call __chkstk + push si + mov si,[bp+12] +; fstcw ctrlw +; fwait +; mov ax,ctrlw +; or ax,00100h +; mov ctrlw,ax +; fldcw ctrlw + + fldz + fwait + mov ax,[bp+14] + inc ax + mov [bp-12],ax +$D15: + fmul QWORD PTR [bp+4] + add si,8 + fwait + fadd QWORD PTR [si-8] + fwait + dec WORD PTR [bp-12] + jne $D15 + fstp ans +; fstcw ctrlw +; fwait +; mov ax,ctrlw +; and ax,0feffh +; mov ctrlw,ax +; fldcw ctrlw + + lea ax, ans + fwait + pop si + mov sp,bp + pop bp + ret +_polevl ENDP + + PUBLIC _p1evl +_p1evl PROC NEAR + push bp + mov bp,sp + mov ax,12 + call __chkstk + push si + +; fstcw ctrlw +; fwait +; mov ax,ctrlw +; or ax,00100h +; mov ctrlw,ax +; fldcw ctrlw + + mov si,[bp+12] + fld QWORD PTR [bp+4] + add si,8 + fadd QWORD PTR [si-8] + fwait + mov ax,[bp+14] + dec ax + mov [bp-12],ax +$D26: + fmul QWORD PTR [bp+4] + add si,8 + fadd QWORD PTR [si-8] + fwait + dec WORD PTR [bp-12] + jne $D26 + fstp ans + lea ax, ans +; fstcw ctrlw +; fwait +; mov ax,ctrlw +; and ax,0feffh +; mov ctrlw,ax +; fldcw ctrlw + fwait + pop si + mov sp,bp + pop bp + ret +_p1evl ENDP + +_TEXT ENDS +END diff --git a/components/external/espruino/libs/math/polevl.c b/components/external/espruino/libs/math/polevl.c new file mode 100644 index 0000000000..4d050fbfc5 --- /dev/null +++ b/components/external/espruino/libs/math/polevl.c @@ -0,0 +1,97 @@ +/* polevl.c + * p1evl.c + * + * Evaluate polynomial + * + * + * + * SYNOPSIS: + * + * int N; + * double x, y, coef[N+1], polevl[]; + * + * y = polevl( x, coef, N ); + * + * + * + * DESCRIPTION: + * + * Evaluates polynomial of degree N: + * + * 2 N + * y = C + C x + C x +...+ C x + * 0 1 2 N + * + * Coefficients are stored in reverse order: + * + * coef[0] = C , ..., coef[N] = C . + * N 0 + * + * The function p1evl() assumes that coef[N] = 1.0 and is + * omitted from the array. Its calling arguments are + * otherwise the same as polevl(). + * + * + * SPEED: + * + * In the interest of speed, there are no checks for out + * of bounds arithmetic. This routine is used by most of + * the functions in the library. Depending on available + * equipment features, the user may wish to rewrite the + * program in microcode or assembly language. + * + */ + + +/* +Cephes Math Library Release 2.1: December, 1988 +Copyright 1984, 1987, 1988 by Stephen L. Moshier +Direct inquiries to 30 Frost Street, Cambridge, MA 02140 +*/ + + +double polevl( x, coef, N ) +double x; +double coef[]; +int N; +{ +double ans; +int i; +double *p; + +p = coef; +ans = *p++; +i = N; + +do + ans = ans * x + *p++; +while( --i ); + +return( ans ); +} + +/* p1evl() */ +/* N + * Evaluate polynomial when coefficient of x is 1.0. + * Otherwise same as polevl. + */ + +double p1evl( x, coef, N ) +double x; +double coef[]; +int N; +{ +double ans; +double *p; +int i; + +p = coef; +ans = x + *p++; +i = N-1; + +do + ans = ans * x + *p++; +while( --i ); + +return( ans ); +} diff --git a/components/external/espruino/libs/math/pow.c b/components/external/espruino/libs/math/pow.c new file mode 100644 index 0000000000..d481f7c626 --- /dev/null +++ b/components/external/espruino/libs/math/pow.c @@ -0,0 +1,756 @@ +/* pow.c + * + * Power function + * + * + * + * SYNOPSIS: + * + * double x, y, z, pow(); + * + * z = pow( x, y ); + * + * + * + * DESCRIPTION: + * + * Computes x raised to the yth power. Analytically, + * + * x**y = exp( y log(x) ). + * + * Following Cody and Waite, this program uses a lookup table + * of 2**-i/16 and pseudo extended precision arithmetic to + * obtain an extra three bits of accuracy in both the logarithm + * and the exponential. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -26,26 30000 4.2e-16 7.7e-17 + * DEC -26,26 60000 4.8e-17 9.1e-18 + * 1/26 < x < 26, with log(x) uniformly distributed. + * -26 < y < 26, y uniformly distributed. + * IEEE 0,8700 30000 1.5e-14 2.1e-15 + * 0.99 < x < 1.01, 0 < y < 8700, uniformly distributed. + * + * + * ERROR MESSAGES: + * + * message condition value returned + * pow overflow x**y > MAXNUM INFINITY + * pow underflow x**y < 1/MAXNUM 0.0 + * pow domain x<0 and y noninteger 0.0 + * + */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + + +#include "mconf.h" +static char fname[] = {"pow"}; + +#define SQRTH 0.70710678118654752440 + +#ifdef UNK +const static double P[] = { + 4.97778295871696322025E-1, + 3.73336776063286838734E0, + 7.69994162726912503298E0, + 4.66651806774358464979E0 +}; +const static double Q[] = { +/* 1.00000000000000000000E0, */ + 9.33340916416696166113E0, + 2.79999886606328401649E1, + 3.35994905342304405431E1, + 1.39995542032307539578E1 +}; +/* 2^(-i/16), IEEE precision */ +const static double A[] = { + 1.00000000000000000000E0, + 9.57603280698573700036E-1, + 9.17004043204671215328E-1, + 8.78126080186649726755E-1, + 8.40896415253714502036E-1, + 8.05245165974627141736E-1, + 7.71105412703970372057E-1, + 7.38413072969749673113E-1, + 7.07106781186547572737E-1, + 6.77127773468446325644E-1, + 6.48419777325504820276E-1, + 6.20928906036742001007E-1, + 5.94603557501360513449E-1, + 5.69394317378345782288E-1, + 5.45253866332628844837E-1, + 5.22136891213706877402E-1, + 5.00000000000000000000E-1 +}; +const static double B[] = { + 0.00000000000000000000E0, + 1.64155361212281360176E-17, + 4.09950501029074826006E-17, + 3.97491740484881042808E-17, +-4.83364665672645672553E-17, + 1.26912513974441574796E-17, + 1.99100761573282305549E-17, +-1.52339103990623557348E-17, + 0.00000000000000000000E0 +}; +const static double R[] = { + 1.49664108433729301083E-5, + 1.54010762792771901396E-4, + 1.33335476964097721140E-3, + 9.61812908476554225149E-3, + 5.55041086645832347466E-2, + 2.40226506959099779976E-1, + 6.93147180559945308821E-1 +}; + +#define douba(k) A[k] +#define doubb(k) B[k] +#define MEXP 16383.0 +#ifdef DENORMAL +#define MNEXP -17183.0 +#else +#define MNEXP -16383.0 +#endif +#endif + +#ifdef DEC +static unsigned short P[] = { +0037776,0156313,0175332,0163602, +0040556,0167577,0052366,0174245, +0040766,0062753,0175707,0055564, +0040625,0052035,0131344,0155636, +}; +static unsigned short Q[] = { +/*0040200,0000000,0000000,0000000,*/ +0041025,0052644,0154404,0105155, +0041337,0177772,0007016,0047646, +0041406,0062740,0154273,0020020, +0041137,0177054,0106127,0044555, +}; +static unsigned short A[] = { +0040200,0000000,0000000,0000000, +0040165,0022575,0012444,0103314, +0040152,0140306,0163735,0022071, +0040140,0146336,0166052,0112341, +0040127,0042374,0145326,0116553, +0040116,0022214,0012437,0102201, +0040105,0063452,0010525,0003333, +0040075,0004243,0117530,0006067, +0040065,0002363,0031771,0157145, +0040055,0054076,0165102,0120513, +0040045,0177326,0124661,0050471, +0040036,0172462,0060221,0120422, +0040030,0033760,0050615,0134251, +0040021,0141723,0071653,0010703, +0040013,0112701,0161752,0105727, +0040005,0125303,0063714,0044173, +0040000,0000000,0000000,0000000 +}; +static unsigned short B[] = { +0000000,0000000,0000000,0000000, +0021473,0040265,0153315,0140671, +0121074,0062627,0042146,0176454, +0121413,0003524,0136332,0066212, +0121767,0046404,0166231,0012553, +0121257,0015024,0002357,0043574, +0021736,0106532,0043060,0056206, +0121310,0020334,0165705,0035326, +0000000,0000000,0000000,0000000 +}; + +static unsigned short R[] = { +0034173,0014076,0137624,0115771, +0035041,0076763,0003744,0111311, +0035656,0141766,0041127,0074351, +0036435,0112533,0073611,0116664, +0037143,0054106,0134040,0152223, +0037565,0176757,0176026,0025551, +0040061,0071027,0173721,0147572 +}; + +/* +const static double R[] = { +0.14928852680595608186e-4, +0.15400290440989764601e-3, +0.13333541313585784703e-2, +0.96181290595172416964e-2, +0.55504108664085595326e-1, +0.24022650695909537056e0, +0.69314718055994529629e0 +}; +*/ +#define douba(k) (*(double *)&A[(k)<<2]) +#define doubb(k) (*(double *)&B[(k)<<2]) +#define MEXP 2031.0 +#define MNEXP -2031.0 +#endif + +#ifdef IBMPC +static unsigned short P[] = { +0x5cf0,0x7f5b,0xdb99,0x3fdf, +0xdf15,0xea9e,0xddef,0x400d, +0xeb6f,0x7f78,0xccbd,0x401e, +0x9b74,0xb65c,0xaa83,0x4012, +}; +static unsigned short Q[] = { +/*0x0000,0x0000,0x0000,0x3ff0,*/ +0x914e,0x9b20,0xaab4,0x4022, +0xc9f5,0x41c1,0xffff,0x403b, +0x6402,0x1b17,0xccbc,0x4040, +0xe92e,0x918a,0xffc5,0x402b, +}; +static unsigned short A[] = { +0x0000,0x0000,0x0000,0x3ff0, +0x90da,0xa2a4,0xa4af,0x3fee, +0xa487,0xdcfb,0x5818,0x3fed, +0x529c,0xdd85,0x199b,0x3fec, +0xd3ad,0x995a,0xe89f,0x3fea, +0xf090,0x82a3,0xc491,0x3fe9, +0xa0db,0x422a,0xace5,0x3fe8, +0x0187,0x73eb,0xa114,0x3fe7, +0x3bcd,0x667f,0xa09e,0x3fe6, +0x5429,0xdd48,0xab07,0x3fe5, +0x2a27,0xd536,0xbfda,0x3fe4, +0x3422,0x4c12,0xdea6,0x3fe3, +0xb715,0x0a31,0x06fe,0x3fe3, +0x6238,0x6e75,0x387a,0x3fe2, +0x517b,0x3c7d,0x72b8,0x3fe1, +0x890f,0x6cf9,0xb558,0x3fe0, +0x0000,0x0000,0x0000,0x3fe0 +}; +static unsigned short B[] = { +0x0000,0x0000,0x0000,0x0000, +0x3707,0xd75b,0xed02,0x3c72, +0xcc81,0x345d,0xa1cd,0x3c87, +0x4b27,0x5686,0xe9f1,0x3c86, +0x6456,0x13b2,0xdd34,0xbc8b, +0x42e2,0xafec,0x4397,0x3c6d, +0x82e4,0xd231,0xf46a,0x3c76, +0x8a76,0xb9d7,0x9041,0xbc71, +0x0000,0x0000,0x0000,0x0000 +}; +static unsigned short R[] = { +0x937f,0xd7f2,0x6307,0x3eef, +0x9259,0x60fc,0x2fbe,0x3f24, +0xef1d,0xc84a,0xd87e,0x3f55, +0x33b7,0x6ef1,0xb2ab,0x3f83, +0x1a92,0xd704,0x6b08,0x3fac, +0xc56d,0xff82,0xbfbd,0x3fce, +0x39ef,0xfefa,0x2e42,0x3fe6 +}; + +#define douba(k) (*(double *)&A[(k)<<2]) +#define doubb(k) (*(double *)&B[(k)<<2]) +#define MEXP 16383.0 +#ifdef DENORMAL +#define MNEXP -17183.0 +#else +#define MNEXP -16383.0 +#endif +#endif + +#ifdef MIEEE +static unsigned short P[] = { +0x3fdf,0xdb99,0x7f5b,0x5cf0, +0x400d,0xddef,0xea9e,0xdf15, +0x401e,0xccbd,0x7f78,0xeb6f, +0x4012,0xaa83,0xb65c,0x9b74 +}; +static unsigned short Q[] = { +0x4022,0xaab4,0x9b20,0x914e, +0x403b,0xffff,0x41c1,0xc9f5, +0x4040,0xccbc,0x1b17,0x6402, +0x402b,0xffc5,0x918a,0xe92e +}; +static unsigned short A[] = { +0x3ff0,0x0000,0x0000,0x0000, +0x3fee,0xa4af,0xa2a4,0x90da, +0x3fed,0x5818,0xdcfb,0xa487, +0x3fec,0x199b,0xdd85,0x529c, +0x3fea,0xe89f,0x995a,0xd3ad, +0x3fe9,0xc491,0x82a3,0xf090, +0x3fe8,0xace5,0x422a,0xa0db, +0x3fe7,0xa114,0x73eb,0x0187, +0x3fe6,0xa09e,0x667f,0x3bcd, +0x3fe5,0xab07,0xdd48,0x5429, +0x3fe4,0xbfda,0xd536,0x2a27, +0x3fe3,0xdea6,0x4c12,0x3422, +0x3fe3,0x06fe,0x0a31,0xb715, +0x3fe2,0x387a,0x6e75,0x6238, +0x3fe1,0x72b8,0x3c7d,0x517b, +0x3fe0,0xb558,0x6cf9,0x890f, +0x3fe0,0x0000,0x0000,0x0000 +}; +static unsigned short B[] = { +0x0000,0x0000,0x0000,0x0000, +0x3c72,0xed02,0xd75b,0x3707, +0x3c87,0xa1cd,0x345d,0xcc81, +0x3c86,0xe9f1,0x5686,0x4b27, +0xbc8b,0xdd34,0x13b2,0x6456, +0x3c6d,0x4397,0xafec,0x42e2, +0x3c76,0xf46a,0xd231,0x82e4, +0xbc71,0x9041,0xb9d7,0x8a76, +0x0000,0x0000,0x0000,0x0000 +}; +static unsigned short R[] = { +0x3eef,0x6307,0xd7f2,0x937f, +0x3f24,0x2fbe,0x60fc,0x9259, +0x3f55,0xd87e,0xc84a,0xef1d, +0x3f83,0xb2ab,0x6ef1,0x33b7, +0x3fac,0x6b08,0xd704,0x1a92, +0x3fce,0xbfbd,0xff82,0xc56d, +0x3fe6,0x2e42,0xfefa,0x39ef +}; + +#define douba(k) (*(double *)&A[(k)<<2]) +#define doubb(k) (*(double *)&B[(k)<<2]) +#define MEXP 16383.0 +#ifdef DENORMAL +#define MNEXP -17183.0 +#else +#define MNEXP -16383.0 +#endif +#endif + +/* log2(e) - 1 */ +#define LOG2EA 0.44269504088896340736 + +#define F W +#define Fa Wa +#define Fb Wb +#define G W +#define Ga Wa +#define Gb u +#define H W +#define Ha Wb +#define Hb Wb + +#ifdef ANSIPROT +extern double floor ( double ); +extern double fabs ( double ); +extern double frexp ( double, int * ); +extern double ldexp ( double, int ); +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern double powi ( double, int ); +extern int signbit ( double ); +extern int isnan ( double ); +extern int isfinite ( double ); +const static double reduc ( double ); +#else +double floor(), fabs(), frexp(), ldexp(); +double polevl(), p1evl(), powi(); +int signbit(), isnan(), isfinite(); +const static double reduc(); +#endif +extern double MAXNUM; +#ifdef INFINITIES +extern double INFINITY; +#endif +#ifdef NANS +extern double NAN; +#endif +#ifdef MINUSZERO +extern double NEGZERO; +#endif + +double pow( x, y ) +double x, y; +{ +double w, z, W, Wa, Wb, ya, yb, u; +/* double F, Fa, Fb, G, Ga, Gb, H, Ha, Hb */ +double aw, ay, wy; +int e, i, nflg, iyflg, yoddint; + +if( y == 0.0 ) + return( 1.0 ); +#ifdef NANS +if( isnan(x) ) + return( x ); +if( isnan(y) ) + return( y ); +#endif +if( y == 1.0 ) + return( x ); + + +#ifdef INFINITIES +if( !isfinite(y) && (x == 1.0 || x == -1.0) ) + { + mtherr( "pow", DOMAIN ); +#ifdef NANS + return( NAN ); +#else + return( INFINITY ); +#endif + } +#endif + +if( x == 1.0 ) + return( 1.0 ); + +if( y >= MAXNUM ) + { +#ifdef INFINITIES + if( x > 1.0 ) + return( INFINITY ); +#else + if( x > 1.0 ) + return( MAXNUM ); +#endif + if( x > 0.0 && x < 1.0 ) + return( 0.0); + if( x < -1.0 ) + { +#ifdef INFINITIES + return( INFINITY ); +#else + return( MAXNUM ); +#endif + } + if( x > -1.0 && x < 0.0 ) + return( 0.0 ); + } +if( y <= -MAXNUM ) + { + if( x > 1.0 ) + return( 0.0 ); +#ifdef INFINITIES + if( x > 0.0 && x < 1.0 ) + return( INFINITY ); +#else + if( x > 0.0 && x < 1.0 ) + return( MAXNUM ); +#endif + if( x < -1.0 ) + return( 0.0 ); +#ifdef INFINITIES + if( x > -1.0 && x < 0.0 ) + return( INFINITY ); +#else + if( x > -1.0 && x < 0.0 ) + return( MAXNUM ); +#endif + } +if( x >= MAXNUM ) + { +#if INFINITIES + if( y > 0.0 ) + return( INFINITY ); +#else + if( y > 0.0 ) + return( MAXNUM ); +#endif + return(0.0); + } +/* Set iyflg to 1 if y is an integer. */ +iyflg = 0; +w = floor(y); +if( w == y ) + iyflg = 1; + +/* Test for odd integer y. */ +yoddint = 0; +if( iyflg ) + { + ya = fabs(y); + ya = floor(0.5 * ya); + yb = 0.5 * fabs(w); + if( ya != yb ) + yoddint = 1; + } + +if( x <= -MAXNUM ) + { + if( y > 0.0 ) + { +#ifdef INFINITIES + if( yoddint ) + return( -INFINITY ); + return( INFINITY ); +#else + if( yoddint ) + return( -MAXNUM ); + return( MAXNUM ); +#endif + } + if( y < 0.0 ) + { +#ifdef MINUSZERO + if( yoddint ) + return( NEGZERO ); +#endif + return( 0.0 ); + } + } + +nflg = 0; /* flag = 1 if x<0 raised to integer power */ +if( x <= 0.0 ) + { + if( x == 0.0 ) + { + if( y < 0.0 ) + { +#ifdef MINUSZERO + if( signbit(x) && yoddint ) + return( -INFINITY ); +#endif +#ifdef INFINITIES + return( INFINITY ); +#else + return( MAXNUM ); +#endif + } + if( y > 0.0 ) + { +#ifdef MINUSZERO + if( signbit(x) && yoddint ) + return( NEGZERO ); +#endif + return( 0.0 ); + } + return( 1.0 ); + } + else + { + if( iyflg == 0 ) + { /* noninteger power of negative number */ + mtherr( fname, DOMAIN ); +#ifdef NANS + return(NAN); +#else + return(0.0L); +#endif + } + nflg = 1; + } + } + +/* Integer power of an integer. */ + +if( iyflg ) + { + i = w; + w = floor(x); + if( (w == x) && (fabs(y) < 32768.0) ) + { + w = powi( x, (int) y ); + return( w ); + } + } + +if( nflg ) + x = fabs(x); + +/* For results close to 1, use a series expansion. */ +w = x - 1.0; +aw = fabs(w); +ay = fabs(y); +wy = w * y; +ya = fabs(wy); +if((aw <= 1.0e-3 && ay <= 1.0) + || (ya <= 1.0e-3 && ay >= 1.0)) + { + z = (((((w*(y-5.)/720. + 1./120.)*w*(y-4.) + 1./24.)*w*(y-3.) + + 1./6.)*w*(y-2.) + 0.5)*w*(y-1.) )*wy + wy + 1.; + goto done; + } +/* These are probably too much trouble. */ +#if 0 +w = y * log(x); +if (aw > 1.0e-3 && fabs(w) < 1.0e-3) + { + z = (((((( + w/7. + 1.)*w/6. + 1.)*w/5. + 1.)*w/4. + 1.)*w/3. + 1.)*w/2. + 1.)*w + 1.; + goto done; + } + +if(ya <= 1.0e-3 && aw <= 1.0e-4) + { + z = ((((( + wy*1./720. + + (-w*1./48. + 1./120.) )*wy + + ((w*17./144. - 1./12.)*w + 1./24.) )*wy + + (((-w*5./16. + 7./24.)*w - 1./4.)*w + 1./6.) )*wy + + ((((w*137./360. - 5./12.)*w + 11./24.)*w - 1./2.)*w + 1./2.) )*wy + + (((((-w*1./6. + 1./5.)*w - 1./4)*w + 1./3.)*w -1./2.)*w ) )*wy + + wy + 1.0; + goto done; + } +#endif + +/* separate significand from exponent */ +x = frexp( x, &e ); + +#if 0 +/* For debugging, check for gross overflow. */ +if( (e * y) > (MEXP + 1024) ) + goto overflow; +#endif + +/* Find significand of x in antilog table A[]. */ +i = 1; +if( x <= douba(9) ) + i = 9; +if( x <= douba(i+4) ) + i += 4; +if( x <= douba(i+2) ) + i += 2; +if( x >= douba(1) ) + i = -1; +i += 1; + + +/* Find (x - A[i])/A[i] + * in order to compute log(x/A[i]): + * + * log(x) = log( a x/a ) = log(a) + log(x/a) + * + * log(x/a) = log(1+v), v = x/a - 1 = (x-a)/a + */ +x -= douba(i); +x -= doubb(i/2); +x /= douba(i); + + +/* rational approximation for log(1+v): + * + * log(1+v) = v - v**2/2 + v**3 P(v) / Q(v) + */ +z = x*x; +w = x * ( z * polevl( x, P, 3 ) / p1evl( x, Q, 4 ) ); +w = w - ldexp( z, -1 ); /* w - 0.5 * z */ + +/* Convert to base 2 logarithm: + * multiply by log2(e) + */ +w = w + LOG2EA * w; +/* Note x was not yet added in + * to above rational approximation, + * so do it now, while multiplying + * by log2(e). + */ +z = w + LOG2EA * x; +z = z + x; + +/* Compute exponent term of the base 2 logarithm. */ +w = -i; +w = ldexp( w, -4 ); /* divide by 16 */ +w += e; +/* Now base 2 log of x is w + z. */ + +/* Multiply base 2 log by y, in extended precision. */ + +/* separate y into large part ya + * and small part yb less than 1/16 + */ +ya = reduc(y); +yb = y - ya; + + +F = z * y + w * yb; +Fa = reduc(F); +Fb = F - Fa; + +G = Fa + w * ya; +Ga = reduc(G); +Gb = G - Ga; + +H = Fb + Gb; +Ha = reduc(H); +w = ldexp( Ga+Ha, 4 ); + +/* Test the power of 2 for overflow */ +if( w > MEXP ) + { +#ifndef INFINITIES + mtherr( fname, OVERFLOW ); +#endif +#ifdef INFINITIES + if( nflg && yoddint ) + return( -INFINITY ); + return( INFINITY ); +#else + if( nflg && yoddint ) + return( -MAXNUM ); + return( MAXNUM ); +#endif + } + +if( w < (MNEXP - 1) ) + { +#ifndef DENORMAL + mtherr( fname, UNDERFLOW ); +#endif +#ifdef MINUSZERO + if( nflg && yoddint ) + return( NEGZERO ); +#endif + return( 0.0 ); + } + +e = w; +Hb = H - Ha; + +if( Hb > 0.0 ) + { + e += 1; + Hb -= 0.0625; + } + +/* Now the product y * log2(x) = Hb + e/16.0. + * + * Compute base 2 exponential of Hb, + * where -0.0625 <= Hb <= 0. + */ +z = Hb * polevl( Hb, R, 6 ); /* z = 2**Hb - 1 */ + +/* Express e/16 as an integer plus a negative number of 16ths. + * Find lookup table entry for the fractional power of 2. + */ +if( e < 0 ) + i = 0; +else + i = 1; +i = e/16 + i; +e = 16*i - e; +w = douba( e ); +z = w + w * z; /* 2**-e * ( 1 + (2**Hb-1) ) */ +z = ldexp( z, i ); /* multiply by integer power of 2 */ + +done: + +/* Negate if odd integer power of negative number */ +if( nflg && yoddint ) + { +#ifdef MINUSZERO + if( z == 0.0 ) + z = NEGZERO; + else +#endif + z = -z; + } +return( z ); +} + + +/* Find a multiple of 1/16 that is within 1/16 of x. */ +const static double reduc(x) +double x; +{ +double t; + +t = ldexp( x, 4 ); +t = floor( t ); +t = ldexp( t, -4 ); +return(t); +} diff --git a/components/external/espruino/libs/math/powi.c b/components/external/espruino/libs/math/powi.c new file mode 100644 index 0000000000..19fe7829f6 --- /dev/null +++ b/components/external/espruino/libs/math/powi.c @@ -0,0 +1,186 @@ +/* powi.c + * + * Real raised to integer power + * + * + * + * SYNOPSIS: + * + * double x, y, powi(); + * int n; + * + * y = powi( x, n ); + * + * + * + * DESCRIPTION: + * + * Returns argument x raised to the nth power. + * The routine efficiently decomposes n as a sum of powers of + * two. The desired power is a product of two-to-the-kth + * powers of x. Thus to compute the 32767 power of x requires + * 28 multiplications instead of 32767 multiplications. + * + * + * + * ACCURACY: + * + * + * Relative error: + * arithmetic x domain n domain # trials peak rms + * DEC .04,26 -26,26 100000 2.7e-16 4.3e-17 + * IEEE .04,26 -26,26 50000 2.0e-15 3.8e-16 + * IEEE 1,2 -1022,1023 50000 8.6e-14 1.6e-14 + * + * Returns MAXNUM on overflow, zero on underflow. + * + */ + +/* powi.c */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + +#include "mconf.h" +#ifdef ANSIPROT +extern double log ( double ); +extern double frexp ( double, int * ); +extern int signbit ( double ); +#else +double log(), frexp(); +int signbit(); +#endif +extern double NEGZERO, INFINITY, MAXNUM, MAXLOG, MINLOG, LOGE2; + +double powi( x, nn ) +double x; +int nn; +{ +int n, e, sign, asign, lx; +double w, y, s; + +/* See pow.c for these tests. */ +if( x == 0.0 ) + { + if( nn == 0 ) + return( 1.0 ); + else if( nn < 0 ) + return( INFINITY ); + else + { + if( nn & 1 ) + return( x ); + else + return( 0.0 ); + } + } + +if( nn == 0 ) + return( 1.0 ); + +if( nn == -1 ) + return( 1.0/x ); + +if( x < 0.0 ) + { + asign = -1; + x = -x; + } +else + asign = 0; + + +if( nn < 0 ) + { + sign = -1; + n = -nn; + } +else + { + sign = 1; + n = nn; + } + +/* Even power will be positive. */ +if( (n & 1) == 0 ) + asign = 0; + +/* Overflow detection */ + +/* Calculate approximate logarithm of answer */ +s = frexp( x, &lx ); +e = (lx - 1)*n; +if( (e == 0) || (e > 64) || (e < -64) ) + { + s = (s - 7.0710678118654752e-1) / (s + 7.0710678118654752e-1); + s = (2.9142135623730950 * s - 0.5 + lx) * nn * LOGE2; + } +else + { + s = LOGE2 * e; + } + +if( s > MAXLOG ) + { + mtherr( "powi", OVERFLOW ); + y = INFINITY; + goto done; + } + +#if DENORMAL +if( s < MINLOG ) + { + y = 0.0; + goto done; + } + +/* Handle tiny denormal answer, but with less accuracy + * since roundoff error in 1.0/x will be amplified. + * The precise demarcation should be the gradual underflow threshold. + */ +if( (s < (-MAXLOG+2.0)) && (sign < 0) ) + { + x = 1.0/x; + sign = -sign; + } +#else +/* do not produce denormal answer */ +if( s < -MAXLOG ) + return(0.0); +#endif + + +/* First bit of the power */ +if( n & 1 ) + y = x; + +else + y = 1.0; + +w = x; +n >>= 1; +while( n ) + { + w = w * w; /* arg to the 2-to-the-kth power */ + if( n & 1 ) /* if that bit is set, then include in product */ + y *= w; + n >>= 1; + } + +if( sign < 0 ) + y = 1.0/y; + +done: + +if( asign ) + { + /* odd power of negative number */ + if( y == 0.0 ) + y = NEGZERO; + else + y = -y; + } +return(y); +} diff --git a/components/external/espruino/libs/math/protos.h b/components/external/espruino/libs/math/protos.h new file mode 100644 index 0000000000..11a9c0d52f --- /dev/null +++ b/components/external/espruino/libs/math/protos.h @@ -0,0 +1,184 @@ +/* + * This file was automatically generated by version 1.7 of cextract. + * Manual editing not recommended. + * + * Created: Fri Mar 31 19:17:33 1995 + */ +extern double acosh ( double x ); +extern int airy ( double, double *, double *, double *, double * ); +extern double asin ( double ); +extern double acos ( double ); +extern double asinh ( double x ); +extern double atan ( double ); +extern double atan2 ( double y, double x ); +extern double atanh ( double ); +extern double bdtrc ( int k, int n, double p ); +extern double bdtr ( int k, int n, double p ); +extern double bdtri ( int k, int n, double y ); +extern double beta ( double a, double b ); +extern double lbeta ( double a, double b ); +extern double btdtr ( double a, double b, double x ); +extern double cbrt ( double ); +extern double chbevl ( double, void *, int ); +extern double chdtrc ( double df, double x ); +extern double chdtr ( double df, double x ); +extern double chdtri ( double df, double y ); +//extern void clog ( cmplx *z, cmplx *w ); +//extern void cexp ( cmplx *z, cmplx *w ); +//extern void csin ( cmplx *z, cmplx *w ); +//extern void ccos ( cmplx *z, cmplx *w ); +//extern void ctan ( cmplx *z, cmplx *w ); +extern void ccot ( cmplx *z, cmplx *w ); +//extern void casin ( cmplx *z, cmplx *w ); +//extern void cacos ( cmplx *z, cmplx *w ); +//extern void catan ( cmplx *z, cmplx *w ); +extern void cadd ( cmplx *a, cmplx *b, cmplx *c ); +extern void csub ( cmplx *a, cmplx *b, cmplx *c ); +extern void cmul ( cmplx *a, cmplx *b, cmplx *c ); +extern void cdiv ( cmplx *a, cmplx *b, cmplx *c ); +extern void cmov ( void *a, void *b ); +extern void cneg ( cmplx *a ); +//extern double cabs ( cmplx *z ); +//extern void csqrt ( cmplx *z, cmplx *w ); +extern double hypot ( double, double ); +extern double cosh ( double ); +extern double dawsn ( double xx ); +extern void eigens ( double A[], double RR[], double E[], int N ); +extern double ellie ( double, double ); +extern double ellik ( double, double ); +extern double ellpe ( double ); +extern int ellpj ( double u, double m, double *sn, double *cn, double *dn, double *ph ); +extern double ellpk ( double ); +extern double exp10 ( double ); +extern double exp1m ( double ); +extern double exp2 ( double ); +extern double expn ( int n, double x ); +extern double fac ( int i ); +extern double fdtrc ( int ia, int ib, double x ); +extern double fdtr ( int ia, int ib, double x ); +extern double fdtri ( int ia, int ib, double y ); +extern int fftr ( double x[], int m0, double sine[] ); +extern double ceil ( double x ); +extern double fabs ( double ); +extern double floor ( double ); +extern double frexp ( double, int * ); +extern double ldexp ( double, int ); +extern int signbit ( double ); +extern int isnan ( double ); +extern int isfinite ( double ); +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern double exp ( double ); +extern double log ( double ); +extern double sin ( double ); +extern double cos ( double ); +extern double sqrt ( double ); +extern int fresnl ( double xxa, double *ssa, double *cca ); +extern double gamma ( double ); +extern double lgam ( double ); +extern double gdtr ( double a, double b, double x ); +extern double gdtrc ( double a, double b, double x ); +extern int gels ( double A[], double R[], int M, double EPS, double AUX[] ); +extern double hyp2f1 ( double a, double b, double c, double x ); +extern double hyperg ( double, double, double ); +extern double hyp2f0 ( double a, double b, double x, int type, double *err ); +extern double i0 ( double ); +extern double i0e ( double x ); +extern double i1 ( double ); +extern double i1e ( double x ); +extern double igamc ( double, double ); +extern double igam ( double, double ); +extern double igami ( double, double ); +extern double incbet ( double, double, double ); +extern double incbi ( double, double, double ); +extern double iv ( double v, double x ); +extern double j0 ( double ); +extern double y0 ( double ); +extern double j1 ( double ); +extern double y1 ( double ); +extern double jn ( int n, double x ); +extern double jv ( double, double ); +extern double k0 ( double x ); +extern double k0e ( double x ); +extern double k1 ( double x ); +extern double k1e ( double x ); +extern double kn ( int nn, double x ); +extern int levnsn ( int n, double r[], double a[], double e[], double refl[] ); +extern double log10 ( double ); +extern double log2 ( double ); +extern long lrand ( void ); +extern long lsqrt ( long x ); +extern int minv ( double A[], double X[], int n, double B[], int IPS[] ); +extern int mmmpy ( int r, int c, double *A, double *B, double *Y ); +extern int mtherr ( char *name, int code ); +extern int mtransp ( int n, double *A, double *T ); +extern int mvmpy ( int r, int c, double *A, double *V, double *Y ); +extern double nbdtrc ( int k, int n, double p ); +extern double nbdtr ( int k, int n, double p ); +extern double nbdtri ( int k, int n, double p ); +extern double ndtr ( double a ); +extern double erfc ( double ); +extern double erf ( double ); +extern double ndtri ( double ); +extern double pdtrc ( int k, double m ); +extern double pdtr ( int k, double m ); +extern double pdtri ( int k, double y ); +extern double pow ( double, double ); +extern double powi ( double, int ); +extern double psi ( double ); +extern void revers ( double y[], double x[], int n ); +extern double rgamma ( double x ); +extern double round ( double ); +extern int sprec ( void ); +extern int dprec ( void ); +extern int ldprec ( void ); +extern int shichi ( double x, double *si, double *ci ); +extern int sici ( double x, double *si, double *ci ); +extern double simpsn ( double f[], double delta ); +extern int simq ( double A[], double B[], double X[], int n, int flag, int IPS[] ); +extern double radian ( double d, double m, double s ); +/* +extern int sincos ( double x, double *s, double *c, int flg ); +*/ +extern double sindg ( double x ); +extern double cosdg ( double x ); +extern double sinh ( double ); +extern double spence ( double ); +extern double stdtr ( int k, double t ); +extern double stdtri ( int k, double p ); +extern double onef2 ( double a, double b, double c, double x, double *err ); +extern double threef0 ( double a, double b, double c, double x, double *err ); +extern double struve ( double v, double x ); +extern double tan ( double ); +extern double cot ( double ); +extern double tandg ( double x ); +extern double cotdg ( double x ); +extern double tanh ( double ); +extern double log1p ( double ); +extern double exmp1 ( double ); +extern double cosm1 ( double x ); +extern double yn ( int, double ); +extern double zeta ( double x, double q ); +extern double zetac ( double ); +extern int drand ( double *a ); +double smirnov ( int, double ); +double smirnovi ( int, double ); +double kolmogorov ( double ); +double kolmogi ( double ); + +/* polyn.c */ +extern void polini ( int maxdeg ); +extern void polprt ( double a[], int na, int d ); +extern void polclr ( double *a, int n ); +extern void polmov ( double *a, int na, double *b ); +extern void polmul ( double a[], int na, double b[], int nb, double c[] ); +extern void poladd ( double a[], int na, double b[], int nb, double c[] ); +extern void polsub ( double a[], int na, double b[], int nb, double c[] ); +extern int poldiv ( double a[], int na, double b[], int nb, double c[] ); +extern void polsbt ( double a[], int na, double b[], int nb, double c[] ); +extern double poleva ( double a[], int na, double x ); +/* polmisc.c */ +extern void polatn ( double num[], double den[], double ans[], int nn ); +extern void polsqt ( double pol[], double ans[], int nn ); +extern void polsin ( double x[], double y[], int nn ); +extern void polcos ( double x[], double y[], int nn ); diff --git a/components/external/espruino/libs/math/round.c b/components/external/espruino/libs/math/round.c new file mode 100644 index 0000000000..9197a2222c --- /dev/null +++ b/components/external/espruino/libs/math/round.c @@ -0,0 +1,70 @@ +/* round.c + * + * Round double to nearest or even integer valued double + * + * + * + * SYNOPSIS: + * + * double x, y, round(); + * + * y = round(x); + * + * + * + * DESCRIPTION: + * + * Returns the nearest integer to x as a double precision + * floating point result. If x ends in 0.5 exactly, the + * nearest even integer is chosen. + * + * + * + * ACCURACY: + * + * If x is greater than 1/(2*MACHEP), its closest machine + * representation is already an integer, so rounding does + * not change it. + */ + +/* +Cephes Math Library Release 2.1: January, 1989 +Copyright 1984, 1987, 1989 by Stephen L. Moshier +Direct inquiries to 30 Frost Street, Cambridge, MA 02140 +*/ +#include "mconf.h" +#ifdef ANSIPROT +double floor ( double ); +#else +double floor(); +#endif + +double round(x) +double x; +{ +double y, r; + +/* Largest integer <= x */ +y = floor(x); + +/* Fractional part */ +r = x - y; + +/* Round up to nearest. */ +if( r > 0.5 ) + goto rndup; + +/* Round to even */ +if( r == 0.5 ) + { + r = y - 2.0 * floor( 0.5 * y ); + if( r == 1.0 ) + { +rndup: + y += 1.0; + } + } + +/* Else round down. */ +return(y); +} diff --git a/components/external/espruino/libs/math/setprbor.asm b/components/external/espruino/libs/math/setprbor.asm new file mode 100644 index 0000000000..8aaf1f6d3f --- /dev/null +++ b/components/external/espruino/libs/math/setprbor.asm @@ -0,0 +1,207 @@ +; +; Borland assembler header +; +; Microsoft MASM subroutines for setting coprocessor precision +; +.286 +.287 +PREC_TEXT SEGMENT BYTE PUBLIC 'CODE' +PREC_TEXT ENDS +DGROUP group _DATA,_BSS + assume cs:PREC_TEXT,ds:DGROUP +_DATA segment word public 'DATA' +d@ label byte +d@w label word +_DATA ends +_BSS segment word public 'BSS' +b@ label byte +b@w label word +_BSS ends + +; exception masks (1 = masked) +; 1 invalid operation +; 2 denormalized operand +; 4 zero divide +; 8 overflow +; 10 underflow +; 20 precision + +_DATA SEGMENT + +; double precision setting +;;ctlwrd dw 01230h ; note this traps on denormal operands! +;;ctld dw 0133fh ; this doesn't trap +ctld dw 01230h + +; single precision +ctls dw 01030h + +; long double precision +ctlld dw 01320h + +_DATA ENDS + +PREC_TEXT segment byte public 'CODE' + assume cs:PREC_TEXT,ds:DGROUP +; Set coprocessor to single precision float + PUBLIC _sprec +_sprec PROC FAR + fclex + fwait + finit + fwait + fldcw word ptr ctls + fwait + ret +_sprec ENDP + +; set coprocessor to long double precision + PUBLIC _ldprec +_ldprec PROC far + fclex + fwait + finit + fwait + fldcw word ptr ctlld + fwait + ret +_ldprec ENDP + +; set coprocessor to double precision + PUBLIC _dprec +_dprec PROC far + fclex + fwait + finit + fwait + fldcw word ptr ctld + fwait + ret +_dprec ENDP + + +; get a double promoted to long double size +; getld( &doub, &ldoub ); + PUBLIC _getld +_getld PROC far + push bp + mov bp,sp + push bx + mov bx, word ptr [bp+4] +; fld st(0) + fld qword ptr [bx] + mov bx, word ptr [bp+6] + fstp tbyte ptr [bx] + mov bx, word ptr [bp+4] + fld qword ptr [bx] + mov bx, word ptr [bp+8] + fstp qword ptr [bx] + pop bx + pop bp + ret +_getld ENDP + + PUBLIC _getprec +_getprec PROC far + push bp + mov bp,sp + sub sp,4 + fstcw [bp-4] + fwait + mov ax,[bp-4] + add sp,4 + pop bp + ret +_getprec ENDP + + + PUBLIC _fpclear +_fpclear PROC far + push bp + mov bp,sp + fnclex + fwait + pop bp + ret +_fpclear ENDP + + + PUBLIC _noexcept +_noexcept PROC far + push bp + mov bp,sp + push ax + sub sp,4 + fnclex + fwait + fstcw [bp-4] + fwait + mov ax,[bp-4] + and ax,0FFC0h + or ax,003fh + mov [bp-4],ax + fldcw [bp-4] + add sp,4 + pop ax + pop bp + ret +_noexcept ENDP + +; single precision square root +; assumes coprocessor precision already set up +; return value in static __fac + PUBLIC _sqrtf +_sqrtf PROC FAR + push bp + mov bp,sp + fld DWORD PTR [bp+6] + fsqrt + fwait + mov sp,bp + pop bp + ret +_sqrtf ENDP + +; double precision square root +; assumes coprocessor precision already set up +; return value in static __fac + PUBLIC _sqrt +_sqrt PROC FAR + push bp + mov bp,sp + fld QWORD PTR [bp+6] + fsqrt + fwait + mov sp,bp + pop bp + ret +_sqrt ENDP + + +; long double precision square root +; assumes coprocessor precision already set up +; return value in fp register + PUBLIC _sqrtl +_sqrtl PROC FAR + push bp + mov bp,sp + fld tbyte ptr [bp+6] + fsqrt + fwait + mov sp,bp + pop bp + ret +_sqrtl ENDP + + +PREC_TEXT ends +_DATA segment word public 'DATA' +s@ label byte +_DATA ends +PREC_TEXT segment byte public 'CODE' +PREC_TEXT ends +_s@ equ s@ + public _sprec + public _dprec + public _ldprec + end diff --git a/components/external/espruino/libs/math/setprec.387 b/components/external/espruino/libs/math/setprec.387 new file mode 100644 index 0000000000..f64bf3d2f4 --- /dev/null +++ b/components/external/espruino/libs/math/setprec.387 @@ -0,0 +1,87 @@ +/* Set 80387 floating point hardware rounding precision */ + + .file "setprec.387" +.text + .align 2 + +.globl _sprec +_sprec: + pushl %ebp + movl %esp,%ebp + pushl %eax + subl $4,%esp + fstcw (%esp) + fwait + movl (%esp),%eax + andl $0xfcff,%eax + movl %eax,(%esp) + fldcw (%esp) + popl %eax + popl %eax + leave + ret + + .align 2 + +.globl _dprec +_dprec: + pushl %ebp + movl %esp,%ebp + pushl %eax + subl $4,%esp + fstcw (%esp) + fwait + movl (%esp),%eax +/* andl $0xfcff,%eax */ +/* exception on overflow */ + andl $0xfcf7,%eax + orl $0x200,%eax + movl %eax,(%esp) + fldcw (%esp) + popl %eax + popl %eax + leave + ret + + .align 2 + +.globl _ldprec +_ldprec: + pushl %ebp + movl %esp,%ebp + pushl %eax + subl $4,%esp + fstcw (%esp) + fwait + movl (%esp),%eax + orl $0x300,%eax + movl %eax,(%esp) + fldcw (%esp) + popl %eax + popl %eax + leave + ret + + +.globl _getprec +_getprec: + pushl %ebp + movl %esp,%ebp + subl $4,%esp + fstcw (%esp) + fwait + movl (%esp),%eax + leave + ret + +.globl _setfpu +_setfpu: + pushl %ebp + movl %esp,%ebp + movl 8(%ebp),%eax + pushl %eax + fldcw (%esp) + fwait + movl %ebp,%esp + popl %ebp + ret diff --git a/components/external/espruino/libs/math/setprec.688 b/components/external/espruino/libs/math/setprec.688 new file mode 100644 index 0000000000..104c5b7b16 --- /dev/null +++ b/components/external/espruino/libs/math/setprec.688 @@ -0,0 +1,35 @@ +/* Set 68881/2 floating point rounding precision */ +/* Reference: MC68881/MC68882 Floating-Point Coprocessor */ +/* User's Manual, Motorola, Prentice-Hall, 1987 (First Edition) */ +/* Pages 1-14, 2-3, 4-68. */ +/* FPcr code $80 sets the 68882 coprocessor to */ +/* rounding precision = 53 bits */ +/* rounding mode = nearest or even */ +/* all exceptions (bits 8-15) disabled */ +/* The instruction is */ +/* FMOVE.L #$80,Fcr */ +/* if the assembler will understand it. */ + + .align 2 +.text + +/* set to single precision */ +.globl _sprec +_sprec + .word 0xf23c,0x9000,0x0000,0x0040 + rts + +/* set to double precision */ +.globl _dprec + +_dprec: + .word 0xf23c,0x9000,0x0000,0x0080 + rts + +/* set to extended (long double) precision */ +.globl _ldprec + +_ldprec: + .word 0xf23c,0x9000,0x0000,0x0000 + rts + diff --git a/components/external/espruino/libs/math/setprec.87 b/components/external/espruino/libs/math/setprec.87 new file mode 100644 index 0000000000..e9e2b081a1 --- /dev/null +++ b/components/external/espruino/libs/math/setprec.87 @@ -0,0 +1,208 @@ +; +; Microsoft MASM subroutines for setting coprocessor precision +; +.286 +.287 +_TEXT SEGMENT BYTE PUBLIC 'CODE' +_TEXT ENDS +CONST SEGMENT WORD PUBLIC 'CONST' +CONST ENDS +_BSS SEGMENT WORD PUBLIC 'BSS' +_BSS ENDS +_DATA SEGMENT WORD PUBLIC 'DATA' +_DATA ENDS +DGROUP GROUP CONST, _BSS, _DATA + ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP +EXTRN __fac:QWORD + +_BSS SEGMENT +EXTRN __fltused:NEAR +_BSS ENDS + + +; exception masks (1 = masked) +; 1 invalid operation +; 2 denormalized operand +; 4 zero divide +; 8 overflow +; 10 underflow +; 20 precision + +_DATA SEGMENT + +; double precision setting +;;ctlwrd dw 01230h ; note this traps on denormal operands! +;;ctld dw 0133fh ; this doesn't trap +ctld dw 01230h + +; single precision +ctls dw 01030h + +; long double precision +ctlld dw 01320h + +_DATA ENDS + + ASSUME CS: _TEXT + +_TEXT SEGMENT +; Set coprocessor to single precision float + PUBLIC _sprec +_sprec PROC NEAR + fclex + fwait + finit + fwait + fldcw word ptr ctls + fwait + ret +_sprec ENDP + +; set coprocessor to long double precision + PUBLIC _ldprec +_ldprec PROC NEAR + fclex + fwait + finit + fwait + fldcw word ptr ctlld + fwait + ret +_ldprec ENDP + +; set coprocessor to double precision + PUBLIC _dprec +_dprec PROC NEAR + fclex + fwait + finit + fwait + fldcw word ptr ctld + fwait + ret +_dprec ENDP + + +; get a double promoted to long double size +; getld( &doub, &ldoub ); + PUBLIC _getld +_getld PROC NEAR + push bp + mov bp,sp + push bx + mov bx, word ptr [bp+4] +; fld st(0) + fld qword ptr [bx] + mov bx, word ptr [bp+6] + fstp tbyte ptr [bx] + mov bx, word ptr [bp+4] + fld qword ptr [bx] + mov bx, word ptr [bp+8] + fstp qword ptr [bx] + pop bx + pop bp + ret +_getld ENDP + + PUBLIC _getprec +_getprec PROC NEAR + push bp + mov bp,sp + sub sp,4 + fstcw [bp-4] + fwait + mov ax,[bp-4] + add sp,4 + pop bp + ret +_getprec ENDP + + + PUBLIC _fpclear +_fpclear PROC NEAR + push bp + mov bp,sp + fnclex + fwait + pop bp + ret +_fpclear ENDP + + + PUBLIC _noexcept +_noexcept PROC NEAR + push bp + mov bp,sp + push ax + sub sp,4 + fnclex + fwait + fstcw [bp-4] + fwait + mov ax,[bp-4] + and ax,0FFC0h + or ax,003fh + mov [bp-4],ax + fldcw [bp-4] + add sp,4 + pop ax + pop bp + ret +_noexcept ENDP + +;; single precision square root +;; assumes coprocessor precision already set up +;; return value in static __fac +; PUBLIC _sqrtf +;_sqrtf PROC NEAR +; push bp +; mov bp,sp +; fld DWORD PTR [bp+4] +; fsqrt +; fwait +; fstp DWORD PTR __fac +; mov ax,OFFSET __fac +; mov sp,bp +; pop bp +; ret +;_sqrtf ENDP +; +; +;; double precision square root +;; assumes coprocessor precision already set up +;; return value in static __fac +; PUBLIC _sqrt +;_sqrt PROC NEAR +; push bp +; mov bp,sp +; fld QWORD PTR [bp+4] +; fsqrt +; fwait +; fstp QWORD PTR __fac +; mov ax,OFFSET __fac +; mov sp,bp +; pop bp +; ret +;_sqrt ENDP +; +; +;; long double precision square root +;; assumes coprocessor precision already set up +;; return value in fp register +; PUBLIC _sqrtl +;_sqrtl PROC NEAR +; push bp +; mov bp,sp +; fld tbyte ptr [bp+4] +; fsqrt +; fwait +; mov sp,bp +; pop bp +; ret +;_sqrtl ENDP +; + +_TEXT ENDS +END + + diff --git a/components/external/espruino/libs/math/setprec.c b/components/external/espruino/libs/math/setprec.c new file mode 100644 index 0000000000..a5222ae733 --- /dev/null +++ b/components/external/espruino/libs/math/setprec.c @@ -0,0 +1,10 @@ +/* Null stubs for coprocessor precision settings */ + +int +sprec() {return 0; } + +int +dprec() {return 0; } + +int +ldprec() {return 0; } diff --git a/components/external/espruino/libs/math/setprelf.387 b/components/external/espruino/libs/math/setprelf.387 new file mode 100644 index 0000000000..e0492643fb --- /dev/null +++ b/components/external/espruino/libs/math/setprelf.387 @@ -0,0 +1,83 @@ +/* Set 80387 floating point hardware rounding precision */ + + .file "setprec.387" + .version "01.01" +.text + .align 16 + +.globl sprec +sprec: + pushl %ebp + movl %esp,%ebp + pushl %eax + subl $4,%esp + fstcw (%esp) + fwait + movl (%esp),%eax + andl $0xfcff,%eax + movl %eax,(%esp) + fldcw (%esp) + popl %eax + popl %eax + leave + ret +.Lfe1: + .size sprec,.Lfe1-sprec + .align 16 + +.globl dprec +dprec: + pushl %ebp + movl %esp,%ebp + pushl %eax + subl $4,%esp + fstcw (%esp) + fwait + movl (%esp),%eax + andl $0xfcff,%eax +/* trap on overflow */ +/* andl $0xfcf7,%eax */ + orl $0x200,%eax + movl %eax,(%esp) + fldcw (%esp) + popl %eax + popl %eax + leave + ret +.Lfe2: + .size dprec,.Lfe2-dprec + .align 16 + +.globl ldprec +ldprec: + pushl %ebp + movl %esp,%ebp + pushl %eax + subl $4,%esp + fstcw (%esp) + fwait + movl (%esp),%eax + orl $0x300,%eax + movl %eax,(%esp) + fldcw (%esp) + popl %eax + popl %eax + leave + ret +.Lfe3: + .size ldprec,.Lfe3-ldprec + + .align 16 +.globl getprec +getprec: + pushl %ebp + movl %esp,%ebp + subl $4,%esp + fstcw (%esp) + fwait + movl (%esp),%eax + leave + ret +.Lfe4: + .size getprec,.Lfe4-getprec + diff --git a/components/external/espruino/libs/math/sin.c b/components/external/espruino/libs/math/sin.c new file mode 100644 index 0000000000..014f75f31d --- /dev/null +++ b/components/external/espruino/libs/math/sin.c @@ -0,0 +1,387 @@ +/* sin.c + * + * Circular sine + * + * + * + * SYNOPSIS: + * + * double x, y, sin(); + * + * y = sin( x ); + * + * + * + * DESCRIPTION: + * + * Range reduction is into intervals of pi/4. The reduction + * error is nearly eliminated by contriving an extended precision + * modular arithmetic. + * + * Two polynomial approximating functions are employed. + * Between 0 and pi/4 the sine is approximated by + * x + x**3 P(x**2). + * Between pi/4 and pi/2 the cosine is represented as + * 1 - x**2 Q(x**2). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC 0, 10 150000 3.0e-17 7.8e-18 + * IEEE -1.07e9,+1.07e9 130000 2.1e-16 5.4e-17 + * + * ERROR MESSAGES: + * + * message condition value returned + * sin total loss x > 1.073741824e9 0.0 + * + * Partial loss of accuracy begins to occur at x = 2**30 + * = 1.074e9. The loss is not gradual, but jumps suddenly to + * about 1 part in 10e7. Results may be meaningless for + * x > 2**49 = 5.6e14. The routine as implemented flags a + * TLOSS error for x > 2**30 and returns 0.0. + */ + /* cos.c + * + * Circular cosine + * + * + * + * SYNOPSIS: + * + * double x, y, cos(); + * + * y = cos( x ); + * + * + * + * DESCRIPTION: + * + * Range reduction is into intervals of pi/4. The reduction + * error is nearly eliminated by contriving an extended precision + * modular arithmetic. + * + * Two polynomial approximating functions are employed. + * Between 0 and pi/4 the cosine is approximated by + * 1 - x**2 Q(x**2). + * Between pi/4 and pi/2 the sine is represented as + * x + x**3 P(x**2). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -1.07e9,+1.07e9 130000 2.1e-16 5.4e-17 + * DEC 0,+1.07e9 17000 3.0e-17 7.2e-18 + */ + +/* sin.c */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1985, 1995, 2000 by Stephen L. Moshier +*/ + +#include "mconf.h" + +#ifdef UNK +const static double sincof[] = { + 1.58962301576546568060E-10, +-2.50507477628578072866E-8, + 2.75573136213857245213E-6, +-1.98412698295895385996E-4, + 8.33333333332211858878E-3, +-1.66666666666666307295E-1, +}; +const static double coscof[6] = { +-1.13585365213876817300E-11, + 2.08757008419747316778E-9, +-2.75573141792967388112E-7, + 2.48015872888517045348E-5, +-1.38888888888730564116E-3, + 4.16666666666665929218E-2, +}; +const static double DP1 = 7.85398125648498535156E-1; +const static double DP2 = 3.77489470793079817668E-8; +const static double DP3 = 2.69515142907905952645E-15; +/* const static double lossth = 1.073741824e9; */ +#endif + +#ifdef DEC +static unsigned short sincof[] = { +0030056,0143750,0177214,0163153, +0131727,0027455,0044510,0175352, +0033470,0167432,0131752,0042414, +0135120,0006400,0146776,0174027, +0036410,0104210,0104207,0137202, +0137452,0125252,0125252,0125103, +}; +static unsigned short coscof[24] = { +0127107,0151115,0002060,0152325, +0031017,0072353,0155161,0174053, +0132623,0171173,0172542,0057056, +0034320,0006400,0147102,0023652, +0135666,0005540,0133012,0076213, +0037052,0125252,0125252,0125126, +}; +/* 7.853981629014015197753906250000E-1 */ +static unsigned short P1[] = {0040111,0007732,0120000,0000000,}; +/* 4.960467869796758577649598009884E-10 */ +static unsigned short P2[] = {0030410,0055060,0100000,0000000,}; +/* 2.860594363054915898381331279295E-18 */ +static unsigned short P3[] = {0021523,0011431,0105056,0001560,}; +#define DP1 *(double *)P1 +#define DP2 *(double *)P2 +#define DP3 *(double *)P3 +#endif + +#ifdef IBMPC +static unsigned short sincof[] = { +0x9ccd,0x1fd1,0xd8fd,0x3de5, +0x1f5d,0xa929,0xe5e5,0xbe5a, +0x48a1,0x567d,0x1de3,0x3ec7, +0xdf03,0x19bf,0x01a0,0xbf2a, +0xf7d0,0x1110,0x1111,0x3f81, +0x5548,0x5555,0x5555,0xbfc5, +}; +static unsigned short coscof[24] = { +0x1a9b,0xa086,0xfa49,0xbda8, +0x3f05,0x7b4e,0xee9d,0x3e21, +0x4bc6,0x7eac,0x7e4f,0xbe92, +0x44f5,0x19c8,0x01a0,0x3efa, +0x4f91,0x16c1,0xc16c,0xbf56, +0x554b,0x5555,0x5555,0x3fa5, +}; +/* + 7.85398125648498535156E-1, + 3.77489470793079817668E-8, + 2.69515142907905952645E-15, +*/ +static unsigned short P1[] = {0x0000,0x4000,0x21fb,0x3fe9}; +static unsigned short P2[] = {0x0000,0x0000,0x442d,0x3e64}; +static unsigned short P3[] = {0x5170,0x98cc,0x4698,0x3ce8}; +#define DP1 *(double *)P1 +#define DP2 *(double *)P2 +#define DP3 *(double *)P3 +#endif + +#ifdef MIEEE +static unsigned short sincof[] = { +0x3de5,0xd8fd,0x1fd1,0x9ccd, +0xbe5a,0xe5e5,0xa929,0x1f5d, +0x3ec7,0x1de3,0x567d,0x48a1, +0xbf2a,0x01a0,0x19bf,0xdf03, +0x3f81,0x1111,0x1110,0xf7d0, +0xbfc5,0x5555,0x5555,0x5548, +}; +static unsigned short coscof[24] = { +0xbda8,0xfa49,0xa086,0x1a9b, +0x3e21,0xee9d,0x7b4e,0x3f05, +0xbe92,0x7e4f,0x7eac,0x4bc6, +0x3efa,0x01a0,0x19c8,0x44f5, +0xbf56,0xc16c,0x16c1,0x4f91, +0x3fa5,0x5555,0x5555,0x554b, +}; +static unsigned short P1[] = {0x3fe9,0x21fb,0x4000,0x0000}; +static unsigned short P2[] = {0x3e64,0x442d,0x0000,0x0000}; +static unsigned short P3[] = {0x3ce8,0x4698,0x98cc,0x5170}; +#define DP1 *(double *)P1 +#define DP2 *(double *)P2 +#define DP3 *(double *)P3 +#endif + +#ifdef ANSIPROT +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern double floor ( double ); +extern double ldexp ( double, int ); +extern int isnan ( double ); +extern int isfinite ( double ); +#else +double polevl(), floor(), ldexp(); +int isnan(), isfinite(); +#endif +extern double PIO4; +const static double lossth = 1.073741824e9; +#ifdef NANS +extern double NAN; +#endif +#ifdef INFINITIES +extern double INFINITY; +#endif + + +double sin(x) +double x; +{ +double y, z, zz; +int j, sign; + +#ifdef MINUSZERO +if( x == 0.0 ) + return(x); +#endif +#ifdef NANS +if( isnan(x) ) + return(x); +if( !isfinite(x) ) + { + mtherr( "sin", DOMAIN ); + return(NAN); + } +#endif +/* make argument positive but save the sign */ +sign = 1; +if( x < 0 ) + { + x = -x; + sign = -1; + } + +if( x > lossth ) + { + mtherr( "sin", TLOSS ); + return(0.0); + } + +y = floor( x/PIO4 ); /* integer part of x/PIO4 */ + +/* strip high bits of integer part to prevent integer overflow */ +z = ldexp( y, -4 ); +z = floor(z); /* integer part of y/8 */ +z = y - ldexp( z, 4 ); /* y - 16 * (y/16) */ + +j = z; /* convert to integer for tests on the phase angle */ +/* map zeros to origin */ +if( j & 1 ) + { + j += 1; + y += 1.0; + } +j = j & 07; /* octant modulo 360 degrees */ +/* reflect in x axis */ +if( j > 3) + { + sign = -sign; + j -= 4; + } + +/* Extended precision modular arithmetic */ +z = ((x - y * DP1) - y * DP2) - y * DP3; + +zz = z * z; + +if( (j==1) || (j==2) ) + { + y = 1.0 - ldexp(zz,-1) + zz * zz * polevl( zz, coscof, 5 ); + } +else + { +/* y = z + z * (zz * polevl( zz, sincof, 5 ));*/ + y = z + z * z * z * polevl( zz, sincof, 5 ); + } + +if(sign < 0) + y = -y; + +return(y); +} + + + + + +double cos(x) +double x; +{ +double y, z, zz; +long i; +int j, sign; + +#ifdef NANS +if( isnan(x) ) + return(x); +if( !isfinite(x) ) + { + mtherr( "cos", DOMAIN ); + return(NAN); + } +#endif + +/* make argument positive */ +sign = 1; +if( x < 0 ) + x = -x; + +if( x > lossth ) + { + mtherr( "cos", TLOSS ); + return(0.0); + } + +y = floor( x/PIO4 ); +z = ldexp( y, -4 ); +z = floor(z); /* integer part of y/8 */ +z = y - ldexp( z, 4 ); /* y - 16 * (y/16) */ + +/* integer and fractional part modulo one octant */ +i = z; +if( i & 1 ) /* map zeros to origin */ + { + i += 1; + y += 1.0; + } +j = i & 07; +if( j > 3) + { + j -=4; + sign = -sign; + } + +if( j > 1 ) + sign = -sign; + +/* Extended precision modular arithmetic */ +z = ((x - y * DP1) - y * DP2) - y * DP3; + +zz = z * z; + +if( (j==1) || (j==2) ) + { +/* y = z + z * (zz * polevl( zz, sincof, 5 ));*/ + y = z + z * z * z * polevl( zz, sincof, 5 ); + } +else + { + y = 1.0 - ldexp(zz,-1) + zz * zz * polevl( zz, coscof, 5 ); + } + +if(sign < 0) + y = -y; + +return(y); +} + + + + + +/* Degrees, minutes, seconds to radians: */ + +/* 1 arc second, in radians = 4.8481368110953599358991410e-5 */ +#ifdef DEC +static unsigned short P648[] = {034513,054170,0176773,0116043,}; +#define P64800 *(double *)P648 +#else +const static double P64800 = 4.8481368110953599358991410e-5; +#endif + +double radian(d,m,s) +double d,m,s; +{ + +return( ((d*60.0 + m)*60.0 + s)*P64800 ); +} diff --git a/components/external/espruino/libs/math/sincos.c b/components/external/espruino/libs/math/sincos.c new file mode 100644 index 0000000000..a50f7421dc --- /dev/null +++ b/components/external/espruino/libs/math/sincos.c @@ -0,0 +1,358 @@ +/* sincos.c + * + * Circular sine and cosine of argument in degrees + * Table lookup and interpolation algorithm + * + * + * + * SYNOPSIS: + * + * double x, sine, cosine, flg, sincos(); + * + * sincos( x, &sine, &cosine, flg ); + * + * + * + * DESCRIPTION: + * + * Returns both the sine and the cosine of the argument x. + * Several different compile time options and minimax + * approximations are supplied to permit tailoring the + * tradeoff between computation speed and accuracy. + * + * Since range reduction is time consuming, the reduction + * of x modulo 360 degrees is also made optional. + * + * sin(i) is internally tabulated for 0 <= i <= 90 degrees. + * Approximation polynomials, ranging from linear interpolation + * to cubics in (x-i)**2, compute the sine and cosine + * of the residual x-i which is between -0.5 and +0.5 degree. + * In the case of the high accuracy options, the residual + * and the tabulated values are combined using the trigonometry + * formulas for sin(A+B) and cos(A+B). + * + * Compile time options are supplied for 5, 11, or 17 decimal + * relative accuracy (ACC5, ACC11, ACC17 respectively). + * A subroutine flag argument "flg" chooses betwen this + * accuracy and table lookup only (peak absolute error + * = 0.0087). + * + * If the argument flg = 1, then the tabulated value is + * returned for the nearest whole number of degrees. The + * approximation polynomials are not computed. At + * x = 0.5 deg, the absolute error is then sin(0.5) = 0.0087. + * + * An intermediate speed and precision can be obtained using + * the compile time option LINTERP and flg = 1. This yields + * a linear interpolation using a slope estimated from the sine + * or cosine at the nearest integer argument. The peak absolute + * error with this option is 3.8e-5. Relative error at small + * angles is about 1e-5. + * + * If flg = 0, then the approximation polynomials are computed + * and applied. + * + * + * + * SPEED: + * + * Relative speed comparisons follow for 6MHz IBM AT clone + * and Microsoft C version 4.0. These figures include + * software overhead of do loop and function calls. + * Since system hardware and software vary widely, the + * numbers should be taken as representative only. + * + * flg=0 flg=0 flg=1 flg=1 + * ACC11 ACC5 LINTERP Lookup only + * In-line 8087 (/FPi) + * sin(), cos() 1.0 1.0 1.0 1.0 + * + * In-line 8087 (/FPi) + * sincos() 1.1 1.4 1.9 3.0 + * + * Software (/FPa) + * sin(), cos() 0.19 0.19 0.19 0.19 + * + * Software (/FPa) + * sincos() 0.39 0.50 0.73 1.7 + * + * + * + * ACCURACY: + * + * The accurate approximations are designed with a relative error + * criterion. The absolute error is greatest at x = 0.5 degree. + * It decreases from a local maximum at i+0.5 degrees to full + * machine precision at each integer i degrees. With the + * ACC5 option, the relative error of 6.3e-6 is equivalent to + * an absolute angular error of 0.01 arc second in the argument + * at x = i+0.5 degrees. For small angles < 0.5 deg, the ACC5 + * accuracy is 6.3e-6 (.00063%) of reading; i.e., the absolute + * error decreases in proportion to the argument. This is true + * for both the sine and cosine approximations, since the latter + * is for the function 1 - cos(x). + * + * If absolute error is of most concern, use the compile time + * option ABSERR to obtain an absolute error of 2.7e-8 for ACC5 + * precision. This is about half the absolute error of the + * relative precision option. In this case the relative error + * for small angles will increase to 9.5e-6 -- a reasonable + * tradeoff. + */ + + +#include "mconf.h" + +/* Define one of the following to be 1: + */ +#define ACC5 1 +#define ACC11 0 +#define ACC17 0 + +/* Option for linear interpolation when flg = 1 + */ +#define LINTERP 1 + +/* Option for absolute error criterion + */ +#define ABSERR 1 + +/* Option to include modulo 360 function: + */ +#define MOD360 1 + +/* +Cephes Math Library Release 2.1 +Copyright 1987 by Stephen L. Moshier +Direct inquiries to 30 Frost Street, Cambridge, MA 02140 +*/ + + +/* Table of sin(i degrees) + * for 0 <= i <= 90 + */ +const static double sintbl[92] = { + 0.00000000000000000000E0, + 1.74524064372835128194E-2, + 3.48994967025009716460E-2, + 5.23359562429438327221E-2, + 6.97564737441253007760E-2, + 8.71557427476581735581E-2, + 1.04528463267653471400E-1, + 1.21869343405147481113E-1, + 1.39173100960065444112E-1, + 1.56434465040230869010E-1, + 1.73648177666930348852E-1, + 1.90808995376544812405E-1, + 2.07911690817759337102E-1, + 2.24951054343864998051E-1, + 2.41921895599667722560E-1, + 2.58819045102520762349E-1, + 2.75637355816999185650E-1, + 2.92371704722736728097E-1, + 3.09016994374947424102E-1, + 3.25568154457156668714E-1, + 3.42020143325668733044E-1, + 3.58367949545300273484E-1, + 3.74606593415912035415E-1, + 3.90731128489273755062E-1, + 4.06736643075800207754E-1, + 4.22618261740699436187E-1, + 4.38371146789077417453E-1, + 4.53990499739546791560E-1, + 4.69471562785890775959E-1, + 4.84809620246337029075E-1, + 5.00000000000000000000E-1, + 5.15038074910054210082E-1, + 5.29919264233204954047E-1, + 5.44639035015027082224E-1, + 5.59192903470746830160E-1, + 5.73576436351046096108E-1, + 5.87785252292473129169E-1, + 6.01815023152048279918E-1, + 6.15661475325658279669E-1, + 6.29320391049837452706E-1, + 6.42787609686539326323E-1, + 6.56059028990507284782E-1, + 6.69130606358858213826E-1, + 6.81998360062498500442E-1, + 6.94658370458997286656E-1, + 7.07106781186547524401E-1, + 7.19339800338651139356E-1, + 7.31353701619170483288E-1, + 7.43144825477394235015E-1, + 7.54709580222771997943E-1, + 7.66044443118978035202E-1, + 7.77145961456970879980E-1, + 7.88010753606721956694E-1, + 7.98635510047292846284E-1, + 8.09016994374947424102E-1, + 8.19152044288991789684E-1, + 8.29037572555041692006E-1, + 8.38670567945424029638E-1, + 8.48048096156425970386E-1, + 8.57167300702112287465E-1, + 8.66025403784438646764E-1, + 8.74619707139395800285E-1, + 8.82947592858926942032E-1, + 8.91006524188367862360E-1, + 8.98794046299166992782E-1, + 9.06307787036649963243E-1, + 9.13545457642600895502E-1, + 9.20504853452440327397E-1, + 9.27183854566787400806E-1, + 9.33580426497201748990E-1, + 9.39692620785908384054E-1, + 9.45518575599316810348E-1, + 9.51056516295153572116E-1, + 9.56304755963035481339E-1, + 9.61261695938318861916E-1, + 9.65925826289068286750E-1, + 9.70295726275996472306E-1, + 9.74370064785235228540E-1, + 9.78147600733805637929E-1, + 9.81627183447663953497E-1, + 9.84807753012208059367E-1, + 9.87688340595137726190E-1, + 9.90268068741570315084E-1, + 9.92546151641322034980E-1, + 9.94521895368273336923E-1, + 9.96194698091745532295E-1, + 9.97564050259824247613E-1, + 9.98629534754573873784E-1, + 9.99390827019095730006E-1, + 9.99847695156391239157E-1, + 1.00000000000000000000E0, + 9.99847695156391239157E-1, +}; + +#ifdef ANSIPROT +double floor ( double ); +#else +double floor(); +#endif + +int sincos(x, s, c, flg) +double x; +double *s, *c; +int flg; +{ +int ix, ssign, csign, xsign; +double y, z, sx, sz, cx, cz; + +/* Make argument nonnegative. + */ +xsign = 1; +if( x < 0.0 ) + { + xsign = -1; + x = -x; + } + + +#if MOD360 +x = x - 360.0 * floor( x/360.0 ); +#endif + +/* Find nearest integer to x. + * Note there should be a domain error test here, + * but this is omitted to gain speed. + */ +ix = x + 0.5; +z = x - ix; /* the residual */ + +/* Look up the sine and cosine of the integer. + */ +if( ix <= 180 ) + { + ssign = 1; + csign = 1; + } +else + { + ssign = -1; + csign = -1; + ix -= 180; + } + +if( ix > 90 ) + { + csign = -csign; + ix = 180 - ix; + } + +sx = sintbl[ix]; +if( ssign < 0 ) + sx = -sx; +cx = sintbl[ 90-ix ]; +if( csign < 0 ) + cx = -cx; + +/* If the flag argument is set, then just return + * the tabulated values for arg to the nearest whole degree. + */ +if( flg ) + { +#if LINTERP + y = sx + 1.74531263774940077459e-2 * z * cx; + cx -= 1.74531263774940077459e-2 * z * sx; + sx = y; +#endif + if( xsign < 0 ) + sx = -sx; + *s = sx; /* sine */ + *c = cx; /* cosine */ + return 0; + } + +/* Find sine and cosine + * of the residual angle between -0.5 and +0.5 degree. + */ +#if ACC5 +#if ABSERR +/* absolute error = 2.769e-8: */ +sz = 1.74531263774940077459e-2 * z; +/* absolute error = 4.146e-11: */ +cz = 1.0 - 1.52307909153324666207e-4 * z * z; +#else +/* relative error = 6.346e-6: */ +sz = 1.74531817576426662296e-2 * z; +/* relative error = 3.173e-6: */ +cz = 1.0 - 1.52308226602566149927e-4 * z * z; +#endif +#else +y = z * z; +#endif + + +#if ACC11 +sz = ( -8.86092781698004819918e-7 * y + + 1.74532925198378577601e-2 ) * z; + +cz = 1.0 - ( -3.86631403698859047896e-9 * y + + 1.52308709893047593702e-4 ) * y; +#endif + + +#if ACC17 +sz = (( 1.34959795251974073996e-11 * y + - 8.86096155697856783296e-7 ) * y + + 1.74532925199432957214e-2 ) * z; + +cz = 1.0 - (( 3.92582397764340914444e-14 * y + - 3.86632385155548605680e-9 ) * y + + 1.52308709893354299569e-4 ) * y; +#endif + + +/* Combine the tabulated part and the calculated part + * by trigonometry. + */ +y = sx * cz + cx * sz; +if( xsign < 0 ) + y = - y; +*s = y; /* sine */ + +*c = cx * cz - sx * sz; /* cosine */ +return 0; +} diff --git a/components/external/espruino/libs/math/sindg.c b/components/external/espruino/libs/math/sindg.c new file mode 100644 index 0000000000..7b2be4b452 --- /dev/null +++ b/components/external/espruino/libs/math/sindg.c @@ -0,0 +1,308 @@ +/* sindg.c + * + * Circular sine of angle in degrees + * + * + * + * SYNOPSIS: + * + * double x, y, sindg(); + * + * y = sindg( x ); + * + * + * + * DESCRIPTION: + * + * Range reduction is into intervals of 45 degrees. + * + * Two polynomial approximating functions are employed. + * Between 0 and pi/4 the sine is approximated by + * x + x**3 P(x**2). + * Between pi/4 and pi/2 the cosine is represented as + * 1 - x**2 P(x**2). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC +-1000 3100 3.3e-17 9.0e-18 + * IEEE +-1000 30000 2.3e-16 5.6e-17 + * + * ERROR MESSAGES: + * + * message condition value returned + * sindg total loss x > 8.0e14 (DEC) 0.0 + * x > 1.0e14 (IEEE) + * + */ + /* cosdg.c + * + * Circular cosine of angle in degrees + * + * + * + * SYNOPSIS: + * + * double x, y, cosdg(); + * + * y = cosdg( x ); + * + * + * + * DESCRIPTION: + * + * Range reduction is into intervals of 45 degrees. + * + * Two polynomial approximating functions are employed. + * Between 0 and pi/4 the cosine is approximated by + * 1 - x**2 P(x**2). + * Between pi/4 and pi/2 the sine is represented as + * x + x**3 P(x**2). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC +-1000 3400 3.5e-17 9.1e-18 + * IEEE +-1000 30000 2.1e-16 5.7e-17 + * See also sin(). + * + */ + +/* Cephes Math Library Release 2.0: April, 1987 + * Copyright 1985, 1987 by Stephen L. Moshier + * Direct inquiries to 30 Frost Street, Cambridge, MA 02140 */ + +#include "mconf.h" + +#ifdef UNK +const static double sincof[] = { + 1.58962301572218447952E-10, +-2.50507477628503540135E-8, + 2.75573136213856773549E-6, +-1.98412698295895384658E-4, + 8.33333333332211858862E-3, +-1.66666666666666307295E-1 +}; +const static double coscof[] = { + 1.13678171382044553091E-11, +-2.08758833757683644217E-9, + 2.75573155429816611547E-7, +-2.48015872936186303776E-5, + 1.38888888888806666760E-3, +-4.16666666666666348141E-2, + 4.99999999999999999798E-1 +}; +const static double PI180 = 1.74532925199432957692E-2; /* pi/180 */ +const static double lossth = 1.0e14; +#endif + +#ifdef DEC +static unsigned short sincof[] = { +0030056,0143750,0177170,0073013, +0131727,0027455,0044510,0132205, +0033470,0167432,0131752,0042263, +0135120,0006400,0146776,0174027, +0036410,0104210,0104207,0137202, +0137452,0125252,0125252,0125103 +}; +static unsigned short coscof[] = { +0027107,0176030,0153315,0110312, +0131017,0072476,0007450,0123243, +0032623,0171174,0070066,0146445, +0134320,0006400,0147355,0163313, +0035666,0005540,0133012,0165067, +0137052,0125252,0125252,0125206, +0040000,0000000,0000000,0000000 +}; +static unsigned short P1[] = {0036616,0175065,0011224,0164711}; +#define PI180 *(double *)P1 +const static double lossth = 8.0e14; +#endif + +#ifdef IBMPC +static unsigned short sincof[] = { +0x0ec1,0x1fcf,0xd8fd,0x3de5, +0x1691,0xa929,0xe5e5,0xbe5a, +0x4896,0x567d,0x1de3,0x3ec7, +0xdf03,0x19bf,0x01a0,0xbf2a, +0xf7d0,0x1110,0x1111,0x3f81, +0x5548,0x5555,0x5555,0xbfc5 +}; +static unsigned short coscof[] = { +0xb219,0x1ad9,0xff83,0x3da8, +0x14d4,0xc1e5,0xeea7,0xbe21, +0xd9a5,0x8e06,0x7e4f,0x3e92, +0xbcd9,0x19dd,0x01a0,0xbefa, +0x5d47,0x16c1,0xc16c,0x3f56, +0x5551,0x5555,0x5555,0xbfa5, +0x0000,0x0000,0x0000,0x3fe0 +}; + +static unsigned short P1[] = {0x9d39,0xa252,0xdf46,0x3f91}; +#define PI180 *(double *)P1 +const static double lossth = 1.0e14; +#endif + +#ifdef MIEEE +static unsigned short sincof[] = { +0x3de5,0xd8fd,0x1fcf,0x0ec1, +0xbe5a,0xe5e5,0xa929,0x1691, +0x3ec7,0x1de3,0x567d,0x4896, +0xbf2a,0x01a0,0x19bf,0xdf03, +0x3f81,0x1111,0x1110,0xf7d0, +0xbfc5,0x5555,0x5555,0x5548 +}; +static unsigned short coscof[] = { +0x3da8,0xff83,0x1ad9,0xb219, +0xbe21,0xeea7,0xc1e5,0x14d4, +0x3e92,0x7e4f,0x8e06,0xd9a5, +0xbefa,0x01a0,0x19dd,0xbcd9, +0x3f56,0xc16c,0x16c1,0x5d47, +0xbfa5,0x5555,0x5555,0x5551, +0x3fe0,0x0000,0x0000,0x0000 +}; + +static unsigned short P1[] = { +0x3f91,0xdf46,0xa252,0x9d39 +}; +#define PI180 *(double *)P1 +const static double lossth = 1.0e14; +#endif + +#ifdef ANSIPROT +extern double polevl ( double, void *, int ); +extern double floor ( double ); +extern double ldexp ( double, int ); +#else +double polevl(), floor(), ldexp(); +#endif +extern double PIO4; + +double sindg(x) +double x; +{ +double y, z, zz; +int j, sign; + +/* make argument positive but save the sign */ +sign = 1; +if( x < 0 ) + { + x = -x; + sign = -1; + } + +if( x > lossth ) + { + mtherr( "sindg", TLOSS ); + return(0.0); + } + +y = floor( x/45.0 ); /* integer part of x/PIO4 */ + +/* strip high bits of integer part to prevent integer overflow */ +z = ldexp( y, -4 ); +z = floor(z); /* integer part of y/8 */ +z = y - ldexp( z, 4 ); /* y - 16 * (y/16) */ + +j = z; /* convert to integer for tests on the phase angle */ +/* map zeros to origin */ +if( j & 1 ) + { + j += 1; + y += 1.0; + } +j = j & 07; /* octant modulo 360 degrees */ +/* reflect in x axis */ +if( j > 3) + { + sign = -sign; + j -= 4; + } + +z = x - y * 45.0; /* x mod 45 degrees */ +z *= PI180; /* multiply by pi/180 to convert to radians */ +zz = z * z; + +if( (j==1) || (j==2) ) + { + y = 1.0 - zz * polevl( zz, coscof, 6 ); + } +else + { + y = z + z * (zz * polevl( zz, sincof, 5 )); + } + +if(sign < 0) + y = -y; + +return(y); +} + + + + + +double cosdg(x) +double x; +{ +double y, z, zz; +int j, sign; + +/* make argument positive */ +sign = 1; +if( x < 0 ) + x = -x; + +if( x > lossth ) + { + mtherr( "cosdg", TLOSS ); + return(0.0); + } + +y = floor( x/45.0 ); +z = ldexp( y, -4 ); +z = floor(z); /* integer part of y/8 */ +z = y - ldexp( z, 4 ); /* y - 16 * (y/16) */ + +/* integer and fractional part modulo one octant */ +j = z; +if( j & 1 ) /* map zeros to origin */ + { + j += 1; + y += 1.0; + } +j = j & 07; +if( j > 3) + { + j -=4; + sign = -sign; + } + +if( j > 1 ) + sign = -sign; + +z = x - y * 45.0; /* x mod 45 degrees */ +z *= PI180; /* multiply by pi/180 to convert to radians */ + +zz = z * z; + +if( (j==1) || (j==2) ) + { + y = z + z * (zz * polevl( zz, sincof, 5 )); + } +else + { + y = 1.0 - zz * polevl( zz, coscof, 6 ); + } + +if(sign < 0) + y = -y; + +return(y); +} diff --git a/components/external/espruino/libs/math/sinh.c b/components/external/espruino/libs/math/sinh.c new file mode 100644 index 0000000000..40ebb3d945 --- /dev/null +++ b/components/external/espruino/libs/math/sinh.c @@ -0,0 +1,148 @@ +/* sinh.c + * + * Hyperbolic sine + * + * + * + * SYNOPSIS: + * + * double x, y, sinh(); + * + * y = sinh( x ); + * + * + * + * DESCRIPTION: + * + * Returns hyperbolic sine of argument in the range MINLOG to + * MAXLOG. + * + * The range is partitioned into two segments. If |x| <= 1, a + * rational function of the form x + x**3 P(x)/Q(x) is employed. + * Otherwise the calculation is sinh(x) = ( exp(x) - exp(-x) )/2. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC +- 88 50000 4.0e-17 7.7e-18 + * IEEE +-MAXLOG 30000 2.6e-16 5.7e-17 + * + */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + +#include "mconf.h" + +#ifdef UNK +const static double P[] = { +-7.89474443963537015605E-1, +-1.63725857525983828727E2, +-1.15614435765005216044E4, +-3.51754964808151394800E5 +}; +const static double Q[] = { +/* 1.00000000000000000000E0,*/ +-2.77711081420602794433E2, + 3.61578279834431989373E4, +-2.11052978884890840399E6 +}; +#endif + +#ifdef DEC +static unsigned short P[] = { +0140112,0015377,0042731,0163255, +0142043,0134721,0146177,0123761, +0143464,0122706,0034353,0006017, +0144653,0140536,0157665,0054045 +}; +static unsigned short Q[] = { +/*0040200,0000000,0000000,0000000,*/ +0142212,0155404,0133513,0022040, +0044015,0036723,0173271,0011053, +0145400,0150407,0023710,0001034 +}; +#endif + +#ifdef IBMPC +static unsigned short P[] = { +0x3cd6,0xe8bb,0x435f,0xbfe9, +0xf4fe,0x398f,0x773a,0xc064, +0x6182,0xc71d,0x94b8,0xc0c6, +0xab05,0xdbf6,0x782b,0xc115 +}; +static unsigned short Q[] = { +/*0x0000,0x0000,0x0000,0x3ff0,*/ +0x6484,0x96e9,0x5b60,0xc071, +0x2245,0x7ed7,0xa7ba,0x40e1, +0x0044,0xe4f9,0x1a20,0xc140 +}; +#endif + +#ifdef MIEEE +static unsigned short P[] = { +0xbfe9,0x435f,0xe8bb,0x3cd6, +0xc064,0x773a,0x398f,0xf4fe, +0xc0c6,0x94b8,0xc71d,0x6182, +0xc115,0x782b,0xdbf6,0xab05 +}; +static unsigned short Q[] = { +0xc071,0x5b60,0x96e9,0x6484, +0x40e1,0xa7ba,0x7ed7,0x2245, +0xc140,0x1a20,0xe4f9,0x0044 +}; +#endif + +#ifdef ANSIPROT +extern double fabs ( double ); +extern double exp ( double ); +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +#else +double fabs(), exp(), polevl(), p1evl(); +#endif +extern double INFINITY, MINLOG, MAXLOG, LOGE2; + +double sinh(x) +double x; +{ +double a; + +#ifdef MINUSZERO +if( x == 0.0 ) + return(x); +#endif +a = fabs(x); +if( (x > (MAXLOG + LOGE2)) || (x > -(MINLOG-LOGE2) ) ) + { + mtherr( "sinh", DOMAIN ); + if( x > 0 ) + return( INFINITY ); + else + return( -INFINITY ); + } +if( a > 1.0 ) + { + if( a >= (MAXLOG - LOGE2) ) + { + a = exp(0.5*a); + a = (0.5 * a) * a; + if( x < 0 ) + a = -a; + return(a); + } + a = exp(a); + a = 0.5*a - (0.5/a); + if( x < 0 ) + a = -a; + return(a); + } + +a *= a; +return( x + x * a * (polevl(a,P,3)/p1evl(a,Q,3)) ); +} diff --git a/components/external/espruino/libs/math/sqrt.c b/components/external/espruino/libs/math/sqrt.c new file mode 100644 index 0000000000..8ff5d050a2 --- /dev/null +++ b/components/external/espruino/libs/math/sqrt.c @@ -0,0 +1,178 @@ +/* sqrt.c + * + * Square root + * + * + * + * SYNOPSIS: + * + * double x, y, sqrt(); + * + * y = sqrt( x ); + * + * + * + * DESCRIPTION: + * + * Returns the square root of x. + * + * Range reduction involves isolating the power of two of the + * argument and using a polynomial approximation to obtain + * a rough value for the square root. Then Heron's iteration + * is used three times to converge to an accurate value. + * + * + * + * ACCURACY: + * + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC 0, 10 60000 2.1e-17 7.9e-18 + * IEEE 0,1.7e308 30000 1.7e-16 6.3e-17 + * + * + * ERROR MESSAGES: + * + * message condition value returned + * sqrt domain x < 0 0.0 + * + */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 2000 by Stephen L. Moshier +*/ + + +#include "mconf.h" +#ifdef ANSIPROT +extern double frexp ( double, int * ); +extern double ldexp ( double, int ); +#else +double frexp(), ldexp(); +#endif +extern double SQRT2; /* SQRT2 = 1.41421356237309504880 */ + +double sqrt(x) +double x; +{ +int e; +#ifndef UNK +short *q; +#endif +double z, w; + +if( x <= 0.0 ) + { + if( x < 0.0 ) + mtherr( "sqrt", DOMAIN ); + return( 0.0 ); + } +w = x; +/* separate exponent and significand */ +#ifdef UNK +z = frexp( x, &e ); +#endif +#ifdef DEC +q = (short *)&x; +e = ((*q >> 7) & 0377) - 0200; +*q &= 0177; +*q |= 040000; +z = x; +#endif + +/* Note, frexp and ldexp are used in order to + * handle denormal numbers properly. + */ +#ifdef IBMPC +z = frexp( x, &e ); +q = (short *)&x; +q += 3; +/* +e = ((*q >> 4) & 0x0fff) - 0x3fe; +*q &= 0x000f; +*q |= 0x3fe0; +z = x; +*/ +#endif +#ifdef MIEEE +z = frexp( x, &e ); +q = (short *)&x; +/* +e = ((*q >> 4) & 0x0fff) - 0x3fe; +*q &= 0x000f; +*q |= 0x3fe0; +z = x; +*/ +#endif + +/* approximate square root of number between 0.5 and 1 + * relative error of approximation = 7.47e-3 + */ +x = 4.173075996388649989089E-1 + 5.9016206709064458299663E-1 * z; + +/* adjust for odd powers of 2 */ +if( (e & 1) != 0 ) + x *= SQRT2; + +/* re-insert exponent */ +#ifdef UNK +x = ldexp( x, (e >> 1) ); +#endif +#ifdef DEC +*q += ((e >> 1) & 0377) << 7; +*q &= 077777; +#endif +#ifdef IBMPC +x = ldexp( x, (e >> 1) ); +/* +*q += ((e >>1) & 0x7ff) << 4; +*q &= 077777; +*/ +#endif +#ifdef MIEEE +x = ldexp( x, (e >> 1) ); +/* +*q += ((e >>1) & 0x7ff) << 4; +*q &= 077777; +*/ +#endif + +/* Newton iterations: */ +#ifdef UNK +x = 0.5*(x + w/x); +x = 0.5*(x + w/x); +x = 0.5*(x + w/x); +#endif + +/* Note, assume the square root cannot be denormal, + * so it is safe to use integer exponent operations here. + */ +#ifdef DEC +x += w/x; +*q -= 0200; +x += w/x; +*q -= 0200; +x += w/x; +*q -= 0200; +#endif +#ifdef IBMPC +x += w/x; +*q -= 0x10; +x += w/x; +*q -= 0x10; +x += w/x; +*q -= 0x10; +#endif +#ifdef MIEEE +x += w/x; +*q -= 0x10; +x += w/x; +*q -= 0x10; +x += w/x; +*q -= 0x10; +#endif + +return(x); +} diff --git a/components/external/espruino/libs/math/tan.c b/components/external/espruino/libs/math/tan.c new file mode 100644 index 0000000000..b2578ca7a6 --- /dev/null +++ b/components/external/espruino/libs/math/tan.c @@ -0,0 +1,304 @@ +/* tan.c + * + * Circular tangent + * + * + * + * SYNOPSIS: + * + * double x, y, tan(); + * + * y = tan( x ); + * + * + * + * DESCRIPTION: + * + * Returns the circular tangent of the radian argument x. + * + * Range reduction is modulo pi/4. A rational function + * x + x**3 P(x**2)/Q(x**2) + * is employed in the basic interval [0, pi/4]. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC +-1.07e9 44000 4.1e-17 1.0e-17 + * IEEE +-1.07e9 30000 2.9e-16 8.1e-17 + * + * ERROR MESSAGES: + * + * message condition value returned + * tan total loss x > 1.073741824e9 0.0 + * + */ + /* cot.c + * + * Circular cotangent + * + * + * + * SYNOPSIS: + * + * double x, y, cot(); + * + * y = cot( x ); + * + * + * + * DESCRIPTION: + * + * Returns the circular cotangent of the radian argument x. + * + * Range reduction is modulo pi/4. A rational function + * x + x**3 P(x**2)/Q(x**2) + * is employed in the basic interval [0, pi/4]. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE +-1.07e9 30000 2.9e-16 8.2e-17 + * + * + * ERROR MESSAGES: + * + * message condition value returned + * cot total loss x > 1.073741824e9 0.0 + * cot singularity x = 0 INFINITY + * + */ + +/* +Cephes Math Library Release 2.8: June, 2000 +yright 1984, 1995, 2000 by Stephen L. Moshier +*/ + +#include "mconf.h" + +#ifdef UNK +const static double P[] = { +-1.30936939181383777646E4, + 1.15351664838587416140E6, +-1.79565251976484877988E7 +}; +const static double Q[] = { +/* 1.00000000000000000000E0,*/ + 1.36812963470692954678E4, +-1.32089234440210967447E6, + 2.50083801823357915839E7, +-5.38695755929454629881E7 +}; +const static double DP1 = 7.853981554508209228515625E-1; +const static double DP2 = 7.94662735614792836714E-9; +const static double DP3 = 3.06161699786838294307E-17; +const static double lossth = 1.073741824e9; +#endif + +#ifdef DEC +static unsigned short P[] = { +0143514,0113306,0111171,0174674, +0045214,0147545,0027744,0167346, +0146210,0177526,0114514,0105660 +}; +static unsigned short Q[] = { +/*0040200,0000000,0000000,0000000,*/ +0043525,0142457,0072633,0025617, +0145241,0036742,0140525,0162256, +0046276,0146176,0013526,0143573, +0146515,0077401,0162762,0150607 +}; +/* 7.853981629014015197753906250000E-1 */ +static unsigned short P1[] = {0040111,0007732,0120000,0000000,}; +/* 4.960467869796758577649598009884E-10 */ +static unsigned short P2[] = {0030410,0055060,0100000,0000000,}; +/* 2.860594363054915898381331279295E-18 */ +static unsigned short P3[] = {0021523,0011431,0105056,0001560,}; +#define DP1 *(double *)P1 +#define DP2 *(double *)P2 +#define DP3 *(double *)P3 +const static double lossth = 1.073741824e9; +#endif + +#ifdef IBMPC +static unsigned short P[] = { +0x3f38,0xd24f,0x92d8,0xc0c9, +0x9ddd,0xa5fc,0x99ec,0x4131, +0x9176,0xd329,0x1fea,0xc171 +}; +static unsigned short Q[] = { +/*0x0000,0x0000,0x0000,0x3ff0,*/ +0x6572,0xeeb3,0xb8a5,0x40ca, +0xbc96,0x582a,0x27bc,0xc134, +0xd8ef,0xc2ea,0xd98f,0x4177, +0x5a31,0x3cbe,0xafe0,0xc189 +}; +/* + 7.85398125648498535156E-1, + 3.77489470793079817668E-8, + 2.69515142907905952645E-15, +*/ +static unsigned short P1[] = {0x0000,0x4000,0x21fb,0x3fe9}; +static unsigned short P2[] = {0x0000,0x0000,0x442d,0x3e64}; +static unsigned short P3[] = {0x5170,0x98cc,0x4698,0x3ce8}; +#define DP1 *(double *)P1 +#define DP2 *(double *)P2 +#define DP3 *(double *)P3 +const static double lossth = 1.073741824e9; +#endif + +#ifdef MIEEE +static unsigned short P[] = { +0xc0c9,0x92d8,0xd24f,0x3f38, +0x4131,0x99ec,0xa5fc,0x9ddd, +0xc171,0x1fea,0xd329,0x9176 +}; +static unsigned short Q[] = { +0x40ca,0xb8a5,0xeeb3,0x6572, +0xc134,0x27bc,0x582a,0xbc96, +0x4177,0xd98f,0xc2ea,0xd8ef, +0xc189,0xafe0,0x3cbe,0x5a31 +}; +static unsigned short P1[] = { +0x3fe9,0x21fb,0x4000,0x0000 +}; +static unsigned short P2[] = { +0x3e64,0x442d,0x0000,0x0000 +}; +static unsigned short P3[] = { +0x3ce8,0x4698,0x98cc,0x5170, +}; +#define DP1 *(double *)P1 +#define DP2 *(double *)P2 +#define DP3 *(double *)P3 +const static double lossth = 1.073741824e9; +#endif + +#ifdef ANSIPROT +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern double floor ( double ); +extern double ldexp ( double, int ); +extern int isnan ( double ); +extern int isfinite ( double ); +const static double tancot(double, int); +#else +double polevl(), p1evl(), floor(), ldexp(); +const static double tancot(); +int isnan(), isfinite(); +#endif +extern double PIO4; +extern double INFINITY; +extern double NAN; + +double tan(x) +double x; +{ +#ifdef MINUSZERO +if( x == 0.0 ) + return(x); +#endif +#ifdef NANS +if( isnan(x) ) + return(x); +if( !isfinite(x) ) + { + mtherr( "tan", DOMAIN ); + return(NAN); + } +#endif +return( tancot(x,0) ); +} + + +double cot(x) +double x; +{ + +if( x == 0.0 ) + { + mtherr( "cot", SING ); + return( INFINITY ); + } +return( tancot(x,1) ); +} + + +const static double tancot( xx, cotflg ) +double xx; +int cotflg; +{ +double x, y, z, zz; +int j, sign; + +/* make argument positive but save the sign */ +if( xx < 0 ) + { + x = -xx; + sign = -1; + } +else + { + x = xx; + sign = 1; + } + +if( x > lossth ) + { + if( cotflg ) + mtherr( "cot", TLOSS ); + else + mtherr( "tan", TLOSS ); + return(0.0); + } + +/* compute x mod PIO4 */ +y = floor( x/PIO4 ); + +/* strip high bits of integer part */ +z = ldexp( y, -3 ); +z = floor(z); /* integer part of y/8 */ +z = y - ldexp( z, 3 ); /* y - 16 * (y/16) */ + +/* integer and fractional part modulo one octant */ +j = z; + +/* map zeros and singularities to origin */ +if( j & 1 ) + { + j += 1; + y += 1.0; + } + +z = ((x - y * DP1) - y * DP2) - y * DP3; + +zz = z * z; + +if( zz > 1.0e-14 ) + y = z + z * (zz * polevl( zz, P, 2 )/p1evl(zz, Q, 4)); +else + y = z; + +if( j & 2 ) + { + if( cotflg ) + y = -y; + else + y = -1.0/y; + } +else + { + if( cotflg ) + y = 1.0/y; + } + +if( sign < 0 ) + y = -y; + +return( y ); +} diff --git a/components/external/espruino/libs/math/tandg.c b/components/external/espruino/libs/math/tandg.c new file mode 100644 index 0000000000..8bbd11d478 --- /dev/null +++ b/components/external/espruino/libs/math/tandg.c @@ -0,0 +1,267 @@ +/* tandg.c + * + * Circular tangent of argument in degrees + * + * + * + * SYNOPSIS: + * + * double x, y, tandg(); + * + * y = tandg( x ); + * + * + * + * DESCRIPTION: + * + * Returns the circular tangent of the argument x in degrees. + * + * Range reduction is modulo pi/4. A rational function + * x + x**3 P(x**2)/Q(x**2) + * is employed in the basic interval [0, pi/4]. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC 0,10 8000 3.4e-17 1.2e-17 + * IEEE 0,10 30000 3.2e-16 8.4e-17 + * + * ERROR MESSAGES: + * + * message condition value returned + * tandg total loss x > 8.0e14 (DEC) 0.0 + * x > 1.0e14 (IEEE) + * tandg singularity x = 180 k + 90 MAXNUM + */ + /* cotdg.c + * + * Circular cotangent of argument in degrees + * + * + * + * SYNOPSIS: + * + * double x, y, cotdg(); + * + * y = cotdg( x ); + * + * + * + * DESCRIPTION: + * + * Returns the circular cotangent of the argument x in degrees. + * + * Range reduction is modulo pi/4. A rational function + * x + x**3 P(x**2)/Q(x**2) + * is employed in the basic interval [0, pi/4]. + * + * + * ERROR MESSAGES: + * + * message condition value returned + * cotdg total loss x > 8.0e14 (DEC) 0.0 + * x > 1.0e14 (IEEE) + * cotdg singularity x = 180 k MAXNUM + */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*/ + +#include "mconf.h" + +#ifdef UNK +const static double P[] = { +-1.30936939181383777646E4, + 1.15351664838587416140E6, +-1.79565251976484877988E7 +}; +const static double Q[] = { +/* 1.00000000000000000000E0,*/ + 1.36812963470692954678E4, +-1.32089234440210967447E6, + 2.50083801823357915839E7, +-5.38695755929454629881E7 +}; +const static double PI180 = 1.74532925199432957692E-2; +const static double lossth = 1.0e14; +#endif + +#ifdef DEC +static unsigned short P[] = { +0143514,0113306,0111171,0174674, +0045214,0147545,0027744,0167346, +0146210,0177526,0114514,0105660 +}; +static unsigned short Q[] = { +/*0040200,0000000,0000000,0000000,*/ +0043525,0142457,0072633,0025617, +0145241,0036742,0140525,0162256, +0046276,0146176,0013526,0143573, +0146515,0077401,0162762,0150607 +}; +static unsigned short P1[] = {0036616,0175065,0011224,0164711}; +#define PI180 *(double *)P1 +const static double lossth = 8.0e14; +#endif + +#ifdef IBMPC +static unsigned short P[] = { +0x3f38,0xd24f,0x92d8,0xc0c9, +0x9ddd,0xa5fc,0x99ec,0x4131, +0x9176,0xd329,0x1fea,0xc171 +}; +static unsigned short Q[] = { +/*0x0000,0x0000,0x0000,0x3ff0,*/ +0x6572,0xeeb3,0xb8a5,0x40ca, +0xbc96,0x582a,0x27bc,0xc134, +0xd8ef,0xc2ea,0xd98f,0x4177, +0x5a31,0x3cbe,0xafe0,0xc189 +}; +static unsigned short P1[] = {0x9d39,0xa252,0xdf46,0x3f91}; +#define PI180 *(double *)P1 +const static double lossth = 1.0e14; +#endif + +#ifdef MIEEE +static unsigned short P[] = { +0xc0c9,0x92d8,0xd24f,0x3f38, +0x4131,0x99ec,0xa5fc,0x9ddd, +0xc171,0x1fea,0xd329,0x9176 +}; +static unsigned short Q[] = { +0x40ca,0xb8a5,0xeeb3,0x6572, +0xc134,0x27bc,0x582a,0xbc96, +0x4177,0xd98f,0xc2ea,0xd8ef, +0xc189,0xafe0,0x3cbe,0x5a31 +}; +static unsigned short P1[] = { +0x3f91,0xdf46,0xa252,0x9d39 +}; +#define PI180 *(double *)P1 +const static double lossth = 1.0e14; +#endif + +#ifdef ANSIPROT +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern double floor ( double ); +extern double ldexp ( double, int ); +const static double tancot( double, int ); +#else +double polevl(), p1evl(), floor(), ldexp(); +const static double tancot(); +#endif +extern double MAXNUM; +extern double PIO4; + + +double tandg(x) +double x; +{ + +return( tancot(x,0) ); +} + + +double cotdg(x) +double x; +{ + +return( tancot(x,1) ); +} + + +const static double tancot( xx, cotflg ) +double xx; +int cotflg; +{ +double x, y, z, zz; +int j, sign; + +/* make argument positive but save the sign */ +if( xx < 0 ) + { + x = -xx; + sign = -1; + } +else + { + x = xx; + sign = 1; + } + +if( x > lossth ) + { + mtherr( "tandg", TLOSS ); + return(0.0); + } + +/* compute x mod PIO4 */ +y = floor( x/45.0 ); + +/* strip high bits of integer part */ +z = ldexp( y, -3 ); +z = floor(z); /* integer part of y/8 */ +z = y - ldexp( z, 3 ); /* y - 16 * (y/16) */ + +/* integer and fractional part modulo one octant */ +j = z; + +/* map zeros and singularities to origin */ +if( j & 1 ) + { + j += 1; + y += 1.0; + } + +z = x - y * 45.0; +z *= PI180; + +zz = z * z; + +if( zz > 1.0e-14 ) + y = z + z * (zz * polevl( zz, P, 2 )/p1evl(zz, Q, 4)); +else + y = z; + +if( j & 2 ) + { + if( cotflg ) + y = -y; + else + { + if( y != 0.0 ) + { + y = -1.0/y; + } + else + { + mtherr( "tandg", SING ); + y = MAXNUM; + } + } + } +else + { + if( cotflg ) + { + if( y != 0.0 ) + y = 1.0/y; + else + { + mtherr( "cotdg", SING ); + y = MAXNUM; + } + } + } + +if( sign < 0 ) + y = -y; + +return( y ); +} diff --git a/components/external/espruino/libs/math/tanh.c b/components/external/espruino/libs/math/tanh.c new file mode 100644 index 0000000000..ec4a5296b8 --- /dev/null +++ b/components/external/espruino/libs/math/tanh.c @@ -0,0 +1,141 @@ +/* tanh.c + * + * Hyperbolic tangent + * + * + * + * SYNOPSIS: + * + * double x, y, tanh(); + * + * y = tanh( x ); + * + * + * + * DESCRIPTION: + * + * Returns hyperbolic tangent of argument in the range MINLOG to + * MAXLOG. + * + * A rational function is used for |x| < 0.625. The form + * x + x**3 P(x)/Q(x) of Cody _& Waite is employed. + * Otherwise, + * tanh(x) = sinh(x)/cosh(x) = 1 - 2/(exp(2x) + 1). + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -2,2 50000 3.3e-17 6.4e-18 + * IEEE -2,2 30000 2.5e-16 5.8e-17 + * + */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + +#include "mconf.h" + +#ifdef UNK +const static double P[] = { +-9.64399179425052238628E-1, +-9.92877231001918586564E1, +-1.61468768441708447952E3 +}; +const static double Q[] = { +/* 1.00000000000000000000E0,*/ + 1.12811678491632931402E2, + 2.23548839060100448583E3, + 4.84406305325125486048E3 +}; +#endif +#ifdef DEC +static unsigned short P[] = { +0140166,0161335,0053753,0075126, +0141706,0111520,0070463,0040552, +0142711,0153001,0101300,0025430 +}; +static unsigned short Q[] = { +/*0040200,0000000,0000000,0000000,*/ +0041741,0117624,0051300,0156060, +0043013,0133720,0071251,0127717, +0043227,0060201,0021020,0020136 +}; +#endif + +#ifdef IBMPC +static unsigned short P[] = { +0x6f4b,0xaafd,0xdc5b,0xbfee, +0x682d,0x0e26,0xd26a,0xc058, +0x0563,0x3058,0x3ac0,0xc099 +}; +static unsigned short Q[] = { +/*0x0000,0x0000,0x0000,0x3ff0,*/ +0x1b86,0x8a58,0x33f2,0x405c, +0x35fa,0x0e55,0x76fa,0x40a1, +0x040c,0x2442,0xec10,0x40b2 +}; +#endif + +#ifdef MIEEE +static unsigned short P[] = { +0xbfee,0xdc5b,0xaafd,0x6f4b, +0xc058,0xd26a,0x0e26,0x682d, +0xc099,0x3ac0,0x3058,0x0563 +}; +static unsigned short Q[] = { +0x405c,0x33f2,0x8a58,0x1b86, +0x40a1,0x76fa,0x0e55,0x35fa, +0x40b2,0xec10,0x2442,0x040c +}; +#endif + +#ifdef ANSIPROT +extern double fabs ( double ); +extern double exp ( double ); +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +#else +double fabs(), exp(), polevl(), p1evl(); +#endif +extern double MAXLOG; + +double tanh(x) +double x; +{ +double s, z; + +#ifdef MINUSZERO +if( x == 0.0 ) + return(x); +#endif +z = fabs(x); +if( z > 0.5 * MAXLOG ) + { + if( x > 0 ) + return( 1.0 ); + else + return( -1.0 ); + } +if( z >= 0.625 ) + { + s = exp(2.0*z); + z = 1.0 - 2.0/(s + 1.0); + if( x < 0 ) + z = -z; + } +else + { + if( x == 0.0 ) + return(x); + s = x * x; + z = polevl( s, P, 2 )/p1evl(s, Q, 3); + z = x * s * z; + z = x + z; + } +return( z ); +} diff --git a/components/external/espruino/libs/math/unity.c b/components/external/espruino/libs/math/unity.c new file mode 100644 index 0000000000..c0de1c3a9f --- /dev/null +++ b/components/external/espruino/libs/math/unity.c @@ -0,0 +1,138 @@ +/* unity.c + * + * Relative error approximations for function arguments near + * unity. + * + * log1p(x) = log(1+x) + * expm1(x) = exp(x) - 1 + * cosm1(x) = cos(x) - 1 + * + */ + +#include "mconf.h" + +#ifdef ANSIPROT +extern int isnan (double); +extern int isfinite (double); +extern double log ( double ); +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern double exp ( double ); +extern double cos ( double ); +#else +double log(), polevl(), p1evl(), exp(), cos(); +int isnan(), isfinite(); +#endif +extern double INFINITY; + +/* log1p(x) = log(1 + x) */ + +/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 2.32e-20 + */ +const static double LP[] = { + 4.5270000862445199635215E-5, + 4.9854102823193375972212E-1, + 6.5787325942061044846969E0, + 2.9911919328553073277375E1, + 6.0949667980987787057556E1, + 5.7112963590585538103336E1, + 2.0039553499201281259648E1, +}; +const static double LQ[] = { +/* 1.0000000000000000000000E0,*/ + 1.5062909083469192043167E1, + 8.3047565967967209469434E1, + 2.2176239823732856465394E2, + 3.0909872225312059774938E2, + 2.1642788614495947685003E2, + 6.0118660497603843919306E1, +}; + +#define SQRTH 0.70710678118654752440 +#define SQRT2 1.41421356237309504880 + +double log1p(x) +double x; +{ +double z; + +z = 1.0 + x; +if( (z < SQRTH) || (z > SQRT2) ) + return( log(z) ); +z = x*x; +z = -0.5 * z + x * ( z * polevl( x, LP, 6 ) / p1evl( x, LQ, 6 ) ); +return (x + z); +} + + + +/* expm1(x) = exp(x) - 1 */ + +/* e^x = 1 + 2x P(x^2)/( Q(x^2) - P(x^2) ) + * -0.5 <= x <= 0.5 + */ + +const static double EP[3] = { + 1.2617719307481059087798E-4, + 3.0299440770744196129956E-2, + 9.9999999999999999991025E-1, +}; +const static double EQ[4] = { + 3.0019850513866445504159E-6, + 2.5244834034968410419224E-3, + 2.2726554820815502876593E-1, + 2.0000000000000000000897E0, +}; + +double expm1(x) +double x; +{ +double r, xx; + +#ifdef NANS +if( isnan(x) ) + return(x); +#endif +#ifdef INFINITIES +if( x == INFINITY ) + return(INFINITY); +if( x == -INFINITY ) + return(-1.0); +#endif +if( (x < -0.5) || (x > 0.5) ) + return( exp(x) - 1.0 ); +xx = x * x; +r = x * polevl( xx, EP, 2 ); +r = r/( polevl( xx, EQ, 3 ) - r ); +return (r + r); +} + + + +/* cosm1(x) = cos(x) - 1 */ + +const static double coscof[7] = { + 4.7377507964246204691685E-14, +-1.1470284843425359765671E-11, + 2.0876754287081521758361E-9, +-2.7557319214999787979814E-7, + 2.4801587301570552304991E-5, +-1.3888888888888872993737E-3, + 4.1666666666666666609054E-2, +}; + +extern double PIO4; + +double cosm1(x) +double x; +{ +double xx; + +if( (x < -PIO4) || (x > PIO4) ) + return( cos(x) - 1.0 ); +xx = x * x; +xx = -0.5*xx + xx * xx * polevl( xx, coscof, 6 ); +return xx; +} diff --git a/components/external/espruino/libs/math/unix.mak b/components/external/espruino/libs/math/unix.mak new file mode 100644 index 0000000000..e6e7da5484 --- /dev/null +++ b/components/external/espruino/libs/math/unix.mak @@ -0,0 +1,109 @@ +# Double precision Cephes library +# Makefile for unix or GCC + +CC = gcc +CFLAGS = -g -O2 -Wall -fno-builtin +AR = ar +RANLIB = ranlib +INCS = mconf.h +AS = as + +OBJS = acosh.o airy.o asin.o asinh.o atan.o atanh.o bdtr.o beta.o \ +btdtr.o cbrt.o chbevl.o chdtr.o clog.o cmplx.o const.o \ +cosh.o dawsn.o drand.o ellie.o ellik.o ellpe.o ellpj.o ellpk.o \ +exp.o exp10.o exp2.o expn.o fabs.o fac.o fdtr.o \ +fresnl.o gamma.o gdtr.o hyp2f1.o hyperg.o i0.o i1.o igami.o \ +incbet.o incbi.o igam.o isnan.o iv.o j0.o j1.o jn.o jv.o k0.o k1.o \ +kn.o log.o log2.o log10.o lrand.o nbdtr.o ndtr.o ndtri.o pdtr.o \ +polevl.o polmisc.o polyn.o pow.o powi.o psi.o rgamma.o round.o \ +shichi.o sici.o sin.o sindg.o sinh.o spence.o stdtr.o struve.o \ +tan.o tandg.o tanh.o unity.o yn.o zeta.o zetac.o \ +sqrt.o floor.o setprec.o mtherr.o + +all: libmd.a mtst dtestvec dcalc paranoia # stamp-timing + +stamp-timing: libmd.a mtst time-it + time-it "mtst > /dev/null" + touch stamp-timing + +time-it: time-it.o + $(CC) -o time-it time-it.o + +time-it.o: time-it.c + $(CC) -O2 -c time-it.c + +dcalc: dcalc.o libmd.a + $(CC) -o dcalc dcalc.o libmd.a +# aout2exe mtst + +mtst: mtst.o libmd.a + $(CC) -v -o mtst mtst.o libmd.a +# gcc -Wl,-verbose -b i486-linuxaout -v -o mtst mtst.o libmd.a +# coff2exe mtst + +mtst.o: mtst.c + $(CC) -O2 -Wall -c mtst.c + +dtestvec: dtestvec.o libmd.a + $(CC) -o dtestvec dtestvec.o libmd.a + +dtestvec.o: dtestvec.c + $(CC) -g -c dtestvec.c + +paranoia: paranoia.o setprec.o libmd.a + $(CC) -o paranoia paranoia.o setprec.o libmd.a + +paranoia.o: paranoia.c + $(CC) $(CFLAGS) -c paranoia.c + +libmd.a: $(OBJS) $(INCS) +# for real Unix: + $(AR) rv libmd.a $(OBJS) +# for djgcc MSDOS: +# >libmd.rf -rv libmd.a $(OBJS) +# $(AR) @libmd.rf + $(RANLIB) libmd.a + +# If the following are all commented out, the C versions +# will be used by default. + +# IBM PC: +#sqrt.o: sqrt.387 +# $(AS) -o sqrt.o sqrt.387 +# +#floor.o: floor.387 +# $(AS) -o floor.o floor.387 +# +#setprec.o: setprec.387 +# $(AS) -o setprec.o setprec.387 + +# ELF versions for linux (no underscores) +sqrt.o: sqrtelf.387 + $(AS) -o sqrt.o sqrtelf.387 + +#floor.o: floorelf.387 +# $(AS) -o floor.o floorelf.387 + +setprec.o: setprelf.387 + $(AS) -o setprec.o setprelf.387 + +# Motorola 68881. Caution, subroutine return conventions vary. +#sqrt.o: sqrt.688 +# $(AS) -o sqrt.o sqrt.688 +# +#setprec.o: setprec.688 +# $(AS) -o setprec.o setprec.688 + +# SPARC: +#sqrt.o: sqrt.spa +# $(AS) -o sqrt.o sqrt.spa + +clean: + rm -f *.o + rm -f mtst + rm -f paranoia + rm -f dcalc + rm -f libmd.a + rm -f time-it + rm -f dtestvec + diff --git a/components/external/espruino/src/jsdevices.c b/components/external/espruino/src/jsdevices.c new file mode 100644 index 0000000000..4c7c9715f9 --- /dev/null +++ b/components/external/espruino/src/jsdevices.c @@ -0,0 +1,336 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Common low-level device handling (Events, IO buffers) + * ---------------------------------------------------------------------------- + */ +#include "jsdevices.h" +#include "jsparse.h" +#include "jsinteractive.h" + +#ifdef LINUX + #include +#endif//LINUX +#ifdef USE_TRIGGER +#include "trigger.h" +#endif +#ifdef USE_CC3000 +#include "board_spi.h" +#endif +// ---------------------------------------------------------------------------- +// BUFFERS + +// ---------------------------------------------------------------------------- +// DATA TRANSMIT BUFFER +typedef struct { + IOEventFlags flags; // Where this data should be transmitted + unsigned char data; // data to transmit +} PACKED_FLAGS TxBufferItem; + +TxBufferItem txBuffer[TXBUFFERMASK+1]; +volatile unsigned char txHead=0, txTail=0; +// ---------------------------------------------------------------------------- + +// Queue a character for transmission +void jshTransmit(IOEventFlags device, unsigned char data) { +#ifdef RT_USING_JS + rt_device_write(rt_console_get_device(), 0, &data, 1); +#else +#ifndef LINUX +#ifdef USB + if (device==EV_USBSERIAL && !jshIsUSBSERIALConnected()) { + jshTransmitClearDevice(EV_USBSERIAL); // clear out stuff already waiting + return; + } +#endif + if (device==EV_NONE) return; + unsigned char txHeadNext = (txHead+1)&TXBUFFERMASK; + if (txHeadNext==txTail) { + jsiSetBusy(BUSY_TRANSMIT, true); + while (txHeadNext==txTail) { + // wait for send to finish as buffer is about to overflow +#ifdef USB + // just in case USB was unplugged while we were waiting! + if (!jshIsUSBSERIALConnected()) jshTransmitClearDevice(EV_USBSERIAL); +#endif + } + jsiSetBusy(BUSY_TRANSMIT, false); + } + txBuffer[txHead].flags = device; + txBuffer[txHead].data = (char)data; + txHead = txHeadNext; + + jshUSARTKick(device); // set up interrupts if required + +#else // if PC, just put to stdout + if (device==DEFAULT_CONSOLE_DEVICE) { + fputc(data, stdout); + fflush(stdout); + } +#endif +#endif +} + +// Try and get a character for transmission - could just return -1 if nothing +int jshGetCharToTransmit(IOEventFlags device) { + unsigned char ptr = txTail; + while (txHead != ptr) { + if (IOEVENTFLAGS_GETTYPE(txBuffer[ptr].flags) == device) { + unsigned char data = txBuffer[ptr].data; + if (ptr != txTail) { // so we weren't right at the back of the queue + // we need to work back from ptr (until we hit tail), shifting everything forwards + unsigned char this = ptr; + unsigned char last = (unsigned char)((this+TXBUFFERMASK)&TXBUFFERMASK); + while (this!=txTail) { // if this==txTail, then last is before it, so stop here + txBuffer[this] = txBuffer[last]; + this = last; + last = (unsigned char)((this+TXBUFFERMASK)&TXBUFFERMASK); + } + } + txTail = (unsigned char)((txTail+1)&TXBUFFERMASK); // advance the tail + return data; // return data + } + ptr = (unsigned char)((ptr+1)&TXBUFFERMASK); + } + return -1; // no data :( +} + +void jshTransmitFlush() { + jsiSetBusy(BUSY_TRANSMIT, true); + while (jshHasTransmitData()) ; // wait for send to finish + jsiSetBusy(BUSY_TRANSMIT, false); +} + +// Clear everything from a device +void jshTransmitClearDevice(IOEventFlags device) { + while (jshGetCharToTransmit(device)>=0); +} + +bool jshHasTransmitData() { +#ifndef LINUX + return txHead != txTail; +#else + return false; +#endif +} + +// ---------------------------------------------------------------------------- +// IO EVENT BUFFER +IOEvent ioBuffer[IOBUFFERMASK+1]; +volatile unsigned char ioHead=0, ioTail=0; +// ---------------------------------------------------------------------------- + + +void jshIOEventOverflowed() { + // Error here - just light LED as we can't do much else right now +} + + +void jshPushIOCharEvent(IOEventFlags channel, char charData) { + if (charData==3 && channel==jsiGetConsoleDevice()) { + // Ctrl-C - force interrupt +#ifdef LINUX + raise(SIGINT); +#endif + jspSetInterrupted(true); + return; + } + if (DEVICE_IS_USART(channel) && jshGetEventsUsed() > IOBUFFER_XOFF) + jshSetFlowControlXON(channel, false); + // Check for existing buffer (we must have at least 2 in the queue to avoid dropping chars though!) + unsigned char nextTail = (unsigned char)((ioTail+1) & IOBUFFERMASK); + if (ioHead!=ioTail && ioHead!=nextTail) { + // we can do this because we only read in main loop, and we're in an interrupt here + unsigned char lastHead = (unsigned char)((ioHead+IOBUFFERMASK) & IOBUFFERMASK); // one behind head + if (IOEVENTFLAGS_GETTYPE(ioBuffer[lastHead].flags) == channel && + IOEVENTFLAGS_GETCHARS(ioBuffer[lastHead].flags) < IOEVENT_MAXCHARS) { + // last event was for this event type, and it has chars left + unsigned char c = (unsigned char)IOEVENTFLAGS_GETCHARS(ioBuffer[lastHead].flags); + ioBuffer[lastHead].data.chars[c] = charData; + IOEVENTFLAGS_SETCHARS(ioBuffer[lastHead].flags, c+1); + return; + } + } + // Make new buffer + unsigned char nextHead = (unsigned char)((ioHead+1) & IOBUFFERMASK); + if (ioTail == nextHead) { + jshIOEventOverflowed(); + return; // queue full - dump this event! + } + ioBuffer[ioHead].flags = channel; + IOEVENTFLAGS_SETCHARS(ioBuffer[ioHead].flags, 1); + ioBuffer[ioHead].data.chars[0] = charData; + ioHead = nextHead; +} + +void jshPushIOWatchEvent(IOEventFlags channel) { + JsSysTime time = jshGetSystemTime(); + bool state = jshGetWatchedPinState(channel); + +/* // This is some simple debounce code - however it requires that the event + // is not taken out of ioBuffer by the main thread, which will require + // a bit of fiddling in jsinteractive.c. In fact it might be worth just + // doing debounce outside of the interrupt + if (true) { // debounce + // scan back and see if we have an event for this pin + unsigned char prevHead = ioHead; + while (prevHead!=ioTail && (IOEVENTFLAGS_GETTYPE(ioBuffer[prevHead].flags)!=channel)) + prevHead = (unsigned char)((prevHead+IOBUFFERMASK) & IOBUFFERMASK); // step back + // if we have an event + if (prevHead!=ioTail && (IOEVENTFLAGS_GETTYPE(ioBuffer[prevHead].flags)==channel)) { + // just use it (with the same timestamp)... + ioBuffer[prevHead].flags = channel | (state?EV_EXTI_IS_HIGH:0); + return; + } + }*/ + +#ifdef USE_TRIGGER + if (trigHandleEXTI(channel | (state?EV_EXTI_IS_HIGH:0), time)) + return; +#endif +#ifdef USE_CC3000 + IOEvent event; + event.flags = channel; + if (!state && jshIsEventForPin(&event, WLAN_IRQ_PIN)) { + cc3000_irq_handler(); + } +#endif + // Otherwise add this event + jshPushIOEvent(channel | (state?EV_EXTI_IS_HIGH:0), time); +} + +void jshPushIOEvent(IOEventFlags channel, JsSysTime time) { + + unsigned char nextHead = (unsigned char)((ioHead+1) & IOBUFFERMASK); + if (ioTail == nextHead) { + jshIOEventOverflowed(); + return; // queue full - dump this event! + } + ioBuffer[ioHead].flags = channel; + ioBuffer[ioHead].data.time = time; + ioHead = nextHead; +} + +// returns true on success +bool jshPopIOEvent(IOEvent *result) { + if (ioHead==ioTail) return false; + *result = ioBuffer[ioTail]; + ioTail = (unsigned char)((ioTail+1) & IOBUFFERMASK); + return true; +} + +bool jshHasEvents() { + return ioHead!=ioTail; +} + +int jshGetEventsUsed() { + int spaceUsed = (ioHead >= ioTail) ? ((int)ioHead-(int)ioTail) : /*or rolled*/((int)ioHead+IOBUFFERMASK+1-(int)ioTail); + return spaceUsed; +} + +bool jshHasEventSpaceForChars(int n) { + int spacesNeeded = 4 + (n/IOEVENT_MAXCHARS); // be sensible - leave a little spare + int spaceUsed = jshGetEventsUsed(); + int spaceLeft = IOBUFFERMASK+1-spaceUsed; + return spaceLeft > spacesNeeded; +} + +// ---------------------------------------------------------------------------- +// DEVICES +const char *jshGetDeviceString(IOEventFlags device) { + switch (device) { +#ifdef USB + case EV_USBSERIAL: return "USB"; +#endif + case EV_SERIAL1: return "Serial1"; + case EV_SERIAL2: return "Serial2"; + case EV_SERIAL3: return "Serial3"; +#if USARTS>=4 + case EV_SERIAL4: return "Serial4"; +#endif +#if USARTS>=5 + case EV_SERIAL5: return "Serial5"; +#endif +#if USARTS>=6 + case EV_SERIAL6: return "Serial6"; +#endif +#if SPIS>=1 + case EV_SPI1: return "SPI1"; +#endif +#if SPIS>=2 + case EV_SPI2: return "SPI2"; +#endif +#if SPIS>=3 + case EV_SPI3: return "SPI3"; +#endif +#if I2CS>=1 + case EV_I2C1: return "I2C1"; +#endif +#if I2CS>=2 + case EV_I2C2: return "I2C2"; +#endif +#if I2CS>=3 + case EV_I2C3: return "I2C3"; +#endif + default: return ""; + } +} + +IOEventFlags jshFromDeviceString(const char *device) { + if (device[0]=='U') { +#ifdef USB + if (strcmp(device, "USB")==0) return EV_USBSERIAL; +#endif + } + else if (device[0]=='S') { + if (device[1]=='e' && device[2]=='r' && device[3]=='i' && device[4]=='a' && device[5]=='l') { + if (strcmp(device, "Serial1")==0) return EV_SERIAL1; + if (strcmp(device, "Serial2")==0) return EV_SERIAL2; + if (strcmp(device, "Serial3")==0) return EV_SERIAL3; +#if USARTS>=4 + if (strcmp(device, "Serial4")==0) return EV_SERIAL4; +#endif +#if USARTS>=5 + if (strcmp(device, "Serial5")==0) return EV_SERIAL5; +#endif +#if USARTS>=6 + if (strcmp(device, "Serial6")==0) return EV_SERIAL6; +#endif + } + if (device[1]=='P' && device[2]=='I') { +#if SPIS>=1 + if (strcmp(device, "SPI1")==0) return EV_SPI1; +#endif +#if SPIS>=2 + if (strcmp(device, "SPI2")==0) return EV_SPI2; +#endif +#if SPIS>=3 + if (strcmp(device, "SPI3")==0) return EV_SPI3; +#endif + } + } + else if (device[0]=='I' && device[1]=='2' && device[2]=='C') { +#if I2CS>=1 + if (strcmp(device, "I2C1")==0) return EV_I2C1; +#endif +#if I2CS>=2 + if (strcmp(device, "I2C2")==0) return EV_I2C2; +#endif +#if I2CS>=3 + if (strcmp(device, "I2C3")==0) return EV_I2C3; +#endif + } + return EV_NONE; +} + +/// Set whether the host should transmit or not +void jshSetFlowControlXON(IOEventFlags device, bool hostShouldTransmit) { +} + diff --git a/components/external/espruino/src/jsdevices.h b/components/external/espruino/src/jsdevices.h new file mode 100644 index 0000000000..020a7ee332 --- /dev/null +++ b/components/external/espruino/src/jsdevices.h @@ -0,0 +1,127 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Common low-level device handling (Events, IO buffers) + * ---------------------------------------------------------------------------- + */ +#ifndef JSDEVICES_H_ +#define JSDEVICES_H_ + +#include "jsutils.h" +#include "platform_config.h" + +typedef enum { + // device type + EV_NONE, + EV_EXTI0, + EV_EXTI1, + EV_EXTI2, + EV_EXTI3, + EV_EXTI4, + EV_EXTI5, + EV_EXTI6, + EV_EXTI7, + EV_EXTI8, + EV_EXTI9, + EV_EXTI10, + EV_EXTI11, + EV_EXTI12, + EV_EXTI13, + EV_EXTI14, + EV_EXTI15, + EV_EXTI_MAX = EV_EXTI15, + EV_USBSERIAL, + EV_SERIAL1, + EV_SERIAL2, + EV_SERIAL3, + EV_SERIAL4, + EV_SERIAL5, + EV_SERIAL6, + EV_SERIAL_MAX = EV_SERIAL6, + EV_SPI1, + EV_SPI2, + EV_SPI3, + EV_SPI_MAX = EV_SPI3, + EV_I2C1, + EV_I2C2, + EV_I2C3, + EV_I2C_MAX = EV_I2C3, + EV_DEVICE_MAX = EV_I2C_MAX, + // EV_DEVICE_MAX should not be >64 - see DEVICE_INITIALISED_FLAGS + // Also helps if we're under 32 so we can fit IOEventFlags into a byte + EV_TYPE_MASK = NEXT_POWER_2(EV_DEVICE_MAX) - 1, + EV_CHARS_MASK = 7 * NEXT_POWER_2(EV_DEVICE_MAX), + // ----------------------------------------- + // if the pin we're watching is high, the handler sets this + EV_EXTI_IS_HIGH = NEXT_POWER_2(EV_DEVICE_MAX), +} PACKED_FLAGS IOEventFlags; + +#define DEVICE_IS_USART(X) (((X)>=EV_USBSERIAL)&& ((X)<=EV_SERIAL_MAX)) +#define DEVICE_IS_SPI(X) (((X)>=EV_SPI1) || ((X)<=EV_SPI_MAX)) +#define DEVICE_IS_I2C(X) (((X)>=EV_I2C1) || ((X)<=EV_I2C_MAX)) +#define DEVICE_IS_EXTI(X) (((X)>=EV_EXTI0) || ((X)<=EV_EXTI_MAX)) + +#define IOEVENTFLAGS_GETTYPE(X) ((X)&EV_TYPE_MASK) +#define IOEVENTFLAGS_GETCHARS(X) ((((X)&EV_CHARS_MASK)>>5)+1) +#define IOEVENTFLAGS_SETCHARS(X,CHARS) ((X)=(((X)&(IOEventFlags)~EV_CHARS_MASK) | (((CHARS)-1)<<5))) +#define IOEVENT_MAXCHARS 8 + +typedef union { + JsSysTime time; // time event occurred + char chars[IOEVENT_MAXCHARS]; +} PACKED_FLAGS IOEventData; + +// IO Events - these happen when a pin changes +typedef struct IOEvent { + IOEventFlags flags; // where this came from, and # of chars in it + IOEventData data; +} PACKED_FLAGS IOEvent; + +void jshPushIOEvent(IOEventFlags channel, JsSysTime time); +void jshPushIOWatchEvent(IOEventFlags channel); // push an even when a pin changes state +/// Push a single character event (for example USART RX) +void jshPushIOCharEvent(IOEventFlags channel, char charData); +/// Push many character events at once (for example USB RX) +static inline void jshPushIOCharEvents(IOEventFlags channel, char *data, unsigned int count) { + // TODO: optimise me! + unsigned int i; + for (i=0;i + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Hardware interface Layer + * NOTE: The definitions of these functions are inside: + * targets/{target}/jshardware.c + * ---------------------------------------------------------------------------- + */ + +#ifndef JSHARDWARE_H_ +#define JSHARDWARE_H_ + +#include "jsutils.h" +#include "jsvar.h" +#include "jsdevices.h" +#include "jspin.h" +#ifndef LINUX +#include "jspininfo.h" +#else +#include +#endif + +void jshInit(); +void jshKill(); +void jshIdle(); // stuff to do on idle + +/// Get this IC's serial number. Passed max # of chars and a pointer to write to. Returns # of chars +int jshGetSerialNumber(unsigned char *data, int maxChars); + +bool jshIsUSBSERIALConnected(); // is the serial device connected? + +/// Get the system time (in ticks) +JsSysTime jshGetSystemTime(); +/// Convert a time in Milliseconds to one in ticks +JsSysTime jshGetTimeFromMilliseconds(JsVarFloat ms); +/// Convert ticks to a time in Milliseconds +JsVarFloat jshGetMillisecondsFromTime(JsSysTime time); + +// software IO functions... +void jshInterruptOff(); +void jshInterruptOn(); +void jshDelayMicroseconds(int microsec); +void jshPinSetValue(Pin pin, bool value); +bool jshPinGetValue(Pin pin); +// ------ + +typedef enum { + JSHPINSTATE_UNDEFINED, + JSHPINSTATE_GPIO_OUT, + JSHPINSTATE_GPIO_OUT_OPENDRAIN, + JSHPINSTATE_GPIO_IN, + JSHPINSTATE_GPIO_IN_PULLUP, + JSHPINSTATE_GPIO_IN_PULLDOWN, + JSHPINSTATE_ADC_IN, + JSHPINSTATE_AF_OUT, + JSHPINSTATE_USART_IN, + JSHPINSTATE_USART_OUT, + JSHPINSTATE_DAC_OUT, + JSHPINSTATE_I2C, + JSHPINSTATE_MASK = NEXT_POWER_2(JSHPINSTATE_I2C)-1, + + JSHPINSTATE_PIN_IS_ON = JSHPINSTATE_MASK+1, +} PACKED_FLAGS JshPinState; + +#define JSHPINSTATE_IS_OUTPUT(state) ( \ + state==JSHPINSTATE_GPIO_OUT || \ + state==JSHPINSTATE_GPIO_OUT_OPENDRAIN || \ + state==JSHPINSTATE_AF_OUT || \ + state==JSHPINSTATE_USART_OUT || \ + state==JSHPINSTATE_DAC_OUT || \ + state==JSHPINSTATE_I2C \ +) + +/// Is the pin state manual (has the user asked us explicitly to change it?) +bool jshGetPinStateIsManual(Pin pin); +/// Is the pin state manual (has the user asked us explicitly to change it?) +void jshSetPinStateIsManual(Pin pin, bool manual); +/// Set the pin state +void jshPinSetState(Pin pin, JshPinState state); +/** Get the pin state (only accurate for simple IO - won't return JSHPINSTATE_USART_OUT for instance). + * Note that you should use JSHPINSTATE_MASK as other flags may have been added */ +JshPinState jshPinGetState(Pin pin); + + +bool jshPinInput(Pin pin); +JsVarFloat jshPinAnalog(Pin pin); +void jshPinOutput(Pin pin, bool value); +void jshPinAnalogOutput(Pin pin, JsVarFloat value, JsVarFloat freq); // if freq<=0, the default is used +void jshPinPulse(Pin pin, bool value, JsVarFloat time); +void jshPinWatch(Pin pin, bool shouldWatch); +/// returns false if timer queue was full... +bool jshPinOutputAtTime(JsSysTime time, Pin pin, bool value); + +/** Check the pin associated with this EXTI - return true if it is a 1 */ +bool jshGetWatchedPinState(IOEventFlags device); + +bool jshIsEventForPin(IOEvent *event, Pin pin); + +/** Is the given device initialised? */ +bool jshIsDeviceInitialised(IOEventFlags device); + + +#define DEFAULT_BAUD_RATE 9600 +#define DEFAULT_BYTESIZE 8 +#define DEFAULT_PARITY 0 +#define DEFAULT_STOPBITS 1 + +typedef struct { + int baudRate; // FIXME uint32_t ??? + Pin pinRX; + Pin pinTX; + unsigned char bytesize; + unsigned char parity; + unsigned char stopbits; +} PACKED_FLAGS JshUSARTInfo; + +static inline void jshUSARTInitInfo(JshUSARTInfo *inf) { + inf->baudRate = DEFAULT_BAUD_RATE; + inf->pinRX = PIN_UNDEFINED; + inf->pinTX = PIN_UNDEFINED; + inf->bytesize = DEFAULT_BYTESIZE; + inf->parity = DEFAULT_PARITY; // PARITY_NONE = 0, PARITY_ODD = 1, PARITY_EVEN = 2 FIXME: enum? + inf->stopbits = DEFAULT_STOPBITS; +} + +/** Set up a UART, if pins are -1 they will be guessed */ +void jshUSARTSetup(IOEventFlags device, JshUSARTInfo *inf); +/** Kick a device into action (if required). For instance we may need + * to set up interrupts */ +void jshUSARTKick(IOEventFlags device); + +typedef enum { + SPIF_CPHA = 1, + SPIF_CPOL = 2, + SPIF_SPI_MODE_0 = 0, + SPIF_SPI_MODE_1 = SPIF_CPHA, + SPIF_SPI_MODE_2 = SPIF_CPOL, + SPIF_SPI_MODE_3 = SPIF_CPHA | SPIF_CPOL, + /* Mode CPOL CPHA + 0 0 0 + 1 0 1 + 2 1 0 + 3 1 1 + */ + +} PACKED_FLAGS JshSPIFlags; + +typedef struct { + int baudRate; + Pin pinSCK; + Pin pinMISO; + Pin pinMOSI; + unsigned char spiMode; +} PACKED_FLAGS JshSPIInfo; +static inline void jshSPIInitInfo(JshSPIInfo *inf) { + inf->baudRate = 1000000; + inf->pinSCK = PIN_UNDEFINED; + inf->pinMISO = PIN_UNDEFINED; + inf->pinMOSI = PIN_UNDEFINED; + inf->spiMode = SPIF_SPI_MODE_0; +} + +/** Set up SPI, if pins are -1 they will be guessed */ +void jshSPISetup(IOEventFlags device, JshSPIInfo *inf); +/** Send data through the given SPI device (if data>=0), and return the result + * of the previous send (or -1). If data<0, no data is sent and the function + * waits for data to be returned */ +int jshSPISend(IOEventFlags device, int data); +/** Send 16 bit data through the given SPI device. */ +void jshSPISend16(IOEventFlags device, int data); +/** Set whether to send 16 bits or 8 over SPI */ +void jshSPISet16(IOEventFlags device, bool is16); + +typedef struct { + Pin pinSCL; + Pin pinSDA; + char slaveAddr; // or -1 if it is master! + // speed? 100khz std + // timeout? +} PACKED_FLAGS JshI2CInfo; +static inline void jshI2CInitInfo(JshI2CInfo *inf) { + inf->pinSCL = PIN_UNDEFINED; + inf->pinSDA = PIN_UNDEFINED; + inf->slaveAddr = (char)-1; // master +} +/** Set up I2C, if pins are -1 they will be guessed */ +void jshI2CSetup(IOEventFlags device, JshI2CInfo *inf); +/** Addresses are 7 bit - that is, between 0 and 0x7F */ +void jshI2CWrite(IOEventFlags device, unsigned char address, int nBytes, const unsigned char *data); +void jshI2CRead(IOEventFlags device, unsigned char address, int nBytes, unsigned char *data); + + +/// Save contents of JsVars into Flash +void jshSaveToFlash(); +/// Load contents of JsVars from Flash +void jshLoadFromFlash(); +/// Returns true if flash contains something useful +bool jshFlashContainsCode(); + +/// Enter simple sleep mode (can be woken up by interrupts). Returns true on success +bool jshSleep(JsSysTime timeUntilWake); + +// ---------------------------------------------- LOW LEVEL +#ifdef ARM +// ---------------------------------------------------------------------------- +// SYSTICK +// On SYSTick interrupt, call this +void jshDoSysTick(); +#ifdef USB +// Kick the USB SysTick watchdog - we need this to see if we have disconnected or not +void jshKickUSBWatchdog(); +#endif + +#endif // ARM + +#endif /* JSHARDWARE_H_ */ diff --git a/components/external/espruino/src/jsinteractive.c b/components/external/espruino/src/jsinteractive.c new file mode 100644 index 0000000000..9e63fed94e --- /dev/null +++ b/components/external/espruino/src/jsinteractive.c @@ -0,0 +1,1686 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Interactive Shell implementation + * ---------------------------------------------------------------------------- + */ +#include "jsutils.h" +#include "jsinteractive.h" +#include "jshardware.h" +#include "jswrapper.h" +#include "jswrap_json.h" +#include "jswrap_io.h" +#ifdef USE_NET +#include "httpserver.h" +#endif +#ifdef USE_LCD_FSMC +#include "graphics.h" +#include "lcd_fsmc.h" +#endif + +#ifdef ARM +#define CHAR_DELETE_SEND 0x08 +#else +#define CHAR_DELETE_SEND '\b' +#endif + +// ---------------------------------------------------------------------------- +typedef struct TimerState { + JsSysTime time; + JsSysTime interval; + bool recurring; + JsVarRef callback; // a calback, or 0 +} TimerState; + +typedef enum { + IS_NONE, + IS_HAD_R, + IS_HAD_27, + IS_HAD_27_79, + IS_HAD_27_91, + IS_HAD_27_91_49, + IS_HAD_27_91_51, + IS_HAD_27_91_52, + IS_HAD_27_91_53, + IS_HAD_27_91_54, +} InputState; + +TODOFlags todo = TODO_NOTHING; +JsVar *events = 0; // Array of events to execute +JsVarRef timerArray = 0; // Linked List of timers to check and run +JsVarRef watchArray = 0; // Linked List of input watches to check and run +// ---------------------------------------------------------------------------- +IOEventFlags consoleDevice = DEFAULT_CONSOLE_DEVICE; ///< The console device for user interaction +Pin pinBusyIndicator = DEFAULT_BUSY_PIN_INDICATOR; +Pin pinSleepIndicator = DEFAULT_SLEEP_PIN_INDICATOR; +bool echo; ///< do we provide any user feedback? +bool allowDeepSleep; +// ---------------------------------------------------------------------------- +JsParse p; ///< The parser we're using for interactiveness +JsVar *inputLine = 0; ///< The current input line +bool inputLineRemoved = false; +int inputCursorPos = 0; ///< The position of the cursor in the input line +InputState inputState = 0; ///< state for dealing with cursor keys +bool hasUsedHistory = false; ///< Used to speed up - if we were cycling through history and then edit, we need to copy the string +unsigned char loopsIdling; ///< How many times around the loop have we been entirely idle? +bool interruptedDuringEvent; ///< Were we interrupted while executing an event? If so may want to clear timers +// ---------------------------------------------------------------------------- + +IOEventFlags jsiGetDeviceFromClass(JsVar *class) { + // Built-in classes have their object data set to the device name + return jshFromDeviceString(class->varData.str); +} + +JsVar *jsiGetClassNameFromDevice(IOEventFlags device) { + const char *deviceName = jshGetDeviceString(device); + return jsvFindChildFromString(p.root, deviceName, false); +} + +static inline bool jsiShowInputLine() { + return echo && !inputLineRemoved; +} + +/// Change the console to a new location +void jsiSetConsoleDevice(IOEventFlags device) { + if (device == consoleDevice) return; + + if (!jshIsDeviceInitialised(device)) { + JshUSARTInfo inf; + jshUSARTInitInfo(&inf); + jshUSARTSetup(device, &inf); + } + + jsiConsoleRemoveInputLine(); + if (echo) { // intentionally not using jsiShowInputLine() + jsiConsolePrint("Console Moved to "); + jsiConsolePrint(jshGetDeviceString(device)); + jsiConsolePrint("\n"); + } + IOEventFlags oldDevice = consoleDevice; + consoleDevice = device; + if (echo) { // intentionally not using jsiShowInputLine() + jsiConsolePrint("Console Moved from "); + jsiConsolePrint(jshGetDeviceString(oldDevice)); + jsiConsolePrint("\n"); + } +} + +/// Get the device that the console is currently on +IOEventFlags jsiGetConsoleDevice() { + return consoleDevice; +} + +void jsiConsolePrintChar(char data) { + jshTransmit(consoleDevice, (unsigned char)data); +} + +void jsiConsolePrint(const char *str) { + while (*str) { + if (*str == '\n') jsiConsolePrintChar('\r'); + jsiConsolePrintChar(*(str++)); + } +} + +void jsiConsolePrintf(const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + vcbprintf((vcbprintf_callback)jsiConsolePrint,0, fmt, argp); + va_end(argp); +} + + +void jsiConsolePrintInt(JsVarInt d) { + char buf[32]; + itoa(d, buf, 10); + jsiConsolePrint(buf); +} + + +/// Print the contents of a string var from a character position until end of line (adding an extra ' ' to delete a character if there was one) +void jsiConsolePrintStringVarUntilEOL(JsVar *v, int fromCharacter, bool andBackup) { + int chars = 0; + JsvStringIterator it; + jsvStringIteratorNew(&it, v, fromCharacter); + while (jsvStringIteratorHasChar(&it)) { + char ch = jsvStringIteratorGetChar(&it); + if (ch == '\n') break; + jsiConsolePrintChar(ch); + chars++; + jsvStringIteratorNext(&it); + } + jsvStringIteratorFree(&it); + if (andBackup) { + jsiConsolePrintChar(' ');chars++; + while (chars--) jsiConsolePrintChar(0x08); //delete + } +} + +/** Print the contents of a string var - directly - starting from the given character, and + * using newLineCh to prefix new lines (if it is not 0). */ +void jsiConsolePrintStringVarWithNewLineChar(JsVar *v, int fromCharacter, char newLineCh) { + JsvStringIterator it; + jsvStringIteratorNew(&it, v, fromCharacter); + while (jsvStringIteratorHasChar(&it)) { + char ch = jsvStringIteratorGetChar(&it); + if (ch == '\n') jsiConsolePrintChar('\r'); + jsiConsolePrintChar(ch); + if (ch == '\n' && newLineCh) jsiConsolePrintChar(newLineCh); + jsvStringIteratorNext(&it); + } + jsvStringIteratorFree(&it); +} + +/// Print the contents of a string var - directly +void jsiConsolePrintStringVar(JsVar *v) { + jsiConsolePrintStringVarWithNewLineChar(v,0,0); +} + +/** Assuming that we are at the end of the string, this backs up + * and deletes it */ +void jsiConsoleEraseStringVarBackwards(JsVar *v) { + assert(jsvHasCharacterData(v)); + + int line, lines = jsvGetLinesInString(v); + for (line=lines;line>0;line--) { + int i,chars = jsvGetCharsOnLine(v, line); + if (line==lines) { + for (i=0;i1) { + // clear the character before - this would have had a colon + jsiConsolePrintChar(0x08); + jsiConsolePrintChar(' '); + // move cursor up + jsiConsolePrintChar(27); + jsiConsolePrintChar(91); + jsiConsolePrintChar(65); + } + } +} + +/** Assuming that we are at fromCharacter position in the string var, + * erase everything that comes AFTER and return the cursor to 'fromCharacter' + * On newlines, if erasePrevCharacter, we remove the character before too. */ +void jsiConsoleEraseStringVarFrom(JsVar *v, int fromCharacter, bool erasePrevCharacter) { + assert(jsvHasCharacterData(v)); + int cursorLine, cursorCol; + jsvGetLineAndCol(v, fromCharacter, &cursorLine, &cursorCol); + // delete contents of current line + int i, chars = jsvGetCharsOnLine(v, cursorLine); + for (i=cursorCol;i<=chars;i++) jsiConsolePrintChar(' '); + for (i=0;i newX) { + jsiConsolePrintChar(27); + jsiConsolePrintChar(91); + jsiConsolePrintChar(68); + oldX--; + } + while (oldY < newY) { + jsiConsolePrintChar(27); + jsiConsolePrintChar(91); + jsiConsolePrintChar(66); + oldY++; + } + while (oldY > newY) { + jsiConsolePrintChar(27); + jsiConsolePrintChar(91); + jsiConsolePrintChar(65); + oldY--; + } +} + +void jsiMoveCursorChar(JsVar *v, int fromCharacter, int toCharacter) { + if (fromCharacter==toCharacter) return; + int oldX, oldY; + jsvGetLineAndCol(v, fromCharacter, &oldY, &oldX); + int newX, newY; + jsvGetLineAndCol(v, toCharacter, &newY, &newX); + jsiMoveCursor(oldX, oldY, newX, newY); +} + +/// If the input line was shown in the console, remove it +void jsiConsoleRemoveInputLine() { + if (!inputLineRemoved) { + inputLineRemoved = true; + if (echo && inputLine) { // intentionally not using jsiShowInputLine() + jsiMoveCursorChar(inputLine, inputCursorPos, 0); + jsiConsoleEraseStringVarFrom(inputLine, 0, true); + jsiConsolePrintChar(0x08); // go back to start of line + } + } +} + +/// If the input line has been removed, return it +void jsiReturnInputLine() { + if (inputLineRemoved) { + inputLineRemoved = false; + if (echo) { // intentionally not using jsiShowInputLine() + jsiConsolePrintChar('\r'); // carriage return + jsiConsolePrintChar('>'); + jsiConsolePrintStringVarWithNewLineChar(inputLine, 0, ':'); + jsiMoveCursorChar(inputLine, (int)jsvGetStringLength(inputLine), inputCursorPos); + } + } +} + +void jsiConsolePrintPosition(struct JsLex *lex, int tokenPos) { + int line,col; + jsvGetLineAndCol(lex->sourceVar, tokenPos, &line, &col); + jsiConsolePrintf("line %d col %d\n",line,col); +} + +void jsiConsolePrintTokenLineMarker(struct JsLex *lex, int tokenPos) { + int line = 1,col = 1; + jsvGetLineAndCol(lex->sourceVar, tokenPos, &line, &col); + int startOfLine = jsvGetIndexFromLineAndCol(lex->sourceVar, line, 1); + jsiConsolePrintStringVarUntilEOL(lex->sourceVar, startOfLine, false); + jsiConsolePrint("\n"); + while (col-- > 1) jsiConsolePrintChar(' '); + jsiConsolePrintChar('^'); + jsiConsolePrint("\n"); +} + + +/// Print the contents of a string var to a device - directly +void jsiTransmitStringVar(IOEventFlags device, JsVar *v) { + JsvStringIterator it; + jsvStringIteratorNew(&it, v, 0); + while (jsvStringIteratorHasChar(&it)) { + char ch = jsvStringIteratorGetChar(&it); + jshTransmit(device, (unsigned char)ch); + jsvStringIteratorNext(&it); + } + jsvStringIteratorFree(&it); +} + +void jsiSetBusy(JsiBusyDevice device, bool isBusy) { + static JsiBusyDevice business = 0; + + if (isBusy) + business |= device; + else + business &= (JsiBusyDevice)~device; + + if (pinBusyIndicator != PIN_UNDEFINED) + jshPinOutput(pinBusyIndicator, business!=0); +} + +void jsiSetSleep(bool isSleep) { + if (pinSleepIndicator != PIN_UNDEFINED) + jshPinOutput(pinSleepIndicator, isSleep); +} + +static JsVarRef _jsiInitNamedArray(const char *name) { + JsVar *arrayName = jsvFindChildFromString(p.root, name, true); + if (!arrayName) return 0; // out of memory + if (!arrayName->firstChild) { + JsVar *array = jsvNewWithFlags(JSV_ARRAY); + if (!array) { // out of memory + jsvUnLock(arrayName); + return 0; + } + + arrayName->firstChild = jsvGetRef(jsvRef(array)); + jsvUnLock(array); + } + JsVarRef arrayRef = jsvRefRef(arrayName->firstChild); + jsvUnLock(arrayName); + return arrayRef; +} + +// Used when recovering after being flashed +// 'claim' anything we are using +void jsiSoftInit() { +#ifdef USE_NET + httpInit(); +#endif +#ifdef USE_LCD_FSMC + JsVar *parent = jspNewObject(jsiGetParser(), "LCD", "Graphics"); + if (parent) { + JsVar *parentObj = jsvSkipName(parent); + JsGraphics gfx; + graphicsStructInit(&gfx); + gfx.data.type = JSGRAPHICSTYPE_FSMC; + gfx.graphicsVar = parentObj; + gfx.data.width = 320; + gfx.data.height = 240; + gfx.data.bpp = 16; + lcdInit_FSMC(&gfx); + lcdSetCallbacks_FSMC(&gfx); + graphicsSplash(&gfx); + graphicsSetVar(&gfx); + jsvUnLock(parentObj); + jsvUnLock(parent); + } +#endif + + + events = jsvNewWithFlags(JSV_ARRAY); + inputLine = jsvNewFromEmptyString(); + inputCursorPos = 0; + allowDeepSleep = false; + + // Load timer/watch arrays + timerArray = _jsiInitNamedArray(JSI_TIMERS_NAME); + watchArray = _jsiInitNamedArray(JSI_WATCHES_NAME); + + // Now run initialisation code + JsVar *initName = jsvFindChildFromString(p.root, JSI_INIT_CODE_NAME, false); + if (initName && initName->firstChild) { + //jsiConsolePrint("Running initialisation code...\n"); + JsVar *initCode = jsvLock(initName->firstChild); + jsvUnLock(jspEvaluateVar(&p, initCode, 0)); + jsvUnLock(initCode); + jsvRemoveChild(p.root, initName); + } + jsvUnLock(initName); + + // Check any existing watches and set up interrupts for them + if (watchArray) { + JsVar *watchArrayPtr = jsvLock(watchArray); + JsVarRef watch = watchArrayPtr->firstChild; + while (watch) { + JsVar *watchNamePtr = jsvLock(watch); + JsVar *watchPin = jsvSkipNameAndUnLock(jsvFindChildFromStringRef(watchNamePtr->firstChild, "pin", false)); + jshPinWatch(jshGetPinFromVar(watchPin), true); + jsvUnLock(watchPin); + watch = watchNamePtr->nextSibling; + jsvUnLock(watchNamePtr); + } + jsvUnLock(watchArrayPtr); + } + + // Check any existing timers and try and set time correctly + if (timerArray) { + JsSysTime currentTime = jshGetSystemTime(); + JsVar *timerArrayPtr = jsvLock(timerArray); + JsVarRef timer = timerArrayPtr->firstChild; + while (timer) { + JsVar *timerNamePtr = jsvLock(timer); + JsVar *timerTime = jsvSkipNameAndUnLock(jsvFindChildFromStringRef(timerNamePtr->firstChild, "time", false)); + JsVarFloat interval = jsvGetFloatAndUnLock(jsvSkipNameAndUnLock(jsvFindChildFromStringRef(timerNamePtr->firstChild, "interval", false))); + jsvSetInteger(timerTime, currentTime + jshGetTimeFromMilliseconds(interval)); + jsvUnLock(timerTime); + timer = timerNamePtr->nextSibling; + jsvUnLock(timerNamePtr); + } + jsvUnLock(timerArrayPtr); + } + // And look for onInit function + JsVar *onInit = jsvFindChildFromString(p.root, JSI_ONINIT_NAME, false); + if (onInit && onInit->firstChild) { + if (echo) jsiConsolePrint("Running onInit()...\n"); + JsVar *func = jsvSkipName(onInit); + if (jsvIsFunction(func)) + jspExecuteFunction(&p, func, 0, 0, (JsVar**)0); + else if (jsvIsString(func)) + jsvUnLock(jspEvaluateVar(&p, func, 0)); + else + jsError("onInit is not a Function or a String"); + } + jsvUnLock(onInit); +} + +/** Append the code required to initialise a serial port to this string */ +void jsiAppendSerialInitialisation(JsVar *str, const char *serialName, bool addCallbacks) { + JsVar *serialVar = jsvObjectGetChild(p.root, serialName, 0); + if (serialVar) { + if (addCallbacks) { + JsVar *onData = jsvSkipOneNameAndUnLock(jsvFindChildFromString(serialVar, USART_CALLBACK_NAME, false)); + if (onData) { + JsVar *onDataStr = jsvAsString(onData, true/*unlock*/); + jsvAppendString(str, serialName); + jsvAppendString(str, ".onData("); + jsvAppendStringVarComplete(str, onDataStr); + jsvAppendString(str, ");\n"); + jsvUnLock(onDataStr); + } + } + JsVar *baud = jsvObjectGetChild(serialVar, USART_BAUDRATE_NAME, 0); + JsVar *options = jsvObjectGetChild(serialVar, DEVICE_OPTIONS_NAME, 0); + if (baud || options) { + JsVarInt baudrate = jsvGetInteger(baud); + if (baudrate <= 0) baudrate = DEFAULT_BAUD_RATE; + jsvAppendPrintf(str, "%s.setup(%d", serialName, baudrate); + if (jsvIsObject(options)) { + jsvAppendString(str, ", "); + jsfGetJSON(options, str); + } + jsvAppendString(str, ");\n"); + } + jsvUnLock(baud); + jsvUnLock(options); + jsvUnLock(serialVar); + } +} + +/** Append the code required to initialise a SPI port to this string */ +void jsiAppendDeviceInitialisation(JsVar *str, const char *deviceName) { + JsVar *deviceVar = jsvObjectGetChild(p.root, deviceName, 0); + if (deviceVar) { + JsVar *options = jsvObjectGetChild(deviceVar, DEVICE_OPTIONS_NAME, 0); + if (options) { + jsvAppendString(str, deviceName); + jsvAppendString(str, ".setup("); + if (jsvIsObject(options)) { + jsfGetJSON(options, str); + } + jsvAppendString(str, ");\n"); + } + jsvUnLock(options); + jsvUnLock(deviceVar); + } +} + +/** Append all the code required to initialise hardware to this string */ +void jsiAppendHardwareInitialisation(JsVar *str, bool addCallbacks) { + if (!echo) jsvAppendString(str, "echo(0);"); + if (pinBusyIndicator != DEFAULT_BUSY_PIN_INDICATOR) { + jsvAppendPrintf(str, "setBusyIndicator(%p);\n", pinBusyIndicator); + } + if (pinSleepIndicator != DEFAULT_BUSY_PIN_INDICATOR) { + jsvAppendPrintf(str, "setSleepIndicator(%p);\n", pinSleepIndicator); + } + if (allowDeepSleep) { + jsvAppendPrintf(str, "setDeepSleep(1);\n"); + } + + jsiAppendSerialInitialisation(str, "USB", addCallbacks); + int i; + for (i=0;ifirstChild; + while (watch) { + JsVar *watchNamePtr = jsvLock(watch); + JsVar *watchPin = jsvSkipNameAndUnLock(jsvFindChildFromStringRef(watchNamePtr->firstChild, "pin", false)); + jshPinWatch(jshGetPinFromVar(watchPin), false); + jsvUnLock(watchPin); + watch = watchNamePtr->nextSibling; + jsvUnLock(watchNamePtr); + } + jsvUnLock(watchArrayPtr); + + jsvUnRefRef(watchArray); + watchArray=0; + } + // Save initialisation information + JsVar *initName = jsvFindChildFromString(p.root, JSI_INIT_CODE_NAME, true); + if (initName->firstChild) { + jsvUnRefRef(initName->firstChild); + initName->firstChild = 0; + } + JsVar *initCode = jsvNewFromEmptyString(); + if (initCode) { // out of memory + initName->firstChild = jsvGetRef(jsvRef(initCode)); + jsiAppendHardwareInitialisation(initCode, false); + jsvUnLock(initCode); + } + jsvUnLock(initName); + +#ifdef USE_NET + httpKill(); +#endif +} + +void jsiInit(bool autoLoad) { + jsvInit(); + jspInit(&p); + +#ifdef USE_LCD + lcdInit_Main(&LCD); +#ifdef USE_LCD_ILI9325 + lcdInit_FSMC_ILI9325(&LCD, LCD_WIDTH, LCD_HEIGHT); +#endif +#ifdef USE_LCD_SDL + lcdInit_SDL(&LCD, LCD_WIDTH, LCD_HEIGHT); +#endif + lcdClear(0); + lcdSplash(); +#endif + + + + /*for (i=0;iroot), 0) + + // Softinit may run initialisation code that will overwrite defaults + jsiSoftInit(); + + if (echo) { // intentionally not using jsiShowInputLine() +#ifndef LINUX + // set up terminal to avoid word wrap + jsiConsolePrint("\e[?7l"); +#endif + // rectangles @ http://www.network-science.de/ascii/ + jsiConsolePrint("\n" + " _____ _ \n" + " | __|___ ___ ___ _ _|_|___ ___ \n" + " | __|_ -| . | _| | | | | . |\n" + " |_____|___| _|_| |___|_|_|_|___|"); + jsiConsolePrint("\n" + " |_| http://www.espruino.com\n" + " "JS_VERSION" Copyright 2013 Gordon Williams\n" + "-------------------------------------------\n" + " KickStarter Version\n" + "-------------------------------------------\n"); + jsiConsolePrint("\n>"); + } +} + + + +void jsiKill() { + jsiSoftKill(); + + jspKill(&p); + jsvKill(); +} + +int jsiCountBracketsInInput() { + int brackets = 0; + + JsLex lex; + jslInit(&lex, inputLine); + while (lex.tk!=LEX_EOF && lex.tk!=LEX_UNFINISHED_COMMENT) { + if (lex.tk=='{' || lex.tk=='[' || lex.tk=='(') brackets++; + if (lex.tk=='}' || lex.tk==']' || lex.tk==')') brackets--; + if (brackets<0) break; // closing bracket before opening! + jslGetNextToken(&lex); + } + if (lex.tk==LEX_UNFINISHED_COMMENT) + brackets=1000; // if there's an unfinished comment, we're in the middle of something + jslKill(&lex); + + return brackets; +} + +/// Tries to get rid of some memory (by clearing command history). Returns true if it got rid of something, false if it didn't. +bool jsiFreeMoreMemory() { + JsVar *history = jsvObjectGetChild(p.root, JSI_HISTORY_NAME, 0); + if (!history) return 0; + JsVar *item = jsvArrayPopFirst(history); + bool freed = item!=0; + jsvUnLock(item); + jsvUnLock(history); + // TODO: could also free the array structure? + return freed; +} + +// Add a new line to the command history +void jsiHistoryAddLine(JsVar *newLine) { + if (!newLine || jsvGetStringLength(newLine)==0) return; + JsVar *history = jsvFindChildFromString(p.root, JSI_HISTORY_NAME, true); + if (!history) return; // out of memory + // ensure we actually have the history array + if (!history->firstChild) { + JsVar *arr = jsvNewWithFlags(JSV_ARRAY); + if (!arr) {// out of memory + jsvUnLock(history); + return; + } + history->firstChild = jsvGetRef(jsvRef(arr)); + jsvUnLock(arr); + } + history = jsvSkipNameAndUnLock(history); + // if it was already in history, remove it - we'll put it back in front + JsVar *alreadyInHistory = jsvGetArrayIndexOf(history, newLine, false/*not exact*/); + if (alreadyInHistory) { + jsvRemoveChild(history, alreadyInHistory); + jsvUnLock(alreadyInHistory); + } + // put it back in front + jsvArrayPush(history, newLine); + jsvUnLock(history); +} + +JsVar *jsiGetHistoryLine(bool previous /* next if false */) { + JsVar *history = jsvObjectGetChild(p.root, JSI_HISTORY_NAME, 0); + JsVar *historyLine = 0; + if (history) { + JsVar *idx = jsvGetArrayIndexOf(history, inputLine, true/*exact*/); // get index of current line + if (idx) { + if (previous && idx->prevSibling) { + historyLine = jsvSkipNameAndUnLock(jsvLock(idx->prevSibling)); + } else if (!previous && idx->nextSibling) { + historyLine = jsvSkipNameAndUnLock(jsvLock(idx->nextSibling)); + } + jsvUnLock(idx); + } else { + if (previous) historyLine = jsvSkipNameAndUnLock(jsvArrayGetLast(history)); + // if next, we weren't using history so couldn't go forwards + } + + jsvUnLock(history); + } + return historyLine; +} + +bool jsiIsInHistory(JsVar *line) { + JsVar *history = jsvObjectGetChild(p.root, JSI_HISTORY_NAME, 0); + if (!history) return false; + JsVar *historyFound = jsvGetArrayIndexOf(history, line, true/*exact*/); + bool inHistory = historyFound!=0; + jsvUnLock(historyFound); + jsvUnLock(history); + return inHistory; +} + +void jsiReplaceInputLine(JsVar *newLine) { + if (jsiShowInputLine()) { + int oldLen = (int)jsvGetStringLength(inputLine); + jsiMoveCursorChar(inputLine, inputCursorPos, oldLen); // move cursor to end + jsiConsoleEraseStringVarBackwards(inputLine); + jsiConsolePrintStringVarWithNewLineChar(newLine,0,':'); + } + jsvUnLock(inputLine); + inputLine = jsvLockAgain(newLine); + inputCursorPos = (int)jsvGetStringLength(inputLine); +} + +void jsiChangeToHistory(bool previous) { + JsVar *nextHistory = jsiGetHistoryLine(previous); + if (nextHistory) { + jsiReplaceInputLine(nextHistory); + jsvUnLock(nextHistory); + hasUsedHistory = true; + } else if (!previous) { // if next, but we have something, just clear the line + if (jsiShowInputLine()) { + jsiConsoleEraseStringVarBackwards(inputLine); + } + jsvUnLock(inputLine); + inputLine = jsvNewFromEmptyString(); + inputCursorPos = 0; + } +} + +void jsiIsAboutToEditInputLine() { + // we probably plan to do something with the line now - check it wasn't in history + // and if it was, duplicate it + if (hasUsedHistory) { + hasUsedHistory = false; + if (jsiIsInHistory(inputLine)) { + JsVar *newLine = jsvCopy(inputLine); + if (newLine) { // could have been out of memory! + jsvUnLock(inputLine); + inputLine = newLine; + } + } + } +} + +void jsiHandleDelete(bool isBackspace) { + int l = (int)jsvGetStringLength(inputLine); + if (isBackspace && inputCursorPos<=0) return; // at beginning of line + if (!isBackspace && inputCursorPos>=l) return; // at end of line + // work out if we are deleting a newline + bool deleteNewline = (isBackspace && jsvGetCharInString(inputLine,inputCursorPos-1)=='\n') || + (!isBackspace && jsvGetCharInString(inputLine,inputCursorPos)=='\n'); + // If we mod this to keep the string, use jsiIsAboutToEditInputLine + if (deleteNewline && jsiShowInputLine()) { + jsiConsoleEraseStringVarFrom(inputLine, inputCursorPos, true/*before newline*/); // erase all in front + if (isBackspace) { + // delete newline char + jsiConsolePrintChar(0x08); + jsiConsolePrintChar(' '); + jsiMoveCursorChar(inputLine, inputCursorPos, inputCursorPos-1); // move cursor back + } + } + + JsVar *v = jsvNewFromEmptyString(); + int p = inputCursorPos; + if (isBackspace) p--; + if (p>0) jsvAppendStringVar(v, inputLine, 0, p); // add before cursor (delete) + if (p+10 && jsvGetCharInString(inputLine,inputCursorPos-1)!='\n') { + if (jsiShowInputLine()) jsiConsolePrintChar(0x08); + inputCursorPos--; + } +} + +void jsiHandleEnd() { + int l = (int)jsvGetStringLength(inputLine); + while (inputCursorPoslines) newY=lines; + // work out cursor pos and feed back through - we might not be able to get right to the same place + // if we move up + inputCursorPos = jsvGetIndexFromLineAndCol(inputLine, newY, newX); + jsvGetLineAndCol(inputLine, inputCursorPos, &newY, &newX); + if (jsiShowInputLine()) { + jsiMoveCursor(x,y,newX,newY); + } +} + +bool jsiAtEndOfInputLine() { + int i = inputCursorPos, l = (int)jsvGetStringLength(inputLine); + while (i < l) { + if (!isWhitespace(jsvGetCharInString(inputLine, i))) + return false; + i++; + } + return true; +} + +void jsiHandleChar(char ch) { + //jsiConsolePrintf("[%d:%d]\n", inputState, ch); + // + // special stuff + // 27 then 91 then 68 - left + // 27 then 91 then 67 - right + // 27 then 91 then 65 - up + // 27 then 91 then 66 - down + // 27 then 91 then 51 then 126 - backwards delete + // 27 then 91 then 52 then 126 - numpad end + // 27 then 91 then 49 then 126 - numpad home + // 27 then 91 then 53 then 126 - pgup + // 27 then 91 then 54 then 126 - pgdn + // 27 then 79 then 70 - home + // 27 then 79 then 72 - end + + if (ch == 0) { + inputState = IS_NONE; // ignore 0 - it's scary + } else if (ch == 27) { + inputState = IS_HAD_27; + } else if (inputState==IS_HAD_27) { + inputState = IS_NONE; + if (ch == 79) + inputState = IS_HAD_27_79; + else if (ch == 91) + inputState = IS_HAD_27_91; + } else if (inputState==IS_HAD_27_79) { // Numpad + inputState = IS_NONE; + if (ch == 70) jsiHandleEnd(); + else if (ch == 72) jsiHandleHome(); + else if (ch == 111) jsiHandleChar('/'); + else if (ch == 106) jsiHandleChar('*'); + else if (ch == 109) jsiHandleChar('-'); + else if (ch == 107) jsiHandleChar('+'); + else if (ch == 77) jsiHandleChar('\r'); + } else if (inputState==IS_HAD_27_91) { + inputState = IS_NONE; + if (ch==68) { // left + if (inputCursorPos>0 && jsvGetCharInString(inputLine,inputCursorPos-1)!='\n') { + inputCursorPos--; + if (jsiShowInputLine()) { + jsiConsolePrintChar(27); + jsiConsolePrintChar(91); + jsiConsolePrintChar(68); + } + } + } else if (ch==67) { // right + if (inputCursorPos<(int)jsvGetStringLength(inputLine) && jsvGetCharInString(inputLine,inputCursorPos)!='\n') { + inputCursorPos++; + if (jsiShowInputLine()) { + jsiConsolePrintChar(27); + jsiConsolePrintChar(91); + jsiConsolePrintChar(67); + } + } + } else if (ch==65) { // up + int l = (int)jsvGetStringLength(inputLine); + if ((l==0 || jsiIsInHistory(inputLine)) && inputCursorPos==l) + jsiChangeToHistory(true); // if at end of line + else + jsiHandleMoveUpDown(-1); + } else if (ch==66) { // down + int l = (int)jsvGetStringLength(inputLine); + if ((l==0 || jsiIsInHistory(inputLine)) && inputCursorPos==l) + jsiChangeToHistory(false); // if at end of line + else + jsiHandleMoveUpDown(1); + } else if (ch==49) { + inputState=IS_HAD_27_91_49; + } else if (ch==51) { + inputState=IS_HAD_27_91_51; + } else if (ch==52) { + inputState=IS_HAD_27_91_52; + } else if (ch==53) { + inputState=IS_HAD_27_91_53; + } else if (ch==54) { + inputState=IS_HAD_27_91_54; + } + } else if (inputState==IS_HAD_27_91_49) { + inputState = IS_NONE; + if (ch==126) { // Numpad Home + jsiHandleHome(); + } + } else if (inputState==IS_HAD_27_91_51) { + inputState = IS_NONE; + if (ch==126) { // Numpad (forwards) Delete + jsiHandleDelete(false/*not backspace*/); + } + } else if (inputState==IS_HAD_27_91_52) { + inputState = IS_NONE; + if (ch==126) { // Numpad End + jsiHandleEnd(); + } + } else if (inputState==IS_HAD_27_91_53) { + inputState = IS_NONE; + if (ch==126) { // Page Up + jsiHandlePageUpDown(0); + } + } else if (inputState==IS_HAD_27_91_54) { + inputState = IS_NONE; + if (ch==126) { // Page Down + jsiHandlePageUpDown(1); + } + } else { + inputState = IS_NONE; + if (ch == 0x08 || ch == 0x7F /*delete*/) { + jsiHandleDelete(true /*backspace*/); + } else if (ch == '\n' && inputState == IS_HAD_R) { + inputState = IS_NONE; // ignore \ r\n - we already handled it all on \r + } else if (ch == '\r' || ch == '\n') { + if (jsiAtEndOfInputLine()) { // at EOL so we need to figure out if we can execute or not + if (ch == '\r') inputState = IS_HAD_R; + if (jsiCountBracketsInInput()<=0) { // actually execute! + if (jsiShowInputLine()) { + jsiConsolePrintChar('\r'); + jsiConsolePrintChar('\n'); + } + inputLineRemoved = true; + + // Get line to execute, and reset inputLine + JsVar *lineToExecute = jsvStringTrimRight(inputLine); + jsvUnLock(inputLine); + inputLine = jsvNewFromEmptyString(); + inputCursorPos = 0; + // execute! + JsVar *v = jspEvaluateVar(&p, lineToExecute, 0); + // add input line to history + jsiHistoryAddLine(lineToExecute); + jsvUnLock(lineToExecute); + // print result + if (echo) { // intentionally not using jsiShowInputLine() + jsiConsolePrintChar('='); + jsfPrintJSON(v); + jsiConsolePrint("\n"); + } + jsvUnLock(v); + // console will be returned next time around the input loop + } else { + // Brackets aren't all closed, so we're going to append a newline + // without executing + if (jsiShowInputLine()) jsiConsolePrint("\n:"); + jsiIsAboutToEditInputLine(); + jsvAppendCharacter(inputLine, '\n'); + inputCursorPos++; + } + } else { // new line - but not at end of line! + jsiIsAboutToEditInputLine(); + if (jsiShowInputLine()) jsiConsoleEraseStringVarFrom(inputLine, inputCursorPos, false/*no need to erase the char before*/); // erase all in front + JsVar *v = jsvNewFromEmptyString(); + if (inputCursorPos>0) jsvAppendStringVar(v, inputLine, 0, inputCursorPos); + jsvAppendCharacter(v, '\n'); + jsvAppendStringVar(v, inputLine, inputCursorPos, JSVAPPENDSTRINGVAR_MAXLENGTH); // add the rest + jsvUnLock(inputLine); + inputLine=v; + if (jsiShowInputLine()) { // now print the rest + jsiConsolePrintStringVarWithNewLineChar(inputLine, inputCursorPos, ':'); + jsiMoveCursorChar(inputLine, (int)jsvGetStringLength(inputLine), inputCursorPos+1); // move cursor back + } + inputCursorPos++; + } + } else if (ch>=32 || ch=='\t') { + // Add the character to our input line + jsiIsAboutToEditInputLine(); + int l = (int)jsvGetStringLength(inputLine); + bool hasTab = ch=='\t'; + if (inputCursorPos>=l) { + if (hasTab) jsvAppendString(inputLine, " "); + else jsvAppendCharacter(inputLine, ch); + } else { + JsVar *v = jsvNewFromEmptyString(); + if (inputCursorPos>0) jsvAppendStringVar(v, inputLine, 0, inputCursorPos); + if (hasTab) jsvAppendString(v, " "); + else jsvAppendCharacter(v, ch); + jsvAppendStringVar(v, inputLine, inputCursorPos, JSVAPPENDSTRINGVAR_MAXLENGTH); // add the rest + jsvUnLock(inputLine); + inputLine=v; + if (jsiShowInputLine()) jsiConsolePrintStringVarUntilEOL(inputLine, inputCursorPos, true/*and backup*/); + } + inputCursorPos += hasTab ? 4 : 1; + if (jsiShowInputLine()) { + if (hasTab) jsiConsolePrint(" "); + else jsiConsolePrintChar(ch); + } + } + } +} + +void jsiQueueEvents(JsVarRef callbacks, JsVar *arg0, JsVar *arg1) { // array of functions or single function + if (!callbacks) return; + + JsVar *callbackVar = jsvLock(callbacks); + // if it is a single callback, just add it + if (jsvIsFunction(callbackVar) || jsvIsString(callbackVar)) { + JsVar *event = jsvNewWithFlags(JSV_OBJECT); + if (event) { // Could be out of memory error! + jsvUnLock(jsvAddNamedChild(event, callbackVar, "func")); + if (arg0) jsvUnLock(jsvAddNamedChild(event, arg0, "arg0")); + if (arg1) jsvUnLock(jsvAddNamedChild(event, arg1, "arg1")); + jsvArrayPushAndUnLock(events, event); + } + jsvUnLock(callbackVar); + } else { + assert(jsvIsArray(callbackVar)); + // go through all callbacks + JsVarRef next = callbackVar->firstChild; + jsvUnLock(callbackVar); + while (next) { + //jsPrint("Queue Event\n"); + JsVar *child = jsvLock(next); + + // for each callback... + JsVar *event = jsvNewWithFlags(JSV_OBJECT); + if (event) { // Could be out of memory error! + jsvUnLock(jsvAddNamedChild(event, child, "func")); + if (arg0) jsvUnLock(jsvAddNamedChild(event, arg0, "arg0")); + if (arg1) jsvUnLock(jsvAddNamedChild(event, arg1, "arg1")); + // add event to the events list + jsvArrayPushAndUnLock(events, event); + // go to next callback + } + next = child->nextSibling; + jsvUnLock(child); + } + } +} + +void jsiQueueObjectCallbacks(JsVar *object, const char *callbackName, JsVar *arg0, JsVar *arg1) { + JsVar *callback = jsvObjectGetChild(object, callbackName, 0); + if (!callback) return; + jsiQueueEvents(jsvGetRef(callback), arg0, arg1); + jsvUnLock(callback); +} + +void jsiExecuteEvents() { + bool hasEvents = !jsvArrayIsEmpty(events); + bool wasInterrupted = jspIsInterrupted(); + if (hasEvents) jsiSetBusy(BUSY_INTERACTIVE, true); + while (!jsvArrayIsEmpty(events)) { + JsVar *event = jsvSkipNameAndUnLock(jsvArrayPopFirst(events)); + // Get function to execute + JsVar *func = jsvObjectGetChild(event, "func", 0); + JsVar *args[2]; + args[0] = jsvObjectGetChild(event, "arg0", 0); + args[1] = jsvObjectGetChild(event, "arg1", 0); + // free + jsvUnLock(event); + + + // now run.. + if (func) { + if (jsvIsFunction(func)) + jspExecuteFunction(&p, func, 0, 2, args); + else if (jsvIsString(func)) + jsvUnLock(jspEvaluateVar(&p, func, 0)); + else + jsError("Unknown type of callback in Event Queue"); + } + //jsPrint("Event Done\n"); + jsvUnLock(func); + jsvUnLock(args[0]); + jsvUnLock(args[1]); + } + if (hasEvents) { + jsiSetBusy(BUSY_INTERACTIVE, false); + if (!wasInterrupted && jspIsInterrupted()) + interruptedDuringEvent = true; + } +} + +void jsiExecuteEventCallback(JsVar *callbackVar, JsVar *arg0, JsVar *arg1) { // array of functions or single function + bool wasInterrupted = jspIsInterrupted(); + JsVar *callbackNoNames = jsvSkipName(callbackVar); + + if (callbackNoNames) { + if (jsvIsArray(callbackNoNames)) { + JsVarRef next = callbackNoNames->firstChild; + while (next) { + JsVar *child = jsvLock(next); + jsiExecuteEventCallback(child, arg0, arg1); + next = child->nextSibling; + jsvUnLock(child); + } + } else if (jsvIsFunction(callbackNoNames)) { + JsVar *args[2] = { arg0, arg1 }; + JsVar *parent = 0; + jspExecuteFunction(&p, callbackNoNames, parent, 2, args); + } else if (jsvIsString(callbackNoNames)) + jsvUnLock(jspEvaluateVar(&p, callbackNoNames, 0)); + else + jsError("Unknown type of callback in Event Queue"); + jsvUnLock(callbackNoNames); + } + if (!wasInterrupted && jspIsInterrupted()) + interruptedDuringEvent = true; +} + +bool jsiHasTimers() { + if (!timerArray) return false; + JsVar *timerArrayPtr = jsvLock(timerArray); + JsVarInt c = jsvGetArrayLength(timerArrayPtr); + jsvUnLock(timerArrayPtr); + return c>0; +} + +void jsiPrintUnregisteredMessage(const char *desc) { + jsiConsolePrint("\n You must have registered Espruino in order to "); + jsiConsolePrint(desc); + jsiConsolePrint(".\n\n Please type register() for more information.\n\n"); +} + +void jsiIdle() { + // This is how many times we have been here and not done anything. + // It will be zeroed if we do stuff later + if (loopsIdling<255) loopsIdling++; + + // Handle hardware-related idle stuff (like checking for pin events) + bool wasBusy = false; + IOEvent event; + while (jshPopIOEvent(&event)) { + jsiSetBusy(BUSY_INTERACTIVE, true); + wasBusy = true; + + IOEventFlags eventType = IOEVENTFLAGS_GETTYPE(event.flags); + + loopsIdling = 0; // because we're not idling + if (eventType == consoleDevice) { + int i, c = IOEVENTFLAGS_GETCHARS(event.flags); + jsiSetBusy(BUSY_INTERACTIVE, true); + for (i=0;i 0) { + dataTime->varData.str[0] = event.data.chars[i] & 0x7F; + } + else if(bytesize == 8 && parity > 0) { + dataTime->varData.str[0] = event.data.chars[i] & 0xFF; + } + else { + dataTime->varData.str[0] = event.data.chars[i]; + } +#else + dataTime->varData.str[0] = event.data.chars[i]; +#endif + + if (dataTime) jsvUnLock(jsvAddNamedChild(data, dataTime, "data")); + jsvUnLock(dataTime); + } + + jsiExecuteEventCallback(callback, data, 0); + jsvUnLock(data); + } + } + jsvUnLock(callback); + jsvUnLock(usartClass); + } + } else if (DEVICE_IS_EXTI(eventType)) { // ---------------------------------------------------------------- PIN WATCH + // we have an event... find out what it was for... + // Check everything in our Watch array + JsVar *watchArrayPtr = jsvLock(watchArray); + JsVarRef watch = watchArrayPtr->firstChild; + while (watch) { + JsVar *watchNamePtr = jsvLock(watch); // effectively the array index + JsVar *watchPin = jsvSkipNameAndUnLock(jsvFindChildFromStringRef(watchNamePtr->firstChild, "pin", false)); + Pin pin = jshGetPinFromVar(watchPin); // TODO: could be faster? + jsvUnLock(watchPin); + + if (jshIsEventForPin(&event, pin)) { + bool pinIsHigh = (event.flags&EV_EXTI_IS_HIGH)!=0; + int watchEdge = (int)jsvGetIntegerAndUnLock(jsvSkipNameAndUnLock(jsvFindChildFromStringRef(watchNamePtr->firstChild, "edge", false))); + if (watchEdge==0 || (pinIsHigh && watchEdge>0) || (!pinIsHigh && watchEdge<0)) { // edge triggering + JsVar *watchCallback = jsvFindChildFromStringRef(watchNamePtr->firstChild, "callback", false); + bool watchRecurring = jsvGetBoolAndUnLock(jsvSkipNameAndUnLock(jsvFindChildFromStringRef(watchNamePtr->firstChild, "recur", false))); + JsVar *data = jsvNewWithFlags(JSV_OBJECT); + if (data) { + JsVar *dataTime = jsvNewFromFloat(jshGetMillisecondsFromTime(event.data.time)/1000); + if (dataTime) jsvUnLock(jsvAddNamedChild(data, dataTime, "time")); + jsvUnLock(dataTime); + JsVar *dataState = jsvNewFromBool(pinIsHigh); + if (dataState) jsvUnLock(jsvAddNamedChild(data, dataState, "state")); + jsvUnLock(dataState); + } + jsiExecuteEventCallback(watchCallback, data, 0); + jsvUnLock(data); + if (!watchRecurring) { + // free all + jsvRemoveChild(watchArrayPtr, watchNamePtr); + } + jsvUnLock(watchCallback); + } + } + watch = watchNamePtr->nextSibling; + jsvUnLock(watchNamePtr); + } + jsvUnLock(watchArrayPtr); + } + } + + // Reset Flow control if it was set... + if (jshGetEventsUsed() < IOBUFFER_XON) { + int i; + for (i=0;ifirstChild; + while (timer) { + JsVar *timerNamePtr = jsvLock(timer); + timer = timerNamePtr->nextSibling; // ptr to next + JsVar *timerTime = jsvSkipNameAndUnLock(jsvFindChildFromStringRef(timerNamePtr->firstChild, "time", false)); + JsSysTime timeUntilNext = jsvGetInteger(timerTime) - time; + if (timeUntilNext < minTimeUntilNext) + minTimeUntilNext = timeUntilNext; + if (timerTime && timeUntilNext<=0) { + // we're now doing work + jsiSetBusy(BUSY_INTERACTIVE, true); + wasBusy = true; + + JsVar *timerCallback = jsvFindChildFromStringRef(timerNamePtr->firstChild, "callback", false); + JsVar *timerRecurring = jsvSkipNameAndUnLock(jsvFindChildFromStringRef(timerNamePtr->firstChild, "recur", false)); + JsVar *data = jsvNewWithFlags(JSV_OBJECT); + if (data) { + JsVar *dataTime = jsvNewFromFloat(jshGetMillisecondsFromTime(jsvGetInteger(timerTime))/1000); + if (dataTime) jsvUnLock(jsvAddNamedChild(data, dataTime, "time")); + jsvUnLock(dataTime); + } + jsiExecuteEventCallback(timerCallback, data, 0); + jsvUnLock(data); + if (jsvGetBool(timerRecurring)) { + JsVarFloat interval = jsvGetFloatAndUnLock(jsvSkipNameAndUnLock(jsvFindChildFromStringRef(timerNamePtr->firstChild, "interval", false))); + if (interval<=0) + jsvSetInteger(timerTime, time); // just set to current system time + else + jsvSetInteger(timerTime, jsvGetInteger(timerTime)+jshGetTimeFromMilliseconds(interval)); + } else { + // free all + JsVar *foundChild = jsvFindChildFromVar(timerArrayPtr, timerNamePtr, false); + if (foundChild) { + // check it exists - could have been removed during jsiExecuteEventCallback! + jsvRemoveChild(timerArrayPtr, timerNamePtr); + jsvUnLock(foundChild); + } + } + jsvUnLock(timerCallback); + jsvUnLock(timerRecurring); + + } + jsvUnLock(timerTime); + jsvUnLock(timerNamePtr); + } + jsvUnLock(timerArrayPtr); + + + // Check for network events +#ifdef USE_NET + httpIdle(); +#endif + + // Just in case we got any events to do and didn't clear loopsIdling before + if (wasBusy || !jsvArrayIsEmpty(events) ) + loopsIdling = 0; + + if (wasBusy) + jsiSetBusy(BUSY_INTERACTIVE, false); + + + // TODO: could now sort events by time? + // execute any outstanding events + if (!jspIsInterrupted()) { + jsiExecuteEvents(); + } + if (interruptedDuringEvent) { + jspSetInterrupted(false); + interruptedDuringEvent = false; + jsiConsolePrint("Execution Interrupted during event processing - clearing all timers and watches.\n"); + jswrap_interface_clearInterval(0); + jswrap_interface_clearWatch(0); + } + + // check for TODOs + if (todo) { + jsiSetBusy(BUSY_INTERACTIVE, true); + if (todo & TODO_RESET) { + todo &= (TODOFlags)~TODO_RESET; + // shut down everything and start up again + jsiKill(); + jsiInit(false); // don't autoload + } + if (todo & TODO_FLASH_SAVE) { + todo &= (TODOFlags)~TODO_FLASH_SAVE; + + jsvGarbageCollect(); // nice to have everything all tidy! + jsiSoftKill(); + jspSoftKill(&p); + jsvSoftKill(); + jshSaveToFlash(); + jsvSoftInit(); + jspSoftInit(&p); + jsiSoftInit(); + } + if (todo & TODO_FLASH_LOAD) { + todo &= (TODOFlags)~TODO_FLASH_LOAD; + + jsiSoftKill(); + jspSoftKill(&p); + jsvSoftKill(); + jshLoadFromFlash(); + jsvSoftInit(); + jspSoftInit(&p); + jsiSoftInit(); + } + jsiSetBusy(BUSY_INTERACTIVE, false); + } + + /* if we've been around this loop, there is nothing to do, and + * we have a spare 10ms then let's do some Garbage Collection + * just in case. */ + if (loopsIdling==1 && + minTimeUntilNext > jshGetTimeFromMilliseconds(10)) { + jsiSetBusy(BUSY_INTERACTIVE, true); + jsvGarbageCollect(); + jsiSetBusy(BUSY_INTERACTIVE, false); + } + // Go to sleep! + if (loopsIdling>1 && // once around the idle loop without having done any work already (just in case) +#ifdef USB + !jshIsUSBSERIALConnected() && // if USB is on, no point sleeping (later, sleep might be more drastic) +#endif + !jshHasEvents() && //no events have arrived in the mean time + !jshHasTransmitData()/* && //nothing left to send over serial? + minTimeUntilNext > SYSTICK_RANGE*5/4*/) { // we are sure we won't miss anything - leave a little leeway (SysTick will wake us up!) + jshSleep(minTimeUntilNext); + } +} + +void jsiLoop() { + // idle stuff for hardware + jshIdle(); + // Do general idle stuff + jsiIdle(); + // Idle LCD +#ifdef USE_LCD + graphicsIdle(); +#endif + + if (jspIsInterrupted()) { + jspSetInterrupted(false); + jsiConsoleRemoveInputLine(); + // clear input line + jsvUnLock(inputLine); + inputLine = jsvNewFromEmptyString(); + } + + // return console (if it was gone!) + jsiReturnInputLine(); +} + +/** Output extra functions defined in an object such that they can be copied to a new device */ +void jsiDumpObjectState(JsVar *parentName, JsVar *parent) { + JsVarRef childRef = parent->firstChild; + while (childRef) { + JsVar *child = jsvLock(childRef); + JsVar *data = jsvSkipName(child); + if (jsvIsStringEqual(child, JSPARSE_PROTOTYPE_VAR)) { + JsVarRef protoRef = data->firstChild; + while (protoRef) { + JsVar *proto = jsvLock(protoRef); + jsiConsolePrintStringVar(parentName); + jsiConsolePrint(".prototype."); + jsiConsolePrintStringVar(proto); + jsiConsolePrint(" = "); + JsVar *protoData = jsvSkipName(proto); + jsfPrintJSON(protoData); + jsvUnLock(protoData); + jsiConsolePrint(";\n"); + protoRef = proto->nextSibling; + jsvUnLock(proto); + } + } else { + jsiConsolePrintStringVar(parentName); + jsiConsolePrint("."); + jsiConsolePrintStringVar(child); + jsiConsolePrint(" = "); + jsfPrintJSON(data); + jsiConsolePrint(";\n"); + + } + jsvUnLock(data); + childRef = child->nextSibling; + jsvUnLock(child); + } +} + +/** Output current interpreter state such that it can be copied to a new device */ +void jsiDumpState() { + JsVarRef childRef = p.root->firstChild; + while (childRef) { + JsVar *child = jsvLock(childRef); + char childName[JSLEX_MAX_TOKEN_LENGTH]; + jsvGetString(child, childName, JSLEX_MAX_TOKEN_LENGTH); + + JsVar *data = jsvSkipName(child); + if (jspIsCreatedObject(&p, data) || jswIsBuiltInObject(childName)) { + jsiDumpObjectState(child, data); + } else if (jsvIsStringEqual(child, JSI_TIMERS_NAME)) { + // skip - done later + } else if (jsvIsStringEqual(child, JSI_WATCHES_NAME)) { + // skip - done later + } else if (child->varData.str[0]==JS_HIDDEN_CHAR || + jshFromDeviceString(childName)!=EV_NONE) { + // skip - don't care about this stuff + } else if (!jsvIsNative(data)) { // just a variable/function! + if (jsvIsFunction(data)) { + // function-specific output + jsiConsolePrint("function "); + jsiConsolePrintStringVar(child); + jsfPrintJSONForFunction(data); + jsiConsolePrint("\n"); + // print any prototypes we had + JsVar *proto = jsvObjectGetChild(data, JSPARSE_PROTOTYPE_VAR, 0); + if (proto) { + JsVarRef protoRef = proto->firstChild; + jsvUnLock(proto); + while (protoRef) { + JsVar *protoName = jsvLock(protoRef); + JsVar *protoData = jsvSkipName(protoName); + jsiConsolePrintStringVar(child); + jsiConsolePrint(".prototype."); + jsiConsolePrintStringVar(protoName); + jsiConsolePrint(" = "); + jsfPrintJSON(protoData); + jsiConsolePrint(";\n"); + jsvUnLock(protoData); + protoRef = protoName->nextSibling; + jsvUnLock(protoName); + } + } + } else { + // normal variable definition + jsiConsolePrint("var "); + jsiConsolePrintStringVar(child); + jsiConsolePrint(" = "); + jsfPrintJSON(data); + jsiConsolePrint(";\n"); + } + } + jsvUnLock(data); + childRef = child->nextSibling; + jsvUnLock(child); + } + // Now do timers + JsVar *timerArrayPtr = jsvLock(timerArray); + JsVarRef timerRef = timerArrayPtr->firstChild; + jsvUnLock(timerArrayPtr); + while (timerRef) { + JsVar *timerNamePtr = jsvLock(timerRef); + JsVar *timerCallback = jsvSkipOneNameAndUnLock(jsvFindChildFromStringRef(timerNamePtr->firstChild, "callback", false)); + bool recur = jsvGetBoolAndUnLock(jsvSkipNameAndUnLock(jsvFindChildFromStringRef(timerNamePtr->firstChild, "recur", false))); + JsVar *timerInterval = jsvSkipNameAndUnLock(jsvFindChildFromStringRef(timerNamePtr->firstChild, "interval", false)); + jsiConsolePrint(recur ? "setInterval(" : "setTimeout("); + jsfPrintJSON(timerCallback); + jsiConsolePrint(", "); + jsfPrintJSON(timerInterval); + jsiConsolePrint(");\n"); + jsvUnLock(timerInterval); + jsvUnLock(timerCallback); + // next + timerRef = timerNamePtr->nextSibling; + jsvUnLock(timerNamePtr); + } + // Now do watches + { + JsVar *watchArrayPtr = jsvLock(watchArray); + JsVarRef watchRef = watchArrayPtr->firstChild; + jsvUnLock(watchArrayPtr); + while (watchRef) { + JsVar *watchNamePtr = jsvLock(watchRef); + JsVar *watchCallback = jsvSkipOneNameAndUnLock(jsvFindChildFromStringRef(watchNamePtr->firstChild, "callback", false)); + bool watchRecur = jsvGetBoolAndUnLock(jsvSkipNameAndUnLock(jsvFindChildFromStringRef(watchNamePtr->firstChild, "recur", false))); + int watchEdge = (int)jsvGetIntegerAndUnLock(jsvSkipNameAndUnLock(jsvFindChildFromStringRef(watchNamePtr->firstChild, "edge", false))); + JsVar *watchPin = jsvSkipNameAndUnLock(jsvFindChildFromStringRef(watchNamePtr->firstChild, "pin", false)); + jsiConsolePrint("setWatch("); + jsfPrintJSON(watchCallback); + jsiConsolePrint(", "); + jsfPrintJSON(watchPin); + jsiConsolePrint(", { repeat:"); + jsiConsolePrint(watchRecur?"true":"false"); + jsiConsolePrint(", edge:"); + if (watchEdge<0) jsiConsolePrint("'falling'"); + else if (watchEdge>0) jsiConsolePrint("'rising'"); + else jsiConsolePrint("'both'"); + jsiConsolePrint(" });\n"); + jsvUnLock(watchPin); + jsvUnLock(watchCallback); + // next + watchRef = watchNamePtr->nextSibling; + jsvUnLock(watchNamePtr); + } + } + // and now serial + JsVar *str = jsvNewFromEmptyString(); + jsiAppendHardwareInitialisation(str, true); + jsiConsolePrintStringVar(str); + jsvUnLock(str); +} + +void jsiSetTodo(TODOFlags newTodo) { + todo = newTodo; +} + +JsParse *jsiGetParser() { + return &p; +} diff --git a/components/external/espruino/src/jsinteractive.h b/components/external/espruino/src/jsinteractive.h new file mode 100644 index 0000000000..6d67bb6788 --- /dev/null +++ b/components/external/espruino/src/jsinteractive.h @@ -0,0 +1,105 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Interactive Shell implementation + * ---------------------------------------------------------------------------- + */ +#ifndef JSINTERACTIVE_H_ +#define JSINTERACTIVE_H_ + +#include "jsparse.h" +#include "jshardware.h" + +#define JSI_WATCHES_NAME ">watches" +#define JSI_TIMERS_NAME ">timers" +#define JSI_HISTORY_NAME ">history" +#define JSI_INIT_CODE_NAME ">init" +#define JSI_ONINIT_NAME "onInit" + +/// autoLoad = do we load the current state if it exists? +void jsiInit(bool autoLoad); +void jsiKill(); + +void jsiLoop(); + +/// Tries to get rid of some memory (by clearing command history). Returns true if it got rid of something, false if it didn't. +bool jsiFreeMoreMemory(); + +bool jsiHasTimers(); // are there timers still left to run? +JsParse *jsiGetParser(); + +/// Queue up callbacks for other things (touchscreen? network?) +void jsiQueueObjectCallbacks(JsVar *object, const char *callbackName, JsVar *arg0, JsVar *arg1); + + +IOEventFlags jsiGetDeviceFromClass(JsVar *deviceClass); +JsVar *jsiGetClassNameFromDevice(IOEventFlags device); + +/// Change the console to a new location +void jsiSetConsoleDevice(IOEventFlags device); +/// Get the device that the console is currently on +IOEventFlags jsiGetConsoleDevice(); +/// Transmit a byte +void jsiConsolePrintChar(char data); +/// Transmit a string +void jsiConsolePrint(const char *str); +/// Write the formatted string to the console (see vcbprintf) +void jsiConsolePrintf(const char *fmt, ...); +/// Print the contents of a string var - directly +void jsiConsolePrintStringVar(JsVar *v); +/// Transmit an integer +void jsiConsolePrintInt(JsVarInt d); +/// Transmit a position in the lexer (for reporting errors) +void jsiConsolePrintPosition(struct JsLex *lex, int tokenPos); +/// Transmit the current line, along with a marker of where the error was (for reporting errors) +void jsiConsolePrintTokenLineMarker(struct JsLex *lex, int tokenPos); +/// Print the contents of a string var to a device - directly +void jsiTransmitStringVar(IOEventFlags device, JsVar *v); +/// If the input line was shown in the console, remove it +void jsiConsoleRemoveInputLine(); +/// Change what is in the inputline into something else (and update the console) +void jsiReplaceInputLine(JsVar *newLine); + +/// Flags for jsiSetBusy - THESE SHOULD BE 2^N +typedef enum { + BUSY_INTERACTIVE = 1, + BUSY_TRANSMIT = 2, + // ??? = 4 +} JsiBusyDevice; +/// Shows a busy indicator, if one is set up +void jsiSetBusy(JsiBusyDevice device, bool isBusy); +/// Shows a sleep indicator, if one is set up +void jsiSetSleep(bool isSleep); + + +// for jswrap_interactive/io.c ---------------------------------------------------- +typedef enum { + TODO_NOTHING = 0, + TODO_FLASH_SAVE = 1, + TODO_FLASH_LOAD = 2, + TODO_RESET = 4, +} TODOFlags; +#define USART_CALLBACK_NAME "_callback" +#define USART_BAUDRATE_NAME "_baudrate" +#define DEVICE_OPTIONS_NAME "_options" + +extern Pin pinBusyIndicator; +extern Pin pinSleepIndicator; +extern bool echo; +extern bool allowDeepSleep; +void jsiDumpState(); +void jsiSetTodo(TODOFlags newTodo); +#define TIMER_MIN_INTERVAL 0.1 // in milliseconds +extern JsVarRef timerArray; // Linked List of timers to check and run +extern JsVarRef watchArray; // Linked List of input watches to check and run +// end for jswrap_interactive/io.c ------------------------------------------------ + + +#endif /* JSINTERACTIVE_H_ */ diff --git a/components/external/espruino/src/jslex.c b/components/external/espruino/src/jslex.c new file mode 100644 index 0000000000..02d9befa58 --- /dev/null +++ b/components/external/espruino/src/jslex.c @@ -0,0 +1,501 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Lexer (convert JsVar strings into a series of tokens) + * ---------------------------------------------------------------------------- + */ +#include "jslex.h" + + +void jslSeek(JsLex *lex, JslCharPos seekToChar) { + jsvStringIteratorFree(&lex->it); + jsvStringIteratorNew(&lex->it, lex->sourceVar, seekToChar); +} + +void NO_INLINE jslGetNextCh(JsLex *lex) { + lex->currCh = lex->nextCh; + lex->nextCh = jsvStringIteratorGetChar(&lex->it); + jsvStringIteratorNextInline(&lex->it); +} + +static inline void jslTokenAppendChar(JsLex *lex, char ch) { + /* Add character to buffer but check it isn't too big. + * Also Leave ONE character at the end for null termination */ + if (lex->tokenl < JSLEX_MAX_TOKEN_LENGTH-1) { + lex->token[lex->tokenl++] = ch; + } +#ifdef DEBUG + else { + jsWarnAt("Token name is too long! skipping character", lex, lex->tokenStart); + } +#endif +} + +static bool jslIsToken(JsLex *lex, const char *token, int startOffset) { + int i; + for (i=startOffset;itokenl;i++) { + if (lex->token[i]!=token[i]) return false; + // if token is smaller than lex->token, there will be a null char + // which will be different from the token + } + return token[lex->tokenl] == 0; // only match if token ends now +} + +void jslGetNextToken(JsLex *lex) { + lex->tk = LEX_EOF; + lex->tokenl = 0; // clear token string + if (lex->tokenValue) { + jsvUnLock(lex->tokenValue); + lex->tokenValue = 0; + } + while (lex->currCh && isWhitespace(lex->currCh)) jslGetNextCh(lex); + // newline comments + if (lex->currCh=='/' && lex->nextCh=='/') { + while (lex->currCh && lex->currCh!='\n') jslGetNextCh(lex); + jslGetNextCh(lex); + jslGetNextToken(lex); + return; + } + // block comments + if (lex->currCh=='/' && lex->nextCh=='*') { + while (lex->currCh && !(lex->currCh=='*' && lex->nextCh=='/')) + jslGetNextCh(lex); + if (!lex->currCh) { + lex->tk = LEX_UNFINISHED_COMMENT; + return; /* an unfinished multi-line comment. When in interactive console, + detect this and make sure we accept new lines */ + } + jslGetNextCh(lex); + jslGetNextCh(lex); + jslGetNextToken(lex); + return; + } + // record beginning of this token + lex->tokenLastStart = lex->tokenStart; + lex->tokenStart = (JslCharPos)(lex->it.index-2); + // tokens + if (isAlpha(lex->currCh) || lex->currCh=='$') { // IDs + while (isAlpha(lex->currCh) || isNumeric(lex->currCh) || lex->currCh=='$') { + jslTokenAppendChar(lex, lex->currCh); + jslGetNextCh(lex); + } + lex->tk = LEX_ID; + // We do fancy stuff here to reduce number of compares (hopefully GCC creates a jump table) + switch (lex->token[0]) { + case 'b': if (jslIsToken(lex,"break", 1)) lex->tk = LEX_R_BREAK; + break; + case 'c': if (jslIsToken(lex,"case", 1)) lex->tk = LEX_R_CASE; + else if (jslIsToken(lex,"continue", 1)) lex->tk = LEX_R_CONTINUE; + break; + case 'd': if (jslIsToken(lex,"default", 1)) lex->tk = LEX_R_DEFAULT; + else if (jslIsToken(lex,"do", 1)) lex->tk = LEX_R_DO; + break; + case 'e': if (jslIsToken(lex,"else", 1)) lex->tk = LEX_R_ELSE; + break; + case 'f': if (jslIsToken(lex,"false", 1)) lex->tk = LEX_R_FALSE; + else if (jslIsToken(lex,"for", 1)) lex->tk = LEX_R_FOR; + else if (jslIsToken(lex,"function", 1)) lex->tk = LEX_R_FUNCTION; + break; + case 'i': if (jslIsToken(lex,"if", 1)) lex->tk = LEX_R_IF; + else if (jslIsToken(lex,"in", 1)) lex->tk = LEX_R_IN; + else if (jslIsToken(lex,"instanceof", 1)) lex->tk = LEX_R_INSTANCEOF; + break; + case 'n': if (jslIsToken(lex,"new", 1)) lex->tk = LEX_R_NEW; + else if (jslIsToken(lex,"null", 1)) lex->tk = LEX_R_NULL; + break; + case 'r': if (jslIsToken(lex,"return", 1)) lex->tk = LEX_R_RETURN; + break; + case 's': if (jslIsToken(lex,"switch", 1)) lex->tk = LEX_R_SWITCH; + break; + case 't': if (jslIsToken(lex,"this", 1)) lex->tk = LEX_R_THIS; + else if (jslIsToken(lex,"true", 1)) lex->tk = LEX_R_TRUE; + else if (jslIsToken(lex,"typeof", 1)) lex->tk = LEX_R_TYPEOF; + break; + case 'u': if (jslIsToken(lex,"undefined", 1)) lex->tk = LEX_R_UNDEFINED; + break; + case 'w': if (jslIsToken(lex,"while", 1)) lex->tk = LEX_R_WHILE; + break; + case 'v': if (jslIsToken(lex,"var", 1)) lex->tk = LEX_R_VAR; + else if (jslIsToken(lex,"void", 1)) lex->tk = LEX_R_VOID; + break; + default: break; + } + } else if (isNumeric(lex->currCh)) { // Numbers + // TODO: check numbers aren't the wrong format + bool canBeFloating = true; + if (lex->currCh=='0') { + jslTokenAppendChar(lex, lex->currCh); + jslGetNextCh(lex); + } + + if ((lex->currCh=='x' || lex->currCh=='X') || + (lex->currCh=='b' || lex->currCh=='B') || + (lex->currCh=='o' || lex->currCh=='O')) { + canBeFloating = false; + jslTokenAppendChar(lex, lex->currCh); jslGetNextCh(lex); + } + lex->tk = LEX_INT; + while (isNumeric(lex->currCh) || (!canBeFloating && isHexadecimal(lex->currCh))) { + jslTokenAppendChar(lex, lex->currCh); + jslGetNextCh(lex); + } + if (canBeFloating && lex->currCh=='.') { + lex->tk = LEX_FLOAT; + jslTokenAppendChar(lex, '.'); + jslGetNextCh(lex); + while (isNumeric(lex->currCh)) { + jslTokenAppendChar(lex, lex->currCh); + jslGetNextCh(lex); + } + } + // do fancy e-style floating point + if (canBeFloating && (lex->currCh=='e'||lex->currCh=='E')) { + lex->tk = LEX_FLOAT; + jslTokenAppendChar(lex, lex->currCh); jslGetNextCh(lex); + if (lex->currCh=='-' || lex->currCh=='+') { jslTokenAppendChar(lex, lex->currCh); jslGetNextCh(lex); } + while (isNumeric(lex->currCh)) { + jslTokenAppendChar(lex, lex->currCh); jslGetNextCh(lex); + } + } + } else if (lex->currCh=='"' || lex->currCh=='\'') { + char delim = lex->currCh; + lex->tokenValue = jsvNewFromEmptyString(); + // strings... + jslGetNextCh(lex); + while (lex->currCh && lex->currCh!=delim) { + if (lex->currCh == '\\') { + jslGetNextCh(lex); + char ch = lex->currCh; + switch (lex->currCh) { + case 'n' : ch = '\n'; jslGetNextCh(lex); break; + case 'a' : ch = '\a'; jslGetNextCh(lex); break; + case 'r' : ch = '\r'; jslGetNextCh(lex); break; + case 't' : ch = '\t'; jslGetNextCh(lex); break; + case 'x' : { // hex digits + char buf[5] = "0x??"; + jslGetNextCh(lex); + buf[2] = lex->currCh; jslGetNextCh(lex); + buf[3] = lex->currCh; jslGetNextCh(lex); + ch = (char)stringToInt(buf); + } break; + default: + if (lex->currCh>='0' && lex->currCh<='7') { + // octal digits + char buf[5] = "0"; + buf[1] = lex->currCh; + int n=2; + jslGetNextCh(lex); + if (lex->currCh>='0' && lex->currCh<='7') { + buf[n++] = lex->currCh; jslGetNextCh(lex); + if (lex->currCh>='0' && lex->currCh<='7') { + buf[n++] = lex->currCh; jslGetNextCh(lex); + } + } + buf[n]=0; + ch = (char)stringToInt(buf); + } else { + // for anything else, just push the character through + jslGetNextCh(lex); + } + break; + } + if (lex->tokenValue) { + jslTokenAppendChar(lex, ch); + jsvAppendCharacter(lex->tokenValue, ch); + } + } else { + if (lex->tokenValue) { + jslTokenAppendChar(lex, lex->currCh); + jsvAppendCharacter(lex->tokenValue, lex->currCh); + } + jslGetNextCh(lex); + } + } + jslGetNextCh(lex); + lex->tk = LEX_STR; + } else { + // single chars + lex->tk = lex->currCh; + jslGetNextCh(lex); + if (lex->tk=='=' && lex->currCh=='=') { // == + lex->tk = LEX_EQUAL; + jslGetNextCh(lex); + if (lex->currCh=='=') { // === + lex->tk = LEX_TYPEEQUAL; + jslGetNextCh(lex); + } + } else if (lex->tk=='!' && lex->currCh=='=') { // != + lex->tk = LEX_NEQUAL; + jslGetNextCh(lex); + if (lex->currCh=='=') { // !== + lex->tk = LEX_NTYPEEQUAL; + jslGetNextCh(lex); + } + } else if (lex->tk=='<') { + if (lex->currCh=='=') { + lex->tk = LEX_LEQUAL; + jslGetNextCh(lex); + } else if (lex->currCh=='<') { + lex->tk = LEX_LSHIFT; + jslGetNextCh(lex); + if (lex->currCh=='=') { // <<= + lex->tk = LEX_LSHIFTEQUAL; + jslGetNextCh(lex); + } + } + } else if (lex->tk=='>') { + if (lex->currCh=='=') { + lex->tk = LEX_GEQUAL; + jslGetNextCh(lex); + } else if (lex->currCh=='>') { + lex->tk = LEX_RSHIFT; + jslGetNextCh(lex); + if (lex->currCh=='=') { // >>= + lex->tk = LEX_RSHIFTEQUAL; + jslGetNextCh(lex); + } else if (lex->currCh=='>') { // >>> + jslGetNextCh(lex); + if (lex->currCh=='=') { // >>>= + lex->tk = LEX_RSHIFTUNSIGNEDEQUAL; + jslGetNextCh(lex); + } else { + lex->tk = LEX_RSHIFTUNSIGNED; + } + } + } + } else if (lex->tk=='+') { + if (lex->currCh=='=') { + lex->tk = LEX_PLUSEQUAL; + jslGetNextCh(lex); + } else if (lex->currCh=='+') { + lex->tk = LEX_PLUSPLUS; + jslGetNextCh(lex); + } + } else if (lex->tk=='-') { + if (lex->currCh=='=') { + lex->tk = LEX_MINUSEQUAL; + jslGetNextCh(lex); + } else if (lex->currCh=='-') { + lex->tk = LEX_MINUSMINUS; + jslGetNextCh(lex); + } + } else if (lex->tk=='&') { + if (lex->currCh=='=') { + lex->tk = LEX_ANDEQUAL; + jslGetNextCh(lex); + } else if (lex->currCh=='&') { + lex->tk = LEX_ANDAND; + jslGetNextCh(lex); + } + } else if (lex->tk=='|') { + if (lex->currCh=='=') { + lex->tk = LEX_OREQUAL; + jslGetNextCh(lex); + } else if (lex->tk=='|' && lex->currCh=='|') { + lex->tk = LEX_OROR; + jslGetNextCh(lex); + } + } else if (lex->tk=='^' && lex->currCh=='=') { + lex->tk = LEX_XOREQUAL; + jslGetNextCh(lex); + } else if (lex->tk=='*' && lex->currCh=='=') { + lex->tk = LEX_MULEQUAL; + jslGetNextCh(lex); + } else if (lex->tk=='/' && lex->currCh=='=') { + lex->tk = LEX_DIVEQUAL; + jslGetNextCh(lex); + } else if (lex->tk=='%' && lex->currCh=='=') { + lex->tk = LEX_MODEQUAL; + jslGetNextCh(lex); + } + } + /* This isn't quite right yet */ + lex->tokenLastEnd = lex->tokenEnd; + lex->tokenEnd = (JslCharPos)(lex->it.index-3)/*because of nextCh/currCh/etc */; +} + +static inline void jslPreload(JsLex *lex) { + // set up.. + jslGetNextCh(lex); + jslGetNextCh(lex); + jslGetNextToken(lex); +} + +void jslInit(JsLex *lex, JsVar *var) { + lex->sourceVar = jsvLockAgain(var); + // reset stuff + lex->tk = 0; + lex->tokenStart = 0; + lex->tokenEnd = 0; + lex->tokenLastStart = 0; + lex->tokenLastEnd = 0; + lex->tokenl = 0; + lex->tokenValue = 0; + // set up iterator + jsvStringIteratorNew(&lex->it, lex->sourceVar, 0); + jslPreload(lex); +} + +void jslKill(JsLex *lex) { + lex->tk = LEX_EOF; // safety ;) + jsvStringIteratorFree(&lex->it); + if (lex->tokenValue) { + jsvUnLock(lex->tokenValue); + lex->tokenValue = 0; + } + jsvUnLock(lex->sourceVar); +} + +void jslSeekTo(JsLex *lex, JslCharPos seekToChar) { + jslSeek(lex, seekToChar); + jslPreload(lex); +} + +void jslReset(JsLex *lex) { + jslSeekTo(lex, 0); +} + +void jslTokenAsString(int token, char *str, size_t len) { + // see JS_ERROR_TOKEN_BUF_SIZE + if (token>32 && token<128) { + assert(len>=4); + str[0] = '\''; + str[1] = (char)token; + str[2] = '\''; + str[3] = 0; + return; + } + + switch (token) { + case LEX_EOF : strncpy(str, "EOF", len); return; + case LEX_ID : strncpy(str, "ID", len); return; + case LEX_INT : strncpy(str, "INT", len); return; + case LEX_FLOAT : strncpy(str, "FLOAT", len); return; + case LEX_STR : strncpy(str, "STRING", len); return; + } + if (token>=LEX_EQUAL && token=\0" + /* LEX_RSHIFT : */ ">>\0" + /* LEX_RSHIFTUNSIGNED */ ">>>\0" + /* LEX_RSHIFTEQUAL : */ ">>=\0" + /* LEX_RSHIFTUNSIGNEDEQUAL */ ">>>=\0" + /* LEX_PLUSEQUAL : */ "+=\0" + /* LEX_MINUSEQUAL : */ "-=\0" + /* LEX_PLUSPLUS : */ "++\0" + /* LEX_MINUSMINUS */ "--\0" + /* LEX_MULEQUAL : */ "*=\0" + /* LEX_DIVEQUAL : */ "/=\0" + /* LEX_MODEQUAL : */ "%=\0" + /* LEX_ANDEQUAL : */ "&=\0" + /* LEX_ANDAND : */ "&&\0" + /* LEX_OREQUAL : */ "|=\0" + /* LEX_OROR : */ "||\0" + /* LEX_XOREQUAL : */ "^=\0" + + // reserved words + /*LEX_R_IF : */ "if\0" + /*LEX_R_ELSE : */ "else\0" + /*LEX_R_DO : */ "do\0" + /*LEX_R_WHILE : */ "while\0" + /*LEX_R_FOR : */ "for\0" + /*LEX_R_BREAK : */ "return\0" + /*LEX_R_CONTINUE */ "continue\0" + /*LEX_R_FUNCTION */ "function\0" + /*LEX_R_RETURN */ "return\0" + /*LEX_R_VAR : */ "var\0" + /*LEX_R_THIS : */ "this\0" + /*LEX_R_TRUE : */ "true\0" + /*LEX_R_FALSE : */ "false\0" + /*LEX_R_NULL : */ "null\0" + /*LEX_R_UNDEFINED */ "undefined\0" + /*LEX_R_NEW : */ "new\0" + /*LEX_R_IN : */ "in\0" + /*LEX_R_INSTANCEOF */ "instanceof\0" + /*LEX_R_SWITCH */ "switch\0" + /*LEX_R_CASE */ "case\0" + /*LEX_R_DEFAULT */ "default\0" + /*LEX_R_TYPEOF : */ "typeof\0" + /*LEX_R_VOID : */ "void\0" + ; + unsigned int p = 0; + int n = token-LEX_EQUAL; + while (n>0 && p=10); + strncpy(str, "?[",len); + itoa(token, &str[2], 10); + strncat(str, "]",len); +} + +void jslGetTokenString(JsLex *lex, char *str, size_t len) { + if (lex->tk == LEX_ID) { + strncpy(str, "ID:", len); + strncat(str, jslGetTokenValueAsString(lex), len); + } else if (lex->tk == LEX_STR) { + strncpy(str, "String:'", len); + strncat(str, jslGetTokenValueAsString(lex), len); + strncat(str, "'", len); + } else + jslTokenAsString(lex->tk, str, len); +} + +char *jslGetTokenValueAsString(JsLex *lex) { + assert(lex->tokenl < JSLEX_MAX_TOKEN_LENGTH); + lex->token[lex->tokenl] = 0; // add final null + return lex->token; +} + +JsVar *jslGetTokenValueAsVar(JsLex *lex) { + if (lex->tokenValue) { + return jsvLockAgain(lex->tokenValue); + } else { + assert(lex->tokenl < JSLEX_MAX_TOKEN_LENGTH); + lex->token[lex->tokenl] = 0; // add final null + return jsvNewFromString(lex->token); + } +} + +/// Match, and return true on success, false on failure +bool jslMatch(JsLex *lex, int expected_tk) { + if (lex->tk!=expected_tk) { + char buf[JS_ERROR_BUF_SIZE]; + size_t bufpos = 0; + strncpy(&buf[bufpos], "Got ", JS_ERROR_BUF_SIZE-bufpos); + bufpos = strlen(buf); + jslGetTokenString(lex, &buf[bufpos], JS_ERROR_BUF_SIZE-bufpos); + bufpos = strlen(buf); + strncpy(&buf[bufpos], " expected ", JS_ERROR_BUF_SIZE-bufpos); + bufpos = strlen(buf); + jslTokenAsString(expected_tk, &buf[bufpos], JS_ERROR_BUF_SIZE-bufpos); + jsErrorAt(buf, lex, lex->tokenStart); + // Sod it, skip this token anyway - stops us looping + jslGetNextToken(lex); + return false; + } + jslGetNextToken(lex); + return true; +} + diff --git a/components/external/espruino/src/jslex.h b/components/external/espruino/src/jslex.h new file mode 100644 index 0000000000..8a1aee3a9b --- /dev/null +++ b/components/external/espruino/src/jslex.h @@ -0,0 +1,59 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Lexer (convert JsVar strings into a series of tokens) + * ---------------------------------------------------------------------------- + */ +#ifndef JSLEX_H_ +#define JSLEX_H_ + +#include "jsutils.h" +#include "jsvar.h" + +typedef struct JsLex +{ + // Actual Lexing related stuff + char currCh, nextCh; + short tk; ///< The type of the token that we have + JslCharPos tokenStart; ///< Position in the data at the beginning of the token we have here + JslCharPos tokenEnd; ///< Position in the data at the last character of the token we have here + JslCharPos tokenLastStart; ///< Position in the data of the first character of the last token + JslCharPos tokenLastEnd; ///< Position in the data of the last character of the last token + char token[JSLEX_MAX_TOKEN_LENGTH]; ///< Data contained in the token we have here + JsVar *tokenValue; ///< JsVar containing the current token - used only for strings + unsigned char tokenl; ///< the current length of token + + /* Where we get our data from... + * + * This is a bit more tricky than normal because the data comes from JsVars, + * which only have fixed length strings. If we go past this, we have to go + * to the next jsVar... + */ + JsVar *sourceVar; // the actual string var + JsvStringIterator it; // Iterator for the string +} JsLex; + +void jslInit(JsLex *lex, JsVar *var); +void jslKill(JsLex *lex); +void jslReset(JsLex *lex); +void jslSeekTo(JsLex *lex, JslCharPos seekToChar); // like jslSeek, but pre-fills characters + +bool jslMatch(JsLex *lex, int expected_tk); ///< Match, and return true on success, false on failure +void jslTokenAsString(int token, char *str, size_t len); ///< output the given token as a string - for debugging +void jslGetTokenString(JsLex *lex, char *str, size_t len); +char *jslGetTokenValueAsString(JsLex *lex); +JsVar *jslGetTokenValueAsVar(JsLex *lex); + +// Only for more 'internal' use +void jslSeek(JsLex *lex, JslCharPos seekToChar); // like jslSeekTo, but doesn't pre-fill characters +void jslGetNextCh(JsLex *lex); +void jslGetNextToken(JsLex *lex); ///< Get the text token from our text string + +#endif /* JSLEX_H_ */ diff --git a/components/external/espruino/src/jsparse.c b/components/external/espruino/src/jsparse.c new file mode 100644 index 0000000000..fb7d42a068 --- /dev/null +++ b/components/external/espruino/src/jsparse.c @@ -0,0 +1,2213 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Recursive descent parser for code execution + * ---------------------------------------------------------------------------- + */ +#include "jsparse.h" +#include "jsinteractive.h" +#include "jswrapper.h" + +/* Info about execution when Parsing - this saves passing it on the stack + * for each call */ +JsExecInfo execInfo; + +// ----------------------------------------------- Forward decls +JsVar *jspeBase(); +JsVar *jspeBaseWithComma(); +JsVar *jspeBlock(); +JsVar *jspeStatement(); +// ----------------------------------------------- Utils +#define JSP_MATCH_WITH_CLEANUP_AND_RETURN(TOKEN, CLEANUP_CODE, RETURN_VAL) { if (!jslMatch(execInfo.lex,(TOKEN))) { jspSetError(); CLEANUP_CODE; return RETURN_VAL; } } +#define JSP_MATCH_WITH_RETURN(TOKEN, RETURN_VAL) JSP_MATCH_WITH_CLEANUP_AND_RETURN(TOKEN, , RETURN_VAL) +#define JSP_MATCH(TOKEN) JSP_MATCH_WITH_CLEANUP_AND_RETURN(TOKEN, , 0) +#define JSP_SHOULD_EXECUTE (((execInfo.execute)&EXEC_RUN_MASK)==EXEC_YES) +#define JSP_SAVE_EXECUTE() JsExecFlags oldExecute = execInfo.execute +#define JSP_RESTORE_EXECUTE() execInfo.execute = (execInfo.execute&(JsExecFlags)(~EXEC_SAVE_RESTORE_MASK)) | (oldExecute&EXEC_SAVE_RESTORE_MASK); +#define JSP_HAS_ERROR (((execInfo.execute)&EXEC_ERROR_MASK)!=0) + +/// if interrupting execution, this is set +bool jspIsInterrupted() { + return (execInfo.execute & EXEC_INTERRUPTED)!=0; +} + +/// if interrupting execution, this is set +void jspSetInterrupted(bool interrupt) { + if (interrupt) + execInfo.execute = execInfo.execute | EXEC_INTERRUPTED; + else + execInfo.execute = execInfo.execute & (JsExecFlags)~EXEC_INTERRUPTED; +} + +static inline void jspSetError() { + execInfo.execute = (execInfo.execute & (JsExecFlags)~EXEC_YES) | EXEC_ERROR; +} + +bool jspHasError() { + return JSP_HAS_ERROR; +} + +///< Same as jsvSetValueOfName, but nice error message +void jspReplaceWith(JsVar *dst, JsVar *src) { + // If this is an index in an array buffer, write directly into the array buffer + if (jsvIsArrayBufferName(dst)) { + JsVarInt idx = jsvGetInteger(dst); + JsVar *arrayBuffer = jsvLock(dst->firstChild); + jsvArrayBufferSet(arrayBuffer, idx, src); + jsvUnLock(arrayBuffer); + return; + } + // if destination isn't there, isn't a 'name', or is used, give an error + if (!jsvIsName(dst)) { + jsErrorAt("Unable to assign value to non-reference", execInfo.lex, execInfo.lex->tokenLastEnd); + jspSetError(); + return; + } + jsvSetValueOfName(dst, src); +} + +void jspeiInit(JsParse *parse, JsLex *lex) { + execInfo.parse = parse; + execInfo.lex = lex; + execInfo.scopeCount = 0; + execInfo.execute = EXEC_YES; +} + +void jspeiKill() { + execInfo.parse = 0; + execInfo.lex = 0; + assert(execInfo.scopeCount==0); +} + +bool jspeiAddScope(JsVarRef scope) { + if (execInfo.scopeCount >= JSPARSE_MAX_SCOPES) { + jsError("Maximum number of scopes exceeded"); + jspSetError(); + return false; + } + execInfo.scopes[execInfo.scopeCount++] = jsvRefRef(scope); + return true; +} + +void jspeiRemoveScope() { + if (execInfo.scopeCount <= 0) { + jsErrorInternal("Too many scopes removed"); + jspSetError(); + return; + } + jsvUnRefRef(execInfo.scopes[--execInfo.scopeCount]); +} + +JsVar *jspeiFindInScopes(const char *name) { + int i; + for (i=execInfo.scopeCount-1;i>=0;i--) { + JsVar *ref = jsvFindChildFromStringRef(execInfo.scopes[i], name, false); + if (ref) return ref; + } + return jsvFindChildFromString(execInfo.parse->root, name, false); +} + +JsVar *jspeiFindOnTop(const char *name, bool createIfNotFound) { + if (execInfo.scopeCount>0) + return jsvFindChildFromStringRef(execInfo.scopes[execInfo.scopeCount-1], name, createIfNotFound); + return jsvFindChildFromString(execInfo.parse->root, name, createIfNotFound); +} +JsVar *jspeiFindNameOnTop(JsVar *childName, bool createIfNotFound) { + if (execInfo.scopeCount>0) + return jsvFindChildFromVarRef(execInfo.scopes[execInfo.scopeCount-1], childName, createIfNotFound); + return jsvFindChildFromVar(execInfo.parse->root, childName, createIfNotFound); +} + +/** Here we assume that we have already looked in the parent itself - + * and are now going down looking at the stuff it inherited */ +JsVar *jspeiFindChildFromStringInParents(JsVar *parent, const char *name) { + if (jsvIsObject(parent)) { + // If an object, look for an 'inherits' var + JsVar *inheritsFrom = jsvObjectGetChild(parent, JSPARSE_INHERITS_VAR, 0); + + // if there's no inheritsFrom, just default to 'Object.prototype' + if (!inheritsFrom) { + JsVar *obj = jsvObjectGetChild(execInfo.parse->root, "Object", 0); + if (obj) { + inheritsFrom = jsvObjectGetChild(obj, JSPARSE_PROTOTYPE_VAR, 0); + jsvUnLock(obj); + } + } + + if (inheritsFrom && inheritsFrom!=parent) { + // we have what it inherits from (this is ACTUALLY the prototype var) + // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/proto + JsVar *child = jsvFindChildFromString(inheritsFrom, name, false); + if (!child) + child = jspeiFindChildFromStringInParents(inheritsFrom, name); + jsvUnLock(inheritsFrom); + if (child) return child; + } + } else { // Not actually an object - but might be an array/string/etc + const char *objectName = jswGetBasicObjectName(parent); + while (objectName) { + JsVar *objName = jsvFindChildFromString(execInfo.parse->root, objectName, false); + if (objName) { + JsVar *result = 0; + JsVar *obj = jsvSkipNameAndUnLock(objName); + if (obj) { + // We have found an object with this name - search for the prototype var + JsVar *proto = jsvObjectGetChild(obj, JSPARSE_PROTOTYPE_VAR, 0); + if (proto) { + result = jsvFindChildFromString(proto, name, false); + jsvUnLock(proto); + } + jsvUnLock(obj); + } + if (result) return result; + } + /* We haven't found anything in the actual object, we should check the 'Object' itself + eg, we tried 'String', so now we should try 'Object'. Built-in types don't have room for + a prototype field, so we hard-code it */ + objectName = jswGetBasicObjectPrototypeName(objectName); + } + } + + // no luck! + return 0; +} + +JsVar *jspeiGetScopesAsVar() { + if (execInfo.scopeCount==0) return 0; + JsVar *arr = jsvNewWithFlags(JSV_ARRAY); + int i; + for (i=0;ifirstChild); + return arr; +} + +void jspeiLoadScopesFromVar(JsVar *arr) { + execInfo.scopeCount = 0; + //printf("%d\n",arr->firstChild); + JsVarRef childref = arr->firstChild; + while (childref) { + JsVar *child = jsvLock(childref); + //printf("%d %d %d %d\n",execInfo.scopeCount,childref,child, child->firstChild); + execInfo.scopes[execInfo.scopeCount] = jsvRefRef(child->firstChild); + execInfo.scopeCount++; + childref = child->nextSibling; + jsvUnLock(child); + } +} +// ----------------------------------------------- +#ifdef ARM +extern int _end; +#endif +bool jspCheckStackPosition() { +#ifdef ARM + void *frame = __builtin_frame_address(0); + if ((char*)frame < ((char*)&_end)+1024/*so many bytes leeway*/) { +// jsiConsolePrintf("frame: %d,end:%d\n",(int)frame,(int)&_end); + jsErrorAt("Too much recursion - the stack is about to overflow", execInfo.lex, execInfo.lex->tokenStart ); + jspSetInterrupted(true); + return false; + } +#endif + return true; +} + + +// Set execFlags such that we are not executing +void jspSetNoExecute() { + execInfo.execute = (execInfo.execute & (JsExecFlags)(int)~EXEC_RUN_MASK) | EXEC_NO; +} + +// parse single variable name +bool jspParseVariableName() { + JSP_MATCH(LEX_ID); + return true; +} + +// parse function with no arguments +bool jspParseEmptyFunction() { + JSP_MATCH(LEX_ID); + JSP_MATCH('('); + if (execInfo.lex->tk != ')') + jsvUnLock(jspeBase()); + // throw away extra params + while (!JSP_HAS_ERROR && execInfo.lex->tk != ')') { + JSP_MATCH(','); + jsvUnLock(jspeBase()); + } + JSP_MATCH(')'); + return true; +} + +// parse function with a single argument, return its value (no names!) +JsVar *jspParseSingleFunction() { + JsVar *v = 0; + JSP_MATCH(LEX_ID); + JSP_MATCH('('); + if (execInfo.lex->tk != ')') + v = jsvSkipNameAndUnLock(jspeBase()); + // throw away extra params + while (!JSP_HAS_ERROR && execInfo.lex->tk != ')') { + JSP_MATCH_WITH_RETURN(',', v); + jsvUnLock(jspeBase()); + } + JSP_MATCH_WITH_RETURN(')', v); + return v; +} + +/// parse function with max 4 arguments (can set arg to 0 to avoid parse). Usually first arg will be 0, but if we DON'T want to skip names on an arg stuff, we can say +bool jspParseFunction(JspSkipFlags skipName, JsVar **a, JsVar **b, JsVar **c, JsVar **d) { + if (a) *a = 0; + if (b) *b = 0; + if (c) *c = 0; + if (d) *d = 0; + JSP_MATCH(LEX_ID); + JSP_MATCH('('); + if (a && execInfo.lex->tk != ')') { + *a = jspeBase(); + if (!(skipName&JSP_NOSKIP_A)) *a = jsvSkipNameAndUnLock(*a); + } + if (b && execInfo.lex->tk != ')') { + JSP_MATCH(','); + *b = jspeBase(); + if (!(skipName&JSP_NOSKIP_B)) *b = jsvSkipNameAndUnLock(*b); + } + if (c && execInfo.lex->tk != ')') { + JSP_MATCH(','); + *c = jspeBase(); + if (!(skipName&JSP_NOSKIP_C)) *c = jsvSkipNameAndUnLock(*c); + } + if (d && execInfo.lex->tk != ')') { + JSP_MATCH(','); + *d = jspeBase(); + if (!(skipName&JSP_NOSKIP_D)) *d = jsvSkipNameAndUnLock(*d); + } + // throw away extra params + while (!JSP_HAS_ERROR && execInfo.lex->tk != ')') { + JSP_MATCH(','); + jsvUnLock(jspeBase()); + } + JSP_MATCH(')'); + return true; +} + +/// parse function with max 8 arguments (can set arg to 0 to avoid parse). Usually first arg will be 0, but if we DON'T want to skip names on an arg stuff, we can say +bool jspParseFunction8(JspSkipFlags skipName, JsVar **a, JsVar **b, JsVar **c, JsVar **d, JsVar **e, JsVar **f, JsVar **g, JsVar **h) { + if (a) *a = 0; + if (b) *b = 0; + if (c) *c = 0; + if (d) *d = 0; + if (e) *e = 0; + if (f) *f = 0; + if (g) *g = 0; + if (h) *h = 0; + JSP_MATCH(LEX_ID); + JSP_MATCH('('); + if (a && execInfo.lex->tk != ')') { + *a = jspeBase(); + if (!(skipName&JSP_NOSKIP_A)) *a = jsvSkipNameAndUnLock(*a); + } + if (b && execInfo.lex->tk != ')') { + JSP_MATCH(','); + *b = jspeBase(); + if (!(skipName&JSP_NOSKIP_B)) *b = jsvSkipNameAndUnLock(*b); + } + if (c && execInfo.lex->tk != ')') { + JSP_MATCH(','); + *c = jspeBase(); + if (!(skipName&JSP_NOSKIP_C)) *c = jsvSkipNameAndUnLock(*c); + } + if (d && execInfo.lex->tk != ')') { + JSP_MATCH(','); + *d = jspeBase(); + if (!(skipName&JSP_NOSKIP_D)) *d = jsvSkipNameAndUnLock(*d); + } + if (e && execInfo.lex->tk != ')') { + JSP_MATCH(','); + *e = jspeBase(); + if (!(skipName&JSP_NOSKIP_E)) *e = jsvSkipNameAndUnLock(*e); + } + if (f && execInfo.lex->tk != ')') { + JSP_MATCH(','); + *f = jspeBase(); + if (!(skipName&JSP_NOSKIP_F)) *f = jsvSkipNameAndUnLock(*f); + } + if (g && execInfo.lex->tk != ')') { + JSP_MATCH(','); + *g = jspeBase(); + if (!(skipName&JSP_NOSKIP_G)) *g = jsvSkipNameAndUnLock(*g); + } + if (h && execInfo.lex->tk != ')') { + JSP_MATCH(','); + *h = jspeBase(); + if (!(skipName&JSP_NOSKIP_H)) *h = jsvSkipNameAndUnLock(*h); + } + // throw away extra params + while (!JSP_HAS_ERROR && execInfo.lex->tk != ')') { + JSP_MATCH(','); + jsvUnLock(jspeBase()); + } + JSP_MATCH(')'); + return true; +} + +/// parse a function with any number of argument, and return an array of de-named aruments +JsVar *jspParseFunctionAsArray() { + JSP_MATCH(LEX_ID); + JsVar *arr = jsvNewWithFlags(JSV_ARRAY); + if (!arr) return 0; // out of memory + JSP_MATCH_WITH_CLEANUP_AND_RETURN('(', jsvUnLock(arr), 0); + while (!JSP_HAS_ERROR && execInfo.lex->tk!=')' && execInfo.lex->tk!=LEX_EOF) { + JsVar *arg = jsvSkipNameAndUnLock(jspeBase()); + jsvArrayPushAndUnLock(arr, arg); // even if undefined + if (execInfo.lex->tk!=')') JSP_MATCH_WITH_CLEANUP_AND_RETURN(',', jsvUnLock(arr), 0); + } + JSP_MATCH_WITH_CLEANUP_AND_RETURN(')', jsvUnLock(arr), 0); + return arr; +} + +// ---------------------------------------------- + +// we return a value so that JSP_MATCH can return 0 if it fails (if we pass 0, we just parse all args) +bool jspeFunctionArguments(JsVar *funcVar) { + JSP_MATCH('('); + while (execInfo.lex->tk!=')') { + if (funcVar) { + JsVar *param = jsvAddNamedChild(funcVar, 0, jslGetTokenValueAsString(execInfo.lex)); + if (!param) { // out of memory + jspSetError(); + return false; + } + param->flags |= JSV_FUNCTION_PARAMETER; // force this to be called a function parameter + jsvUnLock(param); + } + JSP_MATCH(LEX_ID); + if (execInfo.lex->tk!=')') JSP_MATCH(','); + } + JSP_MATCH(')'); + return true; +} + +bool jspeParseNativeFunction(JsCallback callbackPtr) { + char funcName[JSLEX_MAX_TOKEN_LENGTH]; + JsVar *funcVar; + JsVar *base = jsvLockAgain(execInfo.parse->root); + JSP_MATCH(LEX_R_FUNCTION); + // not too bothered about speed/memory here as only called on init :) + strncpy(funcName, jslGetTokenValueAsString(execInfo.lex), JSLEX_MAX_TOKEN_LENGTH); + JSP_MATCH(LEX_ID); + /* Check for dots, we might want to do something like function 'String.substring' ... */ + while (execInfo.lex->tk == '.') { + JsVar *link; + JSP_MATCH('.'); + link = jsvFindChildFromString(base, funcName, false); + // if it doesn't exist, make a new object class + if (!link) { + JsVar *obj = jsvNewWithFlags(JSV_OBJECT); + link = jsvAddNamedChild(base, obj, funcName); + jsvUnLock(obj); + } + // set base to the object (not the name) + jsvUnLock(base); + base = jsvSkipNameAndUnLock(link); + // Look for another name + strncpy(funcName, jslGetTokenValueAsString(execInfo.lex), JSLEX_MAX_TOKEN_LENGTH); + JSP_MATCH(LEX_ID); + } + // So now, base points to an object where we want our function + funcVar = jsvNewWithFlags(JSV_FUNCTION | JSV_NATIVE); + if (!funcVar) { + jsvUnLock(base); + jspSetError(); + return false; // Out of memory + } + funcVar->varData.callback = callbackPtr; + jspeFunctionArguments(funcVar); + + if (JSP_HAS_ERROR) { // probably out of memory while parsing + jsvUnLock(base); + jsvUnLock(funcVar); + return false; + } + // Add the function with its name + JsVar *funcNameVar = jsvFindChildFromString(base, funcName, true); + if (funcNameVar) // could be out of memory + jsvUnLock(jsvSetValueOfName(funcNameVar, funcVar)); // unlocks funcNameVar + jsvUnLock(base); + jsvUnLock(funcVar); + return true; +} + +bool jspAddNativeFunction(JsParse *parse, const char *funcDesc, JsCallback callbackPtr) { + JsVar *fncode = jsvNewFromString(funcDesc); + if (!fncode) return false; // out of memory! + + JSP_SAVE_EXECUTE(); + JsExecInfo oldExecInfo = execInfo; + + // Set up Lexer + + JsLex lex; + jslInit(&lex, fncode); + jsvUnLock(fncode); + + + jspeiInit(parse, &lex); + + // Parse + bool success = jspeParseNativeFunction(callbackPtr); + if (!success) { + jsError("Parsing Native Function failed!"); + jspSetError(); + } + + + // cleanup + jspeiKill(); + jslKill(&lex); + JSP_RESTORE_EXECUTE(); + oldExecInfo.execute = execInfo.execute; // JSP_RESTORE_EXECUTE has made this ok. + execInfo = oldExecInfo; + + return success; +} + +JsVar *jspeFunctionDefinition() { + // actually parse a function... We assume that the LEX_FUNCTION and name + // have already been parsed + JsVar *funcVar = 0; + if (JSP_SHOULD_EXECUTE) + funcVar = jsvNewWithFlags(JSV_FUNCTION); + // Get arguments save them to the structure + if (!jspeFunctionArguments(funcVar)) { + jsvUnLock(funcVar); + // parse failed + return 0; + } + // Get the code - first parse it so we know where it stops + JslCharPos funcBegin = execInfo.lex->tokenStart; + JSP_SAVE_EXECUTE(); + jspSetNoExecute(); + jsvUnLock(jspeBlock()); + JSP_RESTORE_EXECUTE(); + // Then create var and set + if (JSP_SHOULD_EXECUTE) { + // code var + JsVar *funcCodeVar = jsvNewFromLexer(execInfo.lex, funcBegin, (JslCharPos)(execInfo.lex->tokenLastEnd+1)); + jsvUnLock(jsvAddNamedChild(funcVar, funcCodeVar, JSPARSE_FUNCTION_CODE_NAME)); + jsvUnLock(funcCodeVar); + // scope var + JsVar *funcScopeVar = jspeiGetScopesAsVar(); + if (funcScopeVar) { + jsvUnLock(jsvAddNamedChild(funcVar, funcScopeVar, JSPARSE_FUNCTION_SCOPE_NAME)); + jsvUnLock(funcScopeVar); + } + } + return funcVar; +} + +/* Parse just the brackets of a function - and throw + * everything away */ +bool jspeParseFunctionCallBrackets() { + JSP_MATCH('('); + while (!JSP_HAS_ERROR && execInfo.lex->tk != ')') { + jsvUnLock(jspeBase()); + if (execInfo.lex->tk!=')') JSP_MATCH(','); + } + if (!JSP_HAS_ERROR) JSP_MATCH(')'); + return 0; +} + +/** Handle a function call (assumes we've parsed the function name and we're + * on the start bracket). 'thisArg' is the value of the 'this' variable when the + * function is executed (it's usually the parent object) + * + * If !isParsing and arg0!=0, argument 0 is set to what is supplied (same with arg1) + * + * functionName is used only for error reporting - and can be 0 + */ +JsVar *jspeFunctionCall(JsVar *function, JsVar *functionName, JsVar *thisArg, bool isParsing, int argCount, JsVar **argPtr) { + if (JSP_SHOULD_EXECUTE && !function) { + jsErrorAt("Function not found! Skipping.", execInfo.lex, execInfo.lex->tokenLastStart ); + jspSetError(); + } + + if (JSP_SHOULD_EXECUTE) jspCheckStackPosition(); // try and ensure that we won't overflow our stack + + if (JSP_SHOULD_EXECUTE && function) { + JsVar *functionRoot; + JsVar *functionCode = 0; + JsVar *returnVarName; + JsVar *returnVar; + JsVarRef v; + if (!jsvIsFunction(function)) { + char buf[JS_ERROR_BUF_SIZE]; + strncpy(buf, "Expecting a function to call", JS_ERROR_BUF_SIZE); + const char *name = jswGetBasicObjectName(function); + if (name) { + strncat(buf, ", got a ", JS_ERROR_BUF_SIZE); + strncat(buf, name, JS_ERROR_BUF_SIZE); + } + jsErrorAt(buf, execInfo.lex, execInfo.lex->tokenLastStart ); + jspSetError(); + return 0; + } + + /** Special case - we're parsing and we hit an already-defined function + * that has no 'code'. This means that we should use jswHandleFunctionCall + * to try and parse it */ + if (!jsvIsNative(function)) { + functionCode = jsvFindChildFromString(function, JSPARSE_FUNCTION_CODE_NAME, false); + if (isParsing && !functionCode) { + char buf[32]; + jsvGetString(functionName, buf, sizeof(buf)); + JslCharPos pos = execInfo.lex->tokenStart; + jslSeekTo(execInfo.lex, execInfo.lex->tokenLastStart); // NASTY! because jswHandleFunctionCall expects to parse IDs + JsVar *res = jswHandleFunctionCall(0, 0, buf); + // but we didn't find anything - so just carry on... + if (res!=JSW_HANDLEFUNCTIONCALL_UNHANDLED) + return res; + jslSeekTo(execInfo.lex, pos); // NASTY! + } + } + + if (isParsing) JSP_MATCH('('); + // create a new symbol table entry for execution of this function + // OPT: can we cache this function execution environment + param variables? + // OPT: Probably when calling a function ONCE, use it, otherwise when recursing, make new? + functionRoot = jsvNewWithFlags(JSV_FUNCTION); + if (!functionRoot) { // out of memory + jspSetError(); + return 0; + } + JsVar *oldThisVar = execInfo.thisVar; + execInfo.thisVar = thisArg; + if (isParsing) { + int hadParams = 0; + // grab in all parameters. We go around this loop until we've run out + // of named parameters AND we've parsed all the supplied arguments + v = function->firstChild; + while (!JSP_HAS_ERROR && (v || execInfo.lex->tk!=')')) { + JsVar *param = 0; + if (v) param = jsvLock(v); + bool paramDefined = jsvIsFunctionParameter(param); + if (execInfo.lex->tk!=')' || paramDefined) { + hadParams++; + JsVar *value = 0; + // ONLY parse this if it was supplied, otherwise leave 0 (undefined) + if (execInfo.lex->tk!=')') + value = jspeBase(); + // and if execute, copy it over + if (JSP_SHOULD_EXECUTE) { + value = jsvSkipNameAndUnLock(value); + JsVar *paramName = paramDefined ? jsvCopy(param) : jsvNewFromEmptyString(); + paramName->flags |= JSV_FUNCTION_PARAMETER; // force this to be called a function parameter + JsVar *newValueName = jsvMakeIntoVariableName(paramName, value); + if (newValueName) { // could be out of memory + jsvAddName(functionRoot, newValueName); + } else + jspSetError(); + jsvUnLock(newValueName); + } + jsvUnLock(value); + if (execInfo.lex->tk!=')') JSP_MATCH(','); + } + if (param) { + v = param->nextSibling; + jsvUnLock(param); + } + } + JSP_MATCH(')'); + } else if (JSP_SHOULD_EXECUTE && argCount>0) { // and NOT isParsing + int args = 0; + v = function->firstChild; + while (argsflags |= JSV_FUNCTION_PARAMETER; // force this to be called a function parameter + JsVar *newValueName = jsvMakeIntoVariableName(paramName, argPtr[args]); + if (newValueName) // could be out of memory - or maybe just not supplied! + jsvAddName(functionRoot, newValueName); + jsvUnLock(newValueName); + args++; + if (param) { + v = param->nextSibling; + jsvUnLock(param); + } + } + } + // setup a return variable + returnVarName = jsvAddNamedChild(functionRoot, 0, JSPARSE_RETURN_VAR); + if (!returnVarName) // out of memory + jspSetError(); + //jsvTrace(jsvGetRef(functionRoot), 5); // debugging + + if (!JSP_HAS_ERROR) { + if (jsvIsNative(function)) { + assert(function->varData.callback); + if (function->varData.callback) + function->varData.callback(jsvGetRef(functionRoot)); + } else { + // save old scopes + JsVarRef oldScopes[JSPARSE_MAX_SCOPES]; + int oldScopeCount; + int i; + oldScopeCount = execInfo.scopeCount; + for (i=0;ifirstChild); + //jsvTrace(jsvGetRef(functionScopeVar),5); + jspeiLoadScopesFromVar(functionScopeVar); + jsvUnLock(functionScopeVar); + jsvUnLock(functionScope); + } else { + // no scope var defined? We have no scopes at all! + execInfo.scopeCount = 0; + } + // add the function's execute space to the symbol table so we can recurse + if (jspeiAddScope(jsvGetRef(functionRoot))) { + /* Adding scope may have failed - we may have descended too deep - so be sure + * not to pull somebody else's scope off + */ + + /* we just want to execute the block, but something could + * have messed up and left us with the wrong ScriptLex, so + * we want to be careful here... */ + if (functionCode) { + JsLex *oldLex; + JsVar* functionCodeVar = jsvSkipNameAndUnLock(functionCode); + JsLex newLex; + jslInit(&newLex, functionCodeVar); + jsvUnLock(functionCodeVar); + + oldLex = execInfo.lex; + execInfo.lex = &newLex; + JSP_SAVE_EXECUTE(); + jspeBlock(); + bool hasError = JSP_HAS_ERROR; + JSP_RESTORE_EXECUTE(); // because return will probably have set execute to false + jslKill(&newLex); + execInfo.lex = oldLex; + if (hasError) { + jsiConsolePrint("in function "); + if (jsvIsString(functionName)) { + jsiConsolePrint("\""); + jsiConsolePrintStringVar(functionName); + jsiConsolePrint("\" "); + } + jsiConsolePrint("called from "); + if (execInfo.lex) + jsiConsolePrintPosition(execInfo.lex, execInfo.lex->tokenLastEnd); + else + jsiConsolePrint("system\n"); + jspSetError(); + } + } + + jspeiRemoveScope(); + } + + // Unref old scopes + for (i=0;iroot, obj, tokenName); + jsvUnLock(obj); + } + } else { + a = jswHandleFunctionCall(0, 0, tokenName); + if (a != JSW_HANDLEFUNCTIONCALL_UNHANDLED) + return a; + /* Variable doesn't exist! JavaScript says we should create it + * (we won't add it here. This is done in the assignment operator)*/ + a = jsvMakeIntoVariableName(jslGetTokenValueAsVar(execInfo.lex), 0); + } + } + JSP_MATCH_WITH_RETURN(LEX_ID, a); + + return a; +} + +JsVar *jspeFactorMember(JsVar *a, JsVar **parentResult) { + /* The parent if we're executing a method call */ + JsVar *parent = 0; + + while (execInfo.lex->tk=='.' || execInfo.lex->tk=='[') { + if (execInfo.lex->tk == '.') { // ------------------------------------- Record Access + JSP_MATCH('.'); + if (JSP_SHOULD_EXECUTE) { + // Note: name will go away when we oarse something else! + const char *name = jslGetTokenValueAsString(execInfo.lex); + + JsVar *aVar = jsvSkipName(a); + JsVar *child = 0; + if (aVar && jswGetBasicObjectName(aVar)) { + // if we're an object (or pretending to be one) + if (jsvHasChildren(aVar)) + child = jsvFindChildFromString(aVar, name, false); + + if (!child) + child = jspeiFindChildFromStringInParents(aVar, name); + + + if (child) { + // it was found - no need for name ptr now, so match! + JSP_MATCH_WITH_CLEANUP_AND_RETURN(LEX_ID, jsvUnLock(parent);jsvUnLock(a);, child); + } else { // NOT FOUND... + /* Check for builtins via separate function + * This way we save on RAM for built-ins because all comes out of program code. + * + * We don't check for prototype vars, so people can overload the built + * in functions (eg. Person.prototype.toString). HOWEVER if we did + * this for 'this' then we couldn't say 'this.toString()' + * */ + if (!jsvIsString(a) || (!jsvIsStringEqual(a, JSPARSE_PROTOTYPE_VAR))) // don't try and use builtins on the prototype var! + child = jswHandleFunctionCall(aVar, a/*name*/, name); + else + child = JSW_HANDLEFUNCTIONCALL_UNHANDLED; + if (child == JSW_HANDLEFUNCTIONCALL_UNHANDLED) { + child = 0; + // It wasn't handled... We already know this is an object so just add a new child + if (jsvIsObject(aVar) || jsvIsFunction(aVar) || jsvIsArray(aVar)) { + JsVar *value = 0; + if (jsvIsFunction(aVar) && strcmp(name, JSPARSE_PROTOTYPE_VAR)==0) + value = jsvNewWithFlags(JSV_OBJECT); // prototype is supposed to be an object + child = jsvAddNamedChild(aVar, value, name); + jsvUnLock(value); + } else { + // could have been a string... + jsErrorAt("Field or method does not already exist, and can't create it on a non-object", execInfo.lex, execInfo.lex->tokenLastEnd); + jspSetError(); + } + JSP_MATCH_WITH_CLEANUP_AND_RETURN(LEX_ID, jsvUnLock(parent);jsvUnLock(a);, child); + } + } + } else { + jsErrorAt("Using '.' operator on non-object", execInfo.lex, execInfo.lex->tokenLastEnd); + jspSetError(); + JSP_MATCH_WITH_CLEANUP_AND_RETURN(LEX_ID, jsvUnLock(parent);jsvUnLock(a);, child); + } + jsvUnLock(parent); + parent = aVar; + jsvUnLock(a); + a = child; + } else { + // Not executing, just match + JSP_MATCH_WITH_RETURN(LEX_ID, a); + } + } else if (execInfo.lex->tk == '[') { // ------------------------------------- Array Access + JsVar *index; + JSP_MATCH('['); + index = jspeBase(); + JSP_MATCH_WITH_CLEANUP_AND_RETURN(']', jsvUnLock(parent);jsvUnLock(index);, a); + if (JSP_SHOULD_EXECUTE) { + /* Index filtering (bug #19) - if we have an array index A that is: + is_string(A) && int_to_string(string_to_int(A)) = =A + then convert it to an integer. Should be too nasty for performance + as we only do this when accessing an array with a string */ + if (jsvIsString(index) && jsvIsStringNumericStrict(index)) { + JsVar *v = jsvNewFromInteger(jsvGetInteger(index)); + jsvUnLock(index); + index = v; + } + + JsVar *aVar = jsvSkipName(a); + if (aVar && (jsvIsArrayBuffer(aVar))) { + // for array buffers, we actually create a NAME, and hand that back - then when we assign (or use SkipName) we pull out the correct data + JsVar *indexValue = jsvSkipName(index); + jsvUnLock(a); + a = jsvMakeIntoVariableName(jsvNewFromInteger(jsvGetInteger(indexValue)), aVar); + jsvUnLock(indexValue); + if (a) // turn into an 'array buffer name' + a->flags = (a->flags & ~(JSV_NAME|JSV_VARTYPEMASK)) | JSV_ARRAYBUFFERNAME; + } else if (aVar && (jsvIsArray(aVar) || jsvIsObject(aVar) || jsvIsFunction(aVar))) { + // TODO: If we set to undefined, maybe we should remove the name? + JsVar *indexValue = jsvSkipName(index); + if (!jsvIsString(indexValue) && !jsvIsNumeric(indexValue)) + indexValue = jsvAsString(indexValue, true); + JsVar *child = jsvFindChildFromVar(aVar, indexValue, true); + jsvUnLock(indexValue); + + jsvUnLock(parent); + parent = jsvLockAgain(aVar); + jsvUnLock(a); + a = child; + } else if (aVar && (jsvIsString(aVar))) { + JsVarInt idx = jsvGetIntegerAndUnLock(jsvSkipName(index)); + JsVar *child = 0; + if (idx>=0 && idx<(JsVarInt)jsvGetStringLength(aVar)) { + char ch = jsvGetCharInString(aVar, (int)idx); + child = jsvNewFromEmptyString(); + if (child) jsvAppendStringBuf(child, &ch, 1); + } + jsvUnLock(parent); + parent = jsvLockAgain(aVar); + jsvUnLock(a); + a = child; + } else { + jsWarnAt("Variable is not an Array or Object", execInfo.lex, execInfo.lex->tokenLastEnd); + jsvUnLock(parent); + parent = 0; + jsvUnLock(a); + a = 0; + } + jsvUnLock(aVar); + } + jsvUnLock(index); + } else { + assert(0); + } + } + + if (parentResult) *parentResult = parent; + else jsvUnLock(parent); + return a; +} + +JsVar *jspeFactor(); +void jspEnsureIsPrototype(JsVar *prototypeName); + +JsVar *jspeConstruct(JsVar *func, JsVar *funcName, bool hasArgs) { + assert(JSP_SHOULD_EXECUTE); + if (!jsvIsFunction(func)) { + jsErrorAt("Constructor should be a function", execInfo.lex, execInfo.lex->tokenLastEnd); + jspSetError(); + return 0; + } + + JsVar *thisObj = jsvNewWithFlags(JSV_OBJECT); + // Make sure the function has a 'prototype' var + JsVar *prototypeName = jsvFindChildFromString(func, JSPARSE_PROTOTYPE_VAR, true); + jspEnsureIsPrototype(prototypeName); // make sure it's an object + jsvUnLock(jsvAddNamedChild(thisObj, prototypeName, JSPARSE_INHERITS_VAR)); + jsvUnLock(prototypeName); + + JsVar *a = jspeFunctionCall(func, funcName, thisObj, hasArgs, 0, 0); + + if (a) { + jsvUnLock(thisObj); + thisObj = a; + } else { + jsvUnLock(a); + JsVar *constructor = jsvFindChildFromString(thisObj, JSPARSE_CONSTRUCTOR_VAR, true); + if (constructor) { + jsvSetValueOfName(constructor, funcName); + jsvUnLock(constructor); + } + } + return thisObj; +} + +JsVar *jspeFactorFunctionCall() { + /* The parent if we're executing a method call */ + bool isConstructor = false; + if (execInfo.lex->tk==LEX_R_NEW) { + JSP_MATCH(LEX_R_NEW); + isConstructor = true; + + if (execInfo.lex->tk==LEX_R_NEW) { + jsError("Nesting 'new' operators is unsupported"); + jspSetError(); + return 0; + } + } + + JsVar *parent = 0; + JsVar *a = jspeFactorMember(jspeFactor(), &parent); + + while (execInfo.lex->tk=='(' || (isConstructor && JSP_SHOULD_EXECUTE)) { + JsVar *funcName = a; + JsVar *func = jsvSkipName(funcName); + + /* The constructor function doesn't change parsing, so if we're + * not executing, just short-cut it. */ + if (isConstructor && JSP_SHOULD_EXECUTE) { + // If we have '(' parse an argument list, otherwise don't look for any args + bool parseArgs = execInfo.lex->tk=='('; + a = jspeConstruct(func, funcName, parseArgs); + isConstructor = false; // don't treat subsequent brackets as constructors + } else + a = jspeFunctionCall(func, funcName, parent, true, 0, 0); + + jsvUnLock(funcName); + jsvUnLock(func); + + jsvUnLock(parent); parent=0; + a = jspeFactorMember(a, &parent); + } + + jsvUnLock(parent); + return a; +} + +JsVar *jspeFactorId() { + return jspeFactorSingleId(); +} + + +JsVar *jspeFactorObject() { + if (JSP_SHOULD_EXECUTE) { + JsVar *contents = jsvNewWithFlags(JSV_OBJECT); + if (!contents) { // out of memory + jspSetError(); + return 0; + } + /* JSON-style object definition */ + JSP_MATCH_WITH_RETURN('{', contents); + while (!JSP_HAS_ERROR && execInfo.lex->tk != '}') { + JsVar *varName = 0; + if (JSP_SHOULD_EXECUTE) { + varName = jslGetTokenValueAsVar(execInfo.lex); + if (!varName) { // out of memory + return contents; + } + } + // we only allow strings or IDs on the left hand side of an initialisation + if (execInfo.lex->tk==LEX_STR) { + JSP_MATCH_WITH_CLEANUP_AND_RETURN(LEX_STR, jsvUnLock(varName), contents); + } else { + JSP_MATCH_WITH_CLEANUP_AND_RETURN(LEX_ID, jsvUnLock(varName), contents); + } + JSP_MATCH_WITH_CLEANUP_AND_RETURN(':', jsvUnLock(varName), contents); + if (JSP_SHOULD_EXECUTE) { + JsVar *valueVar; + JsVar *value = jspeBase(); // value can be 0 (could be undefined!) + valueVar = jsvSkipNameAndUnLock(value); + varName = jsvMakeIntoVariableName(varName, valueVar); + jsvAddName(contents, varName); + jsvUnLock(valueVar); + } + jsvUnLock(varName); + // no need to clean here, as it will definitely be used + if (execInfo.lex->tk != '}') JSP_MATCH_WITH_RETURN(',', contents); + } + JSP_MATCH_WITH_RETURN('}', contents); + return contents; + } else { + // Not executing so do fast skip + return jspeBlock(); + } +} + +JsVar *jspeFactorArray() { + int idx = 0; + JsVar *contents = 0; + if (JSP_SHOULD_EXECUTE) { + contents = jsvNewWithFlags(JSV_ARRAY); + if (!contents) { // out of memory + jspSetError(); + return 0; + } + } + /* JSON-style array */ + JSP_MATCH_WITH_RETURN('[', contents); + while (!JSP_HAS_ERROR && execInfo.lex->tk != ']') { + if (JSP_SHOULD_EXECUTE) { + // OPT: Store array indices as actual ints + JsVar *a; + JsVar *aVar; + JsVar *indexName; + a = jspeBase(); + aVar = jsvSkipNameAndUnLock(a); + indexName = jsvMakeIntoVariableName(jsvNewFromInteger(idx), aVar); + if (indexName) { // could be out of memory + jsvAddName(contents, indexName); + jsvUnLock(indexName); + } + jsvUnLock(aVar); + } else { + jsvUnLock(jspeBase()); + } + // no need to clean here, as it will definitely be used + if (execInfo.lex->tk != ']') JSP_MATCH_WITH_RETURN(',', contents); + idx++; + } + JSP_MATCH_WITH_RETURN(']', contents); + return contents; +} + +void jspEnsureIsPrototype(JsVar *prototypeName) { + if (!prototypeName) return; + JsVar *prototypeVar = jsvSkipName(prototypeName); + if (!jsvIsObject(prototypeVar)) { + if (!jsvIsUndefined(prototypeVar)) + jsWarn("Prototype is not an Object, so setting it to {}"); + jsvUnLock(prototypeVar); + prototypeVar = jsvNewWithFlags(JSV_OBJECT); // prototype is supposed to be an object + JsVar *lastName = jsvSkipToLastName(prototypeName); + jsvSetValueOfName(lastName, prototypeVar); + jsvUnLock(lastName); + } + jsvUnLock(prototypeVar); +} + +JsVar *jspeFactorTypeOf() { + JSP_MATCH(LEX_R_TYPEOF); + JsVar *a = jspeBase(); + JsVar *result = 0; + if (JSP_SHOULD_EXECUTE) { + a = jsvSkipNameAndUnLock(a); + result=jsvNewFromString(jsvGetTypeOf(a)); + } + jsvUnLock(a); + return result; +} + +JsVar *jspeFactor() { + if (execInfo.lex->tk=='(') { + JsVar *a = 0; + JSP_MATCH('('); + if (jspCheckStackPosition()) + a = jspeBaseWithComma(); + if (!JSP_HAS_ERROR) JSP_MATCH_WITH_RETURN(')',a); + return a; + } else if (execInfo.lex->tk==LEX_R_TRUE) { + JSP_MATCH(LEX_R_TRUE); + return JSP_SHOULD_EXECUTE ? jsvNewFromBool(true) : 0; + } else if (execInfo.lex->tk==LEX_R_FALSE) { + JSP_MATCH(LEX_R_FALSE); + return JSP_SHOULD_EXECUTE ? jsvNewFromBool(false) : 0; + } else if (execInfo.lex->tk==LEX_R_NULL) { + JSP_MATCH(LEX_R_NULL); + return JSP_SHOULD_EXECUTE ? jsvNewWithFlags(JSV_NULL) : 0; + } else if (execInfo.lex->tk==LEX_R_UNDEFINED) { + JSP_MATCH(LEX_R_UNDEFINED); + return 0; + } else if (execInfo.lex->tk==LEX_ID) { + return jspeFactorId(); + } else if (execInfo.lex->tk==LEX_INT) { + // atol works only on decimals + // strtol handles 0x12345 as well + //JsVarInt v = (JsVarInt)atol(jslGetTokenValueAsString(execInfo.lex)); + //JsVarInt v = (JsVarInt)strtol(jslGetTokenValueAsString(execInfo.lex),0,0); // broken on PIC + if (JSP_SHOULD_EXECUTE) { + JsVarInt v = stringToInt(jslGetTokenValueAsString(execInfo.lex)); + JSP_MATCH(LEX_INT); + return jsvNewFromInteger(v); + } else { + JSP_MATCH(LEX_INT); + return 0; + } + } else if (execInfo.lex->tk==LEX_FLOAT) { + if (JSP_SHOULD_EXECUTE) { + JsVarFloat v = stringToFloat(jslGetTokenValueAsString(execInfo.lex)); + JSP_MATCH(LEX_FLOAT); + return jsvNewFromFloat(v); + } else { + JSP_MATCH(LEX_FLOAT); + return 0; + } + } else if (execInfo.lex->tk==LEX_STR) { + if (JSP_SHOULD_EXECUTE) { + JsVar *a = jslGetTokenValueAsVar(execInfo.lex); + JSP_MATCH_WITH_RETURN(LEX_STR, a); + return a; + } else { + JSP_MATCH(LEX_STR); + return 0; + } + } else if (execInfo.lex->tk=='{') { + return jspeFactorObject(); + } else if (execInfo.lex->tk=='[') { + return jspeFactorArray(); + } else if (execInfo.lex->tk==LEX_R_FUNCTION) { + JSP_MATCH(LEX_R_FUNCTION); + return jspeFunctionDefinition(); + } else if (execInfo.lex->tk==LEX_R_THIS) { + JSP_MATCH(LEX_R_THIS); + return jsvLockAgain( execInfo.thisVar ? execInfo.thisVar : execInfo.parse->root ); + } else if (execInfo.lex->tk==LEX_R_TYPEOF) { + return jspeFactorTypeOf(); + } else if (execInfo.lex->tk==LEX_R_VOID) { + JSP_MATCH(LEX_R_VOID); + jsvUnLock(jspeFactor()); + return 0; + } + // Nothing we can do here... just hope it's the end... + JSP_MATCH(LEX_EOF); + return 0; +} + +__attribute((noinline)) JsVar *__jspePostfix(JsVar *a) { + while (execInfo.lex->tk==LEX_PLUSPLUS || execInfo.lex->tk==LEX_MINUSMINUS) { + int op = execInfo.lex->tk; + JSP_MATCH(execInfo.lex->tk); + if (JSP_SHOULD_EXECUTE) { + JsVar *one = jsvNewFromInteger(1); + JsVar *res = jsvMathsOpSkipNames(a, one, op==LEX_PLUSPLUS ? '+' : '-'); + JsVar *oldValue; + jsvUnLock(one); + oldValue = jsvSkipName(a); // keep the old value + // in-place add/subtract + jspReplaceWith(a, res); + jsvUnLock(res); + // but then use the old value + jsvUnLock(a); + a = oldValue; + } + } + return a; +} + +JsVar *jspePostfix() { + JsVar *a; + if (execInfo.lex->tk==LEX_PLUSPLUS || execInfo.lex->tk==LEX_MINUSMINUS) { + int op = execInfo.lex->tk; + JSP_MATCH(execInfo.lex->tk); + a = jspePostfix(); + if (JSP_SHOULD_EXECUTE) { + JsVar *one = jsvNewFromInteger(1); + JsVar *res = jsvMathsOpSkipNames(a, one, op==LEX_PLUSPLUS ? '+' : '-'); + jsvUnLock(one); + // in-place add/subtract + jspReplaceWith(a, res); + jsvUnLock(res); + } + } else + a = jspeFactorFunctionCall(); + return __jspePostfix(a); +} + +JsVar *jspeUnary() { + if (execInfo.lex->tk=='!' || execInfo.lex->tk=='~' || execInfo.lex->tk=='-' || execInfo.lex->tk=='+') { + short tk = execInfo.lex->tk; + JSP_MATCH(execInfo.lex->tk); + if (!JSP_SHOULD_EXECUTE) { + return jspePostfix(); + } + if (tk=='!') { // logical not + return jsvNewFromBool(!jsvGetBoolAndUnLock(jsvSkipNameAndUnLock(jspeUnary()))); + } else if (tk=='~') { // bitwise not + return jsvNewFromInteger(~jsvGetIntegerAndUnLock(jsvSkipNameAndUnLock(jspeUnary()))); + } else if (tk=='-') { // unary minus + return jsvNegateAndUnLock(jspeUnary()); // names already skipped + } else if (tk=='+') { // unary plus (convert to number) + return jsvAsNumber(jspeUnary()); // names already skipped + } + assert(0); + return 0; + } else + return jspePostfix(); +} + +__attribute((noinline)) JsVar *__jspeTerm(JsVar *a) { + while (execInfo.lex->tk=='*' || execInfo.lex->tk=='/' || execInfo.lex->tk=='%') { + JsVar *b; + int op = execInfo.lex->tk; + JSP_MATCH(execInfo.lex->tk); + b = jspeUnary(); + if (JSP_SHOULD_EXECUTE) { + JsVar *res = jsvMathsOpSkipNames(a, b, op); + jsvUnLock(a); a = res; + } + jsvUnLock(b); + } + return a; +} + +JsVar *jspeTerm() { + return __jspeTerm(jspeUnary()); +} + +__attribute((noinline)) JsVar *__jspeExpression(JsVar *a) { + while (execInfo.lex->tk=='+' || execInfo.lex->tk=='-') { + int op = execInfo.lex->tk; + JSP_MATCH(execInfo.lex->tk); + JsVar *b = jspeTerm(); + if (JSP_SHOULD_EXECUTE) { + // not in-place, so just replace + JsVar *res = jsvMathsOpSkipNames(a, b, op); + jsvUnLock(a); a = res; + } + jsvUnLock(b); + } + return a; +} + + +JsVar *jspeExpression() { + return __jspeExpression(jspeTerm()); +} + +__attribute((noinline)) JsVar *__jspeShift(JsVar *a) { + if (execInfo.lex->tk==LEX_LSHIFT || execInfo.lex->tk==LEX_RSHIFT || execInfo.lex->tk==LEX_RSHIFTUNSIGNED) { + JsVar *b; + int op = execInfo.lex->tk; + JSP_MATCH(op); + b = jspeExpression(); + if (JSP_SHOULD_EXECUTE) { + JsVar *res = jsvMathsOpSkipNames(a, b, op); + jsvUnLock(a); a = res; + } + jsvUnLock(b); + } + return a; +} + +JsVar *jspeShift() { + return __jspeShift(jspeExpression()); +} + +__attribute((noinline)) JsVar *__jspeCondition(JsVar *a) { + JsVar *b; + while (execInfo.lex->tk==LEX_EQUAL || execInfo.lex->tk==LEX_NEQUAL || + execInfo.lex->tk==LEX_TYPEEQUAL || execInfo.lex->tk==LEX_NTYPEEQUAL || + execInfo.lex->tk==LEX_LEQUAL || execInfo.lex->tk==LEX_GEQUAL || + execInfo.lex->tk=='<' || execInfo.lex->tk=='>' || + execInfo.lex->tk==LEX_R_INSTANCEOF || + (execInfo.lex->tk==LEX_R_IN && !(execInfo.execute&EXEC_FOR_INIT))) { + int op = execInfo.lex->tk; + JSP_MATCH(execInfo.lex->tk); + b = jspeShift(); + if (JSP_SHOULD_EXECUTE) { + JsVar *res = 0; + if (op==LEX_R_IN) { + JsVar *av = jsvSkipName(a); + JsVar *bv = jsvSkipName(b); + if (jsvIsArray(bv) || jsvIsObject(bv)) { + JsVar *varFound = jsvGetArrayIndexOf(bv, av, false/*not exact*/); // ArrayIndexOf will return 0 if not found + res = jsvNewFromBool(varFound!=0); + jsvUnLock(varFound); + } // else it will be undefined + jsvUnLock(av); + jsvUnLock(bv); + } else if (op==LEX_R_INSTANCEOF) { + bool inst = false; + JsVar *av = jsvSkipName(a); + JsVar *bv = jsvSkipName(b); + if (!jsvIsFunction(bv)) { + jsErrorAt("Expecting a function on RHS in instanceof check", execInfo.lex, execInfo.lex->tokenLastEnd); + jspSetError(); + } else { + if (jsvIsObject(av)) { + JsVar *constructor = jsvObjectGetChild(av, JSPARSE_CONSTRUCTOR_VAR, 0); + if (constructor==bv) inst=true; + else inst = jspIsConstructor(bv,"Object"); + jsvUnLock(constructor); + } else { + const char *name = jswGetBasicObjectName(av); + if (name) { + inst = jspIsConstructor(bv, name); + } + } + } + jsvUnLock(av); + jsvUnLock(bv); + res = jsvNewFromBool(inst); + } else { + res = jsvMathsOpSkipNames(a, b, op); + + } + jsvUnLock(a); a = res; + } + jsvUnLock(b); + } + return a; +} + +JsVar *jspeCondition() { + return __jspeCondition(jspeShift()); +} + +__attribute((noinline)) JsVar *__jspeLogic(JsVar *a) { + JsVar *b = 0; + while (execInfo.lex->tk=='&' || execInfo.lex->tk=='|' || execInfo.lex->tk=='^' || execInfo.lex->tk==LEX_ANDAND || execInfo.lex->tk==LEX_OROR) { + bool shortCircuit = false; + bool boolean = false; + int op = execInfo.lex->tk; + JSP_MATCH(execInfo.lex->tk); + + // if we have short-circuit ops, then if we know the outcome + // we don't bother to execute the other op. Even if not + // we need to tell mathsOp it's an & or | + if (op==LEX_ANDAND) { + op = '&'; + shortCircuit = !jsvGetBoolAndUnLock(jsvSkipName(a)); + boolean = true; + } else if (op==LEX_OROR) { + op = '|'; + shortCircuit = jsvGetBoolAndUnLock(jsvSkipName(a)); + boolean = true; + } + + JSP_SAVE_EXECUTE(); + if (shortCircuit) jspSetNoExecute(); + b = jspeCondition(); + if (shortCircuit) JSP_RESTORE_EXECUTE(); + if (JSP_SHOULD_EXECUTE && !shortCircuit) { + JsVar *res; + if (boolean) { + JsVar *newa = jsvNewFromBool(jsvGetBoolAndUnLock(jsvSkipName(a))); + JsVar *newb = jsvNewFromBool(jsvGetBoolAndUnLock(jsvSkipName(b))); + jsvUnLock(a); a = newa; + jsvUnLock(b); b = newb; + } + res = jsvMathsOpSkipNames(a, b, op); + jsvUnLock(a); a = res; + } + jsvUnLock(b); + } + return a; +} + +JsVar *jspeLogic() { + return __jspeLogic(jspeCondition()); +} + +__attribute((noinline)) JsVar *__jspeTernary(JsVar *lhs) { + if (execInfo.lex->tk=='?') { + JSP_MATCH('?'); + if (!JSP_SHOULD_EXECUTE) { + // just let lhs pass through + jsvUnLock(jspeBase()); + JSP_MATCH(':'); + jsvUnLock(jspeBase()); + } else { + bool first = jsvGetBoolAndUnLock(jsvSkipName(lhs)); + jsvUnLock(lhs); + if (first) { + lhs = jspeBase(); + JSP_MATCH(':'); + JSP_SAVE_EXECUTE(); + jspSetNoExecute(); + jsvUnLock(jspeBase()); + JSP_RESTORE_EXECUTE(); + } else { + JSP_SAVE_EXECUTE(); + jspSetNoExecute(); + jsvUnLock(jspeBase()); + JSP_RESTORE_EXECUTE(); + JSP_MATCH(':'); + lhs = jspeBase(); + } + } + } + + return lhs; +} + +JsVar *jspeTernary() { + return __jspeTernary(jspeLogic()); +} + +__attribute((noinline)) JsVar *__jspeBase(JsVar *lhs) { + if (execInfo.lex->tk=='=' || execInfo.lex->tk==LEX_PLUSEQUAL || execInfo.lex->tk==LEX_MINUSEQUAL || + execInfo.lex->tk==LEX_MULEQUAL || execInfo.lex->tk==LEX_DIVEQUAL || execInfo.lex->tk==LEX_MODEQUAL || + execInfo.lex->tk==LEX_ANDEQUAL || execInfo.lex->tk==LEX_OREQUAL || + execInfo.lex->tk==LEX_XOREQUAL || execInfo.lex->tk==LEX_RSHIFTEQUAL || + execInfo.lex->tk==LEX_LSHIFTEQUAL || execInfo.lex->tk==LEX_RSHIFTUNSIGNEDEQUAL) { + JsVar *rhs; + /* If we're assigning to this and we don't have a parent, + * add it to the symbol table root as per JavaScript. */ + if (JSP_SHOULD_EXECUTE && lhs && !lhs->refs) { + if (jsvIsName(lhs)/* && jsvGetStringLength(lhs)>0*/) { + if (!jsvIsArrayBufferName(lhs)) + jsvAddName(execInfo.parse->root, lhs); + } else // TODO: Why was this here? can it happen? + jsWarnAt("Trying to assign to an un-named type\n", execInfo.lex, execInfo.lex->tokenLastEnd); + } + + int op = execInfo.lex->tk; + JSP_MATCH(execInfo.lex->tk); + rhs = jspeBase(); + rhs = jsvSkipNameAndUnLock(rhs); // ensure we get rid of any references on the RHS + if (JSP_SHOULD_EXECUTE && lhs) { + if (op=='=') { + jspReplaceWith(lhs, rhs); + } else { + if (op==LEX_PLUSEQUAL) op='+'; + else if (op==LEX_MINUSEQUAL) op='-'; + else if (op==LEX_MULEQUAL) op='*'; + else if (op==LEX_DIVEQUAL) op='/'; + else if (op==LEX_MODEQUAL) op='%'; + else if (op==LEX_ANDEQUAL) op='&'; + else if (op==LEX_OREQUAL) op='|'; + else if (op==LEX_XOREQUAL) op='^'; + else if (op==LEX_RSHIFTEQUAL) op=LEX_RSHIFT; + else if (op==LEX_LSHIFTEQUAL) op=LEX_LSHIFT; + else if (op==LEX_RSHIFTUNSIGNEDEQUAL) op=LEX_RSHIFTUNSIGNED; + if (op=='+' && jsvIsName(lhs)) { + JsVar *currentValue = jsvSkipName(lhs); + if (jsvIsString(currentValue) && currentValue->refs==1) { + /* A special case for string += where this is the only use of the string, + * as we may be able to do a simple append (rather than clone + append)*/ + JsVar *str = jsvAsString(rhs, false); + jsvAppendStringVarComplete(currentValue, str); + jsvUnLock(str); + op = 0; + } + jsvUnLock(currentValue); + } + if (op) { + /* Fallback which does a proper add */ + JsVar *res = jsvMathsOpSkipNames(lhs,rhs,op); + jspReplaceWith(lhs, res); + jsvUnLock(res); + } + } + } + jsvUnLock(rhs); + } + return lhs; +} + + +JsVar *jspeBase() { + return __jspeBase(jspeTernary()); +} + +// jspeBase where ',' is allowed to add multiple expressions +JsVar *jspeBaseWithComma() { + while (!JSP_HAS_ERROR) { + JsVar *a = jspeBase(); + if (execInfo.lex->tk!=',') return a; + // if we get a comma, we just forget this data and parse the next bit... + jsvUnLock(a); + JSP_MATCH(','); + } + return 0; +} + +JsVar *jspeBlock() { + JSP_MATCH('{'); + if (JSP_SHOULD_EXECUTE) { + while (execInfo.lex->tk && execInfo.lex->tk!='}') { + jsvUnLock(jspeStatement()); + if (JSP_HAS_ERROR) { + if (execInfo.lex && !(execInfo.execute&EXEC_ERROR_LINE_REPORTED)) { + execInfo.execute = (JsExecFlags)(execInfo.execute | EXEC_ERROR_LINE_REPORTED); + jsiConsolePrint("at "); + jsiConsolePrintPosition(execInfo.lex, execInfo.lex->tokenLastEnd); + jsiConsolePrintTokenLineMarker(execInfo.lex, execInfo.lex->tokenLastEnd); + } + return 0; + } + } + JSP_MATCH('}'); + } else { + // fast skip of blocks + int brackets = 1; + while (execInfo.lex->tk && brackets) { + if (execInfo.lex->tk == '{') brackets++; + if (execInfo.lex->tk == '}') brackets--; + JSP_MATCH(execInfo.lex->tk); + } + } + return 0; +} + +JsVar *jspeBlockOrStatement() { + if (execInfo.lex->tk=='{') + return jspeBlock(); + else { + JsVar *v = jspeStatement(); + if (execInfo.lex->tk==';') JSP_MATCH(';'); + return v; + } +} + +JsVar *jspeStatementVar() { + JsVar *lastDefined = 0; + /* variable creation. TODO - we need a better way of parsing the left + * hand side. Maybe just have a flag called can_create_var that we + * set and then we parse as if we're doing a normal equals.*/ + JSP_MATCH(LEX_R_VAR); + bool hasComma = true; // for first time in loop + while (hasComma && execInfo.lex->tk == LEX_ID) { + JsVar *a = 0; + if (JSP_SHOULD_EXECUTE) { + a = jspeiFindOnTop(jslGetTokenValueAsString(execInfo.lex), true); + if (!a) { // out of memory + jspSetError(); + return lastDefined; + } + } + JSP_MATCH_WITH_CLEANUP_AND_RETURN(LEX_ID, jsvUnLock(a), lastDefined); + // now do stuff defined with dots + while (execInfo.lex->tk == '.') { + JSP_MATCH_WITH_CLEANUP_AND_RETURN('.', jsvUnLock(a), lastDefined); + if (JSP_SHOULD_EXECUTE) { + JsVar *lastA = a; + a = jsvFindChildFromString(lastA, jslGetTokenValueAsString(execInfo.lex), true); + jsvUnLock(lastA); + } + JSP_MATCH_WITH_CLEANUP_AND_RETURN(LEX_ID, jsvUnLock(a), lastDefined); + } + // sort out initialiser + if (execInfo.lex->tk == '=') { + JsVar *var; + JSP_MATCH_WITH_CLEANUP_AND_RETURN('=', jsvUnLock(a), lastDefined); + var = jsvSkipNameAndUnLock(jspeBase()); + if (JSP_SHOULD_EXECUTE) + jspReplaceWith(a, var); + jsvUnLock(var); + } + jsvUnLock(lastDefined); + lastDefined = a; + hasComma = execInfo.lex->tk == ','; + if (hasComma) JSP_MATCH_WITH_RETURN(',', lastDefined); + } + return lastDefined; +} + +JsVar *jspeStatementIf() { + bool cond; + JsVar *var; + JSP_MATCH(LEX_R_IF); + JSP_MATCH('('); + var = jspeBase(); + JSP_MATCH(')'); + cond = JSP_SHOULD_EXECUTE && jsvGetBoolAndUnLock(jsvSkipName(var)); + jsvUnLock(var); + + JSP_SAVE_EXECUTE(); + if (!cond) jspSetNoExecute(); + jsvUnLock(jspeBlockOrStatement()); + if (!cond) JSP_RESTORE_EXECUTE(); + if (execInfo.lex->tk==LEX_R_ELSE) { + //JSP_MATCH(';'); ??? + JSP_MATCH(LEX_R_ELSE); + JSP_SAVE_EXECUTE(); + if (cond) jspSetNoExecute(); + jsvUnLock(jspeBlockOrStatement()); + if (cond) JSP_RESTORE_EXECUTE(); + } + return 0; +} + +JsVar *jspeStatementSwitch() { + JSP_MATCH(LEX_R_SWITCH); + JSP_MATCH('('); + JsVar *switchOn = jspeBase(); + JSP_MATCH_WITH_CLEANUP_AND_RETURN(')', jsvUnLock(switchOn), 0); + JSP_MATCH_WITH_CLEANUP_AND_RETURN('{', jsvUnLock(switchOn), 0); + JSP_SAVE_EXECUTE(); + bool execute = JSP_SHOULD_EXECUTE; + bool hasExecuted = false; + if (execute) execInfo.execute=EXEC_NO|EXEC_IN_SWITCH; + while (execInfo.lex->tk==LEX_R_CASE) { + JSP_MATCH_WITH_CLEANUP_AND_RETURN(LEX_R_CASE, jsvUnLock(switchOn), 0); + JsExecFlags oldFlags = execInfo.execute; + if (execute) execInfo.execute=EXEC_YES|EXEC_IN_SWITCH; + JsVar *test = jspeBase(); + execInfo.execute = oldFlags|EXEC_IN_SWITCH;; + JSP_MATCH_WITH_CLEANUP_AND_RETURN(':', jsvUnLock(switchOn);jsvUnLock(test), 0); + bool cond = false; + if (execute) + cond = jsvGetBoolAndUnLock(jsvMathsOpSkipNames(switchOn, test, LEX_EQUAL)); + if (cond) hasExecuted = true; + jsvUnLock(test); + if (cond && (execInfo.execute&EXEC_RUN_MASK)==EXEC_NO) + execInfo.execute=EXEC_YES|EXEC_IN_SWITCH; + while (!JSP_HAS_ERROR && execInfo.lex->tk!=LEX_EOF && execInfo.lex->tk!=LEX_R_CASE && execInfo.lex->tk!=LEX_R_DEFAULT && execInfo.lex->tk!='}') + jsvUnLock(jspeBlockOrStatement()); + } + jsvUnLock(switchOn); + if (execute && (execInfo.execute&EXEC_RUN_MASK)==EXEC_BREAK) + execInfo.execute=EXEC_YES|EXEC_IN_SWITCH; + JSP_RESTORE_EXECUTE(); + + if (execInfo.lex->tk==LEX_R_DEFAULT) { + JSP_MATCH(LEX_R_DEFAULT); + JSP_MATCH(':'); + JSP_SAVE_EXECUTE(); + if (hasExecuted) jspSetNoExecute(); + while (!JSP_HAS_ERROR && execInfo.lex->tk!=LEX_EOF && execInfo.lex->tk!='}') + jsvUnLock(jspeBlockOrStatement()); + JSP_RESTORE_EXECUTE(); + } + JSP_MATCH('}'); + return 0; +} + +JsVar *jspeStatementWhile() { +#ifdef JSPARSE_MAX_LOOP_ITERATIONS + int loopCount = JSPARSE_MAX_LOOP_ITERATIONS; +#endif + JsVar *cond; + bool loopCond; + bool hasHadBreak = false; + // We do repetition by pulling out the string representing our statement + // there's definitely some opportunity for optimisation here + JSP_MATCH(LEX_R_WHILE); + JSP_MATCH('('); + JslCharPos whileCondStart = execInfo.lex->tokenStart; + cond = jspeBase(); + loopCond = JSP_SHOULD_EXECUTE && jsvGetBoolAndUnLock(jsvSkipName(cond)); + jsvUnLock(cond); + JSP_MATCH(')'); + JslCharPos whileBodyStart = execInfo.lex->tokenStart; + JSP_SAVE_EXECUTE(); + // actually try and execute first bit of while loop (we'll do the rest in the actual loop later) + if (!loopCond) jspSetNoExecute(); + execInfo.execute |= EXEC_IN_LOOP; + jsvUnLock(jspeBlockOrStatement()); + JslCharPos whileBodyEnd = execInfo.lex->tokenStart; + execInfo.execute &= (JsExecFlags)~EXEC_IN_LOOP; + if (execInfo.execute == EXEC_CONTINUE) + execInfo.execute = EXEC_YES; + if (execInfo.execute == EXEC_BREAK) { + execInfo.execute = EXEC_YES; + hasHadBreak = true; // fail loop condition, so we exit + } + if (!loopCond) JSP_RESTORE_EXECUTE(); + + while (!hasHadBreak && loopCond +#ifdef JSPARSE_MAX_LOOP_ITERATIONS + && loopCount-->0 +#endif + ) { + jslSeekTo(execInfo.lex, whileCondStart); + cond = jspeBase(); + loopCond = JSP_SHOULD_EXECUTE && jsvGetBoolAndUnLock(jsvSkipName(cond)); + jsvUnLock(cond); + if (loopCond) { + jslSeekTo(execInfo.lex, whileBodyStart); + execInfo.execute |= EXEC_IN_LOOP; + jsvUnLock(jspeBlockOrStatement()); + execInfo.execute &= (JsExecFlags)~EXEC_IN_LOOP; + if (execInfo.execute == EXEC_CONTINUE) + execInfo.execute = EXEC_YES; + if (execInfo.execute == EXEC_BREAK) { + execInfo.execute = EXEC_YES; + hasHadBreak = true; + } + } + } + jslSeekTo(execInfo.lex, whileBodyEnd); +#ifdef JSPARSE_MAX_LOOP_ITERATIONS + if (loopCount<=0) { + jsErrorAt("WHILE Loop exceeded the maximum number of iterations (" STRINGIFY(JSPARSE_MAX_LOOP_ITERATIONS) ")", execInfo.lex, execInfo.lex->tokenLastEnd); + jspSetError(); + } +#endif + return 0; +} + +JsVar *jspeStatementFor() { + JSP_MATCH(LEX_R_FOR); + JSP_MATCH('('); + execInfo.execute |= EXEC_FOR_INIT; + // initialisation + JsVar *forStatement = 0; + // we could have 'for (;;)' - so don't munch up our semicolon if that's all we have + if (execInfo.lex->tk != ';') + forStatement = jspeStatement(); + execInfo.execute &= (JsExecFlags)~EXEC_FOR_INIT; + if (execInfo.lex->tk == LEX_R_IN) { + // for (i in array) + // where i = jsvUnLock(forStatement); + if (!jsvIsName(forStatement)) { + jsvUnLock(forStatement); + jsErrorAt("FOR a IN b - 'a' must be a variable name", execInfo.lex, execInfo.lex->tokenLastEnd); + jspSetError(); + return 0; + } + bool addedIteratorToScope = false; + if (JSP_SHOULD_EXECUTE && !forStatement->refs) { + // if the variable did not exist, add it to the scope + addedIteratorToScope = true; + jsvAddName(execInfo.parse->root, forStatement); + } + JSP_MATCH_WITH_CLEANUP_AND_RETURN(LEX_R_IN, jsvUnLock(forStatement), 0); + JsVar *array = jsvSkipNameAndUnLock(jspeExpression()); + JSP_MATCH_WITH_CLEANUP_AND_RETURN(')', jsvUnLock(forStatement);jsvUnLock(array), 0); + JslCharPos forBodyStart = execInfo.lex->tokenStart; + JSP_SAVE_EXECUTE(); + jspSetNoExecute(); + execInfo.execute |= EXEC_IN_LOOP; + jsvUnLock(jspeBlockOrStatement()); + JslCharPos forBodyEnd = execInfo.lex->tokenStart; + execInfo.execute &= (JsExecFlags)~EXEC_IN_LOOP; + JSP_RESTORE_EXECUTE(); + + if (jsvIsIterable(array)) { + bool (*checkerFunction)(JsVar*) = 0; + if (jsvIsFunction(array)) checkerFunction = jsvIsInternalFunctionKey; + else if (jsvIsObject(array)) checkerFunction = jsvIsInternalObjectKey; + JsvIterator it; + jsvIteratorNew(&it, array); + bool hasHadBreak = false; + while (JSP_SHOULD_EXECUTE && jsvIteratorHasElement(&it) && !hasHadBreak) { + JsVar *loopIndexVar = jsvIteratorGetKey(&it); + bool ignore = false; + if (checkerFunction && checkerFunction(loopIndexVar)) + ignore = true; + if (!ignore) { + JsVar *indexValue = jsvIsName(loopIndexVar) ? + jsvCopyNameOnly(loopIndexVar, false/*no copy children*/, false/*not a name*/) : + loopIndexVar; + if (indexValue) { // could be out of memory + assert(!jsvIsName(indexValue) && indexValue->refs==0); + jsvSetValueOfName(forStatement, indexValue); + if (indexValue!=loopIndexVar) jsvUnLock(indexValue); + + jsvIteratorNext(&it); + + jslSeekTo(execInfo.lex, forBodyStart); + execInfo.execute |= EXEC_IN_LOOP; + jsvUnLock(jspeBlockOrStatement()); + execInfo.execute &= (JsExecFlags)~EXEC_IN_LOOP; + + if (execInfo.execute == EXEC_CONTINUE) + execInfo.execute = EXEC_YES; + if (execInfo.execute == EXEC_BREAK) { + execInfo.execute = EXEC_YES; + hasHadBreak = true; + } + } + } else + jsvIteratorNext(&it); + jsvUnLock(loopIndexVar); + } + jsvIteratorFree(&it); + } else { + jsErrorAt("FOR loop can only iterate over Arrays, Strings or Objects", execInfo.lex, execInfo.lex->tokenLastEnd); + jspSetError(); + } + + jslSeekTo(execInfo.lex, forBodyEnd); + + if (addedIteratorToScope) { + jsvRemoveChild(execInfo.parse->root, forStatement); + } + jsvUnLock(forStatement); + jsvUnLock(array); + } else { // NORMAL FOR LOOP +#ifdef JSPARSE_MAX_LOOP_ITERATIONS + int loopCount = JSPARSE_MAX_LOOP_ITERATIONS; +#endif + bool loopCond = true; + bool hasHadBreak = false; + + jsvUnLock(forStatement); + JSP_MATCH(';'); + JslCharPos forCondStart = execInfo.lex->tokenStart; + if (execInfo.lex->tk != ';') { + JsVar *cond = jspeBase(); // condition + loopCond = JSP_SHOULD_EXECUTE && jsvGetBoolAndUnLock(jsvSkipName(cond)); + jsvUnLock(cond); + } + JSP_MATCH(';'); + JslCharPos forIterStart = execInfo.lex->tokenStart; + if (execInfo.lex->tk != ')') { // we could have 'for (;;)' + JSP_SAVE_EXECUTE(); + jspSetNoExecute(); + jsvUnLock(jspeBase()); // iterator + JSP_RESTORE_EXECUTE(); + } + JSP_MATCH(')'); + + JslCharPos forBodyStart = execInfo.lex->tokenStart; // actual for body + JSP_SAVE_EXECUTE(); + if (!loopCond) jspSetNoExecute(); + execInfo.execute |= EXEC_IN_LOOP; + jsvUnLock(jspeBlockOrStatement()); + JslCharPos forBodyEnd = execInfo.lex->tokenStart; + execInfo.execute &= (JsExecFlags)~EXEC_IN_LOOP; + if (execInfo.execute == EXEC_CONTINUE) + execInfo.execute = EXEC_YES; + if (execInfo.execute == EXEC_BREAK) { + execInfo.execute = EXEC_YES; + hasHadBreak = true; + } + if (!loopCond) JSP_RESTORE_EXECUTE(); + if (loopCond) { + jslSeekTo(execInfo.lex, forIterStart); + if (execInfo.lex->tk != ')') jsvUnLock(jspeBase()); + } + while (!hasHadBreak && JSP_SHOULD_EXECUTE && loopCond +#ifdef JSPARSE_MAX_LOOP_ITERATIONS + && loopCount-->0 +#endif + ) { + jslSeekTo(execInfo.lex, forCondStart); + ; + if (execInfo.lex->tk == ';') { + loopCond = true; + } else { + JsVar *cond = jspeBase(); + loopCond = jsvGetBoolAndUnLock(jsvSkipName(cond)); + jsvUnLock(cond); + } + if (JSP_SHOULD_EXECUTE && loopCond) { + jslSeekTo(execInfo.lex, forBodyStart); + execInfo.execute |= EXEC_IN_LOOP; + jsvUnLock(jspeBlockOrStatement()); + execInfo.execute &= (JsExecFlags)~EXEC_IN_LOOP; + if (execInfo.execute == EXEC_CONTINUE) + execInfo.execute = EXEC_YES; + if (execInfo.execute == EXEC_BREAK) { + execInfo.execute = EXEC_YES; + hasHadBreak = true; + } + } + if (JSP_SHOULD_EXECUTE && loopCond) { + jslSeekTo(execInfo.lex, forIterStart); + if (execInfo.lex->tk != ')') jsvUnLock(jspeBase()); + } + } + jslSeekTo(execInfo.lex, forBodyEnd); +#ifdef JSPARSE_MAX_LOOP_ITERATIONS + if (loopCount<=0) { + jsErrorAt("FOR Loop exceeded the maximum number of iterations ("STRINGIFY(JSPARSE_MAX_LOOP_ITERATIONS)")", execInfo.lex, execInfo.lex->tokenLastEnd); + jspSetError(); + } +#endif + } + return 0; +} + +JsVar *jspeStatementReturn() { + JsVar *result = 0; + JSP_MATCH(LEX_R_RETURN); + if (execInfo.lex->tk != ';') { + // we only want the value, so skip the name if there was one + result = jsvSkipNameAndUnLock(jspeBaseWithComma()); + } + if (JSP_SHOULD_EXECUTE) { + JsVar *resultVar = jspeiFindOnTop(JSPARSE_RETURN_VAR, false); + if (resultVar) { + jspReplaceWith(resultVar, result); + jsvUnLock(resultVar); + } else { + jsErrorAt("RETURN statement, but not in a function.\n", execInfo.lex, execInfo.lex->tokenLastEnd); + jspSetError(); + } + jspSetNoExecute(); // Stop anything else in this function executing + } + jsvUnLock(result); + return 0; +} + +JsVar *jspeStatementFunctionDecl() { + JsVar *funcName = 0; + JsVar *funcVar; + JSP_MATCH(LEX_R_FUNCTION); + if (JSP_SHOULD_EXECUTE) + funcName = jsvMakeIntoVariableName(jsvNewFromString(jslGetTokenValueAsString(execInfo.lex)), 0); + if (!funcName) { // out of memory + jspSetError(); + return 0; + } + JSP_MATCH(LEX_ID); + funcVar = jspeFunctionDefinition(); + if (JSP_SHOULD_EXECUTE) { + // find a function with the same name (or make one) + // OPT: can Find* use just a JsVar that is a 'name'? + JsVar *existingFunc = jspeiFindNameOnTop(funcName, true); + // replace it + jspReplaceWith(existingFunc, funcVar); + jsvUnLock(funcName); + funcName = existingFunc; + } + jsvUnLock(funcVar); + return funcName; +} + +JsVar *jspeStatement() { + if (execInfo.lex->tk==LEX_ID || + execInfo.lex->tk==LEX_INT || + execInfo.lex->tk==LEX_FLOAT || + execInfo.lex->tk==LEX_STR || + execInfo.lex->tk==LEX_R_NEW || + execInfo.lex->tk==LEX_R_NULL || + execInfo.lex->tk==LEX_R_UNDEFINED || + execInfo.lex->tk==LEX_R_TRUE || + execInfo.lex->tk==LEX_R_FALSE || + execInfo.lex->tk==LEX_R_THIS || + execInfo.lex->tk==LEX_R_TYPEOF || + execInfo.lex->tk==LEX_R_VOID || + execInfo.lex->tk==LEX_PLUSPLUS || + execInfo.lex->tk==LEX_MINUSMINUS || + execInfo.lex->tk=='!' || + execInfo.lex->tk=='-' || + execInfo.lex->tk=='+' || + execInfo.lex->tk=='~' || + execInfo.lex->tk=='[' || + execInfo.lex->tk=='(') { + /* Execute a simple statement that only contains basic arithmetic... */ + return jspeBaseWithComma(); + } else if (execInfo.lex->tk=='{') { + /* A block of code */ + return jspeBlock(); + } else if (execInfo.lex->tk==';') { + /* Empty statement - to allow things like ;;; */ + JSP_MATCH(';'); + return 0; + } else if (execInfo.lex->tk==LEX_R_VAR) { + return jspeStatementVar(); + } else if (execInfo.lex->tk==LEX_R_IF) { + return jspeStatementIf(); + } else if (execInfo.lex->tk==LEX_R_WHILE) { + return jspeStatementWhile(); + } else if (execInfo.lex->tk==LEX_R_FOR) { + return jspeStatementFor(); + } else if (execInfo.lex->tk==LEX_R_RETURN) { + return jspeStatementReturn(); + } else if (execInfo.lex->tk==LEX_R_FUNCTION) { + return jspeStatementFunctionDecl(); + } else if (execInfo.lex->tk==LEX_R_CONTINUE) { + JSP_MATCH(LEX_R_CONTINUE); + if (JSP_SHOULD_EXECUTE) { + if (!(execInfo.execute & EXEC_IN_LOOP)) + jsErrorAt("CONTINUE statement outside of FOR or WHILE loop", execInfo.lex, execInfo.lex->tokenLastEnd); + else + execInfo.execute = (execInfo.execute & (JsExecFlags)~EXEC_RUN_MASK) | EXEC_CONTINUE; + } + } else if (execInfo.lex->tk==LEX_R_BREAK) { + JSP_MATCH(LEX_R_BREAK); + if (JSP_SHOULD_EXECUTE) { + if (!(execInfo.execute & (EXEC_IN_LOOP|EXEC_IN_SWITCH))) + jsErrorAt("BREAK statement outside of SWITCH, FOR or WHILE loop", execInfo.lex, execInfo.lex->tokenLastEnd); + else + execInfo.execute = (execInfo.execute & (JsExecFlags)~EXEC_RUN_MASK) | EXEC_BREAK; + } + } else if (execInfo.lex->tk==LEX_R_SWITCH) { + return jspeStatementSwitch(); + } else JSP_MATCH(LEX_EOF); + return 0; +} + +// ----------------------------------------------------------------------------- +/// Create a new built-in object that jswrapper can use to check for built-in functions +JsVar *jspNewBuiltin(const char *instanceOf) { + JsVar *objFunc = jsvNewWithFlags(JSV_FUNCTION); + if (!objFunc) return 0; // out of memory + // set object data to be object name + if (strlen(instanceOf)==sizeof(objFunc->varData)) + memcpy(objFunc->varData.str, instanceOf, sizeof(objFunc->varData)); // no trailing zero! + else + strncpy(objFunc->varData.str, instanceOf, sizeof(objFunc->varData)); + return objFunc; +} + + +JsVar *jspNewObject(JsParse *parse, const char *name, const char *instanceOf) { + JsVar *objFuncName = jsvFindChildFromString(parse->root, instanceOf, true); + if (!objFuncName) // out of memory + return 0; + + JsVar *objFunc = jsvSkipName(objFuncName); + if (!objFunc) { + objFunc = jspNewBuiltin(instanceOf); + if (!objFunc) { // out of memory + jsvUnLock(objFuncName); + return 0; + } + + // set up name + jsvSetValueOfName(objFuncName, objFunc); + } + + JsVar *prototypeName = jsvFindChildFromString(objFunc, JSPARSE_PROTOTYPE_VAR, true); + jspEnsureIsPrototype(prototypeName); // make sure it's an object + jsvUnLock(objFunc); + if (!prototypeName) { // out of memory + jsvUnLock(objFuncName); + return 0; + } + + JsVar *obj = jsvNewWithFlags(JSV_OBJECT); + if (!obj) { // out of memory + jsvUnLock(objFuncName); + jsvUnLock(prototypeName); + return 0; + } + if (name) { + // set object data to be object name + strncpy(obj->varData.str, name, sizeof(obj->varData)); + } + // add inherits/constructor/etc + jsvUnLock(jsvAddNamedChild(obj, prototypeName, JSPARSE_INHERITS_VAR)); + jsvUnLock(prototypeName);prototypeName=0; + jsvUnLock(jsvAddNamedChild(obj, objFuncName, JSPARSE_CONSTRUCTOR_VAR)); + jsvUnLock(objFuncName); + if (name) { + JsVar *objName = jsvAddNamedChild(parse->root, obj, name); + jsvUnLock(obj); + if (!objName) { // out of memory + return 0; + } + return objName; + } else + return obj; +} + +/** Returns true if the constructor function given is the same as that + * of the object with the given name. */ +bool jspIsConstructor(JsVar *constructor, const char *constructorName) { + JsVar *objFunc = jsvObjectGetChild(execInfo.parse->root, constructorName, 0); + if (!objFunc) return false; + bool isConstructor = objFunc == constructor; + jsvUnLock(objFunc); + return isConstructor; +} + +// ----------------------------------------------------------------------------- + +void jspSoftInit(JsParse *parse) { + parse->root = jsvFindOrCreateRoot(); + // Root now has a lock and a ref +} + +/** Is v likely to have been created by this parser? */ +bool jspIsCreatedObject(JsParse *parse, JsVar *v) { + return + v==parse->root; +} + +void jspSoftKill(JsParse *parse) { + jsvUnLock(parse->root); + // Root now has just a ref +} + +void jspInit(JsParse *parse) { + jspSoftInit(parse); +} + +void jspKill(JsParse *parse) { + jspSoftKill(parse); + // Unreffing this should completely kill everything attached to root + JsVar *r = jsvFindOrCreateRoot(); + jsvUnRef(r); + jsvUnLock(r); +} + + + +JsVar *jspEvaluateVar(JsParse *parse, JsVar *str, JsVar *scope) { + JsLex lex; + JsVar *v = 0; + JSP_SAVE_EXECUTE(); + JsExecInfo oldExecInfo = execInfo; + + assert(jsvIsString(str)); + jslInit(&lex, str); + + jspeiInit(parse, &lex); + bool scopeAdded = false; + if (scope) + scopeAdded = jspeiAddScope(jsvGetRef(scope)); + while (!JSP_HAS_ERROR && execInfo.lex->tk != LEX_EOF) { + jsvUnLock(v); + v = jspeBlockOrStatement(); + } + // clean up + if (scopeAdded) jspeiRemoveScope(); + jspeiKill(); + jslKill(&lex); + + // restore state + JSP_RESTORE_EXECUTE(); + oldExecInfo.execute = execInfo.execute; // JSP_RESTORE_EXECUTE has made this ok. + execInfo = oldExecInfo; + + // It may have returned a reference, but we just want the value... + if (v) { + return jsvSkipNameAndUnLock(v); + } + // nothing returned + return 0; +} + +JsVar *jspEvaluate(JsParse *parse, const char *str) { + JsVar *v = 0; + + JsVar *evCode = jsvNewFromString(str); + if (!jsvIsMemoryFull()) + v = jspEvaluateVar(parse, evCode, 0); + jsvUnLock(evCode); + + return v; +} + +bool jspExecuteFunction(JsParse *parse, JsVar *func, JsVar *parent, int argCount, JsVar **argPtr) { + JSP_SAVE_EXECUTE(); + JsExecInfo oldExecInfo = execInfo; + + jspeiInit(parse, 0); + JsVar *resultVar = jspeFunctionCall(func, 0, parent, false, argCount, argPtr); + bool result = jsvGetBool(resultVar); + jsvUnLock(resultVar); + // clean up + jspeiKill(); + // restore state + JSP_RESTORE_EXECUTE(); + oldExecInfo.execute = execInfo.execute; // JSP_RESTORE_EXECUTE has made this ok. + execInfo = oldExecInfo; + + + return result; +} + + +/// Evaluate a JavaScript module and return its exports +JsVar *jspEvaluateModule(JsParse *parse, JsVar *moduleContents) { + assert(jsvIsString(moduleContents)); + JsVar *scope = jsvNewWithFlags(JSV_OBJECT); + if (!scope) return 0; // out of mem + JsVar *scopeExports = jsvNewWithFlags(JSV_OBJECT); + if (!scopeExports) { jsvUnLock(scope); return 0; } // out of mem + jsvUnLock(jsvAddNamedChild(scope, scopeExports, "exports")); + + jsvUnLock(jspEvaluateVar(parse, moduleContents, scope)); + + jsvUnLock(scope); + return scopeExports; +} diff --git a/components/external/espruino/src/jsparse.h b/components/external/espruino/src/jsparse.h new file mode 100644 index 0000000000..7abaee4b6e --- /dev/null +++ b/components/external/espruino/src/jsparse.h @@ -0,0 +1,126 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Recursive descent parser for code execution + * ---------------------------------------------------------------------------- + */ +#ifndef JSPARSE_H_ +#define JSPARSE_H_ + +#include "jsvar.h" +#include "jslex.h" + + +typedef struct { + JsVar *root; ///< root of symbol table +} JsParse; + +void jspInit(JsParse *parse); +void jspKill(JsParse *parse); + +// jspSoft* - 'release' or 'claim' anything we are using, but ensure that it doesn't get freed +void jspSoftInit(JsParse *parse); ///< used when recovering from or saving to flash +void jspSoftKill(JsParse *parse); ///< used when recovering from or saving to flash +bool jspIsCreatedObject(JsParse *parse, JsVar *v); ///< Is v likely to have been created by this parser? +/** Returns true if the constructor function given is the same as that + * of the object with the given name. */ +bool jspIsConstructor(JsVar *constructor, const char *constructorName); + +/// Create a new built-in object that jswrapper can use to check for built-in functions +JsVar *jspNewBuiltin(const char *name); +/** Create a new object of the given instance and add it to root with name 'name'. + * If name!=0, added to root with name, and the name is returned + * If name==0, not added to root and Object itself returned */ +JsVar *jspNewObject(JsParse *parse, const char *name, const char *instanceOf); + +/// if interrupting execution, this is set +bool jspIsInterrupted(); +/// if interrupting execution, this is set +void jspSetInterrupted(bool interrupt); +/// Has there been an error during parsing +bool jspHasError(); + +bool jspAddNativeFunction(JsParse *parse, const char *funcDesc, JsCallback callbackPtr); +JsVar *jspEvaluateVar(JsParse *parse, JsVar *str, JsVar *scope); +JsVar *jspEvaluate(JsParse *parse, const char *str); +bool jspExecuteFunction(JsParse *parse, JsVar *func, JsVar *parent, int argCount, JsVar **argPtr); + +/// Evaluate a JavaScript module and return its exports +JsVar *jspEvaluateModule(JsParse *parse, JsVar *moduleContents); + +/** When parsing, this enum defines whether + we are executing or not */ +typedef enum { + EXEC_NO = 0, + EXEC_YES = 1, + EXEC_BREAK = 2, + EXEC_CONTINUE = 4, + + EXEC_INTERRUPTED = 8, // true if execution has been interrupted + EXEC_ERROR = 16, + EXEC_ERROR_LINE_REPORTED = 32, // if an error has been reported, set this so we don't do it too much + + EXEC_FOR_INIT = 64, // when in for initialiser parsing - hack to avoid getting confused about multiple use for IN + EXEC_IN_LOOP = 128, // when in a loop, set this - we can then block break/continue outside it + EXEC_IN_SWITCH = 256, // when in a switch, set this - we can then block break outside it/loops + + EXEC_RUN_MASK = EXEC_YES|EXEC_BREAK|EXEC_CONTINUE|EXEC_INTERRUPTED, + EXEC_ERROR_MASK = EXEC_INTERRUPTED|EXEC_ERROR, + EXEC_SAVE_RESTORE_MASK = EXEC_YES|EXEC_IN_LOOP|EXEC_IN_SWITCH, // the things JSP_SAVE/RESTORE_EXECUTE should keep track of +} JsExecFlags; + +/** This structure is used when parsing the JavaScript. It contains + * everything that should be needed. */ +typedef struct { + JsParse *parse; + JsLex *lex; + + // TODO: could store scopes as JsVar array for speed + JsVarRef scopes[JSPARSE_MAX_SCOPES]; + int scopeCount; + /// Value of 'this' reserved word + JsVar *thisVar; + + JsExecFlags execute; +} JsExecInfo; + +/// flags for jspParseFunction +typedef enum { + JSP_NOSKIP_A = 1, + JSP_NOSKIP_B = 2, + JSP_NOSKIP_C = 4, + JSP_NOSKIP_D = 8, + JSP_NOSKIP_E = 16, + JSP_NOSKIP_F = 32, + JSP_NOSKIP_G = 64, + JSP_NOSKIP_H = 128, +} JspSkipFlags; + +/// parse function with max 4 arguments (can set arg to 0 to avoid parse). Usually first arg will be 0, but if we DON'T want to skip names on an arg stuff, we can say +bool jspParseFunction(JspSkipFlags skipName, JsVar **a, JsVar **b, JsVar **c, JsVar **d); +/// parse function with max 8 arguments (can set arg to 0 to avoid parse). Usually first arg will be 0, but if we DON'T want to skip names on an arg stuff, we can say +bool jspParseFunction8(JspSkipFlags skipName, JsVar **a, JsVar **b, JsVar **c, JsVar **d, JsVar **e, JsVar **f, JsVar **g, JsVar **h); + +bool jspParseVariableName(); ///< parse single variable name +bool jspParseEmptyFunction(); ///< parse function with no arguments +JsVar *jspParseSingleFunction(); ///< parse function with a single argument, return its value (no names!) +JsVar *jspParseFunctionAsArray(); ///< parse a function with any number of argument, and return an array of de-named aruments + +/** Handle a function call (assumes we've parsed the function name and we're + * on the start bracket). 'thisArg' is the value of the 'this' variable when the + * function is executed (it's usually the parent object) + * + * If !isParsing and arg0!=0, argument 0 is set to what is supplied (same with arg1) + * + * functionName is used only for error reporting - and can be 0 + */ +JsVar *jspeFunctionCall(JsVar *function, JsVar *functionName, JsVar *thisArg, bool isParsing, int argCount, JsVar **argPtr); + +#endif /* JSPARSE_H_ */ diff --git a/components/external/espruino/src/jspin.c b/components/external/espruino/src/jspin.c new file mode 100644 index 0000000000..c345e615e8 --- /dev/null +++ b/components/external/espruino/src/jspin.c @@ -0,0 +1,150 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Utilities and definitions for handling Pins + * ---------------------------------------------------------------------------- + */ + +#include "jspin.h" +#include "jspininfo.h" // auto-generated + +bool jshIsPinValid(Pin pin) { + // Note, PIN_UNDEFINED is always > JSH_PIN_COUNT + return pin < JSH_PIN_COUNT && pinInfo[pin].port!=JSH_PORT_NONE; +} + + +Pin jshGetPinFromString(const char *s) { + // built in constants + + if (s[0]=='B' && s[1]=='T' && s[2]=='N') { +#ifdef BTN1_PININDEX + if (!s[3]) return BTN1_PININDEX; + if (s[3]=='1' && !s[4]) return BTN1_PININDEX; +#endif +#ifdef BTN2_PININDEX + if (s[3]=='2' && !s[4]) return BTN2_PININDEX; +#endif +#ifdef BTN3_PININDEX + if (s[3]=='3' && !s[4]) return BTN3_PININDEX; +#endif +#ifdef BTN4_PININDEX + if (s[3]=='4' && !s[4]) return BTN4_PININDEX; +#endif + } + if (s[0]=='L' && s[1]=='E' && s[2]=='D') { +#ifdef LED1_PININDEX + if (!s[3]) return LED1_PININDEX; + if (s[3]=='1' && !s[4]) return LED1_PININDEX; +#endif +#ifdef LED2_PININDEX + if (s[3]=='2' && !s[4]) return LED2_PININDEX; +#endif +#ifdef LED3_PININDEX + if (s[3]=='3' && !s[4]) return LED3_PININDEX; +#endif +#ifdef LED4_PININDEX + if (s[3]=='4' && !s[4]) return LED4_PININDEX; +#endif +#ifdef LED5_PININDEX + if (s[3]=='5' && !s[4]) return LED5_PININDEX; +#endif +#ifdef LED6_PININDEX + if (s[3]=='6' && !s[4]) return LED6_PININDEX; +#endif +#ifdef LED7_PININDEX + if (s[3]=='7' && !s[4]) return LED7_PININDEX; +#endif +#ifdef LED8_PININDEX + if (s[3]=='8' && !s[4]) return LED8_PININDEX; +#endif + } + + if ((s[0]>='A' && s[0]<='H') && s[1]) { // first 6 are analogs + int port = JSH_PORTA+s[0]-'A'; + Pin pin = 127; + if (!s[2] && (s[1]>='0' && s[1]<='9')) { // D0-D9 + pin = (Pin)(s[1]-'0'); + } else if (!s[3] && (s[1]>='1' && s[1]<='3' && s[2]>='0' && s[2]<='9')) { // D1X-D3X + pin = (Pin)((s[1]-'0')*10 + (s[2]-'0')); + } + if (port == JSH_PORTA) { + if (pin=JSH_PORTA_OFFSET && +#endif + pin=JSH_PORTB_OFFSET && pin=JSH_PORTC_OFFSET && pin=JSH_PORTD_OFFSET && pin=JSH_PORTE_OFFSET && pin=JSH_PORTF_OFFSET && pin=JSH_PORTG_OFFSET && pin=JSH_PORTH_OFFSET && pin + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Utilities and definitions for handling Pins + * ---------------------------------------------------------------------------- + */ + +#ifndef JSPIN_H +#define JSPIN_H + +#include "jsutils.h" +#include "jsvar.h" + +typedef unsigned char Pin; ///< for specifying pins for hardware +#define PIN_UNDEFINED ((Pin)0xFF) + +typedef enum { + JSH_PORT_NONE, + JSH_PORTA=1, + JSH_PORTB, + JSH_PORTC, + JSH_PORTD, + JSH_PORTE, + JSH_PORTF, + JSH_PORTG, + JSH_PORTH, +} PACKED_FLAGS JsvPinInfoPort; + +typedef enum { + JSH_PIN0 = 0, + JSH_PIN1, + JSH_PIN2, + JSH_PIN3, + JSH_PIN4, + JSH_PIN5, + JSH_PIN6, + JSH_PIN7, + JSH_PIN8, + JSH_PIN9, + JSH_PIN10, + JSH_PIN11, + JSH_PIN12, + JSH_PIN13, + JSH_PIN14, + JSH_PIN15, +#ifndef ARM + JSH_PIN16, + JSH_PIN17, + JSH_PIN18, + JSH_PIN19, + JSH_PIN20, + JSH_PIN21, + JSH_PIN22, + JSH_PIN23, + JSH_PIN24, + JSH_PIN25, + JSH_PIN26, + JSH_PIN27, + JSH_PIN28, + JSH_PIN29, + JSH_PIN30, + JSH_PIN31, +#endif +} PACKED_FLAGS JsvPinInfoPin; + +typedef enum { + JSH_ANALOG_NONE = 0, + JSH_ANALOG1 = 32, + JSH_ANALOG2 = 64, + JSH_ANALOG3 = 128, + JSH_ANALOG4 = 256, + JSH_ANALOG12 = JSH_ANALOG1|JSH_ANALOG2, + JSH_ANALOG123 = JSH_ANALOG1|JSH_ANALOG2|JSH_ANALOG3, + JSH_ANALOG34 = JSH_ANALOG3|JSH_ANALOG4, + + JSH_ANALOG_CH0 = 0, + JSH_ANALOG_CH1, + JSH_ANALOG_CH2, + JSH_ANALOG_CH3, + JSH_ANALOG_CH4, + JSH_ANALOG_CH5, + JSH_ANALOG_CH6, + JSH_ANALOG_CH7, + JSH_ANALOG_CH8, + JSH_ANALOG_CH9, + JSH_ANALOG_CH10, + JSH_ANALOG_CH11, + JSH_ANALOG_CH12, + JSH_ANALOG_CH13, + JSH_ANALOG_CH14, + JSH_ANALOG_CH15, + JSH_ANALOG_CH16, + + JSH_MASK_ANALOG_CH = 31, + JSH_MASK_ANALOG_ADC = JSH_ANALOG1|JSH_ANALOG2|JSH_ANALOG3|JSH_ANALOG4, + +} PACKED_FLAGS JsvPinInfoAnalog; + +typedef enum { + // ---------------------------- JSH_MASK_AF + JSH_AF0 = 0, + JSH_AF1, + JSH_AF2, + JSH_AF3, + JSH_AF4, + JSH_AF5, + JSH_AF6, + JSH_AF7, + JSH_AF8, + JSH_AF9, + JSH_AF10, + JSH_AF11, + JSH_AF12, + JSH_AF13, + JSH_AF14, + JSH_AF15, + + // ---------------------------- JSH_MASK_TYPE + JSH_TIMER1 = 0x0010, + JSH_TIMER2 = 0x0020, + JSH_TIMER3 = 0x0030, + JSH_TIMER4 = 0x0040, + JSH_TIMER5 = 0x0050, + JSH_TIMER6 = 0x0060, + JSH_TIMER7 = 0x0070, + JSH_TIMER8 = 0x0080, + JSH_TIMER9 = 0x0090, + JSH_TIMER10 = 0x00A0, + JSH_TIMER11 = 0x00B0, + JSH_TIMER12 = 0x00C0, + JSH_TIMER13 = 0x00D0, + JSH_TIMER14 = 0x00E0, + JSH_TIMER15 = 0x00F0, + JSH_TIMER16 = 0x0100, + JSH_TIMER17 = 0x0110, + JSH_TIMER18 = 0x0120, + JSH_TIMERMAX = JSH_TIMER18, + JSH_DAC = 0x0180, + JSH_SPI1 = 0x0200, + JSH_SPI2 = 0x0210, + JSH_SPI3 = 0x0220, + JSH_SPIMAX = JSH_SPI3, + JSH_I2C1 = 0x0280, + JSH_I2C2 = 0x0290, + JSH_I2C3 = 0x02A0, + JSH_I2CMAX = JSH_I2C3, + JSH_USART1 = 0x0300, + JSH_USART2 = 0x0310, + JSH_USART3 = 0x0320, + JSH_USART4 = 0x0330, + JSH_USART5 = 0x0340, + JSH_USART6 = 0x0350, + JSH_USARTMAX = JSH_USART6, + + // ---------------------------- JSH_MASK_INFO + + JSH_TIMER_CH1 = 0x0000, + JSH_TIMER_CH2 = 0x1000, + JSH_TIMER_CH3 = 0x2000, + JSH_TIMER_CH4 = 0x3000, + JSH_MASK_TIMER_CH = 0x7000, + JSH_TIMER_NEGATED = 0x8000, + + JSH_USART_RX = 0x0000, + JSH_USART_TX = 0x1000, + + JSH_SPI_MISO = 0x0000, + JSH_SPI_MOSI = 0x1000, + JSH_SPI_SCK = 0x2000, + + JSH_I2C_SCL = 0x0000, + JSH_I2C_SDA = 0x1000, + + JSH_DAC_CH1 = 0x0000, + JSH_DAC_CH2 = 0x1000, + + // ---------------------------- Masks + JSH_MASK_AF = 0x000F, + JSH_MASK_TYPE = 0x0FF0, + JSH_MASK_INFO = 0xF000, +} PACKED_FLAGS JshPinFunction; + +#define JSH_PINFUNCTION_IS_TIMER(F) ( \ + (((F)&JSH_MASK_TYPE)>=JSH_TIMER1) && \ + (((F)&JSH_MASK_TYPE)<=JSH_TIMER18)) +#define JSH_PINFUNCTION_IS_DAC(F) ( \ + (((F)&JSH_MASK_TYPE)==JSH_DAC) || \ +0 ) +#define JSH_PINFUNCTION_IS_USART(F) ( \ + (((F)&JSH_MASK_TYPE)>=JSH_USART1) && \ + (((F)&JSH_MASK_TYPE)<=JSH_USART6)) +#define JSH_PINFUNCTION_IS_I2C(F) ( \ + (((F)&JSH_MASK_TYPE)>=JSH_I2C1) && \ + (((F)&JSH_MASK_TYPE)<=JSH_I2CMAX)) +#define JSH_PINFUNCTION_IS_SPI(F) ( \ + (((F)&JSH_MASK_TYPE)>=JSH_SPI1) && \ + (((F)&JSH_MASK_TYPE)<=JSH_SPIMAX)) + +bool jshIsPinValid(Pin pin); ///< is the specific pin actually valid? + +/// Given a string, convert it to a pin ID (or -1 if it doesn't exist) +Pin jshGetPinFromString(const char *s); +/** Write the pin name to a string. String must have at least 8 characters (to be safe) */ +void jshGetPinString(char *result, Pin pin); + +/// Given a var, convert it to a pin ID (or -1 if it doesn't exist). safe for undefined! +static inline Pin jshGetPinFromVar(JsVar *pinv) { + if (jsvIsString(pinv) && pinv->varData.str[5]==0/*should never be more than 4 chars!*/) { + return jshGetPinFromString(&pinv->varData.str[0]); + } else if (jsvIsInt(pinv) /* This also tests for the Pin datatype */) { + return (Pin)jsvGetInteger(pinv); + } else return PIN_UNDEFINED; +} + +static inline Pin jshGetPinFromVarAndUnLock(JsVar *pinv) { + Pin pin = jshGetPinFromVar(pinv); + jsvUnLock(pinv); + return pin; +} + +#endif //JSPIN_H diff --git a/components/external/espruino/src/jsutils.c b/components/external/espruino/src/jsutils.c new file mode 100644 index 0000000000..669956989e --- /dev/null +++ b/components/external/espruino/src/jsutils.c @@ -0,0 +1,439 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Misc utils and cheapskate stdlib implementation + * ---------------------------------------------------------------------------- + */ +#include "jsutils.h" +#include "jslex.h" +#include "jshardware.h" +#include "jsinteractive.h" + +// needed for isnan / isfinite +#ifdef ARM +#include "mconf.h" +#include "protos.h" +#else +#include +#endif + +extern double jswrap_math_pow(double x, double y); // for pow + +bool isIDString(const char *s) { + if (!isAlpha(*s)) + return false; + while (*s) { + if (!(isAlpha(*s) || isNumeric(*s))) + return false; + s++; + } + return true; +} + +/** escape a character - if it is required. This may return a reference to a static array, +so you can't store the value it returns in a variable and call it again. */ +const char *escapeCharacter(char ch) { + if (ch=='\b') return "\\b"; + if (ch=='\f') return "\\f"; + if (ch=='\n') return "\\n"; + if (ch=='\a') return "\\a"; + if (ch=='\r') return "\\r"; + if (ch=='\t') return "\\t"; + if (ch=='\\') return "\\\\"; + if (ch=='"') return "\\\""; + static char buf[5]; + if (ch<32) { + /** just encode as hex - it's more understandable + * and doesn't have the issue of "\16"+"1" != "\161" */ + buf[0]='\\'; + buf[1]='x'; + int n = (ch>>4)&15; + buf[2] = (char)((n<10)?('0'+n):('A'+n-10)); + n=ch&15; + buf[3] = (char)((n<10)?('0'+n):('A'+n-10)); + buf[4] = 0; + return buf; + } + buf[1] = 0; + buf[0] = ch; + return buf; +} + +/* convert a number in the given radix to an int. if radix=0, autodetect */ +JsVarInt stringToIntWithRadix(const char *s, int forceRadix, bool *hasError) { + bool isNegated = false; + JsVarInt v = 0; + JsVarInt radix = 10; + if (*s == '-') { + isNegated = true; + s++; + } + if (*s == '0') { + radix = 8; + s++; + + // OctalIntegerLiteral: 0o01, 0O01 + if (*s == 'o' || *s == 'O') { + radix = 8; + s++; + + // HexIntegerLiteral: 0x01, 0X01 + } else if (*s == 'x' || *s == 'X') { + radix = 16; + s++; + + // BinaryIntegerLiteral: 0b01, 0B01 + } else if (*s == 'b' || *s == 'B') { + radix = 2; + s++; + } + } + if (forceRadix>0 && forceRadix<=36) + radix = forceRadix; + + while (*s) { + int digit = 0; + if (*s >= '0' && *s <= '9') + digit = (*s - '0'); + else if (*s >= 'a' && *s <= 'f') + digit = (10 + *s - 'a'); + else if (*s >= 'A' && *s <= 'F') + digit = (10 + *s - 'A'); + else break; + if (digit>=radix) + break; + v = v*radix + digit; + s++; + } + + if (hasError) *hasError = *s!=0; // we're ok if we reached the end of the string + + if (isNegated) return -v; + return v; +} + +/* convert hex, binary, octal or decimal string into an int */ +JsVarInt stringToInt(const char *s) { + return stringToIntWithRadix(s,0,0); +} + +void jsError(const char *fmt, ...) { + jsiConsoleRemoveInputLine(); + jsiConsolePrint("ERROR: "); + va_list argp; + va_start(argp, fmt); + vcbprintf((vcbprintf_callback)jsiConsolePrint,0, fmt, argp); + va_end(argp); + jsiConsolePrint("\n"); +} + +void jsErrorInternal(const char *fmt, ...) { + jsiConsoleRemoveInputLine(); + jsiConsolePrint("INTERNAL ERROR: "); + va_list argp; + va_start(argp, fmt); + vcbprintf((vcbprintf_callback)jsiConsolePrint,0, fmt, argp); + va_end(argp); + jsiConsolePrint("\n"); +} + +void jsErrorAt(const char *message, struct JsLex *lex, int tokenPos) { + jsiConsoleRemoveInputLine(); + jsiConsolePrint("ERROR: "); + jsiConsolePrint(message); + jsiConsolePrint(" at "); + jsiConsolePrintPosition(lex, tokenPos); + jsiConsolePrintTokenLineMarker(lex, tokenPos); +} + +void jsWarn(const char *fmt, ...) { + jsiConsoleRemoveInputLine(); + jsiConsolePrint("WARNING: "); + va_list argp; + va_start(argp, fmt); + vcbprintf((vcbprintf_callback)jsiConsolePrint,0, fmt, argp); + va_end(argp); + jsiConsolePrint("\n"); +} + +void jsWarnAt(const char *message, struct JsLex *lex, int tokenPos) { + jsiConsoleRemoveInputLine(); + jsiConsolePrint("WARNING: "); + jsiConsolePrint(message); + jsiConsolePrint(" at "); + jsiConsolePrintPosition(lex, tokenPos); +} + +void jsAssertFail(const char *file, int line, const char *expr) { + jsiConsoleRemoveInputLine(); + if (expr) { + jsiConsolePrintf("ASSERT(%s) FAILED AT ", expr); + } else + jsiConsolePrint("ASSERT FAILED AT "); + jsiConsolePrintf("%s:%d\n",file,line); + + jsvTrace(jsvGetRef(jsvFindOrCreateRoot()), 2); + exit(1); +} + +#ifdef SDCC +void exit(int errcode) {dst; + jsiConsolePrint("EXIT CALLED.\n"); +} +#endif + +#ifdef FAKE_STDLIB +int __errno; + +void exit(int errcode) { + NOT_USED(errcode); + jsiConsolePrint("EXIT CALLED.\n"); + while (1); +} + +char * strncat(char *dst, const char *src, size_t c) { + char *dstx = dst; + while (*(++dstx)) c--; + while (*src && c>1) { + *(dstx++) = *(src++); + c--; + } + if (c>0) *dstx = 0; + return dst; +} +char *strncpy(char *dst, const char *src, size_t c) { + char *dstx = dst; + while (*src && c>1) { + *(dstx++) = *(src++); + c--; + } + if (c>0) *dstx = 0; + return dst; +} +size_t strlen(const char *s) { + size_t l=0; + while (*(s++)) l++; + return l; +} +int strcmp(const char *a, const char *b) { + while (*a && *b) { + if (*a != *b) + return *a - *b; // correct? + a++;b++; + } + return *a - *b; +} +void *memcpy(void *dst, const void *src, size_t size) { + size_t i; + for (i=0;i> 16); + m_w = 18000 * (m_w & 65535) + (m_w >> 16); + return (m_z << 16) + m_w; /* 32-bit result */ +} +#endif + +JsVarFloat stringToFloat(const char *s) { + bool isNegated = false; + JsVarFloat v = 0; + JsVarFloat mul = 0.1; + if (*s == '-') { + isNegated = true; + s++; + } + // handle integer part + while (*s) { + if (*s >= '0' && *s <= '9') + v = (v*10) + (*s - '0'); + else break; + s++; + } + // handle decimal point + if (*s == '.') { + s++; // skip . + + while (*s) { + if (*s >= '0' && *s <= '9') + v += mul*(*s - '0'); + else break; + mul /= 10; + s++; + } + } + + // handle exponentials + if (*s == 'e' || *s == 'E') { + s++; // skip E + bool isENegated = false; + if (*s == '-' || *s == '+') { + isENegated = *s=='-'; + s++; + } + int e = 0; + while (*s) { + if (*s >= '0' && *s <= '9') + e = (e*10) + (*s - '0'); + else break; + s++; + } + if (isENegated) e=-e; + v = v * jswrap_math_pow(10, e); + } + // check we have parsed everything + if (*s!=0) return NAN; + + if (isNegated) return -v; + return v; +} + + +char itoch(int val) { + if (val<10) return (char)('0'+val); + return (char)('A'+val-10); +} + +#ifndef HAS_STDLIB +void itoa(JsVarInt vals,char *str,unsigned int base) { + JsVarIntUnsigned val; + if (vals<0) { + *(str++)='-'; + val = (JsVarIntUnsigned)(-vals); + } else { + val = (JsVarIntUnsigned)vals; + } + JsVarIntUnsigned d = 1; + while (d*base <= val) d*=base; + while (d > 1) { + unsigned int v = (unsigned int)(val / d); + val -= v*d; + *(str++) = itoch((int)v); + d /= base; + } + *(str++)=itoch((int)val); + *(str++)=0; +} +#endif + +void ftoa(JsVarFloat val,char *str) { + if (isnan(val)) strncpy(str,"NaN",4); + else if (!isfinite(val)) { + if (val<0) strncpy(str,"-Infinity",10); + else strncpy(str,"Infinity",10); + } else { + const JsVarFloat base = 10; + if (val<0) { + *(str++)='-'; + val = -val; + } + JsVarFloat d = 1; + while (d*base <= val) d*=base; + while (d >= 1) { + int v = (int)(val / d); + val -= v*d; + *(str++)=itoch(v); + d /= base; + } + #ifndef USE_NO_FLOATS + if (val>0) { + *(str++)='.'; + while (val>0.000001) { + int v = (int)((val / d) + 0.0000005); + val -= v*d; + *(str++)=itoch(v); + d /= base; + } + } + #endif + + *(str++)=0; + } +} + + +/// Wrap a value so it is always between 0 and size (eg. wrapAround(angle, 360)) +JsVarFloat wrapAround(JsVarFloat val, JsVarFloat size) { + val = val / size; + val = val - (int)val; + return val * size; +} + +/** Espruino-special printf with a callback + * Supported are: + * %d = int + * %x = int as hex + * %L = JsVarInt + * %Lx = JsVarInt as hex + * %f = JsVarFloat + * %s = string (char *) + * %c = char + * %v = JsVar * (prints var as string) + * %t = JsVar * (prints type of var) + * %p = Pin + * + * Anything else will assert + */ +void vcbprintf(vcbprintf_callback user_callback, void *user_data, const char *fmt, va_list argp) { + char buf[32]; + while (*fmt) { + if (*fmt == '%') { + fmt++; + switch (*fmt++) { + case 'd': itoa(va_arg(argp, int), buf, 10); user_callback(buf,user_data); break; + case 'x': itoa(va_arg(argp, int), buf, 16); user_callback(buf,user_data); break; + case 'L': { + unsigned int rad = 10; + if (*fmt=='x') { rad=16; fmt++; } + itoa(va_arg(argp, JsVarInt), buf, rad); user_callback(buf,user_data); + } break; + case 'f': ftoa(va_arg(argp, JsVarFloat), buf); user_callback(buf,user_data); break; + case 's': user_callback(va_arg(argp, char *), user_data); break; + case 'c': buf[0]=(char)va_arg(argp, int/*char*/);buf[1]=0; user_callback(buf, user_data); break; + case 'v': { + JsVar *v = jsvAsString(va_arg(argp, JsVar*), false/*no unlock*/); + buf[1] = 0; + JsvStringIterator it; + jsvStringIteratorNew(&it, v, 0); + // OPT: this could be faster than it is (sending whole blocks at once) + while (jsvStringIteratorHasChar(&it)) { + buf[0] = jsvStringIteratorGetChar(&it); + user_callback(buf,user_data); + jsvStringIteratorNext(&it); + } + jsvStringIteratorFree(&it); + jsvUnLock(v); + } break; + case 't': user_callback(jsvGetTypeOf(va_arg(argp, JsVar*)), user_data); break; + case 'p': jshGetPinString(buf, (Pin)va_arg(argp, int/*Pin*/)); user_callback(buf, user_data); break; + default: assert(0); return; // eep + } + } else { + buf[0] = *(fmt++); + buf[1] = 0; + user_callback(&buf[0], user_data); + } + } +} + + diff --git a/components/external/espruino/src/jsutils.h b/components/external/espruino/src/jsutils.h new file mode 100644 index 0000000000..4097830ed0 --- /dev/null +++ b/components/external/espruino/src/jsutils.h @@ -0,0 +1,374 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Misc utils and cheapskate stdlib implementation + * ---------------------------------------------------------------------------- + */ +#ifndef JSUTILS_H_ +#define JSUTILS_H_ + +#include "platform_config.h" + +#ifndef FAKE_STDLIB +#include +#include +#include +#endif +#include // for va_args + +#define JS_VERSION "1v46" +/* + In code: + TODO - should be fixed + FIXME - will probably break if used + OPT - potential for speed optimisation +*/ + +// surely bool is defined?? +#ifdef RT_USING_JS +typedef unsigned int size_t; +#else +#ifdef ARM +typedef unsigned int size_t; +#define alloca(x) __builtin_alloca(x) +#endif +#endif + +#if !defined(__USB_TYPE_H) && !defined(CPLUSPLUS) // it is defined in this file too! +typedef enum {FALSE = 0, TRUE = !FALSE} bool; +//typedef unsigned char bool; +//#define TRUE (1) +//#define FALSE (0) +#endif + +#define true (1) +#define false (0) +#define NAN (((JsVarFloat)0)/(JsVarFloat)0) + +/* Number of Js Variables allowed and Js Reference format. + + JsVarRef = char -> 15 bytes/JsVar so JSVAR_CACHE_SIZE = (RAM - 3000) / 15 + JsVarRef = short -> 20 bytes/JsVar so JSVAR_CACHE_SIZE = (RAM - 3000) / 20 + JsVarRef = int -> 26 bytes/JsVar so JSVAR_CACHE_SIZE = (RAM - 3000) / 26 + + NOTE: JSVAR_CACHE_SIZE must be at least 2 less than the number we can fit in JsVarRef + See jshardware.c FLASH constants - all this must be able to fit in flash + + +*/ + +#ifdef RESIZABLE_JSVARS + // probably linux - allow us to allocate more blocks of variables + typedef unsigned int JsVarRef; + #define JSVAR_SIZE 30 + #define JSVAR_DATA_STRING_LEN 8 // Actually 9 seems like a good number as 'prototype'==9 + #define JSVAR_DATA_STRING_MAX_LEN 24 // (JSVAR_DATA_STRING_LEN + sizeof(JsVarRef)*3 + sizeof(JsVarRefCounter)) - but see JSV_STRING_LEN_MAX - WE HAVE TO CLIP! +#else + /** JsVerRef stores References for variables - We treat 0 as null + * NOTE: we store JSVAR_DATA_STRING_* as actual values so we can do #if on them below + * + */ + #if JSVAR_CACHE_SIZE <= 254 + typedef unsigned char JsVarRef; + #define JSVAR_SIZE 15 + #define JSVAR_DATA_STRING_LEN 8 // Actually 9 seems like a good number as 'prototype'==9 + #define JSVAR_DATA_STRING_MAX_LEN 12 // (JSVAR_DATA_STRING_LEN + sizeof(JsVarRef)*3 + sizeof(JsVarRefCounter)) - but see JSV_STRING_LEN_MAX too + #else + typedef unsigned short JsVarRef; + #define JSVAR_SIZE 20 + #define JSVAR_DATA_STRING_LEN 8 // Actually 9 seems like a good number as 'prototype'==9 + #define JSVAR_DATA_STRING_MAX_LEN 16 // (JSVAR_DATA_STRING_LEN + sizeof(JsVarRef)*3 + sizeof(JsVarRefCounter)) - but see JSV_STRING_LEN_MAX too - WE HAVE TO CLIP! + #endif +#endif + +typedef long long JsVarInt; +typedef unsigned long long JsVarIntUnsigned; +#ifdef USE_FLOATS +typedef float JsVarFloat; +#else +typedef double JsVarFloat; +#endif + +typedef short JslCharPos; +#define JSSYSTIME_MAX 0x7FFFFFFFFFFFFFFFLL +typedef long long JsSysTime; + +#define JSLEX_MAX_TOKEN_LENGTH 64 +#define JS_ERROR_BUF_SIZE 64 // size of buffer error messages are written into +#define JS_ERROR_TOKEN_BUF_SIZE 16 // see jslTokenAsString + +#define JS_NUMBER_BUFFER_SIZE 24 + +#define JSPARSE_MAX_SCOPES 8 +// Don't restrict number of iterations now +//#define JSPARSE_MAX_LOOP_ITERATIONS 8192 + +#define STRINGIFY_HELPER(x) #x +#define STRINGIFY(x) STRINGIFY_HELPER(x) +#define NOT_USED(x) ( (void)(x) ) + +// javascript specific names +#define JSPARSE_RETURN_VAR "return" // variable name used for returning function results +#define JSPARSE_PROTOTYPE_VAR "prototype" +#define JSPARSE_CONSTRUCTOR_VAR "constructor" +#define JSPARSE_INHERITS_VAR "__proto__" +// internal names that hopefully nobody will be able to access +#define JS_HIDDEN_CHAR '>' // initial character of var name determines that we shouldn't see this stuff +#define JS_HIDDEN_CHAR_STR ">" +#define JSPARSE_FUNCTION_CODE_NAME JS_HIDDEN_CHAR_STR"code" +#define JSPARSE_FUNCTION_SCOPE_NAME JS_HIDDEN_CHAR_STR"scope" +#define JSPARSE_MODULE_CACHE_NAME JS_HIDDEN_CHAR_STR"modules" + +#if !defined(NO_ASSERT) + #ifdef __STRING + #define assert(X) if (!(X)) jsAssertFail(__FILE__,__LINE__,__STRING(X)); + #else + #define assert(X) if (!(X)) jsAssertFail(__FILE__,__LINE__,""); + #endif +#else + #define assert(X) +#endif + +/// Used when we have enums we want to squash down +#define PACKED_FLAGS __attribute__ ((__packed__)) + +/// Used before functions that we want to ensure are not inlined (eg. "void NO_INLINE foo() {}") +#define NO_INLINE __attribute__ ((noinline)) + +/// Maximum amount of locks we ever expect to have on a variable (this could limit recursion) must be 2^n-1 +#define JSV_LOCK_MAX 15 + +/// preprocessor power of 2 - suitable up to 16 bits +#define NEXT_POWER_2(X) \ + (((X) | (X)>>1 | (X)>>2 | (X)>>3 | \ + (X)>>4 | (X)>>5 | (X)>>6 | (X)>>7 | \ + (X)>>8 | (X)>>9 | (X)>>10 | (X)>>11 | \ + (X)>>12 | (X)>>13 | (X)>>14 | (X)>>15)+1) +/// Proprocessor get bit number +#define GET_BIT_NUMBER(X) \ + (((X)== 1)? 0: \ + ((X)== 2)? 1: \ + ((X)== 4)? 2: \ + ((X)== 8)? 3: \ + ((X)== 16)? 4: \ + ((X)== 32)? 5: \ + ((X)== 64)? 6: \ + ((X)== 128)? 7: \ + ((X)== 256)? 8: \ + ((X)== 512)? 9: \ + ((X)== 1024)?10: \ + ((X)== 2048)?11: \ + ((X)== 4096)?12: \ + ((X)== 8192)?13: \ + ((X)==16384)?14: \ + ((X)==32768)?15:10000/*error*/) + + + +/** These flags are at the top of each JsVar and provide information about what it is, as + * well as how many Locks it has. Everything is packed in as much as possible to allow us to + * get down to within 2 bytes. */ +typedef enum { + JSV_UNUSED = 0, ///< Variable not used for anything + JSV_ROOT = JSV_UNUSED+1, ///< The root of everything - there is only one of these + // UNDEFINED is now just stored using '0' as the variable Ref + JSV_NULL = JSV_ROOT+1, ///< it seems null is its own data type + JSV_STRING = JSV_NULL+1, ///< string + JSV_STRING_0 = JSV_STRING, // string of length 0 + JSV_STRING_MAX = JSV_STRING_0+JSVAR_DATA_STRING_LEN, + JSV_STRING_EXT = JSV_STRING_MAX+1, ///< extra character data for string (if it didn't fit in first JsVar). These use unused pointer fields for extra characters + JSV_STRING_EXT_0 = JSV_STRING_EXT, + JSV_STRING_EXT_MAX = JSV_STRING_EXT_0+JSVAR_DATA_STRING_MAX_LEN, + JSV_ARRAY = JSV_STRING_EXT_MAX+1, ///< A JavaScript Array Buffer - Implemented just like a String at the moment + JSV_ARRAYBUFFER = JSV_ARRAY+1, + JSV_OBJECT = JSV_ARRAYBUFFER+1, + JSV_FUNCTION = JSV_OBJECT+1, + JSV_NUMERICSTART = JSV_FUNCTION+1, ///< --------- Start of numeric variable types + JSV_INTEGER = JSV_NUMERICSTART, ///< integer number (note JSV_NUMERICMASK) + JSV_FLOAT = JSV_INTEGER+1, ///< floating point double (note JSV_NUMERICMASK) + JSV_BOOLEAN = JSV_FLOAT+1, ///< boolean (note JSV_NUMERICMASK) + JSV_PIN = JSV_BOOLEAN+1, ///< pin (note JSV_NUMERICMASK) + JSV_NUMERICEND = JSV_PIN, ///< --------- End of numeric variable types + JSV_VAR_END = JSV_NUMERICEND, ///< End of numeric variable types + + JSV_VARTYPEMASK = NEXT_POWER_2(JSV_VAR_END)-1, + + // names can be STRING, + JSV_NAME = JSV_VARTYPEMASK+1, ///< a NAME of a variable - this isn't a variable itself (and can be an int/string/etc.) + JSV_NATIVE = JSV_NAME<<1, ///< to specify this is a native function, root, function parameter, OR that it should not be freed + JSV_GARBAGE_COLLECT = JSV_NATIVE<<1, ///< When garbage collecting, this flag is true IF we should GC! + JSV_IS_RECURSING = JSV_GARBAGE_COLLECT<<1, ///< used to stop recursive loops in jsvTrace + JSV_LOCK_ONE = JSV_IS_RECURSING<<1, + JSV_LOCK_MASK = JSV_LOCK_MAX * JSV_LOCK_ONE, + + + + JSV_ARRAYBUFFERNAME = JSV_NAME|JSV_ARRAYBUFFER, ///< used for indexing into an ArrayBuffer. varData is an INT in this case + JSV_FUNCTION_PARAMETER = JSV_NATIVE | JSV_NAME, ///< this is inside a function, so it should be quite obvious + +} PACKED_FLAGS JsVarFlags; // aiming to get this in 2 bytes! + +/// The amount of bits we must shift to get the number of locks - forced to be a constant +static const int JSV_LOCK_SHIFT = GET_BIT_NUMBER(JSV_LOCK_ONE); + +typedef enum LEX_TYPES { + LEX_EOF = 0, + LEX_ID = 256, + LEX_INT, + LEX_FLOAT, + LEX_STR, + LEX_UNFINISHED_COMMENT, + + LEX_EQUAL, + LEX_TYPEEQUAL, + LEX_NEQUAL, + LEX_NTYPEEQUAL, + LEX_LEQUAL, + LEX_LSHIFT, + LEX_LSHIFTEQUAL, + LEX_GEQUAL, + LEX_RSHIFT, + LEX_RSHIFTUNSIGNED, + LEX_RSHIFTEQUAL, + LEX_RSHIFTUNSIGNEDEQUAL, + LEX_PLUSEQUAL, + LEX_MINUSEQUAL, + LEX_PLUSPLUS, + LEX_MINUSMINUS, + LEX_MULEQUAL, + LEX_DIVEQUAL, + LEX_MODEQUAL, + LEX_ANDEQUAL, + LEX_ANDAND, + LEX_OREQUAL, + LEX_OROR, + LEX_XOREQUAL, + // reserved words +#define LEX_R_LIST_START LEX_R_IF + LEX_R_IF, + LEX_R_ELSE, + LEX_R_DO, + LEX_R_WHILE, + LEX_R_FOR, + LEX_R_BREAK, + LEX_R_CONTINUE, + LEX_R_FUNCTION, + LEX_R_RETURN, + LEX_R_VAR, + LEX_R_THIS, + LEX_R_TRUE, + LEX_R_FALSE, + LEX_R_NULL, + LEX_R_UNDEFINED, + LEX_R_NEW, + LEX_R_IN, + LEX_R_INSTANCEOF, + LEX_R_SWITCH, + LEX_R_CASE, + LEX_R_DEFAULT, + LEX_R_TYPEOF, + LEX_R_VOID, + + LEX_R_LIST_END /* always the last entry */ +} LEX_TYPES; + +// To handle variable size bit fields +#define BITFIELD_DECL(BITFIELD, N) unsigned int BITFIELD[(N+31)/32] +#define BITFIELD_GET(BITFIELD, N) ((BITFIELD[(N)>>5] >> ((N)&31))&1) +#define BITFIELD_SET(BITFIELD, N, VALUE) (BITFIELD[(N)>>5] = (BITFIELD[(N)>>5]& (unsigned int)~(1 << ((N)&31))) | (unsigned int)((VALUE)?(1 << ((N)&31)):0) ) + + +static inline bool isWhitespace(char ch) { + return (ch==' ') || (ch=='\t') || (ch=='\n') || (ch=='\r'); +} + +static inline bool isNumeric(char ch) { + return (ch>='0') && (ch<='9'); +} + +static inline bool isHexadecimal(char ch) { + return ((ch>='0') && (ch<='9')) || + ((ch>='a') && (ch<='f')) || + ((ch>='A') && (ch<='F')); +} +static inline bool isAlpha(char ch) { + return ((ch>='a') && (ch<='z')) || ((ch>='A') && (ch<='Z')) || ch=='_'; +} + + +bool isIDString(const char *s); + +/** escape a character - if it is required. This may return a reference to a static array, +so you can't store the value it returns in a variable and call it again. */ +const char *escapeCharacter(char ch); +/* convert a number in the given radix to an int. if radix=0, autodetect */ +JsVarInt stringToIntWithRadix(const char *s, int radix, bool *hasError); +/* convert hex, binary, octal or decimal string into an int */ +JsVarInt stringToInt(const char *s); + +// forward decl +struct JsLex; +// ------------ + +void jsError(const char *fmt, ...); +void jsErrorInternal(const char *fmt, ...); +void jsErrorAt(const char *message, struct JsLex *lex, int tokenPos); +void jsWarn(const char *fmt, ...); +void jsWarnAt(const char *message, struct JsLex *lex, int tokenPos); +void jsAssertFail(const char *file, int line, const char *expr); + +#ifdef FAKE_STDLIB +void exit(int errcode); +char *strncat(char *dst, const char *src, size_t c); +char *strncpy(char *dst, const char *src, size_t c); +size_t strlen(const char *s); +int strcmp(const char *a, const char *b); +void *memcpy(void *dst, const void *src, size_t size); +void *memset(void *dst, int val, size_t size); +#define RAND_MAX (0xFFFFFFFFU) +unsigned int rand(); +#else +// FIXME: use itoa/ftoa direct - sprintf is huge +//#define itoa(val,str,base) sprintf(str,"%d",(int)val) +//#define ftoa(val,str) sprintf(str,"%f",val) + +#endif + +JsVarFloat stringToFloat(const char *str); + +#ifndef HAS_STDLIB +void itoa(JsVarInt val,char *str,unsigned int base); +#endif +char itoch(int val); +void ftoa(JsVarFloat val,char *str); + +/// Wrap a value so it is always between 0 and size (eg. wrapAround(angle, 360)) +JsVarFloat wrapAround(JsVarFloat val, JsVarFloat size); + + +typedef void (*vcbprintf_callback)(const char *str, void *user_data); +/** Espruino-special printf with a callback + * Supported are: + * %d = int + * %x = int as hex + * %L = JsVarInt + * %Lx = JsVarInt as hex + * %f = JsVarFloat + * %s = string (char *) + * %c = char + * %v = JsVar * + * %p = Pin + * + * Anything else will assert + */ +void vcbprintf(vcbprintf_callback user_callback, void *user_data, const char *fmt, va_list argp); + + +#endif /* JSUTILS_H_ */ diff --git a/components/external/espruino/src/jsvar.c b/components/external/espruino/src/jsvar.c new file mode 100644 index 0000000000..242a8f049b --- /dev/null +++ b/components/external/espruino/src/jsvar.c @@ -0,0 +1,2542 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Variables + * ---------------------------------------------------------------------------- + */ +#include "jsvar.h" +#include "jslex.h" +#include "jsparse.h" +#include "jswrap_json.h" +#include "jsinteractive.h" +#include "jswrapper.h" + + +/** Basically, JsVars are stored in one big array, so save the need for + * lots of memory allocation. On Linux, the arrays are in blocks, so that + * more blocks can be allocated. We can't use realloc on one big block as + * this may change the address of vars that are already locked! + * + */ + +#ifdef RESIZABLE_JSVARS +JsVar **jsVarBlocks = 0; +unsigned int jsVarsSize = 0; +#define JSVAR_BLOCK_SIZE 1024 +#define JSVAR_BLOCK_SHIFT 10 +#else +JsVar jsVars[JSVAR_CACHE_SIZE]; +unsigned int jsVarsSize = JSVAR_CACHE_SIZE; +#endif + +JsVarRef jsVarFirstEmpty; ///< reference of first unused variable (variables are in a linked list) + +/** Return a pointer - UNSAFE for null refs. + * This is effectively a Lock without locking! */ +static inline JsVar *jsvGetAddressOf(JsVarRef ref) { + assert(ref); +#ifdef RESIZABLE_JSVARS + JsVarRef t = ref-1; + return &jsVarBlocks[t>>JSVAR_BLOCK_SHIFT][t&(JSVAR_BLOCK_SIZE-1)]; +#else + return &jsVars[ref-1]; +#endif +} + +JsVar *_jsvGetAddressOf(JsVarRef ref) { + return jsvGetAddressOf(ref); +} + + +// For debugging/testing ONLY - maximum # of vars we are allowed to use +void jsvSetMaxVarsUsed(unsigned int size) { +#ifdef RESIZABLE_JSVARS + assert(size < JSVAR_BLOCK_SIZE); // remember - this is only for DEBUGGING - as such it doesn't use multiple blocks +#else + assert(size < JSVAR_CACHE_SIZE); +#endif + jsVarsSize = size; +} + + +// maps the empty variables in... +void jsvSoftInit() { + jsVarFirstEmpty = 0; + JsVar *lastEmpty = 0; + JsVarRef i; + for (i=1;i<=jsVarsSize;i++) { + if ((jsvGetAddressOf(i)->flags&JSV_VARTYPEMASK) == JSV_UNUSED) { + jsvGetAddressOf(i)->nextSibling = 0; + if (lastEmpty) + lastEmpty->nextSibling = i; + else + jsVarFirstEmpty = i; + lastEmpty = jsvGetAddressOf(i); + } + } +} + +void jsvSoftKill() { +} + +/** This links all JsVars together, so we can have our nice + * linked list of free JsVars. It returns the ref of the first + * item - that we should set jsVarFirstEmpty to (if it is 0) */ +static JsVarRef jsvInitJsVars(JsVarRef start, unsigned int count) { + JsVarRef i; + for (i=start;iflags = JSV_UNUSED; +#ifdef LARGE_MEM + v->this = i; +#endif + // v->locks = 0; // locks is 0 anyway because it is stored in flags + v->nextSibling = (JsVarRef)(i+1); // link to next + } + jsvGetAddressOf((JsVarRef)(start+count-1))->nextSibling = (JsVarRef)0; // set the final one to 0 + return start; +} + +void jsvInit() { +#ifdef RESIZABLE_JSVARS + jsVarsSize = JSVAR_BLOCK_SIZE; + jsVarBlocks = malloc(sizeof(JsVar*)); // just 1 + jsVarBlocks[0] = malloc(sizeof(JsVar) * JSVAR_BLOCK_SIZE); +#endif + + jsVarFirstEmpty = jsvInitJsVars(1/*first*/, jsVarsSize); + jsvSoftInit(); +} + +void jsvKill() { +#ifdef RESIZABLE_JSVARS + + unsigned int i; + for (i=0;i>JSVAR_BLOCK_SHIFT;i++) + free(jsVarBlocks[i]); + free(jsVarBlocks); + jsVarBlocks = 0; + jsVarsSize = 0; +#endif +} + +/** Find or create the ROOT variable item - used mainly + * if recovering from a saved state. */ +JsVar *jsvFindOrCreateRoot() { + JsVarRef i; + for (i=1;i<=jsVarsSize;i++) + if (jsvIsRoot(jsvGetAddressOf(i))) + return jsvLock(i); + + return jsvRef(jsvNewWithFlags(JSV_ROOT)); +} + +/// Get number of memory records (JsVars) used +unsigned int jsvGetMemoryUsage() { + unsigned int usage = 0; + unsigned int i; + for (i=1;i<=jsVarsSize;i++) { + JsVar *v = jsvGetAddressOf((JsVarRef)i); + if ((v->flags&JSV_VARTYPEMASK) != JSV_UNUSED) + usage++; + } + return usage; +} + +/// Get total amount of memory records +unsigned int jsvGetMemoryTotal() { + return jsVarsSize; +} + +/// Try and allocate more memory - only works if RESIZABLE_JSVARS is defined +void jsvSetMemoryTotal(unsigned int jsNewVarCount) { +#ifdef RESIZABLE_JSVARS + if (jsNewVarCount <= jsVarsSize) return; // never allow us to have less! + // When resizing, we just allocate a bunch more + unsigned int oldSize = jsVarsSize; + unsigned int oldBlockCount = jsVarsSize >> JSVAR_BLOCK_SHIFT; + unsigned int newBlockCount = (jsNewVarCount+JSVAR_BLOCK_SIZE-1) >> JSVAR_BLOCK_SHIFT; + jsVarsSize = newBlockCount << JSVAR_BLOCK_SHIFT; + // resize block table + jsVarBlocks = realloc(jsVarBlocks, sizeof(JsVar*)*newBlockCount); + // allocate more blocks + unsigned int i; + for (i=oldBlockCount;iflags&JSV_VARTYPEMASK) != JSV_UNUSED) { + jsiConsolePrintf("USED VAR #%d:",i); + jsvTrace(i, 2); + } + } +} + +bool jsvHasCharacterData(const JsVar *v) { + return jsvIsString(v) || jsvIsStringExt(v); +} + +bool jsvHasStringExt(const JsVar *v) { + return jsvIsString(v) || jsvIsStringExt(v); +} + +bool jsvHasChildren(const JsVar *v) { + return jsvIsFunction(v) || jsvIsObject(v) || jsvIsArray(v) || jsvIsRoot(v); +} + +/// Is this variable a type that uses firstChild to point to a single Variable (ie. it doesn't have multiple children) +bool jsvHasSingleChild(const JsVar *v) { + return jsvIsName(v) || jsvIsArrayBuffer(v) || jsvIsArrayBufferName(v); +} + + + +JsVar *jsvNew() { + if (jsVarFirstEmpty!=0) { + JsVar *v = jsvLock(jsVarFirstEmpty); + jsVarFirstEmpty = v->nextSibling; // move our reference to the next in the free list + assert((v->flags&JSV_VARTYPEMASK) == JSV_UNUSED); + // reset it + v->refs = 0; + //v->locks = 1; + v->flags = JSV_LOCK_ONE; + v->varData.callback = 0; + v->firstChild = 0; + v->lastChild = 0; + v->prevSibling = 0; + v->nextSibling = 0; + // return pointer + return v; + } + /* we don't have memort - second last hope - run garbage collector */ + if (jsvGarbageCollect()) + return jsvNew(); // if it freed something, continue + /* we don't have memory - last hope - ask jsInteractive to try and free some it + may have kicking around */ + if (jsiFreeMoreMemory()) + return jsvNew(); + /* We couldn't claim any more memory by Garbage collecting... */ +#ifdef RESIZABLE_JSVARS + jsvSetMemoryTotal(jsVarsSize*2); + return jsvNew(); +#else + // On a micro, we're screwed. + jsError("Out of Memory!"); + jspSetInterrupted(true); + return 0; +#endif +} + +void jsvFreePtr(JsVar *var) { + /* To be here, we're not supposed to be part of anything else. If + * we were, we'd have been freed by jsvGarbageCollect */ + assert(jsvIsStringExt(var) || (!var->nextSibling && !var->prevSibling)); + + // Names that Link to other things + if (jsvHasSingleChild(var)) { + if (var->firstChild) { + JsVar *child = jsvLock(var->firstChild); + jsvUnRef(child); var->firstChild = 0; // unlink the child + jsvUnLock(child); // unlock should trigger a free + } + } + /* No else, because a String Name may have a single child, but + * also StringExts */ + + /* Now, free children - see jsvar.h comments for how! */ + if (jsvHasStringExt(var)) { + // TODO: make string free this non-recursive + JsVarRef stringDataRef = var->lastChild; + var->lastChild = 0; + if (stringDataRef) { + JsVar *child = jsvLock(stringDataRef); + assert(jsvIsStringExt(child)); + jsvFreePtr(child); + jsvUnLock(child); + } + } else if (jsvHasChildren(var)) { + JsVarRef childref = var->firstChild; + var->firstChild = 0; + var->lastChild = 0; + while (childref) { + JsVar *child = jsvLock(childref); + assert(jsvIsName(child)); + childref = child->nextSibling; + child->prevSibling = 0; + child->nextSibling = 0; + jsvUnRef(child); + jsvUnLock(child); + } + } else { + assert(!var->firstChild); + assert(!var->lastChild); + } + + // free! + var->flags = (var->flags & ~JSV_VARTYPEMASK) | JSV_UNUSED; + // add this to our free list + var->nextSibling = jsVarFirstEmpty; + jsVarFirstEmpty = jsvGetRef(var); +} + +/// Get a reference from a var - SAFE for null vars +JsVarRef jsvGetRef(JsVar *var) { + if (!var) return 0; +#ifdef LARGE_MEM + return var->this; +#else + #ifdef RESIZABLE_JSVARS + unsigned int i, c = jsVarsSize>>JSVAR_BLOCK_SHIFT; + for (i=0;i=jsVarBlocks[i] && var<&jsVarBlocks[i][JSVAR_BLOCK_SIZE]) { + JsVarRef r = (JsVarRef)(1 + (i<locks++; + assert(jsvGetLocks(var) < JSV_LOCK_MAX); + var->flags += JSV_LOCK_ONE; +#ifdef DEBUG + if (jsvGetLocks(var)==0) { + jsError("Too many locks to Variable!"); + //jsPrint("Var #");jsPrintInt(ref);jsPrint("\n"); + } +#endif + return var; +} + +/// Lock this pointer and return a pointer - UNSAFE for null pointer +JsVar *jsvLockAgain(JsVar *var) { + assert(var); + assert(jsvGetLocks(var) < JSV_LOCK_MAX); + var->flags += JSV_LOCK_ONE; +#ifdef DEBUG + if (var->locks==0) { + jsError("Too many locks to Variable!"); + //jsPrint("Var #");jsPrintInt(ref);jsPrint("\n"); + } +#endif + return var; +} + +/// Unlock this variable - this is SAFE for null variables +void jsvUnLock(JsVar *var) { + if (!var) return; + assert(jsvGetLocks(var)>0); + var->flags -= JSV_LOCK_ONE; + /* if we know we're free, then we can just free + * this variable right now. Loops of variables + * are handled by the Garbage Collector. + * Note: we check var->refs first as it is fastest and most likely to be false */ + if (var->refs == 0 && jsvHasRef(var) && jsvGetLocks(var) == 0 && (var->flags&JSV_VARTYPEMASK)!=JSV_UNUSED) { + jsvFreePtr(var); + } +} + +/// Reference - set this variable as used by something +JsVar *jsvRef(JsVar *v) { + assert(v && jsvHasRef(v)); + v->refs++; + return v; +} + +/// Unreference - set this variable as not used by anything +void jsvUnRef(JsVar *var) { + assert(var && var->refs>0 && jsvHasRef(var)); + var->refs--; + // locks are never 0 here, so why bother checking! + assert(jsvGetLocks(var)>0); +} + +/// Helper fn, Reference - set this variable as used by something +JsVarRef jsvRefRef(JsVarRef ref) { + JsVar *v; + assert(ref); + v = jsvLock(ref); + assert(!jsvIsStringExt(v)); + jsvRef(v); + jsvUnLock(v); + return ref; +} + +/// Helper fn, Unreference - set this variable as not used by anything +JsVarRef jsvUnRefRef(JsVarRef ref) { + JsVar *v; + assert(ref); + v = jsvLock(ref); + assert(!jsvIsStringExt(v)); + jsvUnRef(v); + jsvUnLock(v); + return 0; +} + +JsVar *jsvNewFromString(const char *str) { + // Create a var + JsVar *first = jsvNewWithFlags(JSV_STRING); + if (!first) { + jsWarn("Unable to create string as not enough memory"); + return 0; + } + // Now we copy the string, but keep creating new jsVars if we go + // over the end + JsVar *var = jsvLockAgain(first); + while (*str) { + // copy data in + size_t i, l = jsvGetMaxCharactersInVar(var); + for (i=0;ivarData.str[i] = *(str++); + // might as well shove a zero terminator on it if we can + if (ivarData.str[i]=0; + // we've stopped if the string was empty + jsvSetCharactersInVar(var, i); + + // if there is still some left, it's because we filled up our var... + // make a new one, link it in, and unlock the old one. + if (*str) { + JsVar *next = jsvNewWithFlags(JSV_STRING_EXT); + if (!next) { + jsWarn("Truncating string as not enough memory"); + jsvUnLock(var); + return first; + } + // we don't ref, because StringExts are never reffed as they only have one owner (and ALWAYS have an owner) + var->lastChild = jsvGetRef(next); + jsvUnLock(var); + var = next; + } + } + jsvUnLock(var); + // return + return first; +} + +JsVar *jsvNewStringOfLength(unsigned int byteLength) { + // Create a var + JsVar *first = jsvNewWithFlags(JSV_STRING); + if (!first) { + jsWarn("Unable to create string as not enough memory"); + return 0; + } + // Now zero the string, but keep creating new jsVars if we go + // over the end + JsVar *var = jsvLockAgain(first); + while (byteLength>0) { + // copy data in + size_t i, l = jsvGetMaxCharactersInVar(var); + for (i=0;i0;i++,byteLength--) + var->varData.str[i] = 0; + // might as well shove a zero terminator on it if we can + if (ivarData.str[i]=0; + // we've stopped if the string was empty + jsvSetCharactersInVar(var, i); + + // if there is still some left, it's because we filled up our var... + // make a new one, link it in, and unlock the old one. + if (byteLength>0) { + JsVar *next = jsvNewWithFlags(JSV_STRING_EXT); + if (!next) { + jsWarn("Truncating string as not enough memory"); + jsvUnLock(var); + return first; + } + // we don't ref, because StringExts are never reffed as they only have one owner (and ALWAYS have an owner) + var->lastChild = jsvGetRef(next); + jsvUnLock(var); + var = next; + } + } + jsvUnLock(var); + // return + return first; +} + +JsVar *jsvNewFromLexer(struct JsLex *lex, JslCharPos charFrom, JslCharPos charTo) { + // Create a var + JsVar *var = jsvNewFromEmptyString(); + if (!var) { // out of memory + return 0; + } + + jsvAppendStringVar(var, lex->sourceVar, charFrom, (JslCharPos)charTo-charFrom); + return var; +} + +JsVar *jsvNewWithFlags(JsVarFlags flags) { + JsVar *var = jsvNew(); + if (!var) return 0; // no memory + var->flags = (var->flags&(JsVarFlags)(~JSV_VARTYPEMASK)) | (flags&(JsVarFlags)(~JSV_LOCK_MASK)); + return var; +} +JsVar *jsvNewFromInteger(JsVarInt value) { + JsVar *var = jsvNewWithFlags(JSV_INTEGER); + if (!var) return 0; // no memory + var->varData.integer = value; + return var; +} +JsVar *jsvNewFromBool(bool value) { + JsVar *var = jsvNewWithFlags(JSV_BOOLEAN); + if (!var) return 0; // no memory + var->varData.integer = value ? 1 : 0; + return var; +} +JsVar *jsvNewFromFloat(JsVarFloat value) { + JsVar *var = jsvNewWithFlags(JSV_FLOAT); + if (!var) return 0; // no memory + var->varData.floating = value; + return var; +} +JsVar *jsvMakeIntoVariableName(JsVar *var, JsVar *valueOrZero) { + if (!var) return 0; + assert(var->refs==0); // make sure it's unused + var->flags |= JSV_NAME; + if (valueOrZero) + var->firstChild = jsvGetRef(jsvRef(valueOrZero)); + return var; +} + +JsVar *jsvNewFromPin(int pin) { + JsVar *v = jsvNewFromInteger((JsVarInt)pin); + if (v) { + v->flags = (JsVarFlags)((v->flags & ~JSV_VARTYPEMASK) | JSV_PIN); + } + return v; +} + +bool jsvIsBasicVarEqual(JsVar *a, JsVar *b) { + // quick checks + if (a==b) return true; + if (!a || !b) return false; // one of them is undefined + // OPT: would this be useful as compare instead? + assert(jsvIsBasic(a) && jsvIsBasic(b)); + if (jsvIsNumeric(a) && jsvIsNumeric(b)) { + if (jsvIsInt(a)) { + if (jsvIsInt(b)) { + return a->varData.integer == b->varData.integer; + } else { + assert(jsvIsFloat(b)); + return a->varData.integer == b->varData.floating; + } + } else { + assert(jsvIsFloat(a)); + if (jsvIsInt(b)) { + return a->varData.floating == b->varData.integer; + } else { + assert(jsvIsFloat(b)); + return a->varData.floating == b->varData.floating; + } + } + } else if (jsvIsString(a) && jsvIsString(b)) { + JsvStringIterator ita, itb; + jsvStringIteratorNew(&ita, a, 0); + jsvStringIteratorNew(&itb, b, 0); + while (true) { + char a = jsvStringIteratorGetChar(&ita); + char b = jsvStringIteratorGetChar(&itb); + if (a != b) { + jsvStringIteratorFree(&ita); + jsvStringIteratorFree(&itb); + return false; + } + if (!a) { // equal, but end of string + jsvStringIteratorFree(&ita); + jsvStringIteratorFree(&itb); + return true; + } + jsvStringIteratorNext(&ita); + jsvStringIteratorNext(&itb); + } + // we never get here + return false; // make compiler happy + } else { + //TODO: are there any other combinations we should check here?? String v int? + return false; + } +} + +bool jsvIsEqual(JsVar *a, JsVar *b) { + if (jsvIsBasic(a) && jsvIsBasic(b)) + return jsvIsBasicVarEqual(a,b); + return jsvGetRef(a)==jsvGetRef(b); +} + +/// Get a const string representing this variable - if we can. Otherwise return 0 +const char *jsvGetConstString(const JsVar *v) { + if (jsvIsUndefined(v)) { + return "undefined"; + } else if (jsvIsNull(v)) { + return "null"; + } else if (jsvIsBoolean(v)) { + return jsvGetBool(v) ? "true" : "false"; + } else if (jsvIsRoot(v)) { + return "[object Hardware]"; + } else if (jsvIsObject(v)) { + return "[object Object]"; + } + return 0; +} + +/// Return the 'type' of the JS variable (eg. JS's typeof operator) +const char *jsvGetTypeOf(const JsVar *v) { + if (jsvIsNull(v)) return "object"; + if (jsvIsUndefined(v)) return "undefined"; + if (jsvIsFunction(v)) return "function"; + if (jsvIsObject(v) || jsvIsArray(v)) return "object"; + if (jsvIsString(v)) return "string"; + if (jsvIsBoolean(v)) return "boolean"; + if (jsvIsNumeric(v)) return "number"; + return "?"; +} + +/// Save this var as a string to the given buffer, and return how long it was (return val doesn't include terminating 0) +size_t jsvGetString(const JsVar *v, char *str, size_t len) { + const char *s = jsvGetConstString(v); + if (s) { + strncpy(str, s, len); + return strlen(s); + } else if (jsvIsInt(v)) { + itoa(v->varData.integer, str, 10); + return strlen(str); + } else if (jsvIsFloat(v)) { + ftoa(v->varData.floating, str); + return strlen(str); + } else if (jsvHasCharacterData(v)) { + if (jsvIsStringExt(v)) + jsErrorInternal("Calling jsvGetString on a JSV_STRING_EXT"); + size_t l = len; + JsvStringIterator it; + jsvStringIteratorNewConst(&it, v, 0); + while (jsvStringIteratorHasChar(&it)) { + if (l--<=1) { + *str = 0; + jsWarn("jsvGetString overflowed\n"); + jsvStringIteratorFree(&it); + return len; + } + *(str++) = jsvStringIteratorGetChar(&it); + jsvStringIteratorNext(&it); + } + jsvStringIteratorFree(&it); + *str = 0; + return len-l; + } else { + // Try and get as a JsVar string, and try again + JsVar *stringVar = jsvAsString((JsVar*)v, false); // we know we're casting to non-const here + if (stringVar) { + size_t l = jsvGetString(stringVar, str, len); // call again - but this time with converted var + jsvUnLock(stringVar); + return l; + } else { + strncpy(str, "", len); + jsErrorInternal("Variable type cannot be converted to string"); + return 0; + } + } +} + +/// Set the Data in this string. This must JUST overwrite - not extend or shrink +void jsvSetString(JsVar *v, char *str, size_t len) { + assert(jsvHasCharacterData(v)); + assert(len == jsvGetStringLength(v)); + + JsvStringIterator it; + jsvStringIteratorNew(&it, v, 0); + size_t i; + for (i=0;ivarData.integer); + str = jsvNewFromString(buf); + } else if (jsvIsInt(v)) { + char buf[JS_NUMBER_BUFFER_SIZE]; + itoa(v->varData.integer, buf, 10); + str = jsvNewFromString(buf); + } else if (jsvIsFloat(v)) { + char buf[JS_NUMBER_BUFFER_SIZE]; + ftoa(v->varData.floating, buf); + str = jsvNewFromString(buf); + } else if (jsvIsArray(v) || jsvIsArrayBuffer(v)) { + JsVar *filler = jsvNewFromString(","); + str = jsvArrayJoin(v, filler); + jsvUnLock(filler); + } else if (jsvIsFunction(v)) { + str = jsvNewFromEmptyString(); + if (str) jsfGetJSON(v, str); + } else { + jsErrorInternal("Variable type cannot be converted to string"); + str = 0; + } + } + + if (unlockVar) jsvUnLock(v); + return str; +} + +size_t jsvGetStringLength(JsVar *v) { + size_t strLength = 0; + JsVar *var = v; + JsVarRef ref = 0; + + if (!jsvHasCharacterData(v)) return 0; + + while (var) { + JsVarRef refNext = var->lastChild; + strLength += jsvGetCharactersInVar(var); + + // Go to next + if (ref) jsvUnLock(var); // note use of if (ref), not var + ref = refNext; + var = ref ? jsvLock(ref) : 0; + } + if (ref) jsvUnLock(var); // note use of if (ref), not var + return strLength; +} + +// IN A STRING get the number of lines in the string (min=1) +int jsvGetLinesInString(JsVar *v) { + int lines = 1; + JsvStringIterator it; + jsvStringIteratorNew(&it, v, 0); + while (jsvStringIteratorHasChar(&it)) { + if (jsvStringIteratorGetChar(&it)=='\n') lines++; + jsvStringIteratorNext(&it); + } + jsvStringIteratorFree(&it); + return lines; +} + +// IN A STRING Get the number of characters on a line - lines start at 1 +int jsvGetCharsOnLine(JsVar *v, int line) { + int currentLine = 1; + int chars = 0; + JsvStringIterator it; + jsvStringIteratorNew(&it, v, 0); + while (jsvStringIteratorHasChar(&it)) { + if (jsvStringIteratorGetChar(&it)=='\n') { + currentLine++; + if (currentLine > line) break; + } else if (currentLine==line) chars++; + jsvStringIteratorNext(&it); + } + jsvStringIteratorFree(&it); + return chars; +} + +// IN A STRING, get the line and column of the given character. Both values must be non-null +void jsvGetLineAndCol(JsVar *v, int charIdx, int* line, int *col) { + int x = 1; + int y = 1; + int n = 0; + assert(line && col); + + JsvStringIterator it; + jsvStringIteratorNew(&it, v, 0); + while (jsvStringIteratorHasChar(&it)) { + char ch = jsvStringIteratorGetChar(&it); + if (n==charIdx) { + jsvStringIteratorFree(&it); + *line = y; + *col = x; + return; + } + x++; + if (ch=='\n') { + x=1; y++; + } + n++; + jsvStringIteratorNext(&it); + } + jsvStringIteratorFree(&it); + // uh-oh - not found + *line = y; + *col = x; +} + +// IN A STRING, get a character index from a line and column +int jsvGetIndexFromLineAndCol(JsVar *v, int line, int col) { + int x = 1; + int y = 1; + int n = 0; + JsvStringIterator it; + jsvStringIteratorNew(&it, v, 0); + while (jsvStringIteratorHasChar(&it)) { + char ch = jsvStringIteratorGetChar(&it); + if ((y==line && x>=col) || y>line) { + jsvStringIteratorFree(&it); + return (y>line) ? (n-1) : n; + } + x++; + if (ch=='\n') { + x=1; y++; + } + n++; + jsvStringIteratorNext(&it); + } + jsvStringIteratorFree(&it); + return n; +} + +void jsvAppendString(JsVar *var, const char *str) { + assert(jsvIsString(var)); + JsVar *block = jsvLockAgain(var); + // Find the block at end of the string... + while (block->lastChild) { + JsVarRef next = block->lastChild; + jsvUnLock(block); + block = jsvLock(next); + } + // find how full the block is + size_t blockChars = jsvGetCharactersInVar(block); + // now start appending + while (*str) { + // copy data in + size_t i, l=jsvGetMaxCharactersInVar(block); + for (i=blockChars;ivarData.str[i] = *(str++); + } + jsvSetCharactersInVar(block, i); + // if there is still some left, it's because we filled up our var... + // make a new one, link it in, and unlock the old one. + if (*str) { + JsVar *next = jsvNewWithFlags(JSV_STRING_EXT); + if (!next) break; + // we don't ref, because StringExts are never reffed as they only have one owner (and ALWAYS have an owner) + block->lastChild = jsvGetRef(next); + jsvUnLock(block); + block = next; + blockChars=0; // it's new, so empty + } + } + jsvUnLock(block); +} + +void jsvAppendStringBuf(JsVar *var, const char *str, int length) { + assert(jsvIsString(var)); + JsVar *block = jsvLockAgain(var); + // Find the block at end of the string... + while (block->lastChild) { + JsVarRef next = block->lastChild; + jsvUnLock(block); + block = jsvLock(next); + } + // find how full the block is + size_t blockChars = jsvGetCharactersInVar(block); + // now start appending + while (length) { + // copy data in + size_t i, l=jsvGetMaxCharactersInVar(block); + for (i=blockChars;ivarData.str[i] = *(str++); + length--; + } + jsvSetCharactersInVar(block, i); + // if there is still some left, it's because we filled up our var... + // make a new one, link it in, and unlock the old one. + if (length) { + JsVar *next = jsvNewWithFlags(JSV_STRING_EXT); + if (!next) break; + // we don't ref, because StringExts are never reffed as they only have one owner (and ALWAYS have an owner) + block->lastChild = jsvGetRef(next); + jsvUnLock(block); + block = next; + blockChars=0; // it's new, so empty + } + } + jsvUnLock(block); +} + +static void _jsvAppendPrintf(const char *str, void *user_data) { + while (*str) + jsvStringIteratorAppend((JsvStringIterator *)user_data, *(str++)); +} + +void jsvAppendPrintf(JsVar *var, const char *fmt, ...) { + JsvStringIterator it; + jsvStringIteratorNew(&it, var, 0); + jsvStringIteratorGotoEnd(&it); + + va_list argp; + va_start(argp, fmt); + vcbprintf((vcbprintf_callback)&_jsvAppendPrintf,&it, fmt, argp); + va_end(argp); + + jsvStringIteratorFree(&it); +} + +/** Append str to var. Both must be strings. stridx = start char or str, maxLength = max number of characters (can be JSVAPPENDSTRINGVAR_MAXLENGTH). + * stridx can be negative to go from end of string */ +void jsvAppendStringVar(JsVar *var, const JsVar *str, int stridx, int maxLength) { + JsVar *block = jsvLockAgain(var); + assert(jsvIsString(var)); + // Find the block at end of the string... + while (block->lastChild) { + JsVarRef next = block->lastChild; + jsvUnLock(block); + block = jsvLock(next); + } + // find how full the block is + size_t blockChars = jsvGetCharactersInVar(block); + // now start appending + JsvStringIterator it; + jsvStringIteratorNewConst(&it, str, stridx); + while (jsvStringIteratorHasChar(&it) && (maxLength-->0)) { + char ch = jsvStringIteratorGetChar(&it); + if (blockChars >= jsvGetMaxCharactersInVar(block)) { + jsvSetCharactersInVar(block, blockChars); + JsVar *next = jsvNewWithFlags(JSV_STRING_EXT); + if (!next) break; // out of memory + // we don't ref, because StringExts are never reffed as they only have one owner (and ALWAYS have an owner) + block->lastChild = jsvGetRef(next); + jsvUnLock(block); + block = next; + blockChars=0; // it's new, so empty + } + block->varData.str[blockChars++] = ch; + jsvStringIteratorNext(&it); + } + jsvStringIteratorFree(&it); + jsvSetCharactersInVar(block, blockChars); + jsvUnLock(block); +} + +/** Append all of str to var. Both must be strings. */ +void jsvAppendStringVarComplete(JsVar *var, const JsVar *str) { + jsvAppendStringVar(var, str, 0, JSVAPPENDSTRINGVAR_MAXLENGTH); +} + +char jsvGetCharInString(JsVar *v, int idx) { + if (!jsvIsString(v)) return 0; + if (idx<0) idx += (int)jsvGetStringLength(v); // <0 goes from end of string + if (idx<0) return 0; + + JsvStringIterator it; + jsvStringIteratorNew(&it, v, idx); + char ch = jsvStringIteratorGetChar(&it); + jsvStringIteratorFree(&it); + return ch; +} + +/** Does this string contain only Numeric characters? */ +bool jsvIsStringNumeric(const JsVar *var) { + assert(jsvIsString(var)); + JsvStringIterator it; + jsvStringIteratorNewConst(&it, var, 0); // we know it's non const + int chars = 0; + while (jsvStringIteratorHasChar(&it)) { + chars++; + char ch = jsvStringIteratorGetChar(&it); + if (!isNumeric(ch)) { // FIXME: should check for non-integer values (floating point?) + jsvStringIteratorFree(&it); + return false; + } + jsvStringIteratorNext(&it); + } + jsvStringIteratorFree(&it); + return chars>0; +} + +/** Does this string contain only Numeric characters? This is for arrays + * and makes the assertion that int_to_string(string_to_int(var))==var */ +bool jsvIsStringNumericStrict(const JsVar *var) { + assert(jsvIsString(var)); + JsvStringIterator it; + jsvStringIteratorNewConst(&it, var, 0); // we know it's non const + bool hadNonZero = false; + bool hasLeadingZero = false; + int chars = 0; + while (jsvStringIteratorHasChar(&it)) { + chars++; + char ch = jsvStringIteratorGetChar(&it); + if (!isNumeric(ch)) { + // test for leading zero ensures int_to_string(string_to_int(var))==var + jsvStringIteratorFree(&it); + return false; + } + if (!hadNonZero && ch=='0') hasLeadingZero=true; + if (ch!='0') hadNonZero=true; + jsvStringIteratorNext(&it); + } + jsvStringIteratorFree(&it); + return chars>0 && (!hasLeadingZero || chars==1); +} + +JsVarInt jsvGetInteger(const JsVar *v) { + if (!v) return 0; // undefined + /* strtol understands about hex and octal */ + if (jsvIsInt(v) || jsvIsBoolean(v) || jsvIsPin(v) || jsvIsArrayBufferName(v)) return v->varData.integer; + if (jsvIsNull(v)) return 0; + if (jsvIsUndefined(v)) return 0; + if (jsvIsFloat(v)) return (JsVarInt)v->varData.floating; + if (jsvIsString(v) && jsvIsStringNumeric(v)) { + char buf[32]; + jsvGetString(v, buf, sizeof(buf)); + return stringToInt(buf); + } + return 0; +} + +void jsvSetInteger(JsVar *v, JsVarInt value) { + assert(jsvIsInt(v)); + v->varData.integer = value; +} + +bool jsvGetBool(const JsVar *v) { + return jsvGetInteger(v)!=0; +} + +JsVarFloat jsvGetFloat(const JsVar *v) { + if (!v) return NAN; // undefined + if (jsvIsFloat(v)) return v->varData.floating; + if (jsvIsInt(v)) return (JsVarFloat)v->varData.integer; + if (jsvIsNull(v)) return 0; + if (jsvIsString(v) && jsvIsStringNumeric(v)) { + char buf[32]; + jsvGetString(v, buf, sizeof(buf)); + return stringToFloat(buf); + } + return NAN; +} + +/// Convert the given variable to a number +JsVar *jsvAsNumber(JsVar *var) { + if (jsvIsInt(var) || jsvIsFloat(var)) return jsvLockAgain(var); + if (jsvIsBoolean(var) || jsvIsPin(var)) return jsvNewFromInteger(var->varData.integer); + return jsvNewFromFloat(jsvGetFloat(var)); +} + +#ifdef SAVE_ON_FLASH +JsVarInt jsvGetIntegerAndUnLock(JsVar *v) { return _jsvGetIntegerAndUnLock(v); } +JsVarFloat jsvGetFloatAndUnLock(JsVar *v) { return _jsvGetFloatAndUnLock(v); } +bool jsvGetBoolAndUnLock(JsVar *v) { return _jsvGetBoolAndUnLock(v); } +#endif + +/** Get the item at the given location in the array buffer and return the result */ +size_t jsvGetArrayBufferLength(JsVar *arrayBuffer) { + assert(jsvIsArrayBuffer(arrayBuffer)); + return arrayBuffer->varData.arraybuffer.length; +} + +/** Get the item at the given location in the array buffer and return the result */ +JsVar *jsvArrayBufferGet(JsVar *arrayBuffer, JsVarInt idx) { + JsvArrayBufferIterator it; + jsvArrayBufferIteratorNew(&it, arrayBuffer, idx); + JsVar *v = jsvArrayBufferIteratorGetValue(&it); + jsvArrayBufferIteratorFree(&it); + return v; +} + +/** Set the item at the given location in the array buffer */ +void jsvArrayBufferSet(JsVar *arrayBuffer, JsVarInt idx, JsVar *value) { + JsvArrayBufferIterator it; + jsvArrayBufferIteratorNew(&it, arrayBuffer, idx); + jsvArrayBufferIteratorSetValue(&it, value); + jsvArrayBufferIteratorFree(&it); +} + + +/** Given an integer name that points to an arraybuffer or an arraybufferview, evaluate it and return the result */ +JsVar *jsvArrayBufferGetFromName(JsVar *name) { + assert(jsvIsArrayBufferName(name)); + JsVarInt idx = jsvGetInteger(name); + JsVar *arrayBuffer = jsvLock(name->firstChild); + JsVar *value = jsvArrayBufferGet(arrayBuffer, idx); + jsvUnLock(arrayBuffer); + return value; +} + +/** If a is a name skip it and go to what it points to - and so on. + * ALWAYS locks - so must unlock what it returns. It MAY + * return 0. */ +JsVar *jsvSkipName(JsVar *a) { + JsVar *pa = a; + if (!a) return 0; + if (jsvIsArrayBufferName(pa)) return jsvArrayBufferGetFromName(pa); + while (jsvIsName(pa)) { + JsVarRef n = pa->firstChild; + if (pa!=a) jsvUnLock(pa); + if (!n) return 0; + pa = jsvLock(n); + } + if (pa==a) jsvLockAgain(pa); + return pa; +} + +/** If a is a name skip it and go to what it points to. + * ALWAYS locks - so must unlock what it returns. It MAY + * return 0. */ +JsVar *jsvSkipOneName(JsVar *a) { + JsVar *pa = a; + if (!a) return 0; + if (jsvIsArrayBufferName(pa)) return jsvArrayBufferGetFromName(pa); + if (jsvIsName(pa)) { + JsVarRef n = pa->firstChild; + if (pa!=a) jsvUnLock(pa); + if (!n) return 0; + pa = jsvLock(n); + } + if (pa==a) jsvLockAgain(pa); + return pa; +} + +/** If a is a's child is a name skip it and go to what it points to. + * ALWAYS locks - so must unlock what it returns. */ +JsVar *jsvSkipToLastName(JsVar *a) { + assert(jsvIsName(a)); + a = jsvLockAgain(a); + while (true) { + if (!a->firstChild) return a; + JsVar *child = jsvLock(a->firstChild); + if (jsvIsName(child)) { + jsvUnLock(a); + a = child; + } else { + jsvUnLock(child); + return a; + } + } + return 0; // not called +} + + +// Also see jsvIsBasicVarEqual +bool jsvIsStringEqual(JsVar *var, const char *str) { + if (!jsvHasCharacterData(var)) { + assert(jsvIsBasic(var)); + return 0; // not a string so not equal! + } + + JsvStringIterator it; + jsvStringIteratorNew(&it, var, 0); + while (jsvStringIteratorHasChar(&it) && *str) { + if (jsvStringIteratorGetChar(&it) != *str) { + jsvStringIteratorFree(&it); + return false; + } + str++; + jsvStringIteratorNext(&it); + } + bool eq = jsvStringIteratorGetChar(&it)==*str; // should both be 0 if equal + jsvStringIteratorFree(&it); + return eq; +} + + +/** Compare 2 strings, starting from the given character positions. equalAtEndOfString means that + * if one of the strings ends, we treat them as equal. + * For a basic strcmp, do: jsvCompareString(a,b,0,0,false) + * */ +int jsvCompareString(JsVar *va, JsVar *vb, int starta, int startb, bool equalAtEndOfString) { + JsvStringIterator ita, itb; + jsvStringIteratorNew(&ita, va, starta); + jsvStringIteratorNew(&itb, vb, startb); + // step to first positions + while (true) { + int ca = jsvStringIteratorGetCharOrMinusOne(&ita); + int cb = jsvStringIteratorGetCharOrMinusOne(&itb); + + if (ca != cb) { + jsvStringIteratorFree(&ita); + jsvStringIteratorFree(&itb); + if ((ca<0 || cb<0) && equalAtEndOfString) return 0; + return ca - cb; + } + if (ca < 0) { // both equal, but end of string + jsvStringIteratorFree(&ita); + jsvStringIteratorFree(&itb); + return 0; + } + jsvStringIteratorNext(&ita); + jsvStringIteratorNext(&itb); + } + // never get here, but the compiler warns... + return true; +} + +/** Compare 2 integers, >0 if va>vb, <0 if vaflags; + if (!keepAsName) flags &= (JsVarFlags)~JSV_NAME; // make sure this is NOT a name + JsVar *dst = jsvNewWithFlags(flags); + if (!dst) return 0; // out of memory + + memcpy(&dst->varData, &src->varData, sizeof(JsVarData)); + + dst->lastChild = 0; + dst->firstChild = 0; + dst->prevSibling = 0; + dst->nextSibling = 0; + // Copy LINK of what it points to + if (linkChildren && src->firstChild) { + dst->firstChild = jsvRefRef(src->firstChild); + } + // Copy extra string data if there was any + if (jsvHasStringExt(src)) { + // copy extra bits of string if there were any + if (src->lastChild) { + JsVar *child = jsvLock(src->lastChild); + JsVar *childCopy = jsvCopy(child); + if (childCopy) { // could be out of memory + dst->lastChild = jsvGetRef(childCopy); // no ref for stringext + jsvUnLock(childCopy); + } + jsvUnLock(child); + } + } else { + assert(jsvIsBasic(src)); // in case we missed something! + } + return dst; +} + +JsVar *jsvCopy(JsVar *src) { + JsVar *dst = jsvNewWithFlags(src->flags); + if (!dst) return 0; // out of memory + if (!jsvIsStringExt(src)) { + memcpy(&dst->varData, &src->varData, sizeof(JsVarData)); + dst->lastChild = 0; + dst->firstChild = 0; + dst->prevSibling = 0; + dst->nextSibling = 0; + } else { + // stringexts use the extra pointers after varData to store characters + // see jsvGetMaxCharactersInVar + memcpy(&dst->varData, &src->varData, JSVAR_DATA_STRING_MAX_LEN); + dst->lastChild = 0; + } + + // Copy what names point to + if (jsvIsName(src)) { + if (src->firstChild) { + JsVar *child = jsvLock(src->firstChild); + JsVar *childCopy = jsvRef(jsvCopy(child)); + jsvUnLock(child); + if (childCopy) { // could have been out of memory + dst->firstChild = jsvGetRef(childCopy); + jsvUnLock(childCopy); + } + } + } + + if (jsvHasStringExt(src)) { + // copy extra bits of string if there were any + if (src->lastChild) { + JsVar *child = jsvLock(src->lastChild); + JsVar *childCopy = jsvCopy(child); + if (childCopy) {// could be out of memory + dst->lastChild = jsvGetRef(childCopy); // no ref for stringext + jsvUnLock(childCopy); + } + jsvUnLock(child); + } + } else if (jsvHasChildren(src)) { + // Copy children.. + JsVarRef vr; + vr = src->firstChild; + while (vr) { + JsVar *name = jsvLock(vr); + JsVar *child = jsvCopyNameOnly(name, true/*link children*/, true/*keep as name*/); // NO DEEP COPY! + if (child) { // could have been out of memory + jsvAddName(dst, child); + jsvUnLock(child); + } + vr = name->nextSibling; + jsvUnLock(name); + } + } else { + assert(jsvIsBasic(src)); // in case we missed something! + } + + return dst; +} + +void jsvAddName(JsVar *parent, JsVar *namedChild) { + namedChild = jsvRef(namedChild); // ref here VERY important as adding to structure! + assert(jsvIsName(namedChild)); + + if (parent->lastChild) { // we have children already + JsVar *insertAfter = jsvLock(parent->lastChild); + if (jsvIsArray(parent)) { + // we must insert in order - so step back until we get the right place + while (insertAfter && jsvCompareInteger(namedChild, insertAfter)<0) { + JsVarRef prev = insertAfter->prevSibling; + jsvUnLock(insertAfter); + insertAfter = prev ? jsvLock(prev) : 0; + } + } + + if (insertAfter) { + if (insertAfter->nextSibling) { + // great, we're in the middle... + JsVar *insertBefore = jsvLock(insertAfter->nextSibling); + insertBefore->prevSibling = jsvGetRef(namedChild); + namedChild->nextSibling = jsvGetRef(insertBefore); + jsvUnLock(insertBefore); + } else { + // We're at the end - just set up the parent + parent->lastChild = jsvGetRef(namedChild); + } + insertAfter->nextSibling = jsvGetRef(namedChild); + namedChild->prevSibling = jsvGetRef(insertAfter); + jsvUnLock(insertAfter); + } else { // Insert right at the beginning of the array + // Link 2 children together + JsVar *firstChild = jsvLock(parent->firstChild); + firstChild->prevSibling = jsvGetRef(namedChild); + jsvUnLock(firstChild); + + namedChild->nextSibling = parent->firstChild; + // finally set the new child as the first one + parent->firstChild = jsvGetRef(namedChild); + } + } else { // we have no children - just add it + parent->firstChild = parent->lastChild = jsvGetRef(namedChild); + + } +} + +JsVar *jsvAddNamedChild(JsVar *parent, JsVar *child, const char *name) { + JsVar *namedChild = jsvMakeIntoVariableName(jsvNewFromString(name), child); + if (!namedChild) return 0; // Out of memory + jsvAddName(parent, namedChild); + return namedChild; +} + +JsVar *jsvSetNamedChild(JsVar *parent, JsVar *child, const char *name) { + JsVar *namedChild = jsvFindChildFromString(parent, name, true); + if (namedChild) // could be out of memory + return jsvSetValueOfName(namedChild, child); + return 0; +} + +JsVar *jsvSetValueOfName(JsVar *name, JsVar *src) { + assert(name && jsvIsName(name)); + assert(name!=src); // no infinite loops! + // all is fine, so replace the existing child... + /* Existing child may be null in the case of Z = 0 where + * we create 'Z' and pass it down to '=' to have the value + * filled in (or it may be undefined). */ + if (name->firstChild) jsvUnRefRef(name->firstChild); // free existing + if (src) { + // we can link to a name if we want (so can remove the assert!) + name->firstChild = jsvGetRef(jsvRef(src)); + } else + name->firstChild = 0; + return name; +} + +JsVar *jsvFindChildFromString(JsVar *parent, const char *name, bool addIfNotFound) { + /* Pull out first 4 bytes, and ensure that everything + * is 0 padded so that we can do a nice speedy check. */ + char fastCheck[4]; + fastCheck[0] = name[0]; + if (name[0]) { + fastCheck[1] = name[1]; + if (name[1]) { + fastCheck[2] = name[2]; + if (name[2]) { + fastCheck[3] = name[3]; + } else { + fastCheck[3] = 0; + } + } else { + fastCheck[2] = 0; + fastCheck[3] = 0; + } + } else { + fastCheck[1] = 0; + fastCheck[2] = 0; + fastCheck[3] = 0; + } + + assert(jsvHasChildren(parent)); + JsVarRef childref = parent->firstChild; + while (childref) { + // Don't Lock here, just use GetAddressOf - to try and speed up the finding + // TODO: We can do this now, but when/if we move to cacheing vars, it'll break + JsVar *child = jsvGetAddressOf(childref); + if (*(int*)fastCheck==*(int*)child->varData.str && // speedy check of first 4 bytes + jsvIsStringEqual(child, name)) { + // found it! unlock parent but leave child locked + return jsvLockAgain(child); + } + childref = child->nextSibling; + } + + JsVar *child = 0; + if (addIfNotFound) { + child = jsvMakeIntoVariableName(jsvNewFromString(name), 0); + if (child) // could be out of memory + jsvAddName(parent, child); + } + return child; +} + +/** Non-recursive finding */ +JsVar *jsvFindChildFromVar(JsVar *parent, JsVar *childName, bool addIfNotFound) { + JsVar *child; + JsVarRef childref = parent->firstChild; + + while (childref) { + child = jsvLock(childref); + if (jsvIsBasicVarEqual(child, childName)) { + // found it! unlock parent but leave child locked + return child; + } + childref = child->nextSibling; + jsvUnLock(child); + } + + child = 0; + if (addIfNotFound && childName) { + if (childName->refs == 0) { + // Not reffed - great! let's just use it + if (!jsvIsName(childName)) + childName = jsvMakeIntoVariableName(childName, 0); + child = jsvLockAgain(childName); + } else { // it was reffed, we must add a new one + child = jsvMakeIntoVariableName(jsvCopy(childName), 0); + } + jsvAddName(parent, child); + } + return child; +} + +void jsvRemoveChild(JsVar *parent, JsVar *child) { + assert(jsvHasChildren(parent)); + JsVarRef childref = jsvGetRef(child); + // unlink from parent + if (parent->firstChild == childref) + parent->firstChild = child->nextSibling; + if (parent->lastChild == childref) + parent->lastChild = child->prevSibling; + // unlink from child list + if (child->prevSibling) { + JsVar *v = jsvLock(child->prevSibling); + v->nextSibling = child->nextSibling; + jsvUnLock(v); + } + if (child->nextSibling) { + JsVar *v = jsvLock(child->nextSibling); + v->prevSibling = child->prevSibling; + jsvUnLock(v); + } + child->prevSibling = 0; + child->nextSibling = 0; + + jsvUnRef(child); +} + +void jsvRemoveAllChildren(JsVar *parent) { + assert(jsvHasChildren(parent)); + while (parent->firstChild) { + JsVar *v = jsvLock(parent->firstChild); + jsvRemoveChild(parent, v); + jsvUnLock(v); + } +} + +/// Get the named child of an object. If createChild!=0 then create the child +JsVar *jsvObjectGetChild(JsVar *obj, const char *name, JsVarFlags createChild) { + if (!obj) return 0; + assert(jsvHasChildren(obj)); + JsVar *childName = jsvFindChildFromString(obj, name, createChild); + if (!childName && createChild) { + JsVar *child = jsvNewWithFlags(createChild); + jsvSetValueOfName(childName, child); + jsvUnLock(childName); + return child; + } + if (childName) + return jsvSkipNameAndUnLock(childName); + return 0; +} + +/// Set the named child of an object, and return the child (so you can choose to unlock it if you want) +JsVar *jsvObjectSetChild(JsVar *obj, const char *name, JsVar *child) { + assert(jsvHasChildren(obj)); + // child can actually be a name (for instance if it is a named function) + JsVar *childName = jsvFindChildFromString(obj, name, true); + if (!childName) return 0; // out of memory + jsvSetValueOfName(childName, child); + jsvUnLock(childName); + return child; +} + +int jsvGetChildren(JsVar *v) { + //OPT: could length be stored as the value of the array? + int children = 0; + JsVarRef childref = v->firstChild; + while (childref) { + JsVar *child = jsvLock(childref); + children++; + childref = child->nextSibling; + jsvUnLock(child); + } + return children; +} + + +JsVarInt jsvGetArrayLength(JsVar *arr) { + JsVarRef childref = arr->lastChild; + // Just look at last non-string element! + while (childref) { + JsVar *child = jsvLock(childref); + if (jsvIsInt(child)) { + JsVarInt lastIdx = jsvGetInteger(child); + jsvUnLock(child); + return lastIdx+1; + } + // if not an int, keep going + childref = child->prevSibling; + jsvUnLock(child); + } + return 0; +} + +JsVarInt jsvGetLength(JsVar *src) { + if (jsvIsArray(src)) { + return jsvGetArrayLength(src); + } else if (jsvIsArrayBuffer(src)) { + return (JsVarInt)jsvGetArrayBufferLength(src); + } else if (jsvIsString(src)) { + return (JsVarInt)jsvGetStringLength(src); + } else if (jsvIsObject(src) || jsvIsFunction(src)) { + return jsvGetChildren(src); + } else { + return 1; + } +} + +/** Count the amount of JsVars used. Mostly useful for debugging */ +size_t jsvCountJsVarsUsed(JsVar *v) { + size_t count = 1; + if (jsvHasChildren(v)) { + JsVarRef childref = v->firstChild; + while (childref) { + JsVar *child = jsvLock(childref); + count += jsvCountJsVarsUsed(child); + childref = child->nextSibling; + jsvUnLock(child); + } + } + if (jsvHasCharacterData(v)) { + size_t count = 0; + JsVarRef childref = v->lastChild; + while (childref) { + JsVar *child = jsvLock(childref); + count++; + childref = child->lastChild; + jsvUnLock(child); + } + } + if (jsvIsName(v) && v->firstChild) { + JsVar *child = jsvLock(v->firstChild); + count += jsvCountJsVarsUsed(child); + jsvUnLock(child); + } + return count; +} + + +JsVar *jsvGetArrayItem(JsVar *arr, int index) { + JsVarRef childref = arr->firstChild; + while (childref) { + JsVarInt childIndex; + JsVar *child = jsvLock(childref); + + assert(jsvIsInt(child)); + childIndex = jsvGetInteger(child); + if (childIndex == index) { + JsVar *item = child->firstChild ? jsvLock(child->firstChild) : 0; + jsvUnLock(child); + return item; + } + childref = child->nextSibling; + jsvUnLock(child); + } + return 0; // undefined +} + +/// Get the index of the value in the array (matchExact==use pointer, not equality check) +JsVar *jsvGetArrayIndexOf(JsVar *arr, JsVar *value, bool matchExact) { + JsVarRef indexref; + assert(jsvIsArray(arr) || jsvIsObject(arr)); + indexref = arr->firstChild; + while (indexref) { + JsVar *childIndex = jsvLock(indexref); + assert(jsvIsName(childIndex)) + if (childIndex->firstChild) { + JsVar *childValue = jsvLock(childIndex->firstChild); + if ((matchExact && childValue==value) || + (!matchExact && jsvIsBasicVarEqual(childValue, value))) { + jsvUnLock(childValue); + return childIndex; + } + jsvUnLock(childValue); + } else if (jsvIsUndefined(value)) + return childIndex; // both are undefined, so we return the index + indexref = childIndex->nextSibling; + jsvUnLock(childIndex); + } + return 0; // undefined +} + +/// Adds new elements to the end of an array, and returns the new length. initialValue is the item index when no items are currently in the array. +JsVarInt jsvArrayPushWithInitialSize(JsVar *arr, JsVar *value, JsVarInt initialValue) { + assert(jsvIsArray(arr)); + JsVarInt index = jsvGetArrayLength(arr); + if (index==0) index=initialValue; + JsVar *idx = jsvMakeIntoVariableName(jsvNewFromInteger(index), value); + if (!idx) { + jsWarn("Out of memory while appending to array"); + return 0; + } + jsvAddName(arr, idx); + jsvUnLock(idx); + return index+1; // new size +} + +/// Adds new elements to the end of an array, and returns the new length +JsVarInt jsvArrayPush(JsVar *arr, JsVar *value) { + return jsvArrayPushWithInitialSize(arr, value, 0); +} + +/// Adds a new element to the end of an array, unlocks it, and returns the new length +JsVarInt jsvArrayPushAndUnLock(JsVar *arr, JsVar *value) { + JsVarInt l = jsvArrayPushWithInitialSize(arr, value, 0); + jsvUnLock(value); + return l; +} + +/// Removes the last element of an array, and returns that element (or 0 if empty). includes the NAME +JsVar *jsvArrayPop(JsVar *arr) { + assert(jsvIsArray(arr)); + if (arr->lastChild) { + JsVar *child = jsvLock(arr->lastChild); + if (arr->firstChild == arr->lastChild) + arr->firstChild = 0; // if 1 item in array + arr->lastChild = child->prevSibling; // unlink from end of array + jsvUnRef(child); // as no longer in array + if (child->prevSibling) { + JsVar *v = jsvLock(child->prevSibling); + v->nextSibling = 0; + jsvUnLock(v); + } + child->prevSibling = 0; + return child; // and return it + } else { + // no children! + return 0; + } +} + +/// Removes the first element of an array, and returns that element (or 0 if empty). +JsVar *jsvArrayPopFirst(JsVar *arr) { + assert(jsvIsArray(arr)); + if (arr->firstChild) { + JsVar *child = jsvLock(arr->firstChild); + if (arr->firstChild == arr->lastChild) + arr->lastChild = 0; // if 1 item in array + arr->firstChild = child->nextSibling; // unlink from end of array + jsvUnRef(child); // as no longer in array + if (child->nextSibling) { + JsVar *v = jsvLock(child->nextSibling); + v->prevSibling = 0; + jsvUnLock(v); + } + child->nextSibling = 0; + return child; // and return it + } else { + // no children! + return 0; + } +} + +/// Get the last element of an array (does not remove, unlike jsvArrayPop), and returns that element (or 0 if empty) includes the NAME +JsVar *jsvArrayGetLast(JsVar *arr) { + assert(jsvIsArray(arr)); + if (arr->lastChild) { + return jsvLock(arr->lastChild); + } else { // no children! + return 0; + } +} + +/// Join all elements of an array together into a string +JsVar *jsvArrayJoin(JsVar *arr, JsVar *filler) { + JsVar *str = jsvNewFromEmptyString(); + if (!str) return 0; // out of memory + + JsVarInt index = 0; + JsvIterator it; + jsvIteratorNew(&it, arr); + while (jsvIteratorHasElement(&it)) { + JsVar *key = jsvIteratorGetKey(&it); + if (jsvIsInt(key)) { + JsVarInt thisIndex = jsvGetInteger(key); + // add the filler + if (filler) { + while (indexprevSibling; + if (prev) { + JsVar *prevVar = jsvRef(jsvLock(prev)); + jsvSetInteger(idxVar, jsvGetInteger(prevVar)+1); // update index number + prevVar->nextSibling = idxRef; + jsvUnLock(prevVar); + idxVar->prevSibling = prev; + } else { + idxVar->prevSibling = 0; + arr->firstChild = idxRef; + } + beforeIndex->prevSibling = idxRef; + idxVar->nextSibling = jsvGetRef(jsvRef(beforeIndex)); + jsvUnLock(idxVar); + } else + jsvArrayPush(arr, element); +} + +/** Same as jsvMathsOpPtr, but if a or b are a name, skip them + * and go to what they point to. */ +JsVar *jsvMathsOpSkipNames(JsVar *a, JsVar *b, int op) { + JsVar *pa = jsvSkipName(a); + JsVar *pb = jsvSkipName(b); + JsVar *res = jsvMathsOp(pa,pb,op); + jsvUnLock(pa); + jsvUnLock(pb); + return res; +} + + +JsVar *jsvMathsOpError(int op, const char *datatype) { + char buf[JS_ERROR_BUF_SIZE]; + size_t bufpos = 0; + strncpy(&buf[bufpos], "Operation ", JS_ERROR_BUF_SIZE-bufpos); + bufpos=strlen(buf); + jslTokenAsString(op, &buf[bufpos], JS_ERROR_TOKEN_BUF_SIZE-bufpos); + bufpos=strlen(buf); + strncat(&buf[bufpos], " not supported on the ", JS_ERROR_BUF_SIZE-bufpos); + bufpos=strlen(buf); + strncat(&buf[bufpos], datatype, JS_ERROR_BUF_SIZE-bufpos); + bufpos=strlen(buf); + strncat(&buf[bufpos], " datatype", JS_ERROR_BUF_SIZE-bufpos); + jsError(buf); + return 0; +} + +JsVar *jsvMathsOp(JsVar *a, JsVar *b, int op) { + // Type equality check + if (op == LEX_TYPEEQUAL || op == LEX_NTYPEEQUAL) { + // check type first, then call again to check data + bool eql = (a==0) == (b==0); + if (a && b) eql = ((a->flags & JSV_VARTYPEMASK) == + (b->flags & JSV_VARTYPEMASK)); + if (eql) { + JsVar *contents = jsvMathsOp(a,b, LEX_EQUAL); + if (!jsvGetBool(contents)) eql = false; + jsvUnLock(contents); + } + if (op == LEX_TYPEEQUAL) + return jsvNewFromBool(eql); + else + return jsvNewFromBool(!eql); + } + + bool needsInt = op=='&' || op=='|' || op=='^' || op=='%' || op==LEX_LSHIFT || op==LEX_RSHIFT || op==LEX_RSHIFTUNSIGNED; + bool needsNumeric = needsInt || op=='*' || op=='/' || op=='%' || op=='-'; + + // do maths... + if (jsvIsUndefined(a) && jsvIsUndefined(b)) { + if (op == LEX_EQUAL) + return jsvNewFromBool(true); + else if (op == LEX_NEQUAL) + return jsvNewFromBool(false); + else + return 0; // undefined + } else if (needsNumeric || + ((jsvIsNumeric(a) || jsvIsUndefined(a) || jsvIsNull(a)) && + (jsvIsNumeric(b) || jsvIsUndefined(b) || jsvIsNull(b)))) { + if (needsInt || !(jsvIsFloat(a) || jsvIsFloat(b))) { + // use ints + JsVarInt da = jsvGetInteger(a); + JsVarInt db = jsvGetInteger(b); + switch (op) { + case '+': return jsvNewFromInteger(da+db); + case '-': return jsvNewFromInteger(da-db); + case '*': return jsvNewFromInteger(da*db); + case '/': return jsvNewFromFloat((JsVarFloat)da/(JsVarFloat)db); + case '&': return jsvNewFromInteger(da&db); + case '|': return jsvNewFromInteger(da|db); + case '^': return jsvNewFromInteger(da^db); + case '%': return jsvNewFromInteger(da%db); + case LEX_LSHIFT: return jsvNewFromInteger(da << db); + case LEX_RSHIFT: return jsvNewFromInteger(da >> db); + case LEX_RSHIFTUNSIGNED: return jsvNewFromInteger((JsVarInt)(((JsVarIntUnsigned)da) >> db)); + case LEX_EQUAL: return jsvNewFromBool(da==db); + case LEX_NEQUAL: return jsvNewFromBool(da!=db); + case '<': return jsvNewFromBool(da': return jsvNewFromBool(da>db); + case LEX_GEQUAL: return jsvNewFromBool(da>=db); + default: return jsvMathsOpError(op, "Integer"); + } + } else { + // use doubles + JsVarFloat da = jsvGetFloat(a); + JsVarFloat db = jsvGetFloat(b); + switch (op) { + case '+': return jsvNewFromFloat(da+db); + case '-': return jsvNewFromFloat(da-db); + case '*': return jsvNewFromFloat(da*db); + case '/': return jsvNewFromFloat(da/db); + case LEX_EQUAL: return jsvNewFromBool(da==db); + case LEX_NEQUAL: return jsvNewFromBool(da!=db); + case '<': return jsvNewFromBool(da': return jsvNewFromBool(da>db); + case LEX_GEQUAL: return jsvNewFromBool(da>=db); + default: return jsvMathsOpError(op, "Double"); + } + } + } else if ((jsvIsArray(a) || jsvIsObject(a) || + jsvIsArray(b) || jsvIsObject(b)) && + (op == LEX_EQUAL || op==LEX_NEQUAL)) { + bool isArray = jsvIsArray(a); + /* Just check pointers */ + switch (op) { + case LEX_EQUAL: return jsvNewFromBool(a==b); + case LEX_NEQUAL: return jsvNewFromBool(a!=b); + default: return jsvMathsOpError(op, isArray?"Array":"Object"); + } + } else { + JsVar *da = jsvAsString(a, false); + JsVar *db = jsvAsString(b, false); + if (!da || !db) { // out of memory + jsvUnLock(da); + jsvUnLock(db); + return 0; + } + if (op=='+') { + JsVar *v = jsvCopy(da); + // TODO: can we be fancy and not copy da if we know it isn't reffed? what about locks? + if (v) // could be out of memory + jsvAppendStringVarComplete(v, db); + jsvUnLock(da); + jsvUnLock(db); + return v; + } + + int cmp = jsvCompareString(da,db,0,0,false); + jsvUnLock(da); + jsvUnLock(db); + // use strings + switch (op) { + case LEX_EQUAL: return jsvNewFromBool(cmp==0); + case LEX_NEQUAL: return jsvNewFromBool(cmp!=0); + case '<': return jsvNewFromBool(cmp<0); + case LEX_LEQUAL: return jsvNewFromBool(cmp<=0); + case '>': return jsvNewFromBool(cmp>0); + case LEX_GEQUAL: return jsvNewFromBool(cmp>=0); + default: return jsvMathsOpError(op, "String"); + } + } +} + +JsVar *jsvNegateAndUnLock(JsVar *v) { + JsVar *zero = jsvNewFromInteger(0); + JsVar *res = jsvMathsOpSkipNames(zero, v, '-'); + jsvUnLock(zero); + jsvUnLock(v); + return res; +} + +void jsvTraceLockInfo(JsVar *v) { + jsiConsolePrintf("#%d[r%d,l%d] ",jsvGetRef(v),v->refs,jsvGetLocks(v)-1); +} + +/** Get the lowest level at which searchRef appears */ +int _jsvTraceGetLowestLevel(JsVarRef ref, JsVarRef searchRef) { + if (ref == searchRef) return 0; + int found = -1; + JsVar *var = jsvLock(ref); + + // Use IS_RECURSING flag to stop recursion + if (var->flags & JSV_IS_RECURSING) { + jsvUnLock(var); + return -1; + } + var->flags |= JSV_IS_RECURSING; + + if (jsvHasSingleChild(var) && var->firstChild) { + int f = _jsvTraceGetLowestLevel(var->firstChild, searchRef); + if (f>=0 && (found<0 || ffirstChild; + while (childRef) { + int f = _jsvTraceGetLowestLevel(childRef, searchRef); + if (f>=0 && (found<0 || fnextSibling; + jsvUnLock(child); + } + } + + var->flags &= ~JSV_IS_RECURSING; + jsvUnLock(var); + + return found; // searchRef not found +} + +void _jsvTrace(JsVarRef ref, int indent, JsVarRef baseRef, int level) { +#ifdef SAVE_ON_FLASH + jsiConsolePrint("Trace unimplemented in this version.\n"); +#else + int i; + for (i=0;i ");*/ + + + JsVar *var = jsvLock(ref); + jsvTraceLockInfo(var); + + + if (jsvIsName(var)) { + if (jsvIsFunctionParameter(var)) + jsiConsolePrint("Param "); + JsVar *str = jsvAsString(var, false); + if (jsvIsInt(var)) { + jsiConsolePrintf("Name: int %v ", str); + } else if (jsvIsFloat(var)) { + jsiConsolePrintf("Name: flt %v ", str); + } else if (jsvIsString(var) || jsvIsFunctionParameter(var)) { + jsiConsolePrintf("Name: '%v' ", str); + } else if (jsvIsArrayBufferName(var)) { + jsiConsolePrintf("ArrayBufferName[%d] ", jsvGetInteger(var)); + } else { + assert(0); + } + jsvUnLock(str); + // go to what the name points to + ref = var->firstChild; + jsvUnLock(var); + if (ref) { + level++; + int lowestLevel = _jsvTraceGetLowestLevel(baseRef, ref); + /*jsiConsolePrint("<"); + jsiConsolePrintInt(level); + jsiConsolePrint(":"); + jsiConsolePrintInt(lowestLevel); + jsiConsolePrint("> ");*/ + + var = jsvLock(ref); + jsvTraceLockInfo(var); + if (lowestLevel < level) { + // If this data is available elsewhere in the tree (but nearer the root) + // then don't print it. This makes the dump significantly more readable! + // It also stops us getting in recursive loops ... + jsiConsolePrint("...\n"); + jsvUnLock(var); + return; + } + + } else { + jsiConsolePrint("undefined\n"); + return; + } + } + + if (jsvIsName(var)) { + jsiConsolePrint("\n"); + _jsvTrace(jsvGetRef(var), indent+2, baseRef, level+1); + jsvUnLock(var); + return; + } + if (jsvIsObject(var)) jsiConsolePrint("Object {"); + else if (jsvIsArray(var)) jsiConsolePrint("Array ["); + else if (jsvIsPin(var)) jsiConsolePrint("Pin "); + else if (jsvIsInt(var)) jsiConsolePrint("Integer "); + else if (jsvIsBoolean(var)) jsiConsolePrint("Bool "); + else if (jsvIsFloat(var)) jsiConsolePrint("Double "); + else if (jsvIsString(var)) jsiConsolePrint("String "); + else if (jsvIsArrayBuffer(var)) { + jsiConsolePrintf("%s ", jswGetBasicObjectName(var)); // way to get nice name + _jsvTrace(var->firstChild, indent+1, baseRef, level+1); + jsvUnLock(var); + return; + } else if (jsvIsFunction(var)) jsiConsolePrint("Function {"); + else { + jsiConsolePrintf("Flags %d\n", var->flags & (JsVarFlags)~(JSV_LOCK_MASK)); + } + + if (!jsvIsObject(var) && !jsvIsArray(var) && !jsvIsFunction(var)) { + JsVar *str = jsvAsString(var, false); + if (str) { + JsvStringIterator it; + jsvStringIteratorNew(&it, str, 0); + while (jsvStringIteratorHasChar(&it)) { + char ch = jsvStringIteratorGetChar(&it); + jsiConsolePrint(escapeCharacter(ch)); + jsvStringIteratorNext(&it); + } + jsvStringIteratorFree(&it); + jsvUnLock(str); + } + } + + if (jsvHasStringExt(var)) { + if (!jsvIsStringExt(var) && var->firstChild) { // stringext don't have children (the use them for chars) + jsiConsolePrint("( Multi-block string "); + JsVarRef child = var->firstChild; + while (child) { + JsVar *childVar = jsvLock(child); + jsvTraceLockInfo(childVar); + child = childVar->firstChild; + jsvUnLock(childVar); + } + jsiConsolePrint(")\n"); + } else + jsiConsolePrint("\n"); + } else { + JsVarRef child = var->firstChild; + jsiConsolePrint("\n"); + // dump children + while (child) { + JsVar *childVar; + _jsvTrace(child, indent+2, baseRef, level+1); + childVar = jsvLock(child); + child = childVar->nextSibling; + jsvUnLock(childVar); + } + } + + if (jsvIsObject(var) || jsvIsFunction(var) || jsvIsArray(var)) { + int i; + for (i=0;iflags &= (JsVarFlags)~JSV_GARBAGE_COLLECT; + + if (jsvHasCharacterData(var)) { + if (var->lastChild) { + JsVar *childVar = jsvGetAddressOf(var->lastChild); + if (childVar->flags & JSV_GARBAGE_COLLECT) + jsvGarbageCollectMarkUsed(childVar); + } + } + // intentionally no else + if (jsvHasSingleChild(var)) { + if (var->firstChild) { + JsVar *childVar = jsvGetAddressOf(var->firstChild); + if (childVar->flags & JSV_GARBAGE_COLLECT) + jsvGarbageCollectMarkUsed(childVar); + } + } else if (jsvHasChildren(var)) { + JsVarRef child = var->firstChild; + while (child) { + JsVar *childVar; + childVar = jsvGetAddressOf(child); + if (childVar->flags & JSV_GARBAGE_COLLECT) + jsvGarbageCollectMarkUsed(childVar); + child = childVar->nextSibling; + } + } +} + +/** Run a garbage collection sweep - return true if things have been freed */ +bool jsvGarbageCollect() { + JsVarRef i; + // clear garbage collect flags + for (i=1;i<=jsVarsSize;i++) { + JsVar *var = jsvGetAddressOf(i); + if ((var->flags&JSV_VARTYPEMASK) != JSV_UNUSED) // if it is not unused + var->flags |= (JsVarFlags)JSV_GARBAGE_COLLECT; + } + // recursively add 'native' vars + for (i=1;i<=jsVarsSize;i++) { + JsVar *var = jsvGetAddressOf(i); + if ((var->flags & JSV_GARBAGE_COLLECT) && // not already GC'd + jsvGetLocks(var)>0) // or it is locked + jsvGarbageCollectMarkUsed(var); + } + // now sweep for things that we can GC! + bool freedSomething = false; + for (i=1;i<=jsVarsSize;i++) { + JsVar *var = jsvGetAddressOf(i); + if (var->flags & JSV_GARBAGE_COLLECT) { + freedSomething = true; + // free! + var->flags = JSV_UNUSED; + // add this to our free list + var->nextSibling = jsVarFirstEmpty; + jsVarFirstEmpty = jsvGetRef(var); + } + } + return freedSomething; +} + +/** Remove whitespace to the right of a string - on MULTIPLE LINES */ +JsVar *jsvStringTrimRight(JsVar *srcString) { + JsvStringIterator src, dst; + JsVar *dstString = jsvNewFromEmptyString(); + jsvStringIteratorNew(&src, srcString, 0); + jsvStringIteratorNew(&dst, dstString, 0); + int spaces = 0; + while (jsvStringIteratorHasChar(&src)) { + char ch = jsvStringIteratorGetChar(&src); + jsvStringIteratorNext(&src); + + if (ch==' ') spaces++; + else if (ch=='\n') { + spaces = 0; + jsvStringIteratorAppend(&dst, ch); + } else { + for (;spaces>0;spaces--) + jsvStringIteratorAppend(&dst, ' '); + jsvStringIteratorAppend(&dst, ch); + } + } + jsvStringIteratorFree(&src); + jsvStringIteratorFree(&dst); + return dstString; +} + +/// If v is the key of a function, return true if it is internal and shouldn't be visible to the user +bool jsvIsInternalFunctionKey(JsVar *v) { + return (jsvIsString(v) && ( + v->varData.str[0]==JS_HIDDEN_CHAR) + ) || + jsvIsFunctionParameter(v); +} + +/// If v is the key of an object, return true if it is internal and shouldn't be visible to the user +bool jsvIsInternalObjectKey(JsVar *v) { + return (jsvIsString(v) && ( + v->varData.str[0]==JS_HIDDEN_CHAR || + jsvIsStringEqual(v, JSPARSE_INHERITS_VAR) || + jsvIsStringEqual(v, JSPARSE_CONSTRUCTOR_VAR) + )); +} + +// -------------------------------------------------------------------------------------------- + +void jsvStringIteratorNew(JsvStringIterator *it, JsVar *str, int startIdx) { + assert(jsvHasCharacterData(str)); + it->var = jsvLockAgain(str); + it->charsInVar = jsvGetCharactersInVar(str); + it->charIdx = (size_t)startIdx; + it->index = (size_t)startIdx; + while (it->charIdx>0 && it->charIdx >= it->charsInVar) { + it->charIdx -= it->charsInVar; + if (it->var) { + if (it->var->lastChild) { + JsVar *next = jsvLock(it->var->lastChild); + jsvUnLock(it->var); + it->var = next; + it->charsInVar = jsvGetCharactersInVar(it->var); + } else { + jsvUnLock(it->var); + it->var = 0; + it->charsInVar = 0; + return; // get out of loop + } + } + } +} + +void jsvStringIteratorNext(JsvStringIterator *it) { + jsvStringIteratorNextInline(it); +} + +void jsvStringIteratorGotoEnd(JsvStringIterator *it) { + assert(it->var); + while (it->var->lastChild) { + it->index += it->charsInVar; + JsVar *next = jsvLock(it->var->lastChild); + jsvUnLock(it->var); + it->var = next; + it->charsInVar = jsvGetCharactersInVar(it->var); + } + if (it->charsInVar) it->charIdx = it->charsInVar-1; + else it->charIdx = 0; +} + +void jsvStringIteratorAppend(JsvStringIterator *it, char ch) { + if (!it->var) return; + if (it->charsInVar>0) { + assert(it->charIdx+1 == it->charsInVar /* check at end */); + it->charIdx++; + it->index++; + } else + assert(it->charIdx == 0); + if (it->charIdx >= jsvGetMaxCharactersInVar(it->var)) { + assert(!it->var->lastChild); + JsVar *next = jsvNewWithFlags(JSV_STRING_EXT); + if (!next) return; // out of memory + // we don't ref, because StringExts are never reffed as they only have one owner (and ALWAYS have an owner) + it->var->lastChild = jsvGetRef(next); + jsvUnLock(it->var); + it->var = next; + + it->charIdx = 0; // it's new, so empty + } + + it->var->varData.str[it->charIdx] = ch; + it->charsInVar = it->charIdx+1; + jsvSetCharactersInVar(it->var, it->charsInVar); +} + + +// -------------------------------------------------------------------------------------------- +void jsvArrayBufferIteratorNew(JsvArrayBufferIterator *it, JsVar *arrayBuffer, JsVarInt index) { + assert(jsvIsArrayBuffer(arrayBuffer)); + it->index = index; + it->type = arrayBuffer->varData.arraybuffer.type; + it->byteLength = arrayBuffer->varData.arraybuffer.length * JSV_ARRAYBUFFER_GET_SIZE(it->type); + it->byteOffset = arrayBuffer->varData.arraybuffer.byteOffset; + JsVar *arrayBufferData = jsvLock(arrayBuffer->firstChild); + while (jsvIsArrayBuffer(arrayBufferData)) { + JsVar *s = jsvLock(arrayBufferData->firstChild); + jsvUnLock(arrayBufferData); + arrayBufferData = s; + } + assert(jsvIsString(arrayBufferData)); + + it->byteLength += it->byteOffset; // because we'll check if we have more bytes using this + it->byteOffset = it->byteOffset + index*JSV_ARRAYBUFFER_GET_SIZE(it->type); + if (it->byteOffset<0 || (it->byteLength>=0 && it->byteOffset>=(it->byteLength+1-JSV_ARRAYBUFFER_GET_SIZE(it->type)))) { + jsvUnLock(arrayBufferData); + it->type = ARRAYBUFFERVIEW_UNDEFINED; + return; + } + jsvStringIteratorNew(&it->it, arrayBufferData, (int)it->byteOffset); + jsvUnLock(arrayBufferData); + it->hasAccessedElement = false; +} + +static void jsvArrayBufferIteratorGetValueData(JsvArrayBufferIterator *it, char *data) { + if (it->type == ARRAYBUFFERVIEW_UNDEFINED) return; + assert(!it->hasAccessedElement); // we just haven't implemented this case yet + unsigned int i,dataLen = JSV_ARRAYBUFFER_GET_SIZE(it->type); + for (i=0;iit); + if (dataLen!=1) jsvStringIteratorNext(&it->it); + } + if (dataLen!=1) it->hasAccessedElement = true; +} + +static JsVarInt jsvArrayBufferIteratorDataToInt(JsvArrayBufferIterator *it, char *data) { + unsigned int dataLen = JSV_ARRAYBUFFER_GET_SIZE(it->type); + JsVarInt v = 0; + if (dataLen==1) v = *(char*)data; + else if (dataLen==2) v = *(short*)data; + else if (dataLen==4) v = *(int*)data; + else if (dataLen==8) v = *(long long*)data; + else assert(0); + if ((!JSV_ARRAYBUFFER_IS_SIGNED(it->type)) && v<0) + v += 1 << (8*dataLen); + return v; +} + +static JsVarFloat jsvArrayBufferIteratorDataToFloat(JsvArrayBufferIterator *it, char *data) { + unsigned int dataLen = JSV_ARRAYBUFFER_GET_SIZE(it->type); + JsVarFloat v = 0; + if (dataLen==4) v = *(float*)data; + else if (dataLen==8) v = *(double*)data; + else assert(0); + return v; +} + +JsVar *jsvArrayBufferIteratorGetValue(JsvArrayBufferIterator *it) { + if (it->type == ARRAYBUFFERVIEW_UNDEFINED) return 0; + char data[8]; + jsvArrayBufferIteratorGetValueData(it, data); + if (JSV_ARRAYBUFFER_IS_FLOAT(it->type)) { + return jsvNewFromFloat(jsvArrayBufferIteratorDataToFloat(it, data)); + } else { + return jsvNewFromInteger(jsvArrayBufferIteratorDataToInt(it, data)); + } +} + +JsVarInt jsvArrayBufferIteratorGetIntegerValue(JsvArrayBufferIterator *it) { + if (it->type == ARRAYBUFFERVIEW_UNDEFINED) return 0; + char data[8]; + jsvArrayBufferIteratorGetValueData(it, data); + if (JSV_ARRAYBUFFER_IS_FLOAT(it->type)) { + return (JsVarInt)jsvArrayBufferIteratorDataToFloat(it, data); + } else { + return jsvArrayBufferIteratorDataToInt(it, data); + } +} + +JsVarFloat jsvArrayBufferIteratorGetFloatValue(JsvArrayBufferIterator *it) { + if (it->type == ARRAYBUFFERVIEW_UNDEFINED) return 0; + char data[8]; + jsvArrayBufferIteratorGetValueData(it, data); + if (JSV_ARRAYBUFFER_IS_FLOAT(it->type)) { + return jsvArrayBufferIteratorDataToFloat(it, data); + } else { + return (JsVarFloat)jsvArrayBufferIteratorDataToInt(it, data); + } +} + +void jsvArrayBufferIteratorSetValue(JsvArrayBufferIterator *it, JsVar *value) { + if (it->type == ARRAYBUFFERVIEW_UNDEFINED) return; + assert(!it->hasAccessedElement); // we just haven't implemented this case yet + char data[8]; + unsigned int i,dataLen = JSV_ARRAYBUFFER_GET_SIZE(it->type); + + if (JSV_ARRAYBUFFER_IS_FLOAT(it->type)) { + JsVarFloat v = jsvGetFloat(value); ; + if (dataLen==4) { float f = (float)v; memcpy(data,&f,dataLen); } + else if (dataLen==8) { double f = (double)v; memcpy(data,&f,dataLen); } + else assert(0); + } else { + JsVarInt v = jsvGetInteger(value); + // we don't care about sign when writing - as it gets truncated + if (dataLen==1) { char c = (char)v; memcpy(data,&c,dataLen); } + else if (dataLen==2) { short c = (short)v; memcpy(data,&c,dataLen); } + else if (dataLen==4) { int c = (int)v; memcpy(data,&c,dataLen); } + else if (dataLen==8) { long long c = (long long)v; memcpy(data,&c,dataLen); } + else assert(0); + } + + for (i=0;iit, data[i]); + if (dataLen!=1) jsvStringIteratorNext(&it->it); + } + if (dataLen!=1) it->hasAccessedElement = true; +} + +void jsvArrayBufferIteratorSetIntegerValue(JsvArrayBufferIterator *it, JsVarInt value) { + // FIXME: Do this without the allocation! + JsVar *val = jsvNewFromInteger(value); + jsvArrayBufferIteratorSetValue(it, val); + jsvUnLock(val); +} + +JsVar* jsvArrayBufferIteratorGetIndex(JsvArrayBufferIterator *it) { + return jsvNewFromInteger(it->index); +} + +bool jsvArrayBufferIteratorHasElement(JsvArrayBufferIterator *it) { + if (it->type == ARRAYBUFFERVIEW_UNDEFINED) return false; + if (it->hasAccessedElement) return true; + if (it->byteLength>=0) + return it->byteOffset <= (it->byteLength-JSV_ARRAYBUFFER_GET_SIZE(it->type)); + else + return jsvStringIteratorHasChar(&it->it); +} + +void jsvArrayBufferIteratorNext(JsvArrayBufferIterator *it) { + it->index++; + it->byteOffset += JSV_ARRAYBUFFER_GET_SIZE(it->type); + if (!it->hasAccessedElement) { + unsigned int i,dataLen = JSV_ARRAYBUFFER_GET_SIZE(it->type); + for (i=0;iit); + } else + it->hasAccessedElement = false; +} + +void jsvArrayBufferIteratorFree(JsvArrayBufferIterator *it) { + if (it->type == ARRAYBUFFERVIEW_UNDEFINED) return; + jsvStringIteratorFree(&it->it); +} +// -------------------------------------------------------------------------------------------- +/* General Purpose iterator, for Strings, Arrays, Objects, Typed Arrays */ + +void jsvIteratorNew(JsvIterator *it, JsVar *obj) { + if (jsvIsArray(obj)) { + it->type = JSVI_ARRAY; + jsvArrayIteratorNew(&it->it.arr, obj); + } else if (jsvIsObject(obj) || jsvIsFunction(obj)) { + it->type = JSVI_OBJECT; + jsvObjectIteratorNew(&it->it.obj, obj); + } else if (jsvIsArrayBuffer(obj)) { + it->type = JSVI_ARRAYBUFFER; + jsvArrayBufferIteratorNew(&it->it.buf, obj, 0); + } else if (jsvHasCharacterData(obj)) { + it->type = JSVI_STRING; + jsvStringIteratorNew(&it->it.str, obj, 0); + } else assert(0); +} + +JsVar *jsvIteratorGetKey(JsvIterator *it) { + switch (it->type) { + case JSVI_ARRAY : return jsvArrayIteratorGetIndex(&it->it.arr); + case JSVI_OBJECT : return jsvObjectIteratorGetKey(&it->it.obj); + case JSVI_STRING : return jsvNewFromInteger((JsVarInt)jsvStringIteratorGetIndex(&it->it.str)); + case JSVI_ARRAYBUFFER : return jsvArrayBufferIteratorGetIndex(&it->it.buf); + default: assert(0); return 0; + } +} + +JsVar *jsvIteratorGetValue(JsvIterator *it) { + switch (it->type) { + case JSVI_ARRAY : return jsvArrayIteratorGetElement(&it->it.arr); + case JSVI_OBJECT : return jsvObjectIteratorGetValue(&it->it.obj); + case JSVI_STRING : { char buf[2] = {jsvStringIteratorGetChar(&it->it.str),0}; return jsvNewFromString(buf); } + case JSVI_ARRAYBUFFER : return jsvArrayBufferIteratorGetValue(&it->it.buf); + default: assert(0); return 0; + } +} + +JsVarInt jsvIteratorGetIntegerValue(JsvIterator *it) { + switch (it->type) { + case JSVI_ARRAY : return jsvGetIntegerAndUnLock(jsvArrayIteratorGetElement(&it->it.arr)); + case JSVI_OBJECT : return jsvGetIntegerAndUnLock(jsvObjectIteratorGetValue(&it->it.obj)); + case JSVI_STRING : return (JsVarInt)jsvStringIteratorGetChar(&it->it.str); + case JSVI_ARRAYBUFFER : return jsvArrayBufferIteratorGetIntegerValue(&it->it.buf); + default: assert(0); return 0; + } +} + +bool jsvIteratorHasElement(JsvIterator *it) { + switch (it->type) { + case JSVI_ARRAY : return jsvArrayIteratorHasElement(&it->it.arr); + case JSVI_OBJECT : return jsvObjectIteratorHasElement(&it->it.obj); + case JSVI_STRING : return jsvStringIteratorHasChar(&it->it.str); + case JSVI_ARRAYBUFFER : return jsvArrayBufferIteratorHasElement(&it->it.buf); + default: assert(0); return 0; + } +} + +void jsvIteratorNext(JsvIterator *it) { + switch (it->type) { + case JSVI_ARRAY : jsvArrayIteratorNext(&it->it.arr); break; + case JSVI_OBJECT : jsvObjectIteratorNext(&it->it.obj); break; + case JSVI_STRING : jsvStringIteratorNext(&it->it.str); break; + case JSVI_ARRAYBUFFER : jsvArrayBufferIteratorNext(&it->it.buf); break; + default: assert(0); break; + } +} +void jsvIteratorFree(JsvIterator *it) { + switch (it->type) { + case JSVI_ARRAY : jsvArrayIteratorFree(&it->it.arr); break; + case JSVI_OBJECT : jsvObjectIteratorFree(&it->it.obj); break; + case JSVI_STRING : jsvStringIteratorFree(&it->it.str); break; + case JSVI_ARRAYBUFFER : jsvArrayBufferIteratorFree(&it->it.buf); break; + default: assert(0); break; + } +} + + diff --git a/components/external/espruino/src/jsvar.h b/components/external/espruino/src/jsvar.h new file mode 100644 index 0000000000..74d85a6ca3 --- /dev/null +++ b/components/external/espruino/src/jsvar.h @@ -0,0 +1,612 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Variables + * ---------------------------------------------------------------------------- + */ +#ifndef JSVAR_H_ +#define JSVAR_H_ + +#include "jsutils.h" + + +typedef void (*JsCallback)(JsVarRef var) +#ifdef SDCC +__reentrant +#endif +; + +/** To avoid confusion - JsVarRefCounter should be big enough + * to store as many refs as can possibly be created - so it's + * safe just to set it to the same size as JsVarRef. However + * it is NOT a reference itself. + */ +typedef JsVarRef JsVarRefCounter; + +typedef enum { + ARRAYBUFFERVIEW_UNDEFINED = 0, + ARRAYBUFFERVIEW_ARRAYBUFFER = 1 | 64, ///< Basic ArrayBuffer type + + ARRAYBUFFERVIEW_MASK_SIZE = 15, + ARRAYBUFFERVIEW_SIGNED = 16, + ARRAYBUFFERVIEW_FLOAT = 32, + + ARRAYBUFFERVIEW_UINT8 = 1, + ARRAYBUFFERVIEW_INT8 = 1 | ARRAYBUFFERVIEW_SIGNED, + ARRAYBUFFERVIEW_UINT16 = 2, + ARRAYBUFFERVIEW_INT16 = 2 | ARRAYBUFFERVIEW_SIGNED, + ARRAYBUFFERVIEW_UINT32 = 4, + ARRAYBUFFERVIEW_INT32 = 4 | ARRAYBUFFERVIEW_SIGNED, + ARRAYBUFFERVIEW_FLOAT32 = 4 | ARRAYBUFFERVIEW_FLOAT, + ARRAYBUFFERVIEW_FLOAT64 = 8 | ARRAYBUFFERVIEW_FLOAT, +} PACKED_FLAGS JsVarDataArrayBufferViewType; +#define JSV_ARRAYBUFFER_GET_SIZE(T) ((T)&ARRAYBUFFERVIEW_MASK_SIZE) +#define JSV_ARRAYBUFFER_IS_SIGNED(T) (((T)&ARRAYBUFFERVIEW_SIGNED)!=0) +#define JSV_ARRAYBUFFER_IS_FLOAT(T) (((T)&ARRAYBUFFERVIEW_FLOAT)!=0) + +#define JSV_ARRAYBUFFER_MAX_LENGTH 65535 + +typedef struct { + unsigned short byteOffset; + unsigned short length; + JsVarDataArrayBufferViewType type; +} PACKED_FLAGS JsVarDataArrayBufferView; + +typedef union { + char str[JSVAR_DATA_STRING_LEN]; ///< The contents of this variable if it is a string + /* NOTE: For str above, we INTENTIONALLY OVERFLOW str (and hence data) in the case of STRING_EXTS + * to overwrite 3 references in order to grab another 6 bytes worth of string data */ + // TODO do some magic with union/structs in order to make sure we don't intentionally write off the end of arrays + JsVarInt integer; ///< The contents of this variable if it is an int + JsVarFloat floating; ///< The contents of this variable if it is a double + JsCallback callback; ///< Callback for native functions, or 0 + JsVarDataArrayBufferView arraybuffer; ///< information for array buffer views. +} PACKED_FLAGS JsVarData; + +typedef struct { +#ifdef LARGE_MEM + JsVarRef this; ///< The reference of this variable itself (so we can get back) +#endif + JsVarFlags flags; ///< the flags determine the type of the variable - int/double/string/etc. + + JsVarData varData; + /* NOTE: WE INTENTIONALLY OVERFLOW data in the case of STRING_EXTS + * to overwrite the following 3 references in order to grab another + * 6 bytes worth of string data */ + + /* For Variable NAMES (e.g. Object/Array keys) these store actual next/previous pointers for a linked list + * For STRING_EXT - extra characters + * Not used for other stuff + */ + JsVarRef nextSibling; + JsVarRef prevSibling; + + JsVarRefCounter refs; ///< The number of references held to this - used for automatic garbage collection. NOT USED for STRINGEXT though (it is just extra characters) + + /** + * For OBJECT/ARRAY/FUNCTION - this is the first child + * For NAMES and REF - this is a link to the variable it points to + * For STRING_EXT - extra character data (NOT a link) + * For ARRAYBUFFER - a link to a string containing the data for the array buffer * + */ + JsVarRef firstChild; + + /** + * For OBJECT/ARRAY/FUNCTION - this is the last child + * For STRINGS/STRING_EXT/NAME+STRING - this is a link to more string data if it is needed + * For REF - this is the 'parent' that the firstChild is a member of + */ + JsVarRef lastChild; +} PACKED_FLAGS JsVar; + +/* We have a few different types: + * + * OBJECT/ARRAY - uses firstChild/lastChild to link to NAMEs. + * BUILT-IN OBJECT - as above, but we use varData to store the name as well. This means built in object names must be LESS THAN 8 CHARACTERS + * FUNCTION - uses firstChild/lastChild to link to NAMEs, and callback is used + * NAME - use nextSibling/prevSibling linking to other NAMEs, and firstChild to link to a Variable of some kind + * STRING - use firstChild to link to other STRINGs if String value is too long + * INT/DOUBLE - firstChild never used + */ + +static inline unsigned char jsvGetLocks(JsVar *v) { return (unsigned char)((v->flags>>JSV_LOCK_SHIFT) & JSV_LOCK_MAX); } + +// For debugging/testing ONLY - maximum # of vars we are allowed to use +void jsvSetMaxVarsUsed(unsigned int size); + +// Init/kill vars as a whole +void jsvInit(); +void jsvKill(); +void jsvSoftInit(); ///< called when loading from flash +void jsvSoftKill(); ///< called when saving to flash +JsVar *jsvFindOrCreateRoot(); ///< Find or create the ROOT variable item - used mainly if recovering from a saved state. +unsigned int jsvGetMemoryUsage(); ///< Get number of memory records (JsVars) used +unsigned int jsvGetMemoryTotal(); ///< Get total amount of memory records +bool jsvIsMemoryFull(); ///< Get whether memory is full or not +void jsvShowAllocated(); ///< Show what is still allocated, for debugging memory problems +/// Try and allocate more memory - only works if RESIZABLE_JSVARS is defined +void jsvSetMemoryTotal(unsigned int jsNewVarCount); + + +// Note that jsvNew* don't REF a variable for you, but the do LOCK it +JsVar *jsvNew(); ///< Create a new variable +JsVar *jsvNewWithFlags(JsVarFlags flags); +JsVar *jsvNewFromString(const char *str); ///< Create a new string +JsVar *jsvNewStringOfLength(unsigned int byteLength); ///< Create a new string of the given length - full of 0s +static inline JsVar *jsvNewFromEmptyString() { return jsvNewWithFlags(JSV_STRING); } ;///< Create a new empty string +JsVar *jsvNewFromLexer(struct JsLex *lex, JslCharPos charFrom, JslCharPos charTo); // Create a new STRING from part of the lexer +JsVar *jsvNewFromInteger(JsVarInt value); +JsVar *jsvNewFromBool(bool value); +JsVar *jsvNewFromFloat(JsVarFloat value); +// Turns var into a Variable name that links to the given value... No locking so no need to unlock var +JsVar *jsvMakeIntoVariableName(JsVar *var, JsVar *valueOrZero); +JsVar *jsvNewFromPin(int pin); + +/// DO NOT CALL THIS DIRECTLY - this frees an unreffed/locked var +void jsvFreePtr(JsVar *var); + +/// Get a reference from a var - SAFE for null vars +JsVarRef jsvGetRef(JsVar *var); + +/// SCARY - only to be used for vital stuff like load/save +JsVar *_jsvGetAddressOf(JsVarRef ref); + +/// Lock this reference and return a pointer - UNSAFE for null refs +JsVar *jsvLock(JsVarRef ref); + +/// Lock this pointer and return a pointer - UNSAFE for null pointer +JsVar *jsvLockAgain(JsVar *var); + +/// Unlock this variable - this is SAFE for null variables +void jsvUnLock(JsVar *var); + + +/// Reference - set this variable as used by something +JsVar *jsvRef(JsVar *v); + +/// Unreference - set this variable as not used by anything +void jsvUnRef(JsVar *var); + +/// Helper fn, Reference - set this variable as used by something +JsVarRef jsvRefRef(JsVarRef ref); + +/// Helper fn, Unreference - set this variable as not used by anything +JsVarRef jsvUnRefRef(JsVarRef ref); + +static inline bool jsvIsRoot(const JsVar *v) { return v && (v->flags&JSV_VARTYPEMASK)==JSV_ROOT; } +static inline bool jsvIsPin(const JsVar *v) { return v && (v->flags&JSV_VARTYPEMASK)==JSV_PIN; } +static inline bool jsvIsInt(const JsVar *v) { return v && ((v->flags&JSV_VARTYPEMASK)==JSV_INTEGER || (v->flags&JSV_VARTYPEMASK)==JSV_PIN); } +static inline bool jsvIsFloat(const JsVar *v) { return v && (v->flags&JSV_VARTYPEMASK)==JSV_FLOAT; } +static inline bool jsvIsBoolean(const JsVar *v) { return v && (v->flags&JSV_VARTYPEMASK)==JSV_BOOLEAN; } +static inline bool jsvIsString(const JsVar *v) { return v && (v->flags&JSV_VARTYPEMASK)>=JSV_STRING_0 && (v->flags&JSV_VARTYPEMASK)<=JSV_STRING_MAX; } +static inline bool jsvIsStringExt(const JsVar *v) { return v && (v->flags&JSV_VARTYPEMASK)>=JSV_STRING_EXT_0 && (v->flags&JSV_VARTYPEMASK)<=JSV_STRING_EXT_MAX; } ///< The extra bits dumped onto the end of a string to store more data +static inline bool jsvIsNumeric(const JsVar *v) { return v && (v->flags&JSV_VARTYPEMASK)>=JSV_NUMERICSTART && (v->flags&JSV_VARTYPEMASK)<=JSV_NUMERICEND; } +static inline bool jsvIsFunction(const JsVar *v) { return v && (v->flags&JSV_VARTYPEMASK)==JSV_FUNCTION; } +static inline bool jsvIsFunctionParameter(const JsVar *v) { return v && (v->flags&JSV_FUNCTION_PARAMETER) == JSV_FUNCTION_PARAMETER; } +static inline bool jsvIsObject(const JsVar *v) { return v && (((v->flags&JSV_VARTYPEMASK)==JSV_OBJECT) || ((v->flags&JSV_VARTYPEMASK)==JSV_ROOT)); } +static inline bool jsvIsArray(const JsVar *v) { return v && (v->flags&JSV_VARTYPEMASK)==JSV_ARRAY; } +static inline bool jsvIsArrayBuffer(const JsVar *v) { return v && (v->flags&JSV_VARTYPEMASK)==JSV_ARRAYBUFFER; } +static inline bool jsvIsArrayBufferName(const JsVar *v) { return v && (v->flags&(JSV_VARTYPEMASK|JSV_NAME))==JSV_ARRAYBUFFERNAME; } +static inline bool jsvIsNative(const JsVar *v) { return v && (v->flags&JSV_NATIVE)!=0; } +static inline bool jsvIsUndefined(const JsVar *v) { return v==0; } +static inline bool jsvIsNull(const JsVar *v) { return v && (v->flags&JSV_VARTYPEMASK)==JSV_NULL; } +static inline bool jsvIsBasic(const JsVar *v) { return jsvIsNumeric(v) || jsvIsString(v);} ///< Is this *not* an array/object/etc +static inline bool jsvIsName(const JsVar *v) { return v && (v->flags & JSV_NAME)!=0; } ///< NAMEs are what's used to name a variable (it is not the data itself) + +static inline bool jsvIsIterable(const JsVar *v) { + return jsvIsArray(v) || jsvIsObject(v) || jsvIsFunction(v) || + jsvIsString(v) || jsvIsArrayBuffer(v); +} + +/** Does this string contain only Numeric characters? */ +bool jsvIsStringNumeric(const JsVar *var); +/** Does this string contain only Numeric characters? This is for arrays + * and makes the assertion that int_to_string(string_to_int(var))==var */ +bool jsvIsStringNumericStrict(const JsVar *var); + +// TODO: maybe isName shouldn't include ArrayBufferName? +bool jsvHasCharacterData(const JsVar *v); ///< does the v->data union contain character data? +bool jsvHasStringExt(const JsVar *v); +/// Does this variable use firstChild/lastChild to point to multiple childrem +bool jsvHasChildren(const JsVar *v); +/// Is this variable a type that uses firstChild to point to a single Variable (ie. it doesn't have multiple children) +bool jsvHasSingleChild(const JsVar *v); +/// Does this variable have a 'ref' argument? Stringexts use it for extra character data +static inline bool jsvHasRef(const JsVar *v) { return !jsvIsStringExt(v); } + +/// This is the number of characters a JsVar can contain, NOT string length +static inline size_t jsvGetMaxCharactersInVar(const JsVar *v) { + // see jsvCopy - we need to know about this in there too + if (jsvIsStringExt(v)) return JSVAR_DATA_STRING_MAX_LEN; + assert(jsvHasCharacterData(v)); + return JSVAR_DATA_STRING_LEN; +} + +/// This is the number of characters a JsVar can contain, NOT string length +static inline size_t jsvGetCharactersInVar(const JsVar *v) { + assert(jsvIsString(v) || jsvIsStringExt(v)); + int f = v->flags&JSV_VARTYPEMASK; + return (size_t)(f - ((f < JSV_STRING_EXT_0) ? JSV_STRING_0 : JSV_STRING_EXT_0)); +} + +/// This is the number of characters a JsVar can contain, NOT string length +static inline void jsvSetCharactersInVar(JsVar *v, size_t chars) { + assert(jsvIsString(v) || jsvIsStringExt(v)); + if (jsvIsString(v)) { assert(chars <= JSVAR_DATA_STRING_LEN); } + if (jsvIsStringExt(v)) { assert(chars <= JSVAR_DATA_STRING_MAX_LEN); } + + int f = v->flags&JSV_VARTYPEMASK; + v->flags = (JsVarFlags)((v->flags&(~JSV_VARTYPEMASK)) | (((f < JSV_STRING_EXT_0) ? JSV_STRING_0 : JSV_STRING_EXT_0) + (int)chars)); +} + + +/** Check if two Basic Variables are equal (this IGNORES the value that is pointed to, + * so 'a=5'=='a=7' but 'a=5'!='b=5') + */ +bool jsvIsBasicVarEqual(JsVar *a, JsVar *b); + +/** Check if two things are equal. Basic vars are done by value, + * for anything else the reference/pointer must be equal */ +bool jsvIsEqual(JsVar *a, JsVar *b); + + +const char *jsvGetConstString(const JsVar *v); ///< Get a const string representing this variable - if we can. Otherwise return 0 +const char *jsvGetTypeOf(const JsVar *v); ///< Return the 'type' of the JS variable (eg. JS's typeof operator) +size_t jsvGetString(const JsVar *v, char *str, size_t len); ///< Save this var as a string to the given buffer, and return how long it was (return val doesn't include terminating 0) +void jsvSetString(JsVar *v, char *str, size_t len); ///< Set the Data in this string. This must JUST overwrite - not extend or shrink +JsVar *jsvAsString(JsVar *var, bool unlockVar); ///< If var is a string, lock and return it, else create a new string +size_t jsvGetStringLength(JsVar *v); ///< Get the length of this string, IF it is a string +int jsvGetLinesInString(JsVar *v); ///< IN A STRING get the number of lines in the string (min=1) +int jsvGetCharsOnLine(JsVar *v, int line); ///< IN A STRING Get the number of characters on a line - lines start at 1 +void jsvGetLineAndCol(JsVar *v, int charIdx, int* line, int *col); ///< IN A STRING, get the line and column of the given character. Both values must be non-null +int jsvGetIndexFromLineAndCol(JsVar *v, int line, int col); ///< IN A STRING, get a character index from a line and column +bool jsvIsStringEqual(JsVar *var, const char *str); +int jsvCompareString(JsVar *va, JsVar *vb, int starta, int startb, bool equalAtEndOfString); ///< Compare 2 strings, starting from the given character positions +int jsvCompareInteger(JsVar *va, JsVar *vb); ///< Compare 2 integers, >0 if va>vb, <0 if vafirstChild; } ///< Return true is array is empty + +/** Write debug info for this Var out to the console */ +void jsvTrace(JsVarRef ref, int indent); + +/** Run a garbage collection sweep - return true if things have been freed */ +bool jsvGarbageCollect(); + +/** Remove whitespace to the right of a string - on MULTIPLE LINES */ +JsVar *jsvStringTrimRight(JsVar *srcString); + +/** If v is the key of a function, return true if it is internal and shouldn't be visible to the user */ +bool jsvIsInternalFunctionKey(JsVar *v); + +/// If v is the key of an object, return true if it is internal and shouldn't be visible to the user +bool jsvIsInternalObjectKey(JsVar *v); +// -------------------------------------------------------------------------------------------- +typedef struct JsvStringIterator { + size_t charIdx; ///< index of character in var + size_t charsInVar; ///< total characters in var + size_t index; ///< index in string + JsVar *var; ///< current StringExt we're looking at +} JsvStringIterator; + +// slight hack to enure we can use string iterator with const JsVars +#define jsvStringIteratorNewConst(it,str,startIdx) jsvStringIteratorNew(it,(JsVar*)str,startIdx) + +void jsvStringIteratorNew(JsvStringIterator *it, JsVar *str, int startIdx); + +/// Gets the current character (or 0) +static inline char jsvStringIteratorGetChar(JsvStringIterator *it) { + if (!it->var) return 0; + return it->var->varData.str[it->charIdx]; +} + +/// Gets the current (>=0) character (or -1) +static inline int jsvStringIteratorGetCharOrMinusOne(JsvStringIterator *it) { + if (!it->var) return -1; + return (int)(unsigned char)it->var->varData.str[it->charIdx]; +} + +/// Do we have a character, or are we at the end? +static inline bool jsvStringIteratorHasChar(JsvStringIterator *it) { + return it->charIdx < it->charsInVar; +} + +/// Sets a character (will not extend the string - just overwrites) +static inline void jsvStringIteratorSetChar(JsvStringIterator *it, char c) { + if (jsvStringIteratorHasChar(it)) + it->var->varData.str[it->charIdx] = c; +} + +/// Gets the current index in the string +static inline size_t jsvStringIteratorGetIndex(JsvStringIterator *it) { + return it->index; +} + +/// Move to next character +void jsvStringIteratorNext(JsvStringIterator *it); + +/// Move to next character (this one is inlined where speed is needed) +static inline void jsvStringIteratorNextInline(JsvStringIterator *it) { + it->charIdx++; + it->index++; + if (it->charIdx >= it->charsInVar) { + it->charIdx -= it->charsInVar; + if (it->var && it->var->lastChild) { + JsVar *next = jsvLock(it->var->lastChild); + jsvUnLock(it->var); + it->var = next; + it->charsInVar = jsvGetCharactersInVar(it->var); + } else { + jsvUnLock(it->var); + it->var = 0; + it->charsInVar = 0; + } + } +} + + +/// Go to the end of the string iterator - for use with jsvStringIteratorAppend +void jsvStringIteratorGotoEnd(JsvStringIterator *it); + +/// Append a character TO THE END of a string iterator +void jsvStringIteratorAppend(JsvStringIterator *it, char ch); + +static inline void jsvStringIteratorFree(JsvStringIterator *it) { + jsvUnLock(it->var); +} + +// -------------------------------------------------------------------------------------------- +typedef struct JsArrayIterator { + JsVar *var; +} JsArrayIterator; + +static inline void jsvArrayIteratorNew(JsArrayIterator *it, JsVar *arr) { + assert(jsvIsArray(arr)); + it->var = arr->firstChild ? jsvLock(arr->firstChild) : 0; +} + +/// Gets the current array element (or 0) +static inline JsVar *jsvArrayIteratorGetElement(JsArrayIterator *it) { + if (!it->var) return 0; // end of array + return it->var->firstChild ? jsvLock(it->var->firstChild) : 0; // might even be undefined +} + +/// Gets the current array element index (or 0) +static inline JsVar *jsvArrayIteratorGetIndex(JsArrayIterator *it) { + if (!it->var) return 0; + return jsvLockAgain(it->var); +} + +/// Do we have a character, or are we at the end? +static inline bool jsvArrayIteratorHasElement(JsArrayIterator *it) { + return it->var != 0; +} + +/// Move to next character +static inline void jsvArrayIteratorNext(JsArrayIterator *it) { + if (it->var) { + JsVarRef next = it->var->nextSibling; + jsvUnLock(it->var); + it->var = next ? jsvLock(next) : 0; + } +} + +static inline void jsvArrayIteratorFree(JsArrayIterator *it) { + jsvUnLock(it->var); +} +// -------------------------------------------------------------------------------------------- +typedef struct JsObjectIterator { + JsVar *var; +} JsObjectIterator; + +static inline void jsvObjectIteratorNew(JsObjectIterator *it, JsVar *obj) { + assert(jsvIsObject(obj) || jsvIsFunction(obj)); + it->var = obj->firstChild ? jsvLock(obj->firstChild) : 0; +} + +/// Gets the current object element key (or 0) +static inline JsVar *jsvObjectIteratorGetKey(JsObjectIterator *it) { + if (!it->var) return 0; // end of object + return jsvLockAgain(it->var); +} + +/// Gets the current object element value (or 0) +static inline JsVar *jsvObjectIteratorGetValue(JsObjectIterator *it) { + if (!it->var) return 0; // end of object + return it->var->firstChild ? jsvLock(it->var->firstChild) : 0; // might even be undefined +} + +/// Do we have a key, or are we at the end? +static inline bool jsvObjectIteratorHasElement(JsObjectIterator *it) { + return it->var != 0; +} + +/// Move to next character +static inline void jsvObjectIteratorNext(JsObjectIterator *it) { + if (it->var) { + JsVarRef next = it->var->nextSibling; + jsvUnLock(it->var); + it->var = next ? jsvLock(next) : 0; + } +} + +static inline void jsvObjectIteratorFree(JsObjectIterator *it) { + jsvUnLock(it->var); +} +// -------------------------------------------------------------------------------------------- +typedef struct JsvArrayBufferIterator { + JsvStringIterator it; + JsVarDataArrayBufferViewType type; + JsVarInt byteLength; + JsVarInt byteOffset; + JsVarInt index; + bool hasAccessedElement; +} JsvArrayBufferIterator; + +void jsvArrayBufferIteratorNew(JsvArrayBufferIterator *it, JsVar *arrayBuffer, JsVarInt index); +JsVar *jsvArrayBufferIteratorGetValue(JsvArrayBufferIterator *it); +JsVarInt jsvArrayBufferIteratorGetIntegerValue(JsvArrayBufferIterator *it); +JsVarFloat jsvArrayBufferIteratorGetFloatValue(JsvArrayBufferIterator *it); +void jsvArrayBufferIteratorSetValue(JsvArrayBufferIterator *it, JsVar *value); +void jsvArrayBufferIteratorSetIntegerValue(JsvArrayBufferIterator *it, JsVarInt value); +JsVar* jsvArrayBufferIteratorGetIndex(JsvArrayBufferIterator *it); +bool jsvArrayBufferIteratorHasElement(JsvArrayBufferIterator *it); +void jsvArrayBufferIteratorNext(JsvArrayBufferIterator *it); +void jsvArrayBufferIteratorFree(JsvArrayBufferIterator *it); +// -------------------------------------------------------------------------------------------- +union JsvIteratorUnion { + JsvStringIterator str; + JsObjectIterator obj; + JsArrayIterator arr; + JsvArrayBufferIterator buf; +}; + +/** General Purpose iterator, for Strings, Arrays, Objects, Typed Arrays */ +typedef struct JsvIterator { + enum {JSVI_STRING, JSVI_ARRAY, JSVI_OBJECT, JSVI_ARRAYBUFFER } type; + union JsvIteratorUnion it; +} JsvIterator; + +void jsvIteratorNew(JsvIterator *it, JsVar *obj); +JsVar *jsvIteratorGetKey(JsvIterator *it); +JsVar *jsvIteratorGetValue(JsvIterator *it); +JsVarInt jsvIteratorGetIntegerValue(JsvIterator *it); +bool jsvIteratorHasElement(JsvIterator *it); +void jsvIteratorNext(JsvIterator *it); +void jsvIteratorFree(JsvIterator *it); + + + +#endif /* JSVAR_H_ */ diff --git a/components/external/espruino/src/jswrap_array.c b/components/external/espruino/src/jswrap_array.c new file mode 100644 index 0000000000..ad780a8dc9 --- /dev/null +++ b/components/external/espruino/src/jswrap_array.c @@ -0,0 +1,328 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * This file is designed to be parsed during the build process + * + * JavaScript methods for Arrays + * ---------------------------------------------------------------------------- + */ +#include "jswrap_array.h" +#include "jsparse.h" + +#define min(a,b) (((a)<(b))?(a):(b)) +#define max(a,b) (((a)>(b))?(a):(b)) + + +/*JSON{ "type":"class", + "class" : "Array", + "check" : "jsvIsArray(var)", + "description" : ["This is the built-in JavaScript class for arrays.", + "Arrays can be defined with ```[]```, ```new Array()```, or ```new Array(length)```" ] +}*/ + +/*JSON{ "type":"constructor", "class": "Array", "name": "Array", + "description" : "Create an Array. Either give it one integer argument (>=0) which is the length of the array, or any number of arguments ", + "generate" : "jswrap_array_constructor", + "params" : [ [ "args", "JsVarArray", "The length of the array OR any number of items to add to the array" ] ], + "return" : [ "JsVar", "An Array" ] + +}*/ +JsVar *jswrap_array_constructor(JsVar *args) { + assert(args); + if (jsvGetArrayLength(args)==1) { + JsVar *firstArg = jsvSkipNameAndUnLock(jsvArrayGetLast(args)); // also the first! + if (jsvIsInt(firstArg) && jsvGetInteger(firstArg)>=0) { + JsVarInt count = jsvGetInteger(firstArg); + // we cheat - no need to fill the array - just the last element + if (count>0) { + JsVar *arr = jsvNewWithFlags(JSV_ARRAY); + if (!arr) return 0; // out of memory + JsVar *idx = jsvMakeIntoVariableName(jsvNewFromInteger(count-1), 0); + if (idx) { // could be out of memory + jsvAddName(arr, idx); + jsvUnLock(idx); + } + jsvUnLock(firstArg); + return arr; + } + } + jsvUnLock(firstArg); + } + // Otherwise, we just return the array! + return jsvLockAgain(args); +} + +/*JSON{ "type":"method", "class": "Array", "name" : "contains", + "description" : "Return true if this array contains the given value", + "generate" : "jswrap_array_contains", + "params" : [ [ "value", "JsVar", "The value to check for"] ], + "return" : ["bool", "Whether value is in the array or not"] +}*/ +bool jswrap_array_contains(JsVar *parent, JsVar *value) { + // ArrayIndexOf will return 0 if not found + JsVar *arrElement = jsvGetArrayIndexOf(parent, value, false/*not exact*/); + bool contains = arrElement!=0; + jsvUnLock(arrElement); + return contains; +} + +/*JSON{ "type":"method", "class": "Array", "name" : "indexOf", + "description" : "Return the index of the value in the array, or -1", + "generate" : "jswrap_array_indexOf", + "params" : [ [ "value", "JsVar", "The value to check for"] ], + "return" : ["JsVar", "the index of the value in the array, or -1"] +}*/ +JsVar *jswrap_array_indexOf(JsVar *parent, JsVar *value) { + JsVar *idxName = jsvGetArrayIndexOf(parent, value, false/*not exact*/); + // but this is the name - we must turn it into a var + if (idxName == 0) return jsvNewFromInteger(-1); // not found! + JsVar *idx = jsvCopyNameOnly(idxName, false/* no children */, false/* Make sure this is not a name*/); + jsvUnLock(idxName); + return idx; +} + +/*JSON{ "type":"method", "class": "Array", "name" : "join", + "description" : "Join all elements of this array together into one string, using 'separator' between them. eg. ```[1,2,3].join(' ')=='1 2 3'```", + "generate" : "jswrap_array_join", + "params" : [ [ "separator", "JsVar", "The separator"] ], + "return" : ["JsVar", "A String representing the Joined array"] +}*/ +JsVar *jswrap_array_join(JsVar *parent, JsVar *filler) { + if (jsvIsUndefined(filler)) + filler = jsvNewFromString(","); // the default it seems + else + filler = jsvAsString(filler, false); + if (!filler) return 0; // out of memory + JsVar *str = jsvArrayJoin(parent, filler); + jsvUnLock(filler); + return str; +} + +/*JSON{ "type":"method", "class": "Array", "name" : "push", + "description" : "Push a new value onto the end of this array'", + "generate_full" : "jsvArrayPush(parent, value)", + "params" : [ [ "value", "JsVar", "The value to add"] ], + "return" : ["int", "The new size of the array"] +}*/ + +/*JSON{ "type":"method", "class": "Array", "name" : "pop", + "description" : "Pop a new value off of the end of this array", + "generate_full" : "jsvArrayPop(parent)", + "return" : ["JsVar", "The value that is popped off"] +}*/ + +JsVar *_jswrap_array_map_or_forEach(JsVar *parent, JsVar *funcVar, JsVar *thisVar, bool isMap) { + if (!jsvIsFunction(funcVar)) { + jsError("Array.map's first argument should be a function"); + return 0; + } + if (!jsvIsUndefined(thisVar) && !jsvIsObject(thisVar)) { + jsError("Arraymap's second argument should be undefined, or an object"); + return 0; + } + JsVar *array = 0; + if (isMap) + array = jsvNewWithFlags(JSV_ARRAY); + if (array || !isMap) { + JsVarRef childRef = parent->firstChild; + while (childRef) { + JsVar *child = jsvLock(childRef); + if (jsvIsInt(child)) { + JsVar *args[3], *mapped; + args[0] = jsvLock(child->firstChild); + // child is a variable name, create a new variable for the index + args[1] = jsvNewFromInteger(jsvGetInteger(child)); + args[2] = parent; + mapped = jspeFunctionCall(funcVar, 0, thisVar, false, 3, args); + jsvUnLock(args[0]); + jsvUnLock(args[1]); + if (mapped) { + if (isMap) { + JsVar *name = jsvCopyNameOnly(child, false/*linkChildren*/, true/*keepAsName*/); + if (name) { // out of memory? + name->firstChild = jsvGetRef(jsvRef(mapped)); + jsvAddName(array, name); + jsvUnLock(name); + } + } + jsvUnLock(mapped); + } + } + childRef = child->nextSibling; + jsvUnLock(child); + } + } + return array; +} + +/*JSON{ "type":"method", "class": "Array", "name" : "map", + "description" : "Return an array which is made from the following: ```A.map(function) = [function(A[0]), function(A[1]), ...]```", + "generate" : "jswrap_array_map", + "params" : [ [ "function", "JsVar", "Function used to map one item to another"] , + [ "thisArg", "JsVar", "if specified, the function is called with 'this' set to thisArg (optional)"] ], + "return" : ["JsVar", "The value that is popped off"] +}*/ +JsVar *jswrap_array_map(JsVar *parent, JsVar *funcVar, JsVar *thisVar) { + return _jswrap_array_map_or_forEach(parent, funcVar, thisVar, true); +} + + +/*JSON{ "type":"method", "class": "Array", "name" : "splice", + "description" : "Both remove and add items to an array", + "generate" : "jswrap_array_splice", + "params" : [ [ "index", "int", "Index at which to start changing the array. If negative, will begin that many elements from the end"], + [ "howMany", "JsVar", "An integer indicating the number of old array elements to remove. If howMany is 0, no elements are removed."], + [ "element1", "JsVar", "A new item to add (optional)" ], + [ "element2", "JsVar", "A new item to add (optional)" ], + [ "element3", "JsVar", "A new item to add (optional)" ], + [ "element4", "JsVar", "A new item to add (optional)" ], + [ "element5", "JsVar", "A new item to add (optional)" ], + [ "element6", "JsVar", "A new item to add (optional)" ] ], + "return" : ["JsVar", "An array containing the removed elements. If only one element is removed, an array of one element is returned."] +}*/ +JsVar *jswrap_array_splice(JsVar *parent, JsVarInt index, JsVar *howManyVar, JsVar *element1, JsVar *element2, JsVar *element3, JsVar *element4, JsVar *element5, JsVar *element6) { + JsVarInt len = jsvGetArrayLength(parent); + if (index<0) index+=len; + if (index<0) index=0; + if (index>len) index=len; + JsVarInt howMany = len; // how many to delete! + if (jsvIsInt(howManyVar)) howMany = jsvGetInteger(howManyVar); + if (howMany > len-index) howMany = len-index; + JsVarInt newItems = 0; + if (element1) newItems++; + if (element2) newItems++; + if (element3) newItems++; + if (element4) newItems++; + if (element5) newItems++; + if (element6) newItems++; + JsVarInt shift = newItems-howMany; + + bool needToAdd = false; + JsVar *result = jsvNewWithFlags(JSV_ARRAY); + + JsArrayIterator it; + jsvArrayIteratorNew(&it, parent); + while (jsvArrayIteratorHasElement(&it) && !needToAdd) { + bool goToNext = true; + JsVar *idxVar = jsvArrayIteratorGetIndex(&it); + if (idxVar && jsvIsInt(idxVar)) { + JsVarInt idx = jsvGetInteger(idxVar); + if (idx + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * JavaScript methods for Arrays + * ---------------------------------------------------------------------------- + */ +#include "jsvar.h" + +JsVar *jswrap_array_constructor(JsVar *args); +bool jswrap_array_contains(JsVar *parent, JsVar *value); +JsVar *jswrap_array_indexOf(JsVar *parent, JsVar *value); +JsVar *jswrap_array_join(JsVar *parent, JsVar *filler); +JsVar *jswrap_array_map(JsVar *parent, JsVar *funcVar, JsVar *thisVar); +JsVar *jswrap_array_slice(JsVar *parent, JsVar *startVar, JsVar *endVar); +JsVar *jswrap_array_splice(JsVar *parent, JsVarInt index, JsVar *howManyVar, JsVar *element1, JsVar *element2, JsVar *element3, JsVar *element4, JsVar *element5, JsVar *element6); +void jswrap_array_forEach(JsVar *parent, JsVar *funcVar, JsVar *thisVar); diff --git a/components/external/espruino/src/jswrap_arraybuffer.c b/components/external/espruino/src/jswrap_arraybuffer.c new file mode 100644 index 0000000000..49be45c1a5 --- /dev/null +++ b/components/external/espruino/src/jswrap_arraybuffer.c @@ -0,0 +1,315 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * This file is designed to be parsed during the build process + * + * JavaScript methods for ArrayBuffers + * ---------------------------------------------------------------------------- + */ +#include "jswrap_arraybuffer.h" +#include "jsparse.h" +#include "jsinteractive.h" + +/*JSON{ "type":"class", + "class" : "ArrayBuffer", + "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_ARRAYBUFFER", + "not_real_object" : "Don't treat this as a real object - it's handled differently internally", + "description" : ["This is the built-in JavaScript class for array buffers." ] +}*/ + +/*JSON{ "type":"class", + "class" : "ArrayBufferView", + "description" : ["This is the built-in JavaScript class that is the prototype for Uint8Array / Float32Array / etc" ] +}*/ + +/*JSON{ "type":"class", + "class" : "Uint8Array", "prototype" : "ArrayBufferView", + "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_UINT8", + "not_real_object" : "Don't treat this as a real object - it's handled differently internally", + "description" : ["This is the built-in JavaScript class for a typed array.", + "Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). " ] +}*/ +/*JSON{ "type":"class", + "class" : "Int8Array", "prototype" : "ArrayBufferView", + "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_INT8", + "not_real_object" : "Don't treat this as a real object - it's handled differently internally", + "description" : ["This is the built-in JavaScript class for a typed array.", + "Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). " ] +}*/ +/*JSON{ "type":"class", + "class" : "Uint16Array", "prototype" : "ArrayBufferView", + "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_UINT16", + "not_real_object" : "Don't treat this as a real object - it's handled differently internally", + "description" : ["This is the built-in JavaScript class for a typed array.", + "Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). " ] +}*/ +/*JSON{ "type":"class", + "class" : "Int16Array", "prototype" : "ArrayBufferView", + "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_INT16", + "not_real_object" : "Don't treat this as a real object - it's handled differently internally", + "description" : ["This is the built-in JavaScript class for a typed array.", + "Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). " ] +}*/ +/*JSON{ "type":"class", + "class" : "Uint32Array", "prototype" : "ArrayBufferView", + "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_UINT32", + "not_real_object" : "Don't treat this as a real object - it's handled differently internally", + "description" : ["This is the built-in JavaScript class for a typed array.", + "Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). " ] +}*/ +/*JSON{ "type":"class", + "class" : "Int32Array", "prototype" : "ArrayBufferView", + "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_INT32", + "not_real_object" : "Don't treat this as a real object - it's handled differently internally", + "description" : ["This is the built-in JavaScript class for a typed array.", + "Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). " ] +}*/ +/*JSON{ "type":"class", + "class" : "Float32Array", "prototype" : "ArrayBufferView", + "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_FLOAT32", + "not_real_object" : "Don't treat this as a real object - it's handled differently internally", + "description" : ["This is the built-in JavaScript class for a typed array.", + "Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). " ] +}*/ +/*JSON{ "type":"class", + "class" : "Float64Array", "prototype" : "ArrayBufferView", + "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_FLOAT64", + "not_real_object" : "Don't treat this as a real object - it's handled differently internally", + "description" : ["This is the built-in JavaScript class for a typed array.", + "Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). " ] +}*/ + + +/*JSON{ "type":"constructor", "class": "ArrayBuffer", "name": "ArrayBuffer", + "description" : "Create an Array Buffer object", + "generate" : "jswrap_arraybuffer_constructor", + "params" : [ [ "byteLength", "int", "The length in Bytes" ] ], + "return" : [ "JsVar", "An ArrayBuffer object" ] + +}*/ +JsVar *jswrap_arraybuffer_constructor(JsVarInt byteLength) { + if (byteLength <= 0 || byteLength>65535) { + jsError("Invalid length for ArrayBuffer\n"); + return 0; + } + if (byteLength > JSV_ARRAYBUFFER_MAX_LENGTH) { + jsError("ArrayBuffer too long\n"); + return 0; + } + JsVar *arrData = jsvNewStringOfLength((unsigned int)byteLength); + if (!arrData) return 0; + JsVar *arr = jsvNewWithFlags(JSV_ARRAYBUFFER); + if (!arr) { + jsvUnLock(arrData); + return 0; + } + arr->firstChild = jsvGetRef(jsvRef(arrData)); + jsvUnLock(arrData); + arr->varData.arraybuffer.type = ARRAYBUFFERVIEW_ARRAYBUFFER; + arr->varData.arraybuffer.byteOffset = 0; + arr->varData.arraybuffer.length = (unsigned short)byteLength; + return arr; +} + + +/* + * Potential invocations: + * Uint8Array Uint8Array(unsigned long length); + * Uint8Array Uint8Array(TypedArray array); + * Uint8Array Uint8Array(sequence array); + * Uint8Array Uint8Array(ArrayBuffer buffer, optional unsigned long byteOffset, optional unsigned long length); + */ + +/*JSON{ "type":"constructor", "class": "Uint8Array", "name": "Uint8Array", + "description" : "Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array", + "generate_full" : "jswrap_typedarray_constructor(ARRAYBUFFERVIEW_UINT8, arr, jsvGetInteger(byteOffset), jsvGetInteger(length))", + "params" : [ [ "arr", "JsVar", "The array or typed array to base this off, or an integer which is the array length" ], + [ "byteOffset", "int", "The byte offset in the ArrayBuffer (ONLY IF the first argument was an ArrayBuffer)" ], + [ "length", "int", "The length (ONLY IF the first argument was an ArrayBuffer)" ] ], + "return" : [ "JsVar", "A typed array" ] +}*/ +/*JSON{ "type":"constructor", "class": "Int8Array", "name": "Int8Array", + "description" : "Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array", + "generate_full" : "jswrap_typedarray_constructor(ARRAYBUFFERVIEW_INT8, arr, jsvGetInteger(byteOffset), jsvGetInteger(length))", + "params" : [ [ "arr", "JsVar", "The array or typed array to base this off, or an integer which is the array length" ], + [ "byteOffset", "int", "The byte offset in the ArrayBuffer (ONLY IF the first argument was an ArrayBuffer)" ], + [ "length", "int", "The length (ONLY IF the first argument was an ArrayBuffer)" ] ], + "return" : [ "JsVar", "A typed array" ] +}*/ +/*JSON{ "type":"constructor", "class": "Uint16Array", "name": "Uint16Array", + "description" : "Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array", + "generate_full" : "jswrap_typedarray_constructor(ARRAYBUFFERVIEW_UINT16, arr, jsvGetInteger(byteOffset), jsvGetInteger(length))", + "params" : [ [ "arr", "JsVar", "The array or typed array to base this off, or an integer which is the array length" ], + [ "byteOffset", "int", "The byte offset in the ArrayBuffer (ONLY IF the first argument was an ArrayBuffer)" ], + [ "length", "int", "The length (ONLY IF the first argument was an ArrayBuffer)" ] ], + "return" : [ "JsVar", "A typed array" ] +}*/ +/*JSON{ "type":"constructor", "class": "Int16Array", "name": "Int16Array", + "description" : "Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array", + "generate_full" : "jswrap_typedarray_constructor(ARRAYBUFFERVIEW_INT16, arr, jsvGetInteger(byteOffset), jsvGetInteger(length))", + "params" : [ [ "arr", "JsVar", "The array or typed array to base this off, or an integer which is the array length" ], + [ "byteOffset", "int", "The byte offset in the ArrayBuffer (ONLY IF the first argument was an ArrayBuffer)" ], + [ "length", "int", "The length (ONLY IF the first argument was an ArrayBuffer)" ] ], + "return" : [ "JsVar", "A typed array" ] +}*/ +/*JSON{ "type":"constructor", "class": "Uint32Array", "name": "Uint32Array", + "description" : "Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array", + "generate_full" : "jswrap_typedarray_constructor(ARRAYBUFFERVIEW_UINT32, arr, jsvGetInteger(byteOffset), jsvGetInteger(length))", + "params" : [ [ "arr", "JsVar", "The array or typed array to base this off, or an integer which is the array length" ], + [ "byteOffset", "int", "The byte offset in the ArrayBuffer (ONLY IF the first argument was an ArrayBuffer)" ], + [ "length", "int", "The length (ONLY IF the first argument was an ArrayBuffer)" ] ], + "return" : [ "JsVar", "A typed array" ] +}*/ +/*JSON{ "type":"constructor", "class": "Int32Array", "name": "Int32Array", + "description" : "Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array", + "generate_full" : "jswrap_typedarray_constructor(ARRAYBUFFERVIEW_INT32, arr, jsvGetInteger(byteOffset), jsvGetInteger(length))", + "params" : [ [ "arr", "JsVar", "The array or typed array to base this off, or an integer which is the array length" ], + [ "byteOffset", "int", "The byte offset in the ArrayBuffer (ONLY IF the first argument was an ArrayBuffer)" ], + [ "length", "int", "The length (ONLY IF the first argument was an ArrayBuffer)" ] ], + "return" : [ "JsVar", "A typed array" ] +}*/ +/*JSON{ "type":"constructor", "class": "Float32Array", "name": "Float32Array", + "description" : "Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array", + "generate_full" : "jswrap_typedarray_constructor(ARRAYBUFFERVIEW_FLOAT32, arr, jsvGetInteger(byteOffset), jsvGetInteger(length))", + "params" : [ [ "arr", "JsVar", "The array or typed array to base this off, or an integer which is the array length" ], + [ "byteOffset", "int", "The byte offset in the ArrayBuffer (ONLY IF the first argument was an ArrayBuffer)" ], + [ "length", "int", "The length (ONLY IF the first argument was an ArrayBuffer)" ] ], + "return" : [ "JsVar", "A typed array" ] +}*/ +/*JSON{ "type":"constructor", "class": "Float64Array", "name": "Float64Array", + "description" : "Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array", + "generate_full" : "jswrap_typedarray_constructor(ARRAYBUFFERVIEW_FLOAT64, arr, jsvGetInteger(byteOffset), jsvGetInteger(length))", + "params" : [ [ "arr", "JsVar", "The array or typed array to base this off, or an integer which is the array length" ], + [ "byteOffset", "int", "The byte offset in the ArrayBuffer (ONLY IF the first argument was an ArrayBuffer)" ], + [ "length", "int", "The length (ONLY IF the first argument was an ArrayBuffer)" ] ], + "return" : [ "JsVar", "A typed array" ] +}*/ + + + +JsVar *jswrap_typedarray_constructor(JsVarDataArrayBufferViewType type, JsVar *arr, JsVarInt byteOffset, JsVarInt length) { + JsVar *arrayBuffer = 0; + if (jsvIsArrayBuffer(arr)) { + arrayBuffer = jsvLockAgain(arr); + } else if (jsvIsInt(arr)) { + length = jsvGetInteger(arr); + byteOffset = 0; + arrayBuffer = jswrap_arraybuffer_constructor(JSV_ARRAYBUFFER_GET_SIZE(type)*length); + } else if (jsvIsArray(arr)) { + length = jsvGetArrayLength(arr); + byteOffset = 0; + arrayBuffer = jswrap_arraybuffer_constructor(JSV_ARRAYBUFFER_GET_SIZE(type)*length); + // later on we'll populate this + } + if (!arrayBuffer) { + jsError("Unsupported first argument\n"); + return 0; + } + if (length<=0) length = (JsVarInt)jsvGetArrayBufferLength(arrayBuffer) / JSV_ARRAYBUFFER_GET_SIZE(type); + JsVar *typedArr = jsvNewWithFlags(JSV_ARRAYBUFFER); + if (typedArr) { + typedArr->varData.arraybuffer.type = type; + typedArr->varData.arraybuffer.byteOffset = (unsigned short)byteOffset; + typedArr->varData.arraybuffer.length = (unsigned short)length; + typedArr->firstChild = jsvGetRef(jsvRef(arrayBuffer)); + + if (jsvIsArray(arr)) { + // if we were given an array, populate this ArrayBuffer + JsArrayIterator it; + jsvArrayIteratorNew(&it, arr); + while (jsvArrayIteratorHasElement(&it)) { + JsVar *idx = jsvArrayIteratorGetIndex(&it); + if (jsvIsInt(idx)) { + JsVar *val = jsvArrayIteratorGetElement(&it); + jsvArrayBufferSet(typedArr, jsvGetInteger(idx), val); + jsvUnLock(val); + } + jsvUnLock(idx); + jsvArrayIteratorNext(&it); + } + jsvArrayIteratorFree(&it); + } + } + jsvUnLock(arrayBuffer); + return typedArr; +} + + +/*JSON{ "type":"property", "class": "ArrayBufferView", "name": "buffer", + "description" : "The buffer this view references", + "generate_full" : "jsvLock(parent->firstChild)", + "return" : [ "JsVar", "An ArrayBuffer object" ] +}*/ +/*JSON{ "type":"property", "class": "ArrayBufferView", "name": "byteLength", + "description" : "The length, in bytes, of the view", + "generate_full" : "parent->varData.arraybuffer.length * JSV_ARRAYBUFFER_GET_SIZE(parent->varData.arraybuffer.type)", + "return" : [ "int", "The Length" ] +}*/ +/*JSON{ "type":"property", "class": "ArrayBufferView", "name": "byteOffset", + "description" : "The offset, in bytes, to the first byte of the view within the ArrayBuffer", + "generate_full" : "parent->varData.arraybuffer.byteOffset", + "return" : [ "int", "The byte Offset" ] +}*/ + +/*JSON{ "type":"method", "class": "ArrayBufferView", "name": "interpolate", + "description" : "Interpolate between two adjacent values in the Typed Array", + "generate" : "jswrap_arraybufferview_interpolate", + "params" : [ [ "index", "float", "Floating point index to access" ] ], + "return" : [ "float", "The result of interpolating between (int)index and (int)(index+1)" ] +}*/ +JsVarFloat jswrap_arraybufferview_interpolate(JsVar *parent, JsVarFloat findex) { + int idx = (int)findex; + JsVarFloat a = findex-idx; + JsvArrayBufferIterator it; + jsvArrayBufferIteratorNew(&it, parent, idx); + JsVarFloat fa = jsvArrayBufferIteratorGetFloatValue(&it); + jsvArrayBufferIteratorNext(&it); + JsVarFloat fb = jsvArrayBufferIteratorGetFloatValue(&it); + jsvArrayBufferIteratorFree(&it); + return fa*(1-a) + fb*a; +} + +/*JSON{ "type":"method", "class": "ArrayBufferView", "name": "interpolate2d", + "description" : "Interpolate between two adjacent values in the Typed Array", + "generate" : "jswrap_arraybufferview_interpolate2d", + "params" : [ [ "width", "int", "Integer 'width' of 2d array" ], + [ "x", "float", "Floating point X index to access" ], + [ "y", "float", "Floating point Y index to access" ] ], + "return" : [ "float", "The result of interpolating in 2d between the 4 surrounding cells" ] +}*/ +JsVarFloat jswrap_arraybufferview_interpolate2d(JsVar *parent, JsVarInt width, JsVarFloat x, JsVarFloat y) { + int yidx = (int)y; + JsVarFloat ay = y-yidx; + + JsVarFloat findex = x + (JsVarFloat)(yidx*width); + int idx = (int)findex; + JsVarFloat ax = findex-idx; + + JsvArrayBufferIterator it; + jsvArrayBufferIteratorNew(&it, parent, idx); + + JsVarFloat xa,xb; + int i; + + xa = jsvArrayBufferIteratorGetFloatValue(&it); + jsvArrayBufferIteratorNext(&it); + xb = jsvArrayBufferIteratorGetFloatValue(&it); + JsVarFloat ya = xa*(1-ax) + xb*ax; + + for (i=1;i + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * JavaScript methods and functions in the global namespace + * ---------------------------------------------------------------------------- + */ +#include "jsvar.h" + +JsVar *jswrap_arraybuffer_constructor(JsVarInt byteLength); +JsVar *jswrap_typedarray_constructor(JsVarDataArrayBufferViewType type, JsVar *arr, JsVarInt byteOffset, JsVarInt length); +JsVarFloat jswrap_arraybufferview_interpolate(JsVar *parent, JsVarFloat index); +JsVarFloat jswrap_arraybufferview_interpolate2d(JsVar *parent, JsVarInt width, JsVarFloat x, JsVarFloat y); diff --git a/components/external/espruino/src/jswrap_functions.c b/components/external/espruino/src/jswrap_functions.c new file mode 100644 index 0000000000..4445c98537 --- /dev/null +++ b/components/external/espruino/src/jswrap_functions.c @@ -0,0 +1,102 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * This file is designed to be parsed during the build process + * + * JavaScript methods and functions in the global namespace + * ---------------------------------------------------------------------------- + */ +#include "jswrap_functions.h" +#include "jslex.h" +#include "jsparse.h" +#include "jsinteractive.h" + +/*JSON{ "type":"variable", "name" : "arguments", + "description" : "A variable containing the arguments given to the function", + "generate" : "jswrap_arguments", + "return" : ["JsVar", "An array containing all the arguments given to the function"] +}*/ +extern JsExecInfo execInfo; +JsVar *jswrap_arguments() { + JsVar *scope = 0; + if (execInfo.scopeCount>0) + scope = jsvLock(execInfo.scopes[execInfo.scopeCount-1]); + if (!jsvIsFunction(scope)) { + jsvUnLock(scope); + jsError("Can only use 'arguments' variable inside a function"); + return 0; + } + + JsVar *args = jsvNewWithFlags(JSV_ARRAY); + if (!args) return 0; // out of memory + + JsObjectIterator it; + jsvObjectIteratorNew(&it, scope); + while (jsvObjectIteratorHasElement(&it)) { + JsVar *idx = jsvObjectIteratorGetKey(&it); + if (jsvIsFunctionParameter(idx)) { + JsVar *val = jsvSkipOneName(idx); + jsvArrayPushAndUnLock(args, val); + } + jsvUnLock(idx); + jsvObjectIteratorNext(&it); + } + jsvObjectIteratorFree(&it); + jsvUnLock(scope); + + return args; +} + + +/*JSON{ "type":"function", "name" : "eval", + "description" : "Evaluate a string containing JavaScript code", + "generate" : "jswrap_eval", + "params" : [ [ "code", "JsVar", ""] ], + "return" : ["JsVar", "The result of evaluating the string"] +}*/ +JsVar *jswrap_eval(JsVar *v) { + if (!v) return 0; + JsVar *s = jsvAsString(v, false); // get as a string + JsVar *result = jspEvaluateVar(jsiGetParser(), s, 0); + jsvUnLock(s); + return result; +} + +/*JSON{ "type":"function", "name" : "parseInt", + "description" : "Convert a string representing a number into an integer", + "generate" : "jswrap_parseInt", + "params" : [ [ "string", "JsVar", ""], + [ "radix", "JsVar", "The Radix of the string (optional)"] ], + "return" : ["JsVar", "The integer value of the string (or NaN)"] +}*/ +JsVar *jswrap_parseInt(JsVar *v, JsVar *radixVar) { + int radix = 0/*don't force radix*/; + if (jsvIsNumeric(radixVar)) + radix = (int)jsvGetInteger(radixVar); + + char buffer[JS_NUMBER_BUFFER_SIZE]; + jsvGetString(v, buffer, JS_NUMBER_BUFFER_SIZE); + bool hasError; + JsVarInt i = stringToIntWithRadix(buffer, radix, &hasError); + if (hasError) return jsvNewFromFloat(NAN); + return jsvNewFromInteger(i); +} + +/*JSON{ "type":"function", "name" : "parseFloat", + "description" : "Convert a string representing a number into an float", + "generate" : "jswrap_parseFloat", + "params" : [ [ "string", "JsVar", ""] ], + "return" : ["float", "The value of the string"] +}*/ +JsVarFloat jswrap_parseFloat(JsVar *v) { + char buffer[JS_NUMBER_BUFFER_SIZE]; + jsvGetString(v, buffer, JS_NUMBER_BUFFER_SIZE); + return stringToFloat(buffer); +} diff --git a/components/external/espruino/src/jswrap_functions.h b/components/external/espruino/src/jswrap_functions.h new file mode 100644 index 0000000000..dae42cab25 --- /dev/null +++ b/components/external/espruino/src/jswrap_functions.h @@ -0,0 +1,19 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * JavaScript methods and functions in the global namespace + * ---------------------------------------------------------------------------- + */ +#include "jsvar.h" + +JsVar *jswrap_arguments(); +JsVar *jswrap_eval(JsVar *v); +JsVar *jswrap_parseInt(JsVar *v, JsVar *radixVar); +JsVarFloat jswrap_parseFloat(JsVar *v); diff --git a/components/external/espruino/src/jswrap_interactive.c b/components/external/espruino/src/jswrap_interactive.c new file mode 100644 index 0000000000..a2e86aaf08 --- /dev/null +++ b/components/external/espruino/src/jswrap_interactive.c @@ -0,0 +1,203 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * This file is designed to be parsed during the build process + * + * JavaScript methods and functions for the interactive shell + * ---------------------------------------------------------------------------- + */ +#include "jswrap_interactive.h" +#include "jsinteractive.h" + +/*JSON{ "type":"function", "name" : "setBusyIndicator", + "description" : "When Espruino is busy, set the pin specified here high. Set this to undefined to disable the feature.", + "generate" : "jswrap_interface_setBusyIndicator", + "params" : [ [ "pin", "JsVar", ""] ] +}*/ +void jswrap_interface_setBusyIndicator(JsVar *pinVar) { + Pin oldPin = pinBusyIndicator; + pinBusyIndicator = jshGetPinFromVar(pinVar); + // we should be busy right now anyway, so set stuff up right + if (pinBusyIndicator!=oldPin) { + if (oldPin!=PIN_UNDEFINED) jshPinOutput(oldPin, 0); + if (pinBusyIndicator!=PIN_UNDEFINED) jshPinOutput(pinBusyIndicator, 1); + } +} + +/*JSON{ "type":"function", "name" : "setSleepIndicator", + "description" : "When Espruino is asleep, set the pin specified here high. Set this to undefined to disable the feature.", + "generate" : "jswrap_interface_setSleepIndicator", + "params" : [ [ "pin", "JsVar", ""] ] +}*/ +void jswrap_interface_setSleepIndicator(JsVar *pinVar) { + pinSleepIndicator = jshGetPinFromVar(pinVar); +} + +/*JSON{ "type":"function", "name" : "setDeepSleep", + "description" : [ "Set whether we can enter deep sleep mode, which reduces power consumption to around 1mA. This only works on the Espruino Board.", + "Deep Sleep is currently beta. Espruino will only enter Deep Sleep when there are no timers and it is not connected to USB. USB will not wake Espruino from Deep Sleep, nor will Serial comms (only setWatch will wake it). The System Timer will also pause." ], + "generate" : "jswrap_interface_setDeepSleep", + "params" : [ [ "sleep", "bool", ""] ] +}*/ +void jswrap_interface_setDeepSleep(bool sleep) { + allowDeepSleep = sleep; +} + + +/*JSON{ "type":"function", "name" : "trace", "ifndef" : "SAVE_ON_FLASH", + "description" : "Output debugging information", + "generate" : "jswrap_interface_trace", + "params" : [ [ "root", "JsVarName", "The symbol to output (optional). If nothing is specified, everything will be output"] ] +}*/ +void jswrap_interface_trace(JsVar *root) { + if (jsvIsUndefined(root)) { + jsvTrace(jsvGetRef(jsiGetParser()->root), 0); + } else { + jsvTrace(jsvGetRef(root), 0); + } +} + +/*XXX{ "type":"function", "name" : "dotty", + "description" : "Output dotty-format graph of debugging information", + "generate_full" : "jsvDottyOutput()" +}*/ +/*JSON{ "type":"function", "name" : "dump", + "description" : ["Output current interpreter state in a text form such that it can be copied to a new device", + "Note: 'Internal' functions are currently not handled correctly. You will need to recreate these in the onInit function."], + "generate_full" : "jsiDumpState()" +}*/ +/*JSON{ "type":"function", "name" : "load", + "description" : ["Load program memory out of flash", + "This command only executes when the Interpreter returns to the Idle state - for instance ```a=1;load();a=2;``` will still leave 'a' as undefined (or what it was set to in the saved program)."], + "generate_full" : "jsiSetTodo(TODO_FLASH_LOAD)" +}*/ +/*JSON{ "type":"function", "name" : "save", + "description" : ["Save program memory into flash. It will then be loaded automatically every time Espruino powers on or is hard-reset.", + "This command only executes when the Interpreter returns to the Idle state - for instance ```a=1;save();a=2;``` will save 'a' as 2.", + "In order to stop the program saved with this command being loaded automatically, hold down Button 1 while also pressing reset. On some boards, Button 1 enters bootloader mode, so you will need to press Reset with Button 1 raised, and then hold Button 1 down a fraction of a second later."], + "generate_full" : "jsiSetTodo(TODO_FLASH_SAVE)" +}*/ +/*JSON{ "type":"function", "name" : "reset", + "description" : ["Reset the interpreter - clear program memory, and do not load a saved program from flash. This does NOT reset the underlying hardware (which allows you to reset the device without it disconnecting from USB).", + "This command only executes when the Interpreter returns to the Idle state - for instance ```a=1;reset();a=2;``` will still leave 'a' as undefined.", + "The safest way to do a full reset is to hit the reset button."], + "generate_full" : "jsiSetTodo(TODO_RESET)" +}*/ +/*JSON{ "type":"function", "name" : "print", + "description" : "Print the supplied string", + "generate" : "jswrap_interface_print", + "params" : [ [ "text", "JsVarArray", ""] ] +}*/ +/*JSON{ "type":"staticmethod", "class":"console", "name" : "log", + "description" : "Print the supplied string(s)", + "generate" : "jswrap_interface_print", + "params" : [ [ "text", "JsVarArray", "One or more arguments to print"] ] +}*/ +void jswrap_interface_print(JsVar *v) { + assert(jsvIsArray(v)); + JsArrayIterator it; + jsvArrayIteratorNew(&it, v); + while (jsvArrayIteratorHasElement(&it)) { + JsVar *v = jsvAsString(jsvArrayIteratorGetElement(&it), true); + jsiConsoleRemoveInputLine(); + jsiConsolePrintStringVar(v); + jsvUnLock(v); + jsvArrayIteratorNext(&it); + if (jsvArrayIteratorHasElement(&it)) + jsiConsolePrint(" "); + } + jsvArrayIteratorFree(&it); + jsiConsolePrint("\n"); +} + +/*JSON{ "type":"function", "name" : "edit", + "description" : ["Fill the console with the contents of the given function, so you can edit it.", + "NOTE: This is a convenience function - it will not edit 'inner functions'. For that, you must edit the 'outer function' and re-execute it."], + "generate" : "jswrap_interface_edit", + "params" : [ [ "funcName", "JsVarName", "The name of the function to edit (either a string or just the unquoted name)"] ] +}*/ +void jswrap_interface_edit(JsVar *funcName) { + if (jsvIsString(funcName)) { + JsVar *func = 0; + if (jsvIsName(funcName)) + func = jsvSkipName(funcName); + else + func = jsvSkipNameAndUnLock(jsvFindChildFromVar(jsiGetParser()->root, funcName, 0)); + if (jsvIsFunction(func)) { + JsVar *scopeVar = jsvFindChildFromString(func, JSPARSE_FUNCTION_SCOPE_NAME, false); + JsVarRef scope = jsvGetRef(scopeVar); + jsvUnLock(scopeVar); + JsVar *newLine = jsvNewFromEmptyString(); + if (newLine) { // could be out of memory + jsvAppendStringVarComplete(newLine, funcName); + if (scope) { + // If we have a scope, it's an internal function so we will need to write different code + jsvAppendString(newLine, ".replaceWith("); + } else { + jsvAppendString(newLine, " = "); + } + JsVar *funcData = jsvAsString(func, false); + if (funcData) + jsvAppendStringVarComplete(newLine, funcData); + jsvUnLock(funcData); + if (scope) { + jsvAppendString(newLine, ");"); + } else { + jsvAppendString(newLine, ";"); + } + jsiReplaceInputLine(newLine); + jsvUnLock(newLine); + } + } else { + jsError("Edit should be called with the name of a function"); + } + jsvUnLock(func); + } else { + jsError("Edit should be called with edit(funcName) or edit('funcName')"); + } +} + + +/*JSON{ "type":"function", "name" : "echo", + "description" : "Should TinyJS echo what you type back to you? true = yes (Default), false = no. When echo is off, the result of executing a command is not returned. Instead, you must use 'print' to send output.", + "generate" : "jswrap_interface_echo", + "params" : [ [ "echoOn", "bool", ""] ] +}*/ +void jswrap_interface_echo(bool echoOn) { + echo = echoOn; +} + +/*JSON{ "type":"function", "name" : "getTime", + "description" : "Return the current system time in Seconds (as a floating point number)", + "generate_full" : "(JsVarFloat)jshGetSystemTime() / (JsVarFloat)jshGetTimeFromMilliseconds(1000)", + "return" : ["float", ""] +}*/ + + +/*JSON{ "type":"function", "name" : "getSerial", + "description" : "Get the serial number of this board", + "generate" : "jswrap_interface_getSerial", + "return" : ["JsVar", "The board's serial number"] +}*/ +JsVar *jswrap_interface_getSerial() { + char buf[8]; + unsigned char serial[32]; + int i, serialSize = jshGetSerialNumber(serial, sizeof(serial)); + + JsVar *str = jsvNewFromEmptyString(); + if (!str) return 0; + + for (i=0;i + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * JavaScript methods and functions for the interactive shell + * ---------------------------------------------------------------------------- + */ +#include "jsvar.h" +#include "jsinteractive.h" + +void jswrap_interface_setBusyIndicator(JsVar *pinVar); +void jswrap_interface_setSleepIndicator(JsVar *pinVar); +void jswrap_interface_setDeepSleep(bool sleep); +void jswrap_interface_trace(JsVar *root); +void jswrap_interface_print(JsVar *v); +void jswrap_interface_edit(JsVar *funcName); +void jswrap_interface_echo(bool echoOn); +JsVar *jswrap_interface_getSerial(); diff --git a/components/external/espruino/src/jswrap_io.c b/components/external/espruino/src/jswrap_io.c new file mode 100644 index 0000000000..f03cd216a8 --- /dev/null +++ b/components/external/espruino/src/jswrap_io.c @@ -0,0 +1,437 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * This file is designed to be parsed during the build process + * + * JavaScript Hardware IO Functions + * ---------------------------------------------------------------------------- + */ +#include "jswrap_io.h" +#include "jsvar.h" + + +/*JSON{ "type":"function", "name" : "peek8", + "description" : [ "Read 8 bits of memory at the given location - DANGEROUS!" ], + "generate_full" : "(JsVarInt)*(unsigned char*)jsvGetInteger(addr)", + "params" : [ [ "addr", "int", "The address in memory to read"] ], + "return" : ["int", "The value of memory at the given location"] +}*/ +/*JSON{ "type":"function", "name" : "poke8", + "description" : [ "Write 8 bits of memory at the given location - VERY DANGEROUS!" ], + "generate_full" : "(*(unsigned char*)jsvGetInteger(addr)) = (unsigned char)jsvGetInteger(value)", + "params" : [ [ "addr", "int", "The address in memory to write"], + [ "value", "int", "The value to write"] ] +}*/ +/*JSON{ "type":"function", "name" : "peek16", + "description" : [ "Read 16 bits of memory at the given location - DANGEROUS!" ], + "generate_full" : "(JsVarInt)*(unsigned short*)jsvGetInteger(addr)", + "params" : [ [ "addr", "int", "The address in memory to read"] ], + "return" : ["int", "The value of memory at the given location"] +}*/ +/*JSON{ "type":"function", "name" : "poke16", + "description" : [ "Write 16 bits of memory at the given location - VERY DANGEROUS!" ], + "generate_full" : "(*(unsigned short*)jsvGetInteger(addr)) = (unsigned short)jsvGetInteger(value)", + "params" : [ [ "addr", "int", "The address in memory to write"], + [ "value", "int", "The value to write"] ] +}*/ +/*JSON{ "type":"function", "name" : "peek32", + "description" : [ "Read 32 bits of memory at the given location - DANGEROUS!" ], + "generate_full" : "(JsVarInt)*(unsigned int*)jsvGetInteger(addr)", + "params" : [ [ "addr", "int", "The address in memory to read"] ], + "return" : ["int", "The value of memory at the given location"] +}*/ +/*JSON{ "type":"function", "name" : "poke32", + "description" : [ "Write 32 bits of memory at the given location - VERY DANGEROUS!" ], + "generate_full" : "(*(unsigned int*)jsvGetInteger(addr)) = (unsigned int)jsvGetInteger(value)", + "params" : [ [ "addr", "int", "The address in memory to write"], + [ "value", "int", "The value to write"] ] +}*/ + +/*JSON{ "type":"function", "name" : "analogRead", + "description" : ["Get the analog value of the given pin", + "This is different to Arduino which only returns an integer between 0 and 1023", + "However only pins connected to an ADC will work (see the datasheet)"], + "generate" : "jshPinAnalog", + "params" : [ [ "pin", "pin", "The pin to use"] ], + "return" : ["float", "The analog Value of the Pin between 0 and 1"] +}*/ +/*JSON{ "type":"function", "name" : "analogWrite", + "description" : "Set the analog Value of a pin. It will be output using PWM", + "generate" : "jswrap_io_analogWrite", + "params" : [ [ "pin", "pin", "The pin to use"], + [ "value", "float", "A value between 0 and 1"], + [ "options", "JsVar", ["An object containing options.", + "Currently only freq (pulse frequency in Hz) is available: ```analogWrite(LED1,0.5,{ freq : 10 });``` ", + "Note that specifying a frequency will force PWM output, even if the pin has a DAC"] ] ] +}*/ +void jswrap_io_analogWrite(Pin pin, JsVarFloat value, JsVar *options) { + JsVarFloat freq = 0; + if (jsvIsObject(options)) { + freq = jsvGetFloatAndUnLock(jsvObjectGetChild(options, "freq", 0)); + } + + jshPinAnalogOutput(pin, value, freq); +} + +/*JSON{ "type":"function", "name" : "digitalPulse", + "description" : ["Pulse the pin with the value for the given time in milliseconds", + "eg. ```pulse(A0,1,5);``` pulses A0 high for 5ms", + "digitalPulse is for SHORT pulses that need to be very accurate. If you're doing anything over a few milliseconds, use setTimeout instead" ], + "generate" : "jswrap_io_digitalPulse", + "params" : [ [ "pin", "pin", "The pin to use"], + [ "value", "bool", "Whether to pulse high (true) or low (false)"], + [ "time", "float", "A time in milliseconds"] ] +}*/ +void jswrap_io_digitalPulse(Pin pin, bool value, JsVarFloat time) { + if (time<=0) { + jsWarn("Pulse Time given for digitalPulse is less that or equal to 0"); + } else { + //jsPrintInt((JsVarInt)(time*1000)); + jshPinPulse(pin, value, time); + } +} + +/*JSON{ "type":"function", "name" : "digitalWrite", + "description" : ["Set the digital value of the given pin", + "If pin is an array of pins, eg. ```[A2,A1,A0]``` the value will be treated as an integer where the first array element is the MSB" ], + "generate" : "jswrap_io_digitalWrite", + "params" : [ [ "pin", "JsVar", "The pin to use"], + [ "value", "int", "Whether to pulse high (true) or low (false)"] ] +}*/ +void jswrap_io_digitalWrite(JsVar *pinVar, JsVarInt value) { + if (jsvIsArray(pinVar)) { + JsVarRef pinName = pinVar->lastChild; // NOTE: start at end and work back! + while (pinName) { + JsVar *pinNamePtr = jsvLock(pinName); + JsVar *pinPtr = jsvSkipName(pinNamePtr); + jshPinOutput(jshGetPinFromVar(pinPtr), value&1); + jsvUnLock(pinPtr); + pinName = pinNamePtr->prevSibling; + jsvUnLock(pinNamePtr); + value = value>>1; // next bit down + } + } else { + Pin pin = jshGetPinFromVar(pinVar); + jshPinOutput(pin, value!=0); + } +} + + +/*JSON{ "type":"function", "name" : "digitalRead", + "description" : ["Get the digital value of the given pin", + "If pin is an array of pins, eg. ```[A2,A1,A0]``` the value will be treated as an integer where the first array element is the MSB" ], + "generate" : "jswrap_io_digitalRead", + "params" : [ [ "pin", "JsVar", "The pin to use"] ], + "return" : ["int", "The digital Value of the Pin"] +}*/ +JsVarInt jswrap_io_digitalRead(JsVar *pinVar) { + if (jsvIsArray(pinVar)) { + int pins = 0; + JsVarInt value = 0; + JsVarRef pinName = pinVar->firstChild; + while (pinName) { + JsVar *pinNamePtr = jsvLock(pinName); + JsVar *pinPtr = jsvSkipName(pinNamePtr); + value = (value<<1) | jshPinInput(jshGetPinFromVar(pinPtr)); + jsvUnLock(pinPtr); + pinName = pinNamePtr->nextSibling; + jsvUnLock(pinNamePtr); + pins++; + } + if (pins==0) return 0; // return undefined if array empty + return value; + } else { + Pin pin = jshGetPinFromVar(pinVar); + return jshPinInput(pin); + } +} + +/*JSON{ "type":"function", "name" : "pinMode", + "description" : ["Set the mode of the given pin - note that digitalRead/digitalWrite/etc set this automatically unless pinMode has been called first. If you want digitalRead/etc to set the pin mode automatically after you have called pinMode, simply call it again with no mode argument: ```pinMode(pin)```" ], + "generate" : "jswrap_io_pinMode", + "params" : [ [ "pin", "pin", "The pin to use"], [ "mode", "JsVar", "The mode - a string that is either 'input', 'output', 'input_pullup', or 'input_pulldown'. Do not include this argument if you want to revert to automatic pin mode setting."] ] +}*/ +void jswrap_io_pinMode(Pin pin, JsVar *mode) { + if (!jshIsPinValid(pin)) { + jsError("Invalid pin"); + return; + } + JshPinState m = JSHPINSTATE_UNDEFINED; + if (jsvIsString(mode)) { + if (jsvIsStringEqual(mode, "input")) m = JSHPINSTATE_GPIO_IN; + if (jsvIsStringEqual(mode, "input_pullup")) m = JSHPINSTATE_GPIO_IN_PULLUP; + if (jsvIsStringEqual(mode, "input_pulldown")) m = JSHPINSTATE_GPIO_IN_PULLDOWN; + if (jsvIsStringEqual(mode, "output")) m = JSHPINSTATE_GPIO_OUT; + } + if (m != JSHPINSTATE_UNDEFINED) { + jshSetPinStateIsManual(pin, true); + jshPinSetState(pin, m); + } else { + jshSetPinStateIsManual(pin, false); + if (!jsvIsUndefined(mode)) { + jsError("Unknown pin mode"); + } + } +} + + +/*XXXX{ "type":"function", "name" : "bitBang", + "description" : ["bitBang out a message in a one-wire style BROKEN CURRENTLY" ], + "generate" : "jshBitBang", + "params" : [ [ "pin", "pin", "The pin to use"], + [ "t0h", "float", "The time (in milliseconds) to spend high for a 0"], + [ "t0l", "float", "The time (in milliseconds) to spend low for a 0"], + [ "t1h", "float", "The time (in milliseconds) to spend high for a 1"], + [ "t1l", "float", "The time (in milliseconds) to spend low for a 1"], + [ "data", "JsVar", "A string representing the data"] ] +}*/ + + +/*JSON{ "type":"function", "name" : "setInterval", + "description" : ["Call the function specified REPEATEDLY after the timeout in milliseconds.", + "The function that is being called may also take an argument, which is an object containing a field called 'time' (the time in seconds at which the timer happened)", + "for example: ```setInterval(function (e) { print(e.time); }, 1000);```", + "This can also be removed using clearInterval" ], + "generate" : "jswrap_interface_setInterval", + "params" : [ [ "function", "JsVarName", "A Function or String to be executed"], + [ "timeout", "float", "The time between calls to the function" ] ], + "return" : ["JsVar", "An ID that can be passed to clearInterval"] +}*/ +/*JSON{ "type":"function", "name" : "setTimeout", + "description" : ["Call the function specified ONCE after the timeout in milliseconds.", + "The function that is being called may also take an argument, which is an object containing a field called 'time' (the time in seconds at which the timer happened)", + "for example: ```setTimeout(function (e) { print(e.time); }, 1000);```", + "This can also be removed using clearTimeout" ], + "generate" : "jswrap_interface_setTimeout", + "params" : [ [ "function", "JsVarName", "A Function or String to be executed"], + [ "timeout", "float", "The time until the function will be executed" ] ], + "return" : ["JsVar", "An ID that can be passed to clearTimeout"] +}*/ +JsVar *_jswrap_interface_setTimeoutOrInterval(JsVar *func, JsVarFloat interval, bool isTimeout) { + JsVar *skippedFunc = jsvSkipName(func); + JsVar *itemIndex = 0; + if (!jsvIsFunction(skippedFunc) && !jsvIsString(skippedFunc)) { + jsError("Function or String not supplied!"); + } else { + // Create a new timer + JsVar *timerPtr = jsvNewWithFlags(JSV_OBJECT); + if (intervalroot, 0); + return itemIndex; +} +JsVar *jswrap_interface_setInterval(JsVar *func, JsVarFloat timeout) { + return _jswrap_interface_setTimeoutOrInterval(func, timeout, false); +} +JsVar *jswrap_interface_setTimeout(JsVar *func, JsVarFloat timeout) { + return _jswrap_interface_setTimeoutOrInterval(func, timeout, true); +} + +/*JSON{ "type":"function", "name" : "setWatch", + "description" : ["Call the function specified when the pin changes", + "The function may also take an argument, which is an object containing a field called 'time', which is the time in seconds at which the pin changed state, and 'state', which is the current state of the pin", + " This can also be removed using clearWatch" ], + "generate" : "jswrap_interface_setWatch", + "params" : [ [ "function", "JsVarName", "A Function or String to be executed"], + [ "pin", "pin", "The pin to watch" ], + [ "options", "JsVar", ["If this is a boolean or integer, it determines whether to call this once (false = default) or every time a change occurs (true)", + "If this is an object, it can contain the following information: ```{ repeat: true/false(default), edge:'rising'/'falling'/'both'(default)}```" ] ] ], + "return" : ["JsVar", "An ID that can be passed to clearWatch"] +}*/ +JsVar *jswrap_interface_setWatch(JsVar *funcVar, Pin pin, JsVar *repeatOrObject) { + bool repeat = false; + int edge = 0; + if (jsvIsObject(repeatOrObject)) { + JsVar *v; + repeat = jsvGetBoolAndUnLock(jsvObjectGetChild(repeatOrObject, "repeat", 0)); + v = jsvObjectGetChild(repeatOrObject, "edge", 0); + if (jsvIsString(v)) { + if (jsvIsStringEqual(v, "rising")) edge=1; + else if (jsvIsStringEqual(v, "falling")) edge=-1; + else if (jsvIsStringEqual(v, "both")) edge=0; + else jsWarn("'edge' in setWatch should be a string - either 'rising', 'falling' or 'both'"); + } else if (!jsvIsUndefined(v)) + jsWarn("'edge' in setWatch should be a string - either 'rising', 'falling' or 'both'"); + jsvUnLock(v); + } else + repeat = jsvGetBool(repeatOrObject); + + JsVarInt itemIndex = -1; + JsVar *skippedFunc = jsvSkipName(funcVar); + if (!jsvIsFunction(skippedFunc) && !jsvIsString(skippedFunc)) { + jsError("Function or String not supplied!"); + } else { + // Create a new watch + JsVar *watchPtr = jsvNewWithFlags(JSV_OBJECT); + JsVar *v; + v = jsvNewFromPin(pin); + jsvUnLock(jsvAddNamedChild(watchPtr, v, "pin")); + jsvUnLock(v); + v = jsvNewFromBool(repeat); + jsvUnLock(jsvAddNamedChild(watchPtr, v, "recur")); + jsvUnLock(v); + v = jsvNewFromInteger(edge); + jsvUnLock(jsvAddNamedChild(watchPtr, v, "edge")); + jsvUnLock(v); + jsvUnLock(jsvAddNamedChild(watchPtr, funcVar, "callback")); + JsVar *watchArrayPtr = jsvLock(watchArray); + itemIndex = jsvArrayPushWithInitialSize(watchArrayPtr, watchPtr, 1) - 1; + jsvUnLock(watchArrayPtr); + jsvUnLock(watchPtr); + jshPinWatch(pin, true); + } + jsvUnLock(skippedFunc); + return (itemIndex>=0) ? jsvNewFromInteger(itemIndex) : 0/*undefined*/; +} + +/*JSON{ "type":"function", "name" : "clearInterval", + "description" : ["Clear the Interval that was created with setInterval, for example:", + "```var id = setInterval(function () { print('foo'); }, 1000);```", + "```clearInterval(id);```", + "If no argument is supplied, all timers and intervals are stopped" ], + "generate" : "jswrap_interface_clearInterval", + "params" : [ [ "id", "JsVar", "The id returned by a previous call to setInterval"] ] +}*/ +/*JSON{ "type":"function", "name" : "clearTimeout", + "description" : ["Clear the Timeout that was created with setTimeout, for example:", + "```var id = setTimeout(function () { print('foo'); }, 1000);```", + "```clearTimeout(id);```", + "If no argument is supplied, all timers and intervals are stopped" ], + "generate" : "jswrap_interface_clearTimeout", + "params" : [ [ "id", "JsVar", "The id returned by a previous call to setTimeout"] ] +}*/ +void _jswrap_interface_clearTimeoutOrInterval(JsVar *idVar, bool isTimeout) { + if (jsvIsUndefined(idVar)) { + JsVar *timerArrayPtr = jsvLock(timerArray); + jsvRemoveAllChildren(timerArrayPtr); + jsvUnLock(timerArrayPtr); + } else { + JsVar *child = jsvIsBasic(idVar) ? jsvFindChildFromVarRef(timerArray, idVar, false) : 0; + if (child) { + JsVar *timerArrayPtr = jsvLock(timerArray); + jsvRemoveChild(timerArrayPtr, child); + jsvUnLock(child); + jsvUnLock(timerArrayPtr); + } else { + jsError(isTimeout ? "Unknown Timeout" : "Unknown Interval"); + } + } +} +void jswrap_interface_clearInterval(JsVar *idVar) { + _jswrap_interface_clearTimeoutOrInterval(idVar, false); +} +void jswrap_interface_clearTimeout(JsVar *idVar) { + _jswrap_interface_clearTimeoutOrInterval(idVar, true); +} + +/*JSON{ "type":"function", "name" : "changeInterval", + "description" : ["Change the Interval on a callback created with setInterval, for example:", + "```var id = setInterval(function () { print('foo'); }, 1000); // every second```", + "```changeInterval(id, 1500); // now runs every 1.5 seconds```", + "This takes effect the text time the callback is called (so it is not immediate)."], + "generate" : "jswrap_interface_changeInterval", + "params" : [ [ "id", "JsVar", "The id returned by a previous call to setInterval"], + [ "time","float","The new time period in ms" ] ] +}*/ +void jswrap_interface_changeInterval(JsVar *idVar, JsVarFloat interval) { + if (intervalfirstChild; + while (watch) { + JsVar *watchNamePtr = jsvLock(watch); // effectively the array index + JsVar *pinVar = jsvSkipNameAndUnLock(jsvFindChildFromStringRef(watchNamePtr->firstChild, "pin", false)); + jshPinWatch(jshGetPinFromVar(pinVar), false); // 'unwatch' pin because we know that we're removing ALL watches + jsvUnLock(pinVar); + watch = watchNamePtr->nextSibling; + jsvUnLock(watchNamePtr); + } + // remove all items + jsvRemoveAllChildren(watchArrayPtr); + jsvUnLock(watchArrayPtr); + } else { + JsVar *watchNamePtr = jsvFindChildFromVarRef(watchArray, idVar, false); + if (watchNamePtr) { // child is a 'name' + JsVar *pinVar = jsvSkipNameAndUnLock(jsvFindChildFromStringRef(watchNamePtr->firstChild, "pin", false)); + Pin pin = jshGetPinFromVar(pinVar); + jsvUnLock(pinVar); + + JsVar *watchArrayPtr = jsvLock(watchArray); + jsvRemoveChild(watchArrayPtr, watchNamePtr); + jsvUnLock(watchNamePtr); + + // Now check if this pin is still being watched + bool stillWatched = false; + JsArrayIterator it; + jsvArrayIteratorNew(&it, watchArrayPtr); + while (jsvArrayIteratorHasElement(&it)) { + JsVar *watchPtr = jsvArrayIteratorGetElement(&it); + JsVar *pinVar = jsvObjectGetChild(watchPtr, "pin", 0); + if (jshGetPinFromVar(pinVar) == pin) + stillWatched = true; + jsvUnLock(pinVar); + jsvUnLock(watchPtr); + jsvArrayIteratorNext(&it); + } + jsvArrayIteratorFree(&it); + jsvUnLock(watchArrayPtr); + + if (!stillWatched) + jshPinWatch(pin, false); // 'unwatch' pin + } else { + jsError("Unknown Watch"); + } + } +} + + diff --git a/components/external/espruino/src/jswrap_io.h b/components/external/espruino/src/jswrap_io.h new file mode 100644 index 0000000000..68760c103c --- /dev/null +++ b/components/external/espruino/src/jswrap_io.h @@ -0,0 +1,29 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * JavaScript Hardware IO Functions + * ---------------------------------------------------------------------------- + */ +#include "jsvar.h" +#include "jsinteractive.h" + +void jswrap_io_analogWrite(Pin pin, JsVarFloat value, JsVar *options); +void jswrap_io_digitalPulse(Pin pin, bool value, JsVarFloat time); +void jswrap_io_digitalWrite(JsVar *pinVar, JsVarInt value); +JsVarInt jswrap_io_digitalRead(JsVar *pinVar); +void jswrap_io_pinMode(Pin pin, JsVar *mode); + +JsVar *jswrap_interface_setInterval(JsVar *func, JsVarFloat timeout); +JsVar *jswrap_interface_setTimeout(JsVar *func, JsVarFloat timeout); +JsVar *jswrap_interface_setWatch(JsVar *funcVar, Pin pin, JsVar *repeatOrObject); +void jswrap_interface_clearInterval(JsVar *idVar); +void jswrap_interface_clearTimeout(JsVar *idVar); +void jswrap_interface_changeInterval(JsVar *idVar, JsVarFloat interval); +void jswrap_interface_clearWatch(JsVar *idVar); diff --git a/components/external/espruino/src/jswrap_json.c b/components/external/espruino/src/jswrap_json.c new file mode 100644 index 0000000000..9d16c10f13 --- /dev/null +++ b/components/external/espruino/src/jswrap_json.c @@ -0,0 +1,167 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * This file is designed to be parsed during the build process + * + * JavaScript JSON-handling Functions + * ---------------------------------------------------------------------------- + */ +#include "jswrap_json.h" +#include "jsparse.h" +#include "jsinteractive.h" +#include "jswrapper.h" + +/*JSON{ "type":"staticmethod", + "class" : "JSON", "name" : "stringify", + "description" : "Convert the given object into a JSON string which can subsequently be parsed with JSON.parse or eval", + "generate" : "jswrap_json_stringify", + "params" : [ [ "data", "JsVar", "The data to be converted to a JSON string"] ], + "return" : ["JsVar", "A JSON string"] +}*/ +JsVar *jswrap_json_stringify(JsVar *v) { + JsVar *result = jsvNewFromEmptyString(); + if (result) // could be out of memory + jsfGetJSON(v, result); + return result; +} + +/*JSON{ "type":"staticmethod", + "class" : "JSON", "name" : "parse", + "description" : "Parse the given JSON string into a JavaScript object", + "generate" : "jswrap_json_parse", + "params" : [ [ "string", "JsVar", "A JSON string"] ], + "return" : ["JsVar", "The JavaScript object created by parsing the data string"] +}*/ +JsVar *jswrap_json_parse(JsVar *v) { + JsVar *res = 0; + JsVar *bracketed = jsvNewFromString("("); + if (bracketed) { // could be out of memory + v = jsvAsString(v, true); // try and get this as a string + jsvAppendStringVarComplete(bracketed, v); + jsvAppendString(bracketed, ")"); + res = jspEvaluateVar(jsiGetParser(), bracketed, 0); + jsvUnLock(bracketed); + } + return res; +} + +/* This is like jsfGetJSONWithCallback, but handles ONLY functions (and does not print the initial 'function' text) */ +void jsfGetJSONForFunctionWithCallback(JsVar *var, JsfGetJSONCallbackString callbackString, JsfGetJSONCallbackVar callbackVar, void *callbackData) { + assert(jsvIsFunction(var)); + JsVarRef coderef = 0; // TODO: this should really be in jsvAsString + JsVarRef childref = var->firstChild; + bool firstParm = true; + callbackString(callbackData, "("); + while (childref) { + JsVar *child = jsvLock(childref); + childref = child->nextSibling; + if (jsvIsFunctionParameter(child)) { + if (firstParm) + firstParm=false; + else + callbackString(callbackData, ","); + callbackVar(callbackData, child); // FIXME: escape the string + } else if (jsvIsString(child) && jsvIsStringEqual(child, JSPARSE_FUNCTION_CODE_NAME)) { + coderef = child->firstChild; + } + jsvUnLock(child); + } + callbackString(callbackData, ") "); + if (coderef) { + JsVar *codeVar = jsvLock(coderef); + callbackVar(callbackData, codeVar); + jsvUnLock(codeVar); + } else callbackString(callbackData, "{}"); +} + +void jsfGetJSONWithCallback(JsVar *var, JsfGetJSONCallbackString callbackString, JsfGetJSONCallbackVar callbackVar, void *callbackData) { + if (jsvIsUndefined(var)) { + callbackString(callbackData, "undefined"); + } else if (jsvIsArray(var)) { + int length = (int)jsvGetArrayLength(var); + int i; + callbackString(callbackData, "["); + for (i=0;ifirstChild; + callbackString(callbackData, "{"); + while (childref) { + JsVar *child = jsvLock(childref); + bool hidden = jsvIsInternalObjectKey(child); + if (!hidden) { + if (first) + first = false; + else + callbackString(callbackData, ","); + + callbackString(callbackData, "\""); + callbackVar(callbackData, child); // FIXME: escape the string + callbackString(callbackData, "\":"); + } + JsVar *childVar = child->firstChild ? jsvLock(child->firstChild) : 0; + childref = child->nextSibling; + jsvUnLock(child); + + if (!hidden) { + jsfGetJSONWithCallback(childVar, callbackString, callbackVar, callbackData); + } + jsvUnLock(childVar); + } + callbackString(callbackData, "}"); + } else if (jsvIsFunction(var)) { + callbackString(callbackData, "function "); + jsfGetJSONForFunctionWithCallback(var, callbackString, callbackVar, callbackData); + } else if (jsvIsString(var) && !jsvIsName(var)) { + // escape the string + callbackString(callbackData, "\""); + JsvStringIterator it; + jsvStringIteratorNew(&it, var, 0); + while (jsvStringIteratorHasChar(&it)) { + char ch = jsvStringIteratorGetChar(&it); + callbackString(callbackData, escapeCharacter(ch)); + jsvStringIteratorNext(&it); + } + jsvStringIteratorFree(&it); + callbackString(callbackData, "\""); + } else { + JsVar *str = jsvAsString(var, false); + if (str) { + callbackVar(callbackData, str); + jsvUnLock(str); + } + } +} + +void jsfGetJSON(JsVar *var, JsVar *result) { + assert(jsvIsString(result)); + jsfGetJSONWithCallback(var, (JsfGetJSONCallbackString)jsvAppendString, (JsfGetJSONCallbackVar)jsvAppendStringVarComplete, result); +} + +void _jsfPrintJSON_str(void *data, const char *str) { NOT_USED(data); jsiConsolePrint(str); } +void _jsfPrintJSON_var(void *data, JsVar *var) { NOT_USED(data); jsiConsolePrintStringVar(var); } +void jsfPrintJSON(JsVar *var) { + jsfGetJSONWithCallback(var, _jsfPrintJSON_str, _jsfPrintJSON_var, 0); +} +void jsfPrintJSONForFunction(JsVar *var) { + jsfGetJSONForFunctionWithCallback(var, _jsfPrintJSON_str, _jsfPrintJSON_var, 0); +} diff --git a/components/external/espruino/src/jswrap_json.h b/components/external/espruino/src/jswrap_json.h new file mode 100644 index 0000000000..2452f604de --- /dev/null +++ b/components/external/espruino/src/jswrap_json.h @@ -0,0 +1,33 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * JavaScript JSON-handling Functions + * ---------------------------------------------------------------------------- + */ +#include "jsvar.h" + +JsVar *jswrap_json_stringify(JsVar *v); +JsVar *jswrap_json_parse(JsVar *v); + +typedef void (*JsfGetJSONCallbackString)(void *data, const char *string); +typedef void (*JsfGetJSONCallbackVar)(void *data, JsVar *var); + +/* This is like jsfGetJSONWithCallback, but handles ONLY functions (and does not print the initial 'function' text) */ +void jsfGetJSONForFunctionWithCallback(JsVar *var, JsfGetJSONCallbackString callbackString, JsfGetJSONCallbackVar callbackVar, void *callbackData); +/* Dump to JSON, using the given callbacks for printing data */ +void jsfGetJSONWithCallback(JsVar *var, JsfGetJSONCallbackString callbackString, JsfGetJSONCallbackVar callbackVar, void *callbackData); + +/* Convenience function for using jsfGetJSONWithCallback - print to var */ +void jsfGetJSON(JsVar *var, JsVar *result); + +/* Convenience function for using jsfGetJSONWithCallback - print to console */ +void jsfPrintJSON(JsVar *var); +/* Convenience function for using jsfGetJSONForFunctionWithCallback - print to console */ +void jsfPrintJSONForFunction(JsVar *var); diff --git a/components/external/espruino/src/jswrap_modules.c b/components/external/espruino/src/jswrap_modules.c new file mode 100644 index 0000000000..a0f9da7ccc --- /dev/null +++ b/components/external/espruino/src/jswrap_modules.c @@ -0,0 +1,195 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * This file is designed to be parsed during the build process + * + * JavaScript Functions for handling Modules + * ---------------------------------------------------------------------------- + */ +#include "jswrap_functions.h" +#include "jslex.h" +#include "jsvar.h" +#include "jsparse.h" +#include "jsinteractive.h" +#include "jswrapper.h" +#ifdef USE_FILESYSTEM +#include "../libs/jswrap_fat.h" +#endif + +static JsVar *jswrap_modules_getModuleList() { + JsVar *moduleListName = jsvFindChildFromString(jsiGetParser()->root, JSPARSE_MODULE_CACHE_NAME, true); + if (!moduleListName) return 0; // out of memory + JsVar *moduleList = jsvSkipName(moduleListName); + if (!moduleList) { + moduleList = jsvNewWithFlags(JSV_OBJECT); + if (!moduleList) { jsvUnLock(moduleListName); return 0; } // out of memory + jsvSetValueOfName(moduleListName, moduleList); // no need to unlock + } + jsvUnLock(moduleListName); + return moduleList; +} + +/*JSON{ "type":"function", "name" : "require", + "description" : "Load the given module, and return the exported functions", + "generate" : "jswrap_require", + "params" : [ [ "moduleName", "JsVar", "A String containing the name of the given module"] ], + "return" : ["JsVar", "The result of evaluating the string"] +}*/ +JsVar *jswrap_require(JsVar *moduleName) { + if (!jsvIsString(moduleName)) { + jsWarn("Expecting a module name as a string, but got %t", moduleName); + return 0; + } + // Search to see if we have already loaded this module + + JsVar *moduleList = jswrap_modules_getModuleList(); + if (!moduleList) return 0; // out of memory + JsVar *moduleExportName = jsvFindChildFromVar(moduleList, moduleName, true); + jsvUnLock(moduleList); + if (!moduleExportName) return 0; // out of memory + JsVar *moduleExport = jsvSkipName(moduleExportName); + if (moduleExport) { + // Found the module! + jsvUnLock(moduleExportName); + return moduleExport; + } + + // Now check if it is built-in + char moduleNameBuf[32]; + jsvGetString(moduleName, moduleNameBuf, sizeof(moduleNameBuf)); + if (jswIsBuiltInLibrary(moduleNameBuf)) { + // create a 'fake' module that Espruino can use to map its built-in functions against + moduleExport = jspNewBuiltin(moduleNameBuf); + } else { + // Now try and load it + JsVar *fileContents = 0; + //if (jsvIsStringEqual(moduleName,"http")) {} + //if (jsvIsStringEqual(moduleName,"fs")) {} + #ifdef USE_FILESYSTEM + JsVar *modulePath = jsvNewFromString( + #ifdef LINUX + "node_modules/" + #else + "NODE_M~1/" + #endif + ); + if (!modulePath) { jsvUnLock(moduleExportName); return 0; } // out of memory + jsvAppendStringVarComplete(modulePath, moduleName); + jsvAppendString(modulePath,".js"); + fileContents = wrap_fat_readFile(modulePath); + jsvUnLock(modulePath); + #endif + if (!fileContents || jsvIsStringEqual(fileContents,"")) { + jsvUnLock(moduleExportName); + jsvUnLock(fileContents); + jsWarn("Module not found"); + return 0; + } + moduleExport = jspEvaluateModule(jsiGetParser(), fileContents); + jsvUnLock(fileContents); + } + + assert(moduleExport); + jsvSetValueOfName(moduleExportName, moduleExport); // save in cache + jsvUnLock(moduleExportName); + return moduleExport; +} + +/*JSON{ "type":"staticmethod", + "class" : "Modules", "name" : "getCached", + "description" : "Return an array of module names that have been cached", + "generate" : "jswrap_modules_getCached", + "return" : ["JsVar", "An array of module names"] +}*/ +JsVar *jswrap_modules_getCached() { + JsVar *arr = jsvNewWithFlags(JSV_ARRAY); + if (!arr) return 0; // out of memory + + JsVar *moduleList = jswrap_modules_getModuleList(); + if (!moduleList) return arr; // out of memory + + JsObjectIterator it; + jsvObjectIteratorNew(&it, moduleList); + while (jsvObjectIteratorHasElement(&it)) { + JsVar *idx = jsvObjectIteratorGetKey(&it); + JsVar *idxCopy = jsvCopyNameOnly(idx, false, false); + jsvArrayPushAndUnLock(arr, idxCopy); + jsvUnLock(idx); + jsvObjectIteratorNext(&it); + } + jsvObjectIteratorFree(&it); + jsvUnLock(moduleList); + return arr; +} + +/*JSON{ "type":"staticmethod", + "class" : "Modules", "name" : "removeCached", + "description" : "Remove the given module from the list of cached modules", + "generate" : "jswrap_modules_removeCached", + "params" : [ [ "id", "JsVar", "The module name to remove"] ] +}*/ +void jswrap_modules_removeCached(JsVar *id) { + if (!jsvIsString(id)) { + jsError("The argument to removeCached must be a string"); + return; + } + JsVar *moduleList = jswrap_modules_getModuleList(); + if (!moduleList) return; // out of memory + + JsVar *moduleExportName = jsvFindChildFromVar(moduleList, id, false); + if (!moduleExportName) { + jsWarn("Module not found"); + } else { + jsvRemoveChild(moduleList, moduleExportName); + jsvUnLock(moduleExportName); + } + + jsvUnLock(moduleList); +} + +/*JSON{ "type":"staticmethod", + "class" : "Modules", "name" : "removeAllCached", + "description" : "Remove all cached modules", + "generate" : "jswrap_modules_removeAllCached" +}*/ +void jswrap_modules_removeAllCached() { + JsVar *moduleList = jswrap_modules_getModuleList(); + if (!moduleList) return; // out of memory + jsvRemoveAllChildren(moduleList); + jsvUnLock(moduleList); +} + +/*JSON{ "type":"staticmethod", + "class" : "Modules", "name" : "addCached", + "description" : "Add the given module to the cache", + "generate" : "jswrap_modules_addCached", + "params" : [ [ "id", "JsVar", "The module name to add" ], + [ "sourcecode", "JsVar", "The module's sourcecode" ] ] +}*/ +void jswrap_modules_addCached(JsVar *id, JsVar *sourceCode) { + if (!jsvIsString(id) || !jsvIsString(sourceCode)) { + jsError("Both arguments to addCached must be strings"); + return; + } + + JsVar *moduleList = jswrap_modules_getModuleList(); + if (!moduleList) return; // out of memory + + JsVar *moduleExport = jspEvaluateModule(jsiGetParser(), sourceCode); + if (!moduleExport) { + jsWarn("Unable to load module"); + } else { + JsVar *moduleName = jsvFindChildFromVar(moduleList, id, true); + if (moduleName) jsvSetValueOfName(moduleName, moduleExport); + jsvUnLock(moduleExport); + } + jsvUnLock(moduleList); + +} diff --git a/components/external/espruino/src/jswrap_modules.h b/components/external/espruino/src/jswrap_modules.h new file mode 100644 index 0000000000..2d2c07a345 --- /dev/null +++ b/components/external/espruino/src/jswrap_modules.h @@ -0,0 +1,21 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * JavaScript Functions for handling Modules + * ---------------------------------------------------------------------------- + */ +#include "jsvar.h" + +JsVar *jswrap_require(JsVar *modulename); + +JsVar *jswrap_modules_getCached(); +void jswrap_modules_removeCached(JsVar *id); +void jswrap_modules_removeAllCached(); +void jswrap_modules_addCached(JsVar *id, JsVar *sourceCode); diff --git a/components/external/espruino/src/jswrap_object.c b/components/external/espruino/src/jswrap_object.c new file mode 100644 index 0000000000..809ce9b486 --- /dev/null +++ b/components/external/espruino/src/jswrap_object.c @@ -0,0 +1,332 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * This file is designed to be parsed during the build process + * + * JavaScript methods for Objects and Functions + * ---------------------------------------------------------------------------- + */ +#include "jswrap_object.h" +#include "jsparse.h" +#include "jsinteractive.h" + +/*JSON{ "type":"class", + "class" : "Hardware", + "check" : "jsvIsRoot(var)", + "description" : ["This is the built-in class for the Espruino device. It is the 'root scope', as 'Window' is for JavaScript on the desktop." ] +}*/ +/*JSON{ "type":"class", + "class" : "Object", + "check" : "jsvIsObject(var)", + "description" : ["This is the built-in class for Objects" ] +}*/ +/*JSON{ "type":"class", + "class" : "Function", + "check" : "jsvIsFunction(var)", + "description" : ["This is the built-in class for Functions" ] +}*/ +/*JSON{ "type":"class", + "class" : "Integer", + "check" : "jsvIsInt(var)", + "description" : ["This is the built-in class for Integer values" ] +}*/ +/*JSON{ "type":"class", + "class" : "Double", + "check" : "jsvIsFloat(var)", + "description" : ["This is the built-in class for Floating Point values" ] +}*/ + +/*JSON{ "type":"property", "class": "Object", "name" : "length", + "description" : "Find the length of the object", + "generate" : "jswrap_object_length", + "return" : ["JsVar", "The value of the string"] +}*/ +JsVar *jswrap_object_length(JsVar *parent) { + if (jsvIsArray(parent)) { + return jsvNewFromInteger(jsvGetArrayLength(parent)); + } else if (jsvIsArrayBuffer(parent)) { + return jsvNewFromInteger((JsVarInt)jsvGetArrayBufferLength(parent)); + } else if (jsvIsString(parent)) { + return jsvNewFromInteger((JsVarInt)jsvGetStringLength(parent)); + } + return 0; +} + +/*JSON{ "type":"method", "class": "Object", "name" : "toString", + "description" : "Convert the Object to a string", + "generate" : "jswrap_object_toString", + "params" : [ [ "radix", "JsVar", "If the object is an integer, the radix (between 2 and 36) to use. NOTE: Setting a radix does not work on floating point numbers."] ], + "return" : ["JsVar", "A String representing the object"] +}*/ +JsVar *jswrap_object_toString(JsVar *parent, JsVar *arg0) { + if (jsvIsInt(arg0) && jsvIsInt(parent)) { + JsVarInt radix = jsvGetInteger(arg0); + if (radix>=2 && radix<=36) { + char buf[JS_NUMBER_BUFFER_SIZE]; + itoa(parent->varData.integer, buf, (unsigned int)radix); + return jsvNewFromString(buf); + } + } + return jsvAsString(parent, false); +} + +/*JSON{ "type":"method", "class": "Object", "name" : "clone", + "description" : "Copy this object completely", + "generate" : "jswrap_object_clone", + "return" : ["JsVar", "A copy of this Object"] +}*/ +JsVar *jswrap_object_clone(JsVar *parent) { + return jsvCopy(parent); +} + +/*JSON{ "type":"staticmethod", "class": "Object", "name" : "keys", + "description" : "Return all enumerable keys of the given object", + "generate" : "jswrap_object_keys", + "params" : [ [ "object", "JsVar", "The object to return keys for"] ], + "return" : ["JsVar", "An array of strings - one for each key on the given object"] +}*/ +JsVar *jswrap_object_keys(JsVar *obj) { + if (jsvIsIterable(obj)) { + bool (*checkerFunction)(JsVar*) = 0; + if (jsvIsFunction(obj)) checkerFunction = jsvIsInternalFunctionKey; + else if (jsvIsObject(obj)) checkerFunction = jsvIsInternalObjectKey; + + JsVar *arr = jsvNewWithFlags(JSV_ARRAY); + if (!arr) return 0; + JsvIterator it; + jsvIteratorNew(&it, obj); + while (jsvIteratorHasElement(&it)) { + JsVar *key = jsvIteratorGetKey(&it); + if (!(checkerFunction && checkerFunction(key))) { + JsVar *name = jsvCopyNameOnly(key,false,false); + if (name) { + jsvArrayPushAndUnLock(arr, name); + } + } + jsvUnLock(key); + jsvIteratorNext(&it); + } + jsvIteratorFree(&it); + return arr; + } else { + jsWarn("Object.keys called on non-object"); + return 0; + } +} + +/*JSON{ "type":"method", "class": "Object", "name" : "on", + "description" : ["Register an event listener for this object, for instance ```http.on('data', function(d) {...})```. See Node.js's EventEmitter."], + "generate" : "jswrap_object_on", + "params" : [ [ "event", "JsVar", "The name of the event, for instance 'data'"], + [ "listener", "JsVar", "The listener to call when this event is received"] ] +}*/ +void jswrap_object_on(JsVar *parent, JsVar *event, JsVar *listener) { + if (!jsvIsObject(parent)) { + jsWarn("Parent must be a proper object - not a String, Integer, etc."); + return; + } + if (!jsvIsString(event)) { + jsWarn("First argument to EventEmitter.on(..) must be a string"); + return; + } + if (!jsvIsFunction(listener) && !jsvIsString(listener)) { + jsWarn("Second argument to EventEmitter.on(..) must be a function or a String (containing code)"); + return; + } + char eventName[16] = "#on"; + jsvGetString(event, &eventName[3], sizeof(eventName)-4); + + JsVar *eventList = jsvFindChildFromString(parent, eventName, true); + JsVar *eventListeners = jsvSkipName(eventList); + if (jsvIsUndefined(eventListeners)) { + // just add + jsvSetValueOfName(eventList, listener); + } else { + if (jsvIsArray(eventListeners)) { + // we already have an array, just add to it + jsvArrayPush(eventListeners, listener); + } else { + // not an array - we need to make it an array + JsVar *arr = jsvNewWithFlags(JSV_ARRAY); + jsvArrayPush(arr, eventListeners); + jsvArrayPush(arr, listener); + jsvSetValueOfName(eventList, arr); + jsvUnLock(arr); + } + } + jsvUnLock(eventListeners); + jsvUnLock(eventList); +} + +/*JSON{ "type":"method", "class": "Object", "name" : "emit", + "description" : ["Call the event listeners for this object, for instance ```http.emit('data', 'Foo')```. See Node.js's EventEmitter."], + "generate" : "jswrap_object_emit", + "params" : [ [ "event", "JsVar", "The name of the event, for instance 'data'"], + [ "v1", "JsVar", "Optional argument 1"], + [ "v2", "JsVar", "Optional argument 2"] ] +}*/ +void jswrap_object_emit(JsVar *parent, JsVar *event, JsVar *v1, JsVar *v2) { + if (!jsvIsObject(parent)) { + jsWarn("Parent must be a proper object - not a String, Integer, etc."); + return; + } + if (!jsvIsString(event)) { + jsWarn("First argument to EventEmitter.emit(..) must be a string"); + return; + } + char eventName[16] = "#on"; + jsvGetString(event, &eventName[3], sizeof(eventName)-4); + jsiQueueObjectCallbacks(parent, eventName, v1, v2); +} + +/*JSON{ "type":"method", "class": "Object", "name" : "removeAllListeners", + "description" : ["Removes all listeners, or those of the specified event."], + "generate" : "jswrap_object_removeAllListeners", + "params" : [ [ "event", "JsVar", "The name of the event, for instance 'data'"] ] +}*/ +void jswrap_object_removeAllListeners(JsVar *parent, JsVar *event) { + if (!jsvIsObject(parent)) { + jsWarn("Parent must be a proper object - not a String, Integer, etc."); + return; + } + if (jsvIsString(event)) { + // remove the whole child containing listeners + char eventName[16] = "#on"; + jsvGetString(event, &eventName[3], sizeof(eventName)-4); + JsVar *eventList = jsvFindChildFromString(parent, eventName, true); + if (eventList) { + jsvRemoveChild(parent, eventList); + jsvUnLock(eventList); + } + } else if (jsvIsUndefined(event)) { + // Eep. We must remove everything beginning with '#on' + JsObjectIterator it; + jsvObjectIteratorNew(&it, parent); + while (jsvObjectIteratorHasElement(&it)) { + JsVar *key = jsvObjectIteratorGetKey(&it); + jsvObjectIteratorNext(&it); + if (jsvIsString(key) && + key->varData.str[0]=='#' && + key->varData.str[1]=='o' && + key->varData.str[2]=='n') { + // begins with #on - we must kill it + jsvRemoveChild(parent, key); + } + jsvUnLock(key); + } + jsvObjectIteratorFree(&it); + } else { + jsWarn("First argument to EventEmitter.removeAllListeners(..) must be a string, or undefined"); + return; + } +} + +// ------------------------------------------------------------------------------ + +/*JSON{ "type":"method", "class": "Function", "name" : "replaceWith", + "description" : ["This replaces the function with the one in the argument - while keeping the old function's scope. This allows inner functions to be edited, and is used when edit() is called on an inner function."], + "generate" : "jswrap_function_replaceWith", + "params" : [ [ "newFunc", "JsVar", "The new function to replace this function with"] ] +}*/ +void jswrap_function_replaceWith(JsVar *oldFunc, JsVar *newFunc) { + if (!jsvIsFunction(newFunc)) { + jsWarn("First argument of replaceWith should be a function - ignoring"); + return; + } + // Grab scope - the one thing we want to keep + JsVar *scope = jsvFindChildFromString(oldFunc, JSPARSE_FUNCTION_SCOPE_NAME, false); + // so now remove all existing entries + jsvRemoveAllChildren(oldFunc); + // now re-add scope + jsvAddName(oldFunc, scope); + jsvUnLock(scope); + // now re-add other entries + JsObjectIterator it; + jsvObjectIteratorNew(&it, newFunc); + while (jsvObjectIteratorHasElement(&it)) { + JsVar *el = jsvObjectIteratorGetKey(&it); + jsvObjectIteratorNext(&it); + if (!jsvIsStringEqual(el, JSPARSE_FUNCTION_SCOPE_NAME)) { + JsVar *copy = jsvCopy(el); + if (copy) { + jsvAddName(oldFunc, copy); + jsvUnLock(copy); + } + } + } + jsvObjectIteratorFree(&it); + +} + +/*JSON{ "type":"method", "class": "Function", "name" : "call", + "description" : ["This executes the function with the supplied 'this' argument and parameters"], + "generate" : "jswrap_function_call", + "params" : [ [ "this", "JsVar", "The value to use as the 'this' argument when executing the function"], + [ "a", "JsVar", "Optional Parameter 1"], + [ "b", "JsVar", "Optional Parameter 2"], + [ "c", "JsVar", "Optional Parameter 3"], + [ "d", "JsVar", "Optional Parameter 4"] + ], + "return" : [ "JsVar", "The return value of executing this function" ] +}*/ +JsVar *jswrap_function_call(JsVar *parent, JsVar *thisArg, JsVar *a, JsVar *b, JsVar *c, JsVar *d) { + JsVar *args[4] = {a,b,c,d}; + int argC = 0; + while (argC<4 && args[argC]!=0) argC++; + return jspeFunctionCall(parent, 0, thisArg, false, argC, args); +} + +/*JSON{ "type":"method", "class": "Function", "name" : "apply", + "description" : ["This executes the function with the supplied 'this' argument and parameters"], + "generate" : "jswrap_function_apply", + "params" : [ [ "this", "JsVar", "The value to use as the 'this' argument when executing the function"], + [ "args", "JsVar", "Optional Array of Aruments"] + ], + "return" : [ "JsVar", "The return value of executing this function" ] +}*/ +JsVar *jswrap_function_apply(JsVar *parent, JsVar *thisArg, JsVar *argsArray) { + unsigned int i; + JsVar **args = 0; + size_t argC = 0; + + if (jsvIsArray(argsArray)) { + argC = (unsigned int)jsvGetArrayLength(argsArray); + if (argC>64) argC=64; // sanity +#ifdef RT_USING_JS + args = (JsVar**)rt_malloc((size_t)argC * sizeof(JsVar*)); +#else + args = (JsVar**)alloca((size_t)argC * sizeof(JsVar*)); +#endif + + for (i=0;i=0 && idx + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * JavaScript methods for Objects and Functions + * ---------------------------------------------------------------------------- + */ +#include "jsvar.h" + +JsVar *jswrap_object_length(JsVar *parent); +JsVar *jswrap_object_toString(JsVar *parent, JsVar *arg0); +JsVar *jswrap_object_clone(JsVar *parent); +JsVar *jswrap_object_keys(JsVar *obj); + +void jswrap_object_on(JsVar *parent, JsVar *event, JsVar *listener); +void jswrap_object_emit(JsVar *parent, JsVar *event, JsVar *v1, JsVar *v2); +void jswrap_object_removeAllListeners(JsVar *parent, JsVar *event); + +void jswrap_function_replaceWith(JsVar *parent, JsVar *newFunc); +JsVar *jswrap_function_call(JsVar *parent, JsVar *thisArg, JsVar *a, JsVar *b, JsVar *c, JsVar *d); +JsVar *jswrap_function_apply(JsVar *parent, JsVar *thisArg, JsVar *argsArray); diff --git a/components/external/espruino/src/jswrap_onewire.c b/components/external/espruino/src/jswrap_onewire.c new file mode 100644 index 0000000000..f6c670cc6e --- /dev/null +++ b/components/external/espruino/src/jswrap_onewire.c @@ -0,0 +1,332 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * This file is designed to be parsed during the build process + * + * JavaScript OneWire Functions + * ---------------------------------------------------------------------------- + */ +#include "jswrap_onewire.h" +#include "jsdevices.h" +#include "jsinteractive.h" + +/*JSON{ "type":"class", + "class" : "OneWire", + "description" : ["This class provides a software-defined OneWire master. It is designed to be similar to Arduino's OneWire library." ] +}*/ + +static inline Pin onewire_getpin(JsVar *parent) { + return jshGetPinFromVarAndUnLock(jsvObjectGetChild(parent, "pin", 0)); +} + + +/** Reset one-wire, return true if a device was present */ +static bool NO_INLINE OneWireReset(Pin pin) { + jshPinSetState(pin, JSHPINSTATE_GPIO_OUT_OPENDRAIN); + //jshInterruptOff(); + jshPinSetValue(pin, 0); + jshDelayMicroseconds(500); + jshPinSetValue(pin, 1); + jshDelayMicroseconds(80); + bool hasDevice = !jshPinGetValue(pin); + //jshInterruptOn(); + jshDelayMicroseconds(420); + return hasDevice; +} + +/** Write 'bits' bits, and return what was read (to read, you must send all 1s) */ +static JsVarInt NO_INLINE OneWireRead(Pin pin, int bits) { + jshPinSetState(pin, JSHPINSTATE_GPIO_OUT_OPENDRAIN); + JsVarInt result = 0; + JsVarInt mask = 1; + while (bits-- > 0) { + jshInterruptOff(); + jshPinSetValue(pin, 0); + jshDelayMicroseconds(3); + jshPinSetValue(pin, 1); + jshDelayMicroseconds(10); // leave time to let it rise + if (jshPinGetValue(pin)) + result = result | mask; + jshInterruptOn(); + jshDelayMicroseconds(53); + mask = mask << 1; + } + + return result; +} + +/** Write 'bits' bits, and return what was read (to read, you must send all 1s) */ +static void NO_INLINE OneWireWrite(Pin pin, int bits, JsVarInt data) { + jshPinSetState(pin, JSHPINSTATE_GPIO_OUT_OPENDRAIN); + JsVarInt mask = 1; + while (bits-- > 0) { + if (data & mask) { // short pulse + jshInterruptOff(); + jshPinSetValue(pin, 0); + jshDelayMicroseconds(10); + jshPinSetValue(pin, 1); + jshInterruptOn(); + jshDelayMicroseconds(55); + } else { // long pulse + jshInterruptOff(); + jshPinSetValue(pin, 0); + jshDelayMicroseconds(65); + jshPinSetValue(pin, 1); + jshInterruptOn(); + jshDelayMicroseconds(5); + } + mask = mask << 1; + } +} + +/*JSON{ "type":"constructor", "class": "OneWire", "name": "OneWire", + "description" : "Create a software OneWire implementation on the given pin", + "generate" : "jswrap_onewire_constructor", + "params" : [ [ "pin", "pin", "The pin to implement OneWire on" ] ], + "return" : [ "JsVar", "A OneWire object" ] + +}*/ +JsVar *jswrap_onewire_constructor(Pin pin) { + JsVar *ow = jspNewObject(jsiGetParser(), 0, "OneWire"); + if (ow) { + JsVar *pinVar = jsvFindChildFromString(ow, "pin", true); + if (pinVar) { + JsVar *pv = jsvNewFromPin(pin); + jsvSetValueOfName(pinVar, pv); + jsvUnLock(pv); + } + jsvUnLock(pinVar); + } + return ow; +} + + +/*JSON{ "type":"method", "class": "OneWire", "name" : "reset", + "description" : "Perform a reset cycle", + "generate" : "jswrap_onewire_reset", + "return" : [ "bool", "True is a device was present (it held the bus low)" ] +}*/ +bool jswrap_onewire_reset(JsVar *parent) { + Pin pin = onewire_getpin(parent); + if (!jshIsPinValid(pin)) return 0; + return OneWireReset(pin); +} + +/*JSON{ "type":"method", "class": "OneWire", "name" : "select", + "description" : "Select a ROM - reset needs to be done first", + "generate" : "jswrap_onewire_select", + "params" : [ [ "rom", "int", "The rom to select" ] ] +}*/ +void jswrap_onewire_select(JsVar *parent, JsVarInt rom) { + Pin pin = onewire_getpin(parent); + if (!jshIsPinValid(pin)) return; + OneWireWrite(pin, 8, 0x55); + OneWireWrite(pin, 64, rom); +} + +/*JSON{ "type":"method", "class": "OneWire", "name" : "skip", + "description" : "Skip a ROM", + "generate" : "jswrap_onewire_skip" +}*/ +void jswrap_onewire_skip(JsVar *parent) { + Pin pin = onewire_getpin(parent); + if (!jshIsPinValid(pin)) return; + OneWireWrite(pin, 8, 0xCC); +} + +/*JSON{ "type":"method", "class": "OneWire", "name" : "write", + "description" : "Write a byte", + "generate" : "jswrap_onewire_write", + "params" : [ [ "data", "int", "A byte to write" ], + [ "power", "bool", "Whether to leave power on after write (default is false)" ] ] +}*/ +void jswrap_onewire_write(JsVar *parent, int data, bool leavePowerOn) { + Pin pin = onewire_getpin(parent); + if (!jshIsPinValid(pin)) return; + OneWireWrite(pin, 8, data); + + if (!leavePowerOn) { + jshPinSetState(pin, JSHPINSTATE_GPIO_IN); + jshPinSetValue(pin, 0); + } +} + +/*JSON{ "type":"method", "class": "OneWire", "name" : "read", + "description" : "Read a byte", + "generate" : "jswrap_onewire_read", + "return" : [ "int", "The byte that was read" ] +}*/ +JsVarInt jswrap_onewire_read(JsVar *parent) { + Pin pin = onewire_getpin(parent); + if (!jshIsPinValid(pin)) return -1; + return OneWireRead(pin, 8); +} + + +/*JSON{ "type":"method", "class": "OneWire", "name" : "search", + "description" : "Search for devices", + "generate" : "jswrap_onewire_search", + "return" : [ "JsVar", "An array of devices that were found" ] +}*/ +JsVar *jswrap_onewire_search(JsVar *parent) { + // search - code from http://www.maximintegrated.com/app-notes/index.mvp/id/187 + Pin pin = onewire_getpin(parent); + if (!jshIsPinValid(pin)) return 0; + + JsVar *array = jsvNewWithFlags(JSV_ARRAY); + if (!array) return 0; + + // global search state + unsigned char ROM_NO[8]; + int LastDiscrepancy; + int LastFamilyDiscrepancy; + int LastDeviceFlag; + + // reset the search state + LastDiscrepancy = 0; + LastDeviceFlag = FALSE; + LastFamilyDiscrepancy = 0; + + int search_result = true; + + while (search_result) { + + int id_bit_number; + int last_zero, rom_byte_number; + unsigned char id_bit, cmp_id_bit; + unsigned char rom_byte_mask, search_direction; + + // initialize for search + id_bit_number = 1; + last_zero = 0; + rom_byte_number = 0; + rom_byte_mask = 1; + search_result = 0; + + // if the last call was not the last one + if (!LastDeviceFlag) + { + // 1-Wire reset + if (!OneWireReset(pin)) + { + // reset the search + LastDiscrepancy = 0; + LastDeviceFlag = FALSE; + LastFamilyDiscrepancy = 0; + return array; + } + + // issue the search command + OneWireWrite(pin, 8, 0xF0); + + // loop to do the search + do + { + // read a bit and its complement + id_bit = (unsigned char)OneWireRead(pin, 1); + cmp_id_bit = (unsigned char)OneWireRead(pin, 1); + + // check for no devices on 1-wire + if ((id_bit == 1) && (cmp_id_bit == 1)) + break; + else + { + // all devices coupled have 0 or 1 + if (id_bit != cmp_id_bit) + search_direction = id_bit; // bit write value for search + else + { + // if this discrepancy if before the Last Discrepancy + // on a previous next then pick the same as last time + if (id_bit_number < LastDiscrepancy) + search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0); + else + // if equal to last pick 1, if not then pick 0 + search_direction = (id_bit_number == LastDiscrepancy); + + // if 0 was picked then record its position in LastZero + if (search_direction == 0) + { + last_zero = id_bit_number; + + // check for Last discrepancy in family + if (last_zero < 9) + LastFamilyDiscrepancy = last_zero; + } + } + + // set or clear the bit in the ROM byte rom_byte_number + // with mask rom_byte_mask + if (search_direction == 1) + ROM_NO[rom_byte_number] |= rom_byte_mask; + else + ROM_NO[rom_byte_number] &= (unsigned char)~rom_byte_mask; + + // serial number search direction write bit + OneWireWrite(pin, 1, search_direction); + + // increment the byte counter id_bit_number + // and shift the mask rom_byte_mask + id_bit_number++; + rom_byte_mask = (unsigned char)(rom_byte_mask << 1); + + // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask + if (rom_byte_mask == 0) + { + rom_byte_number++; + rom_byte_mask = 1; + } + } + } + while(rom_byte_number < 8); // loop until through all ROM bytes 0-7 + + // if the search was successful then + if (!((id_bit_number < 65))) + { + // search successful so set LastDiscrepancy,LastDeviceFlag,search_result + LastDiscrepancy = last_zero; + + // check for last device + if (LastDiscrepancy == 0) + LastDeviceFlag = TRUE; + + search_result = TRUE; + } + } + + // if no device found then reset counters so next 'search' will be like a first + if (!search_result || !ROM_NO[0]) + { + LastDiscrepancy = 0; + LastDeviceFlag = FALSE; + LastFamilyDiscrepancy = 0; + search_result = FALSE; + } + + if (search_result) { + JsVar *val = jsvNewFromInteger( + (((JsVarInt)ROM_NO[7])<<(7*8)) | + (((JsVarInt)ROM_NO[6])<<(6*8)) | + (((JsVarInt)ROM_NO[5])<<(5*8)) | + (((JsVarInt)ROM_NO[4])<<(4*8)) | + (((JsVarInt)ROM_NO[3])<<(3*8)) | + (((JsVarInt)ROM_NO[2])<<(2*8)) | + (((JsVarInt)ROM_NO[1])<<(1*8)) | + ((JsVarInt)ROM_NO[0]) + ); + if (val) jsvArrayPushAndUnLock(array, val); + } + + NOT_USED(LastFamilyDiscrepancy); + } + + return array; +} + diff --git a/components/external/espruino/src/jswrap_onewire.h b/components/external/espruino/src/jswrap_onewire.h new file mode 100644 index 0000000000..5377bbff32 --- /dev/null +++ b/components/external/espruino/src/jswrap_onewire.h @@ -0,0 +1,23 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * JavaScript OneWire Functions + * ---------------------------------------------------------------------------- + */ +#include "jsvar.h" +#include "jspin.h" + +JsVar *jswrap_onewire_constructor(Pin pin); +bool jswrap_onewire_reset(JsVar *parent); +void jswrap_onewire_select(JsVar *parent, JsVarInt rom); +void jswrap_onewire_skip(JsVar *parent); +void jswrap_onewire_write(JsVar *parent, int data, bool leavePowerOn); +JsVarInt jswrap_onewire_read(JsVar *parent); +JsVar *jswrap_onewire_search(JsVar *parent); diff --git a/components/external/espruino/src/jswrap_pin.c b/components/external/espruino/src/jswrap_pin.c new file mode 100644 index 0000000000..247ec1897a --- /dev/null +++ b/components/external/espruino/src/jswrap_pin.c @@ -0,0 +1,73 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * This file is designed to be parsed during the build process + * + * JavaScript Pin Object Functions + * ---------------------------------------------------------------------------- + */ +#include "jswrap_pin.h" + +/*JSON{ "type":"class", + "class" : "Pin", + "check" : "jsvIsPin(var)", + "description" : ["This is the built-in class for Pins, such as D0,D1,LED1, or BTN", + "You can call the methods on Pin, or you can use Wiring-style functions such as digitalWrite" ] +}*/ + +/*JSON{ "type":"method", "class": "Pin", "name" : "read", + "description" : "Returns the input state of the pin as a boolean", + "generate" : "jswrap_pin_read", + "return" : ["bool", "Whether pin is a logical 1 or 0"] +}*/ +bool jswrap_pin_read(JsVar *parent) { + Pin pin = jshGetPinFromVar(parent); + return jshPinInput(pin); +} + +/*JSON{ "type":"method", "class": "Pin", "name" : "set", + "description" : "Sets the output state of the pin to a 1", + "generate" : "jswrap_pin_set" +}*/ +void jswrap_pin_set(JsVar *parent) { + Pin pin = jshGetPinFromVar(parent); + jshPinOutput(pin, 1); +} + +/*JSON{ "type":"method", "class": "Pin", "name" : "reset", + "description" : "Sets the output state of the pin to a 0", + "generate" : "jswrap_pin_reset" +}*/ +void jswrap_pin_reset(JsVar *parent) { + Pin pin = jshGetPinFromVar(parent); + jshPinOutput(pin, 0); +} + +/*JSON{ "type":"method", "class": "Pin", "name" : "write", + "description" : "Sets the output state of the pin to the parameter given", + "generate" : "jswrap_pin_write", + "params" : [ [ "value", "bool", "Whether to set output high (true/1) or low (false/0)"] ] +}*/ +void jswrap_pin_write(JsVar *parent, bool value) { + Pin pin = jshGetPinFromVar(parent); + jshPinOutput(pin, value); +} + +/*JSON{ "type":"method", "class": "Pin", "name" : "writeAtTime", "ifndef" : "SAVE_ON_FLASH", + "description" : "Sets the output state of the pin to the parameter given at the specified time", + "generate" : "jswrap_pin_writeAtTime", + "params" : [ [ "value", "bool", "Whether to set output high (true/1) or low (false/0)"], + ["time", "float", "Time at which to write"] ] +}*/ +void jswrap_pin_writeAtTime(JsVar *parent, bool value, JsVarFloat time) { + Pin pin = jshGetPinFromVar(parent); + JsSysTime sTime = jshGetTimeFromMilliseconds(time*1000); + jshPinOutputAtTime(sTime, pin, value); +} diff --git a/components/external/espruino/src/jswrap_pin.h b/components/external/espruino/src/jswrap_pin.h new file mode 100644 index 0000000000..26acac5ba1 --- /dev/null +++ b/components/external/espruino/src/jswrap_pin.h @@ -0,0 +1,21 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * JavaScript Pin Object Functions + * ---------------------------------------------------------------------------- + */ +#include "jsvar.h" +#include "jsinteractive.h" + +bool jswrap_pin_read(JsVar *parent); +void jswrap_pin_set(JsVar *parent); +void jswrap_pin_reset(JsVar *parent); +void jswrap_pin_write(JsVar *parent, bool value); +void jswrap_pin_writeAtTime(JsVar *parent, bool value, JsVarFloat time); diff --git a/components/external/espruino/src/jswrap_process.c b/components/external/espruino/src/jswrap_process.c new file mode 100644 index 0000000000..29ffe713fc --- /dev/null +++ b/components/external/espruino/src/jswrap_process.c @@ -0,0 +1,94 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * This file is designed to be parsed during the build process + * + * JavaScript 'process' object - for information about the Espruino board + * ---------------------------------------------------------------------------- + */ +#include "jsvar.h" +#include "jswrap_process.h" +#include "jsinteractive.h" + +/*JSON{ "type":"class", + "class" : "process", + "description" : "This class contains information about Espruino itself" +}*/ + +/*JSON{ "type":"staticproperty", + "class" : "process", "name" : "version", + "description" : "Returns the version of Espruino as a String", + "generate_full" : "jsvNewFromString(JS_VERSION)", + "return" : ["JsVar", "The version of Espruino"] +}*/ + +/*JSON{ "type":"staticproperty", + "class" : "process", "name" : "env", + "description" : "Returns an Object containing various pre-defined variables. standard ones are BOARD, VERSION", + "generate" : "jswrap_process_env", + "return" : ["JsVar", "An object"] +}*/ +JsVar *jswrap_process_env() { + JsVar *obj = jsvNewWithFlags(JSV_OBJECT); + jsvUnLock(jsvObjectSetChild(obj, "VERSION", jsvNewFromString(JS_VERSION))); + jsvUnLock(jsvObjectSetChild(obj, "BUILD_DATE", jsvNewFromString(__DATE__))); + jsvUnLock(jsvObjectSetChild(obj, "BUILD_TIME", jsvNewFromString(__TIME__))); + jsvUnLock(jsvObjectSetChild(obj, "BOARD", jsvNewFromString(PC_BOARD_ID))); + jsvUnLock(jsvObjectSetChild(obj, "CHIP", jsvNewFromString(PC_BOARD_CHIP))); + jsvUnLock(jsvObjectSetChild(obj, "CHIP_FAMILY", jsvNewFromString(PC_BOARD_CHIP_FAMILY))); + jsvUnLock(jsvObjectSetChild(obj, "FLASH", jsvNewFromInteger(FLASH_TOTAL))); + jsvUnLock(jsvObjectSetChild(obj, "RAM", jsvNewFromInteger(RAM_TOTAL))); + + return obj; +} + + +/*JSON{ "type":"staticmethod", + "class" : "process", "name" : "memory", + "description" : ["Run a Garbage Collection pass, and return an object containing information on memory usage.", + "free : Memory that is available to be used", + "usage : Memory that has been used", + "total : Total memory", + "history : Memory used for command history - that is freed if memory is low. Note that this is INCLUDED in the figure for 'free'.", + "On ARM, stackEndAddress is the address (that can be used with peek/poke/etc) of the END of the stack. The stack grows down, so unless you do a lot of recursion, the bytes above this can be used."], + "generate" : "jswrap_process_memory", + "return" : ["JsVar", "Information about memory usage"] +}*/ +#ifdef ARM +extern int _end; // end of ram used (variables) +extern int _etext; // end of flash text (binary) section +#endif +JsVar *jswrap_process_memory() { + jsvGarbageCollect(); + JsVar *obj = jsvNewWithFlags(JSV_OBJECT); + if (obj) { + unsigned int history = 0; + JsVar *historyVar = jsvObjectGetChild(jsiGetParser()->root, JSI_HISTORY_NAME, 0); + if (historyVar) { + history = (unsigned int)jsvCountJsVarsUsed(historyVar); // vars used to store history + jsvUnLock(historyVar); + } + unsigned int usage = jsvGetMemoryUsage() - history; + unsigned int total = jsvGetMemoryTotal(); + jsvUnLock(jsvObjectSetChild(obj, "free", jsvNewFromInteger(total-usage))); + jsvUnLock(jsvObjectSetChild(obj, "usage", jsvNewFromInteger(usage))); + jsvUnLock(jsvObjectSetChild(obj, "total", jsvNewFromInteger(total))); + jsvUnLock(jsvObjectSetChild(obj, "history", jsvNewFromInteger(history))); + +#ifdef ARM + jsvUnLock(jsvObjectSetChild(obj, "stackEndAddress", jsvNewFromInteger((JsVarInt)(unsigned int)&_end))); + jsvUnLock(jsvObjectSetChild(obj, "flash_start", jsvNewFromInteger((JsVarInt)FLASH_START))); + jsvUnLock(jsvObjectSetChild(obj, "flash_binary_end", jsvNewFromInteger((JsVarInt)(unsigned int)&_etext))); + jsvUnLock(jsvObjectSetChild(obj, "flash_code_start", jsvNewFromInteger((JsVarInt)FLASH_SAVED_CODE_START))); + jsvUnLock(jsvObjectSetChild(obj, "flash_length", jsvNewFromInteger((JsVarInt)FLASH_TOTAL))); +#endif + } + return obj; +} diff --git a/components/external/espruino/src/jswrap_process.h b/components/external/espruino/src/jswrap_process.h new file mode 100644 index 0000000000..604be68550 --- /dev/null +++ b/components/external/espruino/src/jswrap_process.h @@ -0,0 +1,19 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * This file is designed to be parsed during the build process + * + * JavaScript 'process' object - for information about the Espruino board + * ---------------------------------------------------------------------------- + */ +#include "jsvar.h" + +JsVar *jswrap_process_env(); +JsVar *jswrap_process_memory(); diff --git a/components/external/espruino/src/jswrap_serial.c b/components/external/espruino/src/jswrap_serial.c new file mode 100644 index 0000000000..61dcf6e7b0 --- /dev/null +++ b/components/external/espruino/src/jswrap_serial.c @@ -0,0 +1,197 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * This file is designed to be parsed during the build process + * + * JavaScript Serial Port Functions + * ---------------------------------------------------------------------------- + */ +#include "jswrap_serial.h" +#include "jsdevices.h" +#include "jsinteractive.h" + +/*JSON{ "type":"class", + "class" : "Serial", + "description" : ["This class allows use of the built-in USARTs", + "Methods may be called on the USB, Serial1, Serial2, Serial3, Serial4, Serial5 and Serial6 objects. While different processors provide different numbers of USARTs, you can always rely on at least Serial1 and Serial2" ] +}*/ + +/*JSON{ "type":"object", "name":"USB", "instanceof" : "Serial", + "description" : ["The USB Serial port" ], + "#if" : "defined(USB)" +}*/ +/*JSON{ "type":"object", "name":"Serial1", "instanceof" : "Serial", + "description" : ["The first Serial (USART) port" ], + "#if" : "USARTS>=1" +}*/ +/*JSON{ "type":"object", "name":"Serial2", "instanceof" : "Serial", + "description" : ["The second Serial (USART) port" ], + "#if" : "USARTS>=2" +}*/ +/*JSON{ "type":"object", "name":"Serial3", "instanceof" : "Serial", + "description" : ["The third Serial (USART) port" ], + "#if" : "USARTS>=3" +}*/ +/*JSON{ "type":"object", "name":"Serial4", "instanceof" : "Serial", + "description" : ["The fourth Serial (USART) port" ], + "#if" : "USARTS>=4" +}*/ +/*JSON{ "type":"object", "name":"Serial5", "instanceof" : "Serial", + "description" : ["The fifth Serial (USART) port" ], + "#if" : "USARTS>=5" +}*/ +/*JSON{ "type":"object", "name":"Serial6", "instanceof" : "Serial", + "description" : ["The sixth Serial (USART) port" ], + "#if" : "USARTS>=6" +}*/ + + + +/*JSON{ "type":"method", "class": "Serial", "name" : "setConsole", + "description" : "Set this Serial port as the port for the console", + "generate_full" : "jsiSetConsoleDevice(jsiGetDeviceFromClass(parent))" +}*/ + +/*JSON{ "type":"method", "class": "Serial", "name" : "setup", + "description" : "Setup this Serial port with the given baud rate and options", + "generate" : "jswrap_serial_setup", + "params" : [ [ "baudrate", "int", "The baud rate - the default is 9600"], + [ "options", "JsVar", ["An optional structure containing extra information on initialising the serial port.", + "```{rx:pin,tx:pin}```", + "Note that even after changing the RX and TX pins, if you have called setup before then the previous RX and TX pins will still be connected to the Serial port as well - until you set them to something else using digitalWrite" ] ] ] +}*/ +void jswrap_serial_setup(JsVar *parent, JsVarInt baud, JsVar *options) { + IOEventFlags device = jsiGetDeviceFromClass(parent); + JshUSARTInfo inf; + jshUSARTInitInfo(&inf); + + if (baud>0) inf.baudRate = (int)baud; + + if (jsvIsObject(options)) { + + inf.pinRX = jshGetPinFromVarAndUnLock(jsvObjectGetChild(options, "rx", 0)); + inf.pinTX = jshGetPinFromVarAndUnLock(jsvObjectGetChild(options, "tx", 0)); + inf.bytesize = (unsigned char)jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "bytesize", 0)); + + JsVar *v; + v = jsvObjectGetChild(options, "parity", 0); + + if(jsvIsNull(v)) { + inf.parity = 0; + } + else if(jsvIsString(v)) { + inf.parity = 0xFF; + char s[8] = ""; + + jsvGetString(v, s, sizeof(s) - 1); + + if(!strcmp(s, "o") || !strcmp(s, "odd")) { + inf.parity = 1; + } + else if(!strcmp(s, "e") || !strcmp(s, "even")) { + inf.parity = 2; + } + } + else if(jsvIsInt(v)) { + inf.parity = (unsigned char)jsvGetInteger(v); + } + + jsvUnLock(v); + + v = jsvObjectGetChild(options, "stopbits", 0); + inf.stopbits = (unsigned char)jsvGetInteger(v); + jsvUnLock(v); + } + + jshUSARTSetup(device, &inf); + // Set baud rate in object, so we can initialise it on startup + if (baud != DEFAULT_BAUD_RATE) { + JsVar *baudVar = jsvNewFromInteger(baud); + jsvUnLock(jsvSetNamedChild(parent, baudVar, USART_BAUDRATE_NAME)); + jsvUnLock(baudVar); + } else + jsvRemoveNamedChild(parent, USART_BAUDRATE_NAME); + // Do the same for options + if (options) + jsvUnLock(jsvSetNamedChild(parent, options, DEVICE_OPTIONS_NAME)); + else + jsvRemoveNamedChild(parent, DEVICE_OPTIONS_NAME); +} + +/*JSON{ "type":"method", "class": "Serial", "name" : "print", + "description" : "Print a string to the serial port - without a line feed", + "generate" : "jswrap_serial_print", + "params" : [ [ "string", "JsVar", "A String to print"] ] +}*/ +/*JSON{ "type":"method", "class": "Serial", "name" : "println", + "description" : "Print a line to the serial port (newline character sent are '\r\n')", + "generate" : "jswrap_serial_println", + "params" : [ [ "string", "JsVar", "A String to print"] ] +}*/ +void _jswrap_serial_print(JsVar *parent, JsVar *str, bool newLine) { + NOT_USED(parent); + IOEventFlags device = jsiGetDeviceFromClass(parent); + str = jsvAsString(str, false); + jsiTransmitStringVar(device,str); + jsvUnLock(str); + if (newLine) { + jshTransmit(device, (unsigned char)'\r'); + jshTransmit(device, (unsigned char)'\n'); + } +} +void jswrap_serial_print(JsVar *parent, JsVar *str) { + _jswrap_serial_print(parent, str, false); +} +void jswrap_serial_println(JsVar *parent, JsVar *str) { + _jswrap_serial_print(parent, str, true); +} +/*JSON{ "type":"method", "class": "Serial", "name" : "write", + "description" : "Write a character or array of characters to the serial port - without a line feed", + "generate" : "jswrap_serial_write", + "params" : [ [ "data", "JsVar", "A byte, a string, or an array of bytes to write"] ] +}*/ +void jswrap_serial_write(JsVar *parent, JsVar *data) { + NOT_USED(parent); + IOEventFlags device = jsiGetDeviceFromClass(parent); + if (jsvIsNumeric(data)) { + jshTransmit(device, (unsigned char)jsvGetInteger(data)); + } else if (jsvIsIterable(data)) { + JsvIterator it; + jsvIteratorNew(&it, data); + while (jsvIteratorHasElement(&it)) { + jshTransmit(device, (unsigned char)jsvIteratorGetIntegerValue(&it)); + jsvIteratorNext(&it); + } + jsvIteratorFree(&it); + } else { + jsWarn("Data supplied was not an integer - or iterable"); + } +} + +/*JSON{ "type":"method", "class": "Serial", "name" : "onData", + "description" : ["When a character is received on this serial port, the function supplied to onData gets called.", + "Only one function can ever be supplied, so calling onData(undefined) will stop any function being called"], + "generate" : "jswrap_serial_onData", + "params" : [ [ "function", "JsVarName", "A function to call when data arrives. It takes one argument, which is an object with a 'data' field"] ] +}*/ +void jswrap_serial_onData(JsVar *parent, JsVar *funcVar) { + JsVar *skippedFunc = jsvSkipName(funcVar); + if (!jsvIsFunction(skippedFunc) && !jsvIsString(skippedFunc)) { + jsiConsolePrint("Function or String not supplied - removing onData handler.\n"); + JsVar *handler = jsvFindChildFromString(parent, USART_CALLBACK_NAME, false); + if (handler) { + jsvRemoveChild(parent, handler); + jsvUnLock(handler); + } + } else { + jsvUnLock(jsvSetNamedChild(parent, funcVar, USART_CALLBACK_NAME)); + } + jsvUnLock(skippedFunc); +} diff --git a/components/external/espruino/src/jswrap_serial.h b/components/external/espruino/src/jswrap_serial.h new file mode 100644 index 0000000000..ff98596753 --- /dev/null +++ b/components/external/espruino/src/jswrap_serial.h @@ -0,0 +1,21 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * JavaScript Serial Port Functions + * ---------------------------------------------------------------------------- + */ +#include "jsvar.h" + + +void jswrap_serial_setup(JsVar *parent, JsVarInt baud, JsVar *options); +void jswrap_serial_print(JsVar *parent, JsVar *str); +void jswrap_serial_println(JsVar *parent, JsVar *str); +void jswrap_serial_write(JsVar *parent, JsVar *data); +void jswrap_serial_onData(JsVar *parent, JsVar *funcVar); diff --git a/components/external/espruino/src/jswrap_spi_i2c.c b/components/external/espruino/src/jswrap_spi_i2c.c new file mode 100644 index 0000000000..3a55d82deb --- /dev/null +++ b/components/external/espruino/src/jswrap_spi_i2c.c @@ -0,0 +1,455 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * This file is designed to be parsed during the build process + * + * JavaScript SPI and I2C Functions + * ---------------------------------------------------------------------------- + */ +#include "jswrap_spi_i2c.h" +#include "jsdevices.h" +#include "jsinteractive.h" +#include "jswrap_arraybuffer.h" + +/*JSON{ "type":"class", + "class" : "SPI", + "description" : ["This class allows use of the built-in SPI ports. Currently it is SPI master only." ] +}*/ + +/*JSON{ "type":"object", "name":"SPI1", "instanceof" : "SPI", + "description" : ["The first SPI port" ], + "#if" : "SPIS>=1" +}*/ +/*JSON{ "type":"object", "name":"SPI2", "instanceof" : "SPI", + "description" : ["The second SPI port" ], + "#if" : "SPIS>=2" +}*/ +/*JSON{ "type":"object", "name":"SPI3", "instanceof" : "SPI", + "description" : ["The third SPI port" ], + "#if" : "SPIS>=3" +}*/ + + +typedef unsigned char (*unsigned_char_map_function)(IOEventFlags device, unsigned char data); + +JsVar *map_var_as_unsigned_char(JsVar *src, IOEventFlags device, unsigned_char_map_function map) { + if (jsvIsNumeric(src)) { + return jsvNewFromInteger(map(device, (unsigned char)jsvGetInteger(src))); + } else if (jsvIsString(src)) { + JsVar *dst = jsvNewFromEmptyString(); + JsvStringIterator it; + jsvStringIteratorNew(&it, src, 0); + while (jsvStringIteratorHasChar(&it)) { + unsigned char in = (unsigned char)jsvStringIteratorGetChar(&it); + unsigned char out = map(device, in); + jsvAppendStringBuf(dst, (char*)&out, 1); + jsvStringIteratorNext(&it); + } + jsvStringIteratorFree(&it); + return dst; + } else if (jsvIsIterable(src)) { + // OPT: could use ArrayBuffer for return values + JsVar *dst = jsvNewWithFlags(JSV_ARRAY); + JsvIterator it; + jsvIteratorNew(&it, src); + while (jsvIteratorHasElement(&it)) { + unsigned char in = (unsigned char)jsvIteratorGetIntegerValue(&it); + unsigned char out = map(device, in); + JsVar *outVar = jsvNewFromInteger(out); + jsvArrayPushAndUnLock(dst, outVar); + jsvIteratorNext(&it); + } + jsvIteratorFree(&it); + return dst; + } else { + jsError("Variable type not suited to transmit operation"); + return 0; + } +} + + +/*JSON{ "type":"method", "class": "SPI", "name" : "setup", + "description" : "Set up this SPI port. Master, MSB first, no checksum", + "generate" : "jswrap_spi_setup", + "params" : [ [ "options", "JsVar", ["An optional structure containing extra information on initialising the SPI port", + "Please note that baud rate is set to the nearest that can be managed - which may be -+ 50%", + "```{sck:pin, miso:pin, mosi:pin, baud:integer, mode:integer=0 }```", + "If sck,miso and mosi are left out, they will automatically be chosen. However if one or more is specified then the unspecified pins will not be set up.", + "The SPI ```mode``` is between 0 and 3 - see http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Clock_polarity_and_phase", + "On STM32F1-based parts, you cannot mix AF and non-AF pins (SPI pins are usually grouped on the chip - and you can't mix pins from two groups). Espruino will not warn you about this." ] ] ] +}*/ +void jswrap_spi_setup(JsVar *parent, JsVar *options) { + IOEventFlags device = jsiGetDeviceFromClass(parent); + JshSPIInfo inf; + jshSPIInitInfo(&inf); + if (jsvIsObject(options)) { + inf.pinSCK = jshGetPinFromVarAndUnLock(jsvObjectGetChild(options, "sck", 0)); + inf.pinMISO = jshGetPinFromVarAndUnLock(jsvObjectGetChild(options, "miso", 0)); + inf.pinMOSI = jshGetPinFromVarAndUnLock(jsvObjectGetChild(options, "mosi", 0)); + JsVar *v; + v = jsvObjectGetChild(options, "baud", 0); + if (jsvIsNumeric(v)) + inf.baudRate = (int)jsvGetInteger(v); + v = jsvObjectGetChild(options, "mode", 0); + if (jsvIsNumeric(v)) + inf.spiMode = ((int)jsvGetInteger(v))&3;; + jsvUnLock(v); + } + jshSPISetup(device, &inf); + // Set up options, so we can initialise it on startup + if (options) + jsvUnLock(jsvSetNamedChild(parent, options, DEVICE_OPTIONS_NAME)); + else + jsvRemoveNamedChild(parent, DEVICE_OPTIONS_NAME); +} + + +/*JSON{ "type":"method", "class": "SPI", "name" : "send", + "description" : [ "Send data down SPI, and return the result", + "Sending multiple bytes in one call to send is preferable as they can then be transmitted end to end. Using multiple calls to send() will result in significantly slower transmission speeds." ], + "generate" : "jswrap_spi_send", + "params" : [ [ "data", "JsVar", "The data to send - either an integer, array, or string (which is the most efficient)" ], + [ "nss_pin", "pin", "An nSS pin - this will be lowered before SPI output and raised afterwards (optional). There will be a small delay between when this is lowered and when sending starts, and also between sending finishing and it being raised." ] ], + "return" : [ "JsVar", "The data that was returned" ] + +}*/ +JsVar *jswrap_spi_send(JsVar *parent, JsVar *srcdata, Pin nss_pin) { + NOT_USED(parent); + IOEventFlags device = jsiGetDeviceFromClass(parent); + + if (!jshIsDeviceInitialised(device)) { + JshSPIInfo inf; + jshSPIInitInfo(&inf); + jshSPISetup(device, &inf); + } + + JsVar *dst = 0; + + // assert NSS + if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, false); + + // send data + if (jsvIsNumeric(srcdata)) { + jshSPISend(device, (unsigned char)jsvGetInteger(srcdata)); + dst = jsvNewFromInteger(jshSPISend(device, -1)); // retrieve the byte (no send!) + } else if (jsvIsArray(srcdata)) { + dst = jsvNewWithFlags(JSV_ARRAY); + JsArrayIterator it; + jsvArrayIteratorNew(&it, srcdata); + int incount = 0, outcount = 0; + while (jsvArrayIteratorHasElement(&it)) { + unsigned char in = (unsigned char)jsvGetIntegerAndUnLock(jsvArrayIteratorGetElement(&it)); + incount++; + int out = jshSPISend(device, in); // this returns -1 only if no data (so if -1 gets in an array it is an error!) + if (out>=0) { + outcount++; + JsVar *outVar = jsvNewFromInteger(out); + jsvArrayPushAndUnLock(dst, outVar); + } + jsvArrayIteratorNext(&it); + } + jsvArrayIteratorFree(&it); + // finally add the remaining bytes (no send!) + while (outcount < incount) { + outcount++; + int out = jshSPISend(device, -1); + JsVar *outVar = jsvNewFromInteger(out); + jsvArrayPushAndUnLock(dst, outVar); + } + } else if (jsvIsString(srcdata)) { + dst = jsvNewFromEmptyString(); + JsvStringIterator it; + jsvStringIteratorNew(&it, srcdata, 0); + int incount = 0, outcount = 0; + while (jsvStringIteratorHasChar(&it)) { + unsigned char in = (unsigned char)jsvStringIteratorGetChar(&it); + incount++; + int out = jshSPISend(device, in); + if (out>=0) { + outcount++; + char outc = (char)out; + jsvAppendStringBuf(dst, (char*)&outc, 1); + } + jsvStringIteratorNext(&it); + } + jsvStringIteratorFree(&it); + // finally add the remaining bytes (no send!) + while (outcount < incount) { + outcount++; + unsigned char out = (unsigned char)jshSPISend(device, -1); + jsvAppendStringBuf(dst, (char*)&out, 1); + } + } else if (jsvIsIterable(srcdata)) { + JsVar *lenVar = jsvNewFromInteger(jsvGetLength(srcdata)); + dst = jswrap_typedarray_constructor(ARRAYBUFFERVIEW_UINT8, lenVar,0,0); + jsvUnLock(lenVar); + JsvIterator it; + JsvArrayBufferIterator dstit; + jsvIteratorNew(&it, srcdata); + jsvArrayBufferIteratorNew(&dstit, dst, 0); + while (jsvIteratorHasElement(&it)) { + unsigned char in = (unsigned char)jsvIteratorGetIntegerValue(&it); + int out = jshSPISend(device, in); + jsvArrayBufferIteratorSetIntegerValue(&dstit, out); + jsvIteratorNext(&it); + jsvArrayBufferIteratorNext(&dstit); + } + jsvIteratorFree(&it); + jsvArrayBufferIteratorFree(&dstit); + } else { + jsError("Variable type not suited to transmit operation"); + dst = 0; + } + + // de-assert NSS + if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, true); + return dst; +} + +// used by jswrap_spi_send4bit +void spi_send4bit(IOEventFlags device, unsigned char data, int bit0, int bit1) { + unsigned char lookup[] = { + (unsigned char)((bit0<<4) | bit0), + (unsigned char)((bit0<<4) | bit1), + (unsigned char)((bit1<<4) | bit0), + (unsigned char)((bit1<<4) | bit1), + }; + // Send each bit as 4 bits, MSB first + /*jshSPISend(device, lookup[(data>>6)&3]); + jshSPISend(device, lookup[(data>>4)&3]); + jshSPISend(device, lookup[(data>>2)&3]); + jshSPISend(device, lookup[(data )&3]);*/ + jshSPISend16(device, (lookup[(data>>6)&3]<<8) | lookup[(data>>4)&3]); + jshSPISend16(device, (lookup[(data>>2)&3]<<8) | lookup[(data )&3]); +} + +// used by jswrap_spi_send8bit +void spi_send8bit(IOEventFlags device, unsigned char data, int bit0, int bit1) { + // Send each bit as 8 bits, MSB first + /*int i; + for (i=7;i>=0;i--) + jshSPISend(device, (unsigned char)(((data>>i)&1) ? bit1 : bit0));*/ + jshSPISend(device, ((((data>>7)&1) ? bit1 : bit0)<<8) | (((data>>6)&1) ? bit1 : bit0)); + jshSPISend(device, ((((data>>5)&1) ? bit1 : bit0)<<8) | (((data>>4)&1) ? bit1 : bit0)); + jshSPISend(device, ((((data>>3)&1) ? bit1 : bit0)<<8) | (((data>>2)&1) ? bit1 : bit0)); + jshSPISend(device, ((((data>>1)&1) ? bit1 : bit0)<<8) | (((data>>0)&1) ? bit1 : bit0)); +} + +/*JSON{ "type":"method", "class": "SPI", "name" : "send4bit", + "description" : ["Send data down SPI, using 4 bits for each 'real' bit (MSB first). This can be useful for faking one-wire style protocols", + "Sending multiple bytes in one call to send is preferable as they can then be transmitted end to end. Using multiple calls to send() will result in significantly slower transmission speeds."], + "generate" : "jswrap_spi_send4bit", + "params" : [ [ "data", "JsVar", "The data to send - either an integer, array, or string" ], + [ "bit0", "int", "The 4 bits to send for a 0 (MSB first)" ], + [ "bit1", "int", "The 4 bits to send for a 1 (MSB first)" ], + [ "nss_pin", "pin", "An nSS pin - this will be lowered before SPI output and raised afterwards (optional). There will be a small delay between when this is lowered and when sending starts, and also between sending finishing and it being raised." ] ] +}*/ +void jswrap_spi_send4bit(JsVar *parent, JsVar *srcdata, int bit0, int bit1, Pin nss_pin) { + NOT_USED(parent); + IOEventFlags device = jsiGetDeviceFromClass(parent); + jshSPISet16(device, true); // 16 bit output + + if (bit0==0 && bit1==0) { + bit0 = 0x01; + bit1 = 0x03; + } + bit0 = bit0 & 0x0F; + bit1 = bit1 & 0x0F; + + if (!jshIsDeviceInitialised(device)) { + JshSPIInfo inf; + jshSPIInitInfo(&inf); + jshSPISetup(device, &inf); + } + + // assert NSS + if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, false); + + // send data + if (jsvIsNumeric(srcdata)) { + spi_send4bit(device, (unsigned char)jsvGetInteger(srcdata), bit0, bit1); + } else if (jsvIsIterable(srcdata)) { + jshInterruptOff(); + JsvIterator it; + jsvIteratorNew(&it, srcdata); + while (jsvIteratorHasElement(&it)) { + unsigned char in = (unsigned char)jsvIteratorGetIntegerValue(&it); + spi_send4bit(device, in, bit0, bit1); + jsvIteratorNext(&it); + } + jsvIteratorFree(&it); + jshInterruptOn(); + } else { + jsError("Variable type not suited to transmit operation"); + } + + // de-assert NSS + if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, true); + jshSPISet16(device, false); // back to 8 bit +} + +/*JSON{ "type":"method", "class": "SPI", "name" : "send8bit", + "description" : ["Send data down SPI, using 8 bits for each 'real' bit (MSB first). This can be useful for faking one-wire style protocols", +"Sending multiple bytes in one call to send is preferable as they can then be transmitted end to end. Using multiple calls to send() will result in significantly slower transmission speeds."], + "generate" : "jswrap_spi_send8bit", + "params" : [ [ "data", "JsVar", "The data to send - either an integer, array, or string" ], + [ "bit0", "int", "The 8 bits to send for a 0 (MSB first)" ], + [ "bit1", "int", "The 8 bits to send for a 1 (MSB first)" ], + [ "nss_pin", "pin", "An nSS pin - this will be lowered before SPI output and raised afterwards (optional). There will be a small delay between when this is lowered and when sending starts, and also between sending finishing and it being raised" ] ] +}*/ +void jswrap_spi_send8bit(JsVar *parent, JsVar *srcdata, int bit0, int bit1, Pin nss_pin) { + NOT_USED(parent); + IOEventFlags device = jsiGetDeviceFromClass(parent); + jshSPISet16(device, true); // 16 bit output + + if (bit0==0 && bit1==0) { + bit0 = 0x03; + bit1 = 0x0F; + } + bit0 = bit0 & 0xFF; + bit1 = bit1 & 0xFF; + + if (!jshIsDeviceInitialised(device)) { + JshSPIInfo inf; + jshSPIInitInfo(&inf); + jshSPISetup(device, &inf); + } + + // assert NSS + if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, false); + + // send data + if (jsvIsNumeric(srcdata)) { + spi_send8bit(device, (unsigned char)jsvGetInteger(srcdata), bit0, bit1); + } else if (jsvIsIterable(srcdata)) { + jshInterruptOff(); + JsvIterator it; + jsvIteratorNew(&it, srcdata); + while (jsvIteratorHasElement(&it)) { + unsigned char in = (unsigned char)jsvIteratorGetIntegerValue(&it); + spi_send8bit(device, in, bit0, bit1); + jsvIteratorNext(&it); + } + jsvIteratorFree(&it); + jshInterruptOn(); + } else { + jsError("Variable type not suited to transmit operation"); + } + + // de-assert NSS + if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, true); + jshSPISet16(device, false); // back to 8 bit +} + +/*JSON{ "type":"class", + "class" : "I2C", + "description" : ["This class allows use of the built-in I2C ports. Currently it allows I2C Master mode only.", + "All addresses are in 7 bit format. If you have an 8 bit address then you need to shift it one bit to the right." ] +}*/ + +/*JSON{ "type":"object", "name":"I2C1", "instanceof" : "I2C", + "description" : ["The first I2C port" ], + "#if" : "I2CS>=1" +}*/ +/*JSON{ "type":"object", "name":"I2C2", "instanceof" : "I2C", + "description" : ["The second I2C port" ], + "#if" : "I2CS>=2" +}*/ +/*JSON{ "type":"object", "name":"I2C3", "instanceof" : "I2C", + "description" : ["The third I2C port" ], + "#if" : "I2CS>=3" +}*/ + + + +/*JSON{ "type":"method", "class": "I2C", "name" : "setup", + "description" : "Set up this I2C port", + "generate" : "jswrap_i2c_setup", + "params" : [ [ "options", "JsVar", ["An optional structure containing extra information on initialising the I2C port", + "{scl:pin, sda:pin}" ] ] ] +}*/ +void jswrap_i2c_setup(JsVar *parent, JsVar *options) { + IOEventFlags device = jsiGetDeviceFromClass(parent); + JshI2CInfo inf; + jshI2CInitInfo(&inf); + if (jsvIsObject(options)) { + inf.pinSCL = jshGetPinFromVarAndUnLock(jsvObjectGetChild(options, "scl", 0)); + inf.pinSDA = jshGetPinFromVarAndUnLock(jsvObjectGetChild(options, "sda", 0)); + } + jshI2CSetup(device, &inf); + // Set up options, so we can initialise it on startup + if (options) + jsvUnLock(jsvSetNamedChild(parent, options, DEVICE_OPTIONS_NAME)); + else + jsvRemoveNamedChild(parent, DEVICE_OPTIONS_NAME); +} + + + + +/*JSON{ "type":"method", "class": "I2C", "name" : "writeTo", + "description" : "Transmit to the slave device with the given address. This is like Arduino's beginTransmission, write, and endTransmission rolled up into one.", + "generate" : "jswrap_i2c_writeTo", + "params" : [ [ "address", "int", "The 7 bit address of the device to transmit to" ], + [ "data", "JsVar", "The Data to send - either a byte, an array of bytes, or a string" ]] +}*/ +#define I2C_BUFSIZE 32 +void jswrap_i2c_writeTo(JsVar *parent, int address, JsVar *data) { + IOEventFlags device = jsiGetDeviceFromClass(parent); + + if (jsvIsNumeric(data)) { + unsigned char buf[1]; + buf[0] = (unsigned char)jsvGetInteger(data); + jshI2CWrite(device, (unsigned char)address, 1, buf); + } else if (jsvIsIterable(data)) { + unsigned char buf[I2C_BUFSIZE]; + int i=0; + JsvIterator it; + jsvIteratorNew(&it, data); + while (jsvIteratorHasElement(&it)) { + if (i=I2C_BUFSIZE) jsError("Too many bytes to write - truncating"); + jshI2CWrite(device, (unsigned char)address, i, buf); + } else { + jsError("Variable type not suited to writeTo operation"); + } +} + +/*JSON{ "type":"method", "class": "I2C", "name" : "readFrom", + "description" : "Request bytes from the given slave device, and return them as an array. This is like using Arduino Wire's requestFrom, available and read functions. Sends a STOP", + "generate" : "jswrap_i2c_readFrom", + "params" : [ [ "address", "int", "The 7 bit address of the device to request bytes from" ], + [ "quantity", "int", "The number of bytes to request" ] ], + "return" : [ "JsVar", "The data that was returned - an array of bytes" ] +}*/ +JsVar *jswrap_i2c_readFrom(JsVar *parent, int address, int nBytes) { + unsigned char buf[I2C_BUFSIZE]; + if (nBytes>I2C_BUFSIZE) { + jsError("Too many bytes to read - truncating"); + nBytes = I2C_BUFSIZE; + } + + IOEventFlags device = jsiGetDeviceFromClass(parent); + jshI2CRead(device, (unsigned char)address, nBytes, buf); + + // OPT: could use ArrayBuffer for return values + JsVar *array = jsvNewWithFlags(JSV_ARRAY); + if (array) { + int i; + for (i=0;i + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * JavaScript SPI and I2C Functions + * ---------------------------------------------------------------------------- + */ +#include "jsvar.h" +#include "jspin.h" + +void jswrap_spi_setup(JsVar *parent, JsVar *options); +JsVar *jswrap_spi_send(JsVar *parent, JsVar *data, Pin nss_pin); +void jswrap_spi_send4bit(JsVar *parent, JsVar *srcdata, int bit0, int bit1, Pin nss_pin); +void jswrap_spi_send8bit(JsVar *parent, JsVar *srcdata, int bit0, int bit1, Pin nss_pin); + +void jswrap_i2c_setup(JsVar *parent, JsVar *options); +void jswrap_i2c_writeTo(JsVar *parent, int address, JsVar *data); +JsVar *jswrap_i2c_readFrom(JsVar *parent, int address, int nBytes); diff --git a/components/external/espruino/src/jswrap_string.c b/components/external/espruino/src/jswrap_string.c new file mode 100644 index 0000000000..23a272b7d5 --- /dev/null +++ b/components/external/espruino/src/jswrap_string.c @@ -0,0 +1,173 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * This file is designed to be parsed during the build process + * + * JavaScript String Functions + * ---------------------------------------------------------------------------- + */ +#include "jswrap_string.h" + +/*JSON{ "type":"class", + "class" : "String", + "check" : "jsvIsString(var)", + "description" : ["This is the built-in class for Text Strings.", + "Text Strings in Espruino are not zero-terminated, so you can store zeros in them." ] +}*/ + +/*JSON{ "type":"constructor", "class": "String", "name": "String", + "description" : "Create a new String", + "generate" : "jswrap_string_constructor", + "params" : [ [ "str", "JsVar", "A value to turn into a string. If undefined or not supplied, an empty String is created." ] ], + "return" : [ "JsVar", "A String" ] + +}*/ +JsVar *jswrap_string_constructor(JsVar *a) { + if (!a) return jsvNewFromEmptyString(); // no argument - return an empty string + return jsvAsString(a, false); +} + +/*JSON{ "type":"staticmethod", "class": "String", "name" : "fromCharCode", + "description" : "Return the character represented by the given character code.", + "generate" : "jswrap_string_fromCharCode", + "params" : [ [ "code", "int", "The character code to create a character from (range 0-255)"] ], + "return" : ["JsVar", "The character"] +}*/ +JsVar *jswrap_string_fromCharCode(JsVarInt code) { + // We do this so we can handle '/0' in a string + JsVar *r = jsvNewFromEmptyString(); + if (r) { // out of mem? + char ch = (char)code; + jsvAppendStringBuf(r, &ch, 1); + } + return r; +} + +/*JSON{ "type":"method", "class": "String", "name" : "charAt", + "description" : "Return a single character at the given position in the String.", + "generate" : "jswrap_string_charAt", + "params" : [ [ "pos", "int", "The character number in the string. Negative values return characters from end of string (-1 = last char)"] ], + "return" : ["JsVar", "The character in the string"] +}*/ +JsVar *jswrap_string_charAt(JsVar *parent, JsVarInt idx) { + // We do this so we can handle '/0' in a string + JsVar *r = jsvNewFromEmptyString(); + if (r) { // out of mem? + char ch = jsvGetCharInString(parent, (int)idx); + jsvAppendStringBuf(r, &ch, 1); + } + return r; +} + +/*JSON{ "type":"method", "class": "String", "name" : "charCodeAt", + "description" : ["Return the integer value of a single character at the given position in the String.", + "Note that this returns 0 not 'NaN' for out of bounds characters"], + "generate" : "jswrap_string_charCodeAt", + "params" : [ [ "pos", "int", "The character number in the string. Negative values return characters from end of string (-1 = last char)"] ], + "return" : ["int", "The integer value of a character in the string"] +}*/ +JsVarInt jswrap_string_charCodeAt(JsVar *parent, JsVarInt idx) { + return jsvGetCharInString(parent, (int)idx); +} + + +/*JSON{ "type":"method", "class": "String", "name" : "indexOf", + "description" : "Return the index of substring in this string, or -1 if not found", + "generate" : "jswrap_string_indexOf", + "params" : [ [ "substring", "JsVar", "The string to search for"] ], + "return" : ["int", "The index of the string, or -1 if not found"] +}*/ +JsVarInt jswrap_string_indexOf(JsVar *parent, JsVar *v) { + // slow, but simple! + v = jsvAsString(v, false); + if (!v) return 0; // out of memory + int idx = -1; + int l = (int)jsvGetStringLength(parent) - (int)jsvGetStringLength(v); + for (idx=0;idx<=l;idx++) { + if (jsvCompareString(parent, v, idx, 0, true)==0) { + jsvUnLock(v); + return idx; + } + } + jsvUnLock(v); + return -1; +} + +/*JSON{ "type":"method", "class": "String", "name" : "substring", + "generate" : "jswrap_string_substring", + "params" : [ [ "start", "int", "The start character index"], + [ "end", "JsVar", "The end character index"] ], + "return" : ["JsVar", "The part of this string between start and end"] +}*/ +JsVar *jswrap_string_substring(JsVar *parent, JsVarInt pStart, JsVar *vEnd) { + JsVar *res; + JsVarInt pEnd = jsvIsUndefined(vEnd) ? JSVAPPENDSTRINGVAR_MAXLENGTH : (int)jsvGetInteger(vEnd); + if (pStart<0) pStart=0; + if (pEnd<0) pEnd=0; + if (pEnd + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * JavaScript String Functions + * ---------------------------------------------------------------------------- + */ +#include "jsvar.h" + +JsVar *jswrap_string_constructor(JsVar *a); +JsVar *jswrap_string_fromCharCode(JsVarInt code); +JsVar *jswrap_string_charAt(JsVar *parent, JsVarInt idx); +JsVarInt jswrap_string_charCodeAt(JsVar *parent, JsVarInt idx); +JsVarInt jswrap_string_indexOf(JsVar *parent, JsVar *v); +JsVar *jswrap_string_substring(JsVar *parent, JsVarInt pStart, JsVar *vEnd); +JsVar *jswrap_string_substr(JsVar *parent, JsVarInt pStart, JsVar *vLen); +JsVar *jswrap_string_split(JsVar *parent, JsVar *split); diff --git a/components/external/espruino/src/jswrapper.h b/components/external/espruino/src/jswrapper.h new file mode 100644 index 0000000000..294b7d5547 --- /dev/null +++ b/components/external/espruino/src/jswrapper.h @@ -0,0 +1,36 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Header for auto-generated Wrapper functions + * ---------------------------------------------------------------------------- + */ + +#include "jsutils.h" +#include "jsparse.h" + +#define JSW_HANDLEFUNCTIONCALL_UNHANDLED ((JsVar*)-1) + +/** If 'name' is something that belongs to an internal function, execute it. */ +JsVar *jswHandleFunctionCall(JsVar *parent, JsVar *parentName, const char *name); + +/// Given the name of an Object, see if we should set it up as a builtin or not +bool jswIsBuiltInObject(const char *name); + +/// If we get this in 'require', should we make an object with this name? +bool jswIsBuiltInLibrary(const char *name); + +/** Given a variable, return the basic object name of it */ +const char *jswGetBasicObjectName(JsVar *var); + +/** Given the name of a Basic Object, eg, Uint8Array, String, etc. Return the prototype object's name - or 0. + * For instance jswGetBasicObjectPrototypeName("Object")==0, jswGetBasicObjectPrototypeName("Integer")=="Object", + * jswGetBasicObjectPrototypeName("Uint8Array")=="ArrayBufferView" + * */ +const char *jswGetBasicObjectPrototypeName(const char *name); diff --git a/components/external/espruino/targets/rtthread/espruino.c b/components/external/espruino/targets/rtthread/espruino.c new file mode 100644 index 0000000000..9980adbe38 --- /dev/null +++ b/components/external/espruino/targets/rtthread/espruino.c @@ -0,0 +1,301 @@ +#include +#include +#include +#include +#include +#include // for readdir + +#include "jslex.h" +#include "jsvar.h" +#include "jsparse.h" +#include "jswrap_json.h" + +#include "jsinteractive.h" +#include "jshardware.h" +#include + +#define TEST_DIR "tests/" + +bool isRunning = true; + +void nativeQuit(JsVarRef var) { + NOT_USED(var); + isRunning = false; +} + +void nativeInterrupt(JsVarRef var) { + NOT_USED(var); + jspSetInterrupted(true); +} + +const char *read_file(const char *filename) { + struct stat results; + if (!stat(filename, &results) == 0) { + printf("Cannot stat file! '%s'\r\n", filename); + return 0; + } + int size = (int)results.st_size; + FILE *file = fopen( filename, "rb" ); + /* if we open as text, the number of bytes read may be > the size we read */ + if( !file ) { + printf("Unable to open file! '%s'\r\n", filename); + return 0; + } + char *buffer = malloc(size+1); + size_t actualRead = fread(buffer,1,size,file); + buffer[actualRead]=0; + buffer[size]=0; + fclose(file); + return buffer; +} + +bool run_test(const char *filename) { + printf("----------------------------------\r\n"); + printf("----------------------------- TEST %s \r\n", filename); + char *buffer = (char *)read_file(filename); + if (!buffer) return (false); + + jshInit(); + jsiInit(false /* do not autoload!!! */); + + jspAddNativeFunction(jsiGetParser(), "function quit()", nativeQuit); + jspAddNativeFunction(jsiGetParser(), "function interrupt()", nativeInterrupt); + + jsvUnLock(jspEvaluate(jsiGetParser(), buffer )); + + isRunning = true; + while (isRunning && jsiHasTimers()) jsiLoop(); + + JsVar *result = jsvObjectGetChild(jsiGetParser()->root, "result", 0/*no create*/); + bool pass = jsvGetBool(result); + jsvUnLock(result); + + if (pass) + printf("----------------------------- PASS %s\r\n", filename); + else { + printf("----------------------------------\r\n"); + printf("----------------------------- FAIL %s <-------\r\n", filename); + jsvTrace(jsvGetRef(jsiGetParser()->root), 0); + printf("----------------------------- FAIL %s <-------\r\n", filename); + printf("----------------------------------\r\n"); + } + printf("BEFORE: %d Memory Records Used\r\n", jsvGetMemoryUsage()); + // jsvTrace(jsiGetParser()->root, 0); + jsiKill(); + printf("AFTER: %d Memory Records Used\r\n", jsvGetMemoryUsage()); + jsvGarbageCollect(); + printf("AFTER GC: %d Memory Records Used (should be 0!)\r\n", jsvGetMemoryUsage()); + jsvShowAllocated(); + jshKill(); + + //jsvDottyOutput(); + printf("\r\n"); + + free(buffer); + return pass; +} + + +bool run_all_tests() { + int count = 0; + int passed = 0; + + char *fails = malloc(1); + fails[0] = 0; + + DIR *dir = opendir(TEST_DIR); + if(dir) { + struct dirent *pDir=NULL; + while((pDir = readdir(dir)) != NULL) { + char *fn = (*pDir).d_name; + int l = strlen(fn); + if (l>3 && fn[l-3]=='.' && fn[l-2]=='j' && fn[l-1]=='s') { + char *full_fn = malloc(1+l+strlen(TEST_DIR)); + strcpy(full_fn, TEST_DIR); + strcat(full_fn, fn); + if (run_test(full_fn)) { + passed++; + } else { + char *t = malloc(strlen(fails)+3+strlen(full_fn)); + strcpy(t, fails); + strcat(t,full_fn); + strcat(t,"\r\n"); + free(fails); + fails =t; + } + count++; + } + } + closedir(dir); + } else { + printf(TEST_DIR" directory not found"); + } + + if (count==0) printf("No tests found in "TEST_DIR"test*.js!\r\n"); + printf("--------------------------------------------------\r\n"); + printf(" %d of %d tests passed\r\n", passed, count); + if (passed!=count) { + printf("FAILS:\r\n%s", fails); + } + printf("--------------------------------------------------\r\n"); + free(fails); + return passed == count; +} + +bool run_memory_test(const char *fn, int vars) { + int i; + int min = 20; + int max = 100; + if (vars>0) { + min = vars; + max = vars+1; + } + for (i=min;i=argc) die("Expecting an extra argument\n"); + jshInit(); + jsiInit(true); + jspAddNativeFunction(jsiGetParser(), "function quit()", nativeQuit); + jsvUnLock(jspEvaluate(jsiGetParser(), argv[i+1])); + isRunning = true; + //while (isRunning && jsiHasTimers()) jsiLoop(); + jsiKill(); + jshKill(); + return (0); + } else if (!strcmp(a,"--test")) { + if (i+1>=argc) die("Expecting an extra argument\n"); + bool ok = run_test(argv[i+1]); + return (ok ? 0 : 1); + } else if (!strcmp(a,"--test-all")) { + bool ok = run_all_tests(); + return (ok ? 0 : 1); + } else if (!strcmp(a,"--test-mem-all")) { + bool ok = run_memory_tests(0); + return (ok ? 0 : 1); + } else if (!strcmp(a,"--test-mem")) { + if (i+1>=argc) die("Expecting an extra argument\n"); + bool ok = run_memory_test(argv[i+1], 0); + return (ok ? 0 : 1); + } else if (!strcmp(a,"--test-mem-n")) { + if (i+2>=argc) die("Expecting an extra 2 arguments\n"); + bool ok = run_memory_test(argv[i+1], atoi(argv[i+2])); + return (ok ? 0 : 1); + } else { + printf("Unknown Argument %s\n", a); + show_help(); + return -1; + } + } + } + + if (argc==1) { + printf("Interactive mode.\n"); + } else if (argc==2) { + // single file - just run it + char *buffer = (char *)read_file(argv[1]); + if (!buffer) return (1); + // check for '#' as the first char, and if so, skip the first line + char *cmd = buffer; + if (cmd[0]=='#') { + while (cmd[0] && cmd[0]!='\n') cmd++; + if (cmd[0]=='\n') cmd++; + } + jshInit(); + jsiInit(false /* do not autoload!!! */); + jspAddNativeFunction(jsiGetParser(), "function quit()", nativeQuit); + jsvUnLock(jspEvaluate(jsiGetParser(), cmd )); + free(buffer); + //isRunning = true; + //while (isRunning && jsiHasTimers()) jsiLoop(); + jsiKill(); + jshKill(); + return -1; + } else { + printf("Unknown arguments!\n"); + show_help(); + return -1; + } + + printf("Size of JsVar is now %d bytes\n", (int)sizeof(JsVar)); + printf("Size of JsVarRef is now %d bytes\n", (int)sizeof(JsVarRef)); + + jshInit(); + jsiInit(true); + + jspAddNativeFunction(jsiGetParser(), "function quit()", nativeQuit); + jspAddNativeFunction(jsiGetParser(), "function interrupt()", nativeInterrupt); + + while (isRunning) { + jsiLoop(); + } + jsiConsolePrint("\n"); + jsiKill(); + + jsvShowAllocated(); + jshKill(); + + return 0; +} + +MSH_CMD_EXPORT(espruino, JavaScript Interpreter) + diff --git a/components/external/espruino/targets/rtthread/jshardware.c b/components/external/espruino/targets/rtthread/jshardware.c new file mode 100644 index 0000000000..934040e5f0 --- /dev/null +++ b/components/external/espruino/targets/rtthread/jshardware.c @@ -0,0 +1,255 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Platform Specific part of Hardware interface Layer + * ---------------------------------------------------------------------------- + */ + #include + #include + #include + #include + #include + #include + #include + +#include "jshardware.h" +#include "jsutils.h" +#include "jsparse.h" +#include "jsinteractive.h" +#include "jspininfo.h" + +#include + +// ---------------------------------------------------------------------------- +// for non-blocking IO + +void reset_terminal_mode() +{ +} + +void set_conio_terminal_mode() +{ +} + +struct +{ + struct rt_semaphore sem; + rt_device_t device; +} dev4js; + +rt_err_t es_rx_ind(rt_device_t dev, rt_size_t size) +{ + rt_sem_release(&dev4js.sem); + + return RT_EOK; +} + +static int kbhit(void) +{ + while (rt_sem_take(&dev4js.sem, RT_WAITING_FOREVER) != RT_EOK); + + return 1; +} + +static char getch() +{ + unsigned char c; + + if (rt_device_read(dev4js.device, 0, &c, 1) == 1) { + if (c=='\3') exit(0); // ctrl-c + return c; + } +} + +void jshInit() { + rt_sem_init(&dev4js.sem, "jssem", 0, RT_IPC_FLAG_PRIO); +} + +void jshKill() { +} + +void jshIdle() { + //while (kbhit()) { + // jshPushIOCharEvent(EV_USBSERIAL, (char)getch()); + //} +} + +// ---------------------------------------------------------------------------- + +int jshGetSerialNumber(unsigned char *data, int maxChars) { + long initialSerial = 0; + long long serial = 0xDEADDEADDEADDEADL; + + memcpy(&data[0], &initialSerial, 4); + memcpy(&data[4], &serial, 8); + return 12; +} + +unsigned int jshGetRegistrationCode() { + unsigned int code = 0xFFFFFFFF; + return code; +} + +void jshSetRegistrationCode(unsigned int code) { +} + +// ---------------------------------------------------------------------------- + +void jshInterruptOff() { +} + +void jshInterruptOn() { +} + +void jshDelayMicroseconds(int microsec) { + int ms = (microsec + 999) / 1000; + + rt_thread_sleep(rt_tick_from_millisecond(ms)); // don't sleep much if we have watches - we need to keep polling them +} + +bool jshGetPinStateIsManual(Pin pin) { + return false; +} + +void jshSetPinStateIsManual(Pin pin, bool manual) { +} + +void jshPinSetState(Pin pin, JshPinState state) { +} + +JshPinState jshPinGetState(Pin pin) { + return JSHPINSTATE_UNDEFINED; +} + +void jshPinSetValue(Pin pin, bool value) { +} + +bool jshPinGetValue(Pin pin) { + + return false; +} + +bool jshIsDeviceInitialised(IOEventFlags device) { return true; } + +bool jshIsUSBSERIALConnected() { + return false; +} + +JsSysTime jshGetTimeFromMilliseconds(JsVarFloat ms) { + return (JsSysTime)(ms*1000); +} + +JsVarFloat jshGetMillisecondsFromTime(JsSysTime time) { + return ((JsVarFloat)time)/1000; +} + + +JsSysTime jshGetSystemTime() { + //struct timeval tm; + //gettimeofday(&tm, 0); + //return tm.tv_sec*1000000L + tm.tv_usec; + return rt_tick_get() * (1000 / RT_TICK_PER_SECOND) * 1000; +} + +// ---------------------------------------------------------------------------- + +bool jshPinInput(Pin pin) { + bool value = false; + + jsError("Invalid pin!"); + return value; +} + +JsVarFloat jshPinAnalog(Pin pin) { + JsVarFloat value = 0; + jsError("Analog is not supported on this device."); + return value; +} + + +void jshPinOutput(Pin pin, bool value) { +} + +bool jshPinOutputAtTime(JsSysTime time, Pin pin, bool value) { + // FIXME +} + +void jshPinAnalogOutput(Pin pin, JsVarFloat value, JsVarFloat freq) { // if freq<=0, the default is used +} + +void jshPinPulse(Pin pin, bool value, JsVarFloat time) { +} + +void jshPinWatch(Pin pin, bool shouldWatch) { +} + +bool jshGetWatchedPinState(IOEventFlags device) { + return false; +} + +bool jshIsEventForPin(IOEvent *event, Pin pin) { + return false; +} + +void jshUSARTSetup(IOEventFlags device, JshUSARTInfo *inf) { +} + +/** Kick a device into action (if required). For instance we may need + * to set up interrupts */ +void jshUSARTKick(IOEventFlags device) { +} + +void jshSPISetup(IOEventFlags device, JshSPIInfo *inf) { +} + +/** Send data through the given SPI device (if data>=0), and return the result + * of the previous send (or -1). If data<0, no data is sent and the function + * waits for data to be returned */ +int jshSPISend(IOEventFlags device, int data) { +} + +/** Send 16 bit data through the given SPI device. */ +void jshSPISend16(IOEventFlags device, int data) { +} + +/** Set whether to send 16 bits or 8 over SPI */ +void jshSPISet16(IOEventFlags device, bool is16) { +} + +void jshI2CSetup(IOEventFlags device, JshI2CInfo *inf) { +} + +void jshI2CWrite(IOEventFlags device, unsigned char address, int nBytes, const unsigned char *data) { +} + +void jshI2CRead(IOEventFlags device, unsigned char address, int nBytes, unsigned char *data) { +} + + +void jshSaveToFlash() { + +} + +void jshLoadFromFlash() { + +} + +bool jshFlashContainsCode() { + +} + +/// Enter simple sleep mode (can be woken up by interrupts). Returns true on success +bool jshSleep(JsSysTime timeUntilWake) { + bool hasWatches = false; + int ms = (hasWatches ? 1000 : (10*1000)) / 1000; + + rt_thread_sleep(rt_tick_from_millisecond(ms)); // don't sleep much if we have watches - we need to keep polling them + return true; +} From 213f47e380e87a26d60ba630a8256cb63224d2aa Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Tue, 25 Feb 2014 09:29:09 +0800 Subject: [PATCH 36/59] Update SConscript --- components/external/espruino/SConscript | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/components/external/espruino/SConscript b/components/external/espruino/SConscript index ca4f32b403..03088359ff 100644 --- a/components/external/espruino/SConscript +++ b/components/external/espruino/SConscript @@ -1,12 +1,7 @@ -import rtconfig -Import('RTT_ROOT') from building import * -path = [RTT_ROOT + r'/components/external/Espruino'] -path = path + [RTT_ROOT + r'/components/external/Espruino/src/'] -path = path + [RTT_ROOT + r'/components/external/Espruino/gen/'] -path = path + [RTT_ROOT + r'/components/external/Espruino/libs/'] -path = path + [RTT_ROOT + r'/components/external/Espruino/targets/rtthread/'] +cwd = GetCurrentDir() +path = [cwd + '/src', cwd + '/gen', cwd + '/libs', cwd + '/targets/rtthread'] src = Split(""" src/jsdevices.c @@ -51,7 +46,7 @@ libs/jswrap_math.c """ ) -src += gen + target + libs +src = src + gen + target + libs group = DefineGroup('Espruino', src, depend = ['RT_USING_JS', 'RT_USING_NEWLIB'], CPPPATH = path) From 3d80e414ff6c03ff04fecb914e7aa9b3fb535e03 Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Tue, 25 Feb 2014 13:43:59 +0800 Subject: [PATCH 37/59] [JS] fix the include path issue --- components/dfs/filesystems/romfs/mkromfs.py | 13 +++++++------ components/external/espruino/SConscript | 2 +- tools/building.py | 5 ----- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/components/dfs/filesystems/romfs/mkromfs.py b/components/dfs/filesystems/romfs/mkromfs.py index a84458e892..d1354eb259 100644 --- a/components/dfs/filesystems/romfs/mkromfs.py +++ b/components/dfs/filesystems/romfs/mkromfs.py @@ -4,6 +4,7 @@ import string basename = '' output = '' +sep = os.sep def mkromfs_output(out): # print '%s' % out, @@ -54,12 +55,12 @@ def mkromfs_dir(dirname, is_root = False): fullpath = os.path.join(path, item) if os.path.isfile(fullpath): subpath = fullpath[len(basename):] - array = subpath.split('\\') + array = subpath.split(sep) arrayname = string.join(array, '_') mkromfs_file(fullpath, arrayname) subpath = path[len(basename):] - dir = subpath.split('\\') + dir = subpath.split(sep) direntname = string.join(dir, '_') if is_root: mkromfs_output('const struct romfs_dirent _root_dirent[] = {\n') @@ -69,12 +70,12 @@ def mkromfs_dir(dirname, is_root = False): for item in list: fullpath = os.path.join(path, item) fn = fullpath[len(dirname):] - if fn[0] == '\\': + if fn[0] == sep: fn = fn[1:] fn = fn.replace('\\', '/') subpath = fullpath[len(basename):] - items = subpath.split('\\') + items = subpath.split(sep) item_name = string.join(items, '_') item_name = item_name.replace('.', '_') item_name = item_name.replace('-', '_') @@ -92,12 +93,12 @@ def mkromfs_dir(dirname, is_root = False): for item in list: fullpath = os.path.join(path, item) fn = fullpath[len(dirname):] - if fn[0] == '\\': + if fn[0] == sep: fn = fn[1:] fn = fn.replace('\\', '/') subpath = fullpath[len(basename):] - items = subpath.split('\\') + items = subpath.split(sep) item_name = string.join(items, '_') item_name = item_name.replace('.', '_') item_name = item_name.replace('-', '_') diff --git a/components/external/espruino/SConscript b/components/external/espruino/SConscript index 03088359ff..7e94473d94 100644 --- a/components/external/espruino/SConscript +++ b/components/external/espruino/SConscript @@ -1,7 +1,7 @@ from building import * cwd = GetCurrentDir() -path = [cwd + '/src', cwd + '/gen', cwd + '/libs', cwd + '/targets/rtthread'] +path = [cwd, cwd + '/src', cwd + '/gen', cwd + '/libs', cwd + '/targets/rtthread'] src = Split(""" src/jsdevices.c diff --git a/tools/building.py b/tools/building.py index 372d93f06f..6427e7c0dd 100644 --- a/tools/building.py +++ b/tools/building.py @@ -284,11 +284,6 @@ def MergeGroup(src_group, group): else: src_group['LIBPATH'] = group['LIBPATH'] - if src_group.has_key('LIBS'): - print src_group['LIBS'] - if src_group.has_key('LIBS'): - print src_group['LIBPATH'] - def DefineGroup(name, src, depend, **parameters): global Env if not GetDepend(depend): From 10c4b6263f92caa21c9cd3b5168678100d4cf18e Mon Sep 17 00:00:00 2001 From: Bright Pan Date: Wed, 26 Feb 2014 11:06:14 +0800 Subject: [PATCH 38/59] Use DeviceDriver ringbuffer. Add hardware flow support. Use new struct serial_ringbuffer. --- components/drivers/include/drivers/serial.h | 33 ++++++++----- components/drivers/serial/serial.c | 52 ++++++--------------- 2 files changed, 36 insertions(+), 49 deletions(-) diff --git a/components/drivers/include/drivers/serial.h b/components/drivers/include/drivers/serial.h index 41132ed916..c966f5459b 100644 --- a/components/drivers/include/drivers/serial.h +++ b/components/drivers/include/drivers/serial.h @@ -29,6 +29,7 @@ #define __SERIAL_H__ #include +#include #define BAUD_RATE_4800 4800 #define BAUD_RATE_9600 9600 @@ -55,6 +56,11 @@ #define NRZ_NORMAL 0 /* Non Return to Zero : normal mode */ #define NRZ_INVERTED 1 /* Non Return to Zero : inverted mode */ +#define HW_CONTROL_NONE 0 +#define HW_CONTROL_RTS 1 +#define HW_CONTROL_CTS 2 +#define HW_CONTROL_RTS_CTS 3 + #ifndef RT_SERIAL_RB_BUFSZ #define RT_SERIAL_RB_BUFSZ 64 #endif @@ -75,21 +81,23 @@ #define RT_SERIAL_TX_DATAQUEUE_LWM 30 /* Default config for serial_configure structure */ -#define RT_SERIAL_CONFIG_DEFAULT \ -{ \ - BAUD_RATE_115200, /* 115200 bits/s */ \ - DATA_BITS_8, /* 8 databits */ \ - STOP_BITS_1, /* 1 stopbit */ \ - PARITY_NONE, /* No parity */ \ - BIT_ORDER_LSB, /* LSB first sent */ \ - NRZ_NORMAL, /* Normal mode */ \ - 0 \ +#define RT_SERIAL_CONFIG_DEFAULT \ +{ \ + BAUD_RATE_115200, /* 115200 bits/s */ \ + DATA_BITS_8, /* 8 databits */ \ + STOP_BITS_1, /* 1 stopbit */ \ + PARITY_NONE, /* No parity */ \ + BIT_ORDER_LSB, /* LSB first sent */ \ + NRZ_NORMAL, /* Normal mode */ \ + HW_CONTROL_NONE, /* Hardware control */\ + 0 \ } struct serial_ringbuffer { - rt_uint8_t buffer[RT_SERIAL_RB_BUFSZ]; - rt_uint16_t put_index, get_index; + struct rt_ringbuffer rb; + rt_uint8_t *pool; + rt_uint16_t size; }; struct serial_configure @@ -100,7 +108,8 @@ struct serial_configure rt_uint32_t parity :2; rt_uint32_t bit_order :1; rt_uint32_t invert :1; - rt_uint32_t reserved :20; + rt_uint32_t hw_control :2; + rt_uint32_t reserved :18; }; struct rt_serial_device diff --git a/components/drivers/serial/serial.c b/components/drivers/serial/serial.c index 5e7a8ec814..a9b4e47b43 100644 --- a/components/drivers/serial/serial.c +++ b/components/drivers/serial/serial.c @@ -25,6 +25,9 @@ * 2012-11-23 bernard fix compiler warning. * 2013-02-20 bernard use RT_SERIAL_RB_BUFSZ to define * the size of ring buffer. + * 2014-02-26 bright use DeviceDriver ringbuffer. + * add hardware flow support. + * use new struct serial_ringbuffer. */ #include @@ -33,9 +36,7 @@ rt_inline void serial_ringbuffer_init(struct serial_ringbuffer *rbuffer) { - rt_memset(rbuffer->buffer, 0, sizeof(rbuffer->buffer)); - rbuffer->put_index = 0; - rbuffer->get_index = 0; + rt_ringbuffer_init(&rbuffer->rb, rbuffer->pool, rbuffer->size); } rt_inline void serial_ringbuffer_putc(struct serial_ringbuffer *rbuffer, @@ -45,17 +46,8 @@ rt_inline void serial_ringbuffer_putc(struct serial_ringbuffer *rbuffer, /* disable interrupt */ level = rt_hw_interrupt_disable(); - - rbuffer->buffer[rbuffer->put_index] = ch; - rbuffer->put_index = (rbuffer->put_index + 1) & (RT_SERIAL_RB_BUFSZ - 1); - - /* if the next position is read index, discard this 'read char' */ - if (rbuffer->put_index == rbuffer->get_index) - { - rbuffer->get_index = (rbuffer->get_index + 1) & (RT_SERIAL_RB_BUFSZ - 1); - } - - /* enable interrupt */ + rt_ringbuffer_putchar(&rbuffer->rb, ch); + // enable interrupt rt_hw_interrupt_enable(level); } @@ -63,25 +55,11 @@ rt_inline int serial_ringbuffer_putchar(struct serial_ringbuffer *rbuffer, char ch) { rt_base_t level; - rt_uint16_t next_index; + //rt_uint16_t next_index; /* disable interrupt */ level = rt_hw_interrupt_disable(); - - next_index = (rbuffer->put_index + 1) & (RT_SERIAL_RB_BUFSZ - 1); - if (next_index != rbuffer->get_index) - { - rbuffer->buffer[rbuffer->put_index] = ch; - rbuffer->put_index = next_index; - } - else - { - /* enable interrupt */ - rt_hw_interrupt_enable(level); - - return -1; - } - + rt_ringbuffer_putchar(&rbuffer->rb, ch); /* enable interrupt */ rt_hw_interrupt_enable(level); @@ -90,17 +68,14 @@ rt_inline int serial_ringbuffer_putchar(struct serial_ringbuffer *rbuffer, rt_inline int serial_ringbuffer_getc(struct serial_ringbuffer *rbuffer) { - int ch; + int ch = 0; rt_base_t level; - ch = -1; /* disable interrupt */ level = rt_hw_interrupt_disable(); - if (rbuffer->get_index != rbuffer->put_index) - { - ch = rbuffer->buffer[rbuffer->get_index]; - rbuffer->get_index = (rbuffer->get_index + 1) & (RT_SERIAL_RB_BUFSZ - 1); - } + /* get char */ + if (!rt_ringbuffer_getchar(&rbuffer->rb, (rt_uint8_t *)&ch)) + ch = -1; /* enable interrupt */ rt_hw_interrupt_enable(level); @@ -113,7 +88,10 @@ rt_inline rt_uint32_t serial_ringbuffer_size(struct serial_ringbuffer *rbuffer) rt_base_t level; level = rt_hw_interrupt_disable(); + size = rt_ringbuffer_space_len(&rbuffer->rb); + /* size = (rbuffer->put_index - rbuffer->get_index) & (RT_SERIAL_RB_BUFSZ - 1); + */ rt_hw_interrupt_enable(level); return size; From a4cd949519dc9d511ee9171b255e67c21128827e Mon Sep 17 00:00:00 2001 From: Bright Pan Date: Wed, 26 Feb 2014 11:22:08 +0800 Subject: [PATCH 39/59] Fix uart device driver for gpio remap and hardware flow control. Add uart4 and uart5 device driver. --- bsp/stm32f10x/drivers/board.h | 2 + bsp/stm32f10x/drivers/usart.c | 586 ++++++++++++++++++++++++++-------- 2 files changed, 458 insertions(+), 130 deletions(-) diff --git a/bsp/stm32f10x/drivers/board.h b/bsp/stm32f10x/drivers/board.h index dc84db9c69..ebd121d631 100644 --- a/bsp/stm32f10x/drivers/board.h +++ b/bsp/stm32f10x/drivers/board.h @@ -41,6 +41,8 @@ #define RT_USING_UART1 #define RT_USING_UART2 #define RT_USING_UART3 +//#define RT_USING_UART4 +//#define RT_USING_UART5 #endif /* __BOARD_H__ */ diff --git a/bsp/stm32f10x/drivers/usart.c b/bsp/stm32f10x/drivers/usart.c index ae47db3a14..4bb320269b 100644 --- a/bsp/stm32f10x/drivers/usart.c +++ b/bsp/stm32f10x/drivers/usart.c @@ -21,25 +21,90 @@ #include /* USART1 */ -#define UART1_GPIO_TX GPIO_Pin_9 -#define UART1_GPIO_RX GPIO_Pin_10 -#define UART1_GPIO GPIOA +#define UART1_TX_PIN GPIO_Pin_9 +#define UART1_TX_GPIO GPIOA +#define UART1_RX_PIN GPIO_Pin_10 +#define UART1_RX_GPIO GPIOA + +#define UART1_CTS_PIN ((uint16_t)0x0000)// cts is disable +#define UART1_CTS_GPIO ((GPIO_TypeDef *)0x00000000) +#define UART1_RTS_PIN ((uint16_t)0x0000)// rts is disable +#define UART1_RTS_GPIO ((GPIO_TypeDef *)0x00000000) + +#define UART1_REMAP (((uint32_t)0x00000000))// remap is disable /* USART2 */ -#define UART2_GPIO_TX GPIO_Pin_2 -#define UART2_GPIO_RX GPIO_Pin_3 -#define UART2_GPIO GPIOA +#define UART2_TX_PIN GPIO_Pin_2 +#define UART2_TX_GPIO GPIOA +#define UART2_RX_PIN GPIO_Pin_3 +#define UART2_RX_GPIO GPIOA -/* USART3_REMAP[1:0] = 00 */ -#define UART3_GPIO_TX GPIO_Pin_10 -#define UART3_GPIO_RX GPIO_Pin_11 -#define UART3_GPIO GPIOB +#define UART2_CTS_PIN ((uint16_t)0x0000)// cts is disable +#define UART2_CTS_GPIO ((GPIO_TypeDef *)0x00000000) +#define UART2_RTS_PIN ((uint16_t)0x0000)// rts is disable +#define UART2_RTS_GPIO ((GPIO_TypeDef *)0x00000000) + +#define UART2_REMAP (((uint32_t)0x00000000))// remap is disable + +/* USART3_REMAP[1:0] = 11 */ +#define UART3_TX_PIN GPIO_Pin_8 +#define UART3_TX_GPIO GPIOD +#define UART3_RX_PIN GPIO_Pin_9 +#define UART3_RX_GPIO GPIOD + +#define UART3_CTS_PIN ((uint16_t)0x0000)// cts is disable +#define UART3_CTS_GPIO ((GPIO_TypeDef *)0x00000000) +#define UART3_RTS_PIN ((uint16_t)0x0000)// rts is disable +#define UART3_RTS_GPIO ((GPIO_TypeDef *)0x00000000) + +#define UART3_REMAP GPIO_FullRemap_USART3 + +/* USART4 */ +#define UART4_TX_PIN GPIO_Pin_10 +#define UART4_TX_GPIO GPIOC +#define UART4_RX_PIN GPIO_Pin_11 +#define UART4_RX_GPIO GPIOC + +#define UART4_CTS_PIN ((uint16_t)0x0000)// cts is disable +#define UART4_CTS_GPIO ((GPIO_TypeDef *)0x00000000) +#define UART4_RTS_PIN ((uint16_t)0x0000)// rts is disable +#define UART4_RTS_GPIO ((GPIO_TypeDef *)0x00000000) + +#define UART4_REMAP (((uint32_t)0x00000000))// remap is disable + +/* USART5 */ +#define UART5_TX_PIN GPIO_Pin_12 +#define UART5_TX_GPIO GPIOC +#define UART5_RX_PIN GPIO_Pin_2 +#define UART5_RX_GPIO GPIOD + +#define UART5_CTS_PIN ((uint16_t)0x0000)// cts is disable +#define UART5_CTS_GPIO ((GPIO_TypeDef *)0x00000000) +#define UART5_RTS_PIN ((uint16_t)0x0000)// rts is disable +#define UART5_RTS_GPIO ((GPIO_TypeDef *)0x00000000) + +#define UART4_REMAP (((uint32_t)0x00000000))// remap is disable /* STM32 uart driver */ struct stm32_uart { USART_TypeDef* uart_device; IRQn_Type irq; + + uint16_t uart_tx_pin; + GPIO_TypeDef *uart_tx_gpio; + + uint16_t uart_rx_pin; + GPIO_TypeDef *uart_rx_gpio; + + uint16_t uart_cts_pin; + GPIO_TypeDef *uart_cts_gpio; + + uint16_t uart_rts_pin; + GPIO_TypeDef *uart_rts_gpio; + + uint32_t uart_remap; + }; static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_configure *cfg) @@ -51,7 +116,7 @@ static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_c RT_ASSERT(cfg != RT_NULL); uart = (struct stm32_uart *)serial->parent.user_data; - + USART_StructInit(&USART_InitStructure); USART_InitStructure.USART_BaudRate = cfg->baud_rate; if (cfg->data_bits == DATA_BITS_8) @@ -62,8 +127,18 @@ static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_c else if (cfg->stop_bits == STOP_BITS_2) USART_InitStructure.USART_StopBits = USART_StopBits_2; - USART_InitStructure.USART_Parity = USART_Parity_No; - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + if (cfg->parity == PARITY_NONE) + USART_InitStructure.USART_Parity = USART_Parity_No; + else if (cfg->parity == PARITY_EVEN) + USART_InitStructure.USART_Parity = USART_Parity_Even; + else if (cfg->parity == PARITY_ODD) + USART_InitStructure.USART_Parity = USART_Parity_Odd; + + if (cfg->hw_control == HW_CONTROL_NONE) + USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + else if (cfg->hw_control == HW_CONTROL_RTS_CTS) + USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_RTS_CTS; + USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(uart->uart_device, &USART_InitStructure); @@ -135,180 +210,327 @@ static const struct rt_uart_ops stm32_uart_ops = stm32_getc, }; +__STATIC_INLINE void serial_device_isr(struct rt_serial_device *serial) +{ + volatile int ch = 0; + struct stm32_uart *uart = serial->parent.user_data; + + /* process uart error */ + if(uart->uart_device->SR & (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE)) + { + ch = uart->uart_device->DR; // invalid read + while (uart->uart_device->SR & USART_FLAG_RXNE) + { + ch = uart->uart_device->DR; // invalid read + } + } + /* process usart receive */ + if (uart->uart_device->SR & USART_FLAG_RXNE) + { + rt_hw_serial_isr(serial);//auto clear interrupt flag + } + /* process usart send */ + if (uart->uart_device->SR & USART_IT_TC) + { + /* clear interrupt */ + uart->uart_device->SR = ~((uint16_t)0x01 << (uint16_t)(USART_IT_TC >> 0x08)); + } +} + #if defined(RT_USING_UART1) /* UART1 device driver structure */ struct serial_ringbuffer uart1_int_rx; +#define UART1_POOL_SIZE 64 +rt_uint8_t uart1_pool[UART1_POOL_SIZE]; struct stm32_uart uart1 = { USART1, USART1_IRQn, + + UART1_TX_PIN, + UART1_TX_GPIO, + UART1_RX_PIN, + UART1_RX_GPIO, + + UART1_CTS_PIN, + UART1_CTS_GPIO, + UART1_RTS_PIN, + UART1_RTS_GPIO, + + UART1_REMAP, }; struct rt_serial_device serial1; void USART1_IRQHandler(void) { - struct stm32_uart* uart; - - uart = &uart1; - /* enter interrupt */ rt_interrupt_enter(); - if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET) - { - rt_hw_serial_isr(&serial1); - /* clear interrupt */ - USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE); - } - if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET) - { - /* clear interrupt */ - USART_ClearITPendingBit(uart->uart_device, USART_IT_TC); - } + serial_device_isr(&serial1); + /* leave interrupt */ rt_interrupt_leave(); } #endif /* RT_USING_UART1 */ #if defined(RT_USING_UART2) -/* UART1 device driver structure */ +/* UART2 device driver structure */ struct serial_ringbuffer uart2_int_rx; +#define UART2_POOL_SIZE 64 +rt_uint8_t uart2_pool[UART2_POOL_SIZE]; struct stm32_uart uart2 = { USART2, USART2_IRQn, + + UART2_TX_PIN, + UART2_TX_GPIO, + UART2_RX_PIN, + UART2_RX_GPIO, + + UART2_CTS_PIN, + UART2_CTS_GPIO, + UART2_RTS_PIN, + UART2_RTS_GPIO, + + UART2_REMAP, + }; struct rt_serial_device serial2; void USART2_IRQHandler(void) { - struct stm32_uart* uart; - - uart = &uart2; - /* enter interrupt */ rt_interrupt_enter(); - if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET) - { - rt_hw_serial_isr(&serial2); - /* clear interrupt */ - USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE); - } - if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET) - { - /* clear interrupt */ - USART_ClearITPendingBit(uart->uart_device, USART_IT_TC); - } + serial_device_isr(&serial2); + /* leave interrupt */ rt_interrupt_leave(); } #endif /* RT_USING_UART2 */ #if defined(RT_USING_UART3) -/* UART1 device driver structure */ +/* UART3 device driver structure */ struct serial_ringbuffer uart3_int_rx; +#define UART3_POOL_SIZE 64 +rt_uint8_t uart3_pool[UART3_POOL_SIZE]; struct stm32_uart uart3 = { USART3, USART3_IRQn, + + UART3_TX_PIN, + UART3_TX_GPIO, + UART3_RX_PIN, + UART3_RX_GPIO, + + UART3_CTS_PIN, + UART3_CTS_GPIO, + UART3_RTS_PIN, + UART3_RTS_GPIO, + + UART3_REMAP, }; struct rt_serial_device serial3; void USART3_IRQHandler(void) { - struct stm32_uart* uart; - - uart = &uart3; - /* enter interrupt */ rt_interrupt_enter(); - if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET) - { - rt_hw_serial_isr(&serial3); - /* clear interrupt */ - USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE); - } - if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET) - { - /* clear interrupt */ - USART_ClearITPendingBit(uart->uart_device, USART_IT_TC); - } + + serial_device_isr(&serial3); /* leave interrupt */ rt_interrupt_leave(); } #endif /* RT_USING_UART3 */ -static void RCC_Configuration(void) +#if defined(RT_USING_UART4) +/* UART4 device driver structure */ +struct serial_ringbuffer uart4_int_rx; +#define UART4_POOL_SIZE 64 +rt_uint8_t uart4_pool[UART4_POOL_SIZE]; +struct stm32_uart uart4 = { -#ifdef RT_USING_UART1 - /* Enable UART GPIO clocks */ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); - /* Enable UART clock */ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); -#endif /* RT_USING_UART1 */ + UART4, + UART4_IRQn, -#ifdef RT_USING_UART2 - /* Enable UART GPIO clocks */ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); - /* Enable UART clock */ - RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); -#endif /* RT_USING_UART2 */ + UART4_TX_PIN, + UART4_TX_GPIO, + UART4_RX_PIN, + UART4_RX_GPIO, -#ifdef RT_USING_UART3 + UART4_CTS_PIN, + UART4_CTS_GPIO, + UART4_RTS_PIN, + UART4_RTS_GPIO, + + UART4_REMAP, +}; +struct rt_serial_device serial4; + +void UART4_IRQHandler(void) +{ + /* enter interrupt */ + rt_interrupt_enter(); + + serial_device_isr(&serial4); + + /* leave interrupt */ + rt_interrupt_leave(); +} +#endif /* RT_USING_UART4 */ + +#if defined(RT_USING_UART5) +/* UART5 device driver structure */ +struct serial_ringbuffer uart5_int_rx; +#define UART5_POOL_SIZE 64 +rt_uint8_t uart5_pool[UART5_POOL_SIZE]; +struct stm32_uart uart5 = +{ + UART5, + UART5_IRQn, + + UART5_TX_PIN, + UART5_TX_GPIO, + UART5_RX_PIN, + UART5_RX_GPIO, + + UART5_CTS_PIN, + UART5_CTS_GPIO, + UART5_RTS_PIN, + UART5_RTS_GPIO, + + UART5_REMAP, +}; +struct rt_serial_device serial5; + +void UART5_IRQHandler(void) +{ + /* enter interrupt */ + rt_interrupt_enter(); + + serial_device_isr(&serial5); + + /* leave interrupt */ + rt_interrupt_leave(); +} +#endif /* RT_USING_UART5 */ + +#define GPIO_RCC_ENABLE(x) \ +do{ \ + if (IS_GPIO_ALL_PERIPH(x)) \ + { \ + if ((x) == GPIOA) \ + { \ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); \ + } \ + if ((x) == GPIOB) \ + { \ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); \ + } \ + if ((x) == GPIOC) \ + { \ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); \ + } \ + if ((x) == GPIOD) \ + { \ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); \ + } \ + if ((x) == GPIOE) \ + { \ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); \ + } \ + if ((x) == GPIOF) \ + { \ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE); \ + } \ + if ((x) == GPIOG) \ + { \ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE); \ + } \ + } \ +}while(0) + +#define UART_RCC_ENABLE(x) \ +do{ \ + if (IS_USART_ALL_PERIPH(x)) \ + { \ + if ((x) == USART1) \ + { \ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); \ + } \ + if ((x) == USART2) \ + { \ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); \ + } \ + if ((x) == USART3) \ + { \ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); \ + } \ + if ((x) == UART4) \ + { \ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE); \ + } \ + if ((x) == UART5) \ + { \ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE); \ + } \ + } \ +}while(0) + +static void RCC_Configuration(struct stm32_uart* uart) +{ /* Enable UART GPIO clocks */ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); + GPIO_RCC_ENABLE(uart->uart_tx_gpio); + GPIO_RCC_ENABLE(uart->uart_rx_gpio); + GPIO_RCC_ENABLE(uart->uart_cts_gpio); + GPIO_RCC_ENABLE(uart->uart_rts_gpio); + /* Enable UART GPIO AF clocks */ + if (IS_GPIO_REMAP(uart->uart_remap)) + { + RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); + GPIO_PinRemapConfig(uart->uart_remap, ENABLE); + } /* Enable UART clock */ - RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); -#endif /* RT_USING_UART3 */ + UART_RCC_ENABLE(uart->uart_device); } -static void GPIO_Configuration(void) +static void GPIO_Configuration(struct stm32_uart* uart) { GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - -#ifdef RT_USING_UART1 + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /* Configure USART Rx/tx PIN */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; - GPIO_InitStructure.GPIO_Pin = UART1_GPIO_RX; - GPIO_Init(UART1_GPIO, &GPIO_InitStructure); + GPIO_InitStructure.GPIO_Pin = uart->uart_rx_pin; + GPIO_Init(uart->uart_rx_gpio, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; - GPIO_InitStructure.GPIO_Pin = UART1_GPIO_TX; - GPIO_Init(UART1_GPIO, &GPIO_InitStructure); -#endif /* RT_USING_UART1 */ + GPIO_InitStructure.GPIO_Pin = uart->uart_tx_pin; + GPIO_Init(uart->uart_tx_gpio, &GPIO_InitStructure); + /* Configure USART RTS/CTS PIN */ + if (IS_GPIO_ALL_PERIPH(uart->uart_cts_gpio) && + IS_GPIO_ALL_PERIPH(uart->uart_rts_gpio) && + IS_GPIO_PIN(uart->uart_cts_pin) && + IS_GPIO_PIN(uart->uart_rts_pin)) + { + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; + GPIO_InitStructure.GPIO_Pin = uart->uart_cts_pin; + GPIO_Init(uart->uart_cts_gpio, &GPIO_InitStructure); -#ifdef RT_USING_UART2 - /* Configure USART Rx/tx PIN */ - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; - GPIO_InitStructure.GPIO_Pin = UART2_GPIO_RX; - GPIO_Init(UART1_GPIO, &GPIO_InitStructure); - - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; - GPIO_InitStructure.GPIO_Pin = UART2_GPIO_TX; - GPIO_Init(UART2_GPIO, &GPIO_InitStructure); -#endif /* RT_USING_UART2 */ - -#ifdef RT_USING_UART3 - /* Configure USART Rx/tx PIN */ - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; - GPIO_InitStructure.GPIO_Pin = UART3_GPIO_RX; - GPIO_Init(UART3_GPIO, &GPIO_InitStructure); - - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; - GPIO_InitStructure.GPIO_Pin = UART3_GPIO_TX; - GPIO_Init(UART3_GPIO, &GPIO_InitStructure); -#endif /* RT_USING_UART3 */ + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; + GPIO_InitStructure.GPIO_Pin = uart->uart_rts_pin; + GPIO_Init(uart->uart_rts_gpio, &GPIO_InitStructure); + } } static void NVIC_Configuration(struct stm32_uart* uart) { NVIC_InitTypeDef NVIC_InitStructure; - /* Enable the USART1 Interrupt */ + /* Enable the USART Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = uart->irq; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; @@ -319,57 +541,161 @@ static void NVIC_Configuration(struct stm32_uart* uart) void rt_hw_usart_init(void) { struct stm32_uart* uart; + struct rt_serial_device *serial; struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; - RCC_Configuration(); - GPIO_Configuration(); - #ifdef RT_USING_UART1 uart = &uart1; + serial = &serial1; + + uart1_int_rx.pool = uart1_pool; + uart1_int_rx.size = UART1_POOL_SIZE; + config.baud_rate = BAUD_RATE_115200; - serial1.ops = &stm32_uart_ops; - serial1.int_rx = &uart1_int_rx; - serial1.config = config; - - NVIC_Configuration(&uart1); + serial->ops = &stm32_uart_ops; + serial->int_rx = &uart1_int_rx; + serial->config = config; + + RCC_Configuration(uart); + GPIO_Configuration(uart); + NVIC_Configuration(uart); /* register UART1 device */ - rt_hw_serial_register(&serial1, "uart1", + rt_hw_serial_register(serial, "uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, uart); #endif /* RT_USING_UART1 */ #ifdef RT_USING_UART2 uart = &uart2; + serial = &serial2; + + uart2_int_rx.pool = uart2_pool; + uart2_int_rx.size = UART2_POOL_SIZE; config.baud_rate = BAUD_RATE_115200; - serial2.ops = &stm32_uart_ops; - serial2.int_rx = &uart2_int_rx; - serial2.config = config; - NVIC_Configuration(&uart2); + serial->ops = &stm32_uart_ops; + serial->int_rx = &uart2_int_rx; + serial->config = config; + + RCC_Configuration(uart); + GPIO_Configuration(uart); + NVIC_Configuration(uart); - /* register UART1 device */ - rt_hw_serial_register(&serial2, "uart2", + /* register UART2 device */ + rt_hw_serial_register(serial, "uart2", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, uart); #endif /* RT_USING_UART2 */ #ifdef RT_USING_UART3 uart = &uart3; + serial = &serial3; + + uart3_int_rx.pool = uart3_pool; + uart3_int_rx.size = UART3_POOL_SIZE; config.baud_rate = BAUD_RATE_115200; - serial3.ops = &stm32_uart_ops; - serial3.int_rx = &uart3_int_rx; - serial3.config = config; + serial->ops = &stm32_uart_ops; + serial->int_rx = &uart3_int_rx; + serial->config = config; + + RCC_Configuration(uart); + GPIO_Configuration(uart); + NVIC_Configuration(uart); - NVIC_Configuration(&uart3); - - /* register UART1 device */ - rt_hw_serial_register(&serial3, "uart3", + /* register UART3 device */ + rt_hw_serial_register(serial, "uart3", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, uart); #endif /* RT_USING_UART3 */ + +#ifdef RT_USING_UART4 + uart = &uart4; + serial = &serial4; + + uart4_int_rx.pool = uart4_pool; + uart4_int_rx.size = UART4_POOL_SIZE; + + config.baud_rate = BAUD_RATE_115200; + + serial->ops = &stm32_uart_ops; + serial->int_rx = &uart4_int_rx; + serial->config = config; + + RCC_Configuration(uart); + GPIO_Configuration(uart); + NVIC_Configuration(uart); + + /* register UART4 device */ + rt_hw_serial_register(serial, "uart4", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, + uart); +#endif /* RT_USING_UART4 */ + +#ifdef RT_USING_UART5 + uart = &uart5; + serial = &serial5; + + uart5_int_rx.pool = uart5_pool; + uart5_int_rx.size = UART5_POOL_SIZE; + + config.baud_rate = BAUD_RATE_115200; + + serial->ops = &stm32_uart_ops; + serial->int_rx = &uart5_int_rx; + serial->config = config; + + RCC_Configuration(uart); + GPIO_Configuration(uart); + NVIC_Configuration(uart); + + /* register UART5 device */ + rt_hw_serial_register(serial, "uart5", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, + uart); +#endif /* RT_USING_UART5 */ } + + +/* uart device test */ +#ifdef RT_USING_FINSH +#include + +#if (defined(RT_USING_UART1) || defined(RT_USING_UART2) || defined(RT_USING_UART3) || defined(RT_USING_UART4) || defined(RT_USING_UART5)) +void uart_rw(const char *name, rt_int8_t cmd, const char *str) +{ + rt_device_t uart; + uart = rt_device_find(name); + if (uart != RT_NULL) + { + if (uart->open_flag == RT_DEVICE_OFLAG_CLOSE) + { + rt_device_open(uart, RT_DEVICE_OFLAG_RDWR); + } + if (cmd == 0) + { + rt_int8_t temp[20]; + memset(temp, '\0', 20); + rt_device_read(uart,0,(void *)temp,20); + rt_kprintf("%s", temp); + } + else + { + rt_kprintf("%s, %d", str, strlen(str)); + rt_device_write(uart,0,str,strlen(str)); + } + //rt_device_close(uart); + } + else + { + rt_kprintf("device %s is not exist!\n", name); + } +} +FINSH_FUNCTION_EXPORT(uart_rw, set uart[name 0 xxx] for read.) +#endif + +#endif From 9ab853aca3385f77f8a41a55c02ea425f14b0028 Mon Sep 17 00:00:00 2001 From: Bright Pan Date: Fri, 28 Feb 2014 18:22:50 +0800 Subject: [PATCH 40/59] Fix rt_serial_control() bug for customized command and indent the code --- components/drivers/serial/serial.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/components/drivers/serial/serial.c b/components/drivers/serial/serial.c index a9b4e47b43..9a356b6f0c 100644 --- a/components/drivers/serial/serial.c +++ b/components/drivers/serial/serial.c @@ -346,20 +346,25 @@ static rt_err_t rt_serial_control(struct rt_device *dev, switch (cmd) { - case RT_DEVICE_CTRL_SUSPEND: - /* suspend device */ - dev->flag |= RT_DEVICE_FLAG_SUSPENDED; - break; + case RT_DEVICE_CTRL_SUSPEND: + /* suspend device */ + dev->flag |= RT_DEVICE_FLAG_SUSPENDED; + break; - case RT_DEVICE_CTRL_RESUME: - /* resume device */ - dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED; - break; + case RT_DEVICE_CTRL_RESUME: + /* resume device */ + dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED; + break; - case RT_DEVICE_CTRL_CONFIG: - /* configure device */ - serial->ops->configure(serial, (struct serial_configure *)args); - break; + case RT_DEVICE_CTRL_CONFIG: + /* configure device */ + serial->ops->configure(serial, (struct serial_configure *)args); + break; + + default : + /* control device */ + serial->ops->control(serial, cmd, args); + break; } return RT_EOK; From f615c1e92de7ff72abe9eea5210a2744a0166692 Mon Sep 17 00:00:00 2001 From: Grissiom Date: Mon, 3 Mar 2014 12:07:13 +0800 Subject: [PATCH 41/59] Revert "Merge pull request #241 from bright-pan/master" This reverts commit 5aeedc4f3a3c3fcfffb0cd4a474f5faa75053839, reversing changes made to 3d80e414ff6c03ff04fecb914e7aa9b3fb535e03. This merge breaks every uart driver in all BSPs. @bright-pan , is there any way to get this done without breaking existing code? --- bsp/stm32f10x/drivers/board.h | 2 - bsp/stm32f10x/drivers/usart.c | 590 +++++--------------- components/drivers/include/drivers/serial.h | 33 +- components/drivers/serial/serial.c | 52 +- 4 files changed, 181 insertions(+), 496 deletions(-) diff --git a/bsp/stm32f10x/drivers/board.h b/bsp/stm32f10x/drivers/board.h index ebd121d631..dc84db9c69 100644 --- a/bsp/stm32f10x/drivers/board.h +++ b/bsp/stm32f10x/drivers/board.h @@ -41,8 +41,6 @@ #define RT_USING_UART1 #define RT_USING_UART2 #define RT_USING_UART3 -//#define RT_USING_UART4 -//#define RT_USING_UART5 #endif /* __BOARD_H__ */ diff --git a/bsp/stm32f10x/drivers/usart.c b/bsp/stm32f10x/drivers/usart.c index 4bb320269b..ae47db3a14 100644 --- a/bsp/stm32f10x/drivers/usart.c +++ b/bsp/stm32f10x/drivers/usart.c @@ -21,90 +21,25 @@ #include /* USART1 */ -#define UART1_TX_PIN GPIO_Pin_9 -#define UART1_TX_GPIO GPIOA -#define UART1_RX_PIN GPIO_Pin_10 -#define UART1_RX_GPIO GPIOA - -#define UART1_CTS_PIN ((uint16_t)0x0000)// cts is disable -#define UART1_CTS_GPIO ((GPIO_TypeDef *)0x00000000) -#define UART1_RTS_PIN ((uint16_t)0x0000)// rts is disable -#define UART1_RTS_GPIO ((GPIO_TypeDef *)0x00000000) - -#define UART1_REMAP (((uint32_t)0x00000000))// remap is disable +#define UART1_GPIO_TX GPIO_Pin_9 +#define UART1_GPIO_RX GPIO_Pin_10 +#define UART1_GPIO GPIOA /* USART2 */ -#define UART2_TX_PIN GPIO_Pin_2 -#define UART2_TX_GPIO GPIOA -#define UART2_RX_PIN GPIO_Pin_3 -#define UART2_RX_GPIO GPIOA +#define UART2_GPIO_TX GPIO_Pin_2 +#define UART2_GPIO_RX GPIO_Pin_3 +#define UART2_GPIO GPIOA -#define UART2_CTS_PIN ((uint16_t)0x0000)// cts is disable -#define UART2_CTS_GPIO ((GPIO_TypeDef *)0x00000000) -#define UART2_RTS_PIN ((uint16_t)0x0000)// rts is disable -#define UART2_RTS_GPIO ((GPIO_TypeDef *)0x00000000) - -#define UART2_REMAP (((uint32_t)0x00000000))// remap is disable - -/* USART3_REMAP[1:0] = 11 */ -#define UART3_TX_PIN GPIO_Pin_8 -#define UART3_TX_GPIO GPIOD -#define UART3_RX_PIN GPIO_Pin_9 -#define UART3_RX_GPIO GPIOD - -#define UART3_CTS_PIN ((uint16_t)0x0000)// cts is disable -#define UART3_CTS_GPIO ((GPIO_TypeDef *)0x00000000) -#define UART3_RTS_PIN ((uint16_t)0x0000)// rts is disable -#define UART3_RTS_GPIO ((GPIO_TypeDef *)0x00000000) - -#define UART3_REMAP GPIO_FullRemap_USART3 - -/* USART4 */ -#define UART4_TX_PIN GPIO_Pin_10 -#define UART4_TX_GPIO GPIOC -#define UART4_RX_PIN GPIO_Pin_11 -#define UART4_RX_GPIO GPIOC - -#define UART4_CTS_PIN ((uint16_t)0x0000)// cts is disable -#define UART4_CTS_GPIO ((GPIO_TypeDef *)0x00000000) -#define UART4_RTS_PIN ((uint16_t)0x0000)// rts is disable -#define UART4_RTS_GPIO ((GPIO_TypeDef *)0x00000000) - -#define UART4_REMAP (((uint32_t)0x00000000))// remap is disable - -/* USART5 */ -#define UART5_TX_PIN GPIO_Pin_12 -#define UART5_TX_GPIO GPIOC -#define UART5_RX_PIN GPIO_Pin_2 -#define UART5_RX_GPIO GPIOD - -#define UART5_CTS_PIN ((uint16_t)0x0000)// cts is disable -#define UART5_CTS_GPIO ((GPIO_TypeDef *)0x00000000) -#define UART5_RTS_PIN ((uint16_t)0x0000)// rts is disable -#define UART5_RTS_GPIO ((GPIO_TypeDef *)0x00000000) - -#define UART4_REMAP (((uint32_t)0x00000000))// remap is disable +/* USART3_REMAP[1:0] = 00 */ +#define UART3_GPIO_TX GPIO_Pin_10 +#define UART3_GPIO_RX GPIO_Pin_11 +#define UART3_GPIO GPIOB /* STM32 uart driver */ struct stm32_uart { USART_TypeDef* uart_device; IRQn_Type irq; - - uint16_t uart_tx_pin; - GPIO_TypeDef *uart_tx_gpio; - - uint16_t uart_rx_pin; - GPIO_TypeDef *uart_rx_gpio; - - uint16_t uart_cts_pin; - GPIO_TypeDef *uart_cts_gpio; - - uint16_t uart_rts_pin; - GPIO_TypeDef *uart_rts_gpio; - - uint32_t uart_remap; - }; static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_configure *cfg) @@ -116,7 +51,7 @@ static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_c RT_ASSERT(cfg != RT_NULL); uart = (struct stm32_uart *)serial->parent.user_data; - USART_StructInit(&USART_InitStructure); + USART_InitStructure.USART_BaudRate = cfg->baud_rate; if (cfg->data_bits == DATA_BITS_8) @@ -127,18 +62,8 @@ static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_c else if (cfg->stop_bits == STOP_BITS_2) USART_InitStructure.USART_StopBits = USART_StopBits_2; - if (cfg->parity == PARITY_NONE) - USART_InitStructure.USART_Parity = USART_Parity_No; - else if (cfg->parity == PARITY_EVEN) - USART_InitStructure.USART_Parity = USART_Parity_Even; - else if (cfg->parity == PARITY_ODD) - USART_InitStructure.USART_Parity = USART_Parity_Odd; - - if (cfg->hw_control == HW_CONTROL_NONE) - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; - else if (cfg->hw_control == HW_CONTROL_RTS_CTS) - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_RTS_CTS; - + USART_InitStructure.USART_Parity = USART_Parity_No; + USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(uart->uart_device, &USART_InitStructure); @@ -210,327 +135,180 @@ static const struct rt_uart_ops stm32_uart_ops = stm32_getc, }; -__STATIC_INLINE void serial_device_isr(struct rt_serial_device *serial) -{ - volatile int ch = 0; - struct stm32_uart *uart = serial->parent.user_data; - - /* process uart error */ - if(uart->uart_device->SR & (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE)) - { - ch = uart->uart_device->DR; // invalid read - while (uart->uart_device->SR & USART_FLAG_RXNE) - { - ch = uart->uart_device->DR; // invalid read - } - } - /* process usart receive */ - if (uart->uart_device->SR & USART_FLAG_RXNE) - { - rt_hw_serial_isr(serial);//auto clear interrupt flag - } - /* process usart send */ - if (uart->uart_device->SR & USART_IT_TC) - { - /* clear interrupt */ - uart->uart_device->SR = ~((uint16_t)0x01 << (uint16_t)(USART_IT_TC >> 0x08)); - } -} - #if defined(RT_USING_UART1) /* UART1 device driver structure */ struct serial_ringbuffer uart1_int_rx; -#define UART1_POOL_SIZE 64 -rt_uint8_t uart1_pool[UART1_POOL_SIZE]; struct stm32_uart uart1 = { USART1, USART1_IRQn, - - UART1_TX_PIN, - UART1_TX_GPIO, - UART1_RX_PIN, - UART1_RX_GPIO, - - UART1_CTS_PIN, - UART1_CTS_GPIO, - UART1_RTS_PIN, - UART1_RTS_GPIO, - - UART1_REMAP, }; struct rt_serial_device serial1; void USART1_IRQHandler(void) { + struct stm32_uart* uart; + + uart = &uart1; + /* enter interrupt */ rt_interrupt_enter(); + if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET) + { + rt_hw_serial_isr(&serial1); + /* clear interrupt */ + USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE); + } + if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET) + { + /* clear interrupt */ + USART_ClearITPendingBit(uart->uart_device, USART_IT_TC); + } - serial_device_isr(&serial1); - /* leave interrupt */ rt_interrupt_leave(); } #endif /* RT_USING_UART1 */ #if defined(RT_USING_UART2) -/* UART2 device driver structure */ +/* UART1 device driver structure */ struct serial_ringbuffer uart2_int_rx; -#define UART2_POOL_SIZE 64 -rt_uint8_t uart2_pool[UART2_POOL_SIZE]; struct stm32_uart uart2 = { USART2, USART2_IRQn, - - UART2_TX_PIN, - UART2_TX_GPIO, - UART2_RX_PIN, - UART2_RX_GPIO, - - UART2_CTS_PIN, - UART2_CTS_GPIO, - UART2_RTS_PIN, - UART2_RTS_GPIO, - - UART2_REMAP, - }; struct rt_serial_device serial2; void USART2_IRQHandler(void) { + struct stm32_uart* uart; + + uart = &uart2; + /* enter interrupt */ rt_interrupt_enter(); + if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET) + { + rt_hw_serial_isr(&serial2); + /* clear interrupt */ + USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE); + } + if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET) + { + /* clear interrupt */ + USART_ClearITPendingBit(uart->uart_device, USART_IT_TC); + } - serial_device_isr(&serial2); - /* leave interrupt */ rt_interrupt_leave(); } #endif /* RT_USING_UART2 */ #if defined(RT_USING_UART3) -/* UART3 device driver structure */ +/* UART1 device driver structure */ struct serial_ringbuffer uart3_int_rx; -#define UART3_POOL_SIZE 64 -rt_uint8_t uart3_pool[UART3_POOL_SIZE]; struct stm32_uart uart3 = { USART3, USART3_IRQn, - - UART3_TX_PIN, - UART3_TX_GPIO, - UART3_RX_PIN, - UART3_RX_GPIO, - - UART3_CTS_PIN, - UART3_CTS_GPIO, - UART3_RTS_PIN, - UART3_RTS_GPIO, - - UART3_REMAP, }; struct rt_serial_device serial3; void USART3_IRQHandler(void) { + struct stm32_uart* uart; + + uart = &uart3; + /* enter interrupt */ rt_interrupt_enter(); - - serial_device_isr(&serial3); + if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET) + { + rt_hw_serial_isr(&serial3); + /* clear interrupt */ + USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE); + } + if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET) + { + /* clear interrupt */ + USART_ClearITPendingBit(uart->uart_device, USART_IT_TC); + } /* leave interrupt */ rt_interrupt_leave(); } #endif /* RT_USING_UART3 */ -#if defined(RT_USING_UART4) -/* UART4 device driver structure */ -struct serial_ringbuffer uart4_int_rx; -#define UART4_POOL_SIZE 64 -rt_uint8_t uart4_pool[UART4_POOL_SIZE]; -struct stm32_uart uart4 = -{ - UART4, - UART4_IRQn, - - UART4_TX_PIN, - UART4_TX_GPIO, - UART4_RX_PIN, - UART4_RX_GPIO, - - UART4_CTS_PIN, - UART4_CTS_GPIO, - UART4_RTS_PIN, - UART4_RTS_GPIO, - - UART4_REMAP, -}; -struct rt_serial_device serial4; - -void UART4_IRQHandler(void) -{ - /* enter interrupt */ - rt_interrupt_enter(); - - serial_device_isr(&serial4); - - /* leave interrupt */ - rt_interrupt_leave(); -} -#endif /* RT_USING_UART4 */ - -#if defined(RT_USING_UART5) -/* UART5 device driver structure */ -struct serial_ringbuffer uart5_int_rx; -#define UART5_POOL_SIZE 64 -rt_uint8_t uart5_pool[UART5_POOL_SIZE]; -struct stm32_uart uart5 = -{ - UART5, - UART5_IRQn, - - UART5_TX_PIN, - UART5_TX_GPIO, - UART5_RX_PIN, - UART5_RX_GPIO, - - UART5_CTS_PIN, - UART5_CTS_GPIO, - UART5_RTS_PIN, - UART5_RTS_GPIO, - - UART5_REMAP, -}; -struct rt_serial_device serial5; - -void UART5_IRQHandler(void) -{ - /* enter interrupt */ - rt_interrupt_enter(); - - serial_device_isr(&serial5); - - /* leave interrupt */ - rt_interrupt_leave(); -} -#endif /* RT_USING_UART5 */ - -#define GPIO_RCC_ENABLE(x) \ -do{ \ - if (IS_GPIO_ALL_PERIPH(x)) \ - { \ - if ((x) == GPIOA) \ - { \ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); \ - } \ - if ((x) == GPIOB) \ - { \ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); \ - } \ - if ((x) == GPIOC) \ - { \ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); \ - } \ - if ((x) == GPIOD) \ - { \ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); \ - } \ - if ((x) == GPIOE) \ - { \ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); \ - } \ - if ((x) == GPIOF) \ - { \ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE); \ - } \ - if ((x) == GPIOG) \ - { \ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE); \ - } \ - } \ -}while(0) - -#define UART_RCC_ENABLE(x) \ -do{ \ - if (IS_USART_ALL_PERIPH(x)) \ - { \ - if ((x) == USART1) \ - { \ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); \ - } \ - if ((x) == USART2) \ - { \ - RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); \ - } \ - if ((x) == USART3) \ - { \ - RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); \ - } \ - if ((x) == UART4) \ - { \ - RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE); \ - } \ - if ((x) == UART5) \ - { \ - RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE); \ - } \ - } \ -}while(0) - -static void RCC_Configuration(struct stm32_uart* uart) +static void RCC_Configuration(void) { +#ifdef RT_USING_UART1 /* Enable UART GPIO clocks */ - GPIO_RCC_ENABLE(uart->uart_tx_gpio); - GPIO_RCC_ENABLE(uart->uart_rx_gpio); - GPIO_RCC_ENABLE(uart->uart_cts_gpio); - GPIO_RCC_ENABLE(uart->uart_rts_gpio); - /* Enable UART GPIO AF clocks */ - if (IS_GPIO_REMAP(uart->uart_remap)) - { - RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); - GPIO_PinRemapConfig(uart->uart_remap, ENABLE); - } + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /* Enable UART clock */ - UART_RCC_ENABLE(uart->uart_device); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); +#endif /* RT_USING_UART1 */ + +#ifdef RT_USING_UART2 + /* Enable UART GPIO clocks */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); + /* Enable UART clock */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); +#endif /* RT_USING_UART2 */ + +#ifdef RT_USING_UART3 + /* Enable UART GPIO clocks */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); + /* Enable UART clock */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); +#endif /* RT_USING_UART3 */ } -static void GPIO_Configuration(struct stm32_uart* uart) +static void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; + +#ifdef RT_USING_UART1 /* Configure USART Rx/tx PIN */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; - GPIO_InitStructure.GPIO_Pin = uart->uart_rx_pin; - GPIO_Init(uart->uart_rx_gpio, &GPIO_InitStructure); + GPIO_InitStructure.GPIO_Pin = UART1_GPIO_RX; + GPIO_Init(UART1_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; - GPIO_InitStructure.GPIO_Pin = uart->uart_tx_pin; - GPIO_Init(uart->uart_tx_gpio, &GPIO_InitStructure); - /* Configure USART RTS/CTS PIN */ - if (IS_GPIO_ALL_PERIPH(uart->uart_cts_gpio) && - IS_GPIO_ALL_PERIPH(uart->uart_rts_gpio) && - IS_GPIO_PIN(uart->uart_cts_pin) && - IS_GPIO_PIN(uart->uart_rts_pin)) - { - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; - GPIO_InitStructure.GPIO_Pin = uart->uart_cts_pin; - GPIO_Init(uart->uart_cts_gpio, &GPIO_InitStructure); + GPIO_InitStructure.GPIO_Pin = UART1_GPIO_TX; + GPIO_Init(UART1_GPIO, &GPIO_InitStructure); +#endif /* RT_USING_UART1 */ - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; - GPIO_InitStructure.GPIO_Pin = uart->uart_rts_pin; - GPIO_Init(uart->uart_rts_gpio, &GPIO_InitStructure); - } +#ifdef RT_USING_UART2 + /* Configure USART Rx/tx PIN */ + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; + GPIO_InitStructure.GPIO_Pin = UART2_GPIO_RX; + GPIO_Init(UART1_GPIO, &GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; + GPIO_InitStructure.GPIO_Pin = UART2_GPIO_TX; + GPIO_Init(UART2_GPIO, &GPIO_InitStructure); +#endif /* RT_USING_UART2 */ + +#ifdef RT_USING_UART3 + /* Configure USART Rx/tx PIN */ + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; + GPIO_InitStructure.GPIO_Pin = UART3_GPIO_RX; + GPIO_Init(UART3_GPIO, &GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; + GPIO_InitStructure.GPIO_Pin = UART3_GPIO_TX; + GPIO_Init(UART3_GPIO, &GPIO_InitStructure); +#endif /* RT_USING_UART3 */ } static void NVIC_Configuration(struct stm32_uart* uart) { NVIC_InitTypeDef NVIC_InitStructure; - /* Enable the USART Interrupt */ + /* Enable the USART1 Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = uart->irq; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; @@ -541,161 +319,57 @@ static void NVIC_Configuration(struct stm32_uart* uart) void rt_hw_usart_init(void) { struct stm32_uart* uart; - struct rt_serial_device *serial; struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; + RCC_Configuration(); + GPIO_Configuration(); + #ifdef RT_USING_UART1 uart = &uart1; - serial = &serial1; - - uart1_int_rx.pool = uart1_pool; - uart1_int_rx.size = UART1_POOL_SIZE; - config.baud_rate = BAUD_RATE_115200; - serial->ops = &stm32_uart_ops; - serial->int_rx = &uart1_int_rx; - serial->config = config; - - RCC_Configuration(uart); - GPIO_Configuration(uart); - NVIC_Configuration(uart); + serial1.ops = &stm32_uart_ops; + serial1.int_rx = &uart1_int_rx; + serial1.config = config; + + NVIC_Configuration(&uart1); /* register UART1 device */ - rt_hw_serial_register(serial, "uart1", + rt_hw_serial_register(&serial1, "uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, uart); #endif /* RT_USING_UART1 */ #ifdef RT_USING_UART2 uart = &uart2; - serial = &serial2; - - uart2_int_rx.pool = uart2_pool; - uart2_int_rx.size = UART2_POOL_SIZE; config.baud_rate = BAUD_RATE_115200; + serial2.ops = &stm32_uart_ops; + serial2.int_rx = &uart2_int_rx; + serial2.config = config; - serial->ops = &stm32_uart_ops; - serial->int_rx = &uart2_int_rx; - serial->config = config; - - RCC_Configuration(uart); - GPIO_Configuration(uart); - NVIC_Configuration(uart); + NVIC_Configuration(&uart2); - /* register UART2 device */ - rt_hw_serial_register(serial, "uart2", + /* register UART1 device */ + rt_hw_serial_register(&serial2, "uart2", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, uart); #endif /* RT_USING_UART2 */ #ifdef RT_USING_UART3 uart = &uart3; - serial = &serial3; - - uart3_int_rx.pool = uart3_pool; - uart3_int_rx.size = UART3_POOL_SIZE; config.baud_rate = BAUD_RATE_115200; - serial->ops = &stm32_uart_ops; - serial->int_rx = &uart3_int_rx; - serial->config = config; - - RCC_Configuration(uart); - GPIO_Configuration(uart); - NVIC_Configuration(uart); + serial3.ops = &stm32_uart_ops; + serial3.int_rx = &uart3_int_rx; + serial3.config = config; - /* register UART3 device */ - rt_hw_serial_register(serial, "uart3", + NVIC_Configuration(&uart3); + + /* register UART1 device */ + rt_hw_serial_register(&serial3, "uart3", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, uart); #endif /* RT_USING_UART3 */ - -#ifdef RT_USING_UART4 - uart = &uart4; - serial = &serial4; - - uart4_int_rx.pool = uart4_pool; - uart4_int_rx.size = UART4_POOL_SIZE; - - config.baud_rate = BAUD_RATE_115200; - - serial->ops = &stm32_uart_ops; - serial->int_rx = &uart4_int_rx; - serial->config = config; - - RCC_Configuration(uart); - GPIO_Configuration(uart); - NVIC_Configuration(uart); - - /* register UART4 device */ - rt_hw_serial_register(serial, "uart4", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, - uart); -#endif /* RT_USING_UART4 */ - -#ifdef RT_USING_UART5 - uart = &uart5; - serial = &serial5; - - uart5_int_rx.pool = uart5_pool; - uart5_int_rx.size = UART5_POOL_SIZE; - - config.baud_rate = BAUD_RATE_115200; - - serial->ops = &stm32_uart_ops; - serial->int_rx = &uart5_int_rx; - serial->config = config; - - RCC_Configuration(uart); - GPIO_Configuration(uart); - NVIC_Configuration(uart); - - /* register UART5 device */ - rt_hw_serial_register(serial, "uart5", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, - uart); -#endif /* RT_USING_UART5 */ } - - -/* uart device test */ -#ifdef RT_USING_FINSH -#include - -#if (defined(RT_USING_UART1) || defined(RT_USING_UART2) || defined(RT_USING_UART3) || defined(RT_USING_UART4) || defined(RT_USING_UART5)) -void uart_rw(const char *name, rt_int8_t cmd, const char *str) -{ - rt_device_t uart; - uart = rt_device_find(name); - if (uart != RT_NULL) - { - if (uart->open_flag == RT_DEVICE_OFLAG_CLOSE) - { - rt_device_open(uart, RT_DEVICE_OFLAG_RDWR); - } - if (cmd == 0) - { - rt_int8_t temp[20]; - memset(temp, '\0', 20); - rt_device_read(uart,0,(void *)temp,20); - rt_kprintf("%s", temp); - } - else - { - rt_kprintf("%s, %d", str, strlen(str)); - rt_device_write(uart,0,str,strlen(str)); - } - //rt_device_close(uart); - } - else - { - rt_kprintf("device %s is not exist!\n", name); - } -} -FINSH_FUNCTION_EXPORT(uart_rw, set uart[name 0 xxx] for read.) -#endif - -#endif diff --git a/components/drivers/include/drivers/serial.h b/components/drivers/include/drivers/serial.h index c966f5459b..41132ed916 100644 --- a/components/drivers/include/drivers/serial.h +++ b/components/drivers/include/drivers/serial.h @@ -29,7 +29,6 @@ #define __SERIAL_H__ #include -#include #define BAUD_RATE_4800 4800 #define BAUD_RATE_9600 9600 @@ -56,11 +55,6 @@ #define NRZ_NORMAL 0 /* Non Return to Zero : normal mode */ #define NRZ_INVERTED 1 /* Non Return to Zero : inverted mode */ -#define HW_CONTROL_NONE 0 -#define HW_CONTROL_RTS 1 -#define HW_CONTROL_CTS 2 -#define HW_CONTROL_RTS_CTS 3 - #ifndef RT_SERIAL_RB_BUFSZ #define RT_SERIAL_RB_BUFSZ 64 #endif @@ -81,23 +75,21 @@ #define RT_SERIAL_TX_DATAQUEUE_LWM 30 /* Default config for serial_configure structure */ -#define RT_SERIAL_CONFIG_DEFAULT \ -{ \ - BAUD_RATE_115200, /* 115200 bits/s */ \ - DATA_BITS_8, /* 8 databits */ \ - STOP_BITS_1, /* 1 stopbit */ \ - PARITY_NONE, /* No parity */ \ - BIT_ORDER_LSB, /* LSB first sent */ \ - NRZ_NORMAL, /* Normal mode */ \ - HW_CONTROL_NONE, /* Hardware control */\ - 0 \ +#define RT_SERIAL_CONFIG_DEFAULT \ +{ \ + BAUD_RATE_115200, /* 115200 bits/s */ \ + DATA_BITS_8, /* 8 databits */ \ + STOP_BITS_1, /* 1 stopbit */ \ + PARITY_NONE, /* No parity */ \ + BIT_ORDER_LSB, /* LSB first sent */ \ + NRZ_NORMAL, /* Normal mode */ \ + 0 \ } struct serial_ringbuffer { - struct rt_ringbuffer rb; - rt_uint8_t *pool; - rt_uint16_t size; + rt_uint8_t buffer[RT_SERIAL_RB_BUFSZ]; + rt_uint16_t put_index, get_index; }; struct serial_configure @@ -108,8 +100,7 @@ struct serial_configure rt_uint32_t parity :2; rt_uint32_t bit_order :1; rt_uint32_t invert :1; - rt_uint32_t hw_control :2; - rt_uint32_t reserved :18; + rt_uint32_t reserved :20; }; struct rt_serial_device diff --git a/components/drivers/serial/serial.c b/components/drivers/serial/serial.c index 9a356b6f0c..622d2cd68c 100644 --- a/components/drivers/serial/serial.c +++ b/components/drivers/serial/serial.c @@ -25,9 +25,6 @@ * 2012-11-23 bernard fix compiler warning. * 2013-02-20 bernard use RT_SERIAL_RB_BUFSZ to define * the size of ring buffer. - * 2014-02-26 bright use DeviceDriver ringbuffer. - * add hardware flow support. - * use new struct serial_ringbuffer. */ #include @@ -36,7 +33,9 @@ rt_inline void serial_ringbuffer_init(struct serial_ringbuffer *rbuffer) { - rt_ringbuffer_init(&rbuffer->rb, rbuffer->pool, rbuffer->size); + rt_memset(rbuffer->buffer, 0, sizeof(rbuffer->buffer)); + rbuffer->put_index = 0; + rbuffer->get_index = 0; } rt_inline void serial_ringbuffer_putc(struct serial_ringbuffer *rbuffer, @@ -46,8 +45,17 @@ rt_inline void serial_ringbuffer_putc(struct serial_ringbuffer *rbuffer, /* disable interrupt */ level = rt_hw_interrupt_disable(); - rt_ringbuffer_putchar(&rbuffer->rb, ch); - // enable interrupt + + rbuffer->buffer[rbuffer->put_index] = ch; + rbuffer->put_index = (rbuffer->put_index + 1) & (RT_SERIAL_RB_BUFSZ - 1); + + /* if the next position is read index, discard this 'read char' */ + if (rbuffer->put_index == rbuffer->get_index) + { + rbuffer->get_index = (rbuffer->get_index + 1) & (RT_SERIAL_RB_BUFSZ - 1); + } + + /* enable interrupt */ rt_hw_interrupt_enable(level); } @@ -55,11 +63,25 @@ rt_inline int serial_ringbuffer_putchar(struct serial_ringbuffer *rbuffer, char ch) { rt_base_t level; - //rt_uint16_t next_index; + rt_uint16_t next_index; /* disable interrupt */ level = rt_hw_interrupt_disable(); - rt_ringbuffer_putchar(&rbuffer->rb, ch); + + next_index = (rbuffer->put_index + 1) & (RT_SERIAL_RB_BUFSZ - 1); + if (next_index != rbuffer->get_index) + { + rbuffer->buffer[rbuffer->put_index] = ch; + rbuffer->put_index = next_index; + } + else + { + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + return -1; + } + /* enable interrupt */ rt_hw_interrupt_enable(level); @@ -68,14 +90,17 @@ rt_inline int serial_ringbuffer_putchar(struct serial_ringbuffer *rbuffer, rt_inline int serial_ringbuffer_getc(struct serial_ringbuffer *rbuffer) { - int ch = 0; + int ch; rt_base_t level; + ch = -1; /* disable interrupt */ level = rt_hw_interrupt_disable(); - /* get char */ - if (!rt_ringbuffer_getchar(&rbuffer->rb, (rt_uint8_t *)&ch)) - ch = -1; + if (rbuffer->get_index != rbuffer->put_index) + { + ch = rbuffer->buffer[rbuffer->get_index]; + rbuffer->get_index = (rbuffer->get_index + 1) & (RT_SERIAL_RB_BUFSZ - 1); + } /* enable interrupt */ rt_hw_interrupt_enable(level); @@ -88,10 +113,7 @@ rt_inline rt_uint32_t serial_ringbuffer_size(struct serial_ringbuffer *rbuffer) rt_base_t level; level = rt_hw_interrupt_disable(); - size = rt_ringbuffer_space_len(&rbuffer->rb); - /* size = (rbuffer->put_index - rbuffer->get_index) & (RT_SERIAL_RB_BUFSZ - 1); - */ rt_hw_interrupt_enable(level); return size; From 0fb9c54efda7fef4346523fdc4b92512a0441ee1 Mon Sep 17 00:00:00 2001 From: shaolin Date: Tue, 4 Mar 2014 08:59:53 +0800 Subject: [PATCH 42/59] 1.replace API prefix usb* with usbh* in USB host stack to distinct with USB device stack; 2.adjust some viable and micro name 3.some other small fix --- components/drivers/include/drivers/usb_host.h | 198 +++++++-------- components/drivers/usb/usbhost/SConscript | 18 +- components/drivers/usb/usbhost/class/adk.c | 191 ++++++++------- components/drivers/usb/usbhost/class/adk.h | 2 +- components/drivers/usb/usbhost/core/core.c | 139 ++++++----- components/drivers/usb/usbhost/core/driver.c | 20 +- components/drivers/usb/usbhost/core/hub.c | 229 +++++++++--------- components/drivers/usb/usbhost/core/usbhost.c | 62 +++-- 8 files changed, 419 insertions(+), 440 deletions(-) diff --git a/components/drivers/include/drivers/usb_host.h b/components/drivers/include/drivers/usb_host.h index a5a850d4cf..0e6c21432b 100644 --- a/components/drivers/include/drivers/usb_host.h +++ b/components/drivers/include/drivers/usb_host.h @@ -37,17 +37,17 @@ extern "C" { #define USB_HUB_PORT_NUM 0x04 #define SIZEOF_USB_REQUEST 0x08 -#define UINST_STATUS_IDLE 0x00 -#define UINST_STATUS_BUSY 0x01 -#define UINST_STATUS_ERROR 0x02 +#define DEV_STATUS_IDLE 0x00 +#define DEV_STATUS_BUSY 0x01 +#define DEV_STATUS_ERROR 0x02 #define UPIPE_STATUS_OK 0x00 #define UPIPE_STATUS_STALL 0x01 #define UPIPE_STATUS_ERROR 0x02 struct uhcd; -struct uifinst; -struct uhubinst; +struct uintf; +struct uhub; struct uclass_driver { @@ -55,8 +55,8 @@ struct uclass_driver int class_code; int subclass_code; - rt_err_t (*run)(void* arg); - rt_err_t (*stop)(void* arg); + rt_err_t (*enable)(void* arg); + rt_err_t (*disable)(void* arg); void* user_data; }; @@ -86,32 +86,31 @@ struct uinstance rt_uint8_t max_packet_size; rt_uint8_t port; - struct uhubinst* parent; - struct uifinst* ifinst[USB_MAX_INTERFACE]; + struct uhub* parent; + struct uintf* intf[USB_MAX_INTERFACE]; }; typedef struct uinstance* uinst_t; -struct uifinst +struct uintf { - uinst_t uinst; + struct uinstance* device; uintf_desc_t intf_desc; ucd_t drv; void *user_data; }; -typedef struct uifinst* uifinst_t; struct upipe { rt_uint32_t status; struct uendpoint_descriptor ep; - uifinst_t ifinst; + struct uintf* intf; func_callback callback; void* user_data; }; typedef struct upipe* upipe_t; -struct uhubinst +struct uhub { struct uhub_descriptor hub_desc; rt_uint8_t num_ports; @@ -122,19 +121,19 @@ struct uhubinst upipe_t pipe_in; rt_uint8_t buffer[8]; struct uinstance* self; - struct uhcd *hcd; + struct uhcd *hcd; }; -typedef struct uhubinst* uhubinst_t; +typedef struct uhub* uhub_t; struct uhcd_ops { - int (*ctl_xfer)(uinst_t inst, ureq_t setup, void* buffer, int nbytes, + int (*ctl_xfer)(struct uinstance* inst, ureq_t setup, void* buffer, int nbytes, int timeout); int (*bulk_xfer)(upipe_t pipe, void* buffer, int nbytes, int timeout); int (*int_xfer)(upipe_t pipe, void* buffer, int nbytes, int timeout); int (*iso_xfer)(upipe_t pipe, void* buffer, int nbytes, int timeout); - rt_err_t (*alloc_pipe)(struct upipe** pipe, uifinst_t ifinst, uep_desc_t ep, + rt_err_t (*alloc_pipe)(struct upipe** pipe, struct uintf* intf, uep_desc_t ep, func_callback callback); rt_err_t (*free_pipe)(upipe_t pipe); rt_err_t (*hub_ctrl)(rt_uint16_t port, rt_uint8_t cmd, void *args); @@ -144,6 +143,7 @@ struct uhcd { struct rt_device parent; struct uhcd_ops* ops; + struct uhub* roothub; }; typedef struct uhcd* uhcd_t; @@ -159,7 +159,7 @@ struct uhost_msg uhost_msg_type type; union { - struct uhubinst* uhub; + struct uhub* hub; struct { func_callback function; @@ -170,82 +170,67 @@ struct uhost_msg typedef struct uhost_msg* uhost_msg_t; /* usb host system interface */ -void rt_usb_host_init(void); -void rt_usb_hub_thread(void); +rt_err_t rt_usb_host_init(void); +void rt_usbh_hub_init(void); /* usb host core interface */ -uinst_t rt_usb_alloc_instance(void); -rt_err_t rt_usb_attatch_instance(uinst_t uinst); -rt_err_t rt_usb_detach_instance(uinst_t uinst); -rt_err_t rt_usb_get_descriptor(uinst_t uinst, - rt_uint8_t type, - void *buffer, - int nbytes); -rt_err_t rt_usb_set_configure(uinst_t uinst, int config); -rt_err_t rt_usb_set_address(uinst_t uinst); -rt_err_t rt_usb_set_interface(uinst_t uinst, int intf); -rt_err_t rt_usb_clear_feature(uinst_t uinst, int endpoint, int feature); -rt_err_t rt_usb_get_interface_descriptor(ucfg_desc_t cfg_desc, - int num, - uintf_desc_t *intf_desc); -rt_err_t rt_usb_get_endpoint_descriptor(uintf_desc_t intf_desc, - int num, - uep_desc_t *ep_desc); +struct uinstance* rt_usbh_alloc_instance(void); +rt_err_t rt_usbh_attatch_instance(struct uinstance* device); +rt_err_t rt_usbh_detach_instance(struct uinstance* device); +rt_err_t rt_usbh_get_descriptor(struct uinstance* device, rt_uint8_t type, void* buffer, + int nbytes); +rt_err_t rt_usbh_set_configure(struct uinstance* device, int config); +rt_err_t rt_usbh_set_address(struct uinstance* device); +rt_err_t rt_usbh_set_interface(struct uinstance* device, int intf); +rt_err_t rt_usbh_clear_feature(struct uinstance* device, int endpoint, int feature); +rt_err_t rt_usbh_get_interface_descriptor(ucfg_desc_t cfg_desc, int num, + uintf_desc_t* intf_desc); +rt_err_t rt_usbh_get_endpoint_descriptor(uintf_desc_t intf_desc, int num, + uep_desc_t* ep_desc); /* usb class driver interface */ -rt_err_t rt_usb_class_driver_init(void); -rt_err_t rt_usb_class_driver_register(ucd_t drv); -rt_err_t rt_usb_class_driver_unregister(ucd_t drv); -rt_err_t rt_usb_class_driver_run(ucd_t drv, void *args); -rt_err_t rt_usb_class_driver_stop(ucd_t drv, void *args); -ucd_t rt_usb_class_driver_find(int class_code, int subclass_code); +rt_err_t rt_usbh_class_driver_init(void); +rt_err_t rt_usbh_class_driver_register(ucd_t drv); +rt_err_t rt_usbh_class_driver_unregister(ucd_t drv); +rt_err_t rt_usbh_class_driver_enable(ucd_t drv, void* args); +rt_err_t rt_usbh_class_driver_disable(ucd_t drv, void* args); +ucd_t rt_usbh_class_driver_find(int class_code, int subclass_code); /* usb class driver implement */ -ucd_t rt_usb_class_driver_hid(void); -ucd_t rt_usb_class_driver_hub(void); -ucd_t rt_usb_class_driver_storage(void); -ucd_t rt_usb_class_driver_adk(void); +ucd_t rt_usbh_class_driver_hid(void); +ucd_t rt_usbh_class_driver_hub(void); +ucd_t rt_usbh_class_driver_storage(void); +ucd_t rt_usbh_class_driver_adk(void); /* usb hid protocal implement */ -uprotocal_t rt_usb_hid_protocal_kbd(void); -uprotocal_t rt_usb_hid_protocal_mouse(void); +uprotocal_t rt_usbh_hid_protocal_kbd(void); +uprotocal_t rt_usbh_hid_protocal_mouse(void); /* usb adk class driver interface */ -rt_err_t rt_usb_adk_set_string(const char *manufacturer, - const char *model, - const char *description, - const char *version, - const char *uri, - const char *serial); +rt_err_t rt_usbh_adk_set_string(const char* manufacturer, const char* model, + const char* description, const char* version, const char* uri, + const char* serial); /* usb hub interface */ -rt_err_t rt_usb_hub_get_descriptor(uinst_t uinst, - rt_uint8_t *buffer, - rt_size_t size); -rt_err_t rt_usb_hub_get_status(uinst_t uinst, rt_uint8_t *buffer); -rt_err_t rt_usb_hub_get_port_status(uhubinst_t uhub, - rt_uint16_t port, - rt_uint8_t *buffer); -rt_err_t rt_usb_hub_clear_port_feature(uhubinst_t uhub, - rt_uint16_t port, - rt_uint16_t feature); -rt_err_t rt_usb_hub_set_port_feature(uhubinst_t uhub, - rt_uint16_t port, - rt_uint16_t feature); -rt_err_t rt_usb_hub_reset_port(uhubinst_t uhub, rt_uint16_t port); -rt_err_t rt_usb_post_event(struct uhost_msg* msg, rt_size_t size); +rt_err_t rt_usbh_hub_get_descriptor(struct uinstance* device, rt_uint8_t *buffer, + rt_size_t size); +rt_err_t rt_usbh_hub_get_status(struct uinstance* device, rt_uint8_t* buffer); +rt_err_t rt_usbh_hub_get_port_status(uhub_t uhub, rt_uint16_t port, + rt_uint8_t* buffer); +rt_err_t rt_usbh_hub_clear_port_feature(uhub_t uhub, rt_uint16_t port, + rt_uint16_t feature); +rt_err_t rt_usbh_hub_set_port_feature(uhub_t uhub, rt_uint16_t port, + rt_uint16_t feature); +rt_err_t rt_usbh_hub_reset_port(uhub_t uhub, rt_uint16_t port); +rt_err_t rt_usbh_event_signal(struct uhost_msg* msg); /* usb host controller driver interface */ -rt_inline rt_err_t rt_usb_hcd_alloc_pipe(uhcd_t hcd, - upipe_t *pipe, - uifinst_t ifinst, - uep_desc_t ep, - func_callback callback) +rt_inline rt_err_t rt_usb_hcd_alloc_pipe(uhcd_t hcd, upipe_t* pipe, + struct uintf* intf, uep_desc_t ep, func_callback callback) { - if (ifinst == RT_NULL) - return -RT_EIO; + if(intf == RT_NULL) return -RT_EIO; - return hcd->ops->alloc_pipe(pipe, ifinst, ep, callback); + return hcd->ops->alloc_pipe(pipe, intf, ep, callback); } rt_inline rt_err_t rt_usb_hcd_free_pipe(uhcd_t hcd, upipe_t pipe) @@ -255,59 +240,40 @@ rt_inline rt_err_t rt_usb_hcd_free_pipe(uhcd_t hcd, upipe_t pipe) return hcd->ops->free_pipe(pipe); } -rt_inline int rt_usb_hcd_bulk_xfer(uhcd_t hcd, - upipe_t pipe, - void *buffer, - int nbytes, - int timeout) +rt_inline int rt_usb_hcd_bulk_xfer(uhcd_t hcd, upipe_t pipe, void* buffer, + int nbytes, int timeout) { - if (pipe == RT_NULL) - return -1; - if (pipe->ifinst == RT_NULL) - return -1; - if (pipe->ifinst->uinst == RT_NULL) - return -1; - if (pipe->ifinst->uinst->status == UINST_STATUS_IDLE) + if(pipe == RT_NULL) return -1; + if(pipe->intf == RT_NULL) return -1; + if(pipe->intf->device == RT_NULL) return -1; + if(pipe->intf->device->status == DEV_STATUS_IDLE) return -1; return hcd->ops->bulk_xfer(pipe, buffer, nbytes, timeout); } -rt_inline int rt_usb_hcd_control_xfer(uhcd_t hcd, - uinst_t uinst, - ureq_t setup, - void *buffer, - int nbytes, - int timeout) +rt_inline int rt_usb_hcd_control_xfer(uhcd_t hcd, struct uinstance* device, ureq_t setup, + void* buffer, int nbytes, int timeout) { - if (uinst->status == UINST_STATUS_IDLE) - return -1; + if(device->status == DEV_STATUS_IDLE) return -1; - return hcd->ops->ctl_xfer(uinst, setup, buffer, nbytes, timeout); + return hcd->ops->ctl_xfer(device, setup, buffer, nbytes, timeout); } -rt_inline int rt_usb_hcd_int_xfer(uhcd_t hcd, - upipe_t pipe, - void *buffer, - int nbytes, - int timeout) +rt_inline int rt_usb_hcd_int_xfer(uhcd_t hcd, upipe_t pipe, void* buffer, + int nbytes, int timeout) { - if (pipe == RT_NULL) - return -1; - if (pipe->ifinst == RT_NULL) - return -1; - if (pipe->ifinst->uinst == RT_NULL) - return -1; - if (pipe->ifinst->uinst->status == UINST_STATUS_IDLE) + if(pipe == RT_NULL) return -1; + if(pipe->intf == RT_NULL) return -1; + if(pipe->intf->device == RT_NULL) return -1; + if(pipe->intf->device->status == DEV_STATUS_IDLE) return -1; return hcd->ops->int_xfer(pipe, buffer, nbytes, timeout); } -rt_inline rt_err_t rt_usb_hcd_hub_control(uhcd_t hcd, - rt_uint16_t port, - rt_uint8_t cmd, - void *args) +rt_inline rt_err_t rt_usb_hcd_hub_control(uhcd_t hcd, rt_uint16_t port, + rt_uint8_t cmd, void *args) { return hcd->ops->hub_ctrl(port, cmd, args); } diff --git a/components/drivers/usb/usbhost/SConscript b/components/drivers/usb/usbhost/SConscript index 02e09f75df..32962b104e 100644 --- a/components/drivers/usb/usbhost/SConscript +++ b/components/drivers/usb/usbhost/SConscript @@ -9,22 +9,22 @@ core/usbhost.c core/hub.c """) -if GetDepend('RT_USB_CLASS_ADK'): +if GetDepend('RT_USBH_ADK'): src += Glob('class/adk.c') - src += Glob('udev/adkapp.c') + src += Glob('class/adkapp.c') -if GetDepend('RT_USB_CLASS_MASS_STORAGE'): +if GetDepend('RT_USBH_MSTORAGE'): src += Glob('class/mass.c') - src += Glob('udev/udisk.c') + src += Glob('class/udisk.c') -if GetDepend('RT_USB_CLASS_HID'): +if GetDepend('RT_USBH_HID'): src += Glob('class/hid.c') -if GetDepend('RT_USB_HID_MOUSE'): - src += Glob('udev/umouse.c') +if GetDepend('RT_USBH_HID_MOUSE'): + src += Glob('class/umouse.c') -if GetDepend('RT_USB_HID_KEYBOARD'): - src += Glob('udev/ukbd.c') +if GetDepend('RT_USBH_HID_KEYBOARD'): + src += Glob('class/ukbd.c') CPPPATH = [cwd, cwd + '/class', cwd + '/core', \ cwd + '/include', cwd + '../../../include'] diff --git a/components/drivers/usb/usbhost/class/adk.c b/components/drivers/usb/usbhost/class/adk.c index 0b470f6884..fd6619599c 100644 --- a/components/drivers/usb/usbhost/class/adk.c +++ b/components/drivers/usb/usbhost/class/adk.c @@ -26,7 +26,7 @@ #include #include "adk.h" -#ifdef RT_USB_CLASS_ADK +#ifdef RT_USBH_ADK static struct uclass_driver adk_driver; static const char* _adk_manufacturer = RT_NULL; @@ -36,7 +36,7 @@ static const char* _adk_version = RT_NULL; static const char* _adk_uri = RT_NULL; static const char* _adk_serial = RT_NULL; -rt_err_t rt_usb_adk_set_string(const char* manufacturer, const char* model, +rt_err_t rt_usbh_adk_set_string(const char* manufacturer, const char* model, const char* description, const char* _version, const char* uri, const char* serial) { @@ -53,29 +53,29 @@ rt_err_t rt_usb_adk_set_string(const char* manufacturer, const char* model, #ifdef RT_USING_MODULE #include -RTM_EXPORT(rt_usb_adk_set_string); +RTM_EXPORT(rt_usbh_adk_set_string); #endif /** * This function will do USB_REQ_GET_PROTOCOL request to set idle period to the usb adk device * - * @param ifinst the interface instance. + * @param intf the interface instance. * @duration the idle period of requesting data. * @report_id the report id * * @return the error code, RT_EOK on successfully. */ -static rt_err_t rt_usb_adk_get_protocol(uifinst_t ifinst, rt_uint16_t *protocol) +static rt_err_t rt_usbh_adk_get_protocol(struct uintf* intf, rt_uint16_t *protocol) { struct ureqest setup; - uinst_t uinst; + uinst_t device; int timeout = 100; /* parameter check */ - RT_ASSERT(ifinst != RT_NULL); - RT_ASSERT(ifinst->uinst != RT_NULL); + RT_ASSERT(intf != RT_NULL); + RT_ASSERT(intf->device != RT_NULL); - uinst = ifinst->uinst; + device = intf->device; setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE; @@ -84,7 +84,7 @@ static rt_err_t rt_usb_adk_get_protocol(uifinst_t ifinst, rt_uint16_t *protocol) setup.length = 2; setup.value = 0; - if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, (void*)protocol, 2, + if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, (void*)protocol, 2, timeout) == 0) return RT_EOK; else return -RT_FALSE; } @@ -92,24 +92,24 @@ static rt_err_t rt_usb_adk_get_protocol(uifinst_t ifinst, rt_uint16_t *protocol) /** * This function will do USB_REQ_SEND_STRING request to set idle period to the usb adk device * - * @param ifinst the interface instance. + * @param intf the interface instance. * @duration the idle period of requesting data. * @report_id the report id * * @return the error code, RT_EOK on successfully. */ -static rt_err_t rt_usb_adk_send_string(uifinst_t ifinst, rt_uint16_t index, +static rt_err_t rt_usbh_adk_send_string(struct uintf* intf, rt_uint16_t index, const char* str) { struct ureqest setup; - uinst_t uinst; + uinst_t device; int timeout = 100; /* parameter check */ - RT_ASSERT(ifinst != RT_NULL); - RT_ASSERT(ifinst->uinst != RT_NULL); + RT_ASSERT(intf != RT_NULL); + RT_ASSERT(intf->device != RT_NULL); - uinst = ifinst->uinst; + device = intf->device; setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE; @@ -118,7 +118,7 @@ static rt_err_t rt_usb_adk_send_string(uifinst_t ifinst, rt_uint16_t index, setup.length = rt_strlen(str) + 1; setup.value = 0; - if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, (void*)str, + if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, (void*)str, rt_strlen(str) + 1, timeout) == 0) return RT_EOK; else return -RT_FALSE; } @@ -126,23 +126,23 @@ static rt_err_t rt_usb_adk_send_string(uifinst_t ifinst, rt_uint16_t index, /** * This function will do USB_REQ_START request to set idle period to the usb adk device * - * @param ifinst the interface instance. + * @param intf the interface instance. * @duration the idle period of requesting data. * @report_id the report id * * @return the error code, RT_EOK on successfully. */ -static rt_err_t rt_usb_adk_start(uifinst_t ifinst) +static rt_err_t rt_usbh_adk_start(struct uintf* intf) { struct ureqest setup; - uinst_t uinst; + uinst_t device; int timeout = 100; /* parameter check */ - RT_ASSERT(ifinst != RT_NULL); - RT_ASSERT(ifinst->uinst != RT_NULL); + RT_ASSERT(intf != RT_NULL); + RT_ASSERT(intf->device != RT_NULL); - uinst = ifinst->uinst; + device = intf->device; setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE; @@ -151,7 +151,7 @@ static rt_err_t rt_usb_adk_start(uifinst_t ifinst) setup.length = 0; setup.value = 0; - if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, RT_NULL, 0, + if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, RT_NULL, 0, timeout) == 0) return RT_EOK; else return -RT_FALSE; } @@ -159,25 +159,25 @@ static rt_err_t rt_usb_adk_start(uifinst_t ifinst) /** * This function will read data from usb adk device * - * @param ifinst the interface instance. + * @param intf the interface instance. * * @return the error code, RT_EOK on successfully. */ -static rt_size_t rt_usb_adk_read(rt_device_t device, rt_off_t pos, void* buffer, +static rt_size_t rt_usbh_adk_read(rt_device_t device, rt_off_t pos, void* buffer, rt_size_t size) { - uadkinst_t adkinst; + uadk_t adk; rt_size_t length; - uifinst_t ifinst; + struct uintf* intf; /* check parameter */ RT_ASSERT(device != RT_NULL); RT_ASSERT(buffer != RT_NULL); - ifinst = (uifinst_t)device->user_data; - adkinst = (uadkinst_t)ifinst->user_data; + intf = (struct uintf*)device->user_data; + adk = (uadk_t)intf->user_data; - length = rt_usb_hcd_bulk_xfer(ifinst->uinst->hcd, adkinst->pipe_in, + length = rt_usb_hcd_bulk_xfer(intf->device->hcd, adk->pipe_in, buffer, size, 300); return length; @@ -187,23 +187,23 @@ static rt_size_t rt_usb_adk_read(rt_device_t device, rt_off_t pos, void* buffer, /** * This function will write data to usb adk device * - * @param ifinst the interface instance. + * @param intf the interface instance. * * @return the error code, RT_EOK on successfully. */ -static rt_size_t rt_usb_adk_write (rt_device_t device, rt_off_t pos, const void* buffer, +static rt_size_t rt_usbh_adk_write (rt_device_t device, rt_off_t pos, const void* buffer, rt_size_t size) { - uadkinst_t adkinst; + uadk_t adk; rt_size_t length; - uifinst_t ifinst; + struct uintf* intf; RT_ASSERT(buffer != RT_NULL); - ifinst = (uifinst_t)device->user_data; - adkinst = (uadkinst_t)ifinst->user_data; + intf = (struct uintf*)device->user_data; + adk = (uadk_t)intf->user_data; - length = rt_usb_hcd_bulk_xfer(ifinst->uinst->hcd, adkinst->pipe_out, + length = rt_usb_hcd_bulk_xfer(intf->device->hcd, adk->pipe_out, (void*)buffer, size, 300); return length; @@ -217,30 +217,30 @@ static rt_size_t rt_usb_adk_write (rt_device_t device, rt_off_t pos, const void* * * @return the error code, RT_EOK on successfully. */ -static rt_err_t rt_usb_adk_run(void* arg) +static rt_err_t rt_usbh_adk_enable(void* arg) { int i = 0; - uadkinst_t adkinst; - uifinst_t ifinst = (uifinst_t)arg; + uadk_t adk; + struct uintf* intf = (struct uintf*)arg; udev_desc_t dev_desc; rt_uint16_t protocol; rt_err_t ret; /* parameter check */ - if(ifinst == RT_NULL) + if(intf == RT_NULL) { rt_kprintf("the interface is not available\n"); return -RT_EIO; } - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usb_adk_run\n")); + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_adk_run\n")); - dev_desc = &ifinst->uinst->dev_desc; + dev_desc = &intf->device->dev_desc; if(dev_desc->idVendor == USB_ACCESSORY_VENDOR_ID && (dev_desc->idProduct == USB_ACCESSORY_PRODUCT_ID || dev_desc->idProduct == USB_ACCESSORY_ADB_PRODUCT_ID)) { - if(ifinst->intf_desc->bInterfaceSubClass != 0xFF) return -RT_ERROR; + if(intf->intf_desc->bInterfaceSubClass != 0xFF) return -RT_ERROR; RT_DEBUG_LOG(RT_DEBUG_USB, ("found android accessory device\n")); } @@ -248,9 +248,9 @@ static rt_err_t rt_usb_adk_run(void* arg) { RT_DEBUG_LOG(RT_DEBUG_USB, ("switch device\n")); - if((ret = rt_usb_adk_get_protocol(ifinst, &protocol)) != RT_EOK) + if((ret = rt_usbh_adk_get_protocol(intf, &protocol)) != RT_EOK) { - rt_kprintf("rt_usb_adk_get_protocol failed\n"); + rt_kprintf("rt_usbh_adk_get_protocol failed\n"); return ret; } @@ -260,17 +260,17 @@ static rt_err_t rt_usb_adk_run(void* arg) return -RT_ERROR; } - rt_usb_adk_send_string(ifinst, + rt_usbh_adk_send_string(intf, ACCESSORY_STRING_MANUFACTURER, _adk_manufacturer); - rt_usb_adk_send_string(ifinst, + rt_usbh_adk_send_string(intf, ACCESSORY_STRING_MODEL, _adk_model); - rt_usb_adk_send_string(ifinst, + rt_usbh_adk_send_string(intf, ACCESSORY_STRING_DESCRIPTION, _adk_description); - rt_usb_adk_send_string(ifinst, + rt_usbh_adk_send_string(intf, ACCESSORY_STRING_VERSION, _adk_version); - rt_usb_adk_send_string(ifinst, + rt_usbh_adk_send_string(intf, ACCESSORY_STRING_URI, _adk_uri); - rt_usb_adk_send_string(ifinst, + rt_usbh_adk_send_string(intf, ACCESSORY_STRING_SERIAL, _adk_serial); RT_DEBUG_LOG(RT_DEBUG_USB, ("manufacturer %s\n", _adk_manufacturer)); @@ -280,28 +280,28 @@ static rt_err_t rt_usb_adk_run(void* arg) RT_DEBUG_LOG(RT_DEBUG_USB, ("uri %s\n", _adk_uri)); RT_DEBUG_LOG(RT_DEBUG_USB, ("serial %s\n", _adk_serial)); - if((ret = rt_usb_adk_start(ifinst)) != RT_EOK) + if((ret = rt_usbh_adk_start(intf)) != RT_EOK) { - rt_kprintf("rt_usb_adk_start failed\n"); + rt_kprintf("rt_usbh_adk_start failed\n"); return ret; } return RT_EOK; } - adkinst = rt_malloc(sizeof(struct uadkinst)); - RT_ASSERT(adkinst != RT_NULL); + adk = rt_malloc(sizeof(struct uadkinst)); + RT_ASSERT(adk != RT_NULL); /* initilize the data structure */ - rt_memset(adkinst, 0, sizeof(struct uadkinst)); - ifinst->user_data = (void*)adkinst; + rt_memset(adk, 0, sizeof(struct uadkinst)); + intf->user_data = (void*)adk; - for(i=0; iintf_desc->bNumEndpoints; i++) + for(i=0; iintf_desc->bNumEndpoints; i++) { uep_desc_t ep_desc; /* get endpoint descriptor from interface descriptor */ - rt_usb_get_endpoint_descriptor(ifinst->intf_desc, i, &ep_desc); + rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc); if(ep_desc == RT_NULL) { rt_kprintf("rt_usb_get_endpoint_descriptor error\n"); @@ -316,41 +316,41 @@ static rt_err_t rt_usb_adk_run(void* arg) if(ep_desc->bEndpointAddress & USB_DIR_IN) { /* allocate an in pipe for the adk instance */ - ret = rt_usb_hcd_alloc_pipe(ifinst->uinst->hcd, &adkinst->pipe_in, - ifinst, ep_desc, RT_NULL); + ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &adk->pipe_in, + intf, ep_desc, RT_NULL); if(ret != RT_EOK) return ret; } else { /* allocate an output pipe for the adk instance */ - ret = rt_usb_hcd_alloc_pipe(ifinst->uinst->hcd, &adkinst->pipe_out, - ifinst, ep_desc, RT_NULL); + ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &adk->pipe_out, + intf, ep_desc, RT_NULL); if(ret != RT_EOK) return ret; } } /* check pipes infomation */ - if(adkinst->pipe_in == RT_NULL || adkinst->pipe_out == RT_NULL) + if(adk->pipe_in == RT_NULL || adk->pipe_out == RT_NULL) { rt_kprintf("pipe error, unsupported device\n"); return -RT_ERROR; } /* set configuration */ - ret = rt_usb_set_configure(ifinst->uinst, 1); + ret = rt_usbh_set_configure(intf->device, 1); if(ret != RT_EOK) return ret; /* register adk device */ - adkinst->device.type = RT_Device_Class_Char; - adkinst->device.init = RT_NULL; - adkinst->device.open = RT_NULL; - adkinst->device.close = RT_NULL; - adkinst->device.read = rt_usb_adk_read; - adkinst->device.write = rt_usb_adk_write; - adkinst->device.control = RT_NULL; - adkinst->device.user_data = (void*)ifinst; + adk->device.type = RT_Device_Class_Char; + adk->device.init = RT_NULL; + adk->device.open = RT_NULL; + adk->device.close = RT_NULL; + adk->device.read = rt_usbh_adk_read; + adk->device.write = rt_usbh_adk_write; + adk->device.control = RT_NULL; + adk->device.user_data = (void*)intf; - rt_device_register(&adkinst->device, "adkdev", RT_DEVICE_FLAG_RDWR); + rt_device_register(&adk->device, "adkdev", RT_DEVICE_FLAG_RDWR); return RT_EOK; } @@ -363,36 +363,39 @@ static rt_err_t rt_usb_adk_run(void* arg) * * @return the error code, RT_EOK on successfully. */ -static rt_err_t rt_usb_adk_stop(void* arg) +static rt_err_t rt_usbh_adk_disable(void* arg) { - uadkinst_t adkinst; - uifinst_t ifinst = (uifinst_t)arg; + uadk_t adk; + struct uintf* intf = (struct uintf*)arg; - RT_ASSERT(ifinst != RT_NULL); + RT_ASSERT(intf != RT_NULL); - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usb_adk_stop\n")); + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_adk_stop\n")); - adkinst = (uadkinst_t)ifinst->user_data; - if(adkinst == RT_NULL) + adk = (uadk_t)intf->user_data; + if(adk == RT_NULL) { - rt_free(ifinst); + rt_free(intf); return RT_EOK; } - if(adkinst->pipe_in != RT_NULL) - rt_usb_hcd_free_pipe(ifinst->uinst->hcd, adkinst->pipe_in); + if(adk->pipe_in != RT_NULL) + rt_usb_hcd_free_pipe(intf->device->hcd, adk->pipe_in); - if(adkinst->pipe_out != RT_NULL) - rt_usb_hcd_free_pipe(ifinst->uinst->hcd, adkinst->pipe_out); + if(adk->pipe_out != RT_NULL) + rt_usb_hcd_free_pipe(intf->device->hcd, adk->pipe_out); /* unregister adk device */ - rt_device_unregister(&adkinst->device); + rt_device_unregister(&adk->device); /* free adk instance */ - if(adkinst != RT_NULL) rt_free(adkinst); + if(adk != RT_NULL) + { + rt_free(adk); + } /* free interface instance */ - rt_free(ifinst); + rt_free(intf); return RT_EOK; } @@ -403,12 +406,12 @@ static rt_err_t rt_usb_adk_stop(void* arg) * * @return the error code, RT_EOK on successfully. */ -ucd_t rt_usb_class_driver_adk(void) +ucd_t rt_usbh_class_driver_adk(void) { adk_driver.class_code = USB_CLASS_ADK; - adk_driver.run = rt_usb_adk_run; - adk_driver.stop = rt_usb_adk_stop; + adk_driver.enable = rt_usbh_adk_enable; + adk_driver.disable = rt_usbh_adk_disable; return &adk_driver; } diff --git a/components/drivers/usb/usbhost/class/adk.h b/components/drivers/usb/usbhost/class/adk.h index 95140ceb7d..f08bea5f59 100644 --- a/components/drivers/usb/usbhost/class/adk.h +++ b/components/drivers/usb/usbhost/class/adk.h @@ -34,7 +34,7 @@ struct uadkinst struct rt_device device; }; -typedef struct uadkinst* uadkinst_t; +typedef struct uadkinst* uadk_t; #define USB_ACCESSORY_VENDOR_ID 0x18D1 #define USB_ACCESSORY_PRODUCT_ID 0x2D00 diff --git a/components/drivers/usb/usbhost/core/core.c b/components/drivers/usb/usbhost/core/core.c index e7da42f7e4..af53370f4b 100644 --- a/components/drivers/usb/usbhost/core/core.c +++ b/components/drivers/usb/usbhost/core/core.c @@ -25,7 +25,7 @@ #include #include -static struct uinstance uinst[USB_MAX_DEVICE]; +static struct uinstance dev[USB_MAX_DEVICE]; /** * This function will allocate an usb device instance from system. @@ -35,7 +35,7 @@ static struct uinstance uinst[USB_MAX_DEVICE]; * * @return the allocate instance on successful, or RT_NULL on failure. */ -uinst_t rt_usb_alloc_instance(void) +uinst_t rt_usbh_alloc_instance(void) { int i; @@ -45,19 +45,19 @@ uinst_t rt_usb_alloc_instance(void) for(i=0; idev_desc; + dev_desc = &device->dev_desc; RT_DEBUG_LOG(RT_DEBUG_USB, ("start enumnation\n")); /* get device descriptor head */ - ret = rt_usb_get_descriptor(uinst, USB_DESC_TYPE_DEVICE, (void*)dev_desc, 8); + ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_DEVICE, (void*)dev_desc, 8); if(ret != RT_EOK) { rt_kprintf("get device descriptor head failed\n"); @@ -100,7 +100,7 @@ rt_err_t rt_usb_attatch_instance(uinst_t uinst) } /* set device address */ - ret = rt_usb_set_address(uinst); + ret = rt_usbh_set_address(device); if(ret != RT_EOK) { rt_kprintf("set device address failed\n"); @@ -108,14 +108,14 @@ rt_err_t rt_usb_attatch_instance(uinst_t uinst) } /* set device max packet size */ - uinst->max_packet_size = uinst->dev_desc.bMaxPacketSize0; + device->max_packet_size = device->dev_desc.bMaxPacketSize0; RT_DEBUG_LOG(RT_DEBUG_USB, ("get device descriptor length %d\n", dev_desc->bLength)); /* get full device descriptor again */ - ret = rt_usb_get_descriptor - (uinst, USB_DESC_TYPE_DEVICE, (void*)dev_desc, dev_desc->bLength); + ret = rt_usbh_get_descriptor + (device, USB_DESC_TYPE_DEVICE, (void*)dev_desc, dev_desc->bLength); if(ret != RT_EOK) { rt_kprintf("get full device descriptor failed\n"); @@ -126,8 +126,7 @@ rt_err_t rt_usb_attatch_instance(uinst_t uinst) RT_DEBUG_LOG(RT_DEBUG_USB, ("Product ID 0x%x\n", dev_desc->idProduct)); /* get configuration descriptor head */ - ret = rt_usb_get_descriptor(uinst, USB_DESC_TYPE_CONFIGURATION, &cfg_desc, - sizeof(struct uconfig_descriptor)); + ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_CONFIGURATION, &cfg_desc, 18); if(ret != RT_EOK) { rt_kprintf("get configuration descriptor head failed\n"); @@ -135,12 +134,12 @@ rt_err_t rt_usb_attatch_instance(uinst_t uinst) } /* alloc memory for configuration descriptor */ - uinst->cfg_desc = (ucfg_desc_t)rt_malloc(cfg_desc.wTotalLength); - rt_memset(uinst->cfg_desc, 0, cfg_desc.wTotalLength); + device->cfg_desc = (ucfg_desc_t)rt_malloc(cfg_desc.wTotalLength); + rt_memset(device->cfg_desc, 0, cfg_desc.wTotalLength); /* get full configuration descriptor */ - ret = rt_usb_get_descriptor(uinst, USB_DESC_TYPE_CONFIGURATION, - uinst->cfg_desc, cfg_desc.wTotalLength); + ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_CONFIGURATION, + device->cfg_desc, cfg_desc.wTotalLength); if(ret != RT_EOK) { rt_kprintf("get full configuration descriptor failed\n"); @@ -148,13 +147,13 @@ rt_err_t rt_usb_attatch_instance(uinst_t uinst) } /* set configuration */ - ret = rt_usb_set_configure(uinst, 1); + ret = rt_usbh_set_configure(device, 1); if(ret != RT_EOK) return ret; - for(i=0; icfg_desc->bNumInterfaces; i++) + for(i=0; icfg_desc->bNumInterfaces; i++) { /* get interface descriptor through configuration descriptor */ - ret = rt_usb_get_interface_descriptor(uinst->cfg_desc, i, &intf_desc); + ret = rt_usbh_get_interface_descriptor(device->cfg_desc, i, &intf_desc); if(ret != RT_EOK) { rt_kprintf("rt_usb_get_interface_descriptor error\n"); @@ -166,22 +165,22 @@ rt_err_t rt_usb_attatch_instance(uinst_t uinst) intf_desc->bInterfaceSubClass)); /* find driver by class code found in interface descriptor */ - drv = rt_usb_class_driver_find(intf_desc->bInterfaceClass, + drv = rt_usbh_class_driver_find(intf_desc->bInterfaceClass, intf_desc->bInterfaceSubClass); if(drv != RT_NULL) { - /* allocate memory for interface uinst */ - uinst->ifinst[i] = - (uifinst_t)rt_malloc(sizeof(struct uifinst)); + /* allocate memory for interface device */ + device->intf[i] = + (struct uintf*)rt_malloc(sizeof(struct uintf)); - uinst->ifinst[i]->drv = drv; - uinst->ifinst[i]->uinst = uinst; - uinst->ifinst[i]->intf_desc = intf_desc; - uinst->ifinst[i]->user_data = RT_NULL; + device->intf[i]->drv = drv; + device->intf[i]->device = device; + device->intf[i]->intf_desc = intf_desc; + device->intf[i]->user_data = RT_NULL; /* open usb class driver */ - ret = rt_usb_class_driver_run(drv, (void*)uinst->ifinst[i]); + ret = rt_usbh_class_driver_enable(drv, (void*)device->intf[i]); if(ret != RT_EOK) { rt_kprintf("interface %d run class driver error\n", i); @@ -201,35 +200,35 @@ rt_err_t rt_usb_attatch_instance(uinst_t uinst) * This function will detach an usb device instance from its host controller, * and release all resource. * - * @param uinst the usb device instance. + * @param device the usb device instance. * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_detach_instance(uinst_t uinst) +rt_err_t rt_usbh_detach_instance(uinst_t device) { int i = 0; - if(uinst == RT_NULL) + if(device == RT_NULL) { rt_kprintf("no usb instance to detach\n"); return -RT_ERROR; } /* free configration descriptor */ - if(uinst->cfg_desc) rt_free(uinst->cfg_desc); + if(device->cfg_desc) rt_free(device->cfg_desc); - for(i=0; icfg_desc->bNumInterfaces; i++) + for(i=0; icfg_desc->bNumInterfaces; i++) { - if(uinst->ifinst[i] == RT_NULL) continue; - if(uinst->ifinst[i]->drv == RT_NULL) continue; + if(device->intf[i] == RT_NULL) continue; + if(device->intf[i]->drv == RT_NULL) continue; - RT_ASSERT(uinst->ifinst[i]->uinst == uinst); + RT_ASSERT(device->intf[i]->device == device); RT_DEBUG_LOG(RT_DEBUG_USB, ("free interface instance %d\n", i)); - rt_usb_class_driver_stop(uinst->ifinst[i]->drv, (void*)uinst->ifinst[i]); + rt_usbh_class_driver_disable(device->intf[i]->drv, (void*)device->intf[i]); } - rt_memset(uinst, 0, sizeof(struct uinstance)); + rt_memset(device, 0, sizeof(struct uinstance)); return RT_EOK; } @@ -237,20 +236,20 @@ rt_err_t rt_usb_detach_instance(uinst_t uinst) /** * This function will do USB_REQ_GET_DESCRIPTO' request for the usb device instance, * - * @param uinst the usb device instance. + * @param device the usb device instance. * @param type the type of descriptor request. * @param buffer the data buffer to save requested data * @param nbytes the size of buffer * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_get_descriptor(uinst_t uinst, rt_uint8_t type, void* buffer, +rt_err_t rt_usbh_get_descriptor(uinst_t device, rt_uint8_t type, void* buffer, int nbytes) { struct ureqest setup; int timeout = 100; - RT_ASSERT(uinst != RT_NULL); + RT_ASSERT(device != RT_NULL); setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE; @@ -259,7 +258,7 @@ rt_err_t rt_usb_get_descriptor(uinst_t uinst, rt_uint8_t type, void* buffer, setup.length = nbytes; setup.value = type << 8; - if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, buffer, nbytes, + if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, buffer, nbytes, timeout) != nbytes) return -RT_EIO; else return RT_EOK; } @@ -267,16 +266,16 @@ rt_err_t rt_usb_get_descriptor(uinst_t uinst, rt_uint8_t type, void* buffer, /** * This function will set an address to the usb device. * - * @param uinst the usb device instance. + * @param device the usb device instance. * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_set_address(uinst_t uinst) +rt_err_t rt_usbh_set_address(uinst_t device) { struct ureqest setup; int timeout = 100; - RT_ASSERT(uinst != RT_NULL); + RT_ASSERT(device != RT_NULL); RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usb_set_address\n")); @@ -285,14 +284,14 @@ rt_err_t rt_usb_set_address(uinst_t uinst) setup.request = USB_REQ_SET_ADDRESS; setup.index = 0; setup.length = 0; - setup.value = uinst->index; + setup.value = device->index; - if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, RT_NULL, 0, + if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, RT_NULL, 0, timeout) != 0) return -RT_EIO; rt_thread_delay(50); - uinst->address = uinst->index; + device->address = device->index; return RT_EOK; } @@ -300,18 +299,18 @@ rt_err_t rt_usb_set_address(uinst_t uinst) /** * This function will set a configuration to the usb device. * - * @param uinst the usb device instance. + * @param device the usb device instance. * @param config the configuration number. * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_set_configure(uinst_t uinst, int config) +rt_err_t rt_usbh_set_configure(uinst_t device, int config) { struct ureqest setup; int timeout = 100; /* check parameter */ - RT_ASSERT(uinst != RT_NULL); + RT_ASSERT(device != RT_NULL); setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE; @@ -320,7 +319,7 @@ rt_err_t rt_usb_set_configure(uinst_t uinst, int config) setup.length = 0; setup.value = config; - if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, RT_NULL, 0, + if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, RT_NULL, 0, timeout) != 0) return -RT_EIO; return RT_EOK; @@ -329,18 +328,18 @@ rt_err_t rt_usb_set_configure(uinst_t uinst, int config) /** * This function will set an interface to the usb device. * - * @param uinst the usb device instance. + * @param device the usb device instance. * @param intf the interface number. * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_set_interface(uinst_t uinst, int intf) +rt_err_t rt_usbh_set_interface(uinst_t device, int intf) { struct ureqest setup; int timeout = 100; /* check parameter */ - RT_ASSERT(uinst != RT_NULL); + RT_ASSERT(device != RT_NULL); setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE; @@ -349,7 +348,7 @@ rt_err_t rt_usb_set_interface(uinst_t uinst, int intf) setup.length = 0; setup.value = intf; - if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, RT_NULL, 0, + if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, RT_NULL, 0, timeout) != 0) return -RT_EIO; return RT_EOK; @@ -358,18 +357,18 @@ rt_err_t rt_usb_set_interface(uinst_t uinst, int intf) /** * This function will clear feature for the endpoint of the usb device. * - * @param uinst the usb device instance. + * @param device the usb device instance. * @param endpoint the endpoint number of the usb device. * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_clear_feature(uinst_t uinst, int endpoint, int feature) +rt_err_t rt_usbh_clear_feature(uinst_t device, int endpoint, int feature) { struct ureqest setup; int timeout = 100; /* check parameter */ - RT_ASSERT(uinst != RT_NULL); + RT_ASSERT(device != RT_NULL); setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_ENDPOINT; @@ -378,7 +377,7 @@ rt_err_t rt_usb_clear_feature(uinst_t uinst, int endpoint, int feature) setup.length = 0; setup.value = feature; - if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, RT_NULL, 0, + if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, RT_NULL, 0, timeout) != 0) return -RT_EIO; return RT_EOK; @@ -393,7 +392,7 @@ rt_err_t rt_usb_clear_feature(uinst_t uinst, int endpoint, int feature) * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_get_interface_descriptor(ucfg_desc_t cfg_desc, int num, +rt_err_t rt_usbh_get_interface_descriptor(ucfg_desc_t cfg_desc, int num, uintf_desc_t* intf_desc) { rt_uint32_t ptr, depth = 0; @@ -438,7 +437,7 @@ rt_err_t rt_usb_get_interface_descriptor(ucfg_desc_t cfg_desc, int num, * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_get_endpoint_descriptor(uintf_desc_t intf_desc, int num, +rt_err_t rt_usbh_get_endpoint_descriptor(uintf_desc_t intf_desc, int num, uep_desc_t* ep_desc) { int count = 0, depth = 0; diff --git a/components/drivers/usb/usbhost/core/driver.c b/components/drivers/usb/usbhost/core/driver.c index 52457d7cfc..165e343093 100644 --- a/components/drivers/usb/usbhost/core/driver.c +++ b/components/drivers/usb/usbhost/core/driver.c @@ -34,7 +34,7 @@ static rt_list_t _driver_list; * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_class_driver_init(void) +rt_err_t rt_usbh_class_driver_init(void) { rt_list_init(&_driver_list); @@ -49,7 +49,7 @@ rt_err_t rt_usb_class_driver_init(void) * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_class_driver_register(ucd_t drv) +rt_err_t rt_usbh_class_driver_register(ucd_t drv) { if (drv == RT_NULL) return -RT_ERROR; @@ -66,7 +66,7 @@ rt_err_t rt_usb_class_driver_register(ucd_t drv) * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_class_driver_unregister(ucd_t drv) +rt_err_t rt_usbh_class_driver_unregister(ucd_t drv) { RT_ASSERT(drv != RT_NULL); @@ -84,12 +84,12 @@ rt_err_t rt_usb_class_driver_unregister(ucd_t drv) * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_class_driver_run(ucd_t drv, void* args) +rt_err_t rt_usbh_class_driver_enable(ucd_t drv, void* args) { RT_ASSERT(drv != RT_NULL); - if(drv->run != RT_NULL) - drv->run(args); + if(drv->enable != RT_NULL) + drv->enable(args); return RT_EOK; } @@ -102,12 +102,12 @@ rt_err_t rt_usb_class_driver_run(ucd_t drv, void* args) * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_class_driver_stop(ucd_t drv, void* args) +rt_err_t rt_usbh_class_driver_disable(ucd_t drv, void* args) { RT_ASSERT(drv != RT_NULL); - if(drv->stop != RT_NULL) - drv->stop(args); + if(drv->disable != RT_NULL) + drv->disable(args); return RT_EOK; } @@ -121,7 +121,7 @@ rt_err_t rt_usb_class_driver_stop(ucd_t drv, void* args) * * @return the registered usb class driver on successful, or RT_NULL on failure. */ -ucd_t rt_usb_class_driver_find(int class_code, int subclass_code) +ucd_t rt_usbh_class_driver_find(int class_code, int subclass_code) { struct rt_list_node *node; diff --git a/components/drivers/usb/usbhost/core/hub.c b/components/drivers/usb/usbhost/core/hub.c index c907defcf6..a71aa4f89c 100644 --- a/components/drivers/usb/usbhost/core/hub.c +++ b/components/drivers/usb/usbhost/core/hub.c @@ -34,20 +34,20 @@ static struct uclass_driver hub_driver; * This function will do USB_REQ_GET_DESCRIPTOR request for the device instance * to get usb hub descriptor. * - * @param ifinst the interface instance. + * @param intf the interface instance. * @buffer the data buffer to save usb hub descriptor. * @param nbytes the size of buffer * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_hub_get_descriptor(uinst_t uinst, rt_uint8_t *buffer, +rt_err_t rt_usbh_hub_get_descriptor(struct uinstance* device, rt_uint8_t *buffer, rt_size_t nbytes) { struct ureqest setup; int timeout = 100; /* parameter check */ - RT_ASSERT(uinst != RT_NULL); + RT_ASSERT(device != RT_NULL); setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE; @@ -56,7 +56,7 @@ rt_err_t rt_usb_hub_get_descriptor(uinst_t uinst, rt_uint8_t *buffer, setup.length = nbytes; setup.value = USB_DESC_TYPE_HUB << 8; - if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, buffer, nbytes, + if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, buffer, nbytes, timeout) == nbytes) return RT_EOK; else return -RT_FALSE; } @@ -65,19 +65,19 @@ rt_err_t rt_usb_hub_get_descriptor(uinst_t uinst, rt_uint8_t *buffer, * This function will do USB_REQ_GET_STATUS request for the device instance * to get usb hub status. * - * @param ifinst the interface instance. + * @param intf the interface instance. * @buffer the data buffer to save usb hub status. * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_hub_get_status(uinst_t uinst, rt_uint8_t* buffer) +rt_err_t rt_usbh_hub_get_status(struct uinstance* device, rt_uint8_t* buffer) { struct ureqest setup; int timeout = 100; int length = 4; /* parameter check */ - RT_ASSERT(uinst != RT_NULL); + RT_ASSERT(device != RT_NULL); setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE; @@ -86,7 +86,7 @@ rt_err_t rt_usb_hub_get_status(uinst_t uinst, rt_uint8_t* buffer) setup.length = length; setup.value = 0; - if(rt_usb_hcd_control_xfer(uinst->hcd, uinst, &setup, buffer, length, + if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, buffer, length, timeout) == length) return RT_EOK; else return -RT_FALSE; } @@ -95,13 +95,13 @@ rt_err_t rt_usb_hub_get_status(uinst_t uinst, rt_uint8_t* buffer) * This function will do USB_REQ_GET_STATUS request for the device instance * to get hub port status. * - * @param ifinst the interface instance. + * @param intf the interface instance. * @port the hub port to get status. * @buffer the data buffer to save usb hub status. * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_hub_get_port_status(uhubinst_t uhub, rt_uint16_t port, +rt_err_t rt_usbh_hub_get_port_status(uhub_t hub, rt_uint16_t port, rt_uint8_t* buffer) { struct ureqest setup; @@ -109,12 +109,12 @@ rt_err_t rt_usb_hub_get_port_status(uhubinst_t uhub, rt_uint16_t port, int length = 4; /* parameter check */ - RT_ASSERT(uhub != RT_NULL); + RT_ASSERT(hub != RT_NULL); /* get roothub port status */ - if(uhub->is_roothub) + if(hub->is_roothub) { - rt_usb_hcd_hub_control(uhub->hcd, port, RH_GET_PORT_STATUS, + rt_usb_hcd_hub_control(hub->hcd, port, RH_GET_PORT_STATUS, (void*)buffer); return RT_EOK; } @@ -126,7 +126,7 @@ rt_err_t rt_usb_hub_get_port_status(uhubinst_t uhub, rt_uint16_t port, setup.length = 4; setup.value = 0; - if(rt_usb_hcd_control_xfer(uhub->hcd, uhub->self, &setup, buffer, + if(rt_usb_hcd_control_xfer(hub->hcd, hub->self, &setup, buffer, length, timeout) == timeout) return RT_EOK; else return -RT_FALSE; } @@ -135,25 +135,25 @@ rt_err_t rt_usb_hub_get_port_status(uhubinst_t uhub, rt_uint16_t port, * This function will do USB_REQ_CLEAR_FEATURE request for the device instance * to clear feature of the hub port. * - * @param ifinst the interface instance. + * @param intf the interface instance. * @port the hub port. * @feature feature to be cleared. * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_hub_clear_port_feature(uhubinst_t uhub, rt_uint16_t port, +rt_err_t rt_usbh_hub_clear_port_feature(uhub_t hub, rt_uint16_t port, rt_uint16_t feature) { struct ureqest setup; int timeout = 100; /* parameter check */ - RT_ASSERT(uhub != RT_NULL); + RT_ASSERT(hub != RT_NULL); /* clear roothub feature */ - if(uhub->is_roothub) + if(hub->is_roothub) { - rt_usb_hcd_hub_control(uhub->hcd, port, RH_CLEAR_PORT_FEATURE, + rt_usb_hcd_hub_control(hub->hcd, port, RH_CLEAR_PORT_FEATURE, (void*)feature); return RT_EOK; } @@ -165,7 +165,7 @@ rt_err_t rt_usb_hub_clear_port_feature(uhubinst_t uhub, rt_uint16_t port, setup.length = 0; setup.value = feature; - if(rt_usb_hcd_control_xfer(uhub->hcd, uhub->self, &setup, RT_NULL, 0, + if(rt_usb_hcd_control_xfer(hub->hcd, hub->self, &setup, RT_NULL, 0, timeout) == 0) return RT_EOK; else return -RT_FALSE; } @@ -174,25 +174,25 @@ rt_err_t rt_usb_hub_clear_port_feature(uhubinst_t uhub, rt_uint16_t port, * This function will do USB_REQ_SET_FEATURE request for the device instance * to set feature of the hub port. * - * @param ifinst the interface instance. + * @param intf the interface instance. * @port the hub port. * @feature feature to be set. * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_hub_set_port_feature(uhubinst_t uhub, rt_uint16_t port, +rt_err_t rt_usbh_hub_set_port_feature(uhub_t hub, rt_uint16_t port, rt_uint16_t feature) { struct ureqest setup; int timeout = 100; /* parameter check */ - RT_ASSERT(uhub != RT_NULL); + RT_ASSERT(hub != RT_NULL); /* clear roothub feature */ - if(uhub->is_roothub) + if(hub->is_roothub) { - rt_usb_hcd_hub_control(uhub->hcd, port, RH_SET_PORT_FEATURE, + rt_usb_hcd_hub_control(hub->hcd, port, RH_SET_PORT_FEATURE, (void*)feature); return RT_EOK; } @@ -204,7 +204,7 @@ rt_err_t rt_usb_hub_set_port_feature(uhubinst_t uhub, rt_uint16_t port, setup.length = 0; setup.value = feature; - if(rt_usb_hcd_control_xfer(uhub->hcd, uhub->self, &setup, RT_NULL, 0, + if(rt_usb_hcd_control_xfer(hub->hcd, hub->self, &setup, RT_NULL, 0, timeout) == 0) return RT_EOK; else return -RT_FALSE; } @@ -212,33 +212,33 @@ rt_err_t rt_usb_hub_set_port_feature(uhubinst_t uhub, rt_uint16_t port, /** * This function will rest hub port, it is invoked when sub device attached to the hub port. * - * @param ifinst the interface instance. + * @param intf the interface instance. * @param port the hub port. * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_hub_reset_port(uhubinst_t uhub, rt_uint16_t port) +rt_err_t rt_usbh_hub_reset_port(uhub_t hub, rt_uint16_t port) { rt_err_t ret; rt_uint32_t pstatus; /* parameter check */ - RT_ASSERT(uhub != RT_NULL); + RT_ASSERT(hub != RT_NULL); rt_thread_delay(50); /* reset hub port */ - ret = rt_usb_hub_set_port_feature(uhub, port, PORT_FEAT_RESET); + ret = rt_usbh_hub_set_port_feature(hub, port, PORT_FEAT_RESET); if(ret != RT_EOK) return ret; while(1) { - ret = rt_usb_hub_get_port_status(uhub, port, (rt_uint8_t*)&pstatus); + ret = rt_usbh_hub_get_port_status(hub, port, (rt_uint8_t*)&pstatus); if(!(pstatus & PORT_PRS)) break; } /* clear port reset feature */ - ret = rt_usb_hub_clear_port_feature(uhub, port, PORT_FEAT_C_RESET); + ret = rt_usbh_hub_clear_port_feature(hub, port, PORT_FEAT_C_RESET); if(ret != RT_EOK) return ret; rt_thread_delay(50); @@ -249,12 +249,12 @@ rt_err_t rt_usb_hub_reset_port(uhubinst_t uhub, rt_uint16_t port) /** * This function will do debouce, it is invoked when sub device attached to the hub port. * - * @param uinst the usb instance. + * @param device the usb instance. * @param port the hub port. * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_hub_port_debounce(uhubinst_t uhub, rt_uint16_t port) +rt_err_t rt_usbh_hub_port_debounce(uhub_t hub, rt_uint16_t port) { rt_err_t ret; int i = 0, times = 20; @@ -262,11 +262,11 @@ rt_err_t rt_usb_hub_port_debounce(uhubinst_t uhub, rt_uint16_t port) rt_bool_t connect = RT_TRUE; /* parameter check */ - RT_ASSERT(uhub != RT_NULL); + RT_ASSERT(hub != RT_NULL); for(i=0; inum_ports; i++) + for (i = 0; i < hub->num_ports; i++) { rt_err_t ret; - uinst_t uinst; + struct uinstance* device; rt_uint32_t pstatus = 0; reconnect = RT_FALSE; /* get hub port status */ - ret = rt_usb_hub_get_port_status(uhub, i + 1, (rt_uint8_t*)&pstatus); + ret = rt_usbh_hub_get_port_status(hub, i + 1, (rt_uint8_t*)&pstatus); if(ret != RT_EOK) continue; - RT_DEBUG_LOG(RT_DEBUG_USB, ("port_status 0x%x\n", pstatus)); + RT_DEBUG_LOG(RT_DEBUG_USB, ("port %d status 0x%x\n", i, pstatus)); /* check port status change */ if ((pstatus & PORT_CCSC)) { /* clear port status change feature */ - rt_usb_hub_clear_port_feature(uhub, i + 1, PORT_FEAT_C_CONNECTION); + rt_usbh_hub_clear_port_feature(hub, i + 1, PORT_FEAT_C_CONNECTION); reconnect = RT_TRUE; } if(pstatus & PORT_PESC) { - rt_usb_hub_clear_port_feature(uhub, i + 1, PORT_FEAT_C_ENABLE); + rt_usbh_hub_clear_port_feature(hub, i + 1, PORT_FEAT_C_ENABLE); reconnect = RT_TRUE; } if(reconnect) { - if(uhub->child[i]->status != UINST_STATUS_IDLE) - rt_usb_detach_instance(uhub->child[i]); + if(hub->child[i]->status != DEV_STATUS_IDLE) + rt_usbh_detach_instance(hub->child[i]); - ret = rt_usb_hub_port_debounce(uhub, i + 1); + ret = rt_usbh_hub_port_debounce(hub, i + 1); if(ret != RT_EOK) continue; /* allocate an usb instance for new connected device */ - uinst = rt_usb_alloc_instance(); - if(uinst == RT_NULL) break; + device = rt_usbh_alloc_instance(); + if(device == RT_NULL) break; /* set usb device speed */ - uinst->speed = (pstatus & PORT_LSDA) ? 1 : 0; - uinst->parent = uhub; - uinst->hcd = uhub->hcd; - uhub->child[i] = uinst; + device->speed = (pstatus & PORT_LSDA) ? 1 : 0; + device->parent = hub; + device->hcd = hub->hcd; + hub->child[i] = device; /* reset usb roothub port */ - rt_usb_hub_reset_port(uhub, i + 1); + rt_usbh_hub_reset_port(hub, i + 1); /* attatch the usb instance to the hcd */ - rt_usb_attatch_instance(uinst); + rt_usbh_attatch_instance(device); } } @@ -363,18 +363,18 @@ static rt_err_t rt_usb_hub_port_change(uhubinst_t uhub) * * @return none. */ -static void rt_usb_hub_irq(void* context) +static void rt_usbh_hub_irq(void* context) { upipe_t pipe; - uifinst_t ifinst; - uhubinst_t uhub; + struct uintf* intf; + uhub_t hub; int timeout = 100; RT_ASSERT(context != RT_NULL); pipe = (upipe_t)context; - ifinst = pipe->ifinst; - uhub = (uhubinst_t)ifinst->user_data; + intf = pipe->intf; + hub = (uhub_t)intf->user_data; if(pipe->status != UPIPE_STATUS_OK) { @@ -382,14 +382,14 @@ static void rt_usb_hub_irq(void* context) return; } - rt_usb_hub_port_change(uhub); + rt_usbh_hub_port_change(hub); rt_kprintf("hub int xfer...\n"); /* parameter check */ - RT_ASSERT(pipe->ifinst->uinst->hcd != RT_NULL); + RT_ASSERT(pipe->intf->device->hcd != RT_NULL); - rt_usb_hcd_int_xfer(ifinst->uinst->hcd, pipe, uhub->buffer, + rt_usb_hcd_int_xfer(intf->device->hcd, pipe, hub->buffer, pipe->ep.wMaxPacketSize, timeout); } @@ -401,33 +401,33 @@ static void rt_usb_hub_irq(void* context) * * @return the error code, RT_EOK on successfully. */ -static rt_err_t rt_usb_hub_run(void *arg) +static rt_err_t rt_usbh_hub_enable(void *arg) { int i = 0; rt_err_t ret = RT_EOK; uep_desc_t ep_desc; - uhubinst_t uhub; - uinst_t uinst; - uifinst_t ifinst = (uifinst_t)arg; + uhub_t hub; + struct uinstance* device; + struct uintf* intf = (struct uintf*)arg; int timeout = 300; /* paremeter check */ - RT_ASSERT(ifinst != RT_NULL); + RT_ASSERT(intf != RT_NULL); - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usb_hub_run\n")); + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_hub_run\n")); /* get usb device instance */ - uinst = ifinst->uinst; + device = intf->device; /* create a hub instance */ - uhub = rt_malloc(sizeof(struct uhubinst)); - rt_memset(uhub, 0, sizeof(struct uhubinst)); + hub = rt_malloc(sizeof(struct uhub)); + rt_memset(hub, 0, sizeof(struct uhub)); /* make interface instance's user data point to hub instance */ - ifinst->user_data = (void*)uhub; + intf->user_data = (void*)hub; /* get hub descriptor head */ - ret = rt_usb_hub_get_descriptor(uinst, (rt_uint8_t*)&uhub->hub_desc, 8); + ret = rt_usbh_hub_get_descriptor(device, (rt_uint8_t*)&hub->hub_desc, 8); if(ret != RT_EOK) { rt_kprintf("get hub descriptor failed\n"); @@ -435,8 +435,8 @@ static rt_err_t rt_usb_hub_run(void *arg) } /* get full hub descriptor */ - ret = rt_usb_hub_get_descriptor(uinst, (rt_uint8_t*)&uhub->hub_desc, - uhub->hub_desc.length); + ret = rt_usbh_hub_get_descriptor(device, (rt_uint8_t*)&hub->hub_desc, + hub->hub_desc.length); if(ret != RT_EOK) { rt_kprintf("get hub descriptor again failed\n"); @@ -444,23 +444,23 @@ static rt_err_t rt_usb_hub_run(void *arg) } /* get hub ports number */ - uhub->num_ports = uhub->hub_desc.num_ports; - uhub->hcd = uinst->hcd; - uhub->self = uinst; + hub->num_ports = hub->hub_desc.num_ports; + hub->hcd = device->hcd; + hub->self = device; /* reset all hub ports */ - for (i = 0; i < uhub->num_ports; i++) + for (i = 0; i < hub->num_ports; i++) { - rt_usb_hub_set_port_feature(uhub, i + 1, PORT_FEAT_POWER); - rt_thread_delay(uhub->hub_desc.pwron_to_good + rt_usbh_hub_set_port_feature(hub, i + 1, PORT_FEAT_POWER); + rt_thread_delay(hub->hub_desc.pwron_to_good * 2 * RT_TICK_PER_SECOND / 1000 ); } - if(ifinst->intf_desc->bNumEndpoints != 1) + if(intf->intf_desc->bNumEndpoints != 1) return -RT_ERROR; /* get endpoint descriptor from interface descriptor */ - rt_usb_get_endpoint_descriptor(ifinst->intf_desc, 0, &ep_desc); + rt_usbh_get_endpoint_descriptor(intf->intf_desc, 0, &ep_desc); if(ep_desc == RT_NULL) { rt_kprintf("rt_usb_get_endpoint_descriptor error\n"); @@ -474,17 +474,17 @@ static rt_err_t rt_usb_hub_run(void *arg) if(ep_desc->bEndpointAddress & USB_DIR_IN) { /* allocate a pipe according to the endpoint type */ - rt_usb_hcd_alloc_pipe(uinst->hcd, &uhub->pipe_in, ifinst, - ep_desc, rt_usb_hub_irq); + rt_usb_hcd_alloc_pipe(device->hcd, &hub->pipe_in, intf, + ep_desc, rt_usbh_hub_irq); } else return -RT_ERROR; } /* parameter check */ - RT_ASSERT(uinst->hcd != RT_NULL); + RT_ASSERT(device->hcd != RT_NULL); - rt_usb_hcd_int_xfer(uinst->hcd, uhub->pipe_in, uhub->buffer, - uhub->pipe_in->ep.wMaxPacketSize, timeout); + rt_usb_hcd_int_xfer(device->hcd, hub->pipe_in, hub->buffer, + hub->pipe_in->ep.wMaxPacketSize, timeout); return RT_EOK; } @@ -497,32 +497,32 @@ static rt_err_t rt_usb_hub_run(void *arg) * * @return the error code, RT_EOK on successfully. */ -static rt_err_t rt_usb_hub_stop(void* arg) +static rt_err_t rt_usbh_hub_disable(void* arg) { int i; - uhubinst_t uhub; - uinst_t uinst; - uifinst_t ifinst = (uifinst_t)arg; + uhub_t hub; + struct uinstance* device; + struct uintf* intf = (struct uintf*)arg; /* paremeter check */ - RT_ASSERT(ifinst != RT_NULL); + RT_ASSERT(intf != RT_NULL); - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usb_hub_stop\n")); + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_hub_stop\n")); - uinst = ifinst->uinst; - uhub = (uhubinst_t)ifinst->user_data; + device = intf->device; + hub = (uhub_t)intf->user_data; - if(uhub->pipe_in != RT_NULL) - rt_usb_hcd_free_pipe(uinst->hcd, uhub->pipe_in); + if(hub->pipe_in != RT_NULL) + rt_usb_hcd_free_pipe(device->hcd, hub->pipe_in); - for(i=0; inum_ports; i++) + for(i=0; inum_ports; i++) { - if(uhub->child[i] != RT_NULL) - rt_usb_detach_instance(uhub->child[i]); + if(hub->child[i] != RT_NULL) + rt_usbh_detach_instance(hub->child[i]); } - if(uhub != RT_NULL) rt_free(uhub); - if(ifinst != RT_NULL) rt_free(ifinst); + if(hub != RT_NULL) rt_free(hub); + if(intf != RT_NULL) rt_free(intf); return RT_EOK; } @@ -533,12 +533,12 @@ static rt_err_t rt_usb_hub_stop(void* arg) * * @return the error code, RT_EOK on successfully. */ -ucd_t rt_usb_class_driver_hub(void) +ucd_t rt_usbh_class_driver_hub(void) { hub_driver.class_code = USB_CLASS_HUB; - hub_driver.run = rt_usb_hub_run; - hub_driver.stop = rt_usb_hub_stop; + hub_driver.enable = rt_usbh_hub_enable; + hub_driver.disable = rt_usbh_hub_disable; return &hub_driver; } @@ -551,7 +551,7 @@ ucd_t rt_usb_class_driver_hub(void) * * @return none. */ -static void rt_usb_hub_thread_entry(void* parameter) +static void rt_usbh_hub_thread_entry(void* parameter) { while(1) { @@ -566,7 +566,7 @@ static void rt_usb_hub_thread_entry(void* parameter) switch (msg.type) { case USB_MSG_CONNECT_CHANGE: - rt_usb_hub_port_change(msg.content.uhub); + rt_usbh_hub_port_change(msg.content.hub); break; case USB_MSG_CALLBACK: /* invoke callback */ @@ -582,16 +582,15 @@ static void rt_usb_hub_thread_entry(void* parameter) * This function will post an message to the usb message queue, * * @param msg the message to be posted - * @param size the size of the message . * * @return the error code, RT_EOK on successfully. */ -rt_err_t rt_usb_post_event(struct uhost_msg* msg, rt_size_t size) +rt_err_t rt_usbh_event_signal(struct uhost_msg* msg) { RT_ASSERT(msg != RT_NULL); /* send message to usb message queue */ - rt_mq_send(usb_mq, (void*)msg, size); + rt_mq_send(usb_mq, (void*)msg, sizeof(struct uhost_msg)); return RT_EOK; } @@ -602,7 +601,7 @@ rt_err_t rt_usb_post_event(struct uhost_msg* msg, rt_size_t size) * @return none. * */ -void rt_usb_hub_thread(void) +void rt_usbh_hub_init(void) { rt_thread_t thread; @@ -610,7 +609,7 @@ void rt_usb_hub_thread(void) usb_mq = rt_mq_create("usbh", 32, 16, RT_IPC_FLAG_FIFO); /* create usb hub thread */ - thread = rt_thread_create("usbh", rt_usb_hub_thread_entry, RT_NULL, + thread = rt_thread_create("usbh", rt_usbh_hub_thread_entry, RT_NULL, USB_THREAD_STACK_SIZE, 8, 20); if(thread != RT_NULL) { diff --git a/components/drivers/usb/usbhost/core/usbhost.c b/components/drivers/usb/usbhost/core/usbhost.c index f40bd71528..dcfdf6a127 100644 --- a/components/drivers/usb/usbhost/core/usbhost.c +++ b/components/drivers/usb/usbhost/core/usbhost.c @@ -24,7 +24,9 @@ #include #include -#if defined(RT_USB_HID_KEYBOARD) || defined(RT_USB_HID_MOUSE) +#define USB_HOST_CONTROLLER_NAME "usbh" + +#if defined(RT_USBH_HID_KEYBOARD) || defined(RT_USBH_HID_MOUSE) #include #endif @@ -34,54 +36,64 @@ * * @return none. */ -int rt_usb_host_init(void) +rt_err_t rt_usb_host_init(void) { ucd_t drv; -#ifdef RT_USB_CLASS_HID + rt_device_t uhc; +#ifdef RT_USBH_HID uprotocal_t protocal; #endif - /* initialize usb hub thread */ - rt_usb_hub_thread(); + uhc = rt_device_find(USB_HOST_CONTROLLER_NAME); + if(uhc == RT_NULL) + { + rt_kprintf("can't find usb host controller %s\n", USB_HOST_CONTROLLER_NAME); + return -RT_ERROR; + } + + /* initialize usb hub */ + rt_usbh_hub_init(); /* initialize class driver */ - rt_usb_class_driver_init(); + rt_usbh_class_driver_init(); -#ifdef RT_USB_CLASS_MASS_STORAGE +#ifdef RT_USBH_MSTORAGE /* register mass storage class driver */ - drv = rt_usb_class_driver_storage(); - rt_usb_class_driver_register(drv); + drv = rt_usbh_class_driver_storage(); + rt_usbh_class_driver_register(drv); #endif -#ifdef RT_USB_CLASS_HID +#ifdef RT_USBH_HID /* register hid class driver */ - drv = rt_usb_class_driver_hid(); - rt_usb_class_driver_register(drv); + drv = rt_usbh_class_driver_hid(); + rt_usbh_class_driver_register(drv); -#ifdef RT_USB_HID_KEYBOARD +#ifdef RT_USBH_HID_KEYBOARD /* register hid keyboard protocal */ - protocal = rt_usb_hid_protocal_kbd(); - rt_usb_hid_protocal_register(protocal); + protocal = rt_usbh_hid_protocal_kbd(); + rt_usbh_hid_protocal_register(protocal); #endif -#ifdef RT_USB_HID_MOUSE +#ifdef RT_USBH_HID_MOUSE /* register hid mouse protocal */ - protocal = rt_usb_hid_protocal_mouse(); - rt_usb_hid_protocal_register(protocal); + protocal = rt_usbh_hid_protocal_mouse(); + rt_usbh_hid_protocal_register(protocal); #endif #endif -#ifdef RT_USB_CLASS_ADK +#ifdef RT_USBH_ADK /* register adk class driver */ - drv = rt_usb_class_driver_adk(); - rt_usb_class_driver_register(drv); + drv = rt_usbh_class_driver_adk(); + rt_usbh_class_driver_register(drv); #endif /* register hub class driver */ - drv = rt_usb_class_driver_hub(); - rt_usb_class_driver_register(drv); + drv = rt_usbh_class_driver_hub(); + rt_usbh_class_driver_register(drv); - return 0; + /* initialize usb host controller */ + rt_device_init(uhc); + + return RT_EOK; } -INIT_COMPONENT_EXPORT(rt_usb_host_init); From 306e1ac43ff1db09fad9432b7181835222d23b12 Mon Sep 17 00:00:00 2001 From: bernard Date: Tue, 4 Mar 2014 14:32:56 +0800 Subject: [PATCH 43/59] [DeviceDrivers] Add watchdog driver frame work --- components/drivers/include/drivers/watchdog.h | 56 +++++++++ components/drivers/include/rtdevice.h | 4 + components/drivers/watchdog/SConscript | 8 ++ components/drivers/watchdog/watchdog.c | 108 ++++++++++++++++++ 4 files changed, 176 insertions(+) create mode 100644 components/drivers/include/drivers/watchdog.h create mode 100644 components/drivers/watchdog/SConscript create mode 100644 components/drivers/watchdog/watchdog.c diff --git a/components/drivers/include/drivers/watchdog.h b/components/drivers/include/drivers/watchdog.h new file mode 100644 index 0000000000..15ae5a1f44 --- /dev/null +++ b/components/drivers/include/drivers/watchdog.h @@ -0,0 +1,56 @@ +/* + * File : watchdog.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2012-2014, Shanghai Real-Thread Electronic Technology Co.,Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-09-12 heyuanjie87 first version. + */ + +#ifndef __WATCHDOG_H__ +#define __WATCHDOG_H__ + +#include + +#define RT_DEVICE_CTRL_WDT_GET_TIMEOUT (1) /* get timeout(in seconds) */ +#define RT_DEVICE_CTRL_WDT_SET_TIMEOUT (2) /* set timeout(in seconds) */ +#define RT_DEVICE_CTRL_WDT_GET_TIMELEFT (3) /* get the left time before reboot(in seconds) */ +#define RT_DEVICE_CTRL_WDT_KEEPALIVE (4) /* refresh watchdog */ +#define RT_DEVICE_CTRL_WDT_START (5) /* start watchdog */ +#define RT_DEVICE_CTRL_WDT_STOP (6) /* stop watchdog */ + +struct rt_watchdog_ops; +struct rt_watchdog_device +{ + struct rt_device parent; + struct rt_watchdog_ops *ops; +}; +typedef struct rt_watchdog_device rt_watchdog_t; + +struct rt_watchdog_ops +{ + rt_err_t (*init)(rt_watchdog_t *wdt); + rt_err_t (*control)(rt_watchdog_t *wdt, int cmd, void *arg); +}; + +rt_err_t rt_hw_watchdog_register(rt_watchdog_t *wdt, + const char *name, + rt_uint32_t flag, + void *data); + +#endif /* __WATCHDOG_H__ */ diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index 8ed9f34ca4..dac85eb716 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -320,5 +320,9 @@ void rt_data_queue_reset(struct rt_data_queue *queue); #include "drivers/sdio.h" #endif +#ifdef RT_USING_WDT +#include "drivers/watchdog.h" +#endif + #endif /* __RT_DEVICE_H__ */ diff --git a/components/drivers/watchdog/SConscript b/components/drivers/watchdog/SConscript new file mode 100644 index 0000000000..38934d3c41 --- /dev/null +++ b/components/drivers/watchdog/SConscript @@ -0,0 +1,8 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd + '/../include'] +group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_WDT'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/watchdog/watchdog.c b/components/drivers/watchdog/watchdog.c new file mode 100644 index 0000000000..c9620d319b --- /dev/null +++ b/components/drivers/watchdog/watchdog.c @@ -0,0 +1,108 @@ +/* + * File : watchdog.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2012-2014, Shanghai Real-Thread Electronic Technology Co.,Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-09-12 heyuanjie87 first version. + * 2014-03-04 Bernard code cleanup + */ + +#include + +/* RT-Thread Device Interface */ + +/* + * This function initializes serial + */ +static rt_err_t rt_watchdog_init(struct rt_device *dev) +{ + rt_watchdog_t *wtd; + + RT_ASSERT(dev != RT_NULL); + wtd = (rt_watchdog_t *)dev; + if (wtd->ops->init) + { + return (wtd->ops->init(wtd)); + } + + return (-RT_ENOSYS); +} + +static rt_err_t rt_watchdog_open(struct rt_device *dev, rt_uint16_t oflag) +{ + return (RT_EOK); +} + +static rt_err_t rt_watchdog_close(struct rt_device *dev) +{ + rt_watchdog_t *wtd; + + RT_ASSERT(dev != RT_NULL); + wtd = (rt_watchdog_t *)dev; + + if (wtd->ops->control(wtd, RT_DEVICE_CTRL_WDT_STOP, RT_NULL) != RT_EOK) + { + rt_kprintf(" This watchdog can not be stoped\n"); + + return (-RT_ERROR); + } + + return (RT_EOK); +} + +static rt_err_t rt_watchdog_control(struct rt_device *dev, + rt_uint8_t cmd, + void *args) +{ + rt_watchdog_t *wtd; + + RT_ASSERT(dev != RT_NULL); + wtd = (rt_watchdog_t *)dev; + + return (wtd->ops->control(wtd, cmd, args)); +} + +/** + * This function register a watchdog device + */ +rt_err_t rt_hw_watchdog_register(struct rt_watchdog_device *wtd, + const char *name, + rt_uint32_t flag, + void *data) +{ + struct rt_device *device; + RT_ASSERT(wtd != RT_NULL); + + device = &(wtd->parent); + + device->type = RT_Device_Class_Miscellaneous; + device->rx_indicate = RT_NULL; + device->tx_complete = RT_NULL; + + device->init = rt_watchdog_init; + device->open = rt_watchdog_open; + device->close = rt_watchdog_close; + device->read = RT_NULL; + device->write = RT_NULL; + device->control = rt_watchdog_control; + device->user_data = data; + + /* register a character device */ + return rt_device_register(device, name, flag); +} From d0d239cd4c094f558c18ada3fad459edd57bb05b Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Mon, 10 Mar 2014 11:21:50 +0800 Subject: [PATCH 44/59] [DFS] fix compiling warning for NFS file system --- components/dfs/filesystems/nfs/mount.h | 4 +- components/dfs/filesystems/nfs/mount_xdr.c | 4 +- components/dfs/filesystems/nfs/nfs.h | 6 +- components/dfs/filesystems/nfs/nfs_xdr.c | 6 +- components/dfs/filesystems/nfs/rpc/xdr.c | 64 +++++----------------- 5 files changed, 23 insertions(+), 61 deletions(-) diff --git a/components/dfs/filesystems/nfs/mount.h b/components/dfs/filesystems/nfs/mount.h index 852cf2dc2b..4ce3714f98 100644 --- a/components/dfs/filesystems/nfs/mount.h +++ b/components/dfs/filesystems/nfs/mount.h @@ -20,7 +20,7 @@ extern "C" { #define FHSIZE3 64 typedef struct { - u_int fhandle3_len; + unsigned int fhandle3_len; char *fhandle3_val; } fhandle3; @@ -51,7 +51,7 @@ typedef enum mountstat3 mountstat3; struct mountres3_ok { fhandle3 fhandle; struct { - u_int auth_flavors_len; + unsigned int auth_flavors_len; int *auth_flavors_val; } auth_flavors; }; diff --git a/components/dfs/filesystems/nfs/mount_xdr.c b/components/dfs/filesystems/nfs/mount_xdr.c index 1f30e0e18a..b87b7e7a6d 100644 --- a/components/dfs/filesystems/nfs/mount_xdr.c +++ b/components/dfs/filesystems/nfs/mount_xdr.c @@ -18,7 +18,7 @@ xdr_fhandle3(register XDR *xdrs, fhandle3 *objp) register long *buf; #endif - if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3)) + if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3)) return (FALSE); return (TRUE); } @@ -132,7 +132,7 @@ xdr_mountres3_ok(register XDR *xdrs, mountres3_ok *objp) if (!xdr_fhandle3(xdrs, &objp->fhandle)) return (FALSE); - if (!xdr_array(xdrs, (char **)&objp->auth_flavors.auth_flavors_val, (u_int *) &objp->auth_flavors.auth_flavors_len, ~0, + if (!xdr_array(xdrs, (char **)&objp->auth_flavors.auth_flavors_val, (unsigned int *) &objp->auth_flavors.auth_flavors_len, ~0, sizeof (int), (xdrproc_t) xdr_int)) return (FALSE); return (TRUE); diff --git a/components/dfs/filesystems/nfs/nfs.h b/components/dfs/filesystems/nfs/nfs.h index e668ac01b6..7e3e3671af 100644 --- a/components/dfs/filesystems/nfs/nfs.h +++ b/components/dfs/filesystems/nfs/nfs.h @@ -130,7 +130,7 @@ typedef struct specdata3 specdata3; struct nfs_fh3 { struct { - u_int data_len; + unsigned int data_len; char *data_val; } data; }; @@ -408,7 +408,7 @@ struct READ3resok { count3 count; bool_t eof; struct { - u_int data_len; + unsigned int data_len; char *data_val; } data; }; @@ -434,7 +434,7 @@ struct WRITE3args { count3 count; stable_how stable; struct { - u_int data_len; + unsigned int data_len; char *data_val; } data; }; diff --git a/components/dfs/filesystems/nfs/nfs_xdr.c b/components/dfs/filesystems/nfs/nfs_xdr.c index f47acd2f4c..ee042b7897 100644 --- a/components/dfs/filesystems/nfs/nfs_xdr.c +++ b/components/dfs/filesystems/nfs/nfs_xdr.c @@ -213,7 +213,7 @@ xdr_specdata3(register XDR *xdrs, specdata3 *objp) bool_t xdr_nfs_fh3(register XDR *xdrs, nfs_fh3 *objp) { - if (!xdr_bytes(xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, NFS3_FHSIZE)) + if (!xdr_bytes(xdrs, (char **)&objp->data.data_val, (unsigned int *) &objp->data.data_len, NFS3_FHSIZE)) return (FALSE); return (TRUE); } @@ -713,7 +713,7 @@ xdr_READ3resok(register XDR *xdrs, READ3resok *objp) return (FALSE); if (!xdr_bool(xdrs, &objp->eof)) return (FALSE); - if (!xdr_bytes(xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0)) + if (!xdr_bytes(xdrs, (char **)&objp->data.data_val, (unsigned int *) &objp->data.data_len, ~0)) return (FALSE); return (TRUE); } @@ -755,7 +755,7 @@ xdr_WRITE3args(register XDR *xdrs, WRITE3args *objp) return (FALSE); if (!xdr_stable_how(xdrs, &objp->stable)) return (FALSE); - if (!xdr_bytes(xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0)) + if (!xdr_bytes(xdrs, (char **)&objp->data.data_val, (unsigned int *) &objp->data.data_len, ~0)) return (FALSE); return (TRUE); } diff --git a/components/dfs/filesystems/nfs/rpc/xdr.c b/components/dfs/filesystems/nfs/rpc/xdr.c index 0c6ee781e6..ec37d6beb9 100644 --- a/components/dfs/filesystems/nfs/rpc/xdr.c +++ b/components/dfs/filesystems/nfs/rpc/xdr.c @@ -50,8 +50,8 @@ static char sccsid[] = "@(#)xdr.c 1.35 87/08/12"; /* * constants specific to the xdr "protocol" */ -#define XDR_FALSE ((long) 0) -#define XDR_TRUE ((long) 1) +#define XDR_FALSE ((long) 0) +#define XDR_TRUE ((long) 1) #define LASTUNSIGNED ((unsigned int) 0-1) /* @@ -327,9 +327,7 @@ bool_t xdr_u_char(XDR* xdrs, unsigned char* cp) /* * XDR booleans */ -bool_t xdr_bool(xdrs, bp) -register XDR *xdrs; -bool_t *bp; +bool_t xdr_bool(XDR *xdrs, bool_t *bp) { long lb; @@ -355,9 +353,7 @@ bool_t *bp; /* * XDR enumerations */ -bool_t xdr_enum(xdrs, ep) -XDR *xdrs; -enum_t *ep; +bool_t xdr_enum(XDR *xdrs, enum_t *ep) { /* * enums are treated as ints @@ -370,10 +366,7 @@ enum_t *ep; * Allows the specification of a fixed size sequence of opaque bytes. * cp points to the opaque object and cnt gives the byte length. */ -bool_t xdr_opaque(xdrs, cp, cnt) -register XDR *xdrs; -char* cp; -register unsigned int cnt; +bool_t xdr_opaque(XDR *xdrs, char* cp, unsigned int cnt) { register unsigned int rndup; static char crud[BYTES_PER_XDR_UNIT]; @@ -421,11 +414,7 @@ register unsigned int cnt; * *cpp is a pointer to the bytes, *sizep is the count. * If *cpp is NULL maxsize bytes are allocated */ -bool_t xdr_bytes(xdrs, cpp, sizep, maxsize) -register XDR *xdrs; -char **cpp; -register unsigned int *sizep; -unsigned int maxsize; +bool_t xdr_bytes(XDR *xdrs, char** cpp, unsigned int *sizep, unsigned int maxsize) { register char *sp = *cpp; /* sp is the actual string pointer */ register unsigned int nodesize; @@ -475,11 +464,8 @@ unsigned int maxsize; /* * Implemented here due to commonality of the object. */ -bool_t xdr_netobj(xdrs, np) -XDR *xdrs; -struct netobj *np; +bool_t xdr_netobj(XDR *xdrs, struct netobj *np) { - return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ)); } @@ -537,10 +523,7 @@ bool_t xdr_union(XDR* xdrs, enum_t* dscmp, char* unp, const struct xdr_discrim* * storage is allocated. The last parameter is the max allowed length * of the string as specified by a protocol. */ -bool_t xdr_string(xdrs, cpp, maxsize) -register XDR *xdrs; -char **cpp; -unsigned int maxsize; +bool_t xdr_string(XDR *xdrs, char **cpp, unsigned int maxsize) { register char *sp = *cpp; /* sp is the actual string pointer */ unsigned int size; @@ -600,9 +583,7 @@ unsigned int maxsize; * Wrapper for xdr_string that can be called directly from * routines like clnt_call */ -bool_t xdr_wrapstring(xdrs, cpp) -XDR *xdrs; -char **cpp; +bool_t xdr_wrapstring(XDR *xdrs, char **cpp) { if (xdr_string(xdrs, cpp, LASTUNSIGNED)) { return (TRUE); @@ -617,13 +598,7 @@ char **cpp; * elsize is the size (in bytes) of each element, and elproc is the * xdr procedure to call to handle each element of the array. */ -bool_t xdr_array(xdrs, addrp, sizep, maxsize, elsize, elproc) -register XDR *xdrs; -char* *addrp; /* array pointer */ -unsigned int *sizep; /* number of elements */ -unsigned int maxsize; /* max numberof elements */ -unsigned int elsize; /* size in bytes of each element */ -xdrproc_t elproc; /* xdr routine to handle each element */ +bool_t xdr_array(XDR *xdrs, char **addrp, unsigned int *sizep, unsigned int maxsize, unsigned int elsize, xdrproc_t elproc) { register unsigned int i; register char* target = *addrp; @@ -700,12 +675,7 @@ xdrproc_t elproc; /* xdr routine to handle each element */ * > elemsize: size of each element * > xdr_elem: routine to XDR each element */ -bool_t xdr_vector(xdrs, basep, nelem, elemsize, xdr_elem) -register XDR *xdrs; -register char *basep; -register unsigned int nelem; -register unsigned int elemsize; -register xdrproc_t xdr_elem; +bool_t xdr_vector(XDR *xdrs, char *basep, unsigned int nelem, unsigned int elemsize, xdrproc_t xdr_elem) { register unsigned int i; register char *elptr; @@ -730,11 +700,7 @@ register xdrproc_t xdr_elem; * size is the sizeof the referneced structure. * proc is the routine to handle the referenced structure. */ -bool_t xdr_reference(xdrs, pp, size, proc) -register XDR *xdrs; -char* *pp; /* the pointer to work on */ -unsigned int size; /* size of the object pointed to */ -xdrproc_t proc; /* xdr routine to handle the object */ +bool_t xdr_reference(XDR *xdrs, char **pp, unsigned int size, xdrproc_t proc) { register char* loc = *pp; register bool_t stat; @@ -783,11 +749,7 @@ xdrproc_t proc; /* xdr routine to handle the object */ * > xdr_obj: routine to XDR an object. * */ -bool_t xdr_pointer(xdrs, objpp, obj_size, xdr_obj) -register XDR *xdrs; -char **objpp; -unsigned int obj_size; -xdrproc_t xdr_obj; +bool_t xdr_pointer(XDR *xdrs, char **objpp, unsigned int obj_size, xdrproc_t xdr_obj) { bool_t more_data; From 6cab3b7dfa5b00df4d0e8bb51e6329ba3d3ea785 Mon Sep 17 00:00:00 2001 From: bernard Date: Mon, 10 Mar 2014 11:48:47 +0800 Subject: [PATCH 45/59] [DFS] fix compiling warning in NFS --- components/dfs/filesystems/nfs/mount_xdr.c | 85 +------------------ components/dfs/filesystems/nfs/nfs_xdr.c | 10 +-- .../dfs/filesystems/nfs/rpc/auth_none.c | 5 +- components/dfs/filesystems/nfs/rpc/clnt_udp.c | 23 +++-- components/dfs/filesystems/nfs/rpc/pmap.c | 10 +-- components/dfs/filesystems/nfs/rpc/rpc_prot.c | 40 +++------ components/dfs/filesystems/nfs/rpc/xdr_mem.c | 4 +- 7 files changed, 39 insertions(+), 138 deletions(-) diff --git a/components/dfs/filesystems/nfs/mount_xdr.c b/components/dfs/filesystems/nfs/mount_xdr.c index b87b7e7a6d..e4d2b86f47 100644 --- a/components/dfs/filesystems/nfs/mount_xdr.c +++ b/components/dfs/filesystems/nfs/mount_xdr.c @@ -11,13 +11,6 @@ bool_t xdr_fhandle3(register XDR *xdrs, fhandle3 *objp) { - -#if defined(_LP64) || defined(_KERNEL) - register int *buf; -#else - register long *buf; -#endif - if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3)) return (FALSE); return (TRUE); @@ -26,13 +19,6 @@ xdr_fhandle3(register XDR *xdrs, fhandle3 *objp) bool_t xdr_dirpath(register XDR *xdrs, dirpath *objp) { - -#if defined(_LP64) || defined(_KERNEL) - register int *buf; -#else - register long *buf; -#endif - if (!xdr_string(xdrs, objp, MNTPATHLEN)) return (FALSE); return (TRUE); @@ -41,13 +27,6 @@ xdr_dirpath(register XDR *xdrs, dirpath *objp) bool_t xdr_name(register XDR *xdrs, name *objp) { - -#if defined(_LP64) || defined(_KERNEL) - register int *buf; -#else - register long *buf; -#endif - if (!xdr_string(xdrs, objp, MNTNAMLEN)) return (FALSE); return (TRUE); @@ -56,13 +35,6 @@ xdr_name(register XDR *xdrs, name *objp) bool_t xdr_exports(register XDR *xdrs, exports *objp) { - -#if defined(_LP64) || defined(_KERNEL) - register int *buf; -#else - register long *buf; -#endif - if (!xdr_pointer(xdrs, (char **)objp, sizeof (struct exportnode), (xdrproc_t) xdr_exportnode)) return (FALSE); return (TRUE); @@ -71,13 +43,6 @@ xdr_exports(register XDR *xdrs, exports *objp) bool_t xdr_groups(register XDR *xdrs, groups *objp) { - -#if defined(_LP64) || defined(_KERNEL) - register int *buf; -#else - register long *buf; -#endif - if (!xdr_pointer(xdrs, (char **)objp, sizeof (struct groupnode), (xdrproc_t) xdr_groupnode)) return (FALSE); return (TRUE); @@ -86,13 +51,6 @@ xdr_groups(register XDR *xdrs, groups *objp) bool_t xdr_mountlist(register XDR *xdrs, mountlist *objp) { - -#if defined(_LP64) || defined(_KERNEL) - register int *buf; -#else - register long *buf; -#endif - if (!xdr_pointer(xdrs, (char **)objp, sizeof (struct mountbody), (xdrproc_t) xdr_mountbody)) return (FALSE); return (TRUE); @@ -103,17 +61,11 @@ xdr_mountstat3(register XDR *xdrs, mountstat3 *objp) { int enum_objp; -#if defined(_LP64) || defined(_KERNEL) - register int *buf; -#else - register long *buf; -#endif - enum_objp = *objp; if (!xdr_enum(xdrs, (enum_t *)&enum_objp)) { - *objp = enum_objp; + *objp = (mountstat3)enum_objp; return (FALSE); } @@ -123,13 +75,6 @@ xdr_mountstat3(register XDR *xdrs, mountstat3 *objp) bool_t xdr_mountres3_ok(register XDR *xdrs, mountres3_ok *objp) { - -#if defined(_LP64) || defined(_KERNEL) - register int *buf; -#else - register long *buf; -#endif - if (!xdr_fhandle3(xdrs, &objp->fhandle)) return (FALSE); if (!xdr_array(xdrs, (char **)&objp->auth_flavors.auth_flavors_val, (unsigned int *) &objp->auth_flavors.auth_flavors_len, ~0, @@ -141,13 +86,6 @@ xdr_mountres3_ok(register XDR *xdrs, mountres3_ok *objp) bool_t xdr_mountres3(register XDR *xdrs, mountres3 *objp) { - -#if defined(_LP64) || defined(_KERNEL) - register int *buf; -#else - register long *buf; -#endif - if (!xdr_mountstat3(xdrs, &objp->fhs_status)) return (FALSE); switch (objp->fhs_status) { @@ -162,13 +100,6 @@ xdr_mountres3(register XDR *xdrs, mountres3 *objp) bool_t xdr_mountbody(register XDR *xdrs, mountbody *objp) { - -#if defined(_LP64) || defined(_KERNEL) - register int *buf; -#else - register long *buf; -#endif - if (!xdr_name(xdrs, &objp->ml_hostname)) return (FALSE); if (!xdr_dirpath(xdrs, &objp->ml_directory)) @@ -181,13 +112,6 @@ xdr_mountbody(register XDR *xdrs, mountbody *objp) bool_t xdr_groupnode(register XDR *xdrs, groupnode *objp) { - -#if defined(_LP64) || defined(_KERNEL) - register int *buf; -#else - register long *buf; -#endif - if (!xdr_name(xdrs, &objp->gr_name)) return (FALSE); if (!xdr_groups(xdrs, &objp->gr_next)) @@ -198,13 +122,6 @@ xdr_groupnode(register XDR *xdrs, groupnode *objp) bool_t xdr_exportnode(register XDR *xdrs, exportnode *objp) { - -#if defined(_LP64) || defined(_KERNEL) - register int *buf; -#else - register long *buf; -#endif - if (!xdr_dirpath(xdrs, &objp->ex_dir)) return (FALSE); if (!xdr_groups(xdrs, &objp->ex_groups)) diff --git a/components/dfs/filesystems/nfs/nfs_xdr.c b/components/dfs/filesystems/nfs/nfs_xdr.c index ee042b7897..72d6edc42a 100644 --- a/components/dfs/filesystems/nfs/nfs_xdr.c +++ b/components/dfs/filesystems/nfs/nfs_xdr.c @@ -151,7 +151,7 @@ xdr_nfsstat3(register XDR *xdrs, nfsstat3 *objp) enum_objp = *objp; if (!xdr_enum(xdrs, (enum_t *)objp)) { - *objp = enum_objp; + *objp = (nfsstat3)enum_objp; return (FALSE); } @@ -165,7 +165,7 @@ xdr_ftype3(register XDR *xdrs, ftype3 *objp) enum_objp = *objp; if (!xdr_enum(xdrs, (enum_t *)objp)) { - *objp = enum_objp; + *objp = (ftype3)enum_objp; return (FALSE); } @@ -179,7 +179,7 @@ xdr_stable_how(register XDR *xdrs, stable_how *objp) enum_objp = *objp; if (!xdr_enum(xdrs, (enum_t *)objp)) { - *objp = enum_objp; + *objp = (stable_how)enum_objp; return (FALSE); } @@ -193,7 +193,7 @@ xdr_createmode3(register XDR *xdrs, createmode3 *objp) enum_objp = *objp; if (!xdr_enum(xdrs, (enum_t *)objp)) { - *objp = enum_objp; + *objp = (createmode3)enum_objp; return (FALSE); } @@ -343,7 +343,7 @@ xdr_time_how(register XDR *xdrs, time_how *objp) enum_objp = *objp; if (!xdr_enum(xdrs, (enum_t *)objp)) { - *objp = enum_objp; + *objp = (time_how)enum_objp; return (FALSE); } diff --git a/components/dfs/filesystems/nfs/rpc/auth_none.c b/components/dfs/filesystems/nfs/rpc/auth_none.c index 2edcd28159..92947581d2 100644 --- a/components/dfs/filesystems/nfs/rpc/auth_none.c +++ b/components/dfs/filesystems/nfs/rpc/auth_none.c @@ -73,6 +73,7 @@ AUTH *authnone_create() register struct authnone_private *ap = authnone_private; XDR xdr_stream; register XDR *xdrs; + extern bool_t xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap); if (ap == 0) { ap = (struct authnone_private *) rt_malloc (sizeof(*ap)); @@ -95,9 +96,7 @@ AUTH *authnone_create() } /*ARGSUSED*/ -static bool_t authnone_marshal(client, xdrs) -AUTH *client; -XDR *xdrs; +static bool_t authnone_marshal(AUTH *client, XDR *xdrs) { register struct authnone_private *ap = authnone_private; diff --git a/components/dfs/filesystems/nfs/rpc/clnt_udp.c b/components/dfs/filesystems/nfs/rpc/clnt_udp.c index e161c1c07b..a69bc0621a 100644 --- a/components/dfs/filesystems/nfs/rpc/clnt_udp.c +++ b/components/dfs/filesystems/nfs/rpc/clnt_udp.c @@ -135,6 +135,10 @@ CLIENT *clntudp_bufcreate(struct sockaddr_in *raddr, if (raddr->sin_port == 0) { unsigned short port; + extern unsigned short pmap_getport(struct sockaddr_in *address, + unsigned long program, + unsigned long version, + unsigned int protocol); if ((port = pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) { @@ -165,8 +169,6 @@ CLIENT *clntudp_bufcreate(struct sockaddr_in *raddr, cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); if (*sockp < 0) { - int dontblock = 1; - *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (*sockp < 0) { @@ -229,7 +231,10 @@ call_again: if ((!XDR_PUTLONG(xdrs, (long *) &proc)) || (!AUTH_MARSHALL(cl->cl_auth, xdrs)) || (!(*xargs) (xdrs, argsp))) - return (cu->cu_error.re_status = RPC_CANTENCODEARGS); + { + cu->cu_error.re_status = RPC_CANTENCODEARGS; + return RPC_CANTENCODEARGS; + } outlen = (int) XDR_GETPOS(xdrs); send_again: @@ -238,7 +243,9 @@ send_again: != outlen) { cu->cu_error.re_errno = errno; - return (cu->cu_error.re_status = RPC_CANTSEND); + cu->cu_error.re_status = RPC_CANTSEND; + + return RPC_CANTSEND; } /* @@ -264,7 +271,9 @@ send_again: { rt_kprintf("recv error, len %d\n", inlen); cu->cu_error.re_errno = errno; - return (cu->cu_error.re_status = RPC_CANTRECV); + cu->cu_error.re_status = RPC_CANTRECV; + + return RPC_CANTRECV; } /* see if reply transaction id matches sent id */ @@ -292,6 +301,8 @@ send_again: } if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { + extern bool_t xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap); + xdrs->x_op = XDR_FREE; (void) xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); } @@ -311,7 +322,7 @@ send_again: cu->cu_error.re_status = RPC_CANTDECODERES; } - return (cu->cu_error.re_status); + return (enum clnt_stat)(cu->cu_error.re_status); } static void clntudp_geterr(CLIENT *cl, struct rpc_err *errp) diff --git a/components/dfs/filesystems/nfs/rpc/pmap.c b/components/dfs/filesystems/nfs/rpc/pmap.c index cbf5add2ab..fcf8e9d948 100644 --- a/components/dfs/filesystems/nfs/rpc/pmap.c +++ b/components/dfs/filesystems/nfs/rpc/pmap.c @@ -6,9 +6,7 @@ static struct timeval timeout = { 5, 0 }; static struct timeval tottimeout = { 60, 0 }; -bool_t xdr_pmap(xdrs, regs) -XDR *xdrs; -struct pmap *regs; +bool_t xdr_pmap(XDR *xdrs, struct pmap *regs) { if (xdr_u_long(xdrs, ®s->pm_prog) && xdr_u_long(xdrs, ®s->pm_vers) && @@ -22,11 +20,7 @@ struct pmap *regs; * Calls the pmap service remotely to do the lookup. * Returns 0 if no map exists. */ -unsigned short pmap_getport(address, program, version, protocol) -struct sockaddr_in *address; -unsigned long program; -unsigned long version; -unsigned int protocol; +unsigned short pmap_getport(struct sockaddr_in *address, unsigned long program, unsigned long version, unsigned int protocol) { unsigned short port = 0; int socket = -1; diff --git a/components/dfs/filesystems/nfs/rpc/rpc_prot.c b/components/dfs/filesystems/nfs/rpc/rpc_prot.c index 3cfb8dc3fa..21fc1f4ea4 100644 --- a/components/dfs/filesystems/nfs/rpc/rpc_prot.c +++ b/components/dfs/filesystems/nfs/rpc/rpc_prot.c @@ -52,9 +52,7 @@ static char sccsid[] = "@(#)rpc_prot.c 1.36 87/08/11 Copyr 1984 Sun Micro"; * XDR an opaque authentication struct * (see auth.h) */ -bool_t xdr_opaque_auth(xdrs, ap) -register XDR *xdrs; -register struct opaque_auth *ap; +bool_t xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap) { if (xdr_enum(xdrs, &(ap->oa_flavor))) @@ -66,9 +64,7 @@ register struct opaque_auth *ap; /* * XDR a DES block */ -bool_t xdr_des_block(xdrs, blkp) -register XDR *xdrs; -register des_block *blkp; +bool_t xdr_des_block(XDR *xdrs, des_block *blkp) { return (xdr_opaque(xdrs, (char*) blkp, sizeof(des_block))); } @@ -78,9 +74,7 @@ register des_block *blkp; /* * XDR the MSG_ACCEPTED part of a reply message union */ -static bool_t xdr_accepted_reply(xdrs, ar) -register XDR *xdrs; -register struct accepted_reply *ar; +static bool_t xdr_accepted_reply(XDR *xdrs, struct accepted_reply *ar) { /* personalized union, rather than calling xdr_union */ @@ -104,9 +98,7 @@ register struct accepted_reply *ar; /* * XDR the MSG_DENIED part of a reply message union */ -static bool_t xdr_rejected_reply(xdrs, rr) -register XDR *xdrs; -register struct rejected_reply *rr; +static bool_t xdr_rejected_reply(XDR *xdrs, struct rejected_reply *rr) { /* personalized union, rather than calling xdr_union */ @@ -134,9 +126,7 @@ static struct xdr_discrim reply_dscrm[3] = { /* * XDR a reply message */ -bool_t xdr_replymsg(xdrs, rmsg) -register XDR *xdrs; -register struct rpc_msg *rmsg; +bool_t xdr_replymsg(XDR *xdrs, struct rpc_msg *rmsg) { if (xdr_u_long(xdrs, &(rmsg->rm_xid)) && xdr_enum(xdrs, (enum_t *) & (rmsg->rm_direction)) && @@ -153,9 +143,7 @@ register struct rpc_msg *rmsg; * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers. * The rm_xid is not really static, but the user can easily munge on the fly. */ -bool_t xdr_callhdr(xdrs, cmsg) -register XDR *xdrs; -register struct rpc_msg *cmsg; +bool_t xdr_callhdr(XDR *xdrs, struct rpc_msg *cmsg) { cmsg->rm_direction = CALL; @@ -172,9 +160,7 @@ register struct rpc_msg *cmsg; /* ************************** Client utility routine ************* */ -static void accepted(acpt_stat, error) -register enum accept_stat acpt_stat; -register struct rpc_err *error; +static void accepted(enum accept_stat acpt_stat, struct rpc_err *error) { switch (acpt_stat) { @@ -209,9 +195,7 @@ register struct rpc_err *error; error->re_lb.s2 = (long) acpt_stat; } -static void rejected(rjct_stat, error) -register enum reject_stat rjct_stat; -register struct rpc_err *error; +static void rejected(enum reject_stat rjct_stat, struct rpc_err *error) { switch (rjct_stat) { @@ -233,9 +217,7 @@ register struct rpc_err *error; /* * given a reply message, fills in the error */ -void _seterr_reply(msg, error) -register struct rpc_msg *msg; -register struct rpc_err *error; +void _seterr_reply(struct rpc_msg *msg, struct rpc_err *error) { /* optimized for normal, SUCCESSful case */ @@ -246,11 +228,11 @@ register struct rpc_err *error; error->re_status = RPC_SUCCESS; return; }; - accepted(msg->acpted_rply.ar_stat, error); + accepted((enum accept_stat)msg->acpted_rply.ar_stat, error); break; case MSG_DENIED: - rejected(msg->rjcted_rply.rj_stat, error); + rejected((enum reject_stat)msg->rjcted_rply.rj_stat, error); break; default: diff --git a/components/dfs/filesystems/nfs/rpc/xdr_mem.c b/components/dfs/filesystems/nfs/rpc/xdr_mem.c index b4afabedb8..d6baf85837 100644 --- a/components/dfs/filesystems/nfs/rpc/xdr_mem.c +++ b/components/dfs/filesystems/nfs/rpc/xdr_mem.c @@ -135,9 +135,7 @@ static unsigned int xdrmem_getpos (const XDR *xdrs) return ((unsigned long) xdrs->x_private - (unsigned long) xdrs->x_base); } -static bool_t xdrmem_setpos(xdrs, pos) -register XDR *xdrs; -unsigned int pos; +static bool_t xdrmem_setpos(XDR *xdrs, unsigned int pos) { register char* newaddr = xdrs->x_base + pos; register char* lastaddr = xdrs->x_private + xdrs->x_handy; From 898e0d2f3fa2e6bb77d3693d693e39cc73814dbb Mon Sep 17 00:00:00 2001 From: bernard Date: Tue, 11 Mar 2014 14:19:24 +0800 Subject: [PATCH 46/59] [Kernel] stop thread timer when suspend a thread --- src/thread.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/thread.c b/src/thread.c index c2282f6ee6..6c0490a6a3 100644 --- a/src/thread.c +++ b/src/thread.c @@ -575,6 +575,9 @@ rt_err_t rt_thread_suspend(rt_thread_t thread) thread->stat = RT_THREAD_SUSPEND; rt_schedule_remove_thread(thread); + /* stop thread timer anyway */ + rt_timer_stop(&(thread->thread_timer)); + /* enable interrupt */ rt_hw_interrupt_enable(temp); From dbcb4a1ccff7c3840a722110d7a98816c0dd5cf2 Mon Sep 17 00:00:00 2001 From: bernard Date: Tue, 11 Mar 2014 15:44:35 +0800 Subject: [PATCH 47/59] [Kernel] declare more APIs in module --- include/rtthread.h | 3 +++ src/module.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/rtthread.h b/include/rtthread.h index f53c7b95b8..abe3a614ed 100644 --- a/include/rtthread.h +++ b/include/rtthread.h @@ -434,6 +434,9 @@ void rt_module_load_sethook(void (*hook)(rt_module_t module)); void rt_module_unload_sethook(void (*hook)(rt_module_t module)); #endif +void rt_module_init_object_container(struct rt_module *module); +rt_err_t rt_module_destroy(rt_module_t module); + /*@}*/ #endif diff --git a/src/module.c b/src/module.c index ec5ed3f7d0..428d42e961 100644 --- a/src/module.c +++ b/src/module.c @@ -242,7 +242,7 @@ static int rt_module_arm_relocate(struct rt_module *module, return 0; } -static void rt_module_init_object_container(struct rt_module *module) +void rt_module_init_object_container(struct rt_module *module) { RT_ASSERT(module != RT_NULL); From 33a5abbbf85683297a1efdc290786ffe455a3b5d Mon Sep 17 00:00:00 2001 From: bernard Date: Tue, 11 Mar 2014 15:54:21 +0800 Subject: [PATCH 48/59] [Finsh] Use msh as prompt when current mode is msh mode. --- components/finsh/shell.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/components/finsh/shell.c b/components/finsh/shell.c index 74b7ed7d95..0f1e1c625e 100644 --- a/components/finsh/shell.c +++ b/components/finsh/shell.c @@ -58,11 +58,16 @@ struct finsh_shell* shell; #include const char* finsh_get_prompt() { - #define _PROMPT "finsh " + #define _MSH_PROMPT "msh " + #define _PROMPT "finsh " static char finsh_prompt[RT_CONSOLEBUF_SIZE + 1] = {_PROMPT}; - + +#ifdef FINSH_USING_MSH + if (msh_is_used()) strcpy(finsh_prompt, _MSH_PROMPT); +#endif + /* get current working directory */ - getcwd(&finsh_prompt[6], RT_CONSOLEBUF_SIZE - 8); + getcwd(&finsh_prompt[rt_strlen(finsh_prompt)], RT_CONSOLEBUF_SIZE - 8); strcat(finsh_prompt, ">"); return finsh_prompt; From 09bb7393b2f8265e281da785925f89b4964f1be7 Mon Sep 17 00:00:00 2001 From: bernard Date: Tue, 11 Mar 2014 16:05:14 +0800 Subject: [PATCH 49/59] [Pthreads] fix compiling warning --- components/pthreads/posix_types.h | 121 +---------------------------- components/pthreads/pthread.c | 4 +- components/pthreads/pthread_attr.c | 10 +-- components/pthreads/sched.c | 2 +- 4 files changed, 12 insertions(+), 125 deletions(-) diff --git a/components/pthreads/posix_types.h b/components/pthreads/posix_types.h index 280867c4ca..6f02417512 100644 --- a/components/pthreads/posix_types.h +++ b/components/pthreads/posix_types.h @@ -68,139 +68,26 @@ struct timeval long tv_usec; /* microseconds */ }; -/* errno definitions */ +#ifdef RT_USING_LWIP +#include +#else #define EPERM 1 /* Operation not permitted */ #define ENOENT 2 /* No such file or directory */ #define ESRCH 3 /* No such process */ #define EINTR 4 /* Interrupted system call */ -#define EIO 5 /* I/O error */ -#define ENXIO 6 /* No such device or address */ -#define E2BIG 7 /* Arg list too long */ -#define ENOEXEC 8 /* Exec format error */ #define EBADF 9 /* Bad file number */ -#define ECHILD 10 /* No child processes */ #define EAGAIN 11 /* Try again */ #define ENOMEM 12 /* Out of memory */ -#define EACCES 13 /* Permission denied */ -#define EFAULT 14 /* Bad address */ -#define ENOTBLK 15 /* Block device required */ #define EBUSY 16 /* Device or resource busy */ #define EEXIST 17 /* File exists */ -#define EXDEV 18 /* Cross-device link */ -#define ENODEV 19 /* No such device */ -#define ENOTDIR 20 /* Not a directory */ -#define EISDIR 21 /* Is a directory */ #define EINVAL 22 /* Invalid argument */ #define ENFILE 23 /* File table overflow */ -#define EMFILE 24 /* Too many open files */ -#define ENOTTY 25 /* Not a typewriter */ -#define ETXTBSY 26 /* Text file busy */ -#define EFBIG 27 /* File too large */ -#define ENOSPC 28 /* No space left on device */ -#define ESPIPE 29 /* Illegal seek */ -#define EROFS 30 /* Read-only file system */ -#define EMLINK 31 /* Too many links */ -#define EPIPE 32 /* Broken pipe */ -#define EDOM 33 /* Math argument out of domain of func */ -#define ERANGE 34 /* Math result not representable */ -#define ENOMSG 35 /* No message of desired type */ -#define EIDRM 36 /* Identifier removed */ -#define ECHRNG 37 /* Channel number out of range */ -#define EL2NSYNC 38 /* Level 2 not synchronized */ -#define EL3HLT 39 /* Level 3 halted */ -#define EL3RST 40 /* Level 3 reset */ -#define ELNRNG 41 /* Link number out of range */ -#define EUNATCH 42 /* Protocol driver not attached */ -#define ENOCSI 43 /* No CSI structure available */ -#define EL2HLT 44 /* Level 2 halted */ #define EDEADLK 45 /* Resource deadlock would occur */ -#define ENOLCK 46 /* No record locks available */ -#define EBADE 50 /* Invalid exchange */ -#define EBADR 51 /* Invalid request descriptor */ -#define EXFULL 52 /* Exchange full */ -#define ENOANO 53 /* No anode */ -#define EBADRQC 54 /* Invalid request code */ -#define EBADSLT 55 /* Invalid slot */ -#define EDEADLOCK 56 /* File locking deadlock error */ -#define EBFONT 59 /* Bad font file format */ -#define ENOSTR 60 /* Device not a stream */ -#define ENODATA 61 /* No data available */ -#define ETIME 62 /* Timer expired */ -#define ENOSR 63 /* Out of streams resources */ -#define ENONET 64 /* Machine is not on the network */ -#define ENOPKG 65 /* Package not installed */ -#define EREMOTE 66 /* Object is remote */ -#define ENOLINK 67 /* Link has been severed */ -#define EADV 68 /* Advertise error */ -#define ESRMNT 69 /* Srmount error */ -#define ECOMM 70 /* Communication error on send */ -#define EPROTO 71 /* Protocol error */ -#define EDOTDOT 73 /* RFS specific error */ -#define EMULTIHOP 74 /* Multihop attempted */ #define EBADMSG 77 /* Not a data message */ -#define ENAMETOOLONG 78 /* File name too long */ -#define EOVERFLOW 79 /* Value too large for defined data type */ -#define ENOTUNIQ 80 /* Name not unique on network */ -#define EBADFD 81 /* File descriptor in bad state */ -#define EREMCHG 82 /* Remote address changed */ -#define ELIBACC 83 /* Can not access a needed shared library */ -#define ELIBBAD 84 /* Accessing a corrupted shared library */ -#define ELIBSCN 85 /* .lib section in a.out corrupted */ -#define ELIBMAX 86 /* Attempting to link in too many shared libraries */ -#define ELIBEXEC 87 /* Cannot exec a shared library directly */ -#define EILSEQ 88 /* Illegal byte sequence */ #define ENOSYS 89 /* Function not implemented */ -#define ELOOP 90 /* Too many symbolic links encountered */ -#define ERESTART 91 /* Interrupted system call should be restarted */ -#define ESTRPIPE 92 /* Streams pipe error */ -#define ENOTEMPTY 93 /* Directory not empty */ -#define EUSERS 94 /* Too many users */ -#define ENOTSOCK 95 /* Socket operation on non-socket */ -#define EDESTADDRREQ 96 /* Destination address required */ -#define EMSGSIZE 97 /* Message too long */ -#define EPROTOTYPE 98 /* Protocol wrong type for socket */ -#define ENOPROTOOPT 99 /* Protocol not available */ -#define EPROTONOSUPPORT 120 /* Protocol not supported */ -#define ESOCKTNOSUPPORT 121 /* Socket type not supported */ #define EOPNOTSUPP 122 /* Operation not supported on transport endpoint */ -#define ENOTSUP EOPNOTSUPP/* Operation not supported on transport endpoint */ -#define EPFNOSUPPORT 123 /* Protocol family not supported */ -#define EAFNOSUPPORT 124 /* Address family not supported by protocol */ -#define EADDRINUSE 125 /* Address already in use */ -#define EADDRNOTAVAIL 126 /* Cannot assign requested address */ -#define ENETDOWN 127 /* Network is down */ -#define ENETUNREACH 128 /* Network is unreachable */ -#define ENETRESET 129 /* Network dropped connection because of reset */ -#define ECONNABORTED 130 /* Software caused connection abort */ -#define ECONNRESET 131 /* Connection reset by peer */ -#define ENOBUFS 132 /* No buffer space available */ -#define EISCONN 133 /* Transport endpoint is already connected */ -#define ENOTCONN 134 /* Transport endpoint is not connected */ -#define EUCLEAN 135 /* Structure needs cleaning */ -#define ENOTNAM 137 /* Not a XENIX named type file */ -#define ENAVAIL 138 /* No XENIX semaphores available */ -#define EISNAM 139 /* Is a named type file */ -#define EREMOTEIO 140 /* Remote I/O error */ -#define EINIT 141 /* Reserved */ -#define EREMDEV 142 /* Error 142 */ -#define ESHUTDOWN 143 /* Cannot send after transport endpoint shutdown */ -#define ETOOMANYREFS 144 /* Too many references: cannot splice */ #define ETIMEDOUT 145 /* Connection timed out */ -#define ECONNREFUSED 146 /* Connection refused */ -#define EHOSTDOWN 147 /* Host is down */ -#define EHOSTUNREACH 148 /* No route to host */ -#define EWOULDBLOCK EAGAIN /* Operation would block */ -#define EALREADY 149 /* Operation already in progress */ -#define EINPROGRESS 150 /* Operation now in progress */ -#define ESTALE 151 /* Stale NFS file handle */ -#define ECANCELED 158 /* AIO operation canceled */ -#define ENOMEDIUM 159 /* No medium found */ -#define EMEDIUMTYPE 160 /* Wrong medium type */ -#define ENOKEY 161 /* Required key not available */ -#define EKEYEXPIRED 162 /* Key has expired */ -#define EKEYREVOKED 163 /* Key has been revoked */ -#define EKEYREJECTED 164 /* Key was rejected by service */ -#define EDQUOT 1133 /* Quota exceeded */ +#endif #ifdef RT_USING_DFS #include diff --git a/components/pthreads/pthread.c b/components/pthreads/pthread.c index a823253d48..41432f760f 100644 --- a/components/pthreads/pthread.c +++ b/components/pthreads/pthread.c @@ -347,13 +347,13 @@ RTM_EXPORT(pthread_once); int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) { - return ENOTSUP; + return EOPNOTSUPP; } RTM_EXPORT(pthread_atfork); int pthread_kill(pthread_t thread, int sig) { - return ENOTSUP; + return EOPNOTSUPP; } RTM_EXPORT(pthread_kill); diff --git a/components/pthreads/pthread_attr.c b/components/pthreads/pthread_attr.c index 9b84935a83..3e0f7b1e4c 100644 --- a/components/pthreads/pthread_attr.c +++ b/components/pthreads/pthread_attr.c @@ -151,7 +151,7 @@ int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack_addr) { RT_ASSERT(attr != RT_NULL); - return ENOTSUP; + return EOPNOTSUPP; } RTM_EXPORT(pthread_attr_setstackaddr); @@ -159,7 +159,7 @@ int pthread_attr_getstackaddr(pthread_attr_t const *attr, void **stack_addr) { RT_ASSERT(attr != RT_NULL); - return ENOTSUP; + return EOPNOTSUPP; } RTM_EXPORT(pthread_attr_getstackaddr); @@ -191,12 +191,12 @@ RTM_EXPORT(pthread_attr_getstack); int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guard_size) { - return ENOTSUP; + return EOPNOTSUPP; } int pthread_attr_getguardsize(pthread_attr_t const *attr, size_t *guard_size) { - return ENOTSUP; + return EOPNOTSUPP; } RTM_EXPORT(pthread_attr_getguardsize); @@ -205,7 +205,7 @@ int pthread_attr_setscope(pthread_attr_t *attr, int scope) if (scope == PTHREAD_SCOPE_SYSTEM) return 0; if (scope == PTHREAD_SCOPE_PROCESS) - return ENOTSUP; + return EOPNOTSUPP; return EINVAL; } diff --git a/components/pthreads/sched.c b/components/pthreads/sched.c index 83810cd8aa..6f75127bf2 100644 --- a/components/pthreads/sched.c +++ b/components/pthreads/sched.c @@ -51,6 +51,6 @@ RTM_EXPORT(sched_get_priority_max); int sched_setscheduler(pid_t pid, int policy) { - return ENOTSUP; + return EOPNOTSUPP; } RTM_EXPORT(sched_setscheduler); From 444b928d2247a7dc980cce7852bf74aeb5bb6bc3 Mon Sep 17 00:00:00 2001 From: bernard Date: Wed, 12 Mar 2014 08:47:10 +0800 Subject: [PATCH 50/59] Add more command to msh for module. --- components/finsh/cmd.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/components/finsh/cmd.c b/components/finsh/cmd.c index 0613452279..9a79ba396b 100644 --- a/components/finsh/cmd.c +++ b/components/finsh/cmd.c @@ -516,8 +516,8 @@ int list_module(void) return 0; } - -FINSH_FUNCTION_EXPORT(list_module, list module in system) +FINSH_FUNCTION_EXPORT(list_module, list module in system); +MSH_CMD_EXPORT(list_module, list module in system); int list_mod_detail(const char *name) { @@ -536,7 +536,7 @@ int list_mod_detail(const char *name) /* list main thread in module */ if (module->module_thread != RT_NULL) - { + { rt_kprintf("main thread pri status sp stack size max used left tick error\n"); rt_kprintf("------------- ---- ------- ---------- ---------- ---------- ---------- ---\n"); thread = module->module_thread; @@ -555,7 +555,7 @@ int list_mod_detail(const char *name) thread->stack_size - ((rt_uint32_t) ptr - (rt_uint32_t)thread->stack_addr), thread->remaining_tick, thread->error); - } + } /* list sub thread in module */ tlist = &module->module_object[RT_Object_Class_Thread].object_list; @@ -605,20 +605,24 @@ int list_mod_detail(const char *name) if (!rt_list_isempty(tlist)) _list_timer(tlist); } - rt_kprintf("symbol address \n"); - rt_kprintf("-------- ----------\n"); - - /* list module export symbols */ - for (i=0; insym; i++) - { - rt_kprintf("%s 0x%x\n", - module->symtab[i].name, module->symtab[i].addr); - } + if (module->nsym > 0) + { + rt_kprintf("symbol address \n"); + rt_kprintf("-------- ----------\n"); + + /* list module export symbols */ + for (i=0; insym; i++) + { + rt_kprintf("%s 0x%x\n", + module->symtab[i].name, module->symtab[i].addr); + } + } } return 0; } FINSH_FUNCTION_EXPORT(list_mod_detail, list module objects in system) +MSH_CMD_EXPORT(list_mod_detail, list module objects in system) #endif long list(void) From 04b5a461799f9be12c72b67a2da87163478fb5d6 Mon Sep 17 00:00:00 2001 From: bernard Date: Wed, 12 Mar 2014 16:25:59 +0800 Subject: [PATCH 51/59] [Finsh] fix the shell prompt issue. --- components/finsh/shell.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/finsh/shell.c b/components/finsh/shell.c index 0f1e1c625e..4313fcf6b2 100644 --- a/components/finsh/shell.c +++ b/components/finsh/shell.c @@ -60,14 +60,16 @@ const char* finsh_get_prompt() { #define _MSH_PROMPT "msh " #define _PROMPT "finsh " - static char finsh_prompt[RT_CONSOLEBUF_SIZE + 1] = {_PROMPT}; + static char finsh_prompt[RT_CONSOLEBUF_SIZE + 1] = {0}; #ifdef FINSH_USING_MSH if (msh_is_used()) strcpy(finsh_prompt, _MSH_PROMPT); + else #endif + strcpy(finsh_prompt, _PROMPT); /* get current working directory */ - getcwd(&finsh_prompt[rt_strlen(finsh_prompt)], RT_CONSOLEBUF_SIZE - 8); + getcwd(&finsh_prompt[rt_strlen(finsh_prompt)], RT_CONSOLEBUF_SIZE - rt_strlen(finsh_prompt)); strcat(finsh_prompt, ">"); return finsh_prompt; From c20ec19a962e537d6a55048b48bb044c03dfda9e Mon Sep 17 00:00:00 2001 From: nongxiaoming Date: Tue, 11 Mar 2014 11:28:22 +0800 Subject: [PATCH 52/59] modify the pixel format to RGB565 in sdl_fb.c --- bsp/simulator/drivers/sdl_fb.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bsp/simulator/drivers/sdl_fb.c b/bsp/simulator/drivers/sdl_fb.c index 84076b757f..198b85d0d9 100755 --- a/bsp/simulator/drivers/sdl_fb.c +++ b/bsp/simulator/drivers/sdl_fb.c @@ -56,7 +56,7 @@ static rt_err_t sdlfb_control(rt_device_t dev, rt_uint8_t cmd, void *args) info = (struct rt_device_graphic_info *) args; info->bits_per_pixel = 16; - info->pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565P; + info->pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565; info->framebuffer = device->screen->pixels; info->width = device->screen->w; info->height = device->screen->h; @@ -306,8 +306,12 @@ static void *sdl_loop(void *lpParam) break; } - if (quit) - break; + if (quit) + { + exit(1); + break; + } + } rt_hw_exit(); return 0; From 6289a1aa25ebe292cad744fa614ef85438842bc1 Mon Sep 17 00:00:00 2001 From: bernard Date: Mon, 24 Mar 2014 14:50:47 +0800 Subject: [PATCH 53/59] Add UA building script. --- tools/building.py | 38 +++++++++++++++++++-------- tools/ua.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 11 deletions(-) create mode 100644 tools/ua.py diff --git a/tools/building.py b/tools/building.py index 6427e7c0dd..54193fcf2f 100644 --- a/tools/building.py +++ b/tools/building.py @@ -145,7 +145,7 @@ def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = [ AddOption('--target', dest='target', type='string', - help='set target project: mdk/iar/vs') + help='set target project: mdk/iar/vs/ua') #{target_name:(CROSS_TOOL, PLATFORM)} tgt_dict = {'mdk':('keil', 'armcc'), @@ -153,7 +153,8 @@ def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = [ 'iar':('iar', 'iar'), 'vs':('msvc', 'cl'), 'vs2012':('msvc', 'cl'), - 'cb':('keil', 'armcc')} + 'cb':('keil', 'armcc'), + 'ua':('keil', 'armcc')} tgt_name = GetOption('target') if tgt_name: # --target will change the toolchain settings which clang-analyzer is @@ -209,17 +210,25 @@ def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = [ return objs def PrepareModuleBuilding(env, root_directory): - import SCons.cpp import rtconfig - global BuildOptions - global Projects global Env global Rtt_Root Env = env Rtt_Root = root_directory + # add build/clean library option for library checking + AddOption('--buildlib', + dest='buildlib', + type='string', + help='building library of a component') + AddOption('--cleanlib', + dest='cleanlib', + action='store_true', + default=False, + help='clean up the library by --buildlib') + # add program path env.PrependENVPath('PATH', rtconfig.EXEC_PATH) @@ -418,16 +427,13 @@ def DoBuilding(target, objects): def EndBuilding(target, program = None): import rtconfig - from keil import MDKProject - from keil import MDK4Project - from iar import IARProject - from vs import VSProject - from vs2012 import VS2012Project - from codeblocks import CBProject Env.AddPostAction(target, rtconfig.POST_ACTION) if GetOption('target') == 'mdk': + from keil import MDKProject + from keil import MDK4Project + template = os.path.isfile('template.Uv2') if template: MDKProject('project.Uv2', Projects) @@ -439,20 +445,30 @@ def EndBuilding(target, program = None): print 'No template project file found.' if GetOption('target') == 'mdk4': + from keil import MDKProject + from keil import MDK4Project MDK4Project('project.uvproj', Projects) if GetOption('target') == 'iar': + from iar import IARProject IARProject('project.ewp', Projects) if GetOption('target') == 'vs': + from vs import VSProject VSProject('project.vcproj', Projects, program) if GetOption('target') == 'vs2012': + from vs2012 import VS2012Project VS2012Project('project.vcxproj', Projects, program) if GetOption('target') == 'cb': + from codeblocks import CBProject CBProject('project.cbp', Projects, program) + if GetOption('target') == 'ua': + from ua import PrepareUA + PrepareUA(Projects, Rtt_Root, str(Dir('#'))) + if GetOption('copy') and program != None: MakeCopy(program) if GetOption('copy-header') and program != None: diff --git a/tools/ua.py b/tools/ua.py new file mode 100644 index 0000000000..89d3190e23 --- /dev/null +++ b/tools/ua.py @@ -0,0 +1,66 @@ +import os +import sys +from utils import _make_path_relative + +def PrefixPath(prefix, path): + path = os.path.abspath(path) + prefix = os.path.abspath(prefix) + + if sys.platform == 'win32': + prefix = prefix.lower() + path = path.lower() + + if path.startswith(prefix): + return True + + return False + +def PrepareUA(project, RTT_ROOT, BSP_ROOT): + with open('rtua.py', 'w') as ua: + # ua.write('import os\n') + # ua.write('import sys\n') + ua.write('\n') + + print RTT_ROOT + + CPPPATH = [] + CPPDEFINES = [] + + for group in project: + # get each include path + if group.has_key('CPPPATH') and group['CPPPATH']: + CPPPATH += group['CPPPATH'] + + # get each group's definitions + if group.has_key('CPPDEFINES') and group['CPPDEFINES']: + CPPDEFINES += group['CPPDEFINES'] + + if len(CPPPATH): + # remove repeat path + paths = [i for i in set(CPPPATH)] + CPPPATH = [] + for path in paths: + if PrefixPath(RTT_ROOT, path): + CPPPATH += ['RTT_ROOT + "/%s",' % _make_path_relative(RTT_ROOT, path).replace('\\', '/')] + + elif PrefixPath(BSP_ROOT, path): + CPPPATH += ['BSP_ROOT + "/%s",' % _make_path_relative(RTT_ROOT, path).replace('\\', '/')] + else: + CPPPATH += ['"%s",' % path.replace('\\', '/')] + + CPPPATH.sort() + ua.write('def GetCPPPATH(BSP_ROOT, RTT_ROOT):\n') + ua.write('\tCPPPATH=[\n') + for path in CPPPATH: + ua.write('\t\t%s\n' % path) + ua.write('\t]\n\n') + ua.write('\treturn CPPPATH\n\n') + + if len(CPPDEFINES): + CPPDEFINES = [i for i in set(CPPDEFINES)] + + ua.write('def GetCPPDEFINES():\n') + ua.write('\tCPPDEFINES=%s\n' % str(CPPDEFINES)) + ua.write('\treturn CPPDEFINES\n\n') + + print CPPDEFINES From de16b800a4e94e39c9e97e95eac15d3eb223a36d Mon Sep 17 00:00:00 2001 From: bernard Date: Tue, 25 Mar 2014 10:04:48 +0800 Subject: [PATCH 54/59] [scons] fix the BSP_ROOT issue in ua.py. --- tools/ua.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/ua.py b/tools/ua.py index 89d3190e23..ac3ea9061c 100644 --- a/tools/ua.py +++ b/tools/ua.py @@ -36,6 +36,10 @@ def PrepareUA(project, RTT_ROOT, BSP_ROOT): CPPDEFINES += group['CPPDEFINES'] if len(CPPPATH): + # use absolute path + for i in range(len(CPPPATH)): + CPPPATH[i] = os.path.abspath(CPPPATH[i]) + # remove repeat path paths = [i for i in set(CPPPATH)] CPPPATH = [] @@ -44,7 +48,7 @@ def PrepareUA(project, RTT_ROOT, BSP_ROOT): CPPPATH += ['RTT_ROOT + "/%s",' % _make_path_relative(RTT_ROOT, path).replace('\\', '/')] elif PrefixPath(BSP_ROOT, path): - CPPPATH += ['BSP_ROOT + "/%s",' % _make_path_relative(RTT_ROOT, path).replace('\\', '/')] + CPPPATH += ['BSP_ROOT + "/%s",' % _make_path_relative(BSP_ROOT, path).replace('\\', '/')] else: CPPPATH += ['"%s",' % path.replace('\\', '/')] From f9659283c0f357bc9559181ca303fecc6801c5e0 Mon Sep 17 00:00:00 2001 From: Grissiom Date: Thu, 27 Mar 2014 15:09:53 +0800 Subject: [PATCH 55/59] [msh] try to complete module path Msh can execute module directly. So try to auto-complete the path when user press TAB. There is a chance that the path is a module. --- components/finsh/msh.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/components/finsh/msh.c b/components/finsh/msh.c index ff3d92f359..f2b6d20860 100644 --- a/components/finsh/msh.c +++ b/components/finsh/msh.c @@ -316,7 +316,7 @@ void msh_auto_complete_path(char *path) if (full_path == RT_NULL) return; /* out of memory */ ptr = full_path; - if (*path != '/') + if (*path != '/') { getcwd(full_path, 256); if (full_path[rt_strlen(full_path) - 1] != '/') @@ -336,7 +336,7 @@ void msh_auto_complete_path(char *path) char *dest = index; /* fill the parent path */ - ptr = full_path; + ptr = full_path; while (*ptr) ptr ++; for (index = path; index != dest;) @@ -361,7 +361,7 @@ void msh_auto_complete_path(char *path) { dirent = readdir(dir); if (dirent == RT_NULL) break; - + rt_kprintf("%s\n", dirent->d_name); } } @@ -450,12 +450,21 @@ void msh_auto_complete(char *prefix) msh_auto_complete_path(ptr + 1); break; } - + ptr --; } +#ifdef RT_USING_MODULE + /* There is a chance that the user want to run the module directly. So + * try to complete the file names. If the completed path is not a + * module, the system won't crash anyway. */ + if (ptr == prefix) + { + msh_auto_complete_path(ptr); + } +#endif } #endif - + /* checks in internal command */ { for (index = _syscall_table_begin; index < _syscall_table_end; FINSH_NEXT_SYSCALL(index)) From c44f32e513569858e95f1aa4e9ab531b8577e398 Mon Sep 17 00:00:00 2001 From: Grissiom Date: Thu, 27 Mar 2014 16:15:56 +0800 Subject: [PATCH 56/59] [msh] cd to path when possible When DFS_USING_WORKDIR is enabled, msh will try to chdir if the command is not found. For example, if there is folder named "SD", and there is no `SD` command and `SD.mo` module, typing "SD" in msh will cd to the folder. In more detail, the execution order right now is: 1. built-in command 2. module 3. cd to path If you have a folder named "ps", you have to run `cd ps` to change the working dir. --- components/finsh/msh.c | 125 ++++++++++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 45 deletions(-) diff --git a/components/finsh/msh.c b/components/finsh/msh.c index f2b6d20860..354f884913 100644 --- a/components/finsh/msh.c +++ b/components/finsh/msh.c @@ -178,35 +178,37 @@ static cmd_function_t msh_get_cmd(char *cmd, int size) } #if defined(RT_USING_MODULE) && defined(RT_USING_DFS) +/* Return 0 on module executed. Other value indicate error. + */ int msh_exec_module(char* cmd_line, int size) { + int ret; int fd = -1; char *pg_name; int length, cmd_length = 0; - if (size == 0) return -RT_ERROR; /* no command */ - /* get the length of command0 */ - while ((cmd_line[cmd_length] != ' ' && cmd_line[cmd_length] != '\t') && cmd_length < size) - cmd_length ++; + if (size == 0) + return -RT_ERROR; + /* get the length of command0 */ + while ((cmd_line[cmd_length] != ' ' && cmd_line[cmd_length] != '\t') && cmd_length < size) + cmd_length ++; /* get name length */ length = cmd_length + 32; - /* allocate program name memory */ + /* allocate program name memory */ pg_name = (char*) rt_malloc(length); - if (pg_name == RT_NULL) return -RT_ENOMEM; /* no memory */ + if (pg_name == RT_NULL) + return -RT_ENOMEM; - /* copy command0 */ - memcpy(pg_name, cmd_line, cmd_length); - pg_name[cmd_length] = '\0'; + /* copy command0 */ + memcpy(pg_name, cmd_line, cmd_length); + pg_name[cmd_length] = '\0'; if (strstr(pg_name, ".mo") != RT_NULL || strstr(pg_name, ".MO") != RT_NULL) { /* try to open program */ - if (fd < 0) - { - fd = open(pg_name, O_RDONLY, 0); - } + fd = open(pg_name, O_RDONLY, 0); /* search in /bin path */ if (fd < 0) @@ -220,16 +222,13 @@ int msh_exec_module(char* cmd_line, int size) /* add .mo and open program */ /* try to open program */ - if (fd < 0) - { - strcat(pg_name, ".mo"); - fd = open(pg_name, O_RDONLY, 0); - } + strcat(pg_name, ".mo"); + fd = open(pg_name, O_RDONLY, 0); /* search in /bin path */ if (fd < 0) { - rt_snprintf(pg_name, length - 1, "/bin/%.*s.mo", cmd_length, cmd_line); + rt_snprintf(pg_name, length - 1, "/bin/%.*s.mo", cmd_length, cmd_line); fd = open(pg_name, O_RDONLY, 0); } } @@ -239,57 +238,93 @@ int msh_exec_module(char* cmd_line, int size) /* found program */ close(fd); rt_module_exec_cmd(pg_name, cmd_line, size); + ret = 0; } else { - rt_kprintf("%s: program not found.\n", cmd_line); + ret = -1; } rt_free(pg_name); - return 0; + return ret; } #endif -int msh_exec(char* cmd, rt_size_t length) +static int _msh_exec_cmd(char* cmd, rt_size_t length, int *retp) { int argc; - char *argv[RT_FINSH_ARG_MAX]; int cmd0_size = 0; cmd_function_t cmd_func; + char *argv[RT_FINSH_ARG_MAX]; - /* strim the beginning of command */ - while(*cmd == ' ' || *cmd == '\t'){cmd++; length--;} - /* find the size of first command */ + RT_ASSERT(cmd); + RT_ASSERT(retp); + + /* find the size of first command */ while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length) cmd0_size ++; - if (cmd0_size == 0) return -1; /* no command found */ + if (cmd0_size == 0) + return -RT_ERROR; - /* try to get built-in command */ cmd_func = msh_get_cmd(cmd, cmd0_size); if (cmd_func == RT_NULL) - { -#ifdef RT_USING_MODULE - msh_exec_module(cmd, length); -#else - argv[0] = cmd; - while(*cmd != ' ') - { - if (*cmd == 0) break; - cmd++; - } - if (*cmd == ' ') *cmd = 0; - rt_kprintf("%s: command not found.\n", argv[0]); -#endif - return -1; - } + return -RT_ERROR; /* split arguments */ memset(argv, 0x00, sizeof(argv)); argc = msh_split(cmd, length, argv); - if (argc == 0) return -1; + if (argc == 0) + return -RT_ERROR; /* exec this command */ - return cmd_func(argc, argv); + *retp = cmd_func(argc, argv); + return 0; +} + +int msh_exec(char* cmd, rt_size_t length) +{ + int cmd_ret; + + /* strim the beginning of command */ + while(*cmd == ' ' || *cmd == '\t') + { + cmd++; + length--; + } + + /* Exec sequence: + * 1. built-in command + * 2. module(if enabled) + * 3. chdir to the directry(if possible) + */ + if (_msh_exec_cmd(cmd, length, &cmd_ret) == 0) + { + return cmd_ret; + } +#ifdef RT_USING_MODULE + if (msh_exec_module(cmd, length) == 0) + { + return 0; + } +#endif +#ifdef DFS_USING_WORKDIR + if (chdir(cmd) == 0) + { + return 0; + } +#endif + /* truncate the cmd at the first space. */ + { + char *tcmd; + tcmd = cmd; + while(*tcmd != ' ' && *tcmd != '\0') + { + tcmd++; + } + *tcmd = '\0'; + } + rt_kprintf("%s: command not found.\n", cmd); + return -1; } static int str_common(const char *str1, const char *str2) From 7d2b7199d8d82848f621d0493540b13c9d9841e9 Mon Sep 17 00:00:00 2001 From: bernard Date: Sat, 29 Mar 2014 08:45:26 +0800 Subject: [PATCH 57/59] Add PNG_ABORT for libpng; Add format field in tjpgd; --- components/external/libpng/pngconf.h | 2 ++ components/external/tjpgd1a/tjpgd.c | 5 +++-- components/external/tjpgd1a/tjpgd.h | 8 ++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/components/external/libpng/pngconf.h b/components/external/libpng/pngconf.h index 047376302d..bb0a189f9d 100644 --- a/components/external/libpng/pngconf.h +++ b/components/external/libpng/pngconf.h @@ -23,6 +23,8 @@ #include #define PNG_MAX_MALLOC_64K #define PNG_NO_STDIO +#define PNG_NO_ERROR_NUMBERS +#define PNG_ABORT() do { rt_kprintf("libpng abort.\n"); } while (0) #ifndef RT_USING_NEWLIB #define PNG_NO_WRITE_SUPPORTED diff --git a/components/external/tjpgd1a/tjpgd.c b/components/external/tjpgd1a/tjpgd.c index 9c69989ced..4817f92b54 100644 --- a/components/external/tjpgd1a/tjpgd.c +++ b/components/external/tjpgd1a/tjpgd.c @@ -525,7 +525,7 @@ JRESULT mcu_load ( } while (++i < 64); /* Next AC element */ if (JD_USE_SCALE && jd->scale == 3) - *bp = (*tmp / 256) + 128; /* If scale ratio is 1/8, IDCT can be ommited and only DC element is used */ + *bp = (BYTE)((*tmp / 256) + 128); /* If scale ratio is 1/8, IDCT can be ommited and only DC element is used */ else block_idct(tmp, bp); /* Apply IDCT and store the block to the MCU buffer */ @@ -669,7 +669,7 @@ JRESULT mcu_output ( } /* Convert RGB888 to RGB565 if needed */ - if (JD_FORMAT == 1) { + if (jd->format == 1) { BYTE *s = (BYTE*)jd->workbuf; WORD w, *d = (WORD*)s; UINT n = rx * ry; @@ -762,6 +762,7 @@ JRESULT jd_prepare ( jd->infunc = infunc; /* Stream input function */ jd->device = dev; /* I/O device identifier */ jd->nrst = 0; /* No restart interval (default) */ + jd->format = 0; /* use RGB888 (3 BYTE/pix) default */ for (i = 0; i < 2; i++) { /* Nulls pointers */ for (j = 0; j < 2; j++) { diff --git a/components/external/tjpgd1a/tjpgd.h b/components/external/tjpgd1a/tjpgd.h index 07a9174196..ee84cd2d2e 100644 --- a/components/external/tjpgd1a/tjpgd.h +++ b/components/external/tjpgd1a/tjpgd.h @@ -4,10 +4,8 @@ /* System Configurations */ -#define JD_SZBUF 512 /* Size of stream input buffer (should be multiple of 512) */ -#define JD_FORMAT 1 /* Output RGB format 0:RGB888 (3 BYTE/pix), 1:RGB565 (1 WORD/pix) */ -#define JD_USE_SCALE 1 /* Use descaling feature for output */ - +#define JD_SZBUF (16 * 1024) /* Size of stream input buffer (should be multiple of 512) */ +#define JD_USE_SCALE 0 /* Use descaling feature for output */ /*---------------------------------------------------------------------------*/ @@ -57,6 +55,8 @@ struct JDEC { UINT (*infunc)(JDEC*, BYTE*, UINT);/* Pointer to jpeg stream input function */ UINT (*outfunc)(JDEC*, void*, JRECT*); /* Pointer to RGB output function */ void* device; /* Pointer to I/O device identifiler for the session */ + + BYTE format; /* the output format, 0:RGB888 (3 BYTE/pix), 1:RGB565 (1 WORD/pix) */ }; From 0979328fb1f7ab43c92b418bdb5111e1b828e301 Mon Sep 17 00:00:00 2001 From: Grissiom Date: Sat, 29 Mar 2014 11:33:20 +0800 Subject: [PATCH 58/59] [msh] don't complain on empty command Just branch out and no complain on command length == 0; --- components/finsh/msh.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/finsh/msh.c b/components/finsh/msh.c index 354f884913..1492e017e1 100644 --- a/components/finsh/msh.c +++ b/components/finsh/msh.c @@ -292,6 +292,9 @@ int msh_exec(char* cmd, rt_size_t length) length--; } + if (length == 0) + return 0; + /* Exec sequence: * 1. built-in command * 2. module(if enabled) From 40b7eba4461d1cfb21496e92caae1231321f94be Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Sat, 29 Mar 2014 14:59:02 +0800 Subject: [PATCH 59/59] [Kernel] Change the version number to 2.0.0. --- include/rtdef.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/rtdef.h b/include/rtdef.h index e24c2fa85b..e6b302d298 100644 --- a/include/rtdef.h +++ b/include/rtdef.h @@ -48,8 +48,8 @@ extern "C" { /*@{*/ /* RT-Thread version information */ -#define RT_VERSION 1L /**< major version number */ -#define RT_SUBVERSION 2L /**< minor version number */ +#define RT_VERSION 2L /**< major version number */ +#define RT_SUBVERSION 0L /**< minor version number */ #define RT_REVISION 0L /**< revise version number */ /* RT-Thread version */