From 629e8893e32888e67e225171428001ffcc6784fe Mon Sep 17 00:00:00 2001 From: TXuian <1163589503@qq.com> Date: Tue, 15 Nov 2022 07:45:21 -0800 Subject: [PATCH] add w5500 support. --- .../XiZi_IIoT/board/xidatong-riscv64/board.c | 255 +- .../third_party_driver/Kconfig | 16 + .../third_party_driver/Makefile | 8 + .../third_party_driver/ethernet/Kconfig | 15 + .../third_party_driver/ethernet/Makefile | 3 + .../third_party_driver/ethernet/ReadMe.md | 24 + .../ethernet/connect_w5500.c | 455 ++++ .../ethernet/imgs/client0.png | Bin 0 -> 80399 bytes .../ethernet/imgs/client1.png | Bin 0 -> 107737 bytes .../ethernet/imgs/ping baidu.png | Bin 0 -> 39956 bytes .../ethernet/imgs/ping w5500.png | Bin 0 -> 52638 bytes .../ethernet/imgs/server0.png | Bin 0 -> 85897 bytes .../ethernet/imgs/server1.png | Bin 0 -> 9689 bytes .../third_party_driver/ethernet/socket.c | 912 +++++++ .../ethernet/spi_interface.c | 35 + .../third_party_driver/ethernet/w5500.c | 255 ++ .../third_party_driver/ethernet/wiz_ping.c | 251 ++ .../third_party_driver/ethernet/wiz_ping.h | 35 + .../ethernet/wizchip_conf.c | 862 ++++++ .../third_party_driver/gpio/drv_io_config.c | 139 +- .../third_party_driver/gpio/gpio.c | 1 + .../third_party_driver/include/connect_spi.h | 36 + .../include/connect_w5500.h | 38 + .../include/drv_io_config.h | 83 +- .../third_party_driver/include/hardware_spi.h | 494 ++++ .../third_party_driver/include/socket.h | 585 +++++ .../third_party_driver/include/w5500.h | 2321 +++++++++++++++++ .../third_party_driver/include/wizchip_conf.h | 704 +++++ .../third_party_driver/spi/Kconfig | 66 + .../third_party_driver/spi/Makefile | 3 + .../third_party_driver/spi/connect_spi.c | 517 ++++ .../third_party_driver/spi/hardware_spi.c | 1523 +++++++++++ 32 files changed, 9407 insertions(+), 229 deletions(-) create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/Kconfig create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/Makefile create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/ReadMe.md create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/connect_w5500.c create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/imgs/client0.png create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/imgs/client1.png create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/imgs/ping baidu.png create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/imgs/ping w5500.png create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/imgs/server0.png create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/imgs/server1.png create mode 100755 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/socket.c create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/spi_interface.c create mode 100755 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/w5500.c create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/wiz_ping.c create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/wiz_ping.h create mode 100755 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/wizchip_conf.c create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/connect_spi.h create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/connect_w5500.h create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/hardware_spi.h create mode 100755 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/socket.h create mode 100755 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/w5500.h create mode 100755 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/wizchip_conf.h create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/spi/Kconfig create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/spi/Makefile create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/spi/connect_spi.c create mode 100644 Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/spi/hardware_spi.c diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/board.c b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/board.c index 337c5e468..fcb181c3b 100644 --- a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/board.c +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/board.c @@ -14,212 +14,225 @@ */ /** -* @file board.c -* @brief support kd233-board init configure and start-up -* @version 1.0 -* @author AIIT XUOS Lab -* @date 2022-07-25 -*/ + * @file board.c + * @brief support kd233-board init configure and start-up + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2022-07-25 + */ /************************************************* File name: board.c -Description: support xidatong-riscv64-board init configure and driver/task/... init -Others: https://canaan-creative.com/developer -History: +Description: support xidatong-riscv64-board init configure and driver/task/... +init Others: https://canaan-creative.com/developer History: 1. Date: 2022-07-25 Author: AIIT XUOS Lab -Modification: +Modification: 1. support xidatong-riscv64-board InitBoardHardware 2. support xidatong-riscv64-board Kd233Start 3. support xidatong-riscv64-board shell cmd, include reboot, shutdown *************************************************/ -#include -#include -#include #include "board.h" -#include "tick.h" +#include "connect_gpio.h" +#include "connect_spi.h" #include "connect_uart.h" +#include "connect_w5500.h" +#include "dmac.h" #include "encoding.h" #include "fpioa.h" -#include "dmac.h" -#include "connect_gpio.h" +#include "tick.h" +#include +#include +#include #if defined(FS_VFS) #include #endif -#define CPU0 (0) -#define CPU1 (1) +#define CPU0 (0) +#define CPU1 (1) extern x_base cpu2_boot_flag; extern void entry(void); extern void SecondaryCpuCStart(void); extern int IoConfigInit(void); extern int HwI2cInit(void); extern int HwTouchInit(void); +extern int HwSpiInit(void); +extern int HwWiznetInit(void); extern int HwCh438Init(void); -#if defined(FS_VFS) && defined (MOUNT_SDCARD) +#if defined(FS_VFS) && defined(MOUNT_SDCARD) #include #include -extern SpiSdDeviceType SpiSdInit(struct Bus *bus, const char *dev_name, const char *drv_name, const char *sd_name); +extern SpiSdDeviceType SpiSdInit(struct Bus *bus, const char *dev_name, + const char *drv_name, const char *sd_name); /** * @description: Mount SD card * @return 0 */ -int MountSDCard(void) -{ - struct Bus *spi_bus; - spi_bus = BusFind(SPI_BUS_NAME_1); - - if (NONE == SpiSdInit(spi_bus, SPI_1_DEVICE_NAME_0, SPI_1_DRV_NAME, SPI_SD_NAME)) { - KPrintf("MountSDCard SpiSdInit error!\n"); - return 0; - } - - if (EOK == MountFilesystem(SPI_BUS_NAME_1, SPI_SD_NAME, SPI_1_DRV_NAME, FSTYPE_FATFS, "/")) - KPrintf("SPI SD card fatfs mounted\n"); +int MountSDCard(void) { + struct Bus *spi_bus; + spi_bus = BusFind(SPI_BUS_NAME_1); + if (NONE == + SpiSdInit(spi_bus, SPI_1_DEVICE_NAME_0, SPI_1_DRV_NAME, SPI_SD_NAME)) { + KPrintf("MountSDCard SpiSdInit error!\n"); return 0; + } + + if (EOK == MountFilesystem(SPI_BUS_NAME_1, SPI_SD_NAME, SPI_1_DRV_NAME, + FSTYPE_FATFS, "/")) + KPrintf("SPI SD card fatfs mounted\n"); + + return 0; } #endif -void InitBss(void) -{ - unsigned int *dst; +void InitBss(void) { + unsigned int *dst; - dst = &__bss_start; - while (dst < &__bss_end){ - *dst++ = 0; - } + dst = &__bss_start; + while (dst < &__bss_end) { + *dst++ = 0; + } } -void Kd233Start(uint32_t mhartid) -{ - switch(mhartid) { - case CPU0: - InitBss(); +void Kd233Start(uint32_t mhartid) { + switch (mhartid) { + case CPU0: + InitBss(); - /*kernel start entry*/ - entry(); - break; - case CPU1: - while(0x2018050420191010 != cpu2_boot_flag) { ///< waiting for boot flag ,then start cpu1 core + /*kernel start entry*/ + entry(); + break; + case CPU1: + while (0x2018050420191010 != + cpu2_boot_flag) { ///< waiting for boot flag ,then start cpu1 core #ifndef ARCH_SMP - asm volatile("wfi"); + asm volatile("wfi"); #endif - } + } #ifdef ARCH_SMP - SecondaryCpuCStart(); + SecondaryCpuCStart(); #endif - break; + break; - default: - break; - } + default: + break; + } } -int Freq(void) -{ - uint64 value = 0; +int Freq(void) { + uint64 value = 0; - value = SysctlClockGetFreq(SYSCTL_CLOCK_PLL0); - KPrintf("PLL0: %d\n", value); - value = SysctlClockGetFreq(SYSCTL_CLOCK_PLL1); - KPrintf("PLL1: %d\n", value); - value = SysctlClockGetFreq(SYSCTL_CLOCK_PLL2); - KPrintf("PLL2: %d\n", value); - value = SysctlClockGetFreq(SYSCTL_CLOCK_CPU); - KPrintf("CPU : %d\n", value); - value = SysctlClockGetFreq(SYSCTL_CLOCK_APB0); - KPrintf("APB0: %d\n", value); - value = SysctlClockGetFreq(SYSCTL_CLOCK_APB1); - KPrintf("APB1: %d\n", value); - value = SysctlClockGetFreq(SYSCTL_CLOCK_APB2); - KPrintf("APB2: %d\n", value); - value = SysctlClockGetFreq(SYSCTL_CLOCK_HCLK); - KPrintf("HCLK: %d\n", value); + value = SysctlClockGetFreq(SYSCTL_CLOCK_PLL0); + KPrintf("PLL0: %d\n", value); + value = SysctlClockGetFreq(SYSCTL_CLOCK_PLL1); + KPrintf("PLL1: %d\n", value); + value = SysctlClockGetFreq(SYSCTL_CLOCK_PLL2); + KPrintf("PLL2: %d\n", value); + value = SysctlClockGetFreq(SYSCTL_CLOCK_CPU); + KPrintf("CPU : %d\n", value); + value = SysctlClockGetFreq(SYSCTL_CLOCK_APB0); + KPrintf("APB0: %d\n", value); + value = SysctlClockGetFreq(SYSCTL_CLOCK_APB1); + KPrintf("APB1: %d\n", value); + value = SysctlClockGetFreq(SYSCTL_CLOCK_APB2); + KPrintf("APB2: %d\n", value); + value = SysctlClockGetFreq(SYSCTL_CLOCK_HCLK); + KPrintf("HCLK: %d\n", value); - value = clint_get_time(); - KPrintf("mtime: %d\n", value); + value = clint_get_time(); + KPrintf("mtime: %d\n", value); - return 0; + return 0; } -SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0),Freq, Freq, show frequency information ); +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC) | + SHELL_CMD_PARAM_NUM(0), + Freq, Freq, show frequency information); #ifdef ARCH_SMP extern int EnableHwclintIpi(void); #endif -struct InitSequenceDesc _board_init[] = -{ +struct InitSequenceDesc _board_init[] = { #ifdef BSP_USING_GPIO - { "hw_pin", HwGpioInit }, - { "io_config", IoConfigInit }, + {"hw_pin", HwGpioInit}, + {"io_config", IoConfigInit}, #endif #ifdef BSP_USING_CH438 - { "hw_extuart", HwCh438Init }, + {"hw_extuart", HwCh438Init}, #endif #ifdef BSP_USING_I2C - { "hw_i2c", HwI2cInit }, + {"hw_i2c", HwI2cInit}, #endif #ifdef BSP_USING_TOUCH - {"touch", HwTouchInit }, + {"touch", HwTouchInit}, #endif - { " NONE ",NONE }, +#ifdef BSP_USING_SPI + {"spi", HwSpiInit}, +#endif +#ifdef BSP_USING_WIZCHIP + {"w5500", HwWiznetInit}, +#endif + {" NONE ", NONE}, }; -void InitBoardHardware(void) -{ - int i = 0; - int ret = 0; - - SysctlPllSetFreq(SYSCTL_PLL0, 800000000UL); - SysctlPllSetFreq(SYSCTL_PLL1, 400000000UL); +void InitBoardHardware(void) { + int i = 0; + int ret = 0; + + SysctlPllSetFreq(SYSCTL_PLL0, 800000000UL); + SysctlPllSetFreq(SYSCTL_PLL1, 400000000UL); #ifdef BSP_USING_GPIO - /* Init FPIOA */ - FpioaInit(); + /* Init FPIOA */ + FpioaInit(); #endif #ifdef BSP_USING_DMA - /* Dmac init */ - DmacInit(); + /* Dmac init */ + DmacInit(); #endif - /* initalize interrupt */ - InitHwinterrupt(); -#ifdef BSP_USING_UART - HwUartInit(); + /* initalize interrupt */ + InitHwinterrupt(); +#ifdef BSP_USING_UART + HwUartInit(); #endif - /* initialize memory system */ - InitBoardMemory(MEMORY_START_ADDRESS, MEMORY_END_ADDRESS); + /* initialize memory system */ + InitBoardMemory(MEMORY_START_ADDRESS, MEMORY_END_ADDRESS); #ifdef KERNEL_CONSOLE - /* set console device */ - InstallConsole(KERNEL_CONSOLE_BUS_NAME, KERNEL_CONSOLE_DRV_NAME, KERNEL_CONSOLE_DEVICE_NAME); - KPrintf("\nconsole init completed.\n"); - KPrintf("board initialization......\n"); + /* set console device */ + InstallConsole(KERNEL_CONSOLE_BUS_NAME, KERNEL_CONSOLE_DRV_NAME, + KERNEL_CONSOLE_DEVICE_NAME); + KPrintf("\nconsole init completed.\n"); + KPrintf("board initialization......\n"); #endif /* KERNEL_CONSOLE */ - InitHwTick(); + InitHwTick(); #ifdef ARCH_SMP - EnableHwclintIpi(); + EnableHwclintIpi(); #endif #ifdef KERNEL_COMPONENTS_INIT - for(i = 0; _board_init[i].fn != NONE; i++) { - ret = _board_init[i].fn(); - KPrintf("initialize %s %s\n",_board_init[i].fn_name, ret == 0 ? "success" : "failed"); - } + for (i = 0; _board_init[i].fn != NONE; i++) { + ret = _board_init[i].fn(); + KPrintf("initialize %s %s\n", _board_init[i].fn_name, + ret == 0 ? "success" : "failed"); + } #endif - KPrintf("board init done.\n"); - KPrintf("start kernel...\n"); + KPrintf("board init done.\n"); + KPrintf("start kernel...\n"); } -void HwCpuReset(void) -{ - sysctl->soft_reset.soft_reset = 1; - while(RET_TRUE); +void HwCpuReset(void) { + sysctl->soft_reset.soft_reset = 1; + while (RET_TRUE) + ; } -SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0),Reboot, HwCpuReset, reset machine ); +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC) | + SHELL_CMD_PARAM_NUM(0), + Reboot, HwCpuReset, reset machine); diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/Kconfig b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/Kconfig index c15389bf5..36d224d95 100755 --- a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/Kconfig +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/Kconfig @@ -20,6 +20,22 @@ if BSP_USING_GPIO source "$BSP_DIR/third_party_driver/gpio/Kconfig" endif +menuconfig BSP_USING_SPI +bool "Using SPI device" +default n +select RESOURCES_SPI +if BSP_USING_SPI +source "$BSP_DIR/third_party_driver/spi/Kconfig" +endif + +menuconfig BSP_USING_WIZCHIP +bool "Using w5500 as network device" +default n +select RESOURCES_WIZCHIP +if BSP_USING_WIZCHIP +source "$BSP_DIR/third_party_driver/ethernet/Kconfig" +endif + menuconfig BSP_USING_I2C bool "Using I2C device" default n diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/Makefile b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/Makefile index 4c330f3b3..575bdea6a 100644 --- a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/Makefile +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/Makefile @@ -16,6 +16,14 @@ ifeq ($(CONFIG_BSP_USING_I2C),y) SRC_DIR += i2c endif +ifeq ($(CONFIG_BSP_USING_SPI),y) + SRC_DIR += spi +endif + +ifeq ($(CONFIG_BSP_USING_WIZCHIP),y) + SRC_DIR += ethernet +endif + ifeq ($(CONFIG_BSP_USING_TOUCH),y) SRC_DIR += touch endif diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/Kconfig b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/Kconfig new file mode 100644 index 000000000..baf59367c --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/Kconfig @@ -0,0 +1,15 @@ +# Kconfig file + +config BSP_USING_W5500 +bool "Using w5500 " +default y + +# if BSP_USING_W5500 + config BSP_WIZ_RST_PIN + int + default 13 + + config BSP_WIZ_INT_PIN + int + default 14 +# endif \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/Makefile b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/Makefile new file mode 100644 index 000000000..1ea20caac --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := socket.c connect_w5500.c w5500.c wizchip_conf.c spi_interface.c wiz_ping.c + +include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/ReadMe.md b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/ReadMe.md new file mode 100644 index 000000000..486671711 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/ReadMe.md @@ -0,0 +1,24 @@ +## w5500 测试文档 + +通过board/xidatong-riscv64/third_party_driver/ethernet/connect_w5500.c 可以找到内写的3个,包含ping, tcp server test, tcp client test; + + - ping 测试,测试结果包括: + - pc ping w5500 + - w5500 ping baidu.com (DNS实现暂未实现,因此使用baidu.com的ip地址进行寻址) + + + + + +- tcp server 测试:在xizi中调用wiz_server_op,指定port,之后可以在pc中向该端口发送数据 + - wiz_server 将额外启动一个线程执行server工作,server将向client返回client发来的消息 + + + + + +- client 测试:通过wiz_client_op可以向pc中打开的tcp server发送消息 + + + + \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/connect_w5500.c b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/connect_w5500.c new file mode 100644 index 000000000..3b882e579 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/connect_w5500.c @@ -0,0 +1,455 @@ + +#include "connect_w5500.h" + +#include +#include +#include +#include +#include +#include + +#include "gpio_common.h" +#include "gpiohs.h" +#include "socket.h" +#include "w5500.h" + +#define SPI_LORA_FREQUENCY 10000000 + +// spi operations +extern void spi_enter_cris(void); +extern void spi_exit_cris(void); +extern void spi_select_cs(void); +extern void spi_deselete_cs(void); + +// global configurations for w5500 tcp connection +const uint32_t socket_tcp = 0; +const uint32_t g_wiznet_buf_size = 2048; + +static wiz_NetInfo g_wiz_netinfo = {.mac = {0x00, 0x08, 0xdc, 0x11, 0x11, 0x11}, + .ip = {192, 168, 31, 13}, + .sn = {255, 255, 255, 0}, + .gw = {192, 168, 31, 1}, + .dns = {0, 0, 0, 0}, + .dhcp = NETINFO_STATIC}; + +int network_init() { + wiz_NetInfo check_wiz_netinfo; + check_wiz_netinfo.dhcp = NETINFO_STATIC; + ctlnetwork(CN_SET_NETINFO, (void *)&g_wiz_netinfo); + ctlnetwork(CN_GET_NETINFO, (void *)&check_wiz_netinfo); + + if (memcmp(&g_wiz_netinfo, &check_wiz_netinfo, sizeof(wiz_NetInfo)) != 0) { + KPrintf( + "mac: %d; ip: %d; gw: %d; sn: %d; dns: %d; dhcp: %d;\n", + memcmp(&g_wiz_netinfo.mac, &check_wiz_netinfo.mac, sizeof(uint8_t) * 6), + memcmp(&g_wiz_netinfo.ip, &check_wiz_netinfo.ip, sizeof(uint8_t) * 4), + memcmp(&g_wiz_netinfo.sn, &check_wiz_netinfo.sn, sizeof(uint8_t) * 4), + memcmp(&g_wiz_netinfo.gw, &check_wiz_netinfo.gw, sizeof(uint8_t) * 4), + memcmp(&g_wiz_netinfo.dns, &check_wiz_netinfo.dns, sizeof(uint8_t) * 4), + memcmp(&g_wiz_netinfo.dhcp, &check_wiz_netinfo.dhcp, sizeof(uint8_t))); + KPrintf("WIZCHIP set network information fail.\n"); + return ERROR; + } + uint8_t tmpstr[6]; + ctlwizchip(CW_GET_ID, (void *)tmpstr); + KPrintf("=== %s NET CONF ===\r\n", (char *)tmpstr); + KPrintf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", g_wiz_netinfo.mac[0], + g_wiz_netinfo.mac[1], g_wiz_netinfo.mac[2], g_wiz_netinfo.mac[3], + g_wiz_netinfo.mac[4], g_wiz_netinfo.mac[5]); + KPrintf("SIP: %d.%d.%d.%d\r\n", g_wiz_netinfo.ip[0], g_wiz_netinfo.ip[1], + g_wiz_netinfo.ip[2], g_wiz_netinfo.ip[3]); + KPrintf("GAR: %d.%d.%d.%d\r\n", g_wiz_netinfo.gw[0], g_wiz_netinfo.gw[1], + g_wiz_netinfo.gw[2], g_wiz_netinfo.gw[3]); + KPrintf("SUB: %d.%d.%d.%d\r\n", g_wiz_netinfo.sn[0], g_wiz_netinfo.sn[1], + g_wiz_netinfo.sn[2], g_wiz_netinfo.sn[3]); + KPrintf("DNS: %d.%d.%d.%d\r\n", g_wiz_netinfo.dns[0], g_wiz_netinfo.dns[1], + g_wiz_netinfo.dns[2], g_wiz_netinfo.dns[3]); + KPrintf("======================\r\n"); + + return EOK; +} + +/****************** spi init ******************/ +static struct Bus *w5500_spi_bus; +int w5500_spi_init() { + x_err_t ret = EOK; + + w5500_spi_bus = BusFind(SPI_BUS_NAME_1); + w5500_spi_bus->owner_haldev = + BusFindDevice(w5500_spi_bus, SPI_1_DEVICE_NAME_0); + w5500_spi_bus->owner_driver = BusFindDriver(w5500_spi_bus, SPI_1_DRV_NAME); + + w5500_spi_bus->match(w5500_spi_bus->owner_driver, + w5500_spi_bus->owner_haldev); + + struct BusConfigureInfo configure_info; + struct SpiMasterParam spi_master_param; + spi_master_param.spi_data_bit_width = 8; + spi_master_param.spi_work_mode = SPI_MODE_0 | SPI_MSB; + spi_master_param.spi_maxfrequency = SPI_LORA_FREQUENCY; + spi_master_param.spi_data_endian = 0; + + configure_info.configure_cmd = OPE_CFG; + configure_info.private_data = (void *)&spi_master_param; + ret = BusDrvConfigure(w5500_spi_bus->owner_driver, &configure_info); + if (ret) { + KPrintf("spi drv OPE_CFG error drv %8p cfg %8p\n", + w5500_spi_bus->owner_driver, &spi_master_param); + return ERROR; + } + + configure_info.configure_cmd = OPE_INT; + ret = BusDrvConfigure(w5500_spi_bus->owner_driver, &configure_info); + if (ret) { + KPrintf("spi drv OPE_INT error drv %8p\n", w5500_spi_bus->owner_driver); + return ERROR; + } + + return EOK; +} + +void spi_write_byte(uint8_t tx_data) { + struct BusBlockWriteParam write_param; + write_param.buffer = &tx_data; + write_param.size = 1; + BusDevWriteData(w5500_spi_bus->owner_haldev, &write_param); +} +uint8_t spi_read_byte(void) { + uint8_t result = 0; + struct BusBlockReadParam read_param; + read_param.buffer = &result; + read_param.size = 1; + BusDevReadData(w5500_spi_bus->owner_haldev, &read_param); + return result; +} +void spi_write_burst(uint8_t *tx_buf, uint16_t len) { + struct BusBlockWriteParam write_param; + write_param.buffer = tx_buf; + write_param.size = len; + BusDevWriteData(w5500_spi_bus->owner_haldev, &write_param); +} +void spi_read_burst(uint8_t *rx_buf, uint16_t len) { + struct BusBlockReadParam read_param; + read_param.buffer = rx_buf; + read_param.size = len; + BusDevReadData(w5500_spi_bus->owner_haldev, &read_param); +} + +/****************** chip init ******************/ + +void wiz_reset() { + gpiohs_set_drive_mode(WIZ_RST_PIN, GPIO_DM_OUTPUT); + gpiohs_set_pin(WIZ_RST_PIN, GPIO_PV_LOW); + MdelayKTask(20); + + gpiohs_set_pin(WIZ_RST_PIN, GPIO_PV_HIGH); + MdelayKTask(20); +} + +void wiz_spi_handler_reg() { + // spi ops registration +#if (_WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_VDM_) || \ + (_WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_FDM_) + /* register SPI device CS select callback function */ + gpiohs_set_drive_mode(SPI1_CS0_PIN, GPIO_DM_OUTPUT); + reg_wizchip_cs_cbfunc(spi_select_cs, spi_deselete_cs); +#else +#if (_WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_SIP_) != _WIZCHIP_IO_MODE_SIP_ +#error "Unknown _WIZCHIP_IO_MODE_" +#else + reg_wizchip_cs_cbfunc(wizchip_select, wizchip_deselect); +#endif +#endif + + reg_wizchip_spi_cbfunc(spi_read_byte, spi_write_byte); + reg_wizchip_cris_cbfunc(spi_enter_cris, spi_exit_cris); + reg_wizchip_spiburst_cbfunc(spi_read_burst, spi_write_burst); +} + +int wiz_chip_cfg_init() { + uint8_t mem_size[2][8] = {{2, 2, 2, 2, 2, 2, 2, 2}, {2, 2, 2, 2, 2, 2, 2, 2}}; + + /* reset WIZnet chip internal PHY, configures PHY mode. */ + if (ctlwizchip(CW_INIT_WIZCHIP, (void *)mem_size) == -1) { + KPrintf("WIZCHIP initialize failed."); + return ERROR; + } + + struct wiz_NetTimeout_t net_timeout; + net_timeout.retry_cnt = 5; + net_timeout.time_100us = 20000; + ctlnetwork(CN_SET_TIMEOUT, (void *)&net_timeout); + + return EOK; +} + +/****************** interrupt handle ******************/ +void wiz_irq_handler() {} + +int wiz_interrupt_init() { + int32_t ret = -ERROR; + + struct Bus *pin_bus = PinBusInitGet(); + + struct PinParam pin_param; + struct BusConfigureInfo pin_configure_info; + + pin_configure_info.configure_cmd = OPE_CFG; + pin_configure_info.private_data = (void *)&pin_param; + + pin_param.cmd = GPIO_CONFIG_MODE; + pin_param.pin = BSP_WIZ_INT_PIN; + pin_param.mode = GPIO_CFG_INPUT_PULLUP; + ret = BusDrvConfigure(pin_bus->owner_driver, &pin_configure_info); + if (ret != EOK) { + KPrintf("config pin_param %d input failed!\n", pin_param.pin); + return -ERROR; + } + + pin_param.cmd = GPIO_IRQ_REGISTER; + pin_param.pin = BSP_WIZ_INT_PIN; + pin_param.irq_set.irq_mode = GPIO_IRQ_EDGE_FALLING; + pin_param.irq_set.hdr = wiz_irq_handler; + pin_param.irq_set.args = NONE; + ret = BusDrvConfigure(pin_bus->owner_driver, &pin_configure_info); + if (ret != EOK) { + KPrintf("register pin_param %d irq failed!\n", pin_param.pin); + return -ERROR; + } + + pin_param.cmd = GPIO_IRQ_DISABLE; + pin_param.pin = BSP_WIZ_INT_PIN; + ret = BusDrvConfigure(pin_bus->owner_driver, &pin_configure_info); + if (ret != EOK) { + KPrintf("disable pin_param %d irq failed!\n", pin_param.pin); + return -ERROR; + } + + // 4. enable interuption + pin_param.cmd = GPIO_IRQ_ENABLE; + pin_param.pin = BSP_WIZ_INT_PIN; + ret = BusDrvConfigure(pin_bus->owner_driver, &pin_configure_info); + if (ret != EOK) { + KPrintf("enable pin_param %d irq failed!\n", pin_param.pin); + return -ERROR; + } + + return EOK; + + return EOK; +} + +int HwWiznetInit(void) { + wiz_reset(); + + if (EOK != w5500_spi_init()) { + return ERROR; + } + + wiz_spi_handler_reg(); + + if (EOK != wiz_chip_cfg_init()) { + return ERROR; + } + + network_init(); + + return EOK; +} + +static void set_netinfo() { + // set g_wiz_netinfo +} + +enum TCP_OPTION { + SEND_DATA = 0, + RECV_DATA, +}; + +uint32_t wiz_client_op(uint8_t sn, uint8_t *buf, uint32_t buf_size, + uint8_t dst_ip[4], uint16_t dst_port, + enum TCP_OPTION opt) { + // assert(buf_size <= g_wiznet_buf_size); + int32_t ret; + switch (getSn_SR(socket_tcp)) { + case SOCK_CLOSE_WAIT: + wiz_sock_disconnect(socket_tcp); + break; + case SOCK_CLOSED: + wiz_socket(socket_tcp, Sn_MR_TCP, 5000, 0x00); + break; + case SOCK_INIT: + KPrintf("[SOCKET CLIENT] sock init.\n"); + wiz_sock_connect(socket_tcp, dst_ip, dst_port); + break; + case SOCK_ESTABLISHED: + if (getSn_IR(socket_tcp) & Sn_IR_CON) { + printf("[SOCKET CLIENT] %d:Connected\r\n", socket_tcp); + setSn_IR(socket_tcp, Sn_IR_CON); + } + if (opt == SEND_DATA) { + uint32_t sent_size = 0; + ret = wiz_sock_send(socket_tcp, buf, buf_size); + if (ret < 0) { + wiz_sock_close(socket_tcp); + return ret; + } + } else if (opt == RECV_DATA) { + uint32_t size = 0; + if ((size = getSn_RX_RSR(sn)) > 0) { + if (size > buf_size) size = buf_size; + ret = wiz_sock_recv(sn, buf, size); + if (ret <= 0) return ret; + } + } + break; + default: + break; + } +} + +void wiz_client_op_test(char *addr, uint16_t port, char *msg) { + /* argv[1]: ip + * argv[2]: port + * argv[3]: msg + */ + uint8_t client_sock = 2; + uint8_t ip[4] = {192, 168, 31, 127}; + uint32_t tmp_ip[4]; + KPrintf("wiz client to %s", addr); + sscanf(addr, "%d.%d.%d.%d", &tmp_ip[0], &tmp_ip[1], &tmp_ip[2], &tmp_ip[3]); + // for (int i = 0; i < 4; ++i) { + // ip[i] = (uint8_t)tmp_ip[i]; + // } + uint8_t buf[g_wiznet_buf_size]; + // TODO: bug if argv[2] is not a port + // TODO: bug if msg size > 2048 + KPrintf("wiz_server, send to %d.%d.%d.%d %d\n", ip[0], ip[1], ip[2], ip[3], + port); + sscanf(msg, "%s", buf); + wiz_client_op(client_sock, buf, g_wiznet_buf_size, ip, port, SEND_DATA); + MdelayKTask(10); + memset(buf, 0, g_wiznet_buf_size); + wiz_client_op(client_sock, buf, g_wiznet_buf_size, ip, port, RECV_DATA); + KPrintf("received msg: %s\n", buf); +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC) | + SHELL_CMD_PARAM_NUM(3), + wiz_client_op, wiz_client_op_test, + wiz_sock_recv or wiz_sock_send data as tcp client); + +int32_t wiz_server_op(uint8_t sn, uint8_t *buf, uint32_t buf_size, + uint16_t port, enum TCP_OPTION opt) { + int32_t ret = 0; + uint16_t size = 0, sentsize = 0; + switch (getSn_SR(sn)) { + case SOCK_ESTABLISHED: + if (getSn_IR(sn) & Sn_IR_CON) { + printf("%d:Connected\r\n", sn); + setSn_IR(sn, Sn_IR_CON); + } + if (opt == SEND_DATA) { + uint32_t sent_size = 0; + ret = wiz_sock_send(socket_tcp, buf, buf_size); + if (ret < 0) { + wiz_sock_close(socket_tcp); + return ret; + } + } else if (opt == RECV_DATA) { + uint32_t size = 0; + if ((size = getSn_RX_RSR(sn)) > 0) { + if (size > buf_size) size = buf_size; + ret = wiz_sock_recv(sn, buf, size); + return ret; + } + } + break; + case SOCK_CLOSE_WAIT: + printf("%d:CloseWait\r\n", sn); + if ((ret = wiz_sock_disconnect(sn)) != SOCK_OK) return ret; + printf("%d:Closed\r\n", sn); + break; + case SOCK_INIT: + printf("%d:Listen, port [%d]\r\n", sn, port); + if ((ret = wiz_sock_listen(sn)) != SOCK_OK) return ret; + break; + case SOCK_CLOSED: + printf("%d:LBTStart\r\n", sn); + if ((ret = wiz_socket(sn, Sn_MR_TCP, port, 0x00)) != sn) return ret; + printf("%d:Opened\r\n", sn); + break; + default: + break; + } + return 0; +} + +void wiz_server(void *param) { + uint16_t port = *(uint16_t *)param; + KPrintf("wiz server, listen port: %d\n", port); + uint8_t buf[g_wiznet_buf_size]; + memset(buf, 0, g_wiznet_buf_size); + int ret = 0; + while (1) { + ret = wiz_server_op(0, buf, g_wiznet_buf_size, port, RECV_DATA); + if (ret > 0) { + wiz_server_op(0, buf, g_wiznet_buf_size, port, SEND_DATA); + }; + } +} + +void wiz_server_test(uint16_t port) { + /* argv[1]: port + */ + int32 wiz_server_id = + KTaskCreate("wiz_server", wiz_server, (void *)&port, 4096, 25); + x_err_t flag = StartupKTask(wiz_server_id); + if (flag != EOK) { + KPrintf("StartupKTask wiz_server_id failed .\n"); + } +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC) | + SHELL_CMD_PARAM_NUM(1), + wiz_server_op, wiz_server_test, + wiz_sock_recv or wiz_sock_send data as tcp server); + +int32_t loopback_udps(uint8_t sn, uint8_t *buf, uint16_t port) { + int32_t ret; + uint16_t size, sentsize; + uint8_t destip[4]; + uint16_t destport; + // uint8_t packinfo = 0; + switch (getSn_SR(sn)) { + case SOCK_UDP: + if ((size = getSn_RX_RSR(sn)) > 0) { + if (size > g_wiznet_buf_size) size = g_wiznet_buf_size; + ret = wiz_sock_recvfrom(sn, buf, size, destip, (uint16_t *)&destport); + if (ret <= 0) { + printf("%d: wiz_sock_recvfrom error. %ld\r\n", sn, ret); + return ret; + } + size = (uint16_t)ret; + sentsize = 0; + while (sentsize != size) { + ret = wiz_sock_sendto(sn, buf + sentsize, size - sentsize, destip, + destport); + if (ret < 0) { + printf("%d: wiz_sock_sendto error. %ld\r\n", sn, ret); + return ret; + } + sentsize += ret; // Don't care SOCKERR_BUSY, because it is zero. + } + } + break; + case SOCK_CLOSED: + printf("%d:LBUStart\r\n", sn); + if ((ret = wiz_socket(sn, Sn_MR_UDP, port, 0x00)) != sn) return ret; + printf("%d:Opened, port [%d]\r\n", sn, port); + break; + default: + break; + } + return 1; +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/imgs/client0.png b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/imgs/client0.png new file mode 100644 index 0000000000000000000000000000000000000000..7df09b0d920a5bb61e8801e0f1d3a7481d22e4d3 GIT binary patch literal 80399 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≫m@LeRdNwL|V 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%0A4-JMz z3o!x7(EKsCmI9FPkv;V`VuM1z*@rcF7}*d$GQazM64_Qwra0-Gp6IOA6#m zmS+6mu)n4zP+?=rnzcZ4#25??F$tL6nc@7ZFX#K#E|1Yk207W)kG?gIfKpO&&;ZoZ z!l9s7W=o{)9n}|-Ql}V*@D!$|@3m=tk&<#R)_~If^}dn0x;js}J6vj3U!X}i1aoXf z+QXeKN^yPRo9Q{!__eVUz1|z+e1z2=h&+?Uatn|} zSwb~MP|iBn=u#nx;C4Eh+Q)%z#fl_Jw&c9bjs1to91=?w4eq8n4%RG(;@ea=O9g_u z*<6(9JP8MT1pq~LXfg_gms0Eb2EAVoTX?1Jjp~$U-LJebk1bCQnn)yE>5@izBQ(EU zR+rBcmrcYJ@bp#GzMP!?_0-S;l#-kZ#lf_QMe!LNJ3DmiY1#K`3dT? zV2-(E0+Q&#AqxCJT*pQ!iHw9)Di_07CG;XdX=y8NEG!C0cG3jOK?*~ZjXkM<~Bp>`KaqSc2T297Ql&v+5R{HGO)wo$AiAFV(Q z?_q(8Ou){!KUN`ndDV2@Zhm}uTIC{2N()=Gz}NzXn70-O^2h4HM!{=E<7t%q@akQ~ zu=+SSn8w&4#+*Mdb;umX1pnl)(A=U~p44U6gZ!3< zg>keSa!Ukjv&_F{U-08rrqlXq%P+q;H-#hm^gC| z|G*V;lX>TxmkWO^h>wtokui@q_geDrs`4SX@}=J|ytOHOcXq{napUr%DmHhsgSC>S zbeq|C&-i&&=v+iu%9mA3&%_vX9OHW?;-x#y>B*vpJacPgHqZO_XHTW2{rUXvmp26t z>D!#~S+vFTQmPZPe$oGTs^8x3oHK3DQ{k)XcYnToAa+e=j^ph9QiJyCF8-1!iJU!`S;mY3vm&~>|4*T`F^z9Ij_ewEK++1%E&DNiszQt{IR^Ix# z2l{XG{H%Gz@P<3n>uK!y_GmXy!=$Oa9kjT^^m*Xw%R%y=f9Gc%-l<@Y*0@VLzY|>b z{Fl7Qpg literal 0 HcmV?d00001 diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/imgs/client1.png b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/imgs/client1.png new file mode 100644 index 0000000000000000000000000000000000000000..167d455b8fbf29ac7161989f7c1b0c976fbde5c2 GIT binary patch literal 107737 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

VQs=2XZd#;B*mFBp|M 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 literal 0 HcmV?d00001 diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/imgs/ping w5500.png b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/imgs/ping w5500.png new file mode 100644 index 0000000000000000000000000000000000000000..e453995a602225817aa5c6d9b46a65417b6d11cd GIT binary patch literal 52638 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 literal 0 HcmV?d00001 diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/imgs/server0.png b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/imgs/server0.png new file mode 100644 index 0000000000000000000000000000000000000000..63f2d5f57715dfea79eda96726be0de715ea187f GIT binary patch literal 85897 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 literal 0 HcmV?d00001 diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/imgs/server1.png b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/imgs/server1.png new file mode 100644 index 0000000000000000000000000000000000000000..7643c9bf39f35e75583d7b0934964a9fff40f42d GIT binary patch literal 9689 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 SLM2!*Fw)`*VwED_0{;)8=3Tb{ literal 0 HcmV?d00001 diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/socket.c b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/socket.c new file mode 100755 index 000000000..820e0631c --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/socket.c @@ -0,0 +1,912 @@ + +//***************************************************************************** +// +//! \file socket.c +//! \brief SOCKET APIs Implements file. +//! \details SOCKET APIs like as Berkeley Socket APIs. +//! \version 1.0.3 +//! \date 2013/10/21 +//! \par Revision history +//! <2015/02/05> Notice +//! The version history is not updated after this point. +//! Download the latest version directly from GitHub. Please visit the +//! our GitHub repository for ioLibrary. +//! >> https://github.com/Wiznet/ioLibrary_Driver +//! <2014/05/01> V1.0.3. Refer to M20140501 +//! 1. Implicit type casting -> Explicit type casting. +//! 2. replace 0x01 with PACK_REMAINED in recvfrom() +//! 3. Validation a destination ip in connect() & sendto(): +//! It occurs a fatal error on converting unint32 address if uint8* +//! addr parameter is not aligned by 4byte address. Copy 4 byte addr +//! value into temporary uint32 variable and then compares it. +//! <2013/12/20> V1.0.2 Refer to M20131220 +//! Remove Warning. +//! <2013/11/04> V1.0.1 2nd Release. Refer to "20131104". +//! In sendto(), Add to clear timeout interrupt status +//! (Sn_IR_TIMEOUT) +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! 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 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. +// +//***************************************************************************** +#include "socket.h" + +#include "wizchip_conf.h" + +// M20150401 : Typing Error +//#define SOCK_ANY_PORT_NUM 0xC000; +#define SOCK_ANY_PORT_NUM 0xC000 + +static uint16_t sock_any_port = SOCK_ANY_PORT_NUM; +static uint16_t sock_io_mode = 0; +static uint16_t sock_is_sending = 0; + +static uint16_t sock_remained_size[_WIZCHIP_SOCK_NUM_] = { + 0, + 0, +}; + +// M20150601 : For extern decleation +// static uint8_t sock_pack_info[_WIZCHIP_SOCK_NUM_] = {0,}; +uint8_t sock_pack_info[_WIZCHIP_SOCK_NUM_] = { + 0, +}; +// + +#if _WIZCHIP_ == 5200 +static uint16_t sock_next_rd[_WIZCHIP_SOCK_NUM_] = { + 0, +}; +#endif + +// A20150601 : For integrating with W5300 +#if _WIZCHIP_ == 5300 +uint8_t sock_remained_byte[_WIZCHIP_SOCK_NUM_] = { + 0, +}; // set by wiz_recv_data() +#endif + +#define CHECK_SOCKNUM() \ + do { \ + if (sn > _WIZCHIP_SOCK_NUM_) return SOCKERR_SOCKNUM; \ + } while (0); + +#define CHECK_SOCKMODE(mode) \ + do { \ + if ((getSn_MR(sn) & 0x0F) != mode) return SOCKERR_SOCKMODE; \ + } while (0); + +#define CHECK_SOCKINIT() \ + do { \ + if ((getSn_SR(sn) != SOCK_INIT)) return SOCKERR_SOCKINIT; \ + } while (0); + +#define CHECK_SOCKDATA() \ + do { \ + if (len == 0) return SOCKERR_DATALEN; \ + } while (0); + +int8_t wiz_socket(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag) { + CHECK_SOCKNUM(); + switch (protocol) { + case Sn_MR_TCP: { + // M20150601 : Fixed the warning - taddr will never be NULL + /* + uint8_t taddr[4]; + getSIPR(taddr); + */ + uint32_t taddr; + getSIPR((uint8_t *)&taddr); + if (taddr == 0) return SOCKERR_SOCKINIT; + break; + } + case Sn_MR_UDP: + case Sn_MR_MACRAW: + case Sn_MR_IPRAW: + break; +#if (_WIZCHIP_ < 5200) + case Sn_MR_PPPoE: + break; +#endif + default: + return SOCKERR_SOCKMODE; + } + // M20150601 : For SF_TCP_ALIGN & W5300 + // if((flag & 0x06) != 0) return SOCKERR_SOCKFLAG; + if ((flag & 0x04) != 0) return SOCKERR_SOCKFLAG; +#if _WIZCHIP_ == 5200 + if (flag & 0x10) return SOCKERR_SOCKFLAG; +#endif + + if (flag != 0) { + switch (protocol) { + case Sn_MR_TCP: + // M20150601 : For SF_TCP_ALIGN & W5300 +#if _WIZCHIP_ == 5300 + if ((flag & (SF_TCP_NODELAY | SF_IO_NONBLOCK | SF_TCP_ALIGN)) == 0) + return SOCKERR_SOCKFLAG; +#else + if ((flag & (SF_TCP_NODELAY | SF_IO_NONBLOCK)) == 0) + return SOCKERR_SOCKFLAG; +#endif + + break; + case Sn_MR_UDP: + if (flag & SF_IGMP_VER2) { + if ((flag & SF_MULTI_ENABLE) == 0) return SOCKERR_SOCKFLAG; + } +#if _WIZCHIP_ == 5500 + if (flag & SF_UNI_BLOCK) { + if ((flag & SF_MULTI_ENABLE) == 0) return SOCKERR_SOCKFLAG; + } +#endif + break; + default: + break; + } + } + wiz_sock_close(sn); +// M20150601 +#if _WIZCHIP_ == 5300 + setSn_MR(sn, ((uint16_t)(protocol | (flag & 0xF0))) | + (((uint16_t)(flag & 0x02)) << 7)); +#else + setSn_MR(sn, (protocol | (flag & 0xF0))); +#endif + if (!port) { + port = sock_any_port++; + if (sock_any_port == 0xFFF0) sock_any_port = SOCK_ANY_PORT_NUM; + } + setSn_PORT(sn, port); + setSn_CR(sn, Sn_CR_OPEN); + while (getSn_CR(sn)) + ; + // A20150401 : For release the previous sock_io_mode + sock_io_mode &= ~(1 << sn); + // + sock_io_mode |= ((flag & SF_IO_NONBLOCK) << sn); + sock_is_sending &= ~(1 << sn); + sock_remained_size[sn] = 0; + // M20150601 : repalce 0 with PACK_COMPLETED + // sock_pack_info[sn] = 0; + sock_pack_info[sn] = PACK_COMPLETED; + // + while (getSn_SR(sn) == SOCK_CLOSED) + ; + return (int8_t)sn; +} + +int8_t wiz_sock_close(uint8_t sn) { + CHECK_SOCKNUM(); +// A20160426 : Applied the erratum 1 of W5300 +#if (_WIZCHIP_ == 5300) + // M20160503 : Wrong socket parameter. s -> sn + // if( ((getSn_MR(s)& 0x0F) == Sn_MR_TCP) && (getSn_TX_FSR(s) != + // getSn_TxMAX(s)) ) + if (((getSn_MR(sn) & 0x0F) == Sn_MR_TCP) && + (getSn_TX_FSR(sn) != getSn_TxMAX(sn))) { + uint8_t destip[4] = {0, 0, 0, 1}; + // TODO + // You can wait for completing to sending data; + // wait about 1 second; + // if you have completed to send data, skip the code of erratum 1 + // ex> wait_1s(); + // if (getSn_TX_FSR(s) == getSn_TxMAX(s)) continue; + // + // M20160503 : The socket() of close() calls close() itself again. It + // occures a infinite loop - close()->socket()->close()->socket()-> ~ + // socket(s,Sn_MR_UDP,0x3000,0); + // sendto(s,destip,1,destip,0x3000); // send the dummy data to an unknown + // destination(0.0.0.1). + setSn_MR(sn, Sn_MR_UDP); + setSn_PORTR(sn, 0x3000); + setSn_CR(sn, Sn_CR_OPEN); + while (getSn_CR(sn) != 0) + ; + while (getSn_SR(sn) != SOCK_UDP) + ; + wiz_sock_sendto( + sn, destip, 1, destip, + 0x3000); // send the dummy data to an unknown destination(0.0.0.1). + }; +#endif + setSn_CR(sn, Sn_CR_CLOSE); + /* wait to process the command... */ + while (getSn_CR(sn)) + ; + /* clear all interrupt of the socket. */ + setSn_IR(sn, 0xFF); + // A20150401 : Release the sock_io_mode of socket n. + sock_io_mode &= ~(1 << sn); + // + sock_is_sending &= ~(1 << sn); + sock_remained_size[sn] = 0; + sock_pack_info[sn] = 0; + while (getSn_SR(sn) != SOCK_CLOSED) + ; + return SOCK_OK; +} + +int8_t wiz_sock_listen(uint8_t sn) { + CHECK_SOCKNUM(); + CHECK_SOCKMODE(Sn_MR_TCP); + CHECK_SOCKINIT(); + setSn_CR(sn, Sn_CR_LISTEN); + while (getSn_CR(sn)) + ; + while (getSn_SR(sn) != SOCK_LISTEN) { + wiz_sock_close(sn); + return SOCKERR_SOCKCLOSED; + } + return SOCK_OK; +} + +int8_t wiz_sock_connect(uint8_t sn, uint8_t *addr, uint16_t port) { + CHECK_SOCKNUM(); + CHECK_SOCKMODE(Sn_MR_TCP); + CHECK_SOCKINIT(); + // M20140501 : For avoiding fatal error on memory align mismatched + // if( *((uint32_t*)addr) == 0xFFFFFFFF || *((uint32_t*)addr) == 0) return + // SOCKERR_IPINVALID; + { + uint32_t taddr; + taddr = ((uint32_t)addr[0] & 0x000000FF); + taddr = (taddr << 8) + ((uint32_t)addr[1] & 0x000000FF); + taddr = (taddr << 8) + ((uint32_t)addr[2] & 0x000000FF); + taddr = (taddr << 8) + ((uint32_t)addr[3] & 0x000000FF); + if (taddr == 0xFFFFFFFF || taddr == 0) return SOCKERR_IPINVALID; + } + // + + if (port == 0) return SOCKERR_PORTZERO; + setSn_DIPR(sn, addr); + setSn_DPORT(sn, port); + setSn_CR(sn, Sn_CR_CONNECT); + while (getSn_CR(sn)) + ; + if (sock_io_mode & (1 << sn)) return SOCK_BUSY; + while (getSn_SR(sn) != SOCK_ESTABLISHED) { + if (getSn_IR(sn) & Sn_IR_TIMEOUT) { + setSn_IR(sn, Sn_IR_TIMEOUT); + return SOCKERR_TIMEOUT; + } + + if (getSn_SR(sn) == SOCK_CLOSED) { + return SOCKERR_SOCKCLOSED; + } + } + + return SOCK_OK; +} + +int8_t wiz_sock_disconnect(uint8_t sn) { + CHECK_SOCKNUM(); + CHECK_SOCKMODE(Sn_MR_TCP); + setSn_CR(sn, Sn_CR_DISCON); + /* wait to process the command... */ + while (getSn_CR(sn)) + ; + sock_is_sending &= ~(1 << sn); + if (sock_io_mode & (1 << sn)) return SOCK_BUSY; + while (getSn_SR(sn) != SOCK_CLOSED) { + if (getSn_IR(sn) & Sn_IR_TIMEOUT) { + wiz_sock_close(sn); + return SOCKERR_TIMEOUT; + } + } + return SOCK_OK; +} + +int32_t wiz_sock_send(uint8_t sn, uint8_t *buf, uint16_t len) { + uint8_t tmp = 0; + uint16_t freesize = 0; + + CHECK_SOCKNUM(); + CHECK_SOCKMODE(Sn_MR_TCP); + CHECK_SOCKDATA(); + tmp = getSn_SR(sn); + if (tmp != SOCK_ESTABLISHED && tmp != SOCK_CLOSE_WAIT) + return SOCKERR_SOCKSTATUS; + if (sock_is_sending & (1 << sn)) { + tmp = getSn_IR(sn); + if (tmp & Sn_IR_SENDOK) { + setSn_IR(sn, Sn_IR_SENDOK); +// M20150401 : Typing Error +//#if _WZICHIP_ == 5200 +#if _WIZCHIP_ == 5200 + if (getSn_TX_RD(sn) != sock_next_rd[sn]) { + setSn_CR(sn, Sn_CR_SEND); + while (getSn_CR(sn)) + ; + return SOCK_BUSY; + } +#endif + sock_is_sending &= ~(1 << sn); + } else if (tmp & Sn_IR_TIMEOUT) { + wiz_sock_close(sn); + return SOCKERR_TIMEOUT; + } else + return SOCK_BUSY; + } + freesize = getSn_TxMAX(sn); + if (len > freesize) len = freesize; // check size not to exceed MAX size. + while (1) { + freesize = getSn_TX_FSR(sn); + tmp = getSn_SR(sn); + if ((tmp != SOCK_ESTABLISHED) && (tmp != SOCK_CLOSE_WAIT)) { + wiz_sock_close(sn); + return SOCKERR_SOCKSTATUS; + } + if ((sock_io_mode & (1 << sn)) && (len > freesize)) return SOCK_BUSY; + if (len <= freesize) break; + } + wiz_send_data(sn, buf, len); +#if _WIZCHIP_ == 5200 + sock_next_rd[sn] = getSn_TX_RD(sn) + len; +#endif + +#if _WIZCHIP_ == 5300 + setSn_TX_WRSR(sn, len); +#endif + + setSn_CR(sn, Sn_CR_SEND); + /* wait to process the command... */ + while (getSn_CR(sn)) + ; + sock_is_sending |= (1 << sn); + // M20150409 : Explicit Type Casting + // return len; + return (int32_t)len; +} + +int32_t wiz_sock_recv(uint8_t sn, uint8_t *buf, uint16_t len) { + uint8_t tmp = 0; + uint16_t recvsize = 0; +// A20150601 : For integarating with W5300 +#if _WIZCHIP_ == 5300 + uint8_t head[2]; + uint16_t mr; +#endif + // + CHECK_SOCKNUM(); + CHECK_SOCKMODE(Sn_MR_TCP); + CHECK_SOCKDATA(); + + recvsize = getSn_RxMAX(sn); + if (recvsize < len) len = recvsize; + +// A20150601 : For Integrating with W5300 +#if _WIZCHIP_ == 5300 + // sock_pack_info[sn] = PACK_COMPLETED; // for clear + if (sock_remained_size[sn] == 0) { +#endif + // + while (1) { + recvsize = getSn_RX_RSR(sn); + tmp = getSn_SR(sn); + if (tmp != SOCK_ESTABLISHED) { + if (tmp == SOCK_CLOSE_WAIT) { + if (recvsize != 0) + break; + else if (getSn_TX_FSR(sn) == getSn_TxMAX(sn)) { + wiz_sock_close(sn); + return SOCKERR_SOCKSTATUS; + } + } else { + wiz_sock_close(sn); + return SOCKERR_SOCKSTATUS; + } + } + if ((sock_io_mode & (1 << sn)) && (recvsize == 0)) return SOCK_BUSY; + if (recvsize != 0) break; + }; +#if _WIZCHIP_ == 5300 + } +#endif + +// A20150601 : For integrating with W5300 +#if _WIZCHIP_ == 5300 + if ((sock_remained_size[sn] == 0) || (getSn_MR(sn) & Sn_MR_ALIGN)) { + mr = getMR(); + if ((getSn_MR(sn) & Sn_MR_ALIGN) == 0) { + wiz_recv_data(sn, head, 2); + if (mr & MR_FS) + recvsize = (((uint16_t)head[1]) << 8) | ((uint16_t)head[0]); + else + recvsize = (((uint16_t)head[0]) << 8) | ((uint16_t)head[1]); + sock_pack_info[sn] = PACK_FIRST; + } + sock_remained_size[sn] = recvsize; + } + if (len > sock_remained_size[sn]) len = sock_remained_size[sn]; + recvsize = len; + if (sock_pack_info[sn] & PACK_FIFOBYTE) { + *buf = sock_remained_byte[sn]; + buf++; + sock_pack_info[sn] &= ~(PACK_FIFOBYTE); + recvsize -= 1; + sock_remained_size[sn] -= 1; + } + if (recvsize != 0) { + wiz_recv_data(sn, buf, recvsize); + setSn_CR(sn, Sn_CR_RECV); + while (getSn_CR(sn)) + ; + } + sock_remained_size[sn] -= recvsize; + if (sock_remained_size[sn] != 0) { + sock_pack_info[sn] |= PACK_REMAINED; + if (recvsize & 0x1) sock_pack_info[sn] |= PACK_FIFOBYTE; + } else + sock_pack_info[sn] = PACK_COMPLETED; + if (getSn_MR(sn) & Sn_MR_ALIGN) sock_remained_size[sn] = 0; + // len = recvsize; +#else + if (recvsize < len) len = recvsize; + wiz_recv_data(sn, buf, len); + setSn_CR(sn, Sn_CR_RECV); + while (getSn_CR(sn)) + ; +#endif + + // M20150409 : Explicit Type Casting + // return len; + return (int32_t)len; +} + +int32_t wiz_sock_sendto(uint8_t sn, uint8_t *buf, uint16_t len, uint8_t *addr, + uint16_t port) { + uint8_t tmp = 0; + uint16_t freesize = 0; + uint32_t taddr; + + CHECK_SOCKNUM(); + switch (getSn_MR(sn) & 0x0F) { + case Sn_MR_UDP: + case Sn_MR_MACRAW: + // break; + // #if ( _WIZCHIP_ < 5200 ) + case Sn_MR_IPRAW: + break; + // #endif + default: + return SOCKERR_SOCKMODE; + } + CHECK_SOCKDATA(); + // M20140501 : For avoiding fatal error on memory align mismatched + // if(*((uint32_t*)addr) == 0) return SOCKERR_IPINVALID; + //{ + // uint32_t taddr; + taddr = ((uint32_t)addr[0]) & 0x000000FF; + taddr = (taddr << 8) + ((uint32_t)addr[1] & 0x000000FF); + taddr = (taddr << 8) + ((uint32_t)addr[2] & 0x000000FF); + taddr = (taddr << 8) + ((uint32_t)addr[3] & 0x000000FF); + //} + // + // if(*((uint32_t*)addr) == 0) return SOCKERR_IPINVALID; + if ((taddr == 0) && ((getSn_MR(sn) & Sn_MR_MACRAW) != Sn_MR_MACRAW)) + return SOCKERR_IPINVALID; + if ((port == 0) && ((getSn_MR(sn) & Sn_MR_MACRAW) != Sn_MR_MACRAW)) + return SOCKERR_PORTZERO; + tmp = getSn_SR(sn); + //#if ( _WIZCHIP_ < 5200 ) + if ((tmp != SOCK_MACRAW) && (tmp != SOCK_UDP) && (tmp != SOCK_IPRAW)) + return SOCKERR_SOCKSTATUS; + //#else + // if(tmp != SOCK_MACRAW && tmp != SOCK_UDP) return SOCKERR_SOCKSTATUS; + //#endif + + setSn_DIPR(sn, addr); + setSn_DPORT(sn, port); + freesize = getSn_TxMAX(sn); + if (len > freesize) len = freesize; // check size not to exceed MAX size. + while (1) { + freesize = getSn_TX_FSR(sn); + if (getSn_SR(sn) == SOCK_CLOSED) return SOCKERR_SOCKCLOSED; + if ((sock_io_mode & (1 << sn)) && (len > freesize)) return SOCK_BUSY; + if (len <= freesize) break; + }; + wiz_send_data(sn, buf, len); + +#if _WIZCHIP_ < 5500 // M20150401 : for WIZCHIP Errata #4, #5 (ARP errata) + getSIPR((uint8_t *)&taddr); + if (taddr == 0) { + getSUBR((uint8_t *)&taddr); + setSUBR((uint8_t *)"\x00\x00\x00\x00"); + } else + taddr = 0; +#endif + +// A20150601 : For W5300 +#if _WIZCHIP_ == 5300 + setSn_TX_WRSR(sn, len); +#endif + // + setSn_CR(sn, Sn_CR_SEND); + /* wait to process the command... */ + while (getSn_CR(sn)) + ; + while (1) { + tmp = getSn_IR(sn); + if (tmp & Sn_IR_SENDOK) { + setSn_IR(sn, Sn_IR_SENDOK); + break; + } + // M:20131104 + // else if(tmp & Sn_IR_TIMEOUT) return SOCKERR_TIMEOUT; + else if (tmp & Sn_IR_TIMEOUT) { + setSn_IR(sn, Sn_IR_TIMEOUT); +// M20150409 : Fixed the lost of sign bits by type casting. +// len = (uint16_t)SOCKERR_TIMEOUT; +// break; +#if _WIZCHIP_ < 5500 // M20150401 : for WIZCHIP Errata #4, #5 (ARP errata) + if (taddr) setSUBR((uint8_t *)&taddr); +#endif + return SOCKERR_TIMEOUT; + } + //////////// + } +#if _WIZCHIP_ < 5500 // M20150401 : for WIZCHIP Errata #4, #5 (ARP errata) + if (taddr) setSUBR((uint8_t *)&taddr); +#endif + // M20150409 : Explicit Type Casting + // return len; + return (int32_t)len; +} + +int32_t wiz_sock_recvfrom(uint8_t sn, uint8_t *buf, uint16_t len, uint8_t *addr, + uint16_t *port) { +// M20150601 : For W5300 +#if _WIZCHIP_ == 5300 + uint16_t mr; + uint16_t mr1; +#else + uint8_t mr; +#endif + // + uint8_t head[8]; + uint16_t pack_len = 0; + + CHECK_SOCKNUM(); + // CHECK_SOCKMODE(Sn_MR_UDP); +// A20150601 +#if _WIZCHIP_ == 5300 + mr1 = getMR(); +#endif + + switch ((mr = getSn_MR(sn)) & 0x0F) { + case Sn_MR_UDP: + case Sn_MR_IPRAW: + case Sn_MR_MACRAW: + break; +#if (_WIZCHIP_ < 5200) + case Sn_MR_PPPoE: + break; +#endif + default: + return SOCKERR_SOCKMODE; + } + CHECK_SOCKDATA(); + if (sock_remained_size[sn] == 0) { + while (1) { + pack_len = getSn_RX_RSR(sn); + if (getSn_SR(sn) == SOCK_CLOSED) return SOCKERR_SOCKCLOSED; + if ((sock_io_mode & (1 << sn)) && (pack_len == 0)) return SOCK_BUSY; + if (pack_len != 0) break; + }; + } + // D20150601 : Move it to bottom + // sock_pack_info[sn] = PACK_COMPLETED; + switch (mr & 0x07) { + case Sn_MR_UDP: + if (sock_remained_size[sn] == 0) { + wiz_recv_data(sn, head, 8); + setSn_CR(sn, Sn_CR_RECV); + while (getSn_CR(sn)) + ; + // read peer's IP address, port number & packet length + // A20150601 : For W5300 +#if _WIZCHIP_ == 5300 + if (mr1 & MR_FS) { + addr[0] = head[1]; + addr[1] = head[0]; + addr[2] = head[3]; + addr[3] = head[2]; + *port = head[5]; + *port = (*port << 8) + head[4]; + sock_remained_size[sn] = head[7]; + sock_remained_size[sn] = (sock_remained_size[sn] << 8) + head[6]; + } else { +#endif + addr[0] = head[0]; + addr[1] = head[1]; + addr[2] = head[2]; + addr[3] = head[3]; + *port = head[4]; + *port = (*port << 8) + head[5]; + sock_remained_size[sn] = head[6]; + sock_remained_size[sn] = (sock_remained_size[sn] << 8) + head[7]; +#if _WIZCHIP_ == 5300 + } +#endif + sock_pack_info[sn] = PACK_FIRST; + } + if (len < sock_remained_size[sn]) + pack_len = len; + else + pack_len = sock_remained_size[sn]; + // A20150601 : For W5300 + len = pack_len; +#if _WIZCHIP_ == 5300 + if (sock_pack_info[sn] & PACK_FIFOBYTE) { + *buf++ = sock_remained_byte[sn]; + pack_len -= 1; + sock_remained_size[sn] -= 1; + sock_pack_info[sn] &= ~PACK_FIFOBYTE; + } +#endif + // + // Need to packet length check (default 1472) + // + wiz_recv_data(sn, buf, pack_len); // data copy. + break; + case Sn_MR_MACRAW: + if (sock_remained_size[sn] == 0) { + wiz_recv_data(sn, head, 2); + setSn_CR(sn, Sn_CR_RECV); + while (getSn_CR(sn)) + ; + // read peer's IP address, port number & packet length + sock_remained_size[sn] = head[0]; + sock_remained_size[sn] = (sock_remained_size[sn] << 8) + head[1] - 2; +#if _WIZCHIP_ == W5300 + if (sock_remained_size[sn] & 0x01) + sock_remained_size[sn] = sock_remained_size[sn] + 1 - 4; + else + sock_remained_size[sn] -= 4; +#endif + if (sock_remained_size[sn] > 1514) { + wiz_sock_close(sn); + return SOCKFATAL_PACKLEN; + } + sock_pack_info[sn] = PACK_FIRST; + } + if (len < sock_remained_size[sn]) + pack_len = len; + else + pack_len = sock_remained_size[sn]; + wiz_recv_data(sn, buf, pack_len); + break; + //#if ( _WIZCHIP_ < 5200 ) + case Sn_MR_IPRAW: + if (sock_remained_size[sn] == 0) { + wiz_recv_data(sn, head, 6); + setSn_CR(sn, Sn_CR_RECV); + while (getSn_CR(sn)) + ; + addr[0] = head[0]; + addr[1] = head[1]; + addr[2] = head[2]; + addr[3] = head[3]; + sock_remained_size[sn] = head[4]; + // M20150401 : For Typing Error + // sock_remaiend_size[sn] = (sock_remained_size[sn] << 8) + head[5]; + sock_remained_size[sn] = (sock_remained_size[sn] << 8) + head[5]; + sock_pack_info[sn] = PACK_FIRST; + } + // + // Need to packet length check + // + if (len < sock_remained_size[sn]) + pack_len = len; + else + pack_len = sock_remained_size[sn]; + wiz_recv_data(sn, buf, pack_len); // data copy. + break; + //#endif + default: + wiz_recv_ignore(sn, pack_len); // data copy. + sock_remained_size[sn] = pack_len; + break; + } + setSn_CR(sn, Sn_CR_RECV); + /* wait to process the command... */ + while (getSn_CR(sn)) + ; + sock_remained_size[sn] -= pack_len; + // M20150601 : + // if(sock_remained_size[sn] != 0) sock_pack_info[sn] |= 0x01; + if (sock_remained_size[sn] != 0) { + sock_pack_info[sn] |= PACK_REMAINED; +#if _WIZCHIP_ == 5300 + if (pack_len & 0x01) sock_pack_info[sn] |= PACK_FIFOBYTE; +#endif + } else + sock_pack_info[sn] = PACK_COMPLETED; +#if _WIZCHIP_ == 5300 + pack_len = len; +#endif + // + // M20150409 : Explicit Type Casting + // return pack_len; + return (int32_t)pack_len; +} + +int8_t wiz_ctlsocket(uint8_t sn, ctlsock_type cstype, void *arg) { + uint8_t tmp = 0; + CHECK_SOCKNUM(); + switch (cstype) { + case CS_SET_IOMODE: + tmp = *((uint8_t *)arg); + if (tmp == SOCK_IO_NONBLOCK) + sock_io_mode |= (1 << sn); + else if (tmp == SOCK_IO_BLOCK) + sock_io_mode &= ~(1 << sn); + else + return SOCKERR_ARG; + break; + case CS_GET_IOMODE: + // M20140501 : implict type casting -> explict type casting + //*((uint8_t*)arg) = (sock_io_mode >> sn) & 0x0001; + *((uint8_t *)arg) = (uint8_t)((sock_io_mode >> sn) & 0x0001); + // + break; + case CS_GET_MAXTXBUF: + *((uint16_t *)arg) = getSn_TxMAX(sn); + break; + case CS_GET_MAXRXBUF: + *((uint16_t *)arg) = getSn_RxMAX(sn); + break; + case CS_CLR_INTERRUPT: + if ((*(uint8_t *)arg) > SIK_ALL) return SOCKERR_ARG; + setSn_IR(sn, *(uint8_t *)arg); + break; + case CS_GET_INTERRUPT: + *((uint8_t *)arg) = getSn_IR(sn); + break; +#if _WIZCHIP_ != 5100 + case CS_SET_INTMASK: + if ((*(uint8_t *)arg) > SIK_ALL) return SOCKERR_ARG; + setSn_IMR(sn, *(uint8_t *)arg); + break; + case CS_GET_INTMASK: + *((uint8_t *)arg) = getSn_IMR(sn); + break; +#endif + default: + return SOCKERR_ARG; + } + return SOCK_OK; +} + +int8_t wiz_setsockopt(uint8_t sn, sockopt_type sotype, void *arg) { + // M20131220 : Remove warning + // uint8_t tmp; + CHECK_SOCKNUM(); + switch (sotype) { + case SO_TTL: + setSn_TTL(sn, *(uint8_t *)arg); + break; + case SO_TOS: + setSn_TOS(sn, *(uint8_t *)arg); + break; + case SO_MSS: + setSn_MSSR(sn, *(uint16_t *)arg); + break; + case SO_DESTIP: + setSn_DIPR(sn, (uint8_t *)arg); + break; + case SO_DESTPORT: + setSn_DPORT(sn, *(uint16_t *)arg); + break; +#if _WIZCHIP_ != 5100 + case SO_KEEPALIVESEND: + CHECK_SOCKMODE(Sn_MR_TCP); +#if _WIZCHIP_ > 5200 + if (getSn_KPALVTR(sn) != 0) return SOCKERR_SOCKOPT; +#endif + setSn_CR(sn, Sn_CR_SEND_KEEP); + while (getSn_CR(sn) != 0) { + // M20131220 + // if ((tmp = getSn_IR(sn)) & Sn_IR_TIMEOUT) + if (getSn_IR(sn) & Sn_IR_TIMEOUT) { + setSn_IR(sn, Sn_IR_TIMEOUT); + return SOCKERR_TIMEOUT; + } + } + break; +#if !((_WIZCHIP_ == 5100) || (_WIZCHIP_ == 5200)) + case SO_KEEPALIVEAUTO: + CHECK_SOCKMODE(Sn_MR_TCP); + setSn_KPALVTR(sn, *(uint8_t *)arg); + break; +#endif +#endif + default: + return SOCKERR_ARG; + } + return SOCK_OK; +} + +int8_t wiz_getsockopt(uint8_t sn, sockopt_type sotype, void *arg) { + CHECK_SOCKNUM(); + switch (sotype) { + case SO_FLAG: + *(uint8_t *)arg = getSn_MR(sn) & 0xF0; + break; + case SO_TTL: + *(uint8_t *)arg = getSn_TTL(sn); + break; + case SO_TOS: + *(uint8_t *)arg = getSn_TOS(sn); + break; + case SO_MSS: + *(uint16_t *)arg = getSn_MSSR(sn); + break; + case SO_DESTIP: + getSn_DIPR(sn, (uint8_t *)arg); + break; + case SO_DESTPORT: + *(uint16_t *)arg = getSn_DPORT(sn); + break; +#if _WIZCHIP_ > 5200 + case SO_KEEPALIVEAUTO: + CHECK_SOCKMODE(Sn_MR_TCP); + *(uint16_t *)arg = getSn_KPALVTR(sn); + break; +#endif + case SO_SENDBUF: + *(uint16_t *)arg = getSn_TX_FSR(sn); + break; + case SO_RECVBUF: + *(uint16_t *)arg = getSn_RX_RSR(sn); + break; + case SO_STATUS: + *(uint8_t *)arg = getSn_SR(sn); + break; + case SO_REMAINSIZE: + if (getSn_MR(sn) & Sn_MR_TCP) + *(uint16_t *)arg = getSn_RX_RSR(sn); + else + *(uint16_t *)arg = sock_remained_size[sn]; + break; + case SO_PACKINFO: + // CHECK_SOCKMODE(Sn_MR_TCP); +#if _WIZCHIP_ != 5300 + if ((getSn_MR(sn) == Sn_MR_TCP)) return SOCKERR_SOCKMODE; +#endif + *(uint8_t *)arg = sock_pack_info[sn]; + break; + default: + return SOCKERR_SOCKOPT; + } + return SOCK_OK; +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/spi_interface.c b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/spi_interface.c new file mode 100644 index 000000000..7dbba1b46 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/spi_interface.c @@ -0,0 +1,35 @@ + +#include +#include +#include +#include +#include +#include + +#include "gpio_common.h" +#include "gpiohs.h" + +// #define SPI1_CS_GPIONUM 24 + +static x_base g_w5500_spi_lock; +/** + * @brief 进入临界区 + * @retval None + */ +void spi_enter_cris(void) { g_w5500_spi_lock = DisableLocalInterrupt(); } +/** + * @brief 退出临界区 + * @retval None + */ +void spi_exit_cris(void) { EnableLocalInterrupt(g_w5500_spi_lock); } + +/** + * @brief 片选信号输出低电平 + * @retval None + */ +void spi_select_cs(void) { gpiohs_set_pin(SPI1_CS0_PIN, GPIO_PV_LOW); } +/** + * @brief 片选信号输出高电平 + * @retval None + */ +void spi_deselete_cs(void) { gpiohs_set_pin(SPI1_CS0_PIN, GPIO_PV_HIGH); } \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/w5500.c b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/w5500.c new file mode 100755 index 000000000..e98739488 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/w5500.c @@ -0,0 +1,255 @@ +//***************************************************************************** +// +//! \file w5500.c +//! \brief W5500 HAL Interface. +//! \version 1.0.2 +//! \date 2013/10/21 +//! \par Revision history +//! <2015/02/05> Notice +//! The version history is not updated after this point. +//! Download the latest version directly from GitHub. Please visit the +//! our GitHub repository for ioLibrary. +//! >> https://github.com/Wiznet/ioLibrary_Driver +//! <2014/05/01> V1.0.2 +//! 1. Implicit type casting -> Explicit type casting. Refer to +//! M20140501 +//! Fixed the problem on porting into under 32bit MCU +//! Issued by Mathias ClauBen, wizwiki forum ID Think01 and bobh +//! Thank for your interesting and serious advices. +//! <2013/12/20> V1.0.1 +//! 1. Remove warning +//! 2. WIZCHIP_READ_BUF WIZCHIP_WRITE_BUF in case +//! _WIZCHIP_IO_MODE_SPI_FDM_ +//! for loop optimized(removed). refer to M20131220 +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! 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 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. +// +//***************************************************************************** +//#include +#include "w5500.h" + +#define _W5500_SPI_VDM_OP_ 0x00 +#define _W5500_SPI_FDM_OP_LEN1_ 0x01 +#define _W5500_SPI_FDM_OP_LEN2_ 0x02 +#define _W5500_SPI_FDM_OP_LEN4_ 0x03 + +#if (_WIZCHIP_ == 5500) +//////////////////////////////////////////////////// + +uint8_t WIZCHIP_READ(uint32_t AddrSel) { + uint8_t ret; + uint8_t spi_data[3]; + + WIZCHIP_CRITICAL_ENTER(); + WIZCHIP.CS._select(); + + AddrSel |= (_W5500_SPI_READ_ | _W5500_SPI_VDM_OP_); + + if (!WIZCHIP.IF.SPI._read_burst || + !WIZCHIP.IF.SPI._write_burst) // byte operation + { + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16); + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8); + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0); + } else // burst operation + { + spi_data[0] = (AddrSel & 0x00FF0000) >> 16; + spi_data[1] = (AddrSel & 0x0000FF00) >> 8; + spi_data[2] = (AddrSel & 0x000000FF) >> 0; + WIZCHIP.IF.SPI._write_burst(spi_data, 3); + } + ret = WIZCHIP.IF.SPI._read_byte(); + + WIZCHIP.CS._deselect(); + WIZCHIP_CRITICAL_EXIT(); + return ret; +} + +void WIZCHIP_WRITE(uint32_t AddrSel, uint8_t wb) { + uint8_t spi_data[4]; + + WIZCHIP_CRITICAL_ENTER(); + WIZCHIP.CS._select(); + + AddrSel |= (_W5500_SPI_WRITE_ | _W5500_SPI_VDM_OP_); + + // if(!WIZCHIP.IF.SPI._read_burst || !WIZCHIP.IF.SPI._write_burst) // byte + // operation + if (!WIZCHIP.IF.SPI._write_burst) // byte operation + { + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16); + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8); + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0); + WIZCHIP.IF.SPI._write_byte(wb); + } else // burst operation + { + spi_data[0] = (AddrSel & 0x00FF0000) >> 16; + spi_data[1] = (AddrSel & 0x0000FF00) >> 8; + spi_data[2] = (AddrSel & 0x000000FF) >> 0; + spi_data[3] = wb; + WIZCHIP.IF.SPI._write_burst(spi_data, 4); + } + + WIZCHIP.CS._deselect(); + WIZCHIP_CRITICAL_EXIT(); +} + +void WIZCHIP_READ_BUF(uint32_t AddrSel, uint8_t *pBuf, uint16_t len) { + uint8_t spi_data[3]; + uint16_t i; + + WIZCHIP_CRITICAL_ENTER(); + WIZCHIP.CS._select(); + + AddrSel |= (_W5500_SPI_READ_ | _W5500_SPI_VDM_OP_); + + if (!WIZCHIP.IF.SPI._read_burst || + !WIZCHIP.IF.SPI._write_burst) // byte operation + { + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16); + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8); + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0); + for (i = 0; i < len; i++) + pBuf[i] = WIZCHIP.IF.SPI._read_byte(); + } else // burst operation + { + spi_data[0] = (AddrSel & 0x00FF0000) >> 16; + spi_data[1] = (AddrSel & 0x0000FF00) >> 8; + spi_data[2] = (AddrSel & 0x000000FF) >> 0; + WIZCHIP.IF.SPI._write_burst(spi_data, 3); + WIZCHIP.IF.SPI._read_burst(pBuf, len); + } + + WIZCHIP.CS._deselect(); + WIZCHIP_CRITICAL_EXIT(); +} + +void WIZCHIP_WRITE_BUF(uint32_t AddrSel, uint8_t *pBuf, uint16_t len) { + uint8_t spi_data[3]; + uint16_t i; + + WIZCHIP_CRITICAL_ENTER(); + WIZCHIP.CS._select(); + + AddrSel |= (_W5500_SPI_WRITE_ | _W5500_SPI_VDM_OP_); + + if (!WIZCHIP.IF.SPI._write_burst) // byte operation + { + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16); + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8); + WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0); + for (i = 0; i < len; i++) + WIZCHIP.IF.SPI._write_byte(pBuf[i]); + } else // burst operation + { + spi_data[0] = (AddrSel & 0x00FF0000) >> 16; + spi_data[1] = (AddrSel & 0x0000FF00) >> 8; + spi_data[2] = (AddrSel & 0x000000FF) >> 0; + WIZCHIP.IF.SPI._write_burst(spi_data, 3); + WIZCHIP.IF.SPI._write_burst(pBuf, len); + } + + WIZCHIP.CS._deselect(); + WIZCHIP_CRITICAL_EXIT(); +} + +uint16_t getSn_TX_FSR(uint8_t sn) { + uint16_t val = 0, val1 = 0; + + do { + val1 = WIZCHIP_READ(Sn_TX_FSR(sn)); + val1 = (val1 << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_FSR(sn), 1)); + if (val1 != 0) { + val = WIZCHIP_READ(Sn_TX_FSR(sn)); + val = (val << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_FSR(sn), 1)); + } + } while (val != val1); + return val; +} + +uint16_t getSn_RX_RSR(uint8_t sn) { + uint16_t val = 0, val1 = 0; + + do { + val1 = WIZCHIP_READ(Sn_RX_RSR(sn)); + val1 = (val1 << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RSR(sn), 1)); + if (val1 != 0) { + val = WIZCHIP_READ(Sn_RX_RSR(sn)); + val = (val << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RSR(sn), 1)); + } + } while (val != val1); + return val; +} + +void wiz_send_data(uint8_t sn, uint8_t *wizdata, uint16_t len) { + uint16_t ptr = 0; + uint32_t addrsel = 0; + + if (len == 0) + return; + ptr = getSn_TX_WR(sn); + // M20140501 : implict type casting -> explict type casting + // addrsel = (ptr << 8) + (WIZCHIP_TXBUF_BLOCK(sn) << 3); + addrsel = ((uint32_t)ptr << 8) + (WIZCHIP_TXBUF_BLOCK(sn) << 3); + // + WIZCHIP_WRITE_BUF(addrsel, wizdata, len); + + ptr += len; + setSn_TX_WR(sn, ptr); +} + +void wiz_recv_data(uint8_t sn, uint8_t *wizdata, uint16_t len) { + uint16_t ptr = 0; + uint32_t addrsel = 0; + + if (len == 0) + return; + ptr = getSn_RX_RD(sn); + // M20140501 : implict type casting -> explict type casting + // addrsel = ((ptr << 8) + (WIZCHIP_RXBUF_BLOCK(sn) << 3); + addrsel = ((uint32_t)ptr << 8) + (WIZCHIP_RXBUF_BLOCK(sn) << 3); + // + WIZCHIP_READ_BUF(addrsel, wizdata, len); + ptr += len; + + setSn_RX_RD(sn, ptr); +} + +void wiz_recv_ignore(uint8_t sn, uint16_t len) { + uint16_t ptr = 0; + + ptr = getSn_RX_RD(sn); + ptr += len; + setSn_RX_RD(sn, ptr); +} + +#endif \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/wiz_ping.c b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/wiz_ping.c new file mode 100644 index 000000000..bb43bbcf5 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/wiz_ping.c @@ -0,0 +1,251 @@ + +#include "wiz_ping.h" + +#include +#include +#include +#include +#include + +#define Sn_PROTO(ch) (0x001408 + (ch << 5)) + +#define PING_BIND_PORT 3000 + +PINGMSGR PingRequest = {0}; +PINGMSGR PingReply = {0}; + +static uint16_t ping_RandomID = 0x1234; +static uint16_t ping_RandomSeqNum = 0x4321; +uint8_t ping_reply_received = 0; +uint8_t ping_req = 0; +uint8_t ping_rep = 0; +uint8_t ping_cnt = 0; +uint8_t ping_rep_buf[150] = {0}; + +// ping状态机 +#define PING_STA_FREE 0 +#define PING_STA_OPEN 1 +#define PING_STA_SEND 2 +#define PING_STA_WAIT 3 +#define PING_STA_CLOSE 4 + +uint8_t ping_sta = PING_STA_FREE; + +//当前ping的设备的序号 +uint8_t ping_socket = 0; + +#define bswap_16(A) ((((uint16)(A)&0xff00) >> 8) | (((uint16)(A)&0x00ff) << 8)) + +uint16_t htons(uint16_t n) { + union { + int i; + char c; + } u = {1}; + return u.c ? bswap_16(n) : n; +} + +uint16_t checksum(uint8_t *src, uint32_t len) { + uint16_t sum, tsum, i, j; + uint32_t lsum; + + j = len >> 1; + lsum = 0; + + for (i = 0; i < j; i++) { + tsum = src[i * 2]; + tsum = tsum << 8; + tsum += src[i * 2 + 1]; + lsum += tsum; + } + + if (len % 2) { + tsum = src[i * 2]; + lsum += (tsum << 8); + } + + sum = lsum; + sum = ~(sum + (lsum >> 16)); + return (uint16_t)sum; +} + +/** + *@brief 设定次数ping外网IP函数 + *@param sn- socket number + *@param addr- 外网IP地址 + *@param pCount- ping的次数 + *@return ping成功次数 + */ +uint8_t ping_count(uint8_t sn, uint16_t pCount, uint8_t *addr) { + uint16_t rlen, cnt, i; + + ping_reply_received = 0; + ping_req = 0; + ping_rep = 0; + KPrintf("Ping:%d.%d.%d.%d\r\n", (addr[0]), (addr[1]), (addr[2]), (addr[3])); + + for (i = 0; i < pCount + 1; i++) /*循环ping pCount次*/ + { + switch (getSn_SR(sn)) /*获取socket状态*/ + { + case SOCK_CLOSED: /*socket关闭状态*/ + { + wiz_sock_close(sn); + /* Create Socket */ + IINCHIP_WRITE(Sn_PROTO(sn), IPPROTO_ICMP); /*设置ICMP 协议*/ + if (wiz_socket(sn, Sn_MR_IPRAW, PING_BIND_PORT, 0) != + 0) /*判断ip raw模式socket是否开启*/ + { + } + /* Check socket register */ + while (getSn_SR(sn) != SOCK_IPRAW) { + MdelayKTask(50); + }; + break; + } + case SOCK_IPRAW: /*ip raw模式*/ + { + cnt = 0; + ping_request(sn, addr); /*发送Ping请求*/ + ping_req++; + while (1) { + if ((rlen = getSn_RX_RSR(sn)) > 0) { + rlen = ping_reply(sn, addr, rlen); /*获取回复信息*/ + ping_rep++; + if (ping_reply_received) { + break; + } + } + if ((cnt > 300)) { + cnt = 0; + break; + } else { + cnt++; + MdelayKTask(10); + } + } + break; + } + default: + break; + } + if (ping_req >= pCount) { + wiz_sock_close(sn); + } + } + return ping_rep; +} + +/** + *@brief ping请求函数 + *@param sn- socket number + *@param addr- P地址 + *@return 无 + */ +uint8_t ping_request(uint8_t sn, uint8_t *addr) { + uint8_t *buffer; + uint16_t i, temp_len = 0; + ping_reply_received = 0; /*ping 回复初始化标志位*/ + PingRequest.Type = PING_REQUEST; /*Ping-Request*/ + PingRequest.Code = CODE_ZERO; /*总是 '0'*/ + PingRequest.ID = htons(ping_RandomID++); /*设置ping响应ID为随机的整型变量*/ + PingRequest.SeqNum = + htons(ping_RandomSeqNum++); /*设置ping响应的序列号为随机整形变量*/ + for (i = 0; i < PING_BUF_LEN; i++) { + PingRequest.Data[i] = (i) % 8; /*ping相应的数在'0'~'8‘*/ + } + PingRequest.CheckSum = 0; + /* 计算响应次数*/ + PingRequest.CheckSum = + htons(checksum((uint8_t *)&PingRequest, sizeof(PingRequest))); + + /*发送ping响应到目的方 */ + if (wiz_sock_sendto(sn, (uint8_t *)&PingRequest, sizeof(PingRequest), addr, + PING_BIND_PORT) == 0) { + KPrintf("Fail to send ping-reply packet\r\n"); + } else { + KPrintf("ping send\n"); + } + return 0; +} + +/** + *@brief 解析Ping回复 + *@param sn- socket number + *@param addr- Ping地址 + *@return 无 + */ +uint8_t ping_reply(uint8_t sn, uint8_t *addr, uint16_t rlen) { + uint16_t tmp_checksum; + uint16_t len; + uint16_t i; + + uint16_t port = PING_BIND_PORT; + PINGMSGR PingReply; + + memset(ping_rep_buf, 0, sizeof(ping_rep_buf)); + len = wiz_sock_recvfrom(sn, ping_rep_buf, rlen, addr, + &port); /*从目的端接收数据*/ + + if (ping_rep_buf[0] == PING_REPLY) { + PingReply.Type = ping_rep_buf[0]; + PingReply.Code = ping_rep_buf[1]; + PingReply.CheckSum = (ping_rep_buf[3] << 8) + ping_rep_buf[2]; + PingReply.ID = (ping_rep_buf[5] << 8) + ping_rep_buf[4]; + PingReply.SeqNum = (ping_rep_buf[7] << 8) + ping_rep_buf[6]; + + for (i = 0; i < len - 8; i++) { + PingReply.Data[i] = ping_rep_buf[8 + i]; + } + tmp_checksum = ~checksum(ping_rep_buf, len); /*检查ping回复的次数*/ + if (tmp_checksum != 0xffff) { + KPrintf("tmp_checksum = %x\r\n", tmp_checksum); + } else { + KPrintf("Reply from %3d.%3d.%3d.%3d ID=%x Byte=%d\r\n\r\n", (addr[0]), + (addr[1]), (addr[2]), (addr[3]), htons(PingReply.ID), (rlen + 6)); + ping_reply_received = 1; /*当退出ping回复循环时,设置ping回复标志为1*/ + } + } else if (ping_rep_buf[0] == PING_REQUEST) { + PingReply.Code = ping_rep_buf[1]; + PingReply.Type = ping_rep_buf[2]; + PingReply.CheckSum = (ping_rep_buf[3] << 8) + ping_rep_buf[2]; + PingReply.ID = (ping_rep_buf[5] << 8) + ping_rep_buf[4]; + PingReply.SeqNum = (ping_rep_buf[7] << 8) + ping_rep_buf[6]; + for (i = 0; i < len - 8; i++) { + PingReply.Data[i] = ping_rep_buf[8 + i]; + } + tmp_checksum = PingReply.CheckSum; /*检查ping回复次数*/ + PingReply.CheckSum = 0; + if (tmp_checksum != PingReply.CheckSum) { + KPrintf(" \n CheckSum is in correct %x shold be %x \n", (tmp_checksum), + htons(PingReply.CheckSum)); + } else { + } + KPrintf( + " Request from %d.%d.%d.%d ID:%x SeqNum:%x :data size %d bytes\r\n", + (addr[0]), (addr[1]), (addr[2]), (addr[3]), (PingReply.ID), + (PingReply.SeqNum), (rlen + 6)); + ping_reply_received = 1; /* 当退出ping回复循环时,设置ping回复标志为1 + */ + } else { + KPrintf(" Unkonwn msg. \n"); + } + return 0; +} + +void wiz_ping_test(int argc, char *argv[]) { + uint32_t tmp_ip[4]; + uint8_t target_ip[4]; + if (argc >= 2) { + KPrintf("this is ping test: %s\n", argv[1]); + sscanf(argv[1], "%d.%d.%d.%d", &tmp_ip[0], &tmp_ip[1], &tmp_ip[2], + &tmp_ip[3]); + target_ip[0] = (uint8_t)tmp_ip[0]; + target_ip[1] = (uint8_t)tmp_ip[1]; + target_ip[2] = (uint8_t)tmp_ip[2]; + target_ip[3] = (uint8_t)tmp_ip[3]; + ping_count(ping_socket, 5, target_ip); + // ping_request(ping_socket, target_ip); + } +} +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), + ping, wiz_ping_test, ping to given addr); \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/wiz_ping.h b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/wiz_ping.h new file mode 100644 index 000000000..3ead801b8 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/wiz_ping.h @@ -0,0 +1,35 @@ +#ifndef _WIZ_PING_H_ +#define _WIZ_PING_H_ + +#include "socket.h" +#include "w5500.h" + +#define PING_BUF_LEN 32 +#define PING_REQUEST 8 +#define PING_REPLY 0 +#define CODE_ZERO 0 + +#define SOCKET_ERROR 1 +#define TIMEOUT_ERROR 2 +#define SUCCESS 3 +#define REPLY_ERROR 4 + +typedef struct pingmsg { + uint8_t Type; // 0 - Ping Reply, 8 - Ping Request + uint8_t Code; // Always 0 + uint16_t CheckSum; // Check sum + uint16_t ID; // Identification + uint16_t SeqNum; // Sequence Number + int8_t Data[PING_BUF_LEN]; // Ping Data : 1452 = IP RAW MTU - + // sizeof(Type+Code+CheckSum+ID+SeqNum) +} PINGMSGR; + +uint8_t ping_count(uint8_t sn, uint16_t pCount, uint8_t *addr); + +uint8_t ping_request(uint8_t s, uint8_t *addr); + +uint8_t ping_reply(uint8_t s, uint8_t *addr, uint16_t rlen); + +void Ethernet_ping_service_deal(uint8_t sn); + +#endif \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/wizchip_conf.c b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/wizchip_conf.c new file mode 100755 index 000000000..1407c852f --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/ethernet/wizchip_conf.c @@ -0,0 +1,862 @@ +//****************************************************************************/ +//! +//! \file wizchip_conf.c +//! \brief WIZCHIP Config Header File. +//! \version 1.0.1 +//! \date 2013/10/21 +//! \par Revision history +//! <2015/02/05> Notice +//! The version history is not updated after this point. +//! Download the latest version directly from GitHub. Please visit the +//! our GitHub repository for ioLibrary. +//! >> https://github.com/Wiznet/ioLibrary_Driver +//! <2014/05/01> V1.0.1 Refer to M20140501 +//! 1. Explicit type casting in wizchip_bus_readdata() & +//! wizchip_bus_writedata() +// Issued by Mathias ClauBen. +//! uint32_t type converts into ptrdiff_t first. And then recoverting +//! it into uint8_t* For remove the warning when pointer type size is +//! not 32bit. If ptrdiff_t doesn't support in your complier, You +//! should must replace ptrdiff_t into your suitable pointer type. +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! 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 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. +// +//*****************************************************************************/ +// A20140501 : for use the type - ptrdiff_t +#include +// + +#include "wizchip_conf.h" + +///////////// +// M20150401 : Remove ; in the default callback function such as +// wizchip_cris_enter(), wizchip_cs_select() and etc. +///////////// + +/** + * @brief Default function to enable interrupt. + * @note This function help not to access wrong address. If you do not describe + * this function or register any functions, null function is called. + */ +// void wizchip_cris_enter(void) {}; +void wizchip_cris_enter(void) {} + +/** + * @brief Default function to disable interrupt. + * @note This function help not to access wrong address. If you do not describe + * this function or register any functions, null function is called. + */ +// void wizchip_cris_exit(void) {}; +void wizchip_cris_exit(void) {} + +/** + * @brief Default function to select chip. + * @note This function help not to access wrong address. If you do not describe + * this function or register any functions, null function is called. + */ +// void wizchip_cs_select(void) {}; +void wizchip_cs_select(void) {} + +/** + * @brief Default function to deselect chip. + * @note This function help not to access wrong address. If you do not describe + * this function or register any functions, null function is called. + */ +// void wizchip_cs_deselect(void) {}; +void wizchip_cs_deselect(void) {} + +/** + * @brief Default function to read in direct or indirect interface. + * @note This function help not to access wrong address. If you do not describe + * this function or register any functions, null function is called. + */ +// M20150601 : Rename the function for integrating with W5300 +// uint8_t wizchip_bus_readbyte(uint32_t AddrSel) { return * ((volatile uint8_t +// *)((ptrdiff_t) AddrSel)); } +iodata_t wizchip_bus_readdata(uint32_t AddrSel) { + return *((volatile iodata_t *)((ptrdiff_t)AddrSel)); +} + +/** + * @brief Default function to write in direct or indirect interface. + * @note This function help not to access wrong address. If you do not describe + * this function or register any functions, null function is called. + */ +// M20150601 : Rename the function for integrating with W5300 +// void wizchip_bus_writebyte(uint32_t AddrSel, uint8_t wb) { *((volatile +// uint8_t*)((ptrdiff_t)AddrSel)) = wb; } +void wizchip_bus_writedata(uint32_t AddrSel, iodata_t wb) { + *((volatile iodata_t *)((ptrdiff_t)AddrSel)) = wb; +} + +/** + * @brief Default function to read in SPI interface. + * @note This function help not to access wrong address. If you do not describe + * this function or register any functions, null function is called. + */ +// uint8_t wizchip_spi_readbyte(void) {return 0;}; +uint8_t wizchip_spi_readbyte(void) { return 0; } + +/** + * @brief Default function to write in SPI interface. + * @note This function help not to access wrong address. If you do not describe + * this function or register any functions, null function is called. + */ +// void wizchip_spi_writebyte(uint8_t wb) {}; +void wizchip_spi_writebyte(uint8_t wb) {} + +/** + * @brief Default function to burst read in SPI interface. + * @note This function help not to access wrong address. If you do not describe + * this function or register any functions, null function is called. + */ +// void wizchip_spi_readburst(uint8_t* pBuf, uint16_t len) {}; +void wizchip_spi_readburst(uint8_t *pBuf, uint16_t len) {} + +/** + * @brief Default function to burst write in SPI interface. + * @note This function help not to access wrong address. If you do not describe + * this function or register any functions, null function is called. + */ +// void wizchip_spi_writeburst(uint8_t* pBuf, uint16_t len) {}; +void wizchip_spi_writeburst(uint8_t *pBuf, uint16_t len) {} + +/** + * @\ref _WIZCHIP instance + */ +// +// M20150401 : For a compiler didnot support a member of structure +// Replace the assignment of struct members with the assingment of +// array +// +/* +_WIZCHIP WIZCHIP = + { + .id = _WIZCHIP_ID_, + .if_mode = _WIZCHIP_IO_MODE_, + .CRIS._enter = wizchip_cris_enter, + .CRIS._exit = wizchip_cris_exit, + .CS._select = wizchip_cs_select, + .CS._deselect = wizchip_cs_deselect, + .IF.BUS._read_byte = wizchip_bus_readbyte, + .IF.BUS._write_byte = wizchip_bus_writebyte +// .IF.SPI._read_byte = wizchip_spi_readbyte, +// .IF.SPI._write_byte = wizchip_spi_writebyte + }; +*/ +_WIZCHIP WIZCHIP = {_WIZCHIP_IO_MODE_, + _WIZCHIP_ID_, + {wizchip_cris_enter, wizchip_cris_exit}, + {wizchip_cs_select, wizchip_cs_deselect}, + { + {// M20150601 : Rename the function + // wizchip_bus_readbyte, + // wizchip_bus_writebyte + wizchip_bus_readdata, wizchip_bus_writedata}, + + }}; + +static uint8_t _DNS_[4]; // DNS server ip address +static dhcp_mode _DHCP_; // DHCP mode + +void reg_wizchip_cris_cbfunc(void (*cris_en)(void), void (*cris_ex)(void)) { + if (!cris_en || !cris_ex) { + WIZCHIP.CRIS._enter = wizchip_cris_enter; + WIZCHIP.CRIS._exit = wizchip_cris_exit; + } else { + WIZCHIP.CRIS._enter = cris_en; + WIZCHIP.CRIS._exit = cris_ex; + } +} + +void reg_wizchip_cs_cbfunc(void (*cs_sel)(void), void (*cs_desel)(void)) { + if (!cs_sel || !cs_desel) { + WIZCHIP.CS._select = wizchip_cs_select; + WIZCHIP.CS._deselect = wizchip_cs_deselect; + } else { + WIZCHIP.CS._select = cs_sel; + WIZCHIP.CS._deselect = cs_desel; + } +} + +// M20150515 : For integrating with W5300 +// void reg_wizchip_bus_cbfunc(uint8_t(*bus_rb)(uint32_t addr), void +// (*bus_wb)(uint32_t addr, uint8_t wb)) +void reg_wizchip_bus_cbfunc(iodata_t (*bus_rb)(uint32_t addr), + void (*bus_wb)(uint32_t addr, iodata_t wb)) { + while (!(WIZCHIP.if_mode & _WIZCHIP_IO_MODE_BUS_)) + ; + // M20150601 : Rename call back function for integrating with W5300 + /* + if(!bus_rb || !bus_wb) + { + WIZCHIP.IF.BUS._read_byte = wizchip_bus_readbyte; + WIZCHIP.IF.BUS._write_byte = wizchip_bus_writebyte; + } + else + { + WIZCHIP.IF.BUS._read_byte = bus_rb; + WIZCHIP.IF.BUS._write_byte = bus_wb; + } + */ + if (!bus_rb || !bus_wb) { + WIZCHIP.IF.BUS._read_data = wizchip_bus_readdata; + WIZCHIP.IF.BUS._write_data = wizchip_bus_writedata; + } else { + WIZCHIP.IF.BUS._read_data = bus_rb; + WIZCHIP.IF.BUS._write_data = bus_wb; + } +} + +void reg_wizchip_spi_cbfunc(uint8_t (*spi_rb)(void), + void (*spi_wb)(uint8_t wb)) { + while (!(WIZCHIP.if_mode & _WIZCHIP_IO_MODE_SPI_)) + ; + + if (!spi_rb || !spi_wb) { + WIZCHIP.IF.SPI._read_byte = wizchip_spi_readbyte; + WIZCHIP.IF.SPI._write_byte = wizchip_spi_writebyte; + } else { + WIZCHIP.IF.SPI._read_byte = spi_rb; + WIZCHIP.IF.SPI._write_byte = spi_wb; + } +} + +// 20140626 Eric Added for SPI burst operations +void reg_wizchip_spiburst_cbfunc(void (*spi_rb)(uint8_t *pBuf, uint16_t len), + void (*spi_wb)(uint8_t *pBuf, uint16_t len)) { + while (!(WIZCHIP.if_mode & _WIZCHIP_IO_MODE_SPI_)) + ; + + if (!spi_rb || !spi_wb) { + WIZCHIP.IF.SPI._read_burst = wizchip_spi_readburst; + WIZCHIP.IF.SPI._write_burst = wizchip_spi_writeburst; + } else { + WIZCHIP.IF.SPI._read_burst = spi_rb; + WIZCHIP.IF.SPI._write_burst = spi_wb; + } +} + +int8_t ctlwizchip(ctlwizchip_type cwtype, void *arg) { +#if _WIZCHIP_ == W5100S || _WIZCHIP_ == W5200 || _WIZCHIP_ == W5500 + uint8_t tmp = 0; +#endif + uint8_t *ptmp[2] = {0, 0}; + switch (cwtype) { + case CW_RESET_WIZCHIP: + wizchip_sw_reset(); + break; + case CW_INIT_WIZCHIP: + if (arg != 0) { + ptmp[0] = (uint8_t *)arg; + ptmp[1] = ptmp[0] + _WIZCHIP_SOCK_NUM_; + } + return wizchip_init(ptmp[0], ptmp[1]); + case CW_CLR_INTERRUPT: + wizchip_clrinterrupt(*((intr_kind *)arg)); + break; + case CW_GET_INTERRUPT: + *((intr_kind *)arg) = wizchip_getinterrupt(); + break; + case CW_SET_INTRMASK: + wizchip_setinterruptmask(*((intr_kind *)arg)); + break; + case CW_GET_INTRMASK: + *((intr_kind *)arg) = wizchip_getinterruptmask(); + break; +// M20150601 : This can be supported by W5200, W5500 +//#if _WIZCHIP_ > W5100 +#if (_WIZCHIP_ == W5200 || _WIZCHIP_ == W5500) + case CW_SET_INTRTIME: + setINTLEVEL(*(uint16_t *)arg); + break; + case CW_GET_INTRTIME: + *(uint16_t *)arg = getINTLEVEL(); + break; +#endif + case CW_GET_ID: + ((uint8_t *)arg)[0] = WIZCHIP.id[0]; + ((uint8_t *)arg)[1] = WIZCHIP.id[1]; + ((uint8_t *)arg)[2] = WIZCHIP.id[2]; + ((uint8_t *)arg)[3] = WIZCHIP.id[3]; + ((uint8_t *)arg)[4] = WIZCHIP.id[4]; + ((uint8_t *)arg)[5] = WIZCHIP.id[5]; + ((uint8_t *)arg)[6] = 0; + break; +#if _WIZCHIP_ == W5100S || _WIZCHIP_ == W5500 + case CW_RESET_PHY: + wizphy_reset(); + break; + case CW_SET_PHYCONF: + wizphy_setphyconf((wiz_PhyConf *)arg); + break; + case CW_GET_PHYCONF: + wizphy_getphyconf((wiz_PhyConf *)arg); + break; + case CW_GET_PHYSTATUS: + break; + case CW_SET_PHYPOWMODE: + return wizphy_setphypmode(*(uint8_t *)arg); +#endif +#if _WIZCHIP_ == W5100S || _WIZCHIP_ == W5200 || _WIZCHIP_ == W5500 + case CW_GET_PHYPOWMODE: + tmp = wizphy_getphypmode(); + if ((int8_t)tmp == -1) + return -1; + *(uint8_t *)arg = tmp; + break; + case CW_GET_PHYLINK: + tmp = wizphy_getphylink(); + if ((int8_t)tmp == -1) + return -1; + *(uint8_t *)arg = tmp; + break; +#endif + default: + return -1; + } + return 0; +} + +int8_t ctlnetwork(ctlnetwork_type cntype, void *arg) { + + switch (cntype) { + case CN_SET_NETINFO: + wizchip_setnetinfo((wiz_NetInfo *)arg); + break; + case CN_GET_NETINFO: + wizchip_getnetinfo((wiz_NetInfo *)arg); + break; + case CN_SET_NETMODE: + return wizchip_setnetmode(*(netmode_type *)arg); + case CN_GET_NETMODE: + *(netmode_type *)arg = wizchip_getnetmode(); + break; + case CN_SET_TIMEOUT: + wizchip_settimeout((wiz_NetTimeout *)arg); + break; + case CN_GET_TIMEOUT: + wizchip_gettimeout((wiz_NetTimeout *)arg); + break; + default: + return -1; + } + return 0; +} + +void wizchip_sw_reset(void) { + uint8_t gw[4], sn[4], sip[4]; + uint8_t mac[6]; +// A20150601 +#if _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_BUS_INDIR_ + uint16_t mr = (uint16_t)getMR(); + setMR(mr | MR_IND); +#endif + // + getSHAR(mac); + getGAR(gw); + getSUBR(sn); + getSIPR(sip); + setMR(MR_RST); + getMR(); // for delay +// A2015051 : For indirect bus mode +#if _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_BUS_INDIR_ + setMR(mr | MR_IND); +#endif + // + setSHAR(mac); + setGAR(gw); + setSUBR(sn); + setSIPR(sip); +} + +int8_t wizchip_init(uint8_t *txsize, uint8_t *rxsize) { + int8_t i; +#if _WIZCHIP_ < W5200 + int8_t j; +#endif + int8_t tmp = 0; + wizchip_sw_reset(); + if (txsize) { + tmp = 0; +// M20150601 : For integrating with W5300 +#if _WIZCHIP_ == W5300 + for (i = 0; i < _WIZCHIP_SOCK_NUM_; i++) { + if (txsize[i] >= 64) + return -1; // No use 64KB even if W5300 support max 64KB memory + // allocation + tmp += txsize[i]; + if (tmp > 128) + return -1; + } + if (tmp % 8) + return -1; +#else + for (i = 0; i < _WIZCHIP_SOCK_NUM_; i++) { + tmp += txsize[i]; + +#if _WIZCHIP_ < W5200 // 2016.10.28 peter add condition for w5100 and w5100s + if (tmp > 8) + return -1; +#else + if (tmp > 16) + return -1; +#endif + } + for (i = 0; i < _WIZCHIP_SOCK_NUM_; i++) { +#if _WIZCHIP_ < W5200 // 2016.10.28 peter add condition for w5100 + j = 0; + while ((txsize[i] >> j != 1) && (txsize[i] != 0)) { + j++; + } + setSn_TXBUF_SIZE(i, j); +#else + setSn_TXBUF_SIZE(i, txsize[i]); +#endif + } + +#endif + } + + if (rxsize) { + tmp = 0; +#if _WIZCHIP_ == W5300 + for (i = 0; i < _WIZCHIP_SOCK_NUM_; i++) { + if (rxsize[i] >= 64) + return -1; // No use 64KB even if W5300 support max 64KB memory + // allocation + tmp += rxsize[i]; + if (tmp > 128) + return -1; + } + if (tmp % 8) + return -1; +#else + for (i = 0; i < _WIZCHIP_SOCK_NUM_; i++) { + tmp += rxsize[i]; +#if _WIZCHIP_ < W5200 // 2016.10.28 peter add condition for w5100 and w5100s + if (tmp > 8) + return -1; +#else + if (tmp > 16) + return -1; +#endif + } + + for (i = 0; i < _WIZCHIP_SOCK_NUM_; i++) { +#if _WIZCHIP_ < W5200 // add condition for w5100 + j = 0; + while ((rxsize[i] >> j != 1) && (txsize[i] != 0)) { + j++; + } + setSn_RXBUF_SIZE(i, j); +#else + setSn_RXBUF_SIZE(i, rxsize[i]); +#endif + } +#endif + } + return 0; +} + +void wizchip_clrinterrupt(intr_kind intr) { + uint8_t ir = (uint8_t)intr; + uint8_t sir = (uint8_t)((uint16_t)intr >> 8); +#if _WIZCHIP_ < W5500 + ir |= (1 << 4); // IK_WOL +#endif +#if _WIZCHIP_ == W5200 + ir |= (1 << 6); +#endif + +#if _WIZCHIP_ < W5200 + sir &= 0x0F; +#endif + +#if _WIZCHIP_ <= W5100S + ir |= sir; + setIR(ir); +// A20150601 : For integrating with W5300 +#elif _WIZCHIP_ == W5300 + setIR(((((uint16_t)ir) << 8) | (((uint16_t)sir) & 0x00FF))); +#else + setIR(ir); + // M20200227 : For clear + // setSIR(sir); + for (ir = 0; ir < 8; ir++) { + if (sir & (0x01 << ir)) + setSn_IR(ir, 0xff); + } + +#endif +} + +intr_kind wizchip_getinterrupt(void) { + uint8_t ir = 0; + uint8_t sir = 0; + uint16_t ret = 0; +#if _WIZCHIP_ <= W5100S + ir = getIR(); + sir = ir & 0x0F; +// A20150601 : For integrating with W5300 +#elif _WIZCHIP_ == W5300 + ret = getIR(); + ir = (uint8_t)(ret >> 8); + sir = (uint8_t)ret; +#else + ir = getIR(); + sir = getSIR(); +#endif + +// M20150601 : For Integrating with W5300 +//#if _WIZCHIP_ < W5500 +#if _WIZCHIP_ < W5200 + ir &= ~(1 << 4); // IK_WOL +#endif +#if _WIZCHIP_ == W5200 + ir &= ~(1 << 6); +#endif + ret = sir; + ret = (ret << 8) + ir; + return (intr_kind)ret; +} + +void wizchip_setinterruptmask(intr_kind intr) { + uint8_t imr = (uint8_t)intr; + uint8_t simr = (uint8_t)((uint16_t)intr >> 8); +#if _WIZCHIP_ < W5500 + imr &= ~(1 << 4); // IK_WOL +#endif +#if _WIZCHIP_ == W5200 + imr &= ~(1 << 6); +#endif + +#if _WIZCHIP_ < W5200 + simr &= 0x0F; + imr |= simr; + setIMR(imr); +// A20150601 : For integrating with W5300 +#elif _WIZCHIP_ == W5300 + setIMR(((((uint16_t)imr) << 8) | (((uint16_t)simr) & 0x00FF))); +#else + setIMR(imr); + setSIMR(simr); +#endif +} + +intr_kind wizchip_getinterruptmask(void) { + uint8_t imr = 0; + uint8_t simr = 0; + uint16_t ret = 0; +#if _WIZCHIP_ < W5200 + imr = getIMR(); + simr = imr & 0x0F; +// A20150601 : For integrating with W5300 +#elif _WIZCHIP_ == W5300 + ret = getIMR(); + imr = (uint8_t)(ret >> 8); + simr = (uint8_t)ret; +#else + imr = getIMR(); + simr = getSIMR(); +#endif + +#if _WIZCHIP_ < W5500 + imr &= ~(1 << 4); // IK_WOL +#endif +#if _WIZCHIP_ == W5200 + imr &= ~(1 << 6); // IK_DEST_UNREACH +#endif + ret = simr; + ret = (ret << 8) + imr; + return (intr_kind)ret; +} + +int8_t wizphy_getphylink(void) { + int8_t tmp = PHY_LINK_OFF; +#if _WIZCHIP_ == W5100S + if (getPHYSR() & PHYSR_LNK) + tmp = PHY_LINK_ON; +#elif _WIZCHIP_ == W5200 + if (getPHYSTATUS() & PHYSTATUS_LINK) + tmp = PHY_LINK_ON; +#elif _WIZCHIP_ == W5500 + if (getPHYCFGR() & PHYCFGR_LNK_ON) + tmp = PHY_LINK_ON; + +#else + tmp = -1; +#endif + return tmp; +} + +#if _WIZCHIP_ > W5100 + +int8_t wizphy_getphypmode(void) { + int8_t tmp = 0; +#if _WIZCHIP_ == W5200 + if (getPHYSTATUS() & PHYSTATUS_POWERDOWN) + tmp = PHY_POWER_DOWN; + else + tmp = PHY_POWER_NORM; +#elif _WIZCHIP_ == 5500 + if ((getPHYCFGR() & PHYCFGR_OPMDC_ALLA) == PHYCFGR_OPMDC_PDOWN) + tmp = PHY_POWER_DOWN; + else + tmp = PHY_POWER_NORM; +#else + tmp = -1; +#endif + return tmp; +} +#endif + +#if _WIZCHIP_ == W5100S +void wizphy_reset(void) { + uint16_t tmp = wiz_mdio_read(PHYMDIO_BMCR); + tmp |= BMCR_RESET; + wiz_mdio_write(PHYMDIO_BMCR, tmp); + while (wiz_mdio_read(PHYMDIO_BMCR) & BMCR_RESET) { + } +} + +void wizphy_setphyconf(wiz_PhyConf *phyconf) { + uint16_t tmp = wiz_mdio_read(PHYMDIO_BMCR); + if (phyconf->mode == PHY_MODE_AUTONEGO) + tmp |= BMCR_AUTONEGO; + else { + tmp &= ~BMCR_AUTONEGO; + if (phyconf->duplex == PHY_DUPLEX_FULL) { + tmp |= BMCR_DUP; + } else { + tmp &= ~BMCR_DUP; + } + if (phyconf->speed == PHY_SPEED_100) { + tmp |= BMCR_SPEED; + } else { + tmp &= ~BMCR_SPEED; + } + } + wiz_mdio_write(PHYMDIO_BMCR, tmp); +} + +void wizphy_getphyconf(wiz_PhyConf *phyconf) { + uint16_t tmp = 0; + tmp = wiz_mdio_read(PHYMDIO_BMCR); + phyconf->by = PHY_CONFBY_SW; + if (tmp & BMCR_AUTONEGO) { + phyconf->mode = PHY_MODE_AUTONEGO; + } else { + phyconf->mode = PHY_MODE_MANUAL; + if (tmp & BMCR_DUP) + phyconf->duplex = PHY_DUPLEX_FULL; + else + phyconf->duplex = PHY_DUPLEX_HALF; + if (tmp & BMCR_SPEED) + phyconf->speed = PHY_SPEED_100; + else + phyconf->speed = PHY_SPEED_10; + } +} + +int8_t wizphy_setphypmode(uint8_t pmode) { + uint16_t tmp = 0; + tmp = wiz_mdio_read(PHYMDIO_BMCR); + if (pmode == PHY_POWER_DOWN) { + tmp |= BMCR_PWDN; + } else { + tmp &= ~BMCR_PWDN; + } + wiz_mdio_write(PHYMDIO_BMCR, tmp); + tmp = wiz_mdio_read(PHYMDIO_BMCR); + if (pmode == PHY_POWER_DOWN) { + if (tmp & BMCR_PWDN) + return 0; + } else { + if ((tmp & BMCR_PWDN) != BMCR_PWDN) + return 0; + } + return -1; +} + +#endif +#if _WIZCHIP_ == W5500 +void wizphy_reset(void) { + uint8_t tmp = getPHYCFGR(); + tmp &= PHYCFGR_RST; + setPHYCFGR(tmp); + tmp = getPHYCFGR(); + tmp |= ~PHYCFGR_RST; + setPHYCFGR(tmp); +} + +void wizphy_setphyconf(wiz_PhyConf *phyconf) { + uint8_t tmp = 0; + if (phyconf->by == PHY_CONFBY_SW) + tmp |= PHYCFGR_OPMD; + else + tmp &= ~PHYCFGR_OPMD; + if (phyconf->mode == PHY_MODE_AUTONEGO) + tmp |= PHYCFGR_OPMDC_ALLA; + else { + if (phyconf->duplex == PHY_DUPLEX_FULL) { + if (phyconf->speed == PHY_SPEED_100) + tmp |= PHYCFGR_OPMDC_100F; + else + tmp |= PHYCFGR_OPMDC_10F; + } else { + if (phyconf->speed == PHY_SPEED_100) + tmp |= PHYCFGR_OPMDC_100H; + else + tmp |= PHYCFGR_OPMDC_10H; + } + } + setPHYCFGR(tmp); + wizphy_reset(); +} + +void wizphy_getphyconf(wiz_PhyConf *phyconf) { + uint8_t tmp = 0; + tmp = getPHYCFGR(); + phyconf->by = (tmp & PHYCFGR_OPMD) ? PHY_CONFBY_SW : PHY_CONFBY_HW; + switch (tmp & PHYCFGR_OPMDC_ALLA) { + case PHYCFGR_OPMDC_ALLA: + case PHYCFGR_OPMDC_100FA: + phyconf->mode = PHY_MODE_AUTONEGO; + break; + default: + phyconf->mode = PHY_MODE_MANUAL; + break; + } + switch (tmp & PHYCFGR_OPMDC_ALLA) { + case PHYCFGR_OPMDC_100FA: + case PHYCFGR_OPMDC_100F: + case PHYCFGR_OPMDC_100H: + phyconf->speed = PHY_SPEED_100; + break; + default: + phyconf->speed = PHY_SPEED_10; + break; + } + switch (tmp & PHYCFGR_OPMDC_ALLA) { + case PHYCFGR_OPMDC_100FA: + case PHYCFGR_OPMDC_100F: + case PHYCFGR_OPMDC_10F: + phyconf->duplex = PHY_DUPLEX_FULL; + break; + default: + phyconf->duplex = PHY_DUPLEX_HALF; + break; + } +} + +void wizphy_getphystat(wiz_PhyConf *phyconf) { + uint8_t tmp = getPHYCFGR(); + phyconf->duplex = + (tmp & PHYCFGR_DPX_FULL) ? PHY_DUPLEX_FULL : PHY_DUPLEX_HALF; + phyconf->speed = (tmp & PHYCFGR_SPD_100) ? PHY_SPEED_100 : PHY_SPEED_10; +} + +int8_t wizphy_setphypmode(uint8_t pmode) { + uint8_t tmp = 0; + tmp = getPHYCFGR(); + if ((tmp & PHYCFGR_OPMD) == 0) + return -1; + tmp &= ~PHYCFGR_OPMDC_ALLA; + if (pmode == PHY_POWER_DOWN) + tmp |= PHYCFGR_OPMDC_PDOWN; + else + tmp |= PHYCFGR_OPMDC_ALLA; + setPHYCFGR(tmp); + wizphy_reset(); + tmp = getPHYCFGR(); + if (pmode == PHY_POWER_DOWN) { + if (tmp & PHYCFGR_OPMDC_PDOWN) + return 0; + } else { + if (tmp & PHYCFGR_OPMDC_ALLA) + return 0; + } + return -1; +} +#endif + +void wizchip_setnetinfo(wiz_NetInfo *pnetinfo) { + setSHAR(pnetinfo->mac); + setGAR(pnetinfo->gw); + setSUBR(pnetinfo->sn); + setSIPR(pnetinfo->ip); + _DNS_[0] = pnetinfo->dns[0]; + _DNS_[1] = pnetinfo->dns[1]; + _DNS_[2] = pnetinfo->dns[2]; + _DNS_[3] = pnetinfo->dns[3]; + _DHCP_ = pnetinfo->dhcp; +} + +void wizchip_getnetinfo(wiz_NetInfo *pnetinfo) { + getSHAR(pnetinfo->mac); + getGAR(pnetinfo->gw); + getSUBR(pnetinfo->sn); + getSIPR(pnetinfo->ip); + pnetinfo->dns[0] = _DNS_[0]; + pnetinfo->dns[1] = _DNS_[1]; + pnetinfo->dns[2] = _DNS_[2]; + pnetinfo->dns[3] = _DNS_[3]; + pnetinfo->dhcp = _DHCP_; +} + +int8_t wizchip_setnetmode(netmode_type netmode) { + uint8_t tmp = 0; +#if _WIZCHIP_ != W5500 + if (netmode & ~(NM_WAKEONLAN | NM_PPPOE | NM_PINGBLOCK)) + return -1; +#else + if (netmode & ~(NM_WAKEONLAN | NM_PPPOE | NM_PINGBLOCK | NM_FORCEARP)) + return -1; +#endif + tmp = getMR(); + tmp |= (uint8_t)netmode; + setMR(tmp); + return 0; +} + +netmode_type wizchip_getnetmode(void) { return (netmode_type)getMR(); } + +void wizchip_settimeout(wiz_NetTimeout *nettime) { + setRCR(nettime->retry_cnt); + setRTR(nettime->time_100us); +} + +void wizchip_gettimeout(wiz_NetTimeout *nettime) { + nettime->retry_cnt = getRCR(); + nettime->time_100us = getRTR(); +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/gpio/drv_io_config.c b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/gpio/drv_io_config.c index 38389e29b..683ad22f5 100644 --- a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/gpio/drv_io_config.c +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/gpio/drv_io_config.c @@ -9,44 +9,49 @@ */ /** -* @file drv_io_config.c -* @brief support xidatong-riscv64-board io configure -* @version 2.0 -* @author AIIT XUOS Lab -* @date 2022-07-25 -*/ + * @file drv_io_config.c + * @brief support xidatong-riscv64-board io configure + * @version 2.0 + * @author AIIT XUOS Lab + * @date 2022-07-25 + */ /************************************************* File name: drv_io_config.c Description: support kd233-board io configure Others: take RT-Thread v4.0.2/bsp/k210/driver/drv_io_config.c for references https://github.com/RT-Thread/rt-thread/tree/v4.0.2 -History: +History: 1. Date: 2022-07-25 Author: AIIT XUOS Lab Modification: support kd233-board io configure *************************************************/ -#include -#include #include "drv_io_config.h" -#include + +#include +#include +#include #define HS_GPIO(n) (FUNC_GPIOHS0 + n) -#define IOCONFIG(pin,func) {pin, func, #func} +#define IOCONFIG(pin, func) \ + { pin, func, #func } -static struct io_config -{ - int io_num; - fpioa_function_t func; - const char * FuncName; -} io_config[] = -{ +static struct io_config { + int io_num; + fpioa_function_t func; + const char* FuncName; +} io_config[] = { #ifdef BSP_USING_LCD - IOCONFIG(BSP_LCD_CS_PIN, FUNC_SPI0_SS0), - IOCONFIG(BSP_LCD_WR_PIN, FUNC_SPI0_SCLK), - IOCONFIG(BSP_LCD_DC_PIN, HS_GPIO(LCD_DC_PIN)), + IOCONFIG(BSP_LCD_CS_PIN, FUNC_SPI0_SS0), + IOCONFIG(BSP_LCD_WR_PIN, FUNC_SPI0_SCLK), + IOCONFIG(BSP_LCD_DC_PIN, HS_GPIO(LCD_DC_PIN)), +#endif + +#ifdef BSP_USING_W5500 + IOCONFIG(BSP_WIZ_RST_PIN, HS_GPIO(WIZ_RST_PIN)), + IOCONFIG(BSP_WIZ_INT_PIN, HS_GPIO(WIZ_INT_PIN)), #endif #ifdef BSP_USING_SPI1 @@ -83,63 +88,59 @@ static struct io_config #endif #ifdef BSP_USING_CH438 - IOCONFIG(BSP_CH438_ALE_PIN, HS_GPIO(FPIOA_CH438_ALE)), - IOCONFIG(BSP_CH438_NWR_PIN, HS_GPIO(FPIOA_CH438_NWR)), - IOCONFIG(BSP_CH438_NRD_PIN, HS_GPIO(FPIOA_CH438_NRD)), - IOCONFIG(BSP_CH438_INT_PIN, HS_GPIO(FPIOA_CH438_INT)), - IOCONFIG(BSP_CH438_D0_PIN, HS_GPIO(FPIOA_CH438_D0)), - IOCONFIG(BSP_CH438_D1_PIN, HS_GPIO(FPIOA_CH438_D1)), - IOCONFIG(BSP_CH438_D2_PIN, HS_GPIO(FPIOA_CH438_D2)), - IOCONFIG(BSP_CH438_D3_PIN, HS_GPIO(FPIOA_CH438_D3)), - IOCONFIG(BSP_CH438_D4_PIN, HS_GPIO(FPIOA_CH438_D4)), - IOCONFIG(BSP_CH438_D5_PIN, HS_GPIO(FPIOA_CH438_D5)), - IOCONFIG(BSP_CH438_D6_PIN, HS_GPIO(FPIOA_CH438_D6)), - IOCONFIG(BSP_CH438_D7_PIN, HS_GPIO(FPIOA_CH438_D7)) + IOCONFIG(BSP_CH438_ALE_PIN, HS_GPIO(FPIOA_CH438_ALE)), + IOCONFIG(BSP_CH438_NWR_PIN, HS_GPIO(FPIOA_CH438_NWR)), + IOCONFIG(BSP_CH438_NRD_PIN, HS_GPIO(FPIOA_CH438_NRD)), + IOCONFIG(BSP_CH438_INT_PIN, HS_GPIO(FPIOA_CH438_INT)), + IOCONFIG(BSP_CH438_D0_PIN, HS_GPIO(FPIOA_CH438_D0)), + IOCONFIG(BSP_CH438_D1_PIN, HS_GPIO(FPIOA_CH438_D1)), + IOCONFIG(BSP_CH438_D2_PIN, HS_GPIO(FPIOA_CH438_D2)), + IOCONFIG(BSP_CH438_D3_PIN, HS_GPIO(FPIOA_CH438_D3)), + IOCONFIG(BSP_CH438_D4_PIN, HS_GPIO(FPIOA_CH438_D4)), + IOCONFIG(BSP_CH438_D5_PIN, HS_GPIO(FPIOA_CH438_D5)), + IOCONFIG(BSP_CH438_D6_PIN, HS_GPIO(FPIOA_CH438_D6)), + IOCONFIG(BSP_CH438_D7_PIN, HS_GPIO(FPIOA_CH438_D7)) #endif }; -static int PrintIoConfig() -{ - int i; - KPrintf("IO Configuration Table\n"); - KPrintf("┌───────┬────────────────────────┐\n"); - KPrintf("│Pin │Function │\n"); - KPrintf("├───────┼────────────────────────┤\n"); - for(i = 0; i < sizeof io_config / sizeof io_config[0]; i++) - { - KPrintf("│%-2d │%-24.24s│\n", io_config[i].io_num, io_config[i].FuncName); - } - KPrintf("└───────┴────────────────────────┘\n"); - return 0; +static int PrintIoConfig() { + int i; + KPrintf("IO Configuration Table\n"); + KPrintf("┌───────┬────────────────────────┐\n"); + KPrintf("│Pin │Function │\n"); + KPrintf("├───────┼────────────────────────┤\n"); + for (i = 0; i < sizeof io_config / sizeof io_config[0]; i++) { + KPrintf("│%-2d │%-24.24s│\n", io_config[i].io_num, + io_config[i].FuncName); + } + KPrintf("└───────┴────────────────────────┘\n"); + return 0; } -SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0), - io,PrintIoConfig,print io config); +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC) | + SHELL_CMD_PARAM_NUM(0), + io, PrintIoConfig, print io config); -int IoConfigInit(void) -{ - int count = sizeof(io_config) / sizeof(io_config[0]); - int i; - int ret = 0; +int IoConfigInit(void) { + int count = sizeof(io_config) / sizeof(io_config[0]); + int i; + int ret = 0; - sysctl_set_power_mode(SYSCTL_POWER_BANK0, SYSCTL_POWER_V18); - sysctl_set_power_mode(SYSCTL_POWER_BANK1, SYSCTL_POWER_V18); - sysctl_set_power_mode(SYSCTL_POWER_BANK2, SYSCTL_POWER_V18); + sysctl_set_power_mode(SYSCTL_POWER_BANK0, SYSCTL_POWER_V18); + sysctl_set_power_mode(SYSCTL_POWER_BANK1, SYSCTL_POWER_V18); + sysctl_set_power_mode(SYSCTL_POWER_BANK2, SYSCTL_POWER_V18); #ifdef BSP_USING_UART2 - // for IO-27/28 - sysctl_set_power_mode(SYSCTL_POWER_BANK4, SYSCTL_POWER_V33); + // for IO-27/28 + sysctl_set_power_mode(SYSCTL_POWER_BANK4, SYSCTL_POWER_V33); #endif -#if defined(BSP_USING_UART1) || defined(BSP_USING_UART3) - // for IO-20~23 - sysctl_set_power_mode(SYSCTL_POWER_BANK3, SYSCTL_POWER_V33); +#if defined(BSP_USING_UART1) || defined(BSP_USING_UART3) + // for IO-20~23 + sysctl_set_power_mode(SYSCTL_POWER_BANK3, SYSCTL_POWER_V33); #endif - for(i = 0; i < count; i++) - { - ret = FpioaSetFunction(io_config[i].io_num, io_config[i].func); - if(ret != 0) - return ret; - } + for (i = 0; i < count; i++) { + ret = FpioaSetFunction(io_config[i].io_num, io_config[i].func); + if (ret != 0) return ret; + } - return ret; + return ret; } - diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/gpio/gpio.c b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/gpio/gpio.c index 9802b69f7..6e71be831 100644 --- a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/gpio/gpio.c +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/gpio/gpio.c @@ -26,6 +26,7 @@ #include "utils.h" #include "fpioa.h" #include "sysctl.h" +#include #define GPIO_MAX_PINNO 8 volatile gpio_t* const gpio = (volatile gpio_t*)GPIO_BASE_ADDR; diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/connect_spi.h b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/connect_spi.h new file mode 100644 index 000000000..cd746d016 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/connect_spi.h @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_spi.h +* @brief define aiit-riscv64-board spi function and struct +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef CONNECT_SPI_H +#define CONNECT_SPI_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int HwSpiInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/connect_w5500.h b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/connect_w5500.h new file mode 100644 index 000000000..43359e8f4 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/connect_w5500.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan + * PSL v2. You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY + * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO + * NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the + * Mulan PSL v2 for more details. + */ + +/** + * @file connect_w5500.h + * @brief define aiit-riscv64-board spi function and struct + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2022-10-16 + */ + +#ifndef _CONNECT_W5500_H_ +#define _CONNECT_W5500_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static struct Bus *spi_bus; + +int HwWiznetInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/drv_io_config.h b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/drv_io_config.h index 4e247e955..7b2dfadca 100644 --- a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/drv_io_config.h +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/drv_io_config.h @@ -9,19 +9,19 @@ */ /** -* @file drv_io_config.h -* @brief define xidatong-riscv64-board io configure -* @version 2.0 -* @author AIIT XUOS Lab -* @date 2022-07-25 -*/ + * @file drv_io_config.h + * @brief define xidatong-riscv64-board io configure + * @version 2.0 + * @author AIIT XUOS Lab + * @date 2022-07-25 + */ /************************************************* File name: drv_io_config.h Description: define xidatong-riscv64-board io configure Others: take RT-Thread v4.0.2/bsp/k210/driver/drv_io_config.h for references https://github.com/RT-Thread/rt-thread/tree/v4.0.2 -History: +History: 1. Date: 2022-07-25 Author: AIIT XUOS Lab Modification: add xidatong-riscv64-board io configure define @@ -30,52 +30,57 @@ Modification: add xidatong-riscv64-board io configure define #ifndef __DRV_IO_CONFIG_H__ #define __DRV_IO_CONFIG_H__ -enum HS_GPIO_CONFIG -{ +#include + +enum HS_GPIO_CONFIG { #ifdef BSP_USING_LCD - LCD_DC_PIN = 0, /* LCD DC PIN */ + LCD_DC_PIN = 0, /* LCD DC PIN */ #endif #ifdef BSP_SPI1_USING_SS0 - SPI1_CS0_PIN, + SPI1_CS0_PIN, #endif #ifdef BSP_SPI1_USING_SS1 - SPI1_CS1_PIN, + SPI1_CS1_PIN, #endif #ifdef BSP_SPI1_USING_SS2 - SPI1_CS2_PIN, + SPI1_CS2_PIN, #endif #ifdef BSP_SPI1_USING_SS3 - SPI1_CS3_PIN, + SPI1_CS3_PIN, #endif - GPIO_ALLOC_START /* index of gpio driver start */ +#ifdef BSP_USING_W5500 + WIZ_RST_PIN, + WIZ_INT_PIN, +#endif + GPIO_ALLOC_START /* index of gpio driver start */ }; #ifdef BSP_USING_CH438 -#define FPIOA_CH438_ALE 12 -#define FPIOA_CH438_NWR 13 -#define FPIOA_CH438_NRD 14 -#define FPIOA_CH438_D0 15 -#define FPIOA_CH438_D1 16 -#define FPIOA_CH438_D2 17 -#define FPIOA_CH438_D3 18 -#define FPIOA_CH438_D4 19 -#define FPIOA_CH438_D5 20 -#define FPIOA_CH438_D6 21 -#define FPIOA_CH438_D7 22 -#define FPIOA_CH438_INT 23 +#define FPIOA_CH438_ALE 12 +#define FPIOA_CH438_NWR 13 +#define FPIOA_CH438_NRD 14 +#define FPIOA_CH438_D0 15 +#define FPIOA_CH438_D1 16 +#define FPIOA_CH438_D2 17 +#define FPIOA_CH438_D3 18 +#define FPIOA_CH438_D4 19 +#define FPIOA_CH438_D5 20 +#define FPIOA_CH438_D6 21 +#define FPIOA_CH438_D7 22 +#define FPIOA_CH438_INT 23 -#define BSP_CH438_ALE_PIN 24 -#define BSP_CH438_NWR_PIN 25 -#define BSP_CH438_NRD_PIN 26 -#define BSP_CH438_D0_PIN 27 -#define BSP_CH438_D1_PIN 28 -#define BSP_CH438_D2_PIN 29 -#define BSP_CH438_D3_PIN 30 -#define BSP_CH438_D4_PIN 31 -#define BSP_CH438_D5_PIN 32 -#define BSP_CH438_D6_PIN 33 -#define BSP_CH438_D7_PIN 34 -#define BSP_CH438_INT_PIN 35 +#define BSP_CH438_ALE_PIN 24 +#define BSP_CH438_NWR_PIN 25 +#define BSP_CH438_NRD_PIN 26 +#define BSP_CH438_D0_PIN 27 +#define BSP_CH438_D1_PIN 28 +#define BSP_CH438_D2_PIN 29 +#define BSP_CH438_D3_PIN 30 +#define BSP_CH438_D4_PIN 31 +#define BSP_CH438_D5_PIN 32 +#define BSP_CH438_D6_PIN 33 +#define BSP_CH438_D7_PIN 34 +#define BSP_CH438_INT_PIN 35 #endif extern int IoConfigInit(void); diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/hardware_spi.h b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/hardware_spi.h new file mode 100644 index 000000000..4d3fd3599 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/hardware_spi.h @@ -0,0 +1,494 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** +* @file hardware_spi.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __HARDWARE_SPI_H__ +#define __HARDWARE_SPI_H__ + +#include "dmac.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +typedef struct _spi +{ + /* SPI Control Register 0 (0x00)*/ + volatile uint32_t ctrlr0; + /* SPI Control Register 1 (0x04)*/ + volatile uint32_t ctrlr1; + /* SPI Enable Register (0x08)*/ + volatile uint32_t ssienr; + /* SPI Microwire Control Register (0x0c)*/ + volatile uint32_t mwcr; + /* SPI Slave Enable Register (0x10)*/ + volatile uint32_t ser; + /* SPI Baud Rate Select (0x14)*/ + volatile uint32_t baudr; + /* SPI Transmit FIFO Threshold Level (0x18)*/ + volatile uint32_t txftlr; + /* SPI Receive FIFO Threshold Level (0x1c)*/ + volatile uint32_t rxftlr; + /* SPI Transmit FIFO Level Register (0x20)*/ + volatile uint32_t txflr; + /* SPI Receive FIFO Level Register (0x24)*/ + volatile uint32_t rxflr; + /* SPI Status Register (0x28)*/ + volatile uint32_t sr; + /* SPI Interrupt Mask Register (0x2c)*/ + volatile uint32_t imr; + /* SPI Interrupt Status Register (0x30)*/ + volatile uint32_t isr; + /* SPI Raw Interrupt Status Register (0x34)*/ + volatile uint32_t risr; + /* SPI Transmit FIFO Overflow Interrupt Clear Register (0x38)*/ + volatile uint32_t txoicr; + /* SPI Receive FIFO Overflow Interrupt Clear Register (0x3c)*/ + volatile uint32_t rxoicr; + /* SPI Receive FIFO Underflow Interrupt Clear Register (0x40)*/ + volatile uint32_t rxuicr; + /* SPI Multi-Master Interrupt Clear Register (0x44)*/ + volatile uint32_t msticr; + /* SPI Interrupt Clear Register (0x48)*/ + volatile uint32_t icr; + /* SPI DMA Control Register (0x4c)*/ + volatile uint32_t dmacr; + /* SPI DMA Transmit Data Level (0x50)*/ + volatile uint32_t dmatdlr; + /* SPI DMA Receive Data Level (0x54)*/ + volatile uint32_t dmardlr; + /* SPI Identification Register (0x58)*/ + volatile uint32_t idr; + /* SPI DWC_ssi component version (0x5c)*/ + volatile uint32_t ssic_version_id; + /* SPI Data Register 0-36 (0x60 -- 0xec)*/ + volatile uint32_t dr[36]; + /* SPI RX Sample Delay Register (0xf0)*/ + volatile uint32_t rx_sample_delay; + /* SPI SPI Control Register (0xf4)*/ + volatile uint32_t spi_ctrlr0; + /* reserved (0xf8)*/ + volatile uint32_t resv; + /* SPI XIP Mode bits (0xfc)*/ + volatile uint32_t xip_mode_bits; + /* SPI XIP INCR transfer opcode (0x100)*/ + volatile uint32_t xip_incr_inst; + /* SPI XIP WRAP transfer opcode (0x104)*/ + volatile uint32_t xip_wrap_inst; + /* SPI XIP Control Register (0x108)*/ + volatile uint32_t xip_ctrl; + /* SPI XIP Slave Enable Register (0x10c)*/ + volatile uint32_t xip_ser; + /* SPI XIP Receive FIFO Overflow Interrupt Clear Register (0x110)*/ + volatile uint32_t xrxoicr; + /* SPI XIP time out register for continuous transfers (0x114)*/ + volatile uint32_t xip_cnt_time_out; + volatile uint32_t endian; +} __attribute__((packed, aligned(4))) spi_t; +/* clang-format on */ + +typedef enum _spi_device_num +{ + SPI_DEVICE_0, + SPI_DEVICE_1, + SPI_DEVICE_2, + SPI_DEVICE_3, + SPI_DEVICE_MAX, +} spi_device_num_t; + +typedef enum _spi_work_mode +{ + SPI_WORK_MODE_0, + SPI_WORK_MODE_1, + SPI_WORK_MODE_2, + SPI_WORK_MODE_3, +} spi_work_mode_t; + +typedef enum _spi_frame_format +{ + SPI_FF_STANDARD, + SPI_FF_DUAL, + SPI_FF_QUAD, + SPI_FF_OCTAL +} spi_frame_format_t; + +typedef enum _spi_instruction_address_trans_mode +{ + SPI_AITM_STANDARD, + SPI_AITM_ADDR_STANDARD, + SPI_AITM_AS_FRAME_FORMAT +} spi_instruction_address_trans_mode_t; + +typedef enum _spi_transfer_mode +{ + SPI_TMOD_TRANS_RECV, + SPI_TMOD_TRANS, + SPI_TMOD_RECV, + SPI_TMOD_EEROM +} spi_transfer_mode_t; + + +typedef enum _spi_transfer_width +{ + SPI_TRANS_CHAR = 0x1, + SPI_TRANS_SHORT = 0x2, + SPI_TRANS_INT = 0x4, +} spi_transfer_width_t; + +typedef enum _spi_chip_select +{ + SPI_CHIP_SELECT_0, + SPI_CHIP_SELECT_1, + SPI_CHIP_SELECT_2, + SPI_CHIP_SELECT_3, + SPI_CHIP_SELECT_MAX, +} spi_chip_select_t; + +typedef enum +{ + WRITE_CONFIG, + READ_CONFIG, + WRITE_DATA_BYTE, + READ_DATA_BYTE, + WRITE_DATA_BLOCK, + READ_DATA_BLOCK, +} spi_slave_command_e; + +typedef struct +{ + uint8_t cmd; + uint8_t err; + uint32_t addr; + uint32_t len; +} spi_slave_command_t; + +typedef enum +{ + IDLE, + COMMAND, + TRANSFER, +} spi_slave_status_e; + +typedef int (*spi_slave_receive_callback_t)(void *ctx); + +typedef struct _spi_slave_instance +{ + uint8_t int_pin; + uint8_t ready_pin; + dmac_channel_number_t dmac_channel; + uint8_t dfs; + uint8_t slv_oe; + uint8_t work_mode; + size_t data_bit_length; + volatile spi_slave_status_e status; + volatile spi_slave_command_t command; + volatile uint8_t *config_ptr; + uint32_t config_len; + spi_slave_receive_callback_t callback; +} spi_slave_instance_t; + +typedef struct _spi_data_t +{ + dmac_channel_number_t tx_channel; + dmac_channel_number_t rx_channel; + uint32_t *tx_buf; + size_t tx_len; + uint32_t *rx_buf; + size_t rx_len; + spi_transfer_mode_t TransferMode; + bool fill_mode; +} spi_data_t; + +extern volatile spi_t *const spi[4]; + +/** + * @brief Set spi configuration + * + * @param[in] spi_num Spi bus number + * @param[in] mode Spi mode + * @param[in] frame_format Spi frame format + * @param[in] data_bit_length Spi data bit length + * @param[in] endian 0:little-endian 1:big-endian + * + * @return Void + */ +void spi_init(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format, + size_t data_bit_length, uint32_t endian); + +/** + * @brief Set multiline configuration + * + * @param[in] spi_num Spi bus number + * @param[in] instruction_length Instruction length + * @param[in] address_length Address length + * @param[in] wait_cycles Wait cycles + * @param[in] instruction_address_trans_mode Spi transfer mode + * + */ +void spi_init_non_standard(spi_device_num_t spi_num, uint32_t instruction_length, uint32_t address_length, + uint32_t wait_cycles, spi_instruction_address_trans_mode_t instruction_address_trans_mode); + +/** + * @brief Spi send data + * + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] CmdBuff Spi command buffer point + * @param[in] CmdLen Spi command length + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_send_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *CmdBuff, + size_t CmdLen, const uint8_t *tx_buff, size_t tx_len); + +/** + * @brief Spi receive data + * + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] CmdBuff Spi command buffer point + * @param[in] CmdLen Spi command length + * @param[in] rx_buff Spi receive buffer point + * @param[in] rx_len Spi receive buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_receive_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *CmdBuff, + size_t CmdLen, uint8_t *rx_buff, size_t rx_len); + +/** + * @brief Spi special receive data + * + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] CmdBuff Spi command buffer point + * @param[in] CmdLen Spi command length + * @param[in] rx_buff Spi receive buffer point + * @param[in] rx_len Spi receive buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_receive_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *CmdBuff, + size_t CmdLen, uint8_t *rx_buff, size_t rx_len); + +/** + * @brief Spi special send data + * + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] CmdBuff Spi command buffer point + * @param[in] CmdLen Spi command length + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_send_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *CmdBuff, + size_t CmdLen, const uint8_t *tx_buff, size_t tx_len); + +/** + * @brief Spi send data by dma + * + * @param[in] channel_num Dmac channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] CmdBuff Spi command buffer point + * @param[in] CmdLen Spi command length + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_send_data_standard_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const uint8_t *CmdBuff, size_t CmdLen, const uint8_t *tx_buff, size_t tx_len); + +/** + * @brief Spi receive data by dma + * + * @param[in] w_channel_num Dmac write channel number + * @param[in] r_channel_num Dmac read channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] CmdBuff Spi command buffer point + * @param[in] CmdLen Spi command length + * @param[in] rx_buff Spi receive buffer point + * @param[in] rx_len Spi receive buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_receive_data_standard_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *CmdBuff, + size_t CmdLen, uint8_t *rx_buff, size_t rx_len); + +/** + * @brief Spi special send data by dma + * + * @param[in] channel_num Dmac channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] CmdBuff Spi command buffer point + * @param[in] CmdLen Spi command length + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_send_data_multiple_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const uint32_t *CmdBuff, size_t CmdLen, const uint8_t *tx_buff, size_t tx_len); + +/** + * @brief Spi special receive data by dma + * + * @param[in] dma_send_channel_num Dmac write channel number + * @param[in] dma_receive_channel_num Dmac read channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] CmdBuff Spi command buffer point + * @param[in] CmdLen Spi command length + * @param[in] rx_buff Spi receive buffer point + * @param[in] rx_len Spi receive buffer length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_receive_data_multiple_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *CmdBuff, + size_t CmdLen, uint8_t *rx_buff, size_t rx_len); + +/** + * @brief Spi fill dma + * + * @param[in] channel_num Dmac channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] tx_buff Spi command buffer point + * @param[in] tx_len Spi command length + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_fill_data_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, spi_chip_select_t chip_select, + const uint32_t *tx_buff, size_t tx_len); + +/** + * @brief Spi normal send by dma + * + * @param[in] channel_num Dmac channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] tx_buff Spi transmit buffer point + * @param[in] tx_len Spi transmit buffer length + * @param[in] stw Spi transfer width + * + * @return Result + * - 0 Success + * - Other Fail + */ +void spi_send_data_normal_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const void *tx_buff, size_t tx_len, spi_transfer_width_t spi_transfer_width); + +/** + * @brief Spi normal send by dma + * + * @param[in] spi_num Spi bus number + * @param[in] spi_clk Spi clock rate + * + * @return The real spi clock rate + */ +uint32_t spi_set_clk_rate(spi_device_num_t spi_num, uint32_t spi_clk); + +/** + * @brief Spi full duplex send receive data by dma + * + * @param[in] dma_send_channel_num Dmac write channel number + * @param[in] dma_receive_channel_num Dmac read channel number + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] tx_buf Spi send buffer + * @param[in] tx_len Spi send buffer length + * @param[in] rx_buf Spi receive buffer + * @param[in] rx_len Spi receive buffer length + * + */ +void spi_dup_send_receive_data_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, + const uint8_t *tx_buf, size_t tx_len, uint8_t *rx_buf, size_t rx_len); + +/** + * @brief Set spi slave configuration + * + * @param[in] int_pin SPI master starts sending data interrupt. + * @param[in] ready_pin SPI slave ready. + * @param[in] dmac_channel Dmac channel number for block. + * @param[in] data_bit_length Spi data bit length + * @param[in] data SPI slave device data buffer. + * @param[in] len The length of SPI slave device data buffer. + * @param[in] callback Callback of spi slave. + * + * @return Void + */ +void spi_slave_config(uint8_t int_pin, uint8_t ready_pin, dmac_channel_number_t dmac_channel, size_t data_bit_length, uint8_t *data, uint32_t len, spi_slave_receive_callback_t callback); + +/** + * @brief Spi handle transfer data operations + * + * @param[in] spi_num Spi bus number + * @param[in] chip_select Spi chip select + * @param[in] data Spi transfer data information + * @param[in] cb Spi DMA callback + * + */ +void spi_handle_data_dma(spi_device_num_t spi_num, spi_chip_select_t chip_select, spi_data_t data, plic_interrupt_t *cb); + +#ifdef __cplusplus +} +#endif + +#endif /* __HARDWARE_SPI_H__ */ diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/socket.h b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/socket.h new file mode 100755 index 000000000..91e1a7bd9 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/socket.h @@ -0,0 +1,585 @@ +//***************************************************************************** +// +//! \file socket.h +//! \brief SOCKET APIs Header file. +//! \details SOCKET APIs like as berkeley socket api. +//! \version 1.0.2 +//! \date 2013/10/21 +//! \par Revision history +//! <2015/02/05> Notice +//! The version history is not updated after this point. +//! Download the latest version directly from GitHub. Please visit the +//! our GitHub repository for ioLibrary. +//! >> https://github.com/Wiznet/ioLibrary_Driver +//! <2014/05/01> V1.0.2. Refer to M20140501 +//! 1. Modify the comment : SO_REMAINED -> PACK_REMAINED +//! 2. Add the comment as zero byte udp data reception in getsockopt(). +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! 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 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. +// +//***************************************************************************** +/** + * @defgroup WIZnet_socket_APIs 1. WIZnet socket APIs + * @brief WIZnet socket APIs are based on Berkeley socket APIs, thus it has + * much similar name and interface. But there is a little bit of difference. + * @details + * Comparison between WIZnet and Berkeley SOCKET APIs + * + * + * + * + * + * + * + * + * + * + * + * + * + *
API WIZnet Berkeley
socket() O O
bind() X O
listen() O O
connect() O O
accept() X O
recv() O O
send() O O
recvfrom() O O
sendto() O O
closesocket() O
close() & disconnect()
O
+ * There are @b bind() and @b accept() functions in @b Berkeley SOCKET API but, + * not in @b WIZnet SOCKET API. Because socket() of WIZnet is not only creating + * a SOCKET but also binding a local port number, and listen() of WIZnet is not + * only listening to connection request from client but also accepting the + * connection request. \n When you program "TCP SERVER" with Berkeley SOCKET + * API, you can use only one listen port. When the listen SOCKET accepts a + * connection request from a client, it keeps listening. After accepting the + * connection request, a new SOCKET is created and the new SOCKET is used in + * communication with the client. \n Following figure shows network flow diagram + * by Berkeley SOCKET API. + * @image html Berkeley_SOCKET.jpg "" + * But, When you program "TCP SERVER" with WIZnet SOCKET API, you can use as + * many as 8 listen SOCKET with same port number. \n Because there's no accept() + * in WIZnet SOCKET APIs, when the listen SOCKET accepts a connection request + * from a client, it is changed in order to communicate with the client. And the + * changed SOCKET is not listening any more and is dedicated for communicating + * with the client. \n If there're many listen SOCKET with same listen port + * number and a client requests a connection, the SOCKET which has the smallest + * SOCKET number accepts the request and is changed as communication SOCKET. \n + * Following figure shows network flow diagram by WIZnet SOCKET API. + * @image html WIZnet_SOCKET.jpg "" + */ +#ifndef _SOCKET_H_ +#define _SOCKET_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#include "wizchip_conf.h" + +#define SOCKET uint8_t ///< SOCKET type define for legacy driver + +#define SOCK_OK 1 ///< Result is OK about socket process. +#define SOCK_BUSY \ + 0 ///< Socket is busy on processing the operation. Valid only Non-block IO + ///< Mode. +#define SOCK_FATAL -1000 ///< Result is fatal error about socket process. + +#define SOCK_ERROR 0 +#define SOCKERR_SOCKNUM (SOCK_ERROR - 1) ///< Invalid socket number +#define SOCKERR_SOCKOPT (SOCK_ERROR - 2) ///< Invalid socket option +#define SOCKERR_SOCKINIT \ + (SOCK_ERROR - 3) ///< Socket is not initialized or SIPR is Zero IP address + ///< when Sn_MR_TCP +#define SOCKERR_SOCKCLOSED (SOCK_ERROR - 4) ///< Socket unexpectedly closed. +#define SOCKERR_SOCKMODE \ + (SOCK_ERROR - 5) ///< Invalid socket mode for socket operation. +#define SOCKERR_SOCKFLAG (SOCK_ERROR - 6) ///< Invalid socket flag +#define SOCKERR_SOCKSTATUS \ + (SOCK_ERROR - 7) ///< Invalid socket status for socket operation. +#define SOCKERR_ARG (SOCK_ERROR - 10) ///< Invalid argument. +#define SOCKERR_PORTZERO (SOCK_ERROR - 11) ///< Port number is zero +#define SOCKERR_IPINVALID (SOCK_ERROR - 12) ///< Invalid IP address +#define SOCKERR_TIMEOUT (SOCK_ERROR - 13) ///< Timeout occurred +#define SOCKERR_DATALEN \ + (SOCK_ERROR - 14) ///< Data length is zero or greater than buffer max size. +#define SOCKERR_BUFFER \ + (SOCK_ERROR - 15) ///< Socket buffer is not enough for data communication. + +#define SOCKFATAL_PACKLEN \ + (SOCK_FATAL - 1) ///< Invalid packet length. Fatal Error. + +/* + * SOCKET FLAG + */ +#define SF_ETHER_OWN \ + (Sn_MR_MFEN) ///< In @ref Sn_MR_MACRAW, Receive only the packet as broadcast, + ///< multicast and own packet +#define SF_IGMP_VER2 \ + (Sn_MR_MC) ///< In @ref Sn_MR_UDP with \ref SF_MULTI_ENABLE, Select IGMP + ///< version 2. +#define SF_TCP_NODELAY (Sn_MR_ND) ///< In @ref Sn_MR_TCP, Use to nodelayed ack. +#define SF_MULTI_ENABLE \ + (Sn_MR_MULTI) ///< In @ref Sn_MR_UDP, Enable multicast mode. + +#if _WIZCHIP_ == 5500 +#define SF_BROAD_BLOCK \ + (Sn_MR_BCASTB) ///< In @ref Sn_MR_UDP or @ref Sn_MR_MACRAW, Block broadcast + ///< packet. Valid only in W5500 +#define SF_MULTI_BLOCK \ + (Sn_MR_MMB) ///< In @ref Sn_MR_MACRAW, Block multicast packet. Valid only in + ///< W5500 +#define SF_IPv6_BLOCK \ + (Sn_MR_MIP6B) ///< In @ref Sn_MR_MACRAW, Block IPv6 packet. Valid only in + ///< W5500 +#define SF_UNI_BLOCK \ + (Sn_MR_UCASTB) ///< In @ref Sn_MR_UDP with \ref SF_MULTI_ENABLE. Valid only + ///< in W5500 +#endif + +// A201505 : For W5300 +#if _WIZCHIP_ == 5300 +#define SF_TCP_ALIGN \ + 0x02 ///< Valid only \ref Sn_MR_TCP and W5300, refer to \ref Sn_MR_ALIGN +#endif + +#define SF_IO_NONBLOCK \ + 0x01 ///< Socket nonblock io mode. It used parameter in \ref socket(). + +/* + * UDP & MACRAW Packet Infomation + */ +#define PACK_FIRST \ + 0x80 ///< In Non-TCP packet, It indicates to start receiving a packet. (When + ///< W5300, This flag can be applied) +#define PACK_REMAINED \ + 0x01 ///< In Non-TCP packet, It indicates to remain a packet to be received. + ///< (When W5300, This flag can be applied) +#define PACK_COMPLETED \ + 0x00 ///< In Non-TCP packet, It indicates to complete to receive a packet. + ///< (When W5300, This flag can be applied) +// A20150601 : For Integrating with W5300 +#define PACK_FIFOBYTE \ + 0x02 ///< Valid only W5300, It indicate to have read already the Sn_RX_FIFOR. +// + +#ifndef AF_WIZ +#define AF_WIZ 46 +#endif + +/** + * @ingroup WIZnet_socket_APIs + * @brief Open a socket. + * @details Initializes the socket with 'sn' passed as parameter and open. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param protocol Protocol type to operate such as TCP, UDP and MACRAW. + * @param port Port number to be bined. + * @param flag Socket flags as \ref SF_ETHER_OWN, \ref SF_IGMP_VER2, \ref + * SF_TCP_NODELAY, \ref SF_MULTI_ENABLE, \ref SF_IO_NONBLOCK and so on.\n Valid + * flags only in W5500 : @ref SF_BROAD_BLOCK, @ref SF_MULTI_BLOCK, @ref + * SF_IPv6_BLOCK, and @ref SF_UNI_BLOCK. + * @sa Sn_MR + * + * @return @b Success : The socket number @b 'sn' passed as parameter\n + * @b Fail :\n @ref SOCKERR_SOCKNUM - Invalid socket number\n + * @ref SOCKERR_SOCKMODE - Not support socket mode as + * TCP, UDP, and so on. \n + * @ref SOCKERR_SOCKFLAG - Invaild socket flag. + */ +int8_t wiz_socket(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Close a socket. + * @details It closes the socket with @b'sn' passed as parameter. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * + * @return @b Success : @ref SOCK_OK \n + * @b Fail : @ref SOCKERR_SOCKNUM - Invalid socket number + */ +int8_t wiz_sock_close(uint8_t sn); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Listen to a connection request from a client. + * @details It is listening to a connection request from a client. + * If connection request is accepted successfully, the connection is + * established. Socket sn is used in passive(server) mode. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @return @b Success : @ref SOCK_OK \n + * @b Fail :\n @ref SOCKERR_SOCKINIT - Socket is not initialized \n + * @ref SOCKERR_SOCKCLOSED - Socket closed unexpectedly. + */ +int8_t wiz_sock_listen(uint8_t sn); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Try to connect a server. + * @details It requests connection to the server with destination IP address and + * port number passed as parameter.\n + * @note It is valid only in TCP client mode. + * In block io mode, it does not return until connection is completed. + * In Non-block io mode, it return @ref SOCK_BUSY immediately. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param addr Pointer variable of destination IP address. It should be + * allocated 4 bytes. + * @param port Destination port number. + * + * @return @b Success : @ref SOCK_OK \n + * @b Fail :\n @ref SOCKERR_SOCKNUM - Invalid socket number\n + * @ref SOCKERR_SOCKMODE - Invalid socket mode\n + * @ref SOCKERR_SOCKINIT - Socket is not initialized\n + * @ref SOCKERR_IPINVALID - Wrong server IP address\n + * @ref SOCKERR_PORTZERO - Server port zero\n + * @ref SOCKERR_TIMEOUT - Timeout occurred during request + * connection\n + * @ref SOCK_BUSY - In non-block io mode, it returned + * immediately\n + */ +int8_t wiz_sock_connect(uint8_t sn, uint8_t *addr, uint16_t port); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Try to disconnect a connection socket. + * @details It sends request message to disconnect the TCP socket 'sn' passed as + parameter to the server or client. + * @note It is valid only in TCP server or client mode. \n + * In block io mode, it does not return until disconnection is completed. + \n + * In Non-block io mode, it return @ref SOCK_BUSY immediately. \n + + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @return @b Success : @ref SOCK_OK \n + * @b Fail :\n @ref SOCKERR_SOCKNUM - Invalid socket number \n + * @ref SOCKERR_SOCKMODE - Invalid operation in the + socket \n + * @ref SOCKERR_TIMEOUT - Timeout occurred \n + * @ref SOCK_BUSY - Socket is busy. + */ +int8_t wiz_sock_disconnect(uint8_t sn); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Send data to the connected peer in TCP socket. + * @details It is used to send outgoing data to the connected socket. + * @note It is valid only in TCP server or client mode. It can't send data + * greater than socket buffer size. \n In block io mode, It doesn't return until + * data send is completed - socket buffer size is greater than data. \n In + * non-block io mode, It return @ref SOCK_BUSY immediately when socket buffer is + * not enough. \n + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param buf Pointer buffer containing data to be sent. + * @param len The byte length of data in buf. + * @return @b Success : The sent data size \n + * @b Fail : \n @ref SOCKERR_SOCKSTATUS - Invalid socket status for + * socket operation \n + * @ref SOCKERR_TIMEOUT - Timeout occurred \n + * @ref SOCKERR_SOCKMODE - Invalid operation in + * the socket \n + * @ref SOCKERR_SOCKNUM - Invalid socket number \n + * @ref SOCKERR_DATALEN - zero data length \n + * @ref SOCK_BUSY - Socket is busy. + */ +int32_t wiz_sock_send(uint8_t sn, uint8_t *buf, uint16_t len); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Receive data from the connected peer. + * @details It is used to read incoming data from the connected socket.\n + * It waits for data as much as the application wants to receive. + * @note It is valid only in TCP server or client mode. It can't receive data + * greater than socket buffer size. \n In block io mode, it doesn't return until + * data reception is completed - data is filled as len in socket buffer. + * \n In non-block io mode, it return @ref SOCK_BUSY immediately when len + * is greater than data size in socket buffer. \n + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param buf Pointer buffer to read incoming data. + * @param len The max data length of data in buf. + * @return @b Success : The real received data size \n + * @b Fail :\n + * @ref SOCKERR_SOCKSTATUS - Invalid socket status for + * socket operation \n + * @ref SOCKERR_SOCKMODE - Invalid operation in the socket + * \n + * @ref SOCKERR_SOCKNUM - Invalid socket number \n + * @ref SOCKERR_DATALEN - zero data length \n + * @ref SOCK_BUSY - Socket is busy. + */ +int32_t wiz_sock_recv(uint8_t sn, uint8_t *buf, uint16_t len); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Sends datagram to the peer with destination IP address and port + * number passed as parameter. + * @details It sends datagram of UDP or MACRAW to the peer with destination IP + * address and port number passed as parameter.\n Even if the connectionless + * socket has been previously connected to a specific address, the address and + * port number parameters override the destination address for that particular + * datagram only. + * @note In block io mode, It doesn't return until data send is completed - + * socket buffer size is greater than len. In non-block io mode, It + * return @ref SOCK_BUSY immediately when socket buffer is not enough. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param buf Pointer buffer to send outgoing data. + * @param len The byte length of data in buf. + * @param addr Pointer variable of destination IP address. It should be + * allocated 4 bytes. + * @param port Destination port number. + * + * @return @b Success : The sent data size \n + * @b Fail :\n @ref SOCKERR_SOCKNUM - Invalid socket number \n + * @ref SOCKERR_SOCKMODE - Invalid operation in the + * socket \n + * @ref SOCKERR_SOCKSTATUS - Invalid socket status for + * socket operation \n + * @ref SOCKERR_DATALEN - zero data length \n + * @ref SOCKERR_IPINVALID - Wrong server IP address\n + * @ref SOCKERR_PORTZERO - Server port zero\n + * @ref SOCKERR_SOCKCLOSED - Socket unexpectedly closed + * \n + * @ref SOCKERR_TIMEOUT - Timeout occurred \n + * @ref SOCK_BUSY - Socket is busy. + */ +int32_t wiz_sock_sendto(uint8_t sn, uint8_t *buf, uint16_t len, uint8_t *addr, + uint16_t port); + +/** + * @ingroup WIZnet_socket_APIs + * @brief Receive datagram of UDP or MACRAW + * @details This function is an application I/F function which is used to + * receive the data in other then TCP mode. \n This function is used to receive + * UDP and MAC_RAW mode, and handle the header as well. This function can divide + * to received the packet data. On the MACRAW SOCKET, the addr and port + * parameters are ignored. + * @note In block io mode, it doesn't return until data reception is + * completed - data is filled as len in socket buffer In non-block io + * mode, it return @ref SOCK_BUSY immediately when len is greater than + * data size in socket buffer. + * + * @param sn Socket number. It should be 0 ~ @ref \_WIZCHIP_SOCK_NUM_. + * @param buf Pointer buffer to read incoming data. + * @param len The max data length of data in buf. + * When the received packet size <= len, receives data as packet + * sized. When others, receives data as len. + * @param addr Pointer variable of destination IP address. It should be + * allocated 4 bytes. It is valid only when the first call recvfrom for + * receiving the packet. When it is valid, @ref packinfo[7] should be set as + * '1' after call @ref getsockopt(sn, SO_PACKINFO, &packinfo). + * @param port Pointer variable of destination port number. + * It is valid only when the first call recvform for receiving the + * packet. When it is valid, @ref packinfo[7] should be set as '1' after call + * @ref getsockopt(sn, SO_PACKINFO, &packinfo). + * + * @return @b Success : This function return real received data size for + * success.\n + * @b Fail : @ref SOCKERR_DATALEN - zero data length \n + * @ref SOCKERR_SOCKMODE - Invalid operation in the + * socket \n + * @ref SOCKERR_SOCKNUM - Invalid socket number \n + * @ref SOCKBUSY - Socket is busy. + */ +int32_t wiz_sock_recvfrom(uint8_t sn, uint8_t *buf, uint16_t len, uint8_t *addr, + uint16_t *port); + +///////////////////////////// +// SOCKET CONTROL & OPTION // +///////////////////////////// +#define SOCK_IO_BLOCK 0 ///< Socket Block IO Mode in @ref setsockopt(). +#define SOCK_IO_NONBLOCK 1 ///< Socket Non-block IO Mode in @ref setsockopt(). + +/** + * @defgroup DATA_TYPE DATA TYPE + */ + +/** + * @ingroup DATA_TYPE + * @brief The kind of Socket Interrupt. + * @sa Sn_IR, Sn_IMR, setSn_IR(), getSn_IR(), setSn_IMR(), getSn_IMR() + */ +typedef enum { + SIK_CONNECTED = (1 << 0), ///< connected + SIK_DISCONNECTED = (1 << 1), ///< disconnected + SIK_RECEIVED = (1 << 2), ///< data received + SIK_TIMEOUT = (1 << 3), ///< timeout occurred + SIK_SENT = (1 << 4), ///< send ok + // M20150410 : Remove the comma of last member + // SIK_ALL = 0x1F, ///< all interrupt + SIK_ALL = 0x1F ///< all interrupt +} sockint_kind; + +/** + * @ingroup DATA_TYPE + * @brief The type of @ref ctlsocket(). + */ +typedef enum { + CS_SET_IOMODE, ///< set socket IO mode with @ref SOCK_IO_BLOCK or @ref + ///< SOCK_IO_NONBLOCK + CS_GET_IOMODE, ///< get socket IO mode + CS_GET_MAXTXBUF, ///< get the size of socket buffer allocated in TX memory + CS_GET_MAXRXBUF, ///< get the size of socket buffer allocated in RX memory + CS_CLR_INTERRUPT, ///< clear the interrupt of socket with @ref sockint_kind + CS_GET_INTERRUPT, ///< get the socket interrupt. refer to @ref sockint_kind +#if _WIZCHIP_ > 5100 + CS_SET_INTMASK, ///< set the interrupt mask of socket with @ref sockint_kind, + ///< Not supported in W5100 + CS_GET_INTMASK ///< get the masked interrupt of socket. refer to @ref + ///< sockint_kind, Not supported in W5100 +#endif +} ctlsock_type; + +/** + * @ingroup DATA_TYPE + * @brief The type of socket option in @ref setsockopt() or @ref getsockopt() + */ +typedef enum { + SO_FLAG, ///< Valid only in getsockopt(), For set flag of socket refer to + ///< flag in @ref socket(). + SO_TTL, ///< Set TTL. @ref Sn_TTL ( @ref setSn_TTL(), @ref getSn_TTL() ) + SO_TOS, ///< Set TOS. @ref Sn_TOS ( @ref setSn_TOS(), @ref getSn_TOS() ) + SO_MSS, ///< Set MSS. @ref Sn_MSSR ( @ref setSn_MSSR(), @ref getSn_MSSR() ) + SO_DESTIP, ///< Set the destination IP address. @ref Sn_DIPR ( @ref + ///< setSn_DIPR(), @ref getSn_DIPR() ) + SO_DESTPORT, ///< Set the destination Port number. @ref Sn_DPORT ( @ref + ///< setSn_DPORT(), @ref getSn_DPORT() ) +#if _WIZCHIP_ != 5100 + SO_KEEPALIVESEND, ///< Valid only in setsockopt. Manually send keep-alive + ///< packet in TCP mode, Not supported in W5100 +#if !((_WIZCHIP_ == 5100) || (_WIZCHIP_ == 5200)) + SO_KEEPALIVEAUTO, ///< Set/Get keep-alive auto transmission timer in TCP + ///< mode, Not supported in W5100, W5200 +#endif +#endif + SO_SENDBUF, ///< Valid only in getsockopt. Get the free data size of Socekt + ///< TX buffer. @ref Sn_TX_FSR, @ref getSn_TX_FSR() + SO_RECVBUF, ///< Valid only in getsockopt. Get the received data size in + ///< socket RX buffer. @ref Sn_RX_RSR, @ref getSn_RX_RSR() + SO_STATUS, ///< Valid only in getsockopt. Get the socket status. @ref Sn_SR, + ///< @ref getSn_SR() + SO_REMAINSIZE, ///< Valid only in getsockopt. Get the remained packet size in + ///< other then TCP mode. + SO_PACKINFO ///< Valid only in getsockopt. Get the packet information as @ref + ///< PACK_FIRST, @ref PACK_REMAINED, and @ref PACK_COMPLETED in + ///< other then TCP mode. +} sockopt_type; + +/** + * @ingroup WIZnet_socket_APIs + * @brief Control socket. + * @details Control IO mode, Interrupt & Mask of socket and get the socket + * buffer information. Refer to @ref ctlsock_type. + * @param sn socket number + * @param cstype type of control socket. refer to @ref ctlsock_type. + * @param arg Data type and value is determined according to @ref ctlsock_type. + * \n + *
@b cstype @b data type@b + * value
@ref CS_SET_IOMODE \n @ref CS_GET_IOMODE + * uint8_t @ref SOCK_IO_BLOCK @ref SOCK_IO_NONBLOCK
+ * @ref CS_GET_MAXTXBUF \n @ref CS_GET_MAXRXBUF uint16_t 0 + * ~ 16K
@ref CS_CLR_INTERRUPT \n @ref CS_GET_INTERRUPT \n + * @ref CS_SET_INTMASK \n @ref CS_GET_INTMASK @ref sockint_kind + * @ref SIK_CONNECTED, etc.
+ * @return @b Success @ref SOCK_OK \n + * @b fail @ref SOCKERR_ARG - Invalid argument\n + */ +int8_t wiz_ctlsocket(uint8_t sn, ctlsock_type cstype, void *arg); + +/** + * @ingroup WIZnet_socket_APIs + * @brief set socket options + * @details Set socket option like as TTL, MSS, TOS, and so on. Refer to @ref + * sockopt_type. + * + * @param sn socket number + * @param sotype socket option type. refer to @ref sockopt_type + * @param arg Data type and value is determined according to sotype. \n + * + * + * + * + * + *
@b sotype @b data type@b + * value
@ref SO_TTL uint8_t 0 ~ 255 + *
@ref SO_TOS uint8_t 0 ~ 255
@ref SO_MSS uint16_t 0 ~ 65535
@ref SO_DESTIP uint8_t[4]
@ref SO_DESTPORT uint16_t 0 ~ + * 65535
@ref SO_KEEPALIVESEND null + * null
@ref SO_KEEPALIVEAUTO uint8_t + * 0 ~ 255
+ * @return + * - @b Success : @ref SOCK_OK \n + * - @b Fail + * - @ref SOCKERR_SOCKNUM - Invalid Socket number \n + * - @ref SOCKERR_SOCKMODE - Invalid socket mode \n + * - @ref SOCKERR_SOCKOPT - Invalid socket option or its value \n + * - @ref SOCKERR_TIMEOUT - Timeout occurred when sending keep-alive packet + * \n + */ +int8_t wiz_setsockopt(uint8_t sn, sockopt_type sotype, void *arg); + +/** + * @ingroup WIZnet_socket_APIs + * @brief get socket options + * @details Get socket option like as FLAG, TTL, MSS, and so on. Refer to @ref + * sockopt_type + * @param sn socket number + * @param sotype socket option type. refer to @ref sockopt_type + * @param arg Data type and value is determined according to sotype. \n + * + * + *
@b sotype @b data type@b + * value
@ref SO_FLAG uint8_t @ref + * SF_ETHER_OWN, etc...
@ref SO_TOS uint8_t + * 0 ~ 255
@ref SO_MSS uint16_t + * 0 ~ 65535
@ref SO_DESTIP + * uint8_t[4]
@ref SO_DESTPORT + * uint16_t
@ref SO_KEEPALIVEAUTO + * uint8_t 0 ~ 255
@ref SO_SENDBUF + * uint16_t 0 ~ 65535
@ref SO_RECVBUF + * uint16_t 0 ~ 65535
@ref SO_STATUS + * uint8_t @ref SOCK_ESTABLISHED, etc..
@ref + * SO_REMAINSIZE uint16_t 0~ 65535
+ * @ref SO_PACKINFO uint8_t @ref PACK_FIRST, etc... + *
+ * @return + * - @b Success : @ref SOCK_OK \n + * - @b Fail + * - @ref SOCKERR_SOCKNUM - Invalid Socket number \n + * - @ref SOCKERR_SOCKOPT - Invalid socket option or its value \n + * - @ref SOCKERR_SOCKMODE - Invalid socket mode \n + * @note + * The option as PACK_REMAINED and SO_PACKINFO is valid only in NON-TCP mode + * and after call @ref recvfrom(). \n When SO_PACKINFO value is PACK_FIRST and + * the return value of recvfrom() is zero, This means the zero byte UDP data(UDP + * Header only) received. + */ +int8_t wiz_getsockopt(uint8_t sn, sockopt_type sotype, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif // _SOCKET_H_ \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/w5500.h b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/w5500.h new file mode 100755 index 000000000..121baab06 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/w5500.h @@ -0,0 +1,2321 @@ +//***************************************************************************** +// +//! \file w5500.h +//! \brief W5500 HAL Header File. +//! \version 1.0.0 +//! \date 2013/10/21 +//! \par Revision history +//! <2015/02/05> Notice +//! The version history is not updated after this point. +//! Download the latest version directly from GitHub. Please visit the +//! our GitHub repository for ioLibrary. +//! >> https://github.com/Wiznet/ioLibrary_Driver +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! 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 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 _W5500_H_ +#define _W5500_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "wizchip_conf.h" +#include + + +/// @cond DOXY_APPLY_CODE +#if (_WIZCHIP_ == 5500) +/// @endcond + +#define _W5500_IO_BASE_ 0x00000000 + +#define _W5500_SPI_READ_ \ + (0x00 << 2) //< SPI interface Read operation in Control Phase +#define _W5500_SPI_WRITE_ \ + (0x01 << 2) //< SPI interface Write operation in Control Phase + +#define WIZCHIP_CREG_BLOCK 0x00 //< Common register block +#define WIZCHIP_SREG_BLOCK(N) (1 + 4 * N) //< Socket N register block +#define WIZCHIP_TXBUF_BLOCK(N) (2 + 4 * N) //< Socket N Tx buffer address block +#define WIZCHIP_RXBUF_BLOCK(N) (3 + 4 * N) //< Socket N Rx buffer address block + +#define WIZCHIP_OFFSET_INC(ADDR, N) \ + (ADDR + (N << 8)) //< Increase offset address + +/////////////////////////////////////// +// Definition For Legacy Chip Driver // +/////////////////////////////////////// +#define IINCHIP_READ(ADDR) \ + WIZCHIP_READ(ADDR) ///< The defined for legacy chip driver +#define IINCHIP_WRITE(ADDR, VAL) \ + WIZCHIP_WRITE(ADDR, VAL) ///< The defined for legacy chip driver +#define IINCHIP_READ_BUF(ADDR, BUF, LEN) \ + WIZCHIP_READ_BUF(ADDR, BUF, LEN) ///< The defined for legacy chip driver +#define IINCHIP_WRITE_BUF(ADDR, BUF, LEN) \ + WIZCHIP_WRITE(ADDR, BUF, LEN) ///< The defined for legacy chip driver + +////////////////////////////// +//-------------------------- defgroup --------------------------------- +/** + * @defgroup W5500 W5500 + * + * @brief WHIZCHIP register defines and I/O functions of @b W5500. + * + * - @ref WIZCHIP_register : @ref Common_register_group and @ref + * Socket_register_group + * - @ref WIZCHIP_IO_Functions : @ref Basic_IO_function, @ref + * Common_register_access_function and @ref Socket_register_access_function + */ + +/** + * @defgroup WIZCHIP_register WIZCHIP register + * @ingroup W5500 + * + * @brief WHIZCHIP register defines register group of @b W5500. + * + * - @ref Common_register_group : Common register group + * - @ref Socket_register_group : \c SOCKET n register group + */ + +/** + * @defgroup WIZCHIP_IO_Functions WIZCHIP I/O functions + * @ingroup W5500 + * + * @brief This supports the basic I/O functions for @ref WIZCHIP_register. + * + * - Basic I/O function \n + * WIZCHIP_READ(), WIZCHIP_WRITE(), WIZCHIP_READ_BUF(), WIZCHIP_WRITE_BUF() + * \n\n + * + * - @ref Common_register_group access functions \n + * -# @b Mode \n + * getMR(), setMR() + * -# @b Interrupt \n + * getIR(), setIR(), getIMR(), setIMR(), getSIR(), setSIR(), getSIMR(), + * setSIMR(), getINTLEVEL(), setINTLEVEL() + * -# Network Information \n + * getSHAR(), setSHAR(), getGAR(), setGAR(), getSUBR(), setSUBR(), getSIPR(), + * setSIPR() + * -# @b Retransmission \n + * getRCR(), setRCR(), getRTR(), setRTR() + * -# @b PPPoE \n + * getPTIMER(), setPTIMER(), getPMAGIC(), getPMAGIC(), getPSID(), setPSID(), + * getPHAR(), setPHAR(), getPMRU(), setPMRU() + * -# ICMP packet \n + * getUIPR(), getUPORTR() + * -# @b etc. \n + * getPHYCFGR(), setPHYCFGR(), getVERSIONR() \n\n + * + * - \ref Socket_register_group access functions \n + * -# SOCKET control \n + * getSn_MR(), setSn_MR(), getSn_CR(), setSn_CR(), getSn_IMR(), + * setSn_IMR(), getSn_IR(), setSn_IR() + * -# SOCKET information \n + * getSn_SR(), getSn_DHAR(), setSn_DHAR(), getSn_PORT(), setSn_PORT(), + * getSn_DIPR(), setSn_DIPR(), getSn_DPORT(), setSn_DPORT() getSn_MSSR(), + * setSn_MSSR() + * -# SOCKET communication \n + * getSn_RXBUF_SIZE(), setSn_RXBUF_SIZE(), getSn_TXBUF_SIZE(), + * setSn_TXBUF_SIZE() \n getSn_TX_RD(), getSn_TX_WR(), setSn_TX_WR() \n + * getSn_RX_RD(), setSn_RX_RD(), getSn_RX_WR() \n + * getSn_TX_FSR(), getSn_RX_RSR(), getSn_KPALVTR(), setSn_KPALVTR() + * -# IP header field \n + * getSn_FRAG(), setSn_FRAG(), getSn_TOS(), setSn_TOS() \n + * getSn_TTL(), setSn_TTL() + */ + +/** + * @defgroup Common_register_group Common register + * @ingroup WIZCHIP_register + * + * @brief Common register group\n + * It set the basic for the networking\n + * It set the configuration such as interrupt, network information, ICMP, etc. + * @details + * @sa MR : Mode register. + * @sa GAR, SUBR, SHAR, SIPR + * @sa INTLEVEL, IR, IMR, SIR, SIMR : Interrupt. + * @sa _RTR_, _RCR_ : Data retransmission. + * @sa PTIMER, PMAGIC, PHAR, PSID, PMRU : PPPoE. + * @sa UIPR, UPORTR : ICMP message. + * @sa PHYCFGR, VERSIONR : etc. + */ + +/** + * @defgroup Socket_register_group Socket register + * @ingroup WIZCHIP_register + * + * @brief Socket register group.\n + * Socket register configures and control SOCKETn which is necessary to data + * communication. + * @details + * @sa Sn_MR, Sn_CR, Sn_IR, Sn_IMR : SOCKETn Control + * @sa Sn_SR, Sn_PORT, Sn_DHAR, Sn_DIPR, Sn_DPORT : SOCKETn Information + * @sa Sn_MSSR, Sn_TOS, Sn_TTL, Sn_KPALVTR, Sn_FRAG : Internet protocol. + * @sa Sn_RXBUF_SIZE, Sn_TXBUF_SIZE, Sn_TX_FSR, Sn_TX_RD, Sn_TX_WR, Sn_RX_RSR, + * Sn_RX_RD, Sn_RX_WR : Data communication + */ + +/** + * @defgroup Basic_IO_function Basic I/O function + * @ingroup WIZCHIP_IO_Functions + * @brief These are basic input/output functions to read values from register or + * write values to register. + */ + +/** + * @defgroup Common_register_access_function Common register access functions + * @ingroup WIZCHIP_IO_Functions + * @brief These are functions to access common registers. + */ + +/** + * @defgroup Socket_register_access_function Socket register access functions + * @ingroup WIZCHIP_IO_Functions + * @brief These are functions to access socket registers. + */ + +//------------------------------- defgroup end +//-------------------------------------------- +//----------------------------- W5500 Common Registers IOMAP +//----------------------------- +/** + * @ingroup Common_register_group + * @brief Mode Register address(R/W)\n + * @ref MR is used for S/W reset, ping block mode, PPPoE mode and etc. + * @details Each bit of @ref MR defined as follows. + * + * + * + * + * + *
7 6 5 4 32 1 0
RST ReservedWOL PB PPPoE Reserved FARPReserved
+ * - \ref MR_RST : Reset + * - \ref MR_WOL : Wake on LAN + * - \ref MR_PB : Ping block + * - \ref MR_PPPOE : PPPoE mode + * - \ref MR_FARP : Force ARP mode + */ +#define MR (_W5500_IO_BASE_ + (0x0000 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Gateway IP Register address(R/W) + * @details @ref GAR configures the default gateway address. + */ +#define GAR (_W5500_IO_BASE_ + (0x0001 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Subnet mask Register address(R/W) + * @details @ref SUBR configures the subnet mask address. + */ +#define SUBR (_W5500_IO_BASE_ + (0x0005 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Source MAC Register address(R/W) + * @details @ref SHAR configures the source hardware address. + */ +#define SHAR (_W5500_IO_BASE_ + (0x0009 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Source IP Register address(R/W) + * @details @ref SIPR configures the source IP address. + */ +#define SIPR (_W5500_IO_BASE_ + (0x000F << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Set Interrupt low level timer register address(R/W) + * @details @ref INTLEVEL configures the Interrupt Assert Time. + */ +#define INTLEVEL (_W5500_IO_BASE_ + (0x0013 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Interrupt Register(R/W) + * @details @ref IR indicates the interrupt status. Each bit of @ref IR will be + * still until the bit will be written to by the host. If @ref IR is not equal + * to x00 INTn PIN is asserted to low until it is x00\n\n Each bit of @ref IR + * defined as follows. + * + * + * + *
7 6 5 43 2 1 0
CONFLICTUNREACH PPPoE MP ReservedReserved Reserved Reserved
+ * - \ref IR_CONFLICT : IP conflict + * - \ref IR_UNREACH : Destination unreachable + * - \ref IR_PPPoE : PPPoE connection close + * - \ref IR_MP : Magic packet + */ +#define IR (_W5500_IO_BASE_ + (0x0015 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Interrupt mask register(R/W) + * @details @ref _IMR_ is used to mask interrupts. Each bit of @ref _IMR_ + * corresponds to each bit of @ref IR. When a bit of @ref _IMR_ is and the + * corresponding bit of @ref IR is an interrupt will be issued. In other words, + * if a bit of @ref _IMR_ is an interrupt will not be issued even if the + * corresponding bit of @ref IR is \n\n Each bit of @ref _IMR_ defined as the + * following. + * + * + * + *
7 6 5 43 2 1 0
IM_IR7IM_IR6 IM_IR5 IM_IR4 ReservedReserved Reserved Reserved
+ * - \ref IM_IR7 : IP Conflict Interrupt Mask + * - \ref IM_IR6 : Destination unreachable Interrupt Mask + * - \ref IM_IR5 : PPPoE Close Interrupt Mask + * - \ref IM_IR4 : Magic Packet Interrupt Mask + */ +// M20150401 : Rename SYMBOE ( Re-define error in a compile) +//#define IMR (_W5500_IO_BASE_ + (0x0016 << 8) + +//(WIZCHIP_CREG_BLOCK << 3)) +#define _IMR_ (_W5500_IO_BASE_ + (0x0016 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Socket Interrupt Register(R/W) + * @details @ref SIR indicates the interrupt status of Socket.\n + * Each bit of @ref SIR be still until @ref Sn_IR is cleared by the host.\n + * If @ref Sn_IR is not equal to x00 the n-th bit of @ref SIR is and INTn PIN is + * asserted until @ref SIR is x00 */ +#define SIR (_W5500_IO_BASE_ + (0x0017 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Socket Interrupt Mask Register(R/W) + * @details Each bit of @ref SIMR corresponds to each bit of @ref SIR. + * When a bit of @ref SIMR is and the corresponding bit of @ref SIR is Interrupt + * will be issued. In other words, if a bit of @ref SIMR is an interrupt will + * be not issued even if the corresponding bit of @ref SIR is + */ +#define SIMR (_W5500_IO_BASE_ + (0x0018 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Timeout register address( 1 is 100us )(R/W) + * @details @ref _RTR_ configures the retransmission timeout period. The unit of + * timeout period is 100us and the default of @ref _RTR_ is x07D0. And so the + * default timeout period is 200ms(100us X 2000). During the time configured by + * @ref _RTR_, W5500 waits for the peer response to the packet that is + * transmitted by \ref Sn_CR (CONNECT, DISCON, CLOSE, SEND, SEND_MAC, SEND_KEEP + * command). If the peer does not respond within the @ref _RTR_ time, W5500 + * retransmits the packet or issues timeout. + */ +// M20150401 : Rename SYMBOE ( Re-define error in a compile) +//#define RTR (_W5500_IO_BASE_ + (0x0019 << 8) + +//(WIZCHIP_CREG_BLOCK << 3)) +#define _RTR_ (_W5500_IO_BASE_ + (0x0019 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Retry count register(R/W) + * @details @ref _RCR_ configures the number of time of retransmission. + * When retransmission occurs as many as ref _RCR_+1 Timeout interrupt is issued + * (@ref Sn_IR_TIMEOUT = '1'). + */ +// M20150401 : Rename SYMBOE ( Re-define error in a compile) +//#define RCR (_W5500_IO_BASE_ + (0x001B << 8) + +//(WIZCHIP_CREG_BLOCK << 3)) +#define _RCR_ (_W5500_IO_BASE_ + (0x001B << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP LCP Request Timer register in PPPoE mode(R/W) + * @details @ref PTIMER configures the time for sending LCP echo request. The + * unit of time is 25ms. + */ +#define PTIMER (_W5500_IO_BASE_ + (0x001C << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP LCP Magic number register in PPPoE mode(R/W) + * @details @ref PMAGIC configures the 4bytes magic number to be used in LCP + * negotiation. + */ +#define PMAGIC (_W5500_IO_BASE_ + (0x001D << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP Destination MAC Register address(R/W) + * @details @ref PHAR configures the PPPoE server hardware address that is + * acquired during PPPoE connection process. + */ +#define PHAR (_W5500_IO_BASE_ + (0x001E << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP Session Identification Register(R/W) + * @details @ref PSID configures the PPPoE sever session ID acquired during + * PPPoE connection process. + */ +#define PSID (_W5500_IO_BASE_ + (0x0024 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PPP Maximum Segment Size(MSS) register(R/W) + * @details @ref PMRU configures the maximum receive unit of PPPoE. + */ +#define PMRU (_W5500_IO_BASE_ + (0x0026 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Unreachable IP register address in UDP mode(R) + * @details W5500 receives an ICMP packet(Destination port unreachable) when + * data is sent to a port number which socket is not open and @ref IR_UNREACH + * bit of @ref IR becomes and @ref UIPR & @ref UPORTR indicates the destination + * IP address & port number respectively. + */ +#define UIPR (_W5500_IO_BASE_ + (0x0028 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief Unreachable Port register address in UDP mode(R) + * @details W5500 receives an ICMP packet(Destination port unreachable) when + * data is sent to a port number which socket is not open and @ref IR_UNREACH + * bit of @ref IR becomes and @ref UIPR & @ref UPORTR indicates the destination + * IP address & port number respectively. + */ +#define UPORTR (_W5500_IO_BASE_ + (0x002C << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief PHY Status Register(R/W) + * @details @ref PHYCFGR configures PHY operation mode and resets PHY. In + * addition, @ref PHYCFGR indicates the status of PHY such as duplex, Speed, + * Link. + */ +#define PHYCFGR (_W5500_IO_BASE_ + (0x002E << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +// Reserved (_W5500_IO_BASE_ + (0x002F << 8) + +// (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0030 << 8) + +// (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0031 << 8) + +// (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0032 << 8) + +// (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0033 << 8) + +// (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0034 << 8) + +// (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0035 << 8) + +// (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0036 << 8) + +// (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0037 << 8) + +// (WIZCHIP_CREG_BLOCK << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0038 << 8) + +// (WIZCHIP_CREG_BLOCK << 3)) + +/** + * @ingroup Common_register_group + * @brief chip version register address(R) + * @details @ref VERSIONR always indicates the W5500 version as @b 0x04. + */ +#define VERSIONR (_W5500_IO_BASE_ + (0x0039 << 8) + (WIZCHIP_CREG_BLOCK << 3)) + +//----------------------------- W5500 Socket Registers IOMAP +//----------------------------- +/** + * @ingroup Socket_register_group + * @brief socket Mode register(R/W) + * @details @ref Sn_MR configures the option or protocol type of Socket n.\n\n + * Each bit of @ref Sn_MR defined as the following. + * + * + * + * + * + *
7 6 5 4 32 1 0
MULTI/MFENBCASTB ND/MC/MMB UCASTB/MIP6B Protocol[3]Protocol[2] Protocol[1] Protocol[0]
+ * - @ref Sn_MR_MULTI : Support UDP Multicasting + * - @ref Sn_MR_BCASTB : Broadcast block in UDP Multicasting + * - @ref Sn_MR_ND : No Delayed Ack(TCP) flag + * - @ref Sn_MR_MC : IGMP version used in UDP mulitcasting + * - @ref Sn_MR_MMB : Multicast Blocking in @ref Sn_MR_MACRAW mode + * - @ref Sn_MR_UCASTB : Unicast Block in UDP Multicating + * - @ref Sn_MR_MIP6B : IPv6 packet Blocking in @ref Sn_MR_MACRAW mode + * - Protocol + * + * + * + * + * + * + * + * + *
Protocol[3] Protocol[2]Protocol[1] Protocol[0] @b Meaning
0 0 0 0 Closed
0 0 0 1 TCP
0 0 1 0 UDP
0 1 0 0MACRAW
+ * - @ref Sn_MR_MACRAW : MAC LAYER RAW SOCK \n + * - @ref Sn_MR_UDP : UDP + * - @ref Sn_MR_TCP : TCP + * - @ref Sn_MR_CLOSE : Unused socket + * @note MACRAW mode should be only used in Socket 0. + */ +#define Sn_MR(N) \ + (_W5500_IO_BASE_ + (0x0000 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Socket command register(R/W) + * @details This is used to set the command for Socket n such as OPEN, CLOSE, + * CONNECT, LISTEN, SEND, and RECEIVE.\n After W5500 accepts the command, the + * @ref Sn_CR register is automatically cleared to 0x00. Even though @ref Sn_CR + * is cleared to 0x00, the command is still being processed.\n To check whether + * the command is completed or not, please check the @ref Sn_IR or @ref Sn_SR. + * - @ref Sn_CR_OPEN : Initialize or open socket. + * - @ref Sn_CR_LISTEN : Wait connection request in TCP mode(Server + * mode) + * - @ref Sn_CR_CONNECT : Send connection request in TCP mode(Client + * mode) + * - @ref Sn_CR_DISCON : Send closing request in TCP mode. + * - @ref Sn_CR_CLOSE : Close socket. + * - @ref Sn_CR_SEND : Update TX buffer pointer and send data. + * - @ref Sn_CR_SEND_MAC : Send data with MAC address, so without ARP + * process. + * - @ref Sn_CR_SEND_KEEP : Send keep alive message. + * - @ref Sn_CR_RECV : Update RX buffer pointer and receive data. + */ +#define Sn_CR(N) \ + (_W5500_IO_BASE_ + (0x0001 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Socket interrupt register(R) + * @details @ref Sn_IR indicates the status of Socket Interrupt such as + * establishment, termination, receiving data, timeout).\n When an interrupt + * occurs and the corresponding bit of @ref Sn_IMR is the corresponding bit of + * @ref Sn_IR becomes \n In order to clear the @ref Sn_IR bit, the host should + * write the bit to \n + * + * + * + *
7 6 5 43 2 1 0
ReservedReserved Reserved SEND_OK TIMEOUTRECV DISCON CON
+ * - \ref Sn_IR_SENDOK : SEND_OK Interrupt + * - \ref Sn_IR_TIMEOUT : TIMEOUT Interrupt + * - \ref Sn_IR_RECV : RECV Interrupt + * - \ref Sn_IR_DISCON : DISCON Interrupt + * - \ref Sn_IR_CON : CON Interrupt + */ +#define Sn_IR(N) \ + (_W5500_IO_BASE_ + (0x0002 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Socket status register(R) + * @details @ref Sn_SR indicates the status of Socket n.\n + * The status of Socket n is changed by @ref Sn_CR or some special control + *packet as SYN, FIN packet in TCP. + * @par Normal status + * - @ref SOCK_CLOSED : Closed + * - @ref SOCK_INIT : Initiate state + * - @ref SOCK_LISTEN : Listen state + * - @ref SOCK_ESTABLISHED : Success to connect + * - @ref SOCK_CLOSE_WAIT : Closing state + * - @ref SOCK_UDP : UDP socket + * - @ref SOCK_MACRAW : MAC raw mode socket + *@par Temporary status during changing the status of Socket n. + * - @ref SOCK_SYNSENT : This indicates Socket n sent the + *connect-request packet (SYN packet) to a peer. + * - @ref SOCK_SYNRECV : It indicates Socket n successfully received + *the connect-request packet (SYN packet) from a peer. + * - @ref SOCK_FIN_WAIT : Connection state + * - @ref SOCK_CLOSING : Closing state + * - @ref SOCK_TIME_WAIT : Closing state + * - @ref SOCK_LAST_ACK : Closing state + */ +#define Sn_SR(N) \ + (_W5500_IO_BASE_ + (0x0003 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief source port register(R/W) + * @details @ref Sn_PORT configures the source port number of Socket n. + * It is valid when Socket n is used in TCP/UDP mode. It should be set before + * OPEN command is ordered. + */ +#define Sn_PORT(N) \ + (_W5500_IO_BASE_ + (0x0004 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Peer MAC register address(R/W) + * @details @ref Sn_DHAR configures the destination hardware address of Socket n + * when using SEND_MAC command in UDP mode or it indicates that it is acquired + * in ARP-process by CONNECT/SEND command. + */ +#define Sn_DHAR(N) \ + (_W5500_IO_BASE_ + (0x0006 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Peer IP register address(R/W) + * @details @ref Sn_DIPR configures or indicates the destination IP address of + * Socket n. It is valid when Socket n is used in TCP/UDP mode. In TCP client + * mode, it configures an IP address of TCP serverbefore CONNECT command. In TCP + * server mode, it indicates an IP address of TCP clientafter successfully + * establishing connection. In UDP mode, it configures an IP address of peer to + * be received the UDP packet by SEND or SEND_MAC command. + */ +#define Sn_DIPR(N) \ + (_W5500_IO_BASE_ + (0x000C << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Peer port register address(R/W) + * @details @ref Sn_DPORT configures or indicates the destination port number of + * Socket n. It is valid when Socket n is used in TCP/UDP mode. In TCP + * clientmode, it configures the listen port number of TCP serverbefore CONNECT + * command. In TCP Servermode, it indicates the port number of TCP client after + * successfully establishing connection. In UDP mode, it configures the port + * number of peer to be transmitted the UDP packet by SEND/SEND_MAC command. + */ +#define Sn_DPORT(N) \ + (_W5500_IO_BASE_ + (0x0010 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Maximum Segment Size(Sn_MSSR0) register address(R/W) + * @details @ref Sn_MSSR configures or indicates the MTU(Maximum Transfer Unit) + * of Socket n. + */ +#define Sn_MSSR(N) \ + (_W5500_IO_BASE_ + (0x0012 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +// Reserved (_W5500_IO_BASE_ + (0x0014 << 8) + +// (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief IP Type of Service(TOS) Register(R/W) + * @details @ref Sn_TOS configures the TOS(Type Of Service field in IP Header) + * of Socket n. It is set before OPEN command. + */ +#define Sn_TOS(N) \ + (_W5500_IO_BASE_ + (0x0015 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +/** + * @ingroup Socket_register_group + * @brief IP Time to live(TTL) Register(R/W) + * @details @ref Sn_TTL configures the TTL(Time To Live field in IP header) of + * Socket n. It is set before OPEN command. + */ +#define Sn_TTL(N) \ + (_W5500_IO_BASE_ + (0x0016 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) +// Reserved (_W5500_IO_BASE_ + (0x0017 << 8) + +// (WIZCHIP_SREG_BLOCK(N) << 3)) Reserved +// (_W5500_IO_BASE_ + (0x0018 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) Reserved +// (_W5500_IO_BASE_ + (0x0019 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) Reserved +// (_W5500_IO_BASE_ + (0x001A << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) Reserved +// (_W5500_IO_BASE_ + (0x001B << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) Reserved +// (_W5500_IO_BASE_ + (0x001C << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) Reserved +// (_W5500_IO_BASE_ + (0x001D << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Receive memory size register(R/W) + * @details @ref Sn_RXBUF_SIZE configures the RX buffer block size of Socket n. + * Socket n RX Buffer Block size can be configured with 1,2,4,8, and 16 Kbytes. + * If a different size is configured, the data cannot be normally received from + * a peer. Although Socket n RX Buffer Block size is initially configured to + * 2Kbytes, user can re-configure its size using @ref Sn_RXBUF_SIZE. The total + * sum of @ref Sn_RXBUF_SIZE can not be exceed 16Kbytes. When exceeded, the data + * reception error is occurred. + */ +#define Sn_RXBUF_SIZE(N) \ + (_W5500_IO_BASE_ + (0x001E << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Transmit memory size register(R/W) + * @details @ref Sn_TXBUF_SIZE configures the TX buffer block size of Socket n. + * Socket n TX Buffer Block size can be configured with 1,2,4,8, and 16 Kbytes. + * If a different size is configured, the data can�t be normally transmitted to + * a peer. Although Socket n TX Buffer Block size is initially configured to + * 2Kbytes, user can be re-configure its size using @ref Sn_TXBUF_SIZE. The + * total sum of @ref Sn_TXBUF_SIZE can not be exceed 16Kbytes. When exceeded, + * the data transmission error is occurred. + */ +#define Sn_TXBUF_SIZE(N) \ + (_W5500_IO_BASE_ + (0x001F << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Transmit free memory size register(R) + * @details @ref Sn_TX_FSR indicates the free size of Socket n TX Buffer Block. + * It is initialized to the configured size by @ref Sn_TXBUF_SIZE. Data bigger + * than @ref Sn_TX_FSR should not be saved in the Socket n TX Buffer because the + * bigger data overwrites the previous saved data not yet sent. Therefore, check + * before saving the data to the Socket n TX Buffer, and if data is equal or + * smaller than its checked size, transmit the data with SEND/SEND_MAC command + * after saving the data in Socket n TX buffer. But, if data is bigger than its + * checked size, transmit the data after dividing into the checked size and + * saving in the Socket n TX buffer. + */ +#define Sn_TX_FSR(N) \ + (_W5500_IO_BASE_ + (0x0020 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Transmit memory read pointer register address(R) + * @details @ref Sn_TX_RD is initialized by OPEN command. However, if + * Sn_MR(P[3:0]) is TCP mode(001, it is re-initialized while connecting with + * TCP. After its initialization, it is auto-increased by SEND command. SEND + * command transmits the saved data from the current @ref Sn_TX_RD to the @ref + * Sn_TX_WR in the Socket n TX Buffer. After transmitting the saved data, the + * SEND command increases the @ref Sn_TX_RD as same as the @ref Sn_TX_WR. If its + * increment value exceeds the maximum value 0xFFFF, (greater than 0x10000 and + * the carry bit occurs), then the carry bit is ignored and will automatically + * update with the lower 16bits value. + */ +#define Sn_TX_RD(N) \ + (_W5500_IO_BASE_ + (0x0022 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Transmit memory write pointer register address(R/W) + * @details @ref Sn_TX_WR is initialized by OPEN command. However, if + * Sn_MR(P[3:0]) is TCP mode(001, it is re-initialized while connecting with + * TCP.\n It should be read or be updated like as follows.\n + * 1. Read the starting address for saving the transmitting data.\n + * 2. Save the transmitting data from the starting address of Socket n TX + * buffer.\n + * 3. After saving the transmitting data, update @ref Sn_TX_WR to the increased + * value as many as transmitting data size. If the increment value exceeds the + * maximum value 0xFFFF(greater than 0x10000 and the carry bit occurs), then the + * carry bit is ignored and will automatically update with the lower 16bits + * value.\n + * 4. Transmit the saved data in Socket n TX Buffer by using SEND/SEND command + */ +#define Sn_TX_WR(N) \ + (_W5500_IO_BASE_ + (0x0024 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Received data size register(R) + * @details @ref Sn_RX_RSR indicates the data size received and saved in Socket + * n RX Buffer. + * @ref Sn_RX_RSR does not exceed the @ref Sn_RXBUF_SIZE and is calculated as + * the difference between �Socket n RX Write Pointer (@ref Sn_RX_WR)and �Socket + * n RX Read Pointer (@ref Sn_RX_RD) + */ +#define Sn_RX_RSR(N) \ + (_W5500_IO_BASE_ + (0x0026 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Read point of Receive memory(R/W) + * @details @ref Sn_RX_RD is initialized by OPEN command. Make sure to be read + * or updated as follows.\n + * 1. Read the starting save address of the received data.\n + * 2. Read data from the starting address of Socket n RX Buffer.\n + * 3. After reading the received data, Update @ref Sn_RX_RD to the increased + * value as many as the reading size. If the increment value exceeds the maximum + * value 0xFFFF, that is, is greater than 0x10000 and the carry bit occurs, + * update with the lower 16bits value ignored the carry bit.\n + * 4. Order RECV command is for notifying the updated @ref Sn_RX_RD to W5500. + */ +#define Sn_RX_RD(N) \ + (_W5500_IO_BASE_ + (0x0028 << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Write point of Receive memory(R) + * @details @ref Sn_RX_WR is initialized by OPEN command and it is + * auto-increased by the data reception. If the increased value exceeds the + * maximum value 0xFFFF, (greater than 0x10000 and the carry bit occurs), then + * the carry bit is ignored and will automatically update with the lower 16bits + * value. + */ +#define Sn_RX_WR(N) \ + (_W5500_IO_BASE_ + (0x002A << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief socket interrupt mask register(R) + * @details @ref Sn_IMR masks the interrupt of Socket n. + * Each bit corresponds to each bit of @ref Sn_IR. When a Socket n Interrupt is + * occurred and the corresponding bit of @ref Sn_IMR is the corresponding bit of + * @ref Sn_IR becomes When both the corresponding bit of @ref Sn_IMR and @ref + * Sn_IR are and the n-th bit of @ref IR is Host is interrupted by asserted INTn + * PIN to low. + */ +#define Sn_IMR(N) \ + (_W5500_IO_BASE_ + (0x002C << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Fragment field value in IP header register(R/W) + * @details @ref Sn_FRAG configures the FRAG(Fragment field in IP header). + */ +#define Sn_FRAG(N) \ + (_W5500_IO_BASE_ + (0x002D << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +/** + * @ingroup Socket_register_group + * @brief Keep Alive Timer register(R/W) + * @details @ref Sn_KPALVTR configures the transmitting timer of �KEEP + * ALIVE(KA)packet of SOCKETn. It is valid only in TCP mode, and ignored in + * other modes. The time unit is 5s. KA packet is transmittable after @ref Sn_SR + * is changed to SOCK_ESTABLISHED and after the data is transmitted or received + * to/from a peer at least once. In case of '@ref Sn_KPALVTR > 0', W5500 + * automatically transmits KA packet after time-period for checking the TCP + * connection (Auto-keepalive-process). In case of '@ref Sn_KPALVTR = 0', + * Auto-keep-alive-process will not operate, and KA packet can be transmitted by + * SEND_KEEP command by the host (Manual-keep-alive-process). + * Manual-keep-alive-process is ignored in case of '@ref Sn_KPALVTR > 0'. + */ +#define Sn_KPALVTR(N) \ + (_W5500_IO_BASE_ + (0x002F << 8) + (WIZCHIP_SREG_BLOCK(N) << 3)) + +//#define Sn_TSR(N) (_W5500_IO_BASE_ + (0x0030 << 8) + +//(WIZCHIP_SREG_BLOCK(N) << 3)) + +//----------------------------- W5500 Register values +//----------------------------- + +/* MODE register values */ +/** + * @brief Reset + * @details If this bit is All internal registers will be initialized. It will + * be automatically cleared as after S/W reset. + */ +#define MR_RST 0x80 + +/** + * @brief Wake on LAN + * @details 0 : Disable WOL mode\n + * 1 : Enable WOL mode\n + * If WOL mode is enabled and the received magic packet over UDP has been + * normally processed, the Interrupt PIN (INTn) asserts to low. When using WOL + * mode, the UDP Socket should be opened with any source port number. (Refer to + * Socket n Mode Register (@ref Sn_MR) for opening Socket.) + * @note The magic packet over UDP supported by W5500 consists of 6 bytes + * synchronization stream (xFFFFFFFFFFFF and 16 times Target MAC address stream + * in UDP payload. The options such like password are ignored. You can use any + * UDP source port number for WOL mode. + */ +#define MR_WOL 0x20 + +/** + * @brief Ping block + * @details 0 : Disable Ping block\n + * 1 : Enable Ping block\n + * If the bit is it blocks the response to a ping request. + */ +#define MR_PB 0x10 + +/** + * @brief Enable PPPoE + * @details 0 : DisablePPPoE mode\n + * 1 : EnablePPPoE mode\n + * If you use ADSL, this bit should be + */ +#define MR_PPPOE 0x08 + +/** + * @brief Enable UDP_FORCE_ARP CHECHK + * @details 0 : Disable Force ARP mode\n + * 1 : Enable Force ARP mode\n + * In Force ARP mode, It forces on sending ARP Request whenever data is sent. + */ +#define MR_FARP 0x02 + +/* IR register values */ +/** + * @brief Check IP conflict. + * @details Bit is set as when own source IP address is same with the sender IP + * address in the received ARP request. + */ +#define IR_CONFLICT 0x80 + +/** + * @brief Get the destination unreachable message in UDP sending. + * @details When receiving the ICMP (Destination port unreachable) packet, this + * bit is set as When this bit is Destination Information such as IP address + * and Port number may be checked with the corresponding @ref UIPR & @ref + * UPORTR. + */ +#define IR_UNREACH 0x40 + +/** + * @brief Get the PPPoE close message. + * @details When PPPoE is disconnected during PPPoE mode, this bit is set. + */ +#define IR_PPPoE 0x20 + +/** + * @brief Get the magic packet interrupt. + * @details When WOL mode is enabled and receives the magic packet over UDP, + * this bit is set. + */ +#define IR_MP 0x10 + +/* PHYCFGR register value */ +#define PHYCFGR_RST ~(1 << 7) //< For PHY reset, must operate AND mask. +#define PHYCFGR_OPMD (1 << 6) // Configre PHY with OPMDC value +#define PHYCFGR_OPMDC_ALLA (7 << 3) +#define PHYCFGR_OPMDC_PDOWN (6 << 3) +#define PHYCFGR_OPMDC_NA (5 << 3) +#define PHYCFGR_OPMDC_100FA (4 << 3) +#define PHYCFGR_OPMDC_100F (3 << 3) +#define PHYCFGR_OPMDC_100H (2 << 3) +#define PHYCFGR_OPMDC_10F (1 << 3) +#define PHYCFGR_OPMDC_10H (0 << 3) +#define PHYCFGR_DPX_FULL (1 << 2) +#define PHYCFGR_DPX_HALF (0 << 2) +#define PHYCFGR_SPD_100 (1 << 1) +#define PHYCFGR_SPD_10 (0 << 1) +#define PHYCFGR_LNK_ON (1 << 0) +#define PHYCFGR_LNK_OFF (0 << 0) + +/* IMR register values */ +/** + * @brief IP Conflict Interrupt Mask. + * @details 0: Disable IP Conflict Interrupt\n + * 1: Enable IP Conflict Interrupt + */ +#define IM_IR7 0x80 + +/** + * @brief Destination unreachable Interrupt Mask. + * @details 0: Disable Destination unreachable Interrupt\n + * 1: Enable Destination unreachable Interrupt + */ +#define IM_IR6 0x40 + +/** + * @brief PPPoE Close Interrupt Mask. + * @details 0: Disable PPPoE Close Interrupt\n + * 1: Enable PPPoE Close Interrupt + */ +#define IM_IR5 0x20 + +/** + * @brief Magic Packet Interrupt Mask. + * @details 0: Disable Magic Packet Interrupt\n + * 1: Enable Magic Packet Interrupt + */ +#define IM_IR4 0x10 + +/* Sn_MR Default values */ +/** + * @brief Support UDP Multicasting + * @details 0 : disable Multicasting\n + * 1 : enable Multicasting\n + * This bit is applied only during UDP mode(P[3:0] = 010.\n + * To use multicasting, @ref Sn_DIPR & @ref Sn_DPORT should be respectively + * configured with the multicast group IP address & port number before Socket n + * is opened by OPEN command of @ref Sn_CR. + */ +#define Sn_MR_MULTI 0x80 + +/** + * @brief Broadcast block in UDP Multicasting. + * @details 0 : disable Broadcast Blocking\n + * 1 : enable Broadcast Blocking\n + * This bit blocks to receive broadcasting packet during UDP mode(P[3:0] = + * 010.\m In addition, This bit does when MACRAW mode(P[3:0] = 100 + */ +#define Sn_MR_BCASTB 0x40 + +/** + * @brief No Delayed Ack(TCP), Multicast flag + * @details 0 : Disable No Delayed ACK option\n + * 1 : Enable No Delayed ACK option\n + * This bit is applied only during TCP mode (P[3:0] = 001.\n + * When this bit is It sends the ACK packet without delay as soon as a Data + * packet is received from a peer.\n When this bit is It sends the ACK packet + * after waiting for the timeout time configured by @ref _RTR_. + */ +#define Sn_MR_ND 0x20 + +/** + * @brief Unicast Block in UDP Multicasting + * @details 0 : disable Unicast Blocking\n + * 1 : enable Unicast Blocking\n + * This bit blocks receiving the unicast packet during UDP mode(P[3:0] = 010 and + * MULTI = + */ +#define Sn_MR_UCASTB 0x10 + +/** + * @brief MAC LAYER RAW SOCK + * @details This configures the protocol mode of Socket n. + * @note MACRAW mode should be only used in Socket 0. + */ +#define Sn_MR_MACRAW 0x04 + +#define Sn_MR_IPRAW 0x03 /**< IP LAYER RAW SOCK */ + +/** + * @brief UDP + * @details This configures the protocol mode of Socket n. + */ +#define Sn_MR_UDP 0x02 + +/** + * @brief TCP + * @details This configures the protocol mode of Socket n. + */ +#define Sn_MR_TCP 0x01 + +/** + * @brief Unused socket + * @details This configures the protocol mode of Socket n. + */ +#define Sn_MR_CLOSE 0x00 + +/* Sn_MR values used with Sn_MR_MACRAW */ +/** + * @brief MAC filter enable in @ref Sn_MR_MACRAW mode + * @details 0 : disable MAC Filtering\n + * 1 : enable MAC Filtering\n + * This bit is applied only during MACRAW mode(P[3:0] = 100.\n + * When set as W5500 can only receive broadcasting packet or packet sent to + * itself. When this bit is W5500 can receive all packets on Ethernet. If user + * wants to implement Hybrid TCP/IP stack, it is recommended that this bit is + * set as for reducing host overhead to process the all received packets. + */ +#define Sn_MR_MFEN Sn_MR_MULTI + +/** + * @brief Multicast Blocking in @ref Sn_MR_MACRAW mode + * @details 0 : using IGMP version 2\n + * 1 : using IGMP version 1\n + * This bit is applied only during UDP mode(P[3:0] = 010 and MULTI = + * It configures the version for IGMP messages (Join/Leave/Report). + */ +#define Sn_MR_MMB Sn_MR_ND + +/** + * @brief IPv6 packet Blocking in @ref Sn_MR_MACRAW mode + * @details 0 : disable IPv6 Blocking\n + * 1 : enable IPv6 Blocking\n + * This bit is applied only during MACRAW mode (P[3:0] = 100. It blocks to + * receiving the IPv6 packet. + */ +#define Sn_MR_MIP6B Sn_MR_UCASTB + +/* Sn_MR value used with Sn_MR_UDP & Sn_MR_MULTI */ +/** + * @brief IGMP version used in UDP mulitcasting + * @details 0 : disable Multicast Blocking\n + * 1 : enable Multicast Blocking\n + * This bit is applied only when MACRAW mode(P[3:0] = 100. It blocks to receive + * the packet with multicast MAC address. + */ +#define Sn_MR_MC Sn_MR_ND + +/* Sn_MR alternate values */ +/** + * @brief For Berkeley Socket API + */ +#define SOCK_STREAM Sn_MR_TCP + +/** + * @brief For Berkeley Socket API + */ +#define SOCK_DGRAM Sn_MR_UDP + +/* Sn_CR values */ +/** + * @brief Initialize or open socket + * @details Socket n is initialized and opened according to the protocol + * selected in Sn_MR(P3:P0). The table below shows the value of @ref Sn_SR + * corresponding to @ref Sn_MR.\n + * + * + * + * + *
\b Sn_MR (P[3:0])\b Sn_SR
Sn_MR_CLOSE + * (000)
Sn_MR_TCP (001) SOCK_INIT (0x13)
Sn_MR_UDP (010) SOCK_UDP (0x22)
S0_MR_MACRAW (100) SOCK_MACRAW (0x02)
+ */ +#define Sn_CR_OPEN 0x01 + +/** + * @brief Wait connection request in TCP mode(Server mode) + * @details This is valid only in TCP mode (\ref Sn_MR(P3:P0) = \ref Sn_MR_TCP). + * In this mode, Socket n operates as a TCP serverand waits for + * connection-request (SYN packet) from any TCP client The @ref Sn_SR changes + * the state from \ref SOCK_INIT to \ref SOCKET_LISTEN. When a TCP + * clientconnection request is successfully established, the @ref Sn_SR changes + * from SOCK_LISTEN to SOCK_ESTABLISHED and the @ref Sn_IR(0) becomes But when a + * TCP clientconnection request is failed, @ref Sn_IR(3) becomes and the status + * of @ref Sn_SR changes to SOCK_CLOSED. + */ +#define Sn_CR_LISTEN 0x02 + +/** + * @brief Send connection request in TCP mode(Client mode) + * @details To connect, a connect-request (SYN packet) is sent to TCP + * serverconfigured by @ref Sn_DIPR & Sn_DPORT(destination address & port). + * If the connect-request is successful, the @ref Sn_SR is changed to @ref + * SOCK_ESTABLISHED and the Sn_IR(0) becomes \n\n The connect-request fails in + * the following three cases.\n + * 1. When a @b ARPTO occurs (@ref Sn_IR[3] = ) because destination hardware + * address is not acquired through the ARP-process.\n + * 2. When a @b SYN/ACK packet is not received and @b TCPTO (Sn_IR(3) = )\n + * 3. When a @b RST packet is received instead of a @b SYN/ACK packet. In these + * cases, @ref Sn_SR is changed to @ref SOCK_CLOSED. + * @note This is valid only in TCP mode and operates when Socket n acts as + * TCP client + */ +#define Sn_CR_CONNECT 0x04 + +/** + * @brief Send closing request in TCP mode + * @details Regardless of TCP serveror TCP client the DISCON + * command processes the disconnect-process (b>Active closeor Passive + * close.\n + * @par Active close + * it transmits disconnect-request(FIN packet) to the connected peer\n + * @par Passive close + * When FIN packet is received from peer, a FIN packet is replied back to the + * peer.\n + * @details When the disconnect-process is successful (that is, FIN/ACK packet + * is received successfully), @ref Sn_SR is changed to @ref SOCK_CLOSED.\n + * Otherwise, TCPTO occurs (\ref Sn_IR(3)='1') and then @ref Sn_SR is changed to + * @ref SOCK_CLOSED. + * @note Valid only in TCP mode. + */ +#define Sn_CR_DISCON 0x08 + +/** + * @brief Close socket + * @details Sn_SR is changed to @ref SOCK_CLOSED. + */ +#define Sn_CR_CLOSE 0x10 + +/** + * @brief Update TX buffer pointer and send data + * @details SEND transmits all the data in the Socket n TX buffer.\n + * For more details, please refer to Socket n TX Free Size Register (@ref + * Sn_TX_FSR), Socket n, TX Write Pointer Register(@ref Sn_TX_WR), and Socket n + * TX Read Pointer Register(@ref Sn_TX_RD). + */ +#define Sn_CR_SEND 0x20 + +/** + * @brief Send data with MAC address, so without ARP process + * @details The basic operation is same as SEND.\n + * Normally SEND transmits data after destination hardware address is acquired + * by the automatic ARP-process(Address Resolution Protocol).\n But SEND_MAC + * transmits data without the automatic ARP-process.\n In this case, the + * destination hardware address is acquired from @ref Sn_DHAR configured by + * host, instead of APR-process. + * @note Valid only in UDP mode. + */ +#define Sn_CR_SEND_MAC 0x21 + +/** + * @brief Send keep alive message + * @details It checks the connection status by sending 1byte keep-alive + * packet.\n If the peer can not respond to the keep-alive packet during timeout + * time, the connection is terminated and the timeout interrupt will occur. + * @note Valid only in TCP mode. + */ +#define Sn_CR_SEND_KEEP 0x22 + +/** + * @brief Update RX buffer pointer and receive data + * @details RECV completes the processing of the received data in Socket n RX + * Buffer by using a RX read pointer register (@ref Sn_RX_RD).\n For more + * details, refer to Socket n RX Received Size Register (@ref Sn_RX_RSR), Socket + * n RX Write Pointer Register (@ref Sn_RX_WR), and Socket n RX Read Pointer + * Register (@ref Sn_RX_RD). + */ +#define Sn_CR_RECV 0x40 + +/* Sn_IR values */ +/** + * @brief SEND_OK Interrupt + * @details This is issued when SEND command is completed. + */ +#define Sn_IR_SENDOK 0x10 + +/** + * @brief TIMEOUT Interrupt + * @details This is issued when ARPTO or TCPTO occurs. + */ +#define Sn_IR_TIMEOUT 0x08 + +/** + * @brief RECV Interrupt + * @details This is issued whenever data is received from a peer. + */ +#define Sn_IR_RECV 0x04 + +/** + * @brief DISCON Interrupt + * @details This is issued when FIN or FIN/ACK packet is received from a peer. + */ +#define Sn_IR_DISCON 0x02 + +/** + * @brief CON Interrupt + * @details This is issued one time when the connection with peer is successful + * and then @ref Sn_SR is changed to @ref SOCK_ESTABLISHED. + */ +#define Sn_IR_CON 0x01 + +/* Sn_SR values */ +/** + * @brief Closed + * @details This indicates that Socket n is released.\n + * When DICON, CLOSE command is ordered, or when a timeout occurs, it is changed + * to @ref SOCK_CLOSED regardless of previous status. + */ +#define SOCK_CLOSED 0x00 + +/** + * @brief Initiate state + * @details This indicates Socket n is opened with TCP mode.\n + * It is changed to @ref SOCK_INIT when @ref Sn_MR(P[3:0]) = 001 and OPEN + * command is ordered.\n After @ref SOCK_INIT, user can use LISTEN /CONNECT + * command. + */ +#define SOCK_INIT 0x13 + +/** + * @brief Listen state + * @details This indicates Socket n is operating as TCP servermode and + * waiting for connection-request (SYN packet) from a peer TCP client.\n + * It will change to @ref SOCK_ESTALBLISHED when the connection-request is + * successfully accepted.\n Otherwise it will change to @ref SOCK_CLOSED after + * TCPTO @ref Sn_IR(TIMEOUT) = '1') is occurred. + */ +#define SOCK_LISTEN 0x14 + +/** + * @brief Connection state + * @details This indicates Socket n sent the connect-request packet (SYN packet) + * to a peer.\n It is temporarily shown when @ref Sn_SR is changed from @ref + * SOCK_INIT to @ref SOCK_ESTABLISHED by CONNECT command.\n If + * connect-accept(SYN/ACK packet) is received from the peer at SOCK_SYNSENT, it + * changes to @ref SOCK_ESTABLISHED.\n Otherwise, it changes to @ref SOCK_CLOSED + * after TCPTO (@ref Sn_IR[TIMEOUT] = '1') is occurred. + */ +#define SOCK_SYNSENT 0x15 + +/** + * @brief Connection state + * @details It indicates Socket n successfully received the connect-request + * packet (SYN packet) from a peer.\n If socket n sends the response (SYN/ACK + * packet) to the peer successfully, it changes to @ref SOCK_ESTABLISHED. \n If + * not, it changes to @ref SOCK_CLOSED after timeout (@ref Sn_IR[TIMEOUT] = '1') + * is occurred. + */ +#define SOCK_SYNRECV 0x16 + +/** + * @brief Success to connect + * @details This indicates the status of the connection of Socket n.\n + * It changes to @ref SOCK_ESTABLISHED when the TCP SERVERprocessed the + * SYN packet from the TCP CLIENTduring @ref SOCK_LISTEN, or when the + * CONNECT command is successful.\n During @ref SOCK_ESTABLISHED, DATA packet + * can be transferred using SEND or RECV command. + */ +#define SOCK_ESTABLISHED 0x17 + +/** + * @brief Closing state + * @details These indicate Socket n is closing.\n + * These are shown in disconnect-process such as active-close and + * passive-close.\n When Disconnect-process is successfully completed, or when + * timeout occurs, these change to @ref SOCK_CLOSED. + */ +#define SOCK_FIN_WAIT 0x18 + +/** + * @brief Closing state + * @details These indicate Socket n is closing.\n + * These are shown in disconnect-process such as active-close and + * passive-close.\n When Disconnect-process is successfully completed, or when + * timeout occurs, these change to @ref SOCK_CLOSED. + */ +#define SOCK_CLOSING 0x1A + +/** + * @brief Closing state + * @details These indicate Socket n is closing.\n + * These are shown in disconnect-process such as active-close and + * passive-close.\n When Disconnect-process is successfully completed, or when + * timeout occurs, these change to @ref SOCK_CLOSED. + */ +#define SOCK_TIME_WAIT 0x1B + +/** + * @brief Closing state + * @details This indicates Socket n received the disconnect-request (FIN packet) + * from the connected peer.\n This is half-closing status, and data can be + * transferred.\n For full-closing, DISCON command is used. But For + * just-closing, CLOSE command is used. + */ +#define SOCK_CLOSE_WAIT 0x1C + +/** + * @brief Closing state + * @details This indicates Socket n is waiting for the response (FIN/ACK packet) + * to the disconnect-request (FIN packet) by passive-close.\n It changes to @ref + * SOCK_CLOSED when Socket n received the response successfully, or when + * timeout(@ref Sn_IR[TIMEOUT] = '1') is occurred. + */ +#define SOCK_LAST_ACK 0x1D + +/** + * @brief UDP socket + * @details This indicates Socket n is opened in UDP mode(@ref Sn_MR(P[3:0]) = + * '010').\n It changes to SOCK_UDP when @ref Sn_MR(P[3:0]) = '010' and @ref + * Sn_CR_OPEN command is ordered.\n Unlike TCP mode, data can be transfered + * without the connection-process. + */ +#define SOCK_UDP 0x22 + +#define SOCK_IPRAW 0x32 /**< IP raw mode socket */ + +/** + * @brief MAC raw mode socket + * @details This indicates Socket 0 is opened in MACRAW mode (S0_MR(P[3:0]) = + * 100and is valid only in Socket 0.\n It changes to SOCK_MACRAW when + * S0_MR(P[3:0] = 100and OPEN command is ordered.\n Like UDP mode socket, MACRAW + * mode Socket 0 can transfer a MAC packet (Ethernet frame) without the + * connection-process. + */ +#define SOCK_MACRAW 0x42 + +//#define SOCK_PPPOE 0x5F + +/* IP PROTOCOL */ +#define IPPROTO_IP 0 //< Dummy for IP +#define IPPROTO_ICMP 1 //< Control message protocol +#define IPPROTO_IGMP 2 //< Internet group management protocol +#define IPPROTO_GGP 3 //< Gateway^2 (deprecated) +#define IPPROTO_TCP 6 //< TCP +#define IPPROTO_PUP 12 //< PUP +#define IPPROTO_UDP 17 //< UDP +#define IPPROTO_IDP 22 //< XNS idp +#define IPPROTO_ND 77 //< UNOFFICIAL net disk protocol +#define IPPROTO_RAW 255 //< Raw IP packet + +/** + * @brief Enter a critical section + * + * @details It is provided to protect your shared code which are executed + * without distribution. \n \n + * + * In non-OS environment, It can be just implemented by disabling whole + * interrupt.\n In OS environment, You can replace it to critical section api + * supported by OS. + * + * \sa WIZCHIP_READ(), WIZCHIP_WRITE(), WIZCHIP_READ_BUF(), WIZCHIP_WRITE_BUF() + * \sa WIZCHIP_CRITICAL_EXIT() + */ +#define WIZCHIP_CRITICAL_ENTER() WIZCHIP.CRIS._enter() + +#ifdef _exit +#undef _exit +#endif + +/** + * @brief Exit a critical section + * + * @details It is provided to protect your shared code which are executed + * without distribution. \n\n + * + * In non-OS environment, It can be just implemented by disabling whole + * interrupt. \n In OS environment, You can replace it to critical section api + * supported by OS. + * + * @sa WIZCHIP_READ(), WIZCHIP_WRITE(), WIZCHIP_READ_BUF(), WIZCHIP_WRITE_BUF() + * @sa WIZCHIP_CRITICAL_ENTER() + */ +#define WIZCHIP_CRITICAL_EXIT() WIZCHIP.CRIS._exit() + +//////////////////////// +// Basic I/O Function // +//////////////////////// + +/** + * @ingroup Basic_IO_function + * @brief It reads 1 byte value from a register. + * @param AddrSel Register address + * @return The value of register + */ +uint8_t WIZCHIP_READ(uint32_t AddrSel); + +/** + * @ingroup Basic_IO_function + * @brief It writes 1 byte value to a register. + * @param AddrSel Register address + * @param wb Write data + * @return void + */ +void WIZCHIP_WRITE(uint32_t AddrSel, uint8_t wb); + +/** + * @ingroup Basic_IO_function + * @brief It reads sequence data from registers. + * @param AddrSel Register address + * @param pBuf Pointer buffer to read data + * @param len Data length + */ +void WIZCHIP_READ_BUF(uint32_t AddrSel, uint8_t *pBuf, uint16_t len); + +/** + * @ingroup Basic_IO_function + * @brief It writes sequence data to registers. + * @param AddrSel Register address + * @param pBuf Pointer buffer to write data + * @param len Data length + */ +void WIZCHIP_WRITE_BUF(uint32_t AddrSel, uint8_t *pBuf, uint16_t len); + +///////////////////////////////// +// Common Register I/O function // +///////////////////////////////// +/** + * @ingroup Common_register_access_function + * @brief Set Mode Register + * @param (uint8_t)mr The value to be set. + * @sa getMR() + */ +#define setMR(mr) WIZCHIP_WRITE(MR, mr) + +/** + * @ingroup Common_register_access_function + * @brief Get Mode Register + * @return uint8_t. The value of Mode register. + * @sa setMR() + */ +#define getMR() WIZCHIP_READ(MR) + +/** + * @ingroup Common_register_access_function + * @brief Set gateway IP address + * @param (uint8_t*)gar Pointer variable to set gateway IP address. It should be + * allocated 4 bytes. + * @sa getGAR() + */ +#define setGAR(gar) WIZCHIP_WRITE_BUF(GAR, gar, 4) + +/** + * @ingroup Common_register_access_function + * @brief Get gateway IP address + * @param (uint8_t*)gar Pointer variable to get gateway IP address. It should be + * allocated 4 bytes. + * @sa setGAR() + */ +#define getGAR(gar) WIZCHIP_READ_BUF(GAR, gar, 4) + +/** + * @ingroup Common_register_access_function + * @brief Set subnet mask address + * @param (uint8_t*)subr Pointer variable to set subnet mask address. It should + * be allocated 4 bytes. + * @sa getSUBR() + */ +#define setSUBR(subr) WIZCHIP_WRITE_BUF(SUBR, subr, 4) + +/** + * @ingroup Common_register_access_function + * @brief Get subnet mask address + * @param (uint8_t*)subr Pointer variable to get subnet mask address. It should + * be allocated 4 bytes. + * @sa setSUBR() + */ +#define getSUBR(subr) WIZCHIP_READ_BUF(SUBR, subr, 4) + +/** + * @ingroup Common_register_access_function + * @brief Set local MAC address + * @param (uint8_t*)shar Pointer variable to set local MAC address. It should be + * allocated 6 bytes. + * @sa getSHAR() + */ +#define setSHAR(shar) WIZCHIP_WRITE_BUF(SHAR, shar, 6) + +/** + * @ingroup Common_register_access_function + * @brief Get local MAC address + * @param (uint8_t*)shar Pointer variable to get local MAC address. It should be + * allocated 6 bytes. + * @sa setSHAR() + */ +#define getSHAR(shar) WIZCHIP_READ_BUF(SHAR, shar, 6) + +/** + * @ingroup Common_register_access_function + * @brief Set local IP address + * @param (uint8_t*)sipr Pointer variable to set local IP address. It should be + * allocated 4 bytes. + * @sa getSIPR() + */ +#define setSIPR(sipr) WIZCHIP_WRITE_BUF(SIPR, sipr, 4) + +/** + * @ingroup Common_register_access_function + * @brief Get local IP address + * @param (uint8_t*)sipr Pointer variable to get local IP address. It should be + * allocated 4 bytes. + * @sa setSIPR() + */ +#define getSIPR(sipr) WIZCHIP_READ_BUF(SIPR, sipr, 4) + +/** + * @ingroup Common_register_access_function + * @brief Set INTLEVEL register + * @param (uint16_t)intlevel Value to set @ref INTLEVEL register. + * @sa getINTLEVEL() + */ +#define setINTLEVEL(intlevel) \ + { \ + WIZCHIP_WRITE(INTLEVEL, (uint8_t)(intlevel >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(INTLEVEL, 1), (uint8_t)intlevel); \ + } + +/** + * @ingroup Common_register_access_function + * @brief Get INTLEVEL register + * @return uint16_t. Value of @ref INTLEVEL register. + * @sa setINTLEVEL() + */ +// M20150401 : Type explict declaration +/* +#define getINTLEVEL() \ + ((WIZCHIP_READ(INTLEVEL) << 8) + +WIZCHIP_READ(WIZCHIP_OFFSET_INC(INTLEVEL,1))) +*/ +#define getINTLEVEL() \ + (((uint16_t)WIZCHIP_READ(INTLEVEL) << 8) + \ + WIZCHIP_READ(WIZCHIP_OFFSET_INC(INTLEVEL, 1))) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref IR register + * @param (uint8_t)ir Value to set @ref IR register. + * @sa getIR() + */ +#define setIR(ir) WIZCHIP_WRITE(IR, (ir & 0xF0)) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref IR register + * @return uint8_t. Value of @ref IR register. + * @sa setIR() + */ +#define getIR() (WIZCHIP_READ(IR) & 0xF0) +/** + * @ingroup Common_register_access_function + * @brief Set @ref _IMR_ register + * @param (uint8_t)imr Value to set @ref _IMR_ register. + * @sa getIMR() + */ +#define setIMR(imr) WIZCHIP_WRITE(_IMR_, imr) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref _IMR_ register + * @return uint8_t. Value of @ref _IMR_ register. + * @sa setIMR() + */ +#define getIMR() WIZCHIP_READ(_IMR_) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref SIR register + * @param (uint8_t)sir Value to set @ref SIR register. + * @sa getSIR() + */ +#define setSIR(sir) WIZCHIP_WRITE(SIR, sir) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref SIR register + * @return uint8_t. Value of @ref SIR register. + * @sa setSIR() + */ +#define getSIR() WIZCHIP_READ(SIR) +/** + * @ingroup Common_register_access_function + * @brief Set @ref SIMR register + * @param (uint8_t)simr Value to set @ref SIMR register. + * @sa getSIMR() + */ +#define setSIMR(simr) WIZCHIP_WRITE(SIMR, simr) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref SIMR register + * @return uint8_t. Value of @ref SIMR register. + * @sa setSIMR() + */ +#define getSIMR() WIZCHIP_READ(SIMR) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref _RTR_ register + * @param (uint16_t)rtr Value to set @ref _RTR_ register. + * @sa getRTR() + */ +#define setRTR(rtr) \ + { \ + WIZCHIP_WRITE(_RTR_, (uint8_t)(rtr >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(_RTR_, 1), (uint8_t)rtr); \ + } + +/** + * @ingroup Common_register_access_function + * @brief Get @ref _RTR_ register + * @return uint16_t. Value of @ref _RTR_ register. + * @sa setRTR() + */ +// M20150401 : Type explict declaration +/* +#define getRTR() \ + ((WIZCHIP_READ(_RTR_) << 8) + +WIZCHIP_READ(WIZCHIP_OFFSET_INC(_RTR_,1))) +*/ +#define getRTR() \ + (((uint16_t)WIZCHIP_READ(_RTR_) << 8) + \ + WIZCHIP_READ(WIZCHIP_OFFSET_INC(_RTR_, 1))) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref _RCR_ register + * @param (uint8_t)rcr Value to set @ref _RCR_ register. + * @sa getRCR() + */ +#define setRCR(rcr) WIZCHIP_WRITE(_RCR_, rcr) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref _RCR_ register + * @return uint8_t. Value of @ref _RCR_ register. + * @sa setRCR() + */ +#define getRCR() WIZCHIP_READ(_RCR_) + +//================================================== test done +//=========================================================== + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PTIMER register + * @param (uint8_t)ptimer Value to set @ref PTIMER register. + * @sa getPTIMER() + */ +#define setPTIMER(ptimer) WIZCHIP_WRITE(PTIMER, ptimer) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PTIMER register + * @return uint8_t. Value of @ref PTIMER register. + * @sa setPTIMER() + */ +#define getPTIMER() WIZCHIP_READ(PTIMER) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PMAGIC register + * @param (uint8_t)pmagic Value to set @ref PMAGIC register. + * @sa getPMAGIC() + */ +#define setPMAGIC(pmagic) WIZCHIP_WRITE(PMAGIC, pmagic) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PMAGIC register + * @return uint8_t. Value of @ref PMAGIC register. + * @sa setPMAGIC() + */ +#define getPMAGIC() WIZCHIP_READ(PMAGIC) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PHAR address + * @param (uint8_t*)phar Pointer variable to set PPP destination MAC register + * address. It should be allocated 6 bytes. + * @sa getPHAR() + */ +#define setPHAR(phar) WIZCHIP_WRITE_BUF(PHAR, phar, 6) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PHAR address + * @param (uint8_t*)phar Pointer variable to PPP destination MAC register + * address. It should be allocated 6 bytes. + * @sa setPHAR() + */ +#define getPHAR(phar) WIZCHIP_READ_BUF(PHAR, phar, 6) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PSID register + * @param (uint16_t)psid Value to set @ref PSID register. + * @sa getPSID() + */ +#define setPSID(psid) \ + { \ + WIZCHIP_WRITE(PSID, (uint8_t)(psid >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(PSID, 1), (uint8_t)psid); \ + } + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PSID register + * @return uint16_t. Value of @ref PSID register. + * @sa setPSID() + */ +// uint16_t getPSID(void); +// M20150401 : Type explict declaration +/* +#define getPSID() \ + ((WIZCHIP_READ(PSID) << 8) + +WIZCHIP_READ(WIZCHIP_OFFSET_INC(PSID,1))) +*/ +#define getPSID() \ + (((uint16_t)WIZCHIP_READ(PSID) << 8) + \ + WIZCHIP_READ(WIZCHIP_OFFSET_INC(PSID, 1))) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PMRU register + * @param (uint16_t)pmru Value to set @ref PMRU register. + * @sa getPMRU() + */ +#define setPMRU(pmru) \ + { \ + WIZCHIP_WRITE(PMRU, (uint8_t)(pmru >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(PMRU, 1), (uint8_t)pmru); \ + } + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PMRU register + * @return uint16_t. Value of @ref PMRU register. + * @sa setPMRU() + */ +// M20150401 : Type explict declaration +/* +#define getPMRU() \ + ((WIZCHIP_READ(PMRU) << 8) + +WIZCHIP_READ(WIZCHIP_OFFSET_INC(PMRU,1))) +*/ +#define getPMRU() \ + (((uint16_t)WIZCHIP_READ(PMRU) << 8) + \ + WIZCHIP_READ(WIZCHIP_OFFSET_INC(PMRU, 1))) + +/** + * @ingroup Common_register_access_function + * @brief Get unreachable IP address + * @param (uint8_t*)uipr Pointer variable to get unreachable IP address. It + * should be allocated 4 bytes. + */ +// M20150401 : Size Error of UIPR (6 -> 4) +/* +#define getUIPR(uipr) \ + WIZCHIP_READ_BUF(UIPR,uipr,6) +*/ +#define getUIPR(uipr) WIZCHIP_READ_BUF(UIPR, uipr, 4) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref UPORTR register + * @return uint16_t. Value of @ref UPORTR register. + */ +// M20150401 : Type explict declaration +/* +#define getUPORTR() \ + ((WIZCHIP_READ(UPORTR) << 8) + +WIZCHIP_READ(WIZCHIP_OFFSET_INC(UPORTR,1))) +*/ +#define getUPORTR() \ + (((uint16_t)WIZCHIP_READ(UPORTR) << 8) + \ + WIZCHIP_READ(WIZCHIP_OFFSET_INC(UPORTR, 1))) + +/** + * @ingroup Common_register_access_function + * @brief Set @ref PHYCFGR register + * @param (uint8_t)phycfgr Value to set @ref PHYCFGR register. + * @sa getPHYCFGR() + */ +#define setPHYCFGR(phycfgr) WIZCHIP_WRITE(PHYCFGR, phycfgr) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref PHYCFGR register + * @return uint8_t. Value of @ref PHYCFGR register. + * @sa setPHYCFGR() + */ +#define getPHYCFGR() WIZCHIP_READ(PHYCFGR) + +/** + * @ingroup Common_register_access_function + * @brief Get @ref VERSIONR register + * @return uint8_t. Value of @ref VERSIONR register. + */ +#define getVERSIONR() WIZCHIP_READ(VERSIONR) + +///////////////////////////////////// + +/////////////////////////////////// +// Socket N register I/O function // +/////////////////////////////////// +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_MR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)mr Value to set @ref Sn_MR + * @sa getSn_MR() + */ +#define setSn_MR(sn, mr) WIZCHIP_WRITE(Sn_MR(sn), mr) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_MR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_MR. + * @sa setSn_MR() + */ +#define getSn_MR(sn) WIZCHIP_READ(Sn_MR(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_CR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)cr Value to set @ref Sn_CR + * @sa getSn_CR() + */ +#define setSn_CR(sn, cr) WIZCHIP_WRITE(Sn_CR(sn), cr) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_CR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_CR. + * @sa setSn_CR() + */ +#define getSn_CR(sn) WIZCHIP_READ(Sn_CR(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_IR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)ir Value to set @ref Sn_IR + * @sa getSn_IR() + */ +#define setSn_IR(sn, ir) WIZCHIP_WRITE(Sn_IR(sn), (ir & 0x1F)) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_IR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_IR. + * @sa setSn_IR() + */ +#define getSn_IR(sn) (WIZCHIP_READ(Sn_IR(sn)) & 0x1F) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_IMR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)imr Value to set @ref Sn_IMR + * @sa getSn_IMR() + */ +#define setSn_IMR(sn, imr) WIZCHIP_WRITE(Sn_IMR(sn), (imr & 0x1F)) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_IMR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_IMR. + * @sa setSn_IMR() + */ +#define getSn_IMR(sn) (WIZCHIP_READ(Sn_IMR(sn)) & 0x1F) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_SR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_SR. + */ +#define getSn_SR(sn) WIZCHIP_READ(Sn_SR(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_PORT register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)port Value to set @ref Sn_PORT. + * @sa getSn_PORT() + */ +#define setSn_PORT(sn, port) \ + { \ + WIZCHIP_WRITE(Sn_PORT(sn), (uint8_t)(port >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_PORT(sn), 1), (uint8_t)port); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_PORT register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_PORT. + * @sa setSn_PORT() + */ +// M20150401 : Type explict declaration +/* +#define getSn_PORT(sn) \ + ((WIZCHIP_READ(Sn_PORT(sn)) << 8) + +WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_PORT(sn),1))) +*/ +#define getSn_PORT(sn) \ + (((uint16_t)WIZCHIP_READ(Sn_PORT(sn)) << 8) + \ + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_PORT(sn), 1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_DHAR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t*)dhar Pointer variable to set socket n destination hardware + * address. It should be allocated 6 bytes. + * @sa getSn_DHAR() + */ +#define setSn_DHAR(sn, dhar) WIZCHIP_WRITE_BUF(Sn_DHAR(sn), dhar, 6) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_MR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t*)dhar Pointer variable to get socket n destination hardware + * address. It should be allocated 6 bytes. + * @sa setSn_DHAR() + */ +#define getSn_DHAR(sn, dhar) WIZCHIP_READ_BUF(Sn_DHAR(sn), dhar, 6) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_DIPR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t*)dipr Pointer variable to set socket n destination IP + * address. It should be allocated 4 bytes. + * @sa getSn_DIPR() + */ +#define setSn_DIPR(sn, dipr) WIZCHIP_WRITE_BUF(Sn_DIPR(sn), dipr, 4) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_DIPR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t*)dipr Pointer variable to get socket n destination IP + * address. It should be allocated 4 bytes. + * @sa setSn_DIPR() + */ +#define getSn_DIPR(sn, dipr) WIZCHIP_READ_BUF(Sn_DIPR(sn), dipr, 4) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_DPORT register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)dport Value to set @ref Sn_DPORT + * @sa getSn_DPORT() + */ +#define setSn_DPORT(sn, dport) \ + { \ + WIZCHIP_WRITE(Sn_DPORT(sn), (uint8_t)(dport >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_DPORT(sn), 1), (uint8_t)dport); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_DPORT register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_DPORT. + * @sa setSn_DPORT() + */ +// M20150401 : Type explict declaration +/* +#define getSn_DPORT(sn) \ + ((WIZCHIP_READ(Sn_DPORT(sn)) << 8) + +WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_DPORT(sn),1))) +*/ +#define getSn_DPORT(sn) \ + (((uint16_t)WIZCHIP_READ(Sn_DPORT(sn)) << 8) + \ + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_DPORT(sn), 1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_MSSR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)mss Value to set @ref Sn_MSSR + * @sa setSn_MSSR() + */ +#define setSn_MSSR(sn, mss) \ + { \ + WIZCHIP_WRITE(Sn_MSSR(sn), (uint8_t)(mss >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_MSSR(sn), 1), (uint8_t)mss); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_MSSR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_MSSR. + * @sa setSn_MSSR() + */ +// M20150401 : Type explict declaration +/* +#define getSn_MSSR(sn) \ + ((WIZCHIP_READ(Sn_MSSR(sn)) << 8) + +WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_MSSR(sn),1))) +*/ +#define getSn_MSSR(sn) \ + (((uint16_t)WIZCHIP_READ(Sn_MSSR(sn)) << 8) + \ + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_MSSR(sn), 1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_TOS register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)tos Value to set @ref Sn_TOS + * @sa getSn_TOS() + */ +#define setSn_TOS(sn, tos) WIZCHIP_WRITE(Sn_TOS(sn), tos) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TOS register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of Sn_TOS. + * @sa setSn_TOS() + */ +#define getSn_TOS(sn) WIZCHIP_READ(Sn_TOS(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_TTL register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)ttl Value to set @ref Sn_TTL + * @sa getSn_TTL() + */ +#define setSn_TTL(sn, ttl) WIZCHIP_WRITE(Sn_TTL(sn), ttl) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TTL register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_TTL. + * @sa setSn_TTL() + */ +#define getSn_TTL(sn) WIZCHIP_READ(Sn_TTL(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_RXBUF_SIZE register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)rxbufsize Value to set @ref Sn_RXBUF_SIZE + * @sa getSn_RXBUF_SIZE() + */ +#define setSn_RXBUF_SIZE(sn, rxbufsize) \ + WIZCHIP_WRITE(Sn_RXBUF_SIZE(sn), rxbufsize) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_RXBUF_SIZE register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_RXBUF_SIZE. + * @sa setSn_RXBUF_SIZE() + */ +#define getSn_RXBUF_SIZE(sn) WIZCHIP_READ(Sn_RXBUF_SIZE(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_TXBUF_SIZE register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)txbufsize Value to set @ref Sn_TXBUF_SIZE + * @sa getSn_TXBUF_SIZE() + */ +#define setSn_TXBUF_SIZE(sn, txbufsize) \ + WIZCHIP_WRITE(Sn_TXBUF_SIZE(sn), txbufsize) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TXBUF_SIZE register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_TXBUF_SIZE. + * @sa setSn_TXBUF_SIZE() + */ +#define getSn_TXBUF_SIZE(sn) WIZCHIP_READ(Sn_TXBUF_SIZE(sn)) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TX_FSR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_TX_FSR. + */ +uint16_t getSn_TX_FSR(uint8_t sn); + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TX_RD register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_TX_RD. + */ +// M20150401 : Type explict declaration +/* +#define getSn_TX_RD(sn) \ + ((WIZCHIP_READ(Sn_TX_RD(sn)) << 8) + +WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_RD(sn),1))) +*/ +#define getSn_TX_RD(sn) \ + (((uint16_t)WIZCHIP_READ(Sn_TX_RD(sn)) << 8) + \ + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_RD(sn), 1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_TX_WR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)txwr Value to set @ref Sn_TX_WR + * @sa GetSn_TX_WR() + */ +#define setSn_TX_WR(sn, txwr) \ + { \ + WIZCHIP_WRITE(Sn_TX_WR(sn), (uint8_t)(txwr >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_TX_WR(sn), 1), (uint8_t)txwr); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_TX_WR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_TX_WR. + * @sa setSn_TX_WR() + */ +// M20150401 : Type explict declaration +/* +#define getSn_TX_WR(sn) \ + ((WIZCHIP_READ(Sn_TX_WR(sn)) << 8) + +WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_WR(sn),1))) +*/ +#define getSn_TX_WR(sn) \ + (((uint16_t)WIZCHIP_READ(Sn_TX_WR(sn)) << 8) + \ + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_WR(sn), 1))) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_RX_RSR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_RX_RSR. + */ +uint16_t getSn_RX_RSR(uint8_t sn); + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_RX_RD register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)rxrd Value to set @ref Sn_RX_RD + * @sa getSn_RX_RD() + */ +#define setSn_RX_RD(sn, rxrd) \ + { \ + WIZCHIP_WRITE(Sn_RX_RD(sn), (uint8_t)(rxrd >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_RX_RD(sn), 1), (uint8_t)rxrd); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_RX_RD register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_RX_RD. + * @sa setSn_RX_RD() + */ +// M20150401 : Type explict declaration +/* +#define getSn_RX_RD(sn) \ + ((WIZCHIP_READ(Sn_RX_RD(sn)) << 8) + +WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RD(sn),1))) +*/ +#define getSn_RX_RD(sn) \ + (((uint16_t)WIZCHIP_READ(Sn_RX_RD(sn)) << 8) + \ + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RD(sn), 1))) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_RX_WR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_RX_WR. + */ +// M20150401 : Type explict declaration +/* +#define getSn_RX_WR(sn) \ + ((WIZCHIP_READ(Sn_RX_WR(sn)) << 8) + +WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_WR(sn),1))) +*/ +#define getSn_RX_WR(sn) \ + (((uint16_t)WIZCHIP_READ(Sn_RX_WR(sn)) << 8) + \ + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_WR(sn), 1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_FRAG register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint16_t)frag Value to set @ref Sn_FRAG + * @sa getSn_FRAD() + */ +#define setSn_FRAG(sn, frag) \ + { \ + WIZCHIP_WRITE(Sn_FRAG(sn), (uint8_t)(frag >> 8)); \ + WIZCHIP_WRITE(WIZCHIP_OFFSET_INC(Sn_FRAG(sn), 1), (uint8_t)frag); \ + } + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_FRAG register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of @ref Sn_FRAG. + * @sa setSn_FRAG() + */ +// M20150401 : Type explict declaration +/* +#define getSn_FRAG(sn) \ + ((WIZCHIP_READ(Sn_FRAG(sn)) << 8) + +WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_FRAG(sn),1))) +*/ +#define getSn_FRAG(sn) \ + (((uint16_t)WIZCHIP_READ(Sn_FRAG(sn)) << 8) + \ + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_FRAG(sn), 1))) + +/** + * @ingroup Socket_register_access_function + * @brief Set @ref Sn_KPALVTR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param (uint8_t)kpalvt Value to set @ref Sn_KPALVTR + * @sa getSn_KPALVTR() + */ +#define setSn_KPALVTR(sn, kpalvt) WIZCHIP_WRITE(Sn_KPALVTR(sn), kpalvt) + +/** + * @ingroup Socket_register_access_function + * @brief Get @ref Sn_KPALVTR register + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint8_t. Value of @ref Sn_KPALVTR. + * @sa setSn_KPALVTR() + */ +#define getSn_KPALVTR(sn) WIZCHIP_READ(Sn_KPALVTR(sn)) + +////////////////////////////////////// + +///////////////////////////////////// +// Sn_TXBUF & Sn_RXBUF IO function // +///////////////////////////////////// +/** + * @brief Socket_register_access_function + * @brief Gets the max buffer size of socket sn passed as parameter. + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of Socket n RX max buffer size. + */ +// M20150401 : Type explict declaration +/* +#define getSn_RxMAX(sn) \ + (getSn_RXBUF_SIZE(sn) << 10) +*/ +#define getSn_RxMAX(sn) (((uint16_t)getSn_RXBUF_SIZE(sn)) << 10) + +/** + * @brief Socket_register_access_function + * @brief Gets the max buffer size of socket sn passed as parameters. + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @return uint16_t. Value of Socket n TX max buffer size. + */ +// M20150401 : Type explict declaration +/* +#define getSn_TxMAX(sn) \ + (getSn_TXBUF_SIZE(sn) << 10) +*/ +#define getSn_TxMAX(sn) (((uint16_t)getSn_TXBUF_SIZE(sn)) << 10) + +/** + * @ingroup Basic_IO_function + * @brief It copies data to internal TX memory + * + * @details This function reads the Tx write pointer register and after that, + * it copies the wizdata(pointer buffer) of the length of + * len(variable) bytes to internal TX memory and updates the Tx write + * pointer register. This function is being called by send() and sendto() + * function also. + * + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param wizdata Pointer buffer to write data + * @param len Data length + * @sa wiz_recv_data() + */ +void wiz_send_data(uint8_t sn, uint8_t *wizdata, uint16_t len); + +/** + * @ingroup Basic_IO_function + * @brief It copies data to your buffer from internal RX memory + * + * @details This function read the Rx read pointer register and after that, + * it copies the received data from internal RX memory + * to wizdata(pointer variable) of the length of len(variable) + * bytes. This function is being called by recv() also. + * + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param wizdata Pointer buffer to read data + * @param len Data length + * @sa wiz_send_data() + */ +void wiz_recv_data(uint8_t sn, uint8_t *wizdata, uint16_t len); + +/** + * @ingroup Basic_IO_function + * @brief It discard the received data in RX memory. + * @details It discards the data of the length of len(variable) bytes in + * internal RX memory. + * @param (uint8_t)sn Socket number. It should be 0 ~ 7. + * @param len Data length + */ +void wiz_recv_ignore(uint8_t sn, uint16_t len); + +/// @cond DOXY_APPLY_CODE +#endif +/// @endcond + +#ifdef __cplusplus +} +#endif + +#endif // _W5500_H_ \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/wizchip_conf.h b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/wizchip_conf.h new file mode 100755 index 000000000..a58da3a19 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/include/wizchip_conf.h @@ -0,0 +1,704 @@ +//***************************************************************************** +// +//! \file wizchip_conf.h +//! \brief WIZCHIP Config Header File. +//! \version 1.0.0 +//! \date 2013/10/21 +//! \par Revision history +//! <2015/02/05> Notice +//! The version history is not updated after this point. +//! Download the latest version directly from GitHub. Please visit the +//! our GitHub repository for ioLibrary. +//! >> https://github.com/Wiznet/ioLibrary_Driver +//! <2013/10/21> 1st Release +//! \author MidnightCow +//! \copyright +//! +//! Copyright (c) 2013, WIZnet Co., LTD. +//! 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 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. +// +//***************************************************************************** + +/** + * @defgroup extra_functions 2. WIZnet Extra Functions + * + * @brief These functions is optional function. It could be replaced at WIZCHIP + * I/O function because they were made by WIZCHIP I/O functions. + * @details There are functions of configuring WIZCHIP, network, interrupt, phy, + * network information and timer. \n + * + */ + +#ifndef _WIZCHIP_CONF_H_ +#define _WIZCHIP_CONF_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +/** + * @brief Select WIZCHIP. + * @todo You should select one, \b W5100, \b W5100S, \b W5200, \b W5300, \b + * W5500 or etc. \n\n ex> #define \_WIZCHIP_ W5500 + */ + +#define W5100 5100 +#define W5100S 5100 + 5 +#define W5200 5200 +#define W5300 5300 +#define W5500 5500 + +#ifndef _WIZCHIP_ +#define _WIZCHIP_ W5500 // W5100, W5100S, W5200, W5300, W5500 +#endif + +#define _WIZCHIP_IO_MODE_NONE_ 0x0000 +#define _WIZCHIP_IO_MODE_BUS_ 0x0100 /**< Bus interface mode */ +#define _WIZCHIP_IO_MODE_SPI_ 0x0200 /**< SPI interface mode */ +//#define _WIZCHIP_IO_MODE_IIC_ 0x0400 +//#define _WIZCHIP_IO_MODE_SDIO_ 0x0800 +// Add to +// + +#define _WIZCHIP_IO_MODE_BUS_DIR_ \ + (_WIZCHIP_IO_MODE_BUS_ + 1) /**< BUS interface mode for direct */ +#define _WIZCHIP_IO_MODE_BUS_INDIR_ \ + (_WIZCHIP_IO_MODE_BUS_ + 2) /**< BUS interface mode for indirect */ + +#define _WIZCHIP_IO_MODE_SPI_VDM_ \ + (_WIZCHIP_IO_MODE_SPI_ + 1) /**< SPI interface mode for variable length \ \ \ + data*/ +#define _WIZCHIP_IO_MODE_SPI_FDM_ \ + (_WIZCHIP_IO_MODE_SPI_ + \ + 2) /**< SPI interface mode for fixed length data mode*/ +#define _WIZCHIP_IO_MODE_SPI_5500_ \ + (_WIZCHIP_IO_MODE_SPI_ + \ + 3) /**< SPI interface mode for fixed length data mode*/ + +#if (_WIZCHIP_ == W5100) +#define _WIZCHIP_ID_ "W5100\0" +/** + * @brief Define interface mode. + * @todo you should select interface mode as chip. Select one of @ref + * \_WIZCHIP_IO_MODE_SPI_ , @ref \_WIZCHIP_IO_MODE_BUS_DIR_ or @ref + * \_WIZCHIP_IO_MODE_BUS_INDIR_ + */ +// #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_DIR_ +// #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_INDIR_ +#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_ + +// A20150601 : Define the unit of IO DATA. +typedef uint8_t iodata_t; +// A20150401 : Indclude W5100.h file +#include "W5100/w5100.h" + +#elif (_WIZCHIP_ == W5100S) +#define _WIZCHIP_ID_ "W5100S\0" +/** + * @brief Define interface mode. + * @todo you should select interface mode as chip. Select one of @ref + * \_WIZCHIP_IO_MODE_SPI_ , @ref \_WIZCHIP_IO_MODE_BUS_DIR_ or @ref + * \_WIZCHIP_IO_MODE_BUS_INDIR_ + */ +// #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_INDIR_ +//#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_5500_ +#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_ + +// A20150601 : Define the unit of IO DATA. +typedef uint8_t iodata_t; +// A20150401 : Indclude W5100.h file +#include "W5100S/w5100s.h" +#elif (_WIZCHIP_ == W5200) +#define _WIZCHIP_ID_ "W5200\0" +/** + * @brief Define interface mode. + * @todo you should select interface mode as chip. Select one of @ref + * \_WIZCHIP_IO_MODE_SPI_ or @ref \ _WIZCHIP_IO_MODE_BUS_INDIR_ + */ +#ifndef _WIZCHIP_IO_MODE_ +// #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_INDIR_ +#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_ +#endif +// A20150601 : Define the unit of IO DATA. +typedef uint8_t iodata_t; +#include "W5200/w5200.h" +#elif (_WIZCHIP_ == W5500) +#define _WIZCHIP_ID_ "W5500\0" + +/** + * @brief Define interface mode. \n + * @todo Should select interface mode as chip. + * - @ref \_WIZCHIP_IO_MODE_SPI_ \n + * -@ref \_WIZCHIP_IO_MODE_SPI_VDM_ : Valid only in @ref \_WIZCHIP_ == + * W5500 \n + * -@ref \_WIZCHIP_IO_MODE_SPI_FDM_ : Valid only in @ref \_WIZCHIP_ == + * W5500 \n + * - @ref \_WIZCHIP_IO_MODE_BUS_ \n + * - @ref \_WIZCHIP_IO_MODE_BUS_DIR_ \n + * - @ref \_WIZCHIP_IO_MODE_BUS_INDIR_ \n + * - Others will be defined in future. \n\n + * ex> #define \_WIZCHIP_IO_MODE_ \_WIZCHIP_IO_MODE_SPI_VDM_ + * + * + */ +#ifndef _WIZCHIP_IO_MODE_ +//#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_FDM_ +#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_VDM_ +#endif +// A20150601 : Define the unit of IO DATA. +typedef uint8_t iodata_t; +#include "w5500.h" +#elif (_WIZCHIP_ == W5300) +#define _WIZCHIP_ID_ "W5300\0" +/** + * @brief Define interface mode. + * @todo you should select interface mode as chip. Select one of @ref + * \_WIZCHIP_IO_MODE_SPI_ , @ref \_WIZCHIP_IO_MODE_BUS_DIR_ or @ref + * \_WIZCHIP_IO_MODE_BUS_INDIR_ + */ +#ifndef _WIZCHIP_IO_MODE_ +#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_DIR_ +// #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_INDIR_ +#endif + +// A20150601 : Define the unit and bus width of IO DATA. +/** + * @brief Select the data width 8 or 16 bits. + * @todo you should select the bus width. Select one of 8 or 16. + */ +#ifndef _WIZCHIP_IO_BUS_WIDTH_ +#define _WIZCHIP_IO_BUS_WIDTH_ 16 // 8 +#endif +#if _WIZCHIP_IO_BUS_WIDTH_ == 8 +typedef uint8_t iodata_t; +#elif _WIZCHIP_IO_BUS_WIDTH_ == 16 +typedef uint16_t iodata_t; +#else +#error "Unknown _WIZCHIP_IO_BUS_WIDTH_. It should be 8 or 16." +#endif +// +#include "W5300/w5300.h" +#else +#error \ + "Unknown defined _WIZCHIP_. You should define one of 5100, 5200, and 5500 !!!" +#endif + +#ifndef _WIZCHIP_IO_MODE_ +#error "Undefined _WIZCHIP_IO_MODE_. You should define it !!!" +#endif + +/** + * @brief Define I/O base address when BUS IF mode. + * @todo Should re-define it to fit your system when BUS IF Mode (@ref + * \_WIZCHIP_IO_MODE_BUS_, + * @ref \_WIZCHIP_IO_MODE_BUS_DIR_, @ref \_WIZCHIP_IO_MODE_BUS_INDIR_). + * \n\n ex> #define \_WIZCHIP_IO_BASE_ 0x00008000 + */ +#if _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_BUS_ +// #define _WIZCHIP_IO_BASE_ 0x60000000 +//// for 5100S IND +#define _WIZCHIP_IO_BASE_ 0x68000000 // for W5300 +#elif _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_SPI_ +#define _WIZCHIP_IO_BASE_ 0x00000000 // for 5100S SPI +#endif + +#ifndef _WIZCHIP_IO_BASE_ +#define _WIZCHIP_IO_BASE_ 0x00000000 // 0x8000 +#endif + +// M20150401 : Typing Error +//#if _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_BUS +#if _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_BUS_ +#ifndef _WIZCHIP_IO_BASE_ +#error "You should be define _WIZCHIP_IO_BASE to fit your system memory map." +#endif +#endif + +#if _WIZCHIP_ >= W5200 +#define _WIZCHIP_SOCK_NUM_ 8 ///< The count of independant socket of @b WIZCHIP +#else +#define _WIZCHIP_SOCK_NUM_ 4 ///< The count of independant socket of @b WIZCHIP +#endif + +/******************************************************** + * WIZCHIP BASIC IF functions for SPI, SDIO, I2C , ETC. + *********************************************************/ +/** + * @ingroup DATA_TYPE + * @brief The set of callback functions for W5500:@ref WIZCHIP_IO_Functions + * W5200:@ref WIZCHIP_IO_Functions_W5200 + */ +typedef struct __WIZCHIP { + uint16_t if_mode; ///< host interface mode + uint8_t id[8]; ///< @b WIZCHIP ID such as @b 5100, @b 5100S, @b 5200, @b + ///< 5500, and so on. + /** + * The set of critical section callback func. + */ + struct _CRIS { + void (*_enter)(void); ///< crtical section enter + void (*_exit)(void); ///< critial section exit + } CRIS; + /** + * The set of @ref \_WIZCHIP_ select control callback func. + */ + struct _CS { + void (*_select)(void); ///< @ref \_WIZCHIP_ selected + void (*_deselect)(void); ///< @ref \_WIZCHIP_ deselected + } CS; + /** + * The set of interface IO callback func. + */ + union _IF { + /** + * For BUS interface IO + */ + // M20156501 : Modify the function name for integrating with W5300 + // struct + //{ + // uint8_t (*_read_byte) (uint32_t AddrSel); + // void (*_write_byte) (uint32_t AddrSel, uint8_t wb); + //}BUS; + struct { + iodata_t (*_read_data)(uint32_t AddrSel); + void (*_write_data)(uint32_t AddrSel, iodata_t wb); + } BUS; + + /** + * For SPI interface IO + */ + struct { + uint8_t (*_read_byte)(void); + void (*_write_byte)(uint8_t wb); + void (*_read_burst)(uint8_t *pBuf, uint16_t len); + void (*_write_burst)(uint8_t *pBuf, uint16_t len); + } SPI; + // To be added + // + } IF; +} _WIZCHIP; + +extern _WIZCHIP WIZCHIP; + +/** + * @ingroup DATA_TYPE + * WIZCHIP control type enumration used in @ref ctlwizchip(). + */ +typedef enum { + CW_RESET_WIZCHIP, ///< Resets WIZCHIP by softly + CW_INIT_WIZCHIP, ///< Initializes to WIZCHIP with SOCKET buffer size 2 or 1 + ///< dimension array typed uint8_t. + CW_GET_INTERRUPT, ///< Get Interrupt status of WIZCHIP + CW_CLR_INTERRUPT, ///< Clears interrupt + CW_SET_INTRMASK, ///< Masks interrupt + CW_GET_INTRMASK, ///< Get interrupt mask + CW_SET_INTRTIME, ///< Set interval time between the current and next + ///< interrupt. + CW_GET_INTRTIME, ///< Set interval time between the current and next + ///< interrupt. + CW_GET_ID, ///< Gets WIZCHIP name. + + // D20150601 : For no modification your application code + //#if _WIZCHIP_ == W5500 + CW_RESET_PHY, ///< Resets internal PHY. Valid Only W5500 + CW_SET_PHYCONF, ///< When PHY configured by internal register, PHY operation + ///< mode (Manual/Auto, 10/100, Half/Full). Valid Only W5000 + CW_GET_PHYCONF, ///< Get PHY operation mode in internal register. Valid Only + ///< W5500 + CW_GET_PHYSTATUS, ///< Get real PHY status on operating. Valid Only W5500 + CW_SET_PHYPOWMODE, ///< Set PHY power mode as normal and down when + ///< PHYSTATUS.OPMD == 1. Valid Only W5500 + //#endif + // D20150601 : For no modification your application code + //#if _WIZCHIP_ == W5200 || _WIZCHIP_ == W5500 + CW_GET_PHYPOWMODE, ///< Get PHY Power mode as down or normal, Valid Only + ///< W5100, W5200 + CW_GET_PHYLINK ///< Get PHY Link status, Valid Only W5100, W5200 + //#endif +} ctlwizchip_type; + +/** + * @ingroup DATA_TYPE + * Network control type enumration used in @ref ctlnetwork(). + */ +typedef enum { + CN_SET_NETINFO, ///< Set Network with @ref wiz_NetInfo + CN_GET_NETINFO, ///< Get Network with @ref wiz_NetInfo + CN_SET_NETMODE, ///< Set network mode as WOL, PPPoE, Ping Block, and Force + ///< ARP mode + CN_GET_NETMODE, ///< Get network mode as WOL, PPPoE, Ping Block, and Force + ///< ARP mode + CN_SET_TIMEOUT, ///< Set network timeout as retry count and time. + CN_GET_TIMEOUT, ///< Get network timeout as retry count and time. +} ctlnetwork_type; + +/** + * @ingroup DATA_TYPE + * Interrupt kind when CW_SET_INTRRUPT, CW_GET_INTERRUPT, CW_SET_INTRMASK + * and CW_GET_INTRMASK is used in @ref ctlnetwork(). + * It can be used with OR operation. + */ +typedef enum { +#if _WIZCHIP_ == W5500 + IK_WOL = + (1 << 4), ///< Wake On Lan by receiving the magic packet. Valid in W500. +#elif _WIZCHIP_ == W5300 + IK_FMTU = (1 << 4), ///< Received a ICMP message (Fragment MTU) +#endif + + IK_PPPOE_TERMINATED = (1 << 5), ///< PPPoE Disconnected + +#if _WIZCHIP_ != W5200 + IK_DEST_UNREACH = + (1 << 6), ///< Destination IP & Port Unreachable, No use in W5200 +#endif + + IK_IP_CONFLICT = (1 << 7), ///< IP conflict occurred + + IK_SOCK_0 = (1 << 8), ///< Socket 0 interrupt + IK_SOCK_1 = (1 << 9), ///< Socket 1 interrupt + IK_SOCK_2 = (1 << 10), ///< Socket 2 interrupt + IK_SOCK_3 = (1 << 11), ///< Socket 3 interrupt +#if _WIZCHIP_ > W5100S + IK_SOCK_4 = (1 << 12), ///< Socket 4 interrupt, No use in 5100 + IK_SOCK_5 = (1 << 13), ///< Socket 5 interrupt, No use in 5100 + IK_SOCK_6 = (1 << 14), ///< Socket 6 interrupt, No use in 5100 + IK_SOCK_7 = (1 << 15), ///< Socket 7 interrupt, No use in 5100 +#endif + +#if _WIZCHIP_ > W5100S + IK_SOCK_ALL = (0xFF << 8) ///< All Socket interrupt +#else + IK_SOCK_ALL = (0x0F << 8) ///< All Socket interrupt +#endif +} intr_kind; + +#define PHY_CONFBY_HW 0 ///< Configured PHY operation mode by HW pin +#define PHY_CONFBY_SW 1 ///< Configured PHY operation mode by SW register +#define PHY_MODE_MANUAL 0 ///< Configured PHY operation mode with user setting. +#define PHY_MODE_AUTONEGO \ + 1 ///< Configured PHY operation mode with auto-negotiation +#define PHY_SPEED_10 0 ///< Link Speed 10 +#define PHY_SPEED_100 1 ///< Link Speed 100 +#define PHY_DUPLEX_HALF 0 ///< Link Half-Duplex +#define PHY_DUPLEX_FULL 1 ///< Link Full-Duplex +#define PHY_LINK_OFF 0 ///< Link Off +#define PHY_LINK_ON 1 ///< Link On +#define PHY_POWER_NORM 0 ///< PHY power normal mode +#define PHY_POWER_DOWN 1 ///< PHY power down mode + +#if _WIZCHIP_ == W5100S || _WIZCHIP_ == W5500 +/** + * @ingroup DATA_TYPE + * It configures PHY configuration when CW_SET PHYCONF or CW_GET_PHYCONF in + * W5500, and it indicates the real PHY status configured by HW or SW in all + * WIZCHIP. \n Valid only in W5500. + */ +typedef struct wiz_PhyConf_t { + uint8_t by; ///< set by @ref PHY_CONFBY_HW or @ref PHY_CONFBY_SW + uint8_t mode; ///< set by @ref PHY_MODE_MANUAL or @ref PHY_MODE_AUTONEGO + uint8_t speed; ///< set by @ref PHY_SPEED_10 or @ref PHY_SPEED_100 + uint8_t duplex; ///< set by @ref PHY_DUPLEX_HALF @ref PHY_DUPLEX_FULL + // uint8_t power; ///< set by @ref PHY_POWER_NORM or @ref PHY_POWER_DOWN + // uint8_t link; ///< Valid only in CW_GET_PHYSTATUS. set by @ref + // PHY_LINK_ON or PHY_DUPLEX_OFF +} wiz_PhyConf; +#endif + +/** + * @ingroup DATA_TYPE + * It used in setting dhcp_mode of @ref wiz_NetInfo. + */ +typedef enum { + NETINFO_STATIC = 1, ///< Static IP configuration by manually. + NETINFO_DHCP ///< Dynamic IP configruation from a DHCP sever +} dhcp_mode; + +/** + * @ingroup DATA_TYPE + * Network Information for WIZCHIP + */ +typedef struct wiz_NetInfo_t { + uint8_t mac[6]; ///< Source Mac Address + uint8_t ip[4]; ///< Source IP Address + uint8_t sn[4]; ///< Subnet Mask + uint8_t gw[4]; ///< Gateway IP Address + uint8_t dns[4]; ///< DNS server IP Address + dhcp_mode dhcp; ///< 1 - Static, 2 - DHCP +} wiz_NetInfo; + +/** + * @ingroup DATA_TYPE + * Network mode + */ +typedef enum { +#if _WIZCHIP_ == W5500 + NM_FORCEARP = (1 << 1), ///< Force to APP send whenever udp data is sent. + ///< Valid only in W5500 +#endif + NM_WAKEONLAN = (1 << 5), ///< Wake On Lan + NM_PINGBLOCK = (1 << 4), ///< Block ping-request + NM_PPPOE = (1 << 3), ///< PPPoE mode +} netmode_type; + +/** + * @ingroup DATA_TYPE + * Used in CN_SET_TIMEOUT or CN_GET_TIMEOUT of @ref ctlwizchip() for timeout + * configruation. + */ +typedef struct wiz_NetTimeout_t { + uint8_t retry_cnt; ///< retry count + uint16_t time_100us; ///< time unit 100us +} wiz_NetTimeout; + +/** + *@brief Registers call back function for critical section of I/O functions such + *as \ref WIZCHIP_READ, @ref WIZCHIP_WRITE, @ref WIZCHIP_READ_BUF and @ref + *WIZCHIP_WRITE_BUF. + *@param cris_en : callback function for critical section enter. + *@param cris_ex : callback function for critical section exit. + *@todo Describe @ref WIZCHIP_CRITICAL_ENTER and @ref WIZCHIP_CRITICAL_EXIT + *marco or register your functions. + *@note If you do not describe or register, default functions(@ref + *wizchip_cris_enter & @ref wizchip_cris_exit) is called. + */ +void reg_wizchip_cris_cbfunc(void (*cris_en)(void), void (*cris_ex)(void)); + +/** + *@brief Registers call back function for WIZCHIP select & deselect. + *@param cs_sel : callback function for WIZCHIP select + *@param cs_desel : callback fucntion for WIZCHIP deselect + *@todo Describe @ref wizchip_cs_select and @ref wizchip_cs_deselect function or + *register your functions. + *@note If you do not describe or register, null function is called. + */ +void reg_wizchip_cs_cbfunc(void (*cs_sel)(void), void (*cs_desel)(void)); + +/** + *@brief Registers call back function for bus interface. + *@param bus_rb : callback function to read byte data using system bus + *@param bus_wb : callback function to write byte data using system bus + *@todo Describe @ref wizchip_bus_readbyte and @ref wizchip_bus_writebyte + *function or register your functions. + *@note If you do not describe or register, null function is called. + */ +// M20150601 : For integrating with W5300 +// void reg_wizchip_bus_cbfunc(uint8_t (*bus_rb)(uint32_t addr), void +// (*bus_wb)(uint32_t addr, uint8_t wb)); +void reg_wizchip_bus_cbfunc(iodata_t (*bus_rb)(uint32_t addr), + void (*bus_wb)(uint32_t addr, iodata_t wb)); + +/** + *@brief Registers call back function for SPI interface. + *@param spi_rb : callback function to read byte using SPI + *@param spi_wb : callback function to write byte using SPI + *@todo Describe \ref wizchip_spi_readbyte and \ref wizchip_spi_writebyte + *function or register your functions. + *@note If you do not describe or register, null function is called. + */ +void reg_wizchip_spi_cbfunc(uint8_t (*spi_rb)(void), + void (*spi_wb)(uint8_t wb)); + +/** + *@brief Registers call back function for SPI interface. + *@param spi_rb : callback function to burst read using SPI + *@param spi_wb : callback function to burst write using SPI + *@todo Describe \ref wizchip_spi_readbyte and \ref wizchip_spi_writebyte + *function or register your functions. + *@note If you do not describe or register, null function is called. + */ +void reg_wizchip_spiburst_cbfunc(void (*spi_rb)(uint8_t *pBuf, uint16_t len), + void (*spi_wb)(uint8_t *pBuf, uint16_t len)); + +/** + * @ingroup extra_functions + * @brief Controls to the WIZCHIP. + * @details Resets WIZCHIP & internal PHY, Configures PHY mode, Monitor + * PHY(Link,Speed,Half/Full/Auto), controls interrupt & mask and so on. + * @param cwtype : Decides to the control type + * @param arg : arg type is dependent on cwtype. + * @return 0 : Success \n + * -1 : Fail because of invalid \ref ctlwizchip_type or unsupported \ref + * ctlwizchip_type in WIZCHIP + */ +int8_t ctlwizchip(ctlwizchip_type cwtype, void *arg); + +/** + * @ingroup extra_functions + * @brief Controls to network. + * @details Controls to network environment, mode, timeout and so on. + * @param cntype : Input. Decides to the control type + * @param arg : Inout. arg type is dependent on cntype. + * @return -1 : Fail because of invalid \ref ctlnetwork_type or unsupported \ref + * ctlnetwork_type in WIZCHIP \n 0 : Success + */ +int8_t ctlnetwork(ctlnetwork_type cntype, void *arg); + +/* + * The following functions are implemented for internal use. + * but You can call these functions for code size reduction instead of + * ctlwizchip() and ctlnetwork(). + */ + +/** + * @ingroup extra_functions + * @brief Reset WIZCHIP by softly. + */ +void wizchip_sw_reset(void); + +/** + * @ingroup extra_functions + * @brief Initializes WIZCHIP with socket buffer size + * @param txsize Socket tx buffer sizes. If null, initialized the default size + * 2KB. + * @param rxsize Socket rx buffer sizes. If null, initialized the default size + * 2KB. + * @return 0 : succcess \n + * -1 : fail. Invalid buffer size + */ +int8_t wizchip_init(uint8_t *txsize, uint8_t *rxsize); + +/** + * @ingroup extra_functions + * @brief Clear Interrupt of WIZCHIP. + * @param intr : @ref intr_kind value operated OR. It can type-cast to uint16_t. + */ +void wizchip_clrinterrupt(intr_kind intr); + +/** + * @ingroup extra_functions + * @brief Get Interrupt of WIZCHIP. + * @return @ref intr_kind value operated OR. It can type-cast to uint16_t. + */ +intr_kind wizchip_getinterrupt(void); + +/** + * @ingroup extra_functions + * @brief Mask or Unmask Interrupt of WIZCHIP. + * @param intr : @ref intr_kind value operated OR. It can type-cast to uint16_t. + */ +void wizchip_setinterruptmask(intr_kind intr); + +/** + * @ingroup extra_functions + * @brief Get Interrupt mask of WIZCHIP. + * @return : The operated OR vaule of @ref intr_kind. It can type-cast to + * uint16_t. + */ +intr_kind wizchip_getinterruptmask(void); + +// todo +#if _WIZCHIP_ > W5100 +int8_t wizphy_getphylink( + void); ///< get the link status of phy in WIZCHIP. No use in W5100 +int8_t wizphy_getphypmode( + void); ///< get the power mode of PHY in WIZCHIP. No use in W5100 +#endif + +#if _WIZCHIP_ == W5100S || _WIZCHIP_ == W5500 +void wizphy_reset(void); ///< Reset phy. Vailid only in W5500 + /** + * @ingroup extra_functions + * @brief Set the phy information for WIZCHIP without power mode + * @param phyconf : @ref wiz_PhyConf + */ +void wizphy_setphyconf(wiz_PhyConf *phyconf); +/** + * @ingroup extra_functions + * @brief Get phy configuration information. + * @param phyconf : @ref wiz_PhyConf + */ +void wizphy_getphyconf(wiz_PhyConf *phyconf); +/** + * @ingroup extra_functions + * @brief Get phy status. + * @param phyconf : @ref wiz_PhyConf + */ +void wizphy_getphystat(wiz_PhyConf *phyconf); +/** + * @ingroup extra_functions + * @brief set the power mode of phy inside WIZCHIP. Refer to @ref PHYCFGR in + * W5500, @ref PHYSTATUS in W5200 + * @param pmode Settig value of power down mode. + */ +int8_t wizphy_setphypmode(uint8_t pmode); +#endif + +/** + * @ingroup extra_functions + * @brief Set the network information for WIZCHIP + * @param pnetinfo : @ref wizNetInfo + */ +void wizchip_setnetinfo(wiz_NetInfo *pnetinfo); + +/** + * @ingroup extra_functions + * @brief Get the network information for WIZCHIP + * @param pnetinfo : @ref wizNetInfo + */ +void wizchip_getnetinfo(wiz_NetInfo *pnetinfo); + +/** + * @ingroup extra_functions + * @brief Set the network mode such WOL, PPPoE, Ping Block, and etc. + * @param pnetinfo Value of network mode. Refer to @ref netmode_type. + */ +int8_t wizchip_setnetmode(netmode_type netmode); + +/** + * @ingroup extra_functions + * @brief Get the network mode such WOL, PPPoE, Ping Block, and etc. + * @return Value of network mode. Refer to @ref netmode_type. + */ +netmode_type wizchip_getnetmode(void); + +/** + * @ingroup extra_functions + * @brief Set retry time value(@ref _RTR_) and retry count(@ref _RCR_). + * @details @ref _RTR_ configures the retransmission timeout period and @ref + * _RCR_ configures the number of time of retransmission. + * @param nettime @ref _RTR_ value and @ref _RCR_ value. Refer to @ref + * wiz_NetTimeout. + */ +void wizchip_settimeout(wiz_NetTimeout *nettime); + +/** + * @ingroup extra_functions + * @brief Get retry time value(@ref _RTR_) and retry count(@ref _RCR_). + * @details @ref _RTR_ configures the retransmission timeout period and @ref + * _RCR_ configures the number of time of retransmission. + * @param nettime @ref _RTR_ value and @ref _RCR_ value. Refer to @ref + * wiz_NetTimeout. + */ +void wizchip_gettimeout(wiz_NetTimeout *nettime); +#ifdef __cplusplus +} +#endif + +#endif // _WIZCHIP_CONF_H_ \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/spi/Kconfig b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/spi/Kconfig new file mode 100644 index 000000000..9eb26b6a3 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/spi/Kconfig @@ -0,0 +1,66 @@ +config BSP_USING_SPI1 +bool "Using spi1 " +default y + + +if BSP_USING_SPI1 + config SPI_BUS_NAME_1 + string "spi bus 1 name" + default "spi1" + config SPI_1_DRV_NAME + string "spi bus 1 driver name" + default "spi1_drv" + config BSP_SPI1_CLK_PIN + int "spi1 clk pin number" + default 9 + config BSP_SPI1_D0_PIN + int "spi1 d0 pin number" + default 11 + config BSP_SPI1_D1_PIN + int "spi1 d1 pin number" + default 10 + menuconfig BSP_SPI1_USING_SS0 + bool "SPI1 Enable SS0" + default y + if BSP_SPI1_USING_SS0 + config SPI_1_DEVICE_NAME_0 + string "spi bus 1 device 0 name" + default "spi1_dev0" + config BSP_SPI1_SS0_PIN + int "spi1 ss0 pin number" + default 12 + menuconfig BSP_SPI1_USING_SS1 + bool "SPI1 Enable SS1" + default n + endif + if BSP_SPI1_USING_SS1 + config SPI_1_DEVICE_NAME_1 + string "spi bus 1 device 1 name" + default "spi1_dev1" + config BSP_SPI1_SS1_PIN + int "spi1 ss1 pin number" + default 13 + endif + menuconfig BSP_SPI1_USING_SS2 + bool "SPI1 Enable SS2" + default n + if BSP_SPI1_USING_SS2 + config SPI_1_DEVICE_NAME_2 + string "spi bus 1 device 2 name" + default "spi1_dev2" + config BSP_SPI1_SS2_PIN + int "spi1 ss2 pin number" + default 26 + endif + menuconfig BSP_SPI1_USING_SS3 + bool "SPI1 Enable SS3" + default n + if BSP_SPI1_USING_SS3 + config SPI_1_DEVICE_NAME_3 + string "spi bus 1 device 3 name" + default "spi1_dev3" + config BSP_SPI1_SS3_PIN + int "spi1 ss3 pin number" + default 27 + endif +endif diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/spi/Makefile b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/spi/Makefile new file mode 100644 index 000000000..945c415a4 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/spi/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := connect_spi.c hardware_spi.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/spi/connect_spi.c b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/spi/connect_spi.c new file mode 100644 index 000000000..4191b4e6b --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/spi/connect_spi.c @@ -0,0 +1,517 @@ +/* + * Copyright (c) 2020 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2019-03-18 ZYH first version + */ + +/** + * @file connect_spi.c + * @brief support aiit-riscv64-board spi function and register to bus framework + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2021-04-25 + */ + +/************************************************* +File name: connect_spi.c +Description: support aiit-riscv64-board spi configure and spi bus register +function Others: take RT-Thread v4.0.2/bsp/k210/driver/drv_spi.c for references + https://github.com/RT-Thread/rt-thread/tree/v4.0.2 +History: +1. Date: 2021-04-25 +Author: AIIT XUOS Lab +Modification: +1. support aiit-riscv64-board spi configure, write and read +2. support aiit-riscv64-board spi bus device and driver register +*************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BSP_SPI1_USING_SS0 +#define SPI_DEVICE_SLAVE_ID_0 0 +#endif + +#ifdef BSP_SPI1_USING_SS1 +#define SPI_DEVICE_SLAVE_ID_1 1 +#endif + +#ifdef BSP_SPI1_USING_SS2 +#define SPI_DEVICE_SLAVE_ID_2 2 +#endif + +#ifdef BSP_SPI1_USING_SS3 +#define SPI_DEVICE_SLAVE_ID_3 3 +#endif + +static volatile spi_t *const spi_instance[4] = { + (volatile spi_t *)SPI0_BASE_ADDR, (volatile spi_t *)SPI1_BASE_ADDR, + (volatile spi_t *)SPI_SLAVE_BASE_ADDR, (volatile spi_t *)SPI3_BASE_ADDR}; + +void __spi_set_tmod(uint8_t spi_num, uint32_t tmod) { + CHECK(spi_num < SPI_DEVICE_MAX); + volatile spi_t *spi_handle = spi[spi_num]; + uint8_t tmod_offset = 0; + switch (spi_num) { + case 0: + case 1: + case 2: + tmod_offset = 8; + break; + case 3: + default: + tmod_offset = 10; + break; + } + set_bit(&spi_handle->ctrlr0, 3 << tmod_offset, tmod << tmod_offset); +} + +/*Init the spi sdk intetface */ +static uint32 SpiSdkInit(struct SpiDriver *spi_drv) { + NULL_PARAM_CHECK(spi_drv); + uint8 cs_gpio_pin, cs_select_id; + uint32 max_frequency; + + SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_drv->driver.private_data); + + cs_gpio_pin = dev_param->spi_slave_param->spi_cs_gpio_pin; + cs_select_id = dev_param->spi_slave_param->spi_cs_select_id; + + gpiohs_set_drive_mode(cs_select_id, + GPIO_DM_OUTPUT); // Set the cs pin as output + gpiohs_set_pin(cs_gpio_pin, GPIO_PV_HIGH); // set the cs gpio high + + spi_init(dev_param->spi_dma_param->spi_master_id, + dev_param->spi_master_param->spi_work_mode & SPI_MODE_3, + dev_param->spi_master_param->spi_frame_format, + dev_param->spi_master_param->spi_data_bit_width, + dev_param->spi_master_param->spi_data_endian); + + max_frequency = + (dev_param->spi_master_param->spi_maxfrequency < SPI_MAX_CLOCK) + ? dev_param->spi_master_param->spi_maxfrequency + : SPI_MAX_CLOCK; + + uint32 real_freq = + spi_set_clk_rate(dev_param->spi_dma_param->spi_master_id, max_frequency); + + return EOK; +} + +static uint32 SpiSdkCfg(struct SpiDriver *spi_drv, + struct SpiMasterParam *spi_param) { + NULL_PARAM_CHECK(spi_drv); + NULL_PARAM_CHECK(spi_param); + + SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_drv->driver.private_data); + + dev_param->spi_master_param = spi_param; + dev_param->spi_master_param->spi_work_mode = + dev_param->spi_master_param->spi_work_mode & SPI_MODE_MASK; + dev_param->spi_master_param->spi_frame_format = SPI_FF_STANDARD; + + return EOK; +} + +/*Configure the spi device param, make sure struct + * (configure_info->private_data) = (SpiMasterParam)*/ +static uint32 SpiDrvConfigure(void *drv, + struct BusConfigureInfo *configure_info) { + NULL_PARAM_CHECK(drv); + NULL_PARAM_CHECK(configure_info); + + x_err_t ret = EOK; + struct SpiDriver *spi_drv = (struct SpiDriver *)drv; + struct SpiMasterParam *spi_param; + + switch (configure_info->configure_cmd) { + case OPE_INT: + ret = SpiSdkInit(spi_drv); + break; + case OPE_CFG: + spi_param = (struct SpiMasterParam *)configure_info->private_data; + ret = SpiSdkCfg(spi_drv, spi_param); + break; + default: + break; + } + + return ret; +} + +static uint32 SpiWriteData(struct SpiHardwareDevice *spi_dev, + struct SpiDataStandard *spi_datacfg) { + DEBUG_PRINT + SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_dev->haldev.private_data); + + uint8 device_id = dev_param->spi_slave_param->spi_slave_id; + uint8 device_master_id = dev_param->spi_dma_param->spi_master_id; + uint8 cs_gpio_pin = dev_param->spi_slave_param->spi_cs_gpio_pin; + + while (NONE != spi_datacfg) { + uint32_t *tx_buff = NONE; + int i; + x_ubase dummy = 0xFFFFFFFFU; + + __spi_set_tmod(device_master_id, SPI_TMOD_TRANS_RECV); + + if (spi_datacfg->spi_chip_select) { + DEBUG_PRINT + gpiohs_set_pin(cs_gpio_pin, GPIO_PV_LOW); + } + + if (spi_datacfg->length) { + DEBUG_PRINT + spi_instance[device_master_id]->dmacr = 0x3; + spi_instance[device_master_id]->ssienr = 0x01; + + sysctl_dma_select(dev_param->spi_dma_param->spi_dmac_txchannel, + SYSCTL_DMA_SELECT_SSI0_TX_REQ + device_master_id * 2); + sysctl_dma_select(dev_param->spi_dma_param->spi_dmac_rxchannel, + SYSCTL_DMA_SELECT_SSI0_RX_REQ + device_master_id * 2); + + dmac_set_single_mode(dev_param->spi_dma_param->spi_dmac_rxchannel, + (void *)(&spi_instance[device_master_id]->dr[0]), + &dummy, DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, + spi_datacfg->length); + + if (!spi_datacfg->tx_buff) { + dmac_set_single_mode( + dev_param->spi_dma_param->spi_dmac_txchannel, &dummy, + (void *)(&spi_instance[device_master_id]->dr[0]), + DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, DMAC_MSIZE_4, + DMAC_TRANS_WIDTH_32, spi_datacfg->length); + } else { + tx_buff = x_malloc(spi_datacfg->length * 4); + if (!tx_buff) { + goto transfer_done; + } + for (i = 0; i < spi_datacfg->length; i++) { + tx_buff[i] = ((uint8_t *)spi_datacfg->tx_buff)[i]; + } + dmac_set_single_mode( + dev_param->spi_dma_param->spi_dmac_txchannel, tx_buff, + (void *)(&spi_instance[device_master_id]->dr[0]), + DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, DMAC_MSIZE_4, + DMAC_TRANS_WIDTH_32, spi_datacfg->length); + } + + spi_instance[device_master_id]->ser = + 1U << dev_param->spi_slave_param->spi_cs_select_id; + dmac_wait_done(dev_param->spi_dma_param->spi_dmac_txchannel); + dmac_wait_done(dev_param->spi_dma_param->spi_dmac_rxchannel); + spi_instance[device_master_id]->ser = 0x00; + spi_instance[device_master_id]->ssienr = 0x00; + + transfer_done: + if (tx_buff) { + x_free(tx_buff); + } + } + + if (spi_datacfg->spi_cs_release) { + DEBUG_PRINT + gpiohs_set_pin(cs_gpio_pin, GPIO_PV_HIGH); + } + + spi_datacfg = spi_datacfg->next; + } + + DEBUG_PRINT + return EOK; +} + +static uint32 SpiReadData(struct SpiHardwareDevice *spi_dev, + struct SpiDataStandard *spi_datacfg) { + DEBUG_PRINT + SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_dev->haldev.private_data); + + uint32 spi_read_length = 0; + ; + uint8 device_id = dev_param->spi_slave_param->spi_slave_id; + uint8 device_master_id = dev_param->spi_dma_param->spi_master_id; + uint8 cs_gpio_pin = dev_param->spi_slave_param->spi_cs_gpio_pin; + + DEBUG_PRINT + while (NONE != spi_datacfg) { + uint32_t *rx_buff = NONE; + int i; + x_ubase dummy = 0xFFFFFFFFU; + + __spi_set_tmod(device_master_id, SPI_TMOD_TRANS_RECV); + + if (spi_datacfg->spi_chip_select) { + DEBUG_PRINT + gpiohs_set_pin(cs_gpio_pin, GPIO_PV_LOW); + } + + if (spi_datacfg->length) { + spi_instance[device_master_id]->dmacr = 0x3; + spi_instance[device_master_id]->ssienr = 0x01; + + sysctl_dma_select(dev_param->spi_dma_param->spi_dmac_txchannel, + SYSCTL_DMA_SELECT_SSI0_TX_REQ + device_master_id * 2); + sysctl_dma_select(dev_param->spi_dma_param->spi_dmac_rxchannel, + SYSCTL_DMA_SELECT_SSI0_RX_REQ + device_master_id * 2); + + dmac_set_single_mode(dev_param->spi_dma_param->spi_dmac_txchannel, &dummy, + (void *)(&spi_instance[device_master_id]->dr[0]), + DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, DMAC_MSIZE_4, + DMAC_TRANS_WIDTH_32, spi_datacfg->length); + + if (!spi_datacfg->rx_buff) { + dmac_set_single_mode(dev_param->spi_dma_param->spi_dmac_rxchannel, + (void *)(&spi_instance[device_master_id]->dr[0]), + &dummy, DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, + spi_datacfg->length); + } else { + rx_buff = x_calloc(spi_datacfg->length * 4, 1); + if (!rx_buff) { + goto transfer_done; + } + + dmac_set_single_mode(dev_param->spi_dma_param->spi_dmac_rxchannel, + (void *)(&spi_instance[device_master_id]->dr[0]), + rx_buff, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, + spi_datacfg->length); + } + + spi_instance[device_master_id]->ser = + 1U << dev_param->spi_slave_param->spi_cs_select_id; + dmac_wait_done(dev_param->spi_dma_param->spi_dmac_txchannel); + dmac_wait_done(dev_param->spi_dma_param->spi_dmac_rxchannel); + spi_instance[device_master_id]->ser = 0x00; + spi_instance[device_master_id]->ssienr = 0x00; + + DEBUG_PRINT + if (spi_datacfg->rx_buff) { + for (i = 0; i < spi_datacfg->length; i++) { + ((uint8_t *)spi_datacfg->rx_buff)[i] = (uint8_t)rx_buff[i]; + } + } + + transfer_done: + if (rx_buff) { + x_free(rx_buff); + } + } + + if (spi_datacfg->spi_cs_release) { + DEBUG_PRINT + gpiohs_set_pin(cs_gpio_pin, GPIO_PV_HIGH); + } + + spi_read_length += spi_datacfg->length; + spi_datacfg = spi_datacfg->next; + } + + DEBUG_PRINT + return spi_read_length; +} + +/*manage the spi device operations*/ +static const struct SpiDevDone spi_dev_done = { + .dev_open = NONE, + .dev_close = NONE, + .dev_write = SpiWriteData, + .dev_read = SpiReadData, +}; + +static int BoardSpiBusInit(struct SpiBus *spi_bus, + struct SpiDriver *spi_driver) { + x_err_t ret = EOK; + + /*Init the spi bus */ + ret = SpiBusInit(spi_bus, SPI_BUS_NAME_1); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiBusInit error %d\n", ret); + return ERROR; + } + + /*Init the spi driver*/ + ret = SpiDriverInit(spi_driver, SPI_1_DRV_NAME); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDriverInit error %d\n", ret); + return ERROR; + } + + /*Attach the spi driver to the spi bus*/ + ret = SpiDriverAttachToBus(SPI_1_DRV_NAME, SPI_BUS_NAME_1); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDriverAttachToBus error %d\n", ret); + return ERROR; + } + + return ret; +} + +/*Attach the spi device to the spi bus*/ +static int BoardSpiDevBend(struct SpiDmaParam *spi_initparam) { + x_err_t ret = EOK; + +#ifdef BSP_SPI1_USING_SS0 + static struct SpiHardwareDevice spi_device0; + memset(&spi_device0, 0, sizeof(struct SpiHardwareDevice)); + + static struct SpiSlaveParam spi_slaveparam0; + memset(&spi_slaveparam0, 0, sizeof(struct SpiSlaveParam)); + + spi_slaveparam0.spi_slave_id = SPI_DEVICE_SLAVE_ID_0; + spi_slaveparam0.spi_cs_gpio_pin = SPI1_CS0_PIN; + spi_slaveparam0.spi_cs_select_id = SPI_CHIP_SELECT_0; + + spi_device0.spi_param.spi_dma_param = spi_initparam; + spi_device0.spi_param.spi_slave_param = &spi_slaveparam0; + + spi_device0.spi_dev_done = &(spi_dev_done); + + ret = SpiDeviceRegister(&spi_device0, (void *)(&spi_device0.spi_param), + SPI_1_DEVICE_NAME_0); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDeviceInit device %s error %d\n", + SPI_1_DEVICE_NAME_0, ret); + return ERROR; + } + + ret = SpiDeviceAttachToBus(SPI_1_DEVICE_NAME_0, SPI_BUS_NAME_1); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDeviceAttachToBus device %s error %d\n", + SPI_1_DEVICE_NAME_0, ret); + return ERROR; + } +#endif + +#ifdef BSP_SPI1_USING_SS1 + static struct SpiHardwareDevice spi_device1; + memset(&spi_device1, 0, sizeof(struct SpiHardwareDevice)); + + static struct SpiSlaveParam spi_slaveparam1; + memset(&spi_slaveparam1, 0, sizeof(struct SpiSlaveParam)); + + spi_slaveparam1.spi_slave_id = SPI_DEVICE_SLAVE_ID_1; + spi_slaveparam1.spi_cs_gpio_pin = SPI1_CS1_PIN; + spi_slaveparam1.spi_cs_select_id = SPI_CHIP_SELECT_1; + + spi_device1.spi_param.spi_dma_param = spi_initparam; + spi_device1.spi_param.spi_slave_param = &spi_slaveparam1; + + spi_device1.spi_dev_done = &(spi_dev_done); + + ret = SpiDeviceRegister(&spi_device1, (void *)(&spi_device1.spi_param), + SPI_1_DEVICE_NAME_1); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDeviceInit device %s error %d\n", + SPI_1_DEVICE_NAME_1, ret); + return ERROR; + } + + ret = SpiDeviceAttachToBus(SPI_1_DEVICE_NAME_1, SPI_BUS_NAME_1); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDeviceAttachToBus device %s error %d\n", + SPI_1_DEVICE_NAME_1, ret); + return ERROR; + } +#endif + +#ifdef BSP_SPI1_USING_SS2 + static struct SpiHardwareDevice spi_device2; + memset(&spi_device2, 0, sizeof(struct SpiHardwareDevice)); + + spi_initparam->spi_slave_id[SPI_DEVICE_SLAVE_ID_2] = SPI_DEVICE_SLAVE_ID_2; + spi_initparam->spi_cs_gpio_pin[SPI_DEVICE_SLAVE_ID_2] = SPI1_CS2_PIN; + spi_initparam->spi_cs_select_id[SPI_DEVICE_SLAVE_ID_2] = SPI_CHIP_SELECT_2; + + spi_device2.spi_dev_done = &(spi_dev_done); + + ret = SpiDeviceRegister(&spi_device2, (void *)(&spi_device2.spi_param), + SPI_1_DEVICE_NAME_2); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDeviceInit device %s error %d\n", + SPI_1_DEVICE_NAME_2, ret); + return ERROR; + } + + ret = SpiDeviceAttachToBus(SPI_1_DEVICE_NAME_2, SPI_BUS_NAME_1); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDeviceAttachToBus device %s error %d\n", + SPI_1_DEVICE_NAME_2, ret); + return ERROR; + } +#endif + +#ifdef BSP_SPI1_USING_SS3 + static struct SpiHardwareDevice spi_device3; + memset(&spi_device3, 0, sizeof(struct SpiHardwareDevice)); + + spi_initparam->spi_slave_id[SPI_DEVICE_SLAVE_ID_3] = SPI_DEVICE_SLAVE_ID_3; + spi_initparam->spi_cs_gpio_pin[SPI_DEVICE_SLAVE_ID_3] = SPI1_CS3_PIN; + spi_initparam->spi_cs_select_id[SPI_DEVICE_SLAVE_ID_3] = SPI_CHIP_SELECT_3; + + spi_device3.spi_dev_done = &(spi_dev_done); + + ret = SpiDeviceRegister(&spi_device3, (void *)(&spi_device3.spi_param), + SPI_1_DEVICE_NAME_3); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDeviceInit device %s error %d\n", + SPI_1_DEVICE_NAME_3, ret); + return ERROR; + } + + ret = SpiDeviceAttachToBus(SPI_1_DEVICE_NAME_3, SPI_BUS_NAME_1); + if (EOK != ret) { + KPrintf("Board_Spi_init SpiDeviceAttachToBus device %s error %d\n", + SPI_1_DEVICE_NAME_3, ret); + return ERROR; + } +#endif + return ret; +} + +/*RISC-V 64 BOARD SPI INIT*/ +int HwSpiInit(void) { + x_err_t ret = EOK; + static struct SpiDmaParam spi_initparam; + memset(&spi_initparam, 0, sizeof(struct SpiDmaParam)); + +#ifdef BSP_USING_SPI1 + + static struct SpiBus spi_bus; + memset(&spi_bus, 0, sizeof(struct SpiBus)); + + static struct SpiDriver spi_driver; + memset(&spi_driver, 0, sizeof(struct SpiDriver)); + + spi_initparam.spi_master_id = SPI_DEVICE_1; + spi_initparam.spi_dmac_txchannel = DMAC_CHANNEL1; + spi_initparam.spi_dmac_rxchannel = DMAC_CHANNEL2; + + spi_driver.configure = &(SpiDrvConfigure); + + ret = BoardSpiBusInit(&spi_bus, &spi_driver); + if (EOK != ret) { + KPrintf("Board_Spi_Init error ret %u\n", ret); + return ERROR; + } + + ret = BoardSpiDevBend(&spi_initparam); + if (EOK != ret) { + KPrintf("Board_Spi_Init error ret %u\n", ret); + return ERROR; + } +#endif + + return ret; +} diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/spi/hardware_spi.c b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/spi/hardware_spi.c new file mode 100644 index 000000000..2947682d3 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-riscv64/third_party_driver/spi/hardware_spi.c @@ -0,0 +1,1523 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** +* @file hardware_spi.c +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +volatile spi_t *const spi[4] = +{ + (volatile spi_t *)SPI0_BASE_ADDR, + (volatile spi_t *)SPI1_BASE_ADDR, + (volatile spi_t *)SPI_SLAVE_BASE_ADDR, + (volatile spi_t *)SPI3_BASE_ADDR +}; + +typedef struct _spi_dma_context +{ + uint8_t *buffer; + size_t BufLen; + uint32_t *MallocBuffer; + spi_transfer_mode_t IntMode; + dmac_channel_number_t dmac_channel; + spi_device_num_t spi_num; + plic_instance_t spi_int_instance; +} spi_dma_context_t; + +spi_dma_context_t spi_dma_context[4]; + +typedef struct _spi_instance_t +{ + spi_device_num_t spi_num; + spi_transfer_mode_t TransferMode; + dmac_channel_number_t dmac_channel; + plic_instance_t spi_int_instance; + spinlock_t lock; +} spi_instance_t; + +static spi_instance_t g_spi_instance[4]; + +static spi_slave_instance_t g_instance; + +static spi_frame_format_t spi_get_frame_format(spi_device_num_t spi_num) +{ + uint8_t frf_offset; + switch(spi_num) + { + case 0: + case 1: + frf_offset = 21; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + frf_offset = 22; + break; + } + volatile spi_t *spi_adapter = spi[spi_num]; + return ((spi_adapter->ctrlr0 >> frf_offset) & 0x3); +} + +static spi_transfer_width_t spi_get_frame_size(size_t data_bit_length) +{ + if (data_bit_length < 8) + return SPI_TRANS_CHAR; + else if (data_bit_length < 16) + return SPI_TRANS_SHORT; + return SPI_TRANS_INT; +} + +static int spi_dma_irq(void *ctx) +{ + spi_instance_t *v_instance = (spi_instance_t *)ctx; + volatile spi_t *spi_handle = spi[v_instance->spi_num]; + dmac_irq_unregister(v_instance->dmac_channel); + while ((spi_handle->sr & 0x05) != 0x04); + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + spinlock_unlock(&v_instance->lock); + if(v_instance->spi_int_instance.callback) + { + v_instance->spi_int_instance.callback(v_instance->spi_int_instance.ctx); + } + return 0; +} + +static int spi_clk_init(uint8_t spi_num) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + if(spi_num == 3) + sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_SPI3, 1); + sysctl_clock_enable(SYSCTL_CLOCK_SPI0 + spi_num); + sysctl_clock_set_threshold(SYSCTL_THRESHOLD_SPI0 + spi_num, 0); + return 0; +} + +static void spi_set_tmod(uint8_t spi_num, uint32_t tmod) +{ + configASSERT(spi_num < SPI_DEVICE_MAX); + volatile spi_t *spi_handle = spi[spi_num]; + uint8_t tmod_offset = 0; + switch(spi_num) + { + case 0: + case 1: + case 2: + tmod_offset = 8; + break; + case 3: + default: + tmod_offset = 10; + break; + } + set_bit(&spi_handle->ctrlr0, 3 << tmod_offset, tmod << tmod_offset); +} + +void spi_init(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format, + size_t data_bit_length, uint32_t endian) +{ + configASSERT(data_bit_length >= 4 && data_bit_length <= 32); + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + spi_clk_init(spi_num); + + uint8_t dfs_offset, frf_offset, work_mode_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + frf_offset = 21; + work_mode_offset = 6; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + frf_offset = 22; + work_mode_offset = 8; + break; + } + + switch (frame_format) + { + case SPI_FF_DUAL: + configASSERT(data_bit_length % 2 == 0); + break; + case SPI_FF_QUAD: + configASSERT(data_bit_length % 4 == 0); + break; + case SPI_FF_OCTAL: + configASSERT(data_bit_length % 8 == 0); + break; + default: + break; + } + volatile spi_t *spi_adapter = spi[spi_num]; + if(spi_adapter->baudr == 0) + spi_adapter->baudr = 0x14; + spi_adapter->imr = 0x00; + spi_adapter->dmacr = 0x00; + spi_adapter->dmatdlr = 0x10; + spi_adapter->dmardlr = 0x00; + spi_adapter->ser = 0x00; + spi_adapter->ssienr = 0x00; + spi_adapter->ctrlr0 = (work_mode << work_mode_offset) | (frame_format << frf_offset) | ((data_bit_length - 1) << dfs_offset); + spi_adapter->spi_ctrlr0 = 0; + spi_adapter->endian = endian; +} + +void spi_init_non_standard(spi_device_num_t spi_num, uint32_t instruction_length, uint32_t address_length, + uint32_t wait_cycles, spi_instruction_address_trans_mode_t instruction_address_trans_mode) +{ + configASSERT(wait_cycles < (1 << 5)); + configASSERT(instruction_address_trans_mode < 3); + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + volatile spi_t *spi_handle = spi[spi_num]; + uint32_t inst_l = 0; + switch (instruction_length) + { + case 0: + inst_l = 0; + break; + case 4: + inst_l = 1; + break; + case 8: + inst_l = 2; + break; + case 16: + inst_l = 3; + break; + default: + configASSERT(!"Invalid instruction length"); + break; + } + + configASSERT(address_length % 4 == 0 && address_length <= 60); + uint32_t addr_l = address_length / 4; + + spi_handle->spi_ctrlr0 = (wait_cycles << 11) | (inst_l << 8) | (addr_l << 2) | instruction_address_trans_mode; +} + +uint32_t spi_set_clk_rate(spi_device_num_t spi_num, uint32_t spi_clk) +{ + uint32_t spi_baudr = SysctlClockGetFreq(SYSCTL_CLOCK_SPI0 + spi_num) / spi_clk; + if(spi_baudr < 2 ) + { + spi_baudr = 2; + } + else if(spi_baudr > 65534) + { + spi_baudr = 65534; + } + volatile spi_t *spi_adapter = spi[spi_num]; + spi_adapter->baudr = spi_baudr; + return SysctlClockGetFreq(SYSCTL_CLOCK_SPI0 + spi_num) / spi_baudr; +} + +void spi_send_data_normal(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + size_t index, fifo_len; + spi_set_tmod(spi_num, SPI_TMOD_TRANS); + + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length); + + uint8_t v_misalign_flag = 0; + uint32_t v_send_data; + if((uintptr_t)tx_buff % frame_width) + v_misalign_flag = 1; + + spi_handle->ssienr = 0x01; + spi_handle->ser = 1U << chip_select; + uint32_t i = 0; + while (tx_len) + { + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < tx_len ? fifo_len : tx_len; + switch(frame_width) + { + case SPI_TRANS_INT: + fifo_len = fifo_len / 4 * 4; + if(v_misalign_flag) + { + for(index = 0; index < fifo_len; index +=4) + { + memcpy(&v_send_data, tx_buff + i , 4); + spi_handle->dr[0] = v_send_data; + i += 4; + } + } + else + { + for (index = 0; index < fifo_len / 4; index++) + spi_handle->dr[0] = ((uint32_t *)tx_buff)[i++]; + } + break; + case SPI_TRANS_SHORT: + fifo_len = fifo_len / 2 * 2; + if(v_misalign_flag) + { + for(index = 0; index < fifo_len; index +=2) + { + memcpy(&v_send_data, tx_buff + i, 2); + spi_handle->dr[0] = v_send_data; + i += 2; + } + } + else + { + for (index = 0; index < fifo_len / 2; index++) + spi_handle->dr[0] = ((uint16_t *)tx_buff)[i++]; + } + break; + default: + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = tx_buff[i++]; + break; + } + tx_len -= fifo_len; + } + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + +} + +void spi_send_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *CmdBuff, + size_t CmdLen, const uint8_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + uint8_t *v_buf = malloc(CmdLen + tx_len); + size_t i; + for(i = 0; i < CmdLen; i++) + v_buf[i] = CmdBuff[i]; + for(i = 0; i < tx_len; i++) + v_buf[CmdLen + i] = tx_buff[i]; + + spi_send_data_normal(spi_num, chip_select, v_buf, CmdLen + tx_len); + free((void *)v_buf); +} + +void spi_send_data_standard_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const uint8_t *CmdBuff, size_t CmdLen, const uint8_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length); + + uint32_t *buf; + size_t v_send_len; + int i; + switch(frame_width) + { + case SPI_TRANS_INT: + buf = malloc(CmdLen + tx_len); + for(i = 0; i < CmdLen / 4; i++) + buf[i] = ((uint32_t *)CmdBuff)[i]; + for(i = 0; i < tx_len / 4; i++) + buf[CmdLen / 4 + i] = ((uint32_t *)tx_buff)[i]; + v_send_len = (CmdLen + tx_len) / 4; + break; + case SPI_TRANS_SHORT: + buf = malloc((CmdLen + tx_len) / 2 * sizeof(uint32_t)); + for(i = 0; i < CmdLen / 2; i++) + buf[i] = ((uint16_t *)CmdBuff)[i]; + for(i = 0; i < tx_len / 2; i++) + buf[CmdLen / 2 + i] = ((uint16_t *)tx_buff)[i]; + v_send_len = (CmdLen + tx_len) / 2; + break; + default: + buf = malloc((CmdLen + tx_len) * sizeof(uint32_t)); + for(i = 0; i < CmdLen; i++) + buf[i] = CmdBuff[i]; + for(i = 0; i < tx_len; i++) + buf[CmdLen + i] = tx_buff[i]; + v_send_len = CmdLen + tx_len; + break; + } + + spi_send_data_normal_dma(channel_num, spi_num, chip_select, buf, v_send_len, SPI_TRANS_INT); + + free((void *)buf); +} + +void spi_send_data_normal_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const void *tx_buff, size_t tx_len, spi_transfer_width_t spi_transfer_width) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + spi_set_tmod(spi_num, SPI_TMOD_TRANS); + volatile spi_t *spi_handle = spi[spi_num]; + uint32_t *buf; + int i; + switch(spi_transfer_width) + { + case SPI_TRANS_SHORT: + buf = malloc((tx_len) * sizeof(uint32_t)); + for(i = 0; i < tx_len; i++) + buf[i] = ((uint16_t *)tx_buff)[i]; + break; + case SPI_TRANS_INT: + buf = (uint32_t *)tx_buff; + break; + case SPI_TRANS_CHAR: + default: + buf = malloc((tx_len) * sizeof(uint32_t)); + for(i = 0; i < tx_len; i++) + buf[i] = ((uint8_t *)tx_buff)[i]; + break; + } + spi_handle->dmacr = 0x2; /*enable dma transmit*/ + spi_handle->ssienr = 0x01; + + sysctl_dma_select((sysctl_dma_channel_t) channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + dmac_set_single_mode(channel_num, buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, tx_len); + spi_handle->ser = 1U << chip_select; + dmac_wait_done(channel_num); + if(spi_transfer_width != SPI_TRANS_INT) + free((void *)buf); + + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; +} + +void spi_dup_send_receive_data_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, + const uint8_t *tx_buf, size_t tx_len, uint8_t *rx_buf, size_t rx_len) +{ + spi_set_tmod(spi_num, SPI_TMOD_TRANS_RECV); + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length); + size_t v_tx_len = tx_len / frame_width; + size_t v_rx_len = rx_len / frame_width; + + size_t v_max_len = v_tx_len > v_rx_len ? v_tx_len : v_rx_len; + + uint32_t *v_tx_buf = malloc(v_max_len * 4); + uint32_t *v_rx_buf = malloc(v_max_len * 4); + uint32_t i = 0; + switch(frame_width) + { + case SPI_TRANS_INT: + for(i = 0; i < v_tx_len; i++) + { + v_tx_buf[i] = ((uint32_t *)tx_buf)[i]; + } + if(v_max_len > v_tx_len) + { + while(i < v_max_len) + { + v_tx_buf[i++] = 0xFFFFFFFF; + } + } + break; + case SPI_TRANS_SHORT: + for(i = 0; i < v_tx_len; i++) + { + v_tx_buf[i] = ((uint16_t *)tx_buf)[i]; + } + if(v_max_len > v_tx_len) + { + while(i < v_max_len) + { + v_tx_buf[i++] = 0xFFFFFFFF; + } + } + break; + default: + for(i = 0; i < v_tx_len; i++) + { + v_tx_buf[i] = tx_buf[i]; + } + if(v_max_len > v_tx_len) + { + while(i < v_max_len) + { + v_tx_buf[i++] = 0xFFFFFFFF; + } + } + break; + } + + spi_handle->dmacr = 0x3; + spi_handle->ssienr = 0x01; + + sysctl_dma_select((sysctl_dma_channel_t)dma_send_channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + sysctl_dma_select((sysctl_dma_channel_t)dma_receive_channel_num, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_num * 2); + + dmac_set_single_mode(dma_receive_channel_num, (void *)(&spi_handle->dr[0]), v_rx_buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, v_max_len); + + dmac_set_single_mode(dma_send_channel_num, v_tx_buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, v_max_len); + + spi_handle->ser = 1U << chip_select; + dmac_wait_done(dma_send_channel_num); + dmac_wait_done(dma_receive_channel_num); + + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + + switch(frame_width) + { + case SPI_TRANS_INT: + for(i = 0; i < v_rx_len; i++) + ((uint32_t *)rx_buf)[i] = v_rx_buf[i]; + break; + case SPI_TRANS_SHORT: + for(i = 0; i < v_rx_len; i++) + ((uint16_t *)rx_buf)[i] = v_rx_buf[i]; + break; + default: + for(i = 0; i < v_rx_len; i++) + rx_buf[i] = v_rx_buf[i]; + break; + } + free(v_tx_buf); + free(v_rx_buf); +} + +void spi_receive_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *CmdBuff, + size_t CmdLen, uint8_t *rx_buff, size_t rx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + size_t index, fifo_len; + if(CmdLen == 0) + spi_set_tmod(spi_num, SPI_TMOD_RECV); + else + spi_set_tmod(spi_num, SPI_TMOD_EEROM); + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length); + + uint32_t i = 0; + size_t v_cmd_len = CmdLen / frame_width; + uint32_t v_rx_len = rx_len / frame_width; + + spi_handle->ctrlr1 = (uint32_t)(v_rx_len - 1); + spi_handle->ssienr = 0x01; + + while (v_cmd_len) + { + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < v_cmd_len ? fifo_len : v_cmd_len; + switch(frame_width) + { + case SPI_TRANS_INT: + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = ((uint32_t *)CmdBuff)[i++]; + break; + case SPI_TRANS_SHORT: + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = ((uint16_t *)CmdBuff)[i++]; + break; + default: + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = CmdBuff[i++]; + break; + } + spi_handle->ser = 1U << chip_select; + v_cmd_len -= fifo_len; + } + + if(CmdLen == 0) + { + spi_handle->dr[0] = 0xffffffff; + spi_handle->ser = 1U << chip_select; + } + + i = 0; + while (v_rx_len) + { + fifo_len = spi_handle->rxflr; + fifo_len = fifo_len < v_rx_len ? fifo_len : v_rx_len; + switch(frame_width) + { + case SPI_TRANS_INT: + for (index = 0; index < fifo_len; index++) + ((uint32_t *)rx_buff)[i++] = spi_handle->dr[0]; + break; + case SPI_TRANS_SHORT: + for (index = 0; index < fifo_len; index++) + ((uint16_t *)rx_buff)[i++] = (uint16_t)spi_handle->dr[0]; + break; + default: + for (index = 0; index < fifo_len; index++) + rx_buff[i++] = (uint8_t)spi_handle->dr[0]; + break; + } + + v_rx_len -= fifo_len; + } + + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; +} + +void spi_receive_data_normal_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, const void *CmdBuff, + size_t CmdLen, void *rx_buff, size_t rx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + if(CmdLen == 0) + spi_set_tmod(spi_num, SPI_TMOD_RECV); + else + spi_set_tmod(spi_num, SPI_TMOD_EEROM); + + volatile spi_t *spi_handle = spi[spi_num]; + + spi_handle->ctrlr1 = (uint32_t)(rx_len - 1); + spi_handle->dmacr = 0x3; + spi_handle->ssienr = 0x01; + if(CmdLen) + sysctl_dma_select((sysctl_dma_channel_t)dma_send_channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + sysctl_dma_select((sysctl_dma_channel_t)dma_receive_channel_num, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_num * 2); + + dmac_set_single_mode(dma_receive_channel_num, (void *)(&spi_handle->dr[0]), rx_buff, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, rx_len); + if(CmdLen) + dmac_set_single_mode(dma_send_channel_num, CmdBuff, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, CmdLen); + if(CmdLen == 0 && spi_get_frame_format(spi_num) == SPI_FF_STANDARD) + spi[spi_num]->dr[0] = 0xffffffff; + spi_handle->ser = 1U << chip_select; + if(CmdLen) + dmac_wait_done(dma_send_channel_num); + dmac_wait_done(dma_receive_channel_num); + + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; +} + + +void spi_receive_data_standard_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *CmdBuff, + size_t CmdLen, uint8_t *rx_buff, size_t rx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length); + + size_t i; + + uint32_t *write_cmd; + uint32_t *ReadBuf; + size_t v_recv_len; + size_t v_cmd_len; + switch(frame_width) + { + case SPI_TRANS_INT: + write_cmd = malloc(CmdLen + rx_len); + for(i = 0; i < CmdLen / 4; i++) + write_cmd[i] = ((uint32_t *)CmdBuff)[i]; + ReadBuf = &write_cmd[i]; + v_recv_len = rx_len / 4; + v_cmd_len = CmdLen / 4; + break; + case SPI_TRANS_SHORT: + write_cmd = malloc((CmdLen + rx_len) /2 * sizeof(uint32_t)); + for(i = 0; i < CmdLen / 2; i++) + write_cmd[i] = ((uint16_t *)CmdBuff)[i]; + ReadBuf = &write_cmd[i]; + v_recv_len = rx_len / 2; + v_cmd_len = CmdLen / 2; + break; + default: + write_cmd = malloc((CmdLen + rx_len) * sizeof(uint32_t)); + for(i = 0; i < CmdLen; i++) + write_cmd[i] = CmdBuff[i]; + ReadBuf = &write_cmd[i]; + v_recv_len = rx_len; + v_cmd_len = CmdLen; + break; + } + + spi_receive_data_normal_dma(dma_send_channel_num, dma_receive_channel_num, spi_num, chip_select, write_cmd, v_cmd_len, ReadBuf, v_recv_len); + + switch(frame_width) + { + case SPI_TRANS_INT: + for(i = 0; i < v_recv_len; i++) + ((uint32_t *)rx_buff)[i] = ReadBuf[i]; + break; + case SPI_TRANS_SHORT: + for(i = 0; i < v_recv_len; i++) + ((uint16_t *)rx_buff)[i] = ReadBuf[i]; + break; + default: + for(i = 0; i < v_recv_len; i++) + rx_buff[i] = ReadBuf[i]; + break; + } + + free(write_cmd); +} + +void spi_receive_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *CmdBuff, + size_t CmdLen, uint8_t *rx_buff, size_t rx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + size_t index, fifo_len; + if(CmdLen == 0) + spi_set_tmod(spi_num, SPI_TMOD_RECV); + else + spi_set_tmod(spi_num, SPI_TMOD_EEROM); + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length); + + uint32_t v_cmd_len = CmdLen; + uint32_t i = 0; + + uint32_t v_rx_len = rx_len / frame_width; + + spi_handle->ctrlr1 = (uint32_t)(v_rx_len - 1); + spi_handle->ssienr = 0x01; + + while (v_cmd_len) + { + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < v_cmd_len ? fifo_len : v_cmd_len; + + for (index = 0; index < fifo_len; index++) + spi_handle->dr[0] = *CmdBuff++; + + spi_handle->ser = 1U << chip_select; + v_cmd_len -= fifo_len; + } + + if(CmdLen == 0) + { + spi_handle->ser = 1U << chip_select; + } + + while (v_rx_len) + { + fifo_len = spi_handle->rxflr; + fifo_len = fifo_len < v_rx_len ? fifo_len : v_rx_len; + switch(frame_width) + { + case SPI_TRANS_INT: + for (index = 0; index < fifo_len; index++) + ((uint32_t *)rx_buff)[i++] = spi_handle->dr[0]; + break; + case SPI_TRANS_SHORT: + for (index = 0; index < fifo_len; index++) + ((uint16_t *)rx_buff)[i++] = (uint16_t)spi_handle->dr[0]; + break; + default: + for (index = 0; index < fifo_len; index++) + rx_buff[i++] = (uint8_t)spi_handle->dr[0]; + break; + } + + v_rx_len -= fifo_len; + } + + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + +} + +void spi_receive_data_multiple_dma(dmac_channel_number_t dma_send_channel_num, + dmac_channel_number_t dma_receive_channel_num, + spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *CmdBuff, + size_t CmdLen, uint8_t *rx_buff, size_t rx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length); + + size_t i; + + uint32_t *write_cmd = NULL; + uint32_t *ReadBuf; + size_t v_recv_len; + switch(frame_width) + { + case SPI_TRANS_INT: + v_recv_len = rx_len / 4; + break; + case SPI_TRANS_SHORT: + write_cmd = malloc(CmdLen + rx_len /2 * sizeof(uint32_t)); + for(i = 0; i < CmdLen; i++) + write_cmd[i] = CmdBuff[i]; + ReadBuf = &write_cmd[i]; + v_recv_len = rx_len / 2; + break; + default: + write_cmd = malloc(CmdLen + rx_len * sizeof(uint32_t)); + for(i = 0; i < CmdLen; i++) + write_cmd[i] = CmdBuff[i]; + ReadBuf = &write_cmd[i]; + v_recv_len = rx_len; + break; + } + if(frame_width == SPI_TRANS_INT) + spi_receive_data_normal_dma(dma_send_channel_num, dma_receive_channel_num, spi_num, chip_select, CmdBuff, CmdLen, rx_buff, v_recv_len); + else + spi_receive_data_normal_dma(dma_send_channel_num, dma_receive_channel_num, spi_num, chip_select, write_cmd, CmdLen, ReadBuf, v_recv_len); + + switch(frame_width) + { + case SPI_TRANS_INT: + break; + case SPI_TRANS_SHORT: + for(i = 0; i < v_recv_len; i++) + ((uint16_t *)rx_buff)[i] = ReadBuf[i]; + break; + default: + for(i = 0; i < v_recv_len; i++) + rx_buff[i] = ReadBuf[i]; + break; + } + + if(frame_width != SPI_TRANS_INT) + free(write_cmd); +} + +void spi_send_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *CmdBuff, + size_t CmdLen, const uint8_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + size_t index, fifo_len; + spi_set_tmod(spi_num, SPI_TMOD_TRANS); + volatile spi_t *spi_handle = spi[spi_num]; + spi_handle->ssienr = 0x01; + spi_handle->ser = 1U << chip_select; + + size_t v_cmd_len = CmdLen * 4; + while(v_cmd_len) + { + fifo_len = 32 - spi_handle->txflr; + fifo_len = fifo_len < v_cmd_len ? fifo_len : v_cmd_len; + fifo_len = fifo_len / 4 * 4; + for (index = 0; index < fifo_len / 4; index++) + spi_handle->dr[0] = *CmdBuff++; + v_cmd_len -= fifo_len; + } + spi_send_data_normal(spi_num, chip_select, tx_buff, tx_len); +} + +void spi_send_data_multiple_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, + spi_chip_select_t chip_select, + const uint32_t *CmdBuff, size_t CmdLen, const uint8_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + volatile spi_t *spi_handle = spi[spi_num]; + + uint8_t dfs_offset; + switch(spi_num) + { + case 0: + case 1: + dfs_offset = 16; + break; + case 2: + configASSERT(!"Spi Bus 2 Not Support!"); + break; + case 3: + default: + dfs_offset = 0; + break; + } + uint32_t data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F; + spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length); + + uint32_t *buf; + size_t v_send_len; + int i; + switch(frame_width) + { + case SPI_TRANS_INT: + buf = malloc(CmdLen * sizeof(uint32_t) + tx_len); + for(i = 0; i < CmdLen; i++) + buf[i] = CmdBuff[i]; + for(i = 0; i < tx_len / 4; i++) + buf[CmdLen + i] = ((uint32_t *)tx_buff)[i]; + v_send_len = CmdLen + tx_len / 4; + break; + case SPI_TRANS_SHORT: + buf = malloc(CmdLen * sizeof(uint32_t) + tx_len / 2 * sizeof(uint32_t)); + for(i = 0; i < CmdLen; i++) + buf[i] = CmdBuff[i]; + for(i = 0; i < tx_len / 2; i++) + buf[CmdLen + i] = ((uint16_t *)tx_buff)[i]; + v_send_len = CmdLen + tx_len / 2; + break; + default: + buf = malloc((CmdLen + tx_len) * sizeof(uint32_t)); + for(i = 0; i < CmdLen; i++) + buf[i] = CmdBuff[i]; + for(i = 0; i < tx_len; i++) + buf[CmdLen + i] = tx_buff[i]; + v_send_len = CmdLen + tx_len; + break; + } + + spi_send_data_normal_dma(channel_num, spi_num, chip_select, buf, v_send_len, SPI_TRANS_INT); + + free((void *)buf); +} + +void spi_fill_data_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, spi_chip_select_t chip_select, + const uint32_t *tx_buff, size_t tx_len) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + + spi_set_tmod(spi_num, SPI_TMOD_TRANS); + volatile spi_t *spi_handle = spi[spi_num]; + spi_handle->dmacr = 0x2; /*enable dma transmit*/ + spi_handle->ssienr = 0x01; + + sysctl_dma_select((sysctl_dma_channel_t)channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + dmac_set_single_mode(channel_num, tx_buff, (void *)(&spi_handle->dr[0]), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, tx_len); + spi_handle->ser = 1U << chip_select; + dmac_wait_done(channel_num); + + while ((spi_handle->sr & 0x05) != 0x04) + ; + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; +} + +static int spi_slave_irq(void *ctx) +{ + volatile spi_t *spi_handle = spi[2]; + + spi_handle->imr = 0x00; + *(volatile uint32_t *)((uintptr_t)spi_handle->icr); + if (g_instance.status == IDLE) + g_instance.status = COMMAND; + return 0; +} + +static void spi_slave_idle_mode(void) +{ + volatile spi_t *spi_handle = spi[2]; + uint32_t DataWidth = g_instance.data_bit_length / 8; + g_instance.status = IDLE; + spi_handle->ssienr = 0x00; + spi_handle->ctrlr0 = (0x0 << g_instance.work_mode) | (0x1 << g_instance.slv_oe) | ((g_instance.data_bit_length - 1) << g_instance.dfs); + spi_handle->rxftlr = 0x08 / DataWidth - 1; + + spi_handle->dmacr = 0x00; + spi_handle->imr = 0x10; + spi_handle->ssienr = 0x01; + gpiohs_set_pin(g_instance.ready_pin, GPIO_PV_HIGH); +} + +static void spi_slave_command_mode(void) +{ + volatile spi_t *spi_handle = spi[2]; + uint8_t CmdData[8], sum = 0; + + spi_transfer_width_t frame_width = spi_get_frame_size(g_instance.data_bit_length - 1); + uint32_t DataWidth = g_instance.data_bit_length / 8; + spi_device_num_t spi_num = SPI_DEVICE_2; + switch(frame_width) + { + case SPI_TRANS_INT: + for (uint32_t i = 0; i < 8 / 4; i++) + ((uint32_t *)CmdData)[i] = spi_handle->dr[0]; + break; + case SPI_TRANS_SHORT: + for (uint32_t i = 0; i < 8 / 2; i++) + ((uint16_t *)CmdData)[i] = spi_handle->dr[0]; + break; + default: + for (uint32_t i = 0; i < 8; i++) + CmdData[i] = spi_handle->dr[0]; + break; + } + + for (uint32_t i = 0; i < 7; i++) + { + sum += CmdData[i]; + } + if (CmdData[7] != sum) + { + spi_slave_idle_mode(); + return; + } + g_instance.command.cmd = CmdData[0]; + g_instance.command.addr = CmdData[1] | (CmdData[2] << 8) | (CmdData[3] << 16) | (CmdData[4] << 24); + g_instance.command.len = CmdData[5] | (CmdData[6] << 8); + if (g_instance.command.len == 0) + g_instance.command.len = 65536; + if ((g_instance.command.cmd < WRITE_DATA_BLOCK) && (g_instance.command.len > 8)) + { + spi_slave_idle_mode(); + return; + } + g_instance.status = TRANSFER; + spi_handle->ssienr = 0x00; + if (g_instance.command.cmd == WRITE_CONFIG) + { + spi_handle->ctrlr0 = (0x0 << g_instance.work_mode) | (0x1 << g_instance.slv_oe) | ((g_instance.data_bit_length - 1) << g_instance.dfs); + spi[2]->rxftlr = g_instance.command.len / DataWidth - 1; + spi_handle->imr = 0x00; + spi_handle->ssienr = 0x01; + } + else if (g_instance.command.cmd == READ_CONFIG) + { + spi_handle->ctrlr0 = (0x0 << g_instance.work_mode) | (0x0 << g_instance.slv_oe) | ((g_instance.data_bit_length - 1) << g_instance.dfs); + spi_set_tmod(2, SPI_TMOD_TRANS); + spi_handle->txftlr = 0x00; + spi_handle->imr = 0x00; + spi_handle->ssienr = 0x01; + switch(frame_width) + { + case SPI_TRANS_INT: + for (uint32_t i = 0; i < g_instance.command.len / 4; i++) + { + spi_handle->dr[0] = ((uint32_t *)&g_instance.config_ptr[g_instance.command.addr])[i]; + } + break; + case SPI_TRANS_SHORT: + for (uint32_t i = 0; i < g_instance.command.len / 2; i++) + { + spi_handle->dr[0] = ((uint16_t *)&g_instance.config_ptr[g_instance.command.addr])[i]; + } + break; + default: + for (uint32_t i = 0; i < g_instance.command.len; i++) + { + spi_handle->dr[0] = ((uint8_t *)&g_instance.config_ptr[g_instance.command.addr])[i]; + } + break; + } + } + else if (g_instance.command.cmd == WRITE_DATA_BYTE) + { + spi_handle->ctrlr0 = (0x0 << g_instance.work_mode) | (0x1 << g_instance.slv_oe) | ((g_instance.data_bit_length - 1) << g_instance.dfs); + spi[2]->rxftlr = g_instance.command.len / DataWidth - 1; + spi_handle->imr = 0x00; + spi_handle->ssienr = 0x01; + } + else if (g_instance.command.cmd == READ_DATA_BYTE) + { + spi_handle->ctrlr0 = (0x0 << g_instance.work_mode) | (0x0 << g_instance.slv_oe) | ((g_instance.data_bit_length - 1) << g_instance.dfs); + spi_set_tmod(2, SPI_TMOD_TRANS); + spi_handle->txftlr = 0x00; + spi_handle->imr = 0x00; + spi_handle->ssienr = 0x01; + switch(frame_width) + { + case SPI_TRANS_INT: + for (uint32_t i = 0; i < g_instance.command.len / 4; i++) + { + spi_handle->dr[0] = ((uint32_t *)(uintptr_t)g_instance.command.addr)[i]; + } + break; + case SPI_TRANS_SHORT: + for (uint32_t i = 0; i < g_instance.command.len / 2; i++) + { + spi_handle->dr[0] = ((uint16_t *)(uintptr_t)g_instance.command.addr)[i]; + } + break; + default: + for (uint32_t i = 0; i < g_instance.command.len; i++) + { + spi_handle->dr[0] = ((uint8_t *)(uintptr_t)g_instance.command.addr)[i]; + } + break; + } + } + else if (g_instance.command.cmd == WRITE_DATA_BLOCK) + { + spi_handle->ctrlr0 = (0x0 << g_instance.work_mode) | (0x1 << g_instance.slv_oe) | ((32 - 1) << g_instance.dfs); + + spi_handle->dmacr = 0x01; + spi_handle->imr = 0x00; + spi_handle->ssienr = 0x01; + + sysctl_dma_select(g_instance.dmac_channel, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_num * 2); + + dmac_set_single_mode(g_instance.dmac_channel, (void *)(&spi_handle->dr[0]), (void *)((uintptr_t)g_instance.command.addr & 0xFFFFFFF0), DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, g_instance.command.len * 4); + } + else if (g_instance.command.cmd == READ_DATA_BLOCK) + { + spi_handle->ctrlr0 = (0x0 << g_instance.work_mode) | (0x0 << g_instance.slv_oe) | ((32 - 1) << g_instance.dfs); + spi_set_tmod(2, SPI_TMOD_TRANS); + spi_handle->dmacr = 0x02; + spi_handle->imr = 0x00; + spi_handle->ssienr = 0x01; + + sysctl_dma_select(g_instance.dmac_channel, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + dmac_set_single_mode(g_instance.dmac_channel, (void *)((uintptr_t)g_instance.command.addr & 0xFFFFFFF0), (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, g_instance.command.len * 4); + } + else + { + spi_slave_idle_mode(); + return; + } + gpiohs_set_pin(g_instance.ready_pin, GPIO_PV_LOW); +} + +static void spi_slave_transfer_mode(void) +{ + spi_transfer_width_t frame_width = spi_get_frame_size(g_instance.data_bit_length - 1); + uint32_t command_len = 0; + + switch(frame_width) + { + case SPI_TRANS_INT: + command_len = g_instance.command.len / 4; + break; + case SPI_TRANS_SHORT: + command_len = g_instance.command.len / 2; + break; + default: + command_len = g_instance.command.len; + break; + } + volatile spi_t *spi_handle = spi[2]; + g_instance.command.err = 0; + if (g_instance.command.cmd == WRITE_CONFIG || g_instance.command.cmd == WRITE_DATA_BYTE) + { + if (spi_handle->rxflr < command_len - 1) + g_instance.command.err = 1; + } + else if (g_instance.command.cmd == READ_CONFIG || g_instance.command.cmd == READ_DATA_BYTE) + { + if (spi_handle->txflr != 0) + g_instance.command.err = 2; + } else if (g_instance.command.cmd == WRITE_DATA_BLOCK || g_instance.command.cmd == READ_DATA_BLOCK) + { + if (dmac->channel[g_instance.dmac_channel].intstatus != 0x02) + g_instance.command.err = 3; + } + else + { + spi_slave_idle_mode(); + return; + } + + if (g_instance.command.err == 0) + { + if (g_instance.command.cmd == WRITE_CONFIG) + { + switch(frame_width) + { + case SPI_TRANS_INT: + for (uint32_t i = 0; i < command_len; i++) + { + ((uint32_t *)&g_instance.config_ptr[g_instance.command.addr])[i] = spi_handle->dr[0]; + } + break; + case SPI_TRANS_SHORT: + for (uint32_t i = 0; i < command_len; i++) + { + ((uint16_t *)&g_instance.config_ptr[g_instance.command.addr])[i] = spi_handle->dr[0]; + } + break; + default: + for (uint32_t i = 0; i < command_len; i++) + { + ((uint8_t *)&g_instance.config_ptr[g_instance.command.addr])[i] = spi_handle->dr[0]; + } + break; + } + } + else if (g_instance.command.cmd == WRITE_DATA_BYTE) + { + switch(frame_width) + { + case SPI_TRANS_INT: + for (uint32_t i = 0; i < command_len; i++) + { + ((uint32_t *)(uintptr_t)g_instance.command.addr)[i] = spi_handle->dr[0]; + } + break; + case SPI_TRANS_SHORT: + for (uint32_t i = 0; i < command_len; i++) + { + ((uint16_t *)(uintptr_t)g_instance.command.addr)[i] = spi_handle->dr[0]; + } + break; + default: + for (uint32_t i = 0; i < command_len; i++) + { + ((uint8_t *)(uintptr_t)g_instance.command.addr)[i] = spi_handle->dr[0]; + } + break; + } + } + } + if(g_instance.callback != NULL) + { + g_instance.callback((void *)&g_instance.command); + } + spi_slave_idle_mode(); +} + +static void spi_slave_cs_irq(void) +{ + if (g_instance.status == IDLE) + spi_slave_idle_mode(); + else if (g_instance.status == COMMAND) + spi_slave_command_mode(); + else if (g_instance.status == TRANSFER) + spi_slave_transfer_mode(); +} + +void spi_slave_config(uint8_t int_pin, uint8_t ready_pin, dmac_channel_number_t dmac_channel, size_t data_bit_length, uint8_t *data, uint32_t len, spi_slave_receive_callback_t callback) +{ + g_instance.status = IDLE; + g_instance.config_ptr = data; + g_instance.config_len = len; + g_instance.work_mode = 6; + g_instance.slv_oe = 10; + g_instance.dfs = 16; + g_instance.data_bit_length = data_bit_length; + g_instance.ready_pin = ready_pin; + g_instance.int_pin = int_pin; + g_instance.callback = callback; + g_instance.dmac_channel = dmac_channel; + sysctl_reset(SYSCTL_RESET_SPI2); + sysctl_clock_enable(SYSCTL_CLOCK_SPI2); + sysctl_clock_set_threshold(SYSCTL_THRESHOLD_SPI2, 9); + + uint32_t DataWidth = data_bit_length / 8; + volatile spi_t *spi_handle = spi[2]; + spi_handle->ssienr = 0x00; + spi_handle->ctrlr0 = (0x0 << g_instance.work_mode) | (0x1 << g_instance.slv_oe) | ((data_bit_length - 1) << g_instance.dfs); + spi_handle->dmatdlr = 0x04; + spi_handle->dmardlr = 0x03; + spi_handle->dmacr = 0x00; + spi_handle->txftlr = 0x00; + spi_handle->rxftlr = 0x08 / DataWidth - 1; + spi_handle->imr = 0x10; + spi_handle->ssienr = 0x01; + + gpiohs_set_drive_mode(g_instance.ready_pin, GPIO_DM_OUTPUT); + gpiohs_set_pin(g_instance.ready_pin, GPIO_PV_HIGH); + + gpiohs_set_drive_mode(g_instance.int_pin, GPIO_DM_INPUT_PULL_UP); + gpiohs_set_pin_edge(g_instance.int_pin, GPIO_PE_RISING); + gpiohs_set_irq(g_instance.int_pin, 3, spi_slave_cs_irq); + + plic_set_priority(IRQN_SPI_SLAVE_INTERRUPT, 4); + plic_irq_enable(IRQN_SPI_SLAVE_INTERRUPT); + plic_irq_register(IRQN_SPI_SLAVE_INTERRUPT, spi_slave_irq, NULL); +} + +void spi_handle_data_dma(spi_device_num_t spi_num, spi_chip_select_t chip_select, spi_data_t data, plic_interrupt_t *cb) +{ + configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2); + configASSERT(chip_select < SPI_CHIP_SELECT_MAX); + switch(data.TransferMode) + { + case SPI_TMOD_TRANS_RECV: + case SPI_TMOD_EEROM: + configASSERT(data.tx_buf && data.tx_len && data.rx_buf && data.rx_len); + break; + case SPI_TMOD_TRANS: + configASSERT(data.tx_buf && data.tx_len); + break; + case SPI_TMOD_RECV: + configASSERT(data.rx_buf && data.rx_len); + break; + default: + configASSERT(!"Transfer Mode ERR"); + break; + } + configASSERT(data.tx_channel < DMAC_CHANNEL_MAX && data.rx_channel < DMAC_CHANNEL_MAX); + volatile spi_t *spi_handle = spi[spi_num]; + + spinlock_lock(&g_spi_instance[spi_num].lock); + if(cb) + { + g_spi_instance[spi_num].spi_int_instance.callback = cb->callback; + g_spi_instance[spi_num].spi_int_instance.ctx = cb->ctx; + } + switch(data.TransferMode) + { + case SPI_TMOD_RECV: + spi_set_tmod(spi_num, SPI_TMOD_RECV); + if(data.rx_len > 65536) + data.rx_len = 65536; + spi_handle->ctrlr1 = (uint32_t)(data.rx_len - 1); + spi_handle->dmacr = 0x03; + spi_handle->ssienr = 0x01; + if(spi_get_frame_format(spi_num) == SPI_FF_STANDARD) + spi_handle->dr[0] = 0xffffffff; + if(cb) + { + dmac_irq_register(data.rx_channel, spi_dma_irq, &g_spi_instance[spi_num], cb->priority); + g_spi_instance[spi_num].dmac_channel = data.rx_channel; + } + sysctl_dma_select((sysctl_dma_channel_t)data.rx_channel, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_num * 2); + dmac_set_single_mode(data.rx_channel, (void *)(&spi_handle->dr[0]), (void *)data.rx_buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, data.rx_len); + spi_handle->ser = 1U << chip_select; + if(!cb) + dmac_wait_idle(data.rx_channel); + break; + case SPI_TMOD_TRANS: + spi_set_tmod(spi_num, SPI_TMOD_TRANS); + spi_handle->dmacr = 0x2; /*enable dma transmit*/ + spi_handle->ssienr = 0x01; + + if(cb) + { + dmac_irq_register(data.tx_channel, spi_dma_irq, &g_spi_instance[spi_num], cb->priority); + g_spi_instance[spi_num].dmac_channel = data.tx_channel; + } + sysctl_dma_select(data.tx_channel, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + if(data.fill_mode) + dmac_set_single_mode(data.tx_channel, data.tx_buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, data.tx_len); + else + dmac_set_single_mode(data.tx_channel, data.tx_buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, data.tx_len); + spi_handle->ser = 1U << chip_select; + if(!cb) + { + dmac_wait_idle(data.tx_channel); + while ((spi_handle->sr & 0x05) != 0x04) + ; + } + break; + case SPI_TMOD_EEROM: + spi_set_tmod(spi_num, SPI_TMOD_EEROM); + if(data.rx_len > 65536) + data.rx_len = 65536; + spi_handle->ctrlr1 = (uint32_t)(data.rx_len - 1); + spi_handle->dmacr = 0x3; + spi_handle->ssienr = 0x01; + sysctl_dma_select(data.tx_channel, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + if(data.fill_mode) + dmac_set_single_mode(data.tx_channel, data.tx_buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, data.tx_len); + else + dmac_set_single_mode(data.tx_channel, data.tx_buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, data.tx_len); + if(cb) + { + dmac_irq_register(data.rx_channel, spi_dma_irq, &g_spi_instance[spi_num], cb->priority); + g_spi_instance[spi_num].dmac_channel = data.rx_channel; + } + sysctl_dma_select(data.rx_channel, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_num * 2); + dmac_set_single_mode(data.rx_channel, (void *)(&spi_handle->dr[0]), (void *)data.rx_buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, data.rx_len); + spi_handle->ser = 1U << chip_select; + if(!cb) + dmac_wait_idle(data.rx_channel); + break; + case SPI_TMOD_TRANS_RECV: + spi_set_tmod(spi_num, SPI_TMOD_TRANS_RECV); + if(data.rx_len > 65536) + data.rx_len = 65536; + + if(cb) + { + if(data.tx_len > data.rx_len) + { + dmac_irq_register(data.tx_channel, spi_dma_irq, &g_spi_instance[spi_num], cb->priority); + g_spi_instance[spi_num].dmac_channel = data.tx_channel; + } + else + { + dmac_irq_register(data.rx_channel, spi_dma_irq, &g_spi_instance[spi_num], cb->priority); + g_spi_instance[spi_num].dmac_channel = data.rx_channel; + } + } + spi_handle->ctrlr1 = (uint32_t)(data.rx_len - 1); + spi_handle->dmacr = 0x3; + spi_handle->ssienr = 0x01; + sysctl_dma_select(data.tx_channel, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2); + if(data.fill_mode) + dmac_set_single_mode(data.tx_channel, data.tx_buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_NOCHANGE, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, data.tx_len); + else + dmac_set_single_mode(data.tx_channel, data.tx_buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE, + DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, data.tx_len); + sysctl_dma_select(data.rx_channel, SYSCTL_DMA_SELECT_SSI0_RX_REQ + spi_num * 2); + dmac_set_single_mode(data.rx_channel, (void *)(&spi_handle->dr[0]), (void *)data.rx_buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT, + DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, data.rx_len); + spi_handle->ser = 1U << chip_select; + if(!cb) + { + dmac_wait_idle(data.tx_channel); + dmac_wait_idle(data.rx_channel); + } + break; + } + if(!cb) + { + spinlock_unlock(&g_spi_instance[spi_num].lock); + spi_handle->ser = 0x00; + spi_handle->ssienr = 0x00; + } +} +