Revert "修正但仍有误"

This reverts commit 7279c647ed.
This commit is contained in:
2025-01-23 21:01:59 +08:00
parent 7279c647ed
commit 0abd316c90
110 changed files with 31062 additions and 809 deletions

View File

@@ -1,11 +1,6 @@
scons.args: &scons
scons_arg:
- '--strict'
# ------ nano CI ------
nano:
<<: *scons
kconfig:
- CONFIG_RT_USING_NANO=y
# ------ kernel CI ------
kernel.klibc-stdlib:
<<: *scons
@@ -187,11 +182,8 @@ peripheral.sram:
peripheral.usb_mouse:
kconfig:
- CONFIG_BSP_USING_USB_MOUSE=y
# ------ component CI ------
component.cherryusb_cdc:
# ------ nano CI ------
nano:
<<: *scons
kconfig:
- CONFIG_RT_USING_CHERRYUSB=y
- CONFIG_RT_CHERRYUSB_DEVICE=y
- CONFIG_RT_CHERRYUSB_DEVICE_DWC2_ST=y
- CONFIG_RT_CHERRYUSB_DEVICE_CDC_ACM=y
- CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM=y
- CONFIG_RT_USING_NANO=y

221
.config
View File

@@ -4,116 +4,10 @@ CONFIG_BOARD_STM32F407_SPARK=y
#
# RT-Thread Kernel
#
#
# klibc options
#
#
# rt_vsnprintf options
#
# CONFIG_RT_KLIBC_USING_LIBC_VSNPRINTF is not set
# CONFIG_RT_KLIBC_USING_VSNPRINTF_LONGLONG is not set
# CONFIG_RT_KLIBC_USING_VSNPRINTF_STANDARD is not set
# end of rt_vsnprintf options
#
# rt_vsscanf options
#
# CONFIG_RT_KLIBC_USING_LIBC_VSSCANF is not set
# end of rt_vsscanf options
#
# rt_memset options
#
# CONFIG_RT_KLIBC_USING_USER_MEMSET is not set
# CONFIG_RT_KLIBC_USING_LIBC_MEMSET is not set
# CONFIG_RT_KLIBC_USING_TINY_MEMSET is not set
# end of rt_memset options
#
# rt_memcpy options
#
# CONFIG_RT_KLIBC_USING_USER_MEMCPY is not set
# CONFIG_RT_KLIBC_USING_LIBC_MEMCPY is not set
# CONFIG_RT_KLIBC_USING_TINY_MEMCPY is not set
# end of rt_memcpy options
#
# rt_memmove options
#
# CONFIG_RT_KLIBC_USING_USER_MEMMOVE is not set
# CONFIG_RT_KLIBC_USING_LIBC_MEMMOVE is not set
# end of rt_memmove options
#
# rt_memcmp options
#
# CONFIG_RT_KLIBC_USING_USER_MEMCMP is not set
# CONFIG_RT_KLIBC_USING_LIBC_MEMCMP is not set
# end of rt_memcmp options
#
# rt_strstr options
#
# CONFIG_RT_KLIBC_USING_USER_STRSTR is not set
# CONFIG_RT_KLIBC_USING_LIBC_STRSTR is not set
# end of rt_strstr options
#
# rt_strcasecmp options
#
# CONFIG_RT_KLIBC_USING_USER_STRCASECMP is not set
# end of rt_strcasecmp options
#
# rt_strncpy options
#
# CONFIG_RT_KLIBC_USING_USER_STRNCPY is not set
# CONFIG_RT_KLIBC_USING_LIBC_STRNCPY is not set
# end of rt_strncpy options
#
# rt_strcpy options
#
# CONFIG_RT_KLIBC_USING_USER_STRCPY is not set
# CONFIG_RT_KLIBC_USING_LIBC_STRCPY is not set
# end of rt_strcpy options
#
# rt_strncmp options
#
# CONFIG_RT_KLIBC_USING_USER_STRNCMP is not set
# CONFIG_RT_KLIBC_USING_LIBC_STRNCMP is not set
# end of rt_strncmp options
#
# rt_strcmp options
#
# CONFIG_RT_KLIBC_USING_USER_STRCMP is not set
# CONFIG_RT_KLIBC_USING_LIBC_STRCMP is not set
# end of rt_strcmp options
#
# rt_strlen options
#
# CONFIG_RT_KLIBC_USING_USER_STRLEN is not set
# CONFIG_RT_KLIBC_USING_LIBC_STRLEN is not set
# end of rt_strlen options
#
# rt_strnlen options
#
# CONFIG_RT_KLIBC_USING_USER_STRNLEN is not set
# end of rt_strnlen options
# CONFIG_RT_UTEST_TC_USING_KLIBC is not set
# end of klibc options
CONFIG_RT_NAME_MAX=8
# CONFIG_RT_USING_ARCH_DATA_TYPE is not set
# CONFIG_RT_USING_NANO is not set
# CONFIG_RT_USING_SMART is not set
# CONFIG_RT_USING_NANO is not set
# CONFIG_RT_USING_AMP is not set
# CONFIG_RT_USING_SMP is not set
CONFIG_RT_CPUS_NR=1
@@ -123,7 +17,6 @@ CONFIG_RT_THREAD_PRIORITY_32=y
# CONFIG_RT_THREAD_PRIORITY_256 is not set
CONFIG_RT_THREAD_PRIORITY_MAX=32
CONFIG_RT_TICK_PER_SECOND=1000
CONFIG_RT_USING_OVERFLOW_CHECK=y
CONFIG_RT_USING_HOOK=y
CONFIG_RT_HOOK_USING_FUNC_PTR=y
# CONFIG_RT_USING_HOOKLIST is not set
@@ -137,17 +30,25 @@ CONFIG_RT_TIMER_THREAD_STACK_SIZE=512
# CONFIG_RT_USING_CPU_USAGE_TRACER is not set
#
# kservice options
# kservice optimization
#
# CONFIG_RT_USING_TINY_FFS is not set
# end of kservice options
# end of kservice optimization
#
# klibc optimization
#
# CONFIG_RT_KLIBC_USING_STDLIB is not set
# CONFIG_RT_KLIBC_USING_TINY_SIZE is not set
# CONFIG_RT_KLIBC_USING_PRINTF_LONGLONG is not set
# end of klibc optimization
CONFIG_RT_USING_DEBUG=y
CONFIG_RT_DEBUGING_ASSERT=y
CONFIG_RT_DEBUGING_COLOR=y
CONFIG_RT_DEBUGING_CONTEXT=y
# CONFIG_RT_DEBUGING_AUTO_INIT is not set
# CONFIG_RT_USING_CI_ACTION is not set
CONFIG_RT_USING_OVERFLOW_CHECK=y
#
# Inter-Thread communication
@@ -182,6 +83,7 @@ CONFIG_RT_USING_DEVICE=y
# CONFIG_RT_USING_DEVICE_OPS is not set
# CONFIG_RT_USING_INTERRUPT_INFO is not set
# CONFIG_RT_USING_THREADSAFE_PRINTF is not set
# CONFIG_RT_USING_SCHED_THREAD_CTX is not set
CONFIG_RT_USING_CONSOLE=y
CONFIG_RT_CONSOLEBUF_SIZE=128
CONFIG_RT_CONSOLE_DEVICE_NAME="uart1"
@@ -270,7 +172,8 @@ CONFIG_RT_USING_DFS_ROMFS=y
# end of DFS: device virtual file system
CONFIG_RT_USING_FAL=y
CONFIG_FAL_USING_DEBUG=y
CONFIG_FAL_DEBUG_CONFIG=y
CONFIG_FAL_DEBUG=1
CONFIG_FAL_PART_HAS_TABLE_CFG=y
CONFIG_FAL_USING_SFUD_PORT=y
CONFIG_FAL_USING_NOR_FLASH_DEV_NAME="norflash0"
@@ -290,7 +193,6 @@ CONFIG_RT_USING_SERIAL_V1=y
# CONFIG_RT_USING_SERIAL_V2 is not set
CONFIG_RT_SERIAL_USING_DMA=y
CONFIG_RT_SERIAL_RB_BUFSZ=64
# CONFIG_RT_USING_SERIAL_BYPASS is not set
# CONFIG_RT_USING_CAN is not set
# CONFIG_RT_USING_CPUTIME is not set
CONFIG_RT_USING_I2C=y
@@ -299,7 +201,6 @@ CONFIG_RT_USING_I2C_BITOPS=y
# CONFIG_RT_I2C_BITOPS_DEBUG is not set
# CONFIG_RT_USING_SOFT_I2C is not set
# CONFIG_RT_USING_PHY is not set
# CONFIG_RT_USING_PHY_V2 is not set
CONFIG_RT_USING_ADC=y
# CONFIG_RT_USING_DAC is not set
# CONFIG_RT_USING_NULL is not set
@@ -321,7 +222,6 @@ CONFIG_RT_MMCSD_STACK_SIZE=1024
CONFIG_RT_MMCSD_THREAD_PREORITY=22
CONFIG_RT_MMCSD_MAX_PARTITION=16
# CONFIG_RT_SDIO_DEBUG is not set
# CONFIG_RT_USING_SDHCI is not set
CONFIG_RT_USING_SPI=y
# CONFIG_RT_USING_SPI_BITOPS is not set
# CONFIG_RT_USING_QSPI is not set
@@ -370,73 +270,11 @@ CONFIG_RT_WLAN_WORKQUEUE_THREAD_NAME="wlan"
CONFIG_RT_WLAN_WORKQUEUE_THREAD_SIZE=2048
CONFIG_RT_WLAN_WORKQUEUE_THREAD_PRIO=15
# CONFIG_RT_WLAN_DEBUG is not set
CONFIG_RT_USING_BLK=y
#
# Partition Types
#
CONFIG_RT_BLK_PARTITION_DFS=y
CONFIG_RT_BLK_PARTITION_EFI=y
# end of Partition Types
# CONFIG_RT_USING_VIRTIO is not set
CONFIG_RT_USING_PIN=y
# CONFIG_RT_USING_KTIME is not set
CONFIG_RT_USING_HWTIMER=y
CONFIG_RT_USING_CHERRYUSB=y
CONFIG_RT_CHERRYUSB_DEVICE=y
CONFIG_RT_CHERRYUSB_DEVICE_SPEED_FS=y
# CONFIG_RT_CHERRYUSB_DEVICE_SPEED_HS is not set
# CONFIG_RT_CHERRYUSB_DEVICE_SPEED_AUTO is not set
# CONFIG_RT_CHERRYUSB_DEVICE_CUSTOM is not set
# CONFIG_RT_CHERRYUSB_DEVICE_FSDEV is not set
CONFIG_RT_CHERRYUSB_DEVICE_DWC2_ST=y
# CONFIG_RT_CHERRYUSB_DEVICE_DWC2_ESP is not set
# CONFIG_RT_CHERRYUSB_DEVICE_DWC2_AT is not set
# CONFIG_RT_CHERRYUSB_DEVICE_DWC2_GD is not set
# CONFIG_RT_CHERRYUSB_DEVICE_DWC2_HC is not set
# CONFIG_RT_CHERRYUSB_DEVICE_DWC2_KENDRYTE is not set
# CONFIG_RT_CHERRYUSB_DEVICE_DWC2_CUSTOM is not set
# CONFIG_RT_CHERRYUSB_DEVICE_MUSB_ES is not set
# CONFIG_RT_CHERRYUSB_DEVICE_MUSB_SUNXI is not set
# CONFIG_RT_CHERRYUSB_DEVICE_MUSB_BK is not set
# CONFIG_RT_CHERRYUSB_DEVICE_MUSB_CUSTOM is not set
# CONFIG_RT_CHERRYUSB_DEVICE_KINETIS_MCX is not set
# CONFIG_RT_CHERRYUSB_DEVICE_KINETIS_CUSTOM is not set
# CONFIG_RT_CHERRYUSB_DEVICE_CHIPIDEA_MCX is not set
# CONFIG_RT_CHERRYUSB_DEVICE_CHIPIDEA_CUSTOM is not set
# CONFIG_RT_CHERRYUSB_DEVICE_BL is not set
# CONFIG_RT_CHERRYUSB_DEVICE_CH32 is not set
# CONFIG_RT_CHERRYUSB_DEVICE_HPM is not set
# CONFIG_RT_CHERRYUSB_DEVICE_AIC is not set
# CONFIG_RT_CHERRYUSB_DEVICE_PUSB2 is not set
CONFIG_RT_CHERRYUSB_DEVICE_CDC_ACM=y
# CONFIG_RT_CHERRYUSB_DEVICE_HID is not set
# CONFIG_RT_CHERRYUSB_DEVICE_MSC is not set
# CONFIG_RT_CHERRYUSB_DEVICE_AUDIO is not set
# CONFIG_RT_CHERRYUSB_DEVICE_VIDEO is not set
# CONFIG_RT_CHERRYUSB_DEVICE_CDC_RNDIS is not set
# CONFIG_RT_CHERRYUSB_DEVICE_CDC_ECM is not set
# CONFIG_RT_CHERRYUSB_DEVICE_CDC_NCM is not set
# CONFIG_RT_CHERRYUSB_DEVICE_DFU is not set
# CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_NONE is not set
CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM=y
# CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_MSC is not set
# CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_HID_KEYBOARD is not set
# CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_HID_MOUSE is not set
# CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_HID_CUSTOM is not set
# CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_VIDEO is not set
# CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V1_MIC_SPEAKER is not set
# CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V2_MIC_SPEAKER is not set
# CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_RNDIS is not set
# CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ECM is not set
# CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_NCM is not set
# CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC is not set
# CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC_HID is not set
# CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV1 is not set
# CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_CDC is not set
# CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_HID is not set
# CONFIG_RT_CHERRYUSB_HOST is not set
# CONFIG_RT_USING_CHERRYUSB is not set
# end of Device Drivers
#
@@ -517,7 +355,6 @@ CONFIG_NETDEV_USING_IFCONFIG=y
CONFIG_NETDEV_USING_PING=y
CONFIG_NETDEV_USING_NETSTAT=y
CONFIG_NETDEV_USING_AUTO_DEFAULT=y
# CONFIG_NETDEV_USING_LINK_STATUS_CALLBACK is not set
# CONFIG_NETDEV_USING_IPV6 is not set
CONFIG_NETDEV_IPV4=1
CONFIG_NETDEV_IPV6=0
@@ -581,7 +418,6 @@ CONFIG_LWIP_NETIF_LOOPBACK=0
# CONFIG_RT_LWIP_USING_HW_CHECKSUM is not set
CONFIG_RT_LWIP_USING_PING=y
# CONFIG_LWIP_USING_DHCPD is not set
# CONFIG_RT_LWIP_ENABLE_USER_HOOKS is not set
# CONFIG_RT_LWIP_DEBUG is not set
# CONFIG_RT_USING_AT is not set
# end of Network
@@ -1058,7 +894,26 @@ CONFIG_PKG_VCONSOLE_VER="latest"
#
# CONFIG_PKG_USING_RT_MEMCPY_CM is not set
# CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set
# CONFIG_PKG_USING_RT_VSNPRINTF_FULL is not set
CONFIG_PKG_USING_RT_VSNPRINTF_FULL=y
CONFIG_PKG_RT_VSNPRINTF_FULL_PATH="/packages/system/enhanced-kservice/rt_vsnprintf_full"
CONFIG_PKG_VSNPRINTF_SUPPORT_DECIMAL_SPECIFIERS=y
CONFIG_PKG_VSNPRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS=y
CONFIG_PKG_VSNPRINTF_SUPPORT_WRITEBACK_SPECIFIER=y
CONFIG_PKG_VSNPRINTF_SUPPORT_LONG_LONG=y
CONFIG_PKG_VSNPRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER=y
# CONFIG_PKG_VSNPRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS is not set
CONFIG_PKG_VSNPRINTF_INTEGER_BUFFER_SIZE=32
CONFIG_PKG_VSNPRINTF_DECIMAL_BUFFER_SIZE=32
CONFIG_PKG_VSNPRINTF_DEFAULT_FLOAT_PRECISION=6
CONFIG_PKG_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL=9
CONFIG_PKG_VSNPRINTF_LOG10_TAYLOR_TERMS=4
# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SPRINTF is not set
# CONFIG_RT_VSNPRINTF_FULL_REPLACING_SNPRINTF is not set
# CONFIG_RT_VSNPRINTF_FULL_REPLACING_PRINTF is not set
# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSPRINTF is not set
# CONFIG_RT_VSNPRINTF_FULL_REPLACING_VSNPRINTF is not set
CONFIG_PKG_USING_RT_VSNPRINTF_FULL_LATEST_VERSION=y
CONFIG_PKG_RT_VSNPRINTF_FULL_VER="latest"
# end of enhanced kernel services
# CONFIG_PKG_USING_AUNITY is not set
@@ -1105,7 +960,6 @@ CONFIG_PKG_PERF_COUNTER_PATH="/packages/system/perf_counter"
CONFIG_PKG_USING_PERF_COUNTER_V2241=y
# CONFIG_PKG_USING_PERF_COUNTER_LATEST_VERSION is not set
CONFIG_PKG_PERF_COUNTER_VER="v2.2.4.1"
CONFIG_FAL_DEBUG_CONFIG=y
# CONFIG_PKG_USING_FILEX is not set
# CONFIG_PKG_USING_LEVELX is not set
# CONFIG_PKG_USING_FLASHDB is not set
@@ -1777,7 +1631,7 @@ CONFIG_BSP_USING_SRAM=y
CONFIG_BSP_USING_ONBOARD_LCD=y
CONFIG_BSP_USING_ONBOARD_LCD_PWM_BL=y
CONFIG_BSP_USING_ONBOARD_LED_MATRIX=y
# CONFIG_BSP_USING_LED_MATRIX_RS485_DEMO is not set
CONFIG_BSP_USING_LED_MATRIX_RS485_DEMO=y
# CONFIG_BSP_USING_LVGL is not set
CONFIG_BSP_USING_SPI_FLASH=y
# CONFIG_BSP_USING_EEPROM is not set
@@ -1867,6 +1721,7 @@ CONFIG_BSP_USING_FMC=y
#
# Board extended module Drivers
#
CONFIG_BSP_USING_TEST=y
# CONFIG_BSP_USING_AT_ESP8266 is not set
# end of Board extended module Drivers
# end of Hardware Drivers Config

View File

@@ -20,5 +20,3 @@
[info] Log at : 2025/1/18|00:50:06|GMT+0800
[info] Log at : 2025/1/23|11:41:41|GMT+0800

View File

@@ -1,8 +1,8 @@
#include <rtthread.h>
#include <rthw.h>
#include <dev_wlan_mgnt.h>
#include <dev_wlan_cfg.h>
#include <dev_wlan_prot.h>
#include <wlan_mgnt.h>
#include <wlan_cfg.h>
#include <wlan_prot.h>
#include <ap3216c.h>
#include "my_func.h"
@@ -50,9 +50,9 @@ INIT_APP_EXPORT(app_init);
int main_init(void)
{
// char str[] = "wifi join Dong abcd07691234";
char str[] = "wifi join Dong abcd07691234";
my_round(20);
// system(str);
system(str);
// rt_thread_mdelay(18000);
// char *argv[] = {"wifi", "join", "Dong", "abcd07691234"};
// wifi_join(4, argv);

View File

@@ -39,8 +39,8 @@ int main(void)
system("snake");
// rt_wlan_config_autoreconnect(RT_TRUE);
// rt_wlan_connect("Dong", "abcd07691234");
// rt_wlan_connect("as", "88888888");
// rt_wlan_connect("as", "88888888");
rt_wlan_connect("as", "88888888");
rt_wlan_connect("as", "88888888");
system("myproject");
// system("mqtt");
mytime();

View File

@@ -33,7 +33,8 @@ Mcu.IP17=TIM14
Mcu.IP18=USART1
Mcu.IP19=USART2
Mcu.IP2=DAC
Mcu.IP20=USB_OTG_FS
Mcu.IP20=USART3
Mcu.IP21=USB_OTG_FS
Mcu.IP3=FSMC
Mcu.IP4=IWDG
Mcu.IP5=NVIC
@@ -41,7 +42,7 @@ Mcu.IP6=RCC
Mcu.IP7=RTC
Mcu.IP8=SDIO
Mcu.IP9=SPI2
Mcu.IPNb=21
Mcu.IPNb=22
Mcu.Name=STM32F407Z(E-G)Tx
Mcu.Package=LQFP144
Mcu.Pin0=PC14-OSC32_IN
@@ -63,47 +64,49 @@ Mcu.Pin22=PE13
Mcu.Pin23=PB10
Mcu.Pin24=PB11
Mcu.Pin25=PB13
Mcu.Pin26=PD12
Mcu.Pin27=PD13
Mcu.Pin28=PD14
Mcu.Pin29=PD15
Mcu.Pin26=PD8
Mcu.Pin27=PD9
Mcu.Pin28=PD12
Mcu.Pin29=PD13
Mcu.Pin3=PF5
Mcu.Pin30=PC8
Mcu.Pin31=PC9
Mcu.Pin32=PA9
Mcu.Pin33=PA10
Mcu.Pin34=PA11
Mcu.Pin35=PA12
Mcu.Pin36=PA13
Mcu.Pin37=PA14
Mcu.Pin38=PC10
Mcu.Pin39=PC11
Mcu.Pin30=PD14
Mcu.Pin31=PD15
Mcu.Pin32=PC8
Mcu.Pin33=PC9
Mcu.Pin34=PA9
Mcu.Pin35=PA10
Mcu.Pin36=PA11
Mcu.Pin37=PA12
Mcu.Pin38=PA13
Mcu.Pin39=PA14
Mcu.Pin4=PF6
Mcu.Pin40=PC12
Mcu.Pin41=PD0
Mcu.Pin42=PD1
Mcu.Pin43=PD2
Mcu.Pin44=PD4
Mcu.Pin45=PD5
Mcu.Pin46=PG10
Mcu.Pin47=PG11
Mcu.Pin48=PG13
Mcu.Pin49=PG14
Mcu.Pin40=PC10
Mcu.Pin41=PC11
Mcu.Pin42=PC12
Mcu.Pin43=PD0
Mcu.Pin44=PD1
Mcu.Pin45=PD2
Mcu.Pin46=PD4
Mcu.Pin47=PD5
Mcu.Pin48=PG10
Mcu.Pin49=PG11
Mcu.Pin5=PF7
Mcu.Pin50=VP_IWDG_VS_IWDG
Mcu.Pin51=VP_RTC_VS_RTC_Activate
Mcu.Pin52=VP_SYS_VS_Systick
Mcu.Pin53=VP_TIM1_VS_ClockSourceINT
Mcu.Pin54=VP_TIM2_VS_ClockSourceINT
Mcu.Pin55=VP_TIM3_VS_ClockSourceINT
Mcu.Pin56=VP_TIM11_VS_ClockSourceINT
Mcu.Pin57=VP_TIM13_VS_ClockSourceINT
Mcu.Pin58=VP_TIM14_VS_ClockSourceINT
Mcu.Pin50=PG13
Mcu.Pin51=PG14
Mcu.Pin52=VP_IWDG_VS_IWDG
Mcu.Pin53=VP_RTC_VS_RTC_Activate
Mcu.Pin54=VP_SYS_VS_Systick
Mcu.Pin55=VP_TIM1_VS_ClockSourceINT
Mcu.Pin56=VP_TIM2_VS_ClockSourceINT
Mcu.Pin57=VP_TIM3_VS_ClockSourceINT
Mcu.Pin58=VP_TIM11_VS_ClockSourceINT
Mcu.Pin59=VP_TIM13_VS_ClockSourceINT
Mcu.Pin6=PF9
Mcu.Pin60=VP_TIM14_VS_ClockSourceINT
Mcu.Pin7=PH0-OSC_IN
Mcu.Pin8=PH1-OSC_OUT
Mcu.Pin9=PC2
Mcu.PinsNb=59
Mcu.PinsNb=61
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32F407ZGTx
@@ -180,6 +183,10 @@ PD2.Mode=SD_4_bits_Wide_bus
PD2.Signal=SDIO_CMD
PD4.Signal=FSMC_NOE
PD5.Signal=FSMC_NWE
PD8.Mode=Asynchronous
PD8.Signal=USART3_TX
PD9.Mode=Asynchronous
PD9.Signal=USART3_RX
PE10.Signal=FSMC_D7_DA7
PE11.Locked=true
PE11.Signal=S_TIM1_CH2
@@ -243,7 +250,7 @@ ProjectManager.ToolChainLocation=
ProjectManager.UAScriptAfterPath=
ProjectManager.UAScriptBeforePath=
ProjectManager.UnderRoot=false
ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false,3-MX_USART1_UART_Init-USART1-false-HAL-true,4-MX_RTC_Init-RTC-false-HAL-true,5-MX_IWDG_Init-IWDG-false-HAL-true,6-MX_TIM14_Init-TIM14-false-HAL-true,7-MX_TIM13_Init-TIM13-false-HAL-true,8-MX_TIM11_Init-TIM11-false-HAL-true,9-MX_SDIO_SD_Init-SDIO-false-HAL-true,10-MX_TIM2_Init-TIM2-false-HAL-true,11-MX_SPI2_Init-SPI2-false-HAL-true,12-MX_TIM4_Init-TIM4-false-HAL-true,13-MX_USB_OTG_FS_PCD_Init-USB_OTG_FS-false-HAL-true,14-MX_FSMC_Init-FSMC-false-HAL-true,15-MX_DAC_Init-DAC-false-HAL-true,16-MX_TIM3_Init-TIM3-false-HAL-true,17-MX_ADC1_Init-ADC1-false-HAL-true,18-MX_ADC3_Init-ADC3-false-HAL-true,19-MX_TIM1_Init-TIM1-false-HAL-true,20-MX_USART2_UART_Init-USART2-false-HAL-true
ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false,3-MX_USART1_UART_Init-USART1-false-HAL-true,4-MX_RTC_Init-RTC-false-HAL-true,5-MX_IWDG_Init-IWDG-false-HAL-true,6-MX_TIM14_Init-TIM14-false-HAL-true,7-MX_TIM13_Init-TIM13-false-HAL-true,8-MX_TIM11_Init-TIM11-false-HAL-true,9-MX_SDIO_SD_Init-SDIO-false-HAL-true,10-MX_TIM2_Init-TIM2-false-HAL-true,11-MX_SPI2_Init-SPI2-false-HAL-true,12-MX_TIM4_Init-TIM4-false-HAL-true,13-MX_USB_OTG_FS_PCD_Init-USB_OTG_FS-false-HAL-true,14-MX_FSMC_Init-FSMC-false-HAL-true,15-MX_DAC_Init-DAC-false-HAL-true,16-MX_TIM3_Init-TIM3-false-HAL-true,17-MX_ADC1_Init-ADC1-false-HAL-true,18-MX_ADC3_Init-ADC3-false-HAL-true,19-MX_TIM1_Init-TIM1-false-HAL-true,20-MX_USART2_UART_Init-USART2-false-HAL-true,21-MX_USART3_UART_Init-USART3-false-HAL-true
RCC.48MHZClocksFreq_Value=48000000
RCC.AHBFreq_Value=168000000
RCC.APB1CLKDivider=RCC_HCLK_DIV4
@@ -335,13 +342,18 @@ TIM2.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4
TIM2.IPParameters=Channel-PWM Generation3 CH3,Channel-PWM Generation4 CH4
TIM3.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2
TIM3.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4
TIM3.IPParameters=Channel-PWM Generation4 CH4,Channel-PWM Generation2 CH2
TIM3.IPParameters=Channel-PWM Generation4 CH4,Channel-PWM Generation2 CH2,Pulse-PWM Generation2 CH2,Period
TIM3.Period=210
TIM3.Pulse-PWM\ Generation2\ CH2=0
TIM4.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
TIM4.IPParameters=Channel-PWM Generation1 CH1
USART1.IPParameters=VirtualMode
USART1.VirtualMode=VM_ASYNC
USART2.IPParameters=VirtualMode
USART2.VirtualMode=VM_ASYNC
USART3.BaudRate=9600
USART3.IPParameters=VirtualMode,BaudRate
USART3.VirtualMode=VM_ASYNC
USB_OTG_FS.IPParameters=VirtualMode
USB_OTG_FS.VirtualMode=Device_Only
VP_IWDG_VS_IWDG.Mode=IWDG_Activate

View File

@@ -73,7 +73,7 @@ extern "C" {
void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
// void Error_Handler(void);
/* USER CODE BEGIN EFP */

View File

@@ -6,7 +6,7 @@
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
@@ -63,6 +63,7 @@ TIM_HandleTypeDef htim14;
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
UART_HandleTypeDef huart3;
PCD_HandleTypeDef hpcd_USB_OTG_FS;
@@ -93,6 +94,7 @@ static void MX_ADC1_Init(void);
static void MX_ADC3_Init(void);
static void MX_TIM1_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_USART3_UART_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
@@ -149,6 +151,7 @@ int main(void)
MX_ADC3_Init();
MX_TIM1_Init();
MX_USART2_UART_Init();
MX_USART3_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
@@ -657,7 +660,7 @@ static void MX_TIM3_Init(void)
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 65535;
htim3.Init.Period = 210;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
@@ -921,6 +924,39 @@ static void MX_USART2_UART_Init(void)
}
/**
* @brief USART3 Initialization Function
* @param None
* @retval None
*/
static void MX_USART3_UART_Init(void)
{
/* USER CODE BEGIN USART3_Init 0 */
/* USER CODE END USART3_Init 0 */
/* USER CODE BEGIN USART3_Init 1 */
/* USER CODE END USART3_Init 1 */
huart3.Instance = USART3;
huart3.Init.BaudRate = 9600;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart3) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART3_Init 2 */
/* USER CODE END USART3_Init 2 */
}
/**
* @brief USB_OTG_FS Initialization Function
* @param None
@@ -1050,16 +1086,16 @@ static void MX_FSMC_Init(void)
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
// void Error_Handler(void)
// {
// /* USER CODE BEGIN Error_Handler_Debug */
// // /* User can add his own implementation to report the HAL error return state */
// // __disable_irq();
// // while (1)
// // {
// // }
// /* USER CODE END Error_Handler_Debug */
// }
#ifdef USE_FULL_ASSERT
/**

View File

@@ -867,6 +867,30 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart)
/* USER CODE END USART2_MspInit 1 */
}
else if(huart->Instance==USART3)
{
/* USER CODE BEGIN USART3_MspInit 0 */
/* USER CODE END USART3_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_USART3_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/**USART3 GPIO Configuration
PD8 ------> USART3_TX
PD9 ------> USART3_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* USER CODE BEGIN USART3_MspInit 1 */
/* USER CODE END USART3_MspInit 1 */
}
}
@@ -916,6 +940,24 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
/* USER CODE END USART2_MspDeInit 1 */
}
else if(huart->Instance==USART3)
{
/* USER CODE BEGIN USART3_MspDeInit 0 */
/* USER CODE END USART3_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USART3_CLK_DISABLE();
/**USART3 GPIO Configuration
PD8 ------> USART3_TX
PD9 ------> USART3_RX
*/
HAL_GPIO_DeInit(GPIOD, GPIO_PIN_8|GPIO_PIN_9);
/* USER CODE BEGIN USART3_MspDeInit 1 */
/* USER CODE END USART3_MspDeInit 1 */
}
}

View File

@@ -722,11 +722,19 @@ menu "On-chip Peripheral Drivers"
bool
default n
source "$(BSP_DIR)/libraries/HAL_Drivers/drivers/Kconfig"
config BSP_USING_USBD
bool "Enable OTGFS as USB device"
select RT_USING_USB_DEVICE
default n
endmenu
menu "Board extended module Drivers"
config BSP_USING_TEST
bool "Enable test driver"
default n
menuconfig BSP_USING_AT_ESP8266
bool "Enable ESP8266(AT Command, COM3)"
default n
@@ -757,7 +765,6 @@ menu "Board extended module Drivers"
comment "May adjust RT_SERIAL_RB_BUFSZ up to 512 if using the Serial V1 device driver"
endif
endmenu
endmenu

View File

@@ -18,7 +18,7 @@ path += [cwd + '/CubeMX_Config/Inc']
startup_path_prefix = SDK_LIB
if rtconfig.PLATFORM in ['gcc', 'llvm-arm']:
src += [startup_path_prefix + '/STM32F4xx_HAL/CMSIS/Device/ST/STM32F4xx/Source/Templates/gcc/startup_stm32f407xx.s']
src += [ cwd + '/startup_stm32f407xx.s']
elif rtconfig.PLATFORM in ['armcc', 'armclang']:
src += [startup_path_prefix + '/STM32F4xx_HAL/CMSIS/Device/ST/STM32F4xx/Source/Templates/arm/startup_stm32f407xx.s']
elif rtconfig.PLATFORM in ['iccarm']:

View File

@@ -46,3 +46,5 @@ void SystemClock_Config(void);
#endif
#define BSP_USING_USBDEVICE

View File

@@ -7,10 +7,9 @@
/* Program Entry, set to mark it as "used" and avoid gc */
MEMORY
{
CODE (rx) : ORIGIN = 0x08000000, LENGTH = 1024k /* 1024KB flash */
RAM1 (rw) : ORIGIN = 0x20000000, LENGTH = 128k /* 128K sram */
RAM2 (rw) : ORIGIN = 0x10000000, LENGTH = 64k /* 64K sram */
MCUlcdgrambysram (rw) : ORIGIN = 0x68000000, LENGTH = 1024k
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024k /* 1024KB - 128kB flash */
RAM (rw) : ORIGIN = 0x20000000, LENGTH = 128k /* 128K sram */
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64k /* 64K ccm sram */
}
ENTRY(Reset_Handler)
_system_stack_size = 0x400;
@@ -43,12 +42,6 @@ SECTIONS
KEEP(*(VSymTab))
__vsymtab_end = .;
/* section information for utest */
. = ALIGN(4);
__rt_utest_tc_tab_start = .;
KEEP(*(UtestTcTab))
__rt_utest_tc_tab_end = .;
/* section information for initial. */
. = ALIGN(4);
__rt_init_start = .;
@@ -62,12 +55,16 @@ SECTIONS
KEEP (*(.init_array))
PROVIDE(__ctors_end__ = .);
/* section information for utest */
. = ALIGN(4);
__rt_utest_tc_tab_start = .;
KEEP(*(UtestTcTab))
__rt_utest_tc_tab_end = .;
. = ALIGN(4);
KEEP(*(.eh_frame*))
. = ALIGN(4);
_etext = .;
} > CODE = 0
} > FLASH = 0
/* .ARM.exidx is sorted, so has to go in its own output section. */
__exidx_start = .;
@@ -77,12 +74,13 @@ SECTIONS
/* This is used by the startup in order to initialize the .data secion */
_sidata = .;
} > CODE
} > FLASH
__exidx_end = .;
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* .data section which is used for initialized data */
.data : AT (_sidata)
.data :
{
. = ALIGN(4);
/* This is used by the startup in order to initialize the .data secion */
@@ -100,7 +98,86 @@ SECTIONS
. = ALIGN(4);
/* This is used by the startup in order to initialize the .data secion */
_edata = . ;
} >RAM1
} >RAM AT> FLASH
_siccmdata = LOADADDR(.ccmdata); /* May be already present */
/* Initialized CCM-RAM section
*
* IMPORTANT NOTE!
* If initialized variables will be placed in this section,
* the startup code needs to be modified to copy the init-values.
*/
.ccmdata :
{
. = ALIGN(4);
_sccmdata = .; /* create a global symbol at data start */
*(.ccmdata) /* .data sections */
*(.ccmdata*) /* .data* sections */
/*
*data_reg.o(.data .data*)
*monitor*.o(.data .data*)
*sender*.o(.data .data*)
*kernel*.o(.data .data*)
*/
. = ALIGN(4);
_eccmdata = .; /* define a global symbol at data end */
} >CCMRAM AT> FLASH
/* _siccm_bss = LOADADDR(.ccm_bss); */
/* CCM-RAM section
*
* IMPORTANT NOTE!
* If initialized variables will be placed in this section,
* the startup code needs to be modified to copy the init-values.
*/
.ccm_bss :
{
. = ALIGN(4);
_sccm_bss = .; /* create a global symbol at ccmram start */
*(.ccm_bss)
*(.ccm_bss*)
/* build\\core\\*.o(.bss .bss*) */
build\\monitor\\**.o(.bss .bss*)
build\\sender\\**.o(.bss .bss*)
/* build\\mapping\\**.o(.bss .bss*) */
/* *board*.o(.bss .bss*) */
/* *autosave.o(.bss .bss*)*/
/* *application*autosave.o(.bss .bss*) */
/* *data_send.o(.bss .bss*) */
/* *isee_http.o(.bss .bss*) */
/* *config.o(.bss .bss*) */
/* *dio.o(.bss .bss*) */
/* *eth.o(.bss .bss*) */
/* *led.o(.bss .bss*) */
/* *packages*agile_telnet*.o(.bss .bss*) */
/* *packages*agile_console*.o(.bss .bss*) */
/* *packages*cJSON*.o(.bss .bss*) */
/* *packages*CmBacktrace*.o(.bss .bss*)*/
/* *packages*easyblink*.o(.bss .bss*) */
/* *packages*webclient*.o(.bss .bss*) */
/* *packages*netutils*.o(.bss .bss*) */
/* *packages*syswatch*.o(.bss .bss*) */
/* *packages*UrlEncode*.o(.bss .bss*) */
build\\kernel\\src\\*.o(.bss .bss*)
/* build\\kernel\\libcpu\\*.o(.bss .bss*) */
/* build\\kernel\\components\\libc\\*.o(.bss .bss*)
/* build\\kernel\\components\\drivers\\*.o(.bss .bss*) */
/* build\\kernel\\components\\dfs\\*.o(.bss .bss*) */
build\\kernel\\components\\net\\lwip\\lwip-2.0.3\\*.o(.bss .bss*)
/* build\\kernel\\components\\net\\lwip\\port\\**.o(.bss .bss*) */
/* build\\kernel\\components\\net\\sal\\*.o(.bss .bss*) */
/* build\\kernel\\components\\net\\netdev\\*.o(.bss .bss*) */
/* build\\kernel\\components\\net\\sal_socket\\*.o(.bss .bss*) */
. = ALIGN(4);
_eccm_bss = .; /* create a global symbol at ccmram end */
} >CCMRAM
.stack :
{
@@ -109,7 +186,7 @@ SECTIONS
. = . + _system_stack_size;
. = ALIGN(4);
_estack = .;
} >RAM1
} >RAM
__bss_start = .;
.bss :
@@ -127,18 +204,9 @@ SECTIONS
_ebss = . ;
*(.bss.init)
} > RAM1
} > RAM
__bss_end = .;
.MCUlcdgrambysram (NOLOAD) : ALIGN(4)
{
. = ALIGN(4);
*(.MCUlcdgrambysram)
*(.MCUlcdgrambysram.*)
. = ALIGN(4);
__MCUlcdgrambysram_free__ = .;
} > MCUlcdgrambysram
_end = .;
/* Stabs debugging sections. */

View File

@@ -1,16 +0,0 @@
from building import *
import os
cwd = GetCurrentDir()
group = []
src = Glob('*.c')
CPPPATH = [cwd]
list = os.listdir(cwd)
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
group = group + SConscript(os.path.join(d, 'SConscript'))
group = group + DefineGroup('cherryusb-port', src, depend = ['RT_CHERRYUSB_DEVICE'], CPPPATH = CPPPATH)
Return('group')

View File

@@ -1,53 +0,0 @@
/*
* Copyright (c) 2025, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-01-17 Supperthomas first version
*/
#include "board.h"
#include "rtthread.h"
#include "drv_config.h"
static PCD_HandleTypeDef hpcd_USB_OTG_FS;
void usb_dc_low_level_init(uint8_t busid)
{
hpcd_USB_OTG_FS.Instance = USB_OTG_FS;
HAL_PCD_MspInit(&hpcd_USB_OTG_FS);
}
void usb_dc_low_level_deinit(uint8_t busid)
{
HAL_PCD_MspDeInit(&hpcd_USB_OTG_FS);
}
#ifdef RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM
/* Register the EMAC device */
static int rt_hw_stm32_cherryusb_cdc_init(void)
{
extern void cdc_acm_init(uint8_t busid, uintptr_t reg_base);
cdc_acm_init(0, USB_OTG_FS_PERIPH_BASE);
return 0;
}
INIT_COMPONENT_EXPORT(rt_hw_stm32_cherryusb_cdc_init);
static int cherry_usb_cdc_send(int argc, char **argv)
{
extern void cdc_acm_data_send_with_dtr_test(uint8_t busid);
cdc_acm_data_send_with_dtr_test(0);
return 0;
}
MSH_CMD_EXPORT(cherry_usb_cdc_send, send the cdc data for test)
#endif
#ifdef USBD_IRQ_HANDLER
void USBD_IRQ_HANDLER(void)
{
extern void USBD_IRQHandler(uint8_t busid);
USBD_IRQHandler(0);
}
#else
#error USBD_IRQ_HANDLER need to USB IRQ like #define USBD_IRQ_HANDLER OTG_HS_IRQHandler
#endif

View File

@@ -1,239 +0,0 @@
/*
* Copyright (c) 2025, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-01-17 Supperthomas first version
*/
#ifndef CHERRYUSB_CONFIG_H
#define CHERRYUSB_CONFIG_H
/* ================ USB common Configuration ================ */
#define CONFIG_USB_PRINTF(...) printf(__VA_ARGS__)
#ifndef CONFIG_USB_DBG_LEVEL
#define CONFIG_USB_DBG_LEVEL USB_DBG_INFO
#endif
/* Enable print with color */
#define CONFIG_USB_PRINTF_COLOR_ENABLE
/* data align size when use dma */
#ifndef CONFIG_USB_ALIGN_SIZE
#define CONFIG_USB_ALIGN_SIZE 4
#endif
/* attribute data into no cache ram */
#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable")))
/* ================= USB Device Stack Configuration ================ */
/* Ep0 in and out transfer buffer */
#ifndef CONFIG_USBDEV_REQUEST_BUFFER_LEN
#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512
#endif
/* Setup packet log for debug */
// #define CONFIG_USBDEV_SETUP_LOG_PRINT
/* Check if the input descriptor is correct */
// #define CONFIG_USBDEV_DESC_CHECK
/* Enable test mode */
// #define CONFIG_USBDEV_TEST_MODE
#ifndef CONFIG_USBDEV_MSC_MAX_LUN
#define CONFIG_USBDEV_MSC_MAX_LUN 1
#endif
#ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE
#define CONFIG_USBDEV_MSC_MAX_BUFSIZE 512
#endif
#ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING
#define CONFIG_USBDEV_MSC_MANUFACTURER_STRING ""
#endif
#ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING
#define CONFIG_USBDEV_MSC_PRODUCT_STRING ""
#endif
#ifndef CONFIG_USBDEV_MSC_VERSION_STRING
#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01"
#endif
// #define CONFIG_USBDEV_MSC_THREAD
#ifndef CONFIG_USBDEV_MSC_PRIO
#define CONFIG_USBDEV_MSC_PRIO 4
#endif
#ifndef CONFIG_USBDEV_MSC_STACKSIZE
#define CONFIG_USBDEV_MSC_STACKSIZE 2048
#endif
#ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
#endif
#ifndef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 2048
#endif
#ifndef CONFIG_USBDEV_RNDIS_VENDOR_ID
#define CONFIG_USBDEV_RNDIS_VENDOR_ID 0x0000ffff
#endif
#ifndef CONFIG_USBDEV_RNDIS_VENDOR_DESC
#define CONFIG_USBDEV_RNDIS_VENDOR_DESC "CherryUSB"
#endif
#define CONFIG_USBDEV_RNDIS_USING_LWIP
/* ================ USB HOST Stack Configuration ================== */
#define CONFIG_USBHOST_MAX_RHPORTS 1
#define CONFIG_USBHOST_MAX_EXTHUBS 1
#define CONFIG_USBHOST_MAX_EHPORTS 4
#define CONFIG_USBHOST_MAX_INTERFACES 8
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 8
#define CONFIG_USBHOST_MAX_ENDPOINTS 4
#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
#define CONFIG_USBHOST_MAX_HID_CLASS 4
#define CONFIG_USBHOST_MAX_MSC_CLASS 2
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1
#define CONFIG_USBHOST_MAX_VIDEO_CLASS 1
#define CONFIG_USBHOST_DEV_NAMELEN 16
#ifndef CONFIG_USBHOST_PSC_PRIO
#define CONFIG_USBHOST_PSC_PRIO 0
#endif
#ifndef CONFIG_USBHOST_PSC_STACKSIZE
#define CONFIG_USBHOST_PSC_STACKSIZE 2048
#endif
//#define CONFIG_USBHOST_GET_STRING_DESC
// #define CONFIG_USBHOST_MSOS_ENABLE
#ifndef CONFIG_USBHOST_MSOS_VENDOR_CODE
#define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00
#endif
/* Ep0 max transfer buffer */
#ifndef CONFIG_USBHOST_REQUEST_BUFFER_LEN
#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 512
#endif
#ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
#define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500
#endif
#ifndef CONFIG_USBHOST_MSC_TIMEOUT
#define CONFIG_USBHOST_MSC_TIMEOUT 5000
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change with 2K,4K,8K,16K,default is 2K to get one TCP_MSS
*/
#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE (2048)
#endif
#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE (2048)
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change with 2K,4K,8K,16K,default is 2K to get one TCP_MSS
*/
#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE (2048)
#endif
#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE (2048)
#endif
#define CONFIG_USBHOST_BLUETOOTH_HCI_H4
// #define CONFIG_USBHOST_BLUETOOTH_HCI_LOG
#ifndef CONFIG_USBHOST_BLUETOOTH_TX_SIZE
#define CONFIG_USBHOST_BLUETOOTH_TX_SIZE 2048
#endif
#ifndef CONFIG_USBHOST_BLUETOOTH_RX_SIZE
#define CONFIG_USBHOST_BLUETOOTH_RX_SIZE 2048
#endif
/* ================ USB Device Port Configuration ================*/
#ifndef CONFIG_USBDEV_MAX_BUS
#define CONFIG_USBDEV_MAX_BUS 1 // for now, bus num must be 1 except hpm ip
#endif
#ifndef CONFIG_USBDEV_EP_NUM
#define CONFIG_USBDEV_EP_NUM 4
#endif
/* ---------------- FSDEV Configuration ---------------- */
//#define CONFIG_USBDEV_FSDEV_PMA_ACCESS 2 // maybe 1 or 2, many chips may have a difference
/* ---------------- DWC2 Configuration ---------------- */
// #define CONFIG_USB_DWC2_RXALL_FIFO_SIZE (1024 / 4)
#define CONFIG_USB_DWC2_TX0_FIFO_SIZE (64 / 4)
#define CONFIG_USB_DWC2_TX1_FIFO_SIZE (64 / 4)
#define CONFIG_USB_DWC2_TX2_FIFO_SIZE (64 / 4)
#define CONFIG_USB_DWC2_TX3_FIFO_SIZE (64 / 4)
// #define CONFIG_USB_DWC2_TX4_FIFO_SIZE (0 / 4)
// #define CONFIG_USB_DWC2_TX5_FIFO_SIZE (0 / 4)
// #define CONFIG_USB_DWC2_TX6_FIFO_SIZE (0 / 4)
// #define CONFIG_USB_DWC2_TX7_FIFO_SIZE (0 / 4)
// #define CONFIG_USB_DWC2_TX8_FIFO_SIZE (0 / 4)
/* ---------------- MUSB Configuration ---------------- */
// #define CONFIG_USB_MUSB_SUNXI
/* ================ USB Host Port Configuration ==================*/
#ifndef CONFIG_USBHOST_MAX_BUS
#define CONFIG_USBHOST_MAX_BUS 1
#endif
#ifndef CONFIG_USBHOST_PIPE_NUM
#define CONFIG_USBHOST_PIPE_NUM 12
#endif
/* ---------------- EHCI Configuration ---------------- */
#define CONFIG_USB_EHCI_HCCR_OFFSET (0x0)
#define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024
#define CONFIG_USB_EHCI_QH_NUM CONFIG_USBHOST_PIPE_NUM
#define CONFIG_USB_EHCI_QTD_NUM 3
#define CONFIG_USB_EHCI_ITD_NUM 20
// #define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
// #define CONFIG_USB_EHCI_CONFIGFLAG
// #define CONFIG_USB_EHCI_ISO
// #define CONFIG_USB_EHCI_WITH_OHCI
/* ---------------- OHCI Configuration ---------------- */
#define CONFIG_USB_OHCI_HCOR_OFFSET (0x0)
/* ---------------- XHCI Configuration ---------------- */
#define CONFIG_USB_XHCI_HCCR_OFFSET (0x0)
/* ---------------- DWC2 Configuration ---------------- */
/* largest non-periodic USB packet used / 4 */
// #define CONFIG_USB_DWC2_NPTX_FIFO_SIZE (512 / 4)
/* largest periodic USB packet used / 4 */
// #define CONFIG_USB_DWC2_PTX_FIFO_SIZE (1024 / 4)
/*
* (largest USB packet used / 4) + 1 for status information + 1 transfer complete +
* 1 location each for Bulk/Control endpoint for handling NAK/NYET scenario
*/
// #define CONFIG_USB_DWC2_RX_FIFO_SIZE ((1012 - CONFIG_USB_DWC2_NPTX_FIFO_SIZE - CONFIG_USB_DWC2_PTX_FIFO_SIZE))
/* ---------------- MUSB Configuration ---------------- */
// #define CONFIG_USB_MUSB_SUNXI
#endif

View File

@@ -56,6 +56,7 @@ static int onboard_fal_mount(void)
fal_init();
/* 在 spi flash 中名为 "filesystem" 的分区上创建一个块设备 */
struct rt_device *flash_dev = fal_blk_device_create(FS_PARTITION_NAME);
// fal_blk_device_create("font");
if (flash_dev == NULL)
{
LOG_E("Can't create a block device on '%s' partition.", FS_PARTITION_NAME);
@@ -71,11 +72,51 @@ static int onboard_fal_mount(void)
LOG_I("Filesystem initialized!");
}
else
{
dfs_mkfs("elm", flash_dev->parent.name);
if (dfs_mount(flash_dev->parent.name, "/fal", "elm", 0, 0) == 0)
{
LOG_I("Filesystem initialized!");
}
else
{
LOG_E("Failed to initialize filesystem!");
LOG_D("You should create a filesystem on the block device first!");
}
}
int ret;
// /* 创建目录 */
// ret = mkdir("/fal/test", 0x777);
// if (ret < 0)
// {
// /* 创建目录失败 */
// rt_kprintf("dir error!\n");
// }
// else
// {
// /* 创建目录成功 */
// rt_kprintf("mkdir ok!\n");
// }
// /* 挂载块设备"font"到 DFS 目录/fal/test中 */
// if (dfs_mount("font", "/fal/test", "elm", 0, 0) == 0)
// {
// LOG_I("font initialized!");
// }
// else
// {
// dfs_mkfs("elm", "font");
// if (dfs_mount("font", "/fal/test", "elm", 0, 0) == 0)
// {
// LOG_I("font initialized!");
// }
// else
// {
// LOG_E("Failed to initialize font!");
// LOG_D("You should create a filesystem(font) on the block device first!");
// }
// }
return RT_EOK;
}
#endif /*BSP_USING_FLASH_FATFS*/

View File

@@ -57,7 +57,7 @@ static const struct fal_partition *part = NULL;
*
* @return result
*/
EfErrCode ef_port_init(ef_env const **default_env, rt_size_t *default_env_size) {
EfErrCode ef_port_init(ef_env const **default_env, size_t *default_env_size) {
EfErrCode result = EF_NO_ERR;
*default_env = default_env_set;
@@ -81,10 +81,10 @@ EfErrCode ef_port_init(ef_env const **default_env, rt_size_t *default_env_size)
*
* @return result
*/
EfErrCode ef_port_read(rt_uint32_t addr, rt_uint32_t *buf, rt_size_t size) {
EfErrCode ef_port_read(uint32_t addr, uint32_t *buf, size_t size) {
EfErrCode result = EF_NO_ERR;
fal_partition_read(part, addr, (rt_uint8_t *)buf, size);
fal_partition_read(part, addr, (uint8_t *)buf, size);
return result;
}
@@ -99,7 +99,7 @@ EfErrCode ef_port_read(rt_uint32_t addr, rt_uint32_t *buf, rt_size_t size) {
*
* @return result
*/
EfErrCode ef_port_erase(rt_uint32_t addr, rt_size_t size) {
EfErrCode ef_port_erase(uint32_t addr, size_t size) {
EfErrCode result = EF_NO_ERR;
/* make sure the start address is a multiple of FLASH_ERASE_MIN_SIZE */
@@ -123,10 +123,10 @@ EfErrCode ef_port_erase(rt_uint32_t addr, rt_size_t size) {
*
* @return result
*/
EfErrCode ef_port_write(rt_uint32_t addr, const rt_uint32_t *buf, rt_size_t size) {
EfErrCode ef_port_write(uint32_t addr, const uint32_t *buf, size_t size) {
EfErrCode result = EF_NO_ERR;
if (fal_partition_write(part, addr, (rt_uint8_t *)buf, size) < 0)
if (fal_partition_write(part, addr, (uint8_t *)buf, size) < 0)
{
result = EF_WRITE_ERR;
}

View File

@@ -12,13 +12,13 @@
#include <sfud.h>
#ifdef RT_USING_SFUD
#include <dev_spi_flash_sfud.h>
#include <spi_flash_sfud.h>
#endif
static int init(void);
static int read(long offset, rt_uint8_t *buf, rt_size_t size);
static int write(long offset, const rt_uint8_t *buf, rt_size_t size);
static int erase(long offset, rt_size_t size);
static int read(long offset, uint8_t *buf, size_t size);
static int write(long offset, const uint8_t *buf, size_t size);
static int erase(long offset, size_t size);
static sfud_flash_t sfud_dev = NULL;
struct fal_flash_dev w25q64 =
@@ -46,19 +46,19 @@ static int init(void)
return 0;
}
static int read(long offset, rt_uint8_t *buf, rt_size_t size)
static int read(long offset, uint8_t *buf, size_t size)
{
RT_ASSERT(sfud_dev);
RT_ASSERT(sfud_dev->init_ok);
assert(sfud_dev);
assert(sfud_dev->init_ok);
sfud_read(sfud_dev, w25q64.addr + offset, size, buf);
return size;
}
static int write(long offset, const rt_uint8_t *buf, rt_size_t size)
static int write(long offset, const uint8_t *buf, size_t size)
{
RT_ASSERT(sfud_dev);
RT_ASSERT(sfud_dev->init_ok);
assert(sfud_dev);
assert(sfud_dev->init_ok);
if (sfud_write(sfud_dev, w25q64.addr + offset, size, buf) != SFUD_SUCCESS)
{
return -1;
@@ -67,10 +67,10 @@ static int write(long offset, const rt_uint8_t *buf, rt_size_t size)
return size;
}
static int erase(long offset, rt_size_t size)
static int erase(long offset, size_t size)
{
RT_ASSERT(sfud_dev);
RT_ASSERT(sfud_dev->init_ok);
assert(sfud_dev);
assert(sfud_dev->init_ok);
if (sfud_erase(sfud_dev, w25q64.addr + offset, size) != SFUD_SUCCESS)
{
return -1;

View File

@@ -45,16 +45,19 @@ const uint8_t tile[] = {2, 7};
// 常见颜色定义
const RGBColor_TypeDef DARK = {0, 0, 0};
const RGBColor_TypeDef GREEN = {255, 0, 0};
const RGBColor_TypeDef RED = {0, 255, 0};
const RGBColor_TypeDef BLUE = {0, 0, 255};
const RGBColor_TypeDef WHITE = {255, 255, 255};
const RGBColor_TypeDef LED_DARK = {0, 0, 0};
const RGBColor_TypeDef LED_GREEN = {255, 0, 0};
const RGBColor_TypeDef LED_RED = {0, 255, 0};
const RGBColor_TypeDef LED_BLUE = {0, 0, 255};
const RGBColor_TypeDef LED_WHITE = {255, 255, 255};
const RGBColor_TypeDef LT_RED = {0, 32, 0};
const RGBColor_TypeDef LT_GREEN = {32, 0, 0};
const RGBColor_TypeDef LT_BLUE = {0, 0, 32};
const RGBColor_TypeDef LT_WHITE = {16, 16, 16};
// 灯颜色缓存
RGBColor_TypeDef RGB_Data[LED_NUM] = {0};
@@ -247,16 +250,16 @@ void led_matrix_fill_test(uint8_t index)
void led_matrix_test1()
{
rt_memset(RGB_Data, 0x00, sizeof(RGB_Data));
Set_LEDColor(0, RED);
Set_LEDColor(1, GREEN);
Set_LEDColor(2, BLUE);
Set_LEDColor(3, RED);
Set_LEDColor(4, GREEN);
Set_LEDColor(5, BLUE);
Set_LEDColor(6, RED);
Set_LEDColor(7, GREEN);
Set_LEDColor(8, BLUE);
Set_LEDColor(9, WHITE);
Set_LEDColor(0, LED_RED);
Set_LEDColor(1, LED_GREEN);
Set_LEDColor(2, LED_BLUE);
Set_LEDColor(3, LED_RED);
Set_LEDColor(4, LED_GREEN);
Set_LEDColor(5, LED_BLUE);
Set_LEDColor(6, LED_RED);
Set_LEDColor(7, LED_GREEN);
Set_LEDColor(8, LED_BLUE);
Set_LEDColor(9, LED_WHITE);
// led_matrix_rst();
RGB_Reflash();
}
@@ -265,22 +268,22 @@ MSH_CMD_EXPORT(led_matrix_test1, Test led matrix on board)
void led_matrix_test2()
{
rt_memset(RGB_Data, 0x00, sizeof(RGB_Data));
Set_LEDColor(0, BLUE);
Set_LEDColor(1, RED);
Set_LEDColor(2, GREEN);
Set_LEDColor(3, BLUE);
Set_LEDColor(4, RED);
Set_LEDColor(5, GREEN);
Set_LEDColor(6, BLUE);
Set_LEDColor(7, RED);
Set_LEDColor(8, GREEN);
Set_LEDColor(9, RED);
Set_LEDColor(0, LED_BLUE);
Set_LEDColor(1, LED_RED);
Set_LEDColor(2, LED_GREEN);
Set_LEDColor(3, LED_BLUE);
Set_LEDColor(4, LED_RED);
Set_LEDColor(5, LED_GREEN);
Set_LEDColor(6, LED_BLUE);
Set_LEDColor(7, LED_RED);
Set_LEDColor(8, LED_GREEN);
Set_LEDColor(9, LED_RED);
Set_LEDColor(14, GREEN);
Set_LEDColor(15, GREEN);
Set_LEDColor(16, BLUE);
Set_LEDColor(17, RED);
Set_LEDColor(18, WHITE);
Set_LEDColor(14, LED_GREEN);
Set_LEDColor(15, LED_GREEN);
Set_LEDColor(16, LED_BLUE);
Set_LEDColor(17, LED_RED);
Set_LEDColor(18, LED_WHITE);
RGB_Reflash();
}

View File

@@ -9,13 +9,19 @@ typedef struct RGBColor_TypeDef
uint8_t B;
} RGBColor_TypeDef; // 颜色结构体
// extern const RGBColor_TypeDef DARK;
// extern const RGBColor_TypeDef GREEN;
// extern const RGBColor_TypeDef RED;
// extern const RGBColor_TypeDef BLUE;
// extern const RGBColor_TypeDef WHITE;
// //灯处于特定颜色还是闪烁状态
// extern uint8_t LED_Blink_Staue[LED_NUM]={0};
// // 灯闪烁颜色缓存
// extern RGBColor_TypeDef LED_Blink_Color[LED_NUM] = {0};
extern const RGBColor_TypeDef LED_DARK;
extern const RGBColor_TypeDef LED_GREEN;
extern const RGBColor_TypeDef LED_RED;
extern const RGBColor_TypeDef LED_BLUE;
extern const RGBColor_TypeDef LED_WHITE;
extern void Set_LEDColor(uint16_t LedId, RGBColor_TypeDef Color);
extern void RGB_Reflash(void);
extern void led_matrix_rst();
#endif

View File

@@ -14,12 +14,13 @@
#include <rtconfig.h>
#define LV_COLOR_DEPTH 16
#define LV_USE_PERF_MONITOR 1
#define MY_DISP_HOR_RES 240
#define MY_DISP_VER_RES 240
//#define LV_USE_LOG 1
/* music player demo */
#ifdef PKG_USING_LV_MUSIC_DEMO
#define LV_USE_DEMO_MUSIC 1
/* music player demo */
#define LV_HOR_RES_MAX MY_DISP_HOR_RES
#define LV_VER_RES_MAX MY_DISP_VER_RES
#define LV_USE_DEMO_RTT_MUSIC 1
@@ -27,14 +28,16 @@
#define LV_FONT_MONTSERRAT_12 1
#define LV_FONT_MONTSERRAT_16 1
#define LV_COLOR_SCREEN_TRANSP 1
#endif
#define LV_USE_SYSMON 1
#define LV_USE_PERF_MONITOR 1
#define LV_USE_DEMO_WIDGETS 1
#define LV_FONT_MONTSERRAT_20 1
#define LV_FONT_MONTSERRAT_24 1
#define LV_FONT_MONTSERRAT_26 1
#define LV_USE_DEMO_BENCHMARK 1
//#define LV_USE_DEMO_WIDGETS 1
//#define LV_USE_DEMO_MUSIC 1
#endif

View File

@@ -26,14 +26,6 @@
#define MY_DISP_VER_RES 240
#endif
#if (PKG_LVGL_VER_NUM >= 0x090000)
#define LV_DISP_TYPE lv_display_t
#define lv_COLOR_TYPE uint8_t
#else
#define LV_DISP_TYPE lv_disp_drv_t
#define lv_COLOR_TYPE lv_color_t
#endif
/**********************
* TYPEDEFS
**********************/
@@ -43,7 +35,9 @@
**********************/
static void disp_init(void);
static void disp_flush(LV_DISP_TYPE * disp_drv, const lv_area_t * area, lv_COLOR_TYPE * color_p);
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
//static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
// const lv_area_t * fill_area, lv_color_t color);
/**********************
* STATIC VARIABLES
@@ -89,6 +83,9 @@ void lv_port_disp_init(void)
* and you only need to change the frame buffer's address.
*/
/* Example for 1) */
static lv_disp_draw_buf_t draw_buf_dsc_1;
/*GCC*/
#if defined ( __GNUC__ )
static lv_color_t buf_1[MY_DISP_HOR_RES * MY_DISP_HOR_RES / 2] __attribute__((section(".LVGLccm"))); /*A buffer for 10 rows*/
@@ -97,29 +94,16 @@ void lv_port_disp_init(void)
__attribute__((at(0x10000000))) lv_color_t buf_1[LCD_H * LCD_W / 2];
#endif
/*-----------------------------------
* Register the display in LVGL
*----------------------------------*/
#if (PKG_LVGL_VER_NUM >= 0x090000)
lv_display_t *display = lv_display_create(MY_DISP_HOR_RES, MY_DISP_VER_RES);
lv_display_set_buffers(display, buf_1, NULL, sizeof(buf_1), LV_DISPLAY_RENDER_MODE_PARTIAL); /*Initialize the display buffer.*/
lv_display_set_flush_cb(display, disp_flush);
#else
/* Example for 1) */
static lv_disp_draw_buf_t draw_buf_dsc_1;
lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * MY_DISP_HOR_RES / 2); /*Initialize the display buffer*/
/*-----------------------------------
* Register the display in LVGL
*----------------------------------*/
static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
/*Set up the functions to access to your display*/
/*Set the resolution of the display*/
disp_drv.hor_res = MY_DISP_HOR_RES;
disp_drv.ver_res = MY_DISP_VER_RES;
@@ -130,11 +114,16 @@ void lv_port_disp_init(void)
/*Set a display buffer*/
disp_drv.draw_buf = &draw_buf_dsc_1;
/*Required for Example 3)*/
//disp_drv.full_refresh = 1;
/* Fill a memory array with a color if you have GPU.
* Note that, in lv_conf.h you can enable GPUs that has built-in support in LVGL.
* But if you have a different GPU you can use with this callback.*/
//disp_drv.gpu_fill_cb = gpu_fill;
/*Finally register the driver*/
lv_disp_drv_register(&disp_drv);
#endif
}
/**********************
@@ -166,13 +155,32 @@ void disp_disable_update(void)
/*Flush the content of the internal buffer the specific area on the display
*You can use DMA or any hardware acceleration to do this operation in the background but
*'lv_disp_flush_ready()' has to be called when finished.*/
static void disp_flush(LV_DISP_TYPE * disp_drv, const lv_area_t * area, lv_COLOR_TYPE * color_p)
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
extern void lcd_fill_array(rt_uint16_t x_start, rt_uint16_t y_start, rt_uint16_t x_end, rt_uint16_t y_end, void *pcolor);
lcd_fill_array(area->x1, area->y1, area->x2, area->y2, color_p);
lv_disp_flush_ready(disp_drv);
}
/*OPTIONAL: GPU INTERFACE*/
/*If your MCU has hardware accelerator (GPU) then you can use it to fill a memory with a color*/
//static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
// const lv_area_t * fill_area, lv_color_t color)
//{
// /*It's an example code which should be done by your GPU*/
// int32_t x, y;
// dest_buf += dest_width * fill_area->y1; /*Go to the first line*/
//
// for(y = fill_area->y1; y <= fill_area->y2; y++) {
// for(x = fill_area->x1; x <= fill_area->x2; x++) {
// dest_buf[x] = color;
// }
// dest_buf+=dest_width; /*Go to the next line*/
// }
//}
#else /*Enable this file at the top*/

View File

@@ -9,8 +9,8 @@
*/
#include <rtthread.h>
#include "dev_spi_flash.h"
#include "dev_spi_flash_sfud.h"
#include "spi_flash.h"
#include "spi_flash_sfud.h"
#include <drv_spi.h>
#include <drv_soft_spi.h>

View File

@@ -9,8 +9,8 @@
*/
#include <rtthread.h>
#include "dev_spi_flash.h"
#include "dev_spi_flash_sfud.h"
#include "spi_flash.h"
#include "spi_flash_sfud.h"
#include <drv_spi.h>
#include <drv_gpio.h>

535
board/startup_stm32f407xx.s Normal file
View File

@@ -0,0 +1,535 @@
/**
******************************************************************************
* @file startup_stm32f407xx.s
* @author MCD Application Team
* @brief STM32F407xx Devices vector table for GCC based toolchains.
* This module performs:
* - Set the initial SP
* - Set the initial PC == Reset_Handler,
* - Set the vector table entries with the exceptions ISR address
* - Branches to main in the C library (which eventually
* calls main()).
* After Reset the Cortex-M4 processor is in Thread mode,
* priority is Privileged, and the Stack is set to Main.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
.syntax unified
.cpu cortex-m4
.fpu softvfp
.thumb
.global g_pfnVectors
.global Default_Handler
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
/* start address for the .bss section. defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss
/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
/**
* @brief This is the code that gets called when the processor first
* starts execution following a reset event. Only the absolutely
* necessary set is performed, after which the application
* supplied main() routine is called.
* @param None
* @retval : None
*/
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
ldr sp, =_estack /* set stack pointer */
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
/* Copy from flash to CCMRAM */
ldr r0, =_sccmdata
ldr r1, =_eccmdata
ldr r2, =_siccmdata
movs r3, #0
b LoopCopyCcmInit
CopyCcmInit:
ldr r4, [r2, r3]
str r4, [r0, r3]
adds r3, r3, #4
LoopCopyCcmInit:
adds r4, r0, r3
cmp r4, r1
bcc CopyCcmInit
/* End of copy to CCMRAM */
ldr r2, =_sccm_bss
b LoopFillZeroCcm
/* Zero fill the ccm bss segment. */
FillZeroCcm:
movs r3, #0
str r3, [r2], #4
LoopFillZeroCcm:
ldr r3, = _eccm_bss
cmp r2, r3
bcc FillZeroCcm
/* End of zero fill to CCMRAM */
ldr r2, =_sbss
b LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, [r2], #4
LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss
/* Call the clock system intitialization function.*/
bl SystemInit
/* Call static constructors */
/* bl __libc_init_array */
/* Call the application's entry point.*/
bl entry
bx lr
.size Reset_Handler, .-Reset_Handler
/**
* @brief This is the code that gets called when the processor receives an
* unexpected interrupt. This simply enters an infinite loop, preserving
* the system state for examination by a debugger.
* @param None
* @retval None
*/
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
/******************************************************************************
*
* The minimal vector table for a Cortex M3. Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
*******************************************************************************/
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word DebugMon_Handler
.word 0
.word PendSV_Handler
.word SysTick_Handler
/* External Interrupts */
.word WWDG_IRQHandler /* Window WatchDog */
.word PVD_IRQHandler /* PVD through EXTI Line detection */
.word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */
.word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
.word FLASH_IRQHandler /* FLASH */
.word RCC_IRQHandler /* RCC */
.word EXTI0_IRQHandler /* EXTI Line0 */
.word EXTI1_IRQHandler /* EXTI Line1 */
.word EXTI2_IRQHandler /* EXTI Line2 */
.word EXTI3_IRQHandler /* EXTI Line3 */
.word EXTI4_IRQHandler /* EXTI Line4 */
.word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */
.word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */
.word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */
.word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */
.word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */
.word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */
.word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */
.word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */
.word CAN1_TX_IRQHandler /* CAN1 TX */
.word CAN1_RX0_IRQHandler /* CAN1 RX0 */
.word CAN1_RX1_IRQHandler /* CAN1 RX1 */
.word CAN1_SCE_IRQHandler /* CAN1 SCE */
.word EXTI9_5_IRQHandler /* External Line[9:5]s */
.word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */
.word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */
.word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */
.word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
.word TIM2_IRQHandler /* TIM2 */
.word TIM3_IRQHandler /* TIM3 */
.word TIM4_IRQHandler /* TIM4 */
.word I2C1_EV_IRQHandler /* I2C1 Event */
.word I2C1_ER_IRQHandler /* I2C1 Error */
.word I2C2_EV_IRQHandler /* I2C2 Event */
.word I2C2_ER_IRQHandler /* I2C2 Error */
.word SPI1_IRQHandler /* SPI1 */
.word SPI2_IRQHandler /* SPI2 */
.word USART1_IRQHandler /* USART1 */
.word USART2_IRQHandler /* USART2 */
.word USART3_IRQHandler /* USART3 */
.word EXTI15_10_IRQHandler /* External Line[15:10]s */
.word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */
.word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */
.word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */
.word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */
.word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */
.word TIM8_CC_IRQHandler /* TIM8 Capture Compare */
.word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */
.word FSMC_IRQHandler /* FSMC */
.word SDIO_IRQHandler /* SDIO */
.word TIM5_IRQHandler /* TIM5 */
.word SPI3_IRQHandler /* SPI3 */
.word UART4_IRQHandler /* UART4 */
.word UART5_IRQHandler /* UART5 */
.word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */
.word TIM7_IRQHandler /* TIM7 */
.word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */
.word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */
.word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */
.word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */
.word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */
.word ETH_IRQHandler /* Ethernet */
.word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */
.word CAN2_TX_IRQHandler /* CAN2 TX */
.word CAN2_RX0_IRQHandler /* CAN2 RX0 */
.word CAN2_RX1_IRQHandler /* CAN2 RX1 */
.word CAN2_SCE_IRQHandler /* CAN2 SCE */
.word OTG_FS_IRQHandler /* USB OTG FS */
.word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */
.word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */
.word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */
.word USART6_IRQHandler /* USART6 */
.word I2C3_EV_IRQHandler /* I2C3 event */
.word I2C3_ER_IRQHandler /* I2C3 error */
.word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */
.word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */
.word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */
.word OTG_HS_IRQHandler /* USB OTG HS */
.word DCMI_IRQHandler /* DCMI */
.word 0 /* CRYP crypto */
.word HASH_RNG_IRQHandler /* Hash and Rng */
.word FPU_IRQHandler /* FPU */
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
.weak MemManage_Handler
.thumb_set MemManage_Handler,Default_Handler
.weak BusFault_Handler
.thumb_set BusFault_Handler,Default_Handler
.weak UsageFault_Handler
.thumb_set UsageFault_Handler,Default_Handler
.weak SVC_Handler
.thumb_set SVC_Handler,Default_Handler
.weak DebugMon_Handler
.thumb_set DebugMon_Handler,Default_Handler
.weak PendSV_Handler
.thumb_set PendSV_Handler,Default_Handler
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
.weak WWDG_IRQHandler
.thumb_set WWDG_IRQHandler,Default_Handler
.weak PVD_IRQHandler
.thumb_set PVD_IRQHandler,Default_Handler
.weak TAMP_STAMP_IRQHandler
.thumb_set TAMP_STAMP_IRQHandler,Default_Handler
.weak RTC_WKUP_IRQHandler
.thumb_set RTC_WKUP_IRQHandler,Default_Handler
.weak FLASH_IRQHandler
.thumb_set FLASH_IRQHandler,Default_Handler
.weak RCC_IRQHandler
.thumb_set RCC_IRQHandler,Default_Handler
.weak EXTI0_IRQHandler
.thumb_set EXTI0_IRQHandler,Default_Handler
.weak EXTI1_IRQHandler
.thumb_set EXTI1_IRQHandler,Default_Handler
.weak EXTI2_IRQHandler
.thumb_set EXTI2_IRQHandler,Default_Handler
.weak EXTI3_IRQHandler
.thumb_set EXTI3_IRQHandler,Default_Handler
.weak EXTI4_IRQHandler
.thumb_set EXTI4_IRQHandler,Default_Handler
.weak DMA1_Stream0_IRQHandler
.thumb_set DMA1_Stream0_IRQHandler,Default_Handler
.weak DMA1_Stream1_IRQHandler
.thumb_set DMA1_Stream1_IRQHandler,Default_Handler
.weak DMA1_Stream2_IRQHandler
.thumb_set DMA1_Stream2_IRQHandler,Default_Handler
.weak DMA1_Stream3_IRQHandler
.thumb_set DMA1_Stream3_IRQHandler,Default_Handler
.weak DMA1_Stream4_IRQHandler
.thumb_set DMA1_Stream4_IRQHandler,Default_Handler
.weak DMA1_Stream5_IRQHandler
.thumb_set DMA1_Stream5_IRQHandler,Default_Handler
.weak DMA1_Stream6_IRQHandler
.thumb_set DMA1_Stream6_IRQHandler,Default_Handler
.weak ADC_IRQHandler
.thumb_set ADC_IRQHandler,Default_Handler
.weak CAN1_TX_IRQHandler
.thumb_set CAN1_TX_IRQHandler,Default_Handler
.weak CAN1_RX0_IRQHandler
.thumb_set CAN1_RX0_IRQHandler,Default_Handler
.weak CAN1_RX1_IRQHandler
.thumb_set CAN1_RX1_IRQHandler,Default_Handler
.weak CAN1_SCE_IRQHandler
.thumb_set CAN1_SCE_IRQHandler,Default_Handler
.weak EXTI9_5_IRQHandler
.thumb_set EXTI9_5_IRQHandler,Default_Handler
.weak TIM1_BRK_TIM9_IRQHandler
.thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler
.weak TIM1_UP_TIM10_IRQHandler
.thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler
.weak TIM1_TRG_COM_TIM11_IRQHandler
.thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler
.weak TIM1_CC_IRQHandler
.thumb_set TIM1_CC_IRQHandler,Default_Handler
.weak TIM2_IRQHandler
.thumb_set TIM2_IRQHandler,Default_Handler
.weak TIM3_IRQHandler
.thumb_set TIM3_IRQHandler,Default_Handler
.weak TIM4_IRQHandler
.thumb_set TIM4_IRQHandler,Default_Handler
.weak I2C1_EV_IRQHandler
.thumb_set I2C1_EV_IRQHandler,Default_Handler
.weak I2C1_ER_IRQHandler
.thumb_set I2C1_ER_IRQHandler,Default_Handler
.weak I2C2_EV_IRQHandler
.thumb_set I2C2_EV_IRQHandler,Default_Handler
.weak I2C2_ER_IRQHandler
.thumb_set I2C2_ER_IRQHandler,Default_Handler
.weak SPI1_IRQHandler
.thumb_set SPI1_IRQHandler,Default_Handler
.weak SPI2_IRQHandler
.thumb_set SPI2_IRQHandler,Default_Handler
.weak USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler
.weak USART2_IRQHandler
.thumb_set USART2_IRQHandler,Default_Handler
.weak USART3_IRQHandler
.thumb_set USART3_IRQHandler,Default_Handler
.weak EXTI15_10_IRQHandler
.thumb_set EXTI15_10_IRQHandler,Default_Handler
.weak RTC_Alarm_IRQHandler
.thumb_set RTC_Alarm_IRQHandler,Default_Handler
.weak OTG_FS_WKUP_IRQHandler
.thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler
.weak TIM8_BRK_TIM12_IRQHandler
.thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler
.weak TIM8_UP_TIM13_IRQHandler
.thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler
.weak TIM8_TRG_COM_TIM14_IRQHandler
.thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler
.weak TIM8_CC_IRQHandler
.thumb_set TIM8_CC_IRQHandler,Default_Handler
.weak DMA1_Stream7_IRQHandler
.thumb_set DMA1_Stream7_IRQHandler,Default_Handler
.weak FSMC_IRQHandler
.thumb_set FSMC_IRQHandler,Default_Handler
.weak SDIO_IRQHandler
.thumb_set SDIO_IRQHandler,Default_Handler
.weak TIM5_IRQHandler
.thumb_set TIM5_IRQHandler,Default_Handler
.weak SPI3_IRQHandler
.thumb_set SPI3_IRQHandler,Default_Handler
.weak UART4_IRQHandler
.thumb_set UART4_IRQHandler,Default_Handler
.weak UART5_IRQHandler
.thumb_set UART5_IRQHandler,Default_Handler
.weak TIM6_DAC_IRQHandler
.thumb_set TIM6_DAC_IRQHandler,Default_Handler
.weak TIM7_IRQHandler
.thumb_set TIM7_IRQHandler,Default_Handler
.weak DMA2_Stream0_IRQHandler
.thumb_set DMA2_Stream0_IRQHandler,Default_Handler
.weak DMA2_Stream1_IRQHandler
.thumb_set DMA2_Stream1_IRQHandler,Default_Handler
.weak DMA2_Stream2_IRQHandler
.thumb_set DMA2_Stream2_IRQHandler,Default_Handler
.weak DMA2_Stream3_IRQHandler
.thumb_set DMA2_Stream3_IRQHandler,Default_Handler
.weak DMA2_Stream4_IRQHandler
.thumb_set DMA2_Stream4_IRQHandler,Default_Handler
.weak ETH_IRQHandler
.thumb_set ETH_IRQHandler,Default_Handler
.weak ETH_WKUP_IRQHandler
.thumb_set ETH_WKUP_IRQHandler,Default_Handler
.weak CAN2_TX_IRQHandler
.thumb_set CAN2_TX_IRQHandler,Default_Handler
.weak CAN2_RX0_IRQHandler
.thumb_set CAN2_RX0_IRQHandler,Default_Handler
.weak CAN2_RX1_IRQHandler
.thumb_set CAN2_RX1_IRQHandler,Default_Handler
.weak CAN2_SCE_IRQHandler
.thumb_set CAN2_SCE_IRQHandler,Default_Handler
.weak OTG_FS_IRQHandler
.thumb_set OTG_FS_IRQHandler,Default_Handler
.weak DMA2_Stream5_IRQHandler
.thumb_set DMA2_Stream5_IRQHandler,Default_Handler
.weak DMA2_Stream6_IRQHandler
.thumb_set DMA2_Stream6_IRQHandler,Default_Handler
.weak DMA2_Stream7_IRQHandler
.thumb_set DMA2_Stream7_IRQHandler,Default_Handler
.weak USART6_IRQHandler
.thumb_set USART6_IRQHandler,Default_Handler
.weak I2C3_EV_IRQHandler
.thumb_set I2C3_EV_IRQHandler,Default_Handler
.weak I2C3_ER_IRQHandler
.thumb_set I2C3_ER_IRQHandler,Default_Handler
.weak OTG_HS_EP1_OUT_IRQHandler
.thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler
.weak OTG_HS_EP1_IN_IRQHandler
.thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler
.weak OTG_HS_WKUP_IRQHandler
.thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler
.weak OTG_HS_IRQHandler
.thumb_set OTG_HS_IRQHandler,Default_Handler
.weak DCMI_IRQHandler
.thumb_set DCMI_IRQHandler,Default_Handler
.weak HASH_RNG_IRQHandler
.thumb_set HASH_RNG_IRQHandler,Default_Handler
.weak FPU_IRQHandler
.thumb_set FPU_IRQHandler,Default_Handler
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -48,13 +48,13 @@ static struct ep_id _ep_pool[] =
{0xFF, USB_EP_ATTR_TYPE_MASK, USB_DIR_MASK, 0, ID_ASSIGNED },
};
// void USBD_IRQ_HANDLER(void)
// {
// rt_interrupt_enter();
// HAL_PCD_IRQHandler(&_stm_pcd);
// /* leave interrupt */
// rt_interrupt_leave();
// }
void USBD_IRQ_HANDLER(void)
{
rt_interrupt_enter();
HAL_PCD_IRQHandler(&_stm_pcd);
/* leave interrupt */
rt_interrupt_leave();
}
void HAL_PCD_ResetCallback(PCD_HandleTypeDef *pcd)
{

View File

@@ -8,20 +8,13 @@
#define LED_NUM 24 // LED灯珠个数
const RGBColor_TypeDef LED_DARK = {0, 0, 0};
const RGBColor_TypeDef LED_GREEN = {255, 0, 0};
const RGBColor_TypeDef LED_RED = {0, 255, 0};
const RGBColor_TypeDef LED_BLUE = {0, 0, 255};
const RGBColor_TypeDef LED_WHITE = {255, 255, 255};
rt_thread_t led_blink_thread = RT_NULL;
rt_thread_t led_breath_thread = RT_NULL;
// 灯是否处于特定颜色还是闪烁状态
uint8_t LED_Blink_State[LED_NUM] = {LED_NOT_BLINKING};
// 呼吸灯是否开启
uint8_t LED_Breath_State = LED_BREATH_OFF_LASTING;
uint8_t LED_Breath_State = LED_BREATH_OFF;
// 灯闪烁颜色缓存
RGBColor_TypeDef LED_Blink_Color[LED_NUM] = {0};
const RGBColor_TypeDef LED_OFF = {0, 0, 0};
@@ -140,15 +133,8 @@ void led_breath_entry(void *parameter)
{
if (LED_Breath_State==LED_BREATH_OFF)
{
LED_Breath_State=LED_BREATH_OFF_LASTING;
rt_thread_mdelay(100);
i = LED_BREATH_ID(1);
LED_SetMore(LED_BREATH_ID(1), LED_BREATH_ID(12), LED_OFF);
continue;
}
else if(LED_Breath_State==LED_BREATH_OFF_LASTING)
{
rt_thread_mdelay(100);
continue;
}

View File

@@ -5,22 +5,16 @@
#define LED_NOT_BLINKING 0
#define LED_BREATH_ON 1
#define LED_BREATH_OFF 0
#define LED_BREATH_OFF_LASTING 2
#define LED_CHARGE_ID(i) (i+12-1) //电源指示灯序号(1-12)
#define LED_BREATH_ID(i) (i-1) //呼吸灯序号(1-12)
void LED_Set(uint16_t LedId, RGBColor_TypeDef Color);
void LED_SetMore(uint16_t LedId_begin,uint16_t LedId_end, RGBColor_TypeDef Color);
void LED_Blink(uint16_t LedId, RGBColor_TypeDef Color);
void LED_BlinkMore(uint16_t LedId_begin, uint16_t LedId_end, RGBColor_TypeDef Color);
void LED_BreathTurn(uint8_t LedBreath_state);
int led_init(void);
extern void LED_Set(uint16_t LedId, RGBColor_TypeDef Color);
extern void LED_SetMore(uint16_t LedId_begin,uint16_t LedId_end, RGBColor_TypeDef Color);
extern void LED_Blink(uint16_t LedId, RGBColor_TypeDef Color);
extern void LED_BlinkMore(uint16_t LedId_begin, uint16_t LedId_end, RGBColor_TypeDef Color);
extern void LED_BreathTurn(uint8_t LedBreath_state);
extern int led_init(void);
extern const RGBColor_TypeDef LED_OFF;
extern const RGBColor_TypeDef LED_ON;
extern const RGBColor_TypeDef LED_DARK ;
extern const RGBColor_TypeDef LED_GREEN;
extern const RGBColor_TypeDef LED_RED ;
extern const RGBColor_TypeDef LED_BLUE ;
extern const RGBColor_TypeDef LED_WHITE;

View File

@@ -0,0 +1,612 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-05-09 Urey first version
* 2019-07-09 Zero-Free improve device ops interface and data flows
*/
#include <stdio.h>
#include <string.h>
#include <rthw.h>
#include <rtdevice.h>
#define DBG_TAG "audio"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
enum
{
REPLAY_EVT_NONE = 0x00,
REPLAY_EVT_START = 0x01,
REPLAY_EVT_STOP = 0x02,
};
static rt_err_t _audio_send_replay_frame(struct rt_audio_device *audio)
{
rt_err_t result = RT_EOK;
rt_uint8_t *data;
rt_size_t dst_size, src_size;
rt_uint16_t position, remain_bytes = 0, index = 0;
struct rt_audio_buf_info *buf_info;
RT_ASSERT(audio != RT_NULL);
buf_info = &audio->replay->buf_info;
/* save current pos */
position = audio->replay->pos;
dst_size = buf_info->block_size;
/* check replay queue is empty */
if (rt_data_queue_peek(&audio->replay->queue, (const void **)&data, &src_size) != RT_EOK)
{
/* ack stop event */
if (audio->replay->event & REPLAY_EVT_STOP)
rt_completion_done(&audio->replay->cmp);
/* send zero frames */
rt_memset(&buf_info->buffer[audio->replay->pos], 0, dst_size);
audio->replay->pos += dst_size;
audio->replay->pos %= buf_info->total_size;
}
else
{
rt_memset(&buf_info->buffer[audio->replay->pos], 0, dst_size);
/* copy data from memory pool to hardware device fifo */
while (index < dst_size)
{
result = rt_data_queue_peek(&audio->replay->queue, (const void **)&data, &src_size);
if (result != RT_EOK)
{
LOG_D("under run %d, remain %d", audio->replay->pos, remain_bytes);
audio->replay->pos -= remain_bytes;
audio->replay->pos += dst_size;
audio->replay->pos %= buf_info->total_size;
audio->replay->read_index = 0;
result = -RT_EEMPTY;
break;
}
remain_bytes = MIN((dst_size - index), (src_size - audio->replay->read_index));
rt_memcpy(&buf_info->buffer[audio->replay->pos],
&data[audio->replay->read_index], remain_bytes);
index += remain_bytes;
audio->replay->read_index += remain_bytes;
audio->replay->pos += remain_bytes;
audio->replay->pos %= buf_info->total_size;
if (audio->replay->read_index == src_size)
{
/* free memory */
audio->replay->read_index = 0;
rt_data_queue_pop(&audio->replay->queue, (const void **)&data, &src_size, RT_WAITING_NO);
rt_mp_free(data);
/* notify transmitted complete. */
if (audio->parent.tx_complete != RT_NULL)
audio->parent.tx_complete(&audio->parent, (void *)data);
}
}
}
if (audio->ops->transmit != RT_NULL)
{
if (audio->ops->transmit(audio, &buf_info->buffer[position], RT_NULL, dst_size) != dst_size)
result = -RT_ERROR;
}
return result;
}
static rt_err_t _audio_flush_replay_frame(struct rt_audio_device *audio)
{
rt_err_t result = RT_EOK;
if (audio->replay->write_index)
{
result = rt_data_queue_push(&audio->replay->queue,
(const void **)audio->replay->write_data,
audio->replay->write_index,
RT_WAITING_FOREVER);
audio->replay->write_index = 0;
}
return result;
}
static rt_err_t _aduio_replay_start(struct rt_audio_device *audio)
{
rt_err_t result = RT_EOK;
if (audio->replay->activated != RT_TRUE)
{
/* start playback hardware device */
if (audio->ops->start)
result = audio->ops->start(audio, AUDIO_STREAM_REPLAY);
audio->replay->activated = RT_TRUE;
LOG_D("start audio replay device");
}
return result;
}
static rt_err_t _aduio_replay_stop(struct rt_audio_device *audio)
{
rt_err_t result = RT_EOK;
if (audio->replay->activated == RT_TRUE)
{
/* flush replay remian frames */
_audio_flush_replay_frame(audio);
/* notify irq(or thread) to stop the data transmission */
audio->replay->event |= REPLAY_EVT_STOP;
/* waiting for the remaining data transfer to complete */
rt_completion_init(&audio->replay->cmp);
rt_completion_wait(&audio->replay->cmp, RT_WAITING_FOREVER);
audio->replay->event &= ~REPLAY_EVT_STOP;
/* stop playback hardware device */
if (audio->ops->stop)
result = audio->ops->stop(audio, AUDIO_STREAM_REPLAY);
audio->replay->activated = RT_FALSE;
LOG_D("stop audio replay device");
}
return result;
}
static rt_err_t _audio_record_start(struct rt_audio_device *audio)
{
rt_err_t result = RT_EOK;
if (audio->record->activated != RT_TRUE)
{
/* open audio record pipe */
rt_device_open(RT_DEVICE(&audio->record->pipe), RT_DEVICE_OFLAG_RDONLY);
/* start record hardware device */
if (audio->ops->start)
result = audio->ops->start(audio, AUDIO_STREAM_RECORD);
audio->record->activated = RT_TRUE;
LOG_D("start audio record device");
}
return result;
}
static rt_err_t _audio_record_stop(struct rt_audio_device *audio)
{
rt_err_t result = RT_EOK;
if (audio->record->activated == RT_TRUE)
{
/* stop record hardware device */
if (audio->ops->stop)
result = audio->ops->stop(audio, AUDIO_STREAM_RECORD);
/* close audio record pipe */
rt_device_close(RT_DEVICE(&audio->record->pipe));
audio->record->activated = RT_FALSE;
LOG_D("stop audio record device");
}
return result;
}
static rt_err_t _audio_dev_init(struct rt_device *dev)
{
rt_err_t result = RT_EOK;
struct rt_audio_device *audio;
RT_ASSERT(dev != RT_NULL);
audio = (struct rt_audio_device *) dev;
/* initialize replay & record */
audio->replay = RT_NULL;
audio->record = RT_NULL;
/* initialize replay */
if (dev->flag & RT_DEVICE_FLAG_WRONLY)
{
struct rt_audio_replay *replay = (struct rt_audio_replay *) rt_malloc(sizeof(struct rt_audio_replay));
if (replay == RT_NULL)
return -RT_ENOMEM;
rt_memset(replay, 0, sizeof(struct rt_audio_replay));
/* init memory pool for replay */
replay->mp = rt_mp_create("adu_mp", RT_AUDIO_REPLAY_MP_BLOCK_COUNT, RT_AUDIO_REPLAY_MP_BLOCK_SIZE);
if (replay->mp == RT_NULL)
{
rt_free(replay);
LOG_E("create memory pool for replay failed");
return -RT_ENOMEM;
}
/* init queue for audio replay */
rt_data_queue_init(&replay->queue, CFG_AUDIO_REPLAY_QUEUE_COUNT, 0, RT_NULL);
/* init mutex lock for audio replay */
rt_mutex_init(&replay->lock, "replay", RT_IPC_FLAG_PRIO);
replay->activated = RT_FALSE;
audio->replay = replay;
}
/* initialize record */
if (dev->flag & RT_DEVICE_FLAG_RDONLY)
{
struct rt_audio_record *record = (struct rt_audio_record *) rt_malloc(sizeof(struct rt_audio_record));
rt_uint8_t *buffer;
if (record == RT_NULL)
return -RT_ENOMEM;
rt_memset(record, 0, sizeof(struct rt_audio_record));
/* init pipe for record*/
buffer = rt_malloc(RT_AUDIO_RECORD_PIPE_SIZE);
if (buffer == RT_NULL)
{
rt_free(record);
LOG_E("malloc memory for for record pipe failed");
return -RT_ENOMEM;
}
rt_audio_pipe_init(&record->pipe, "record",
(rt_int32_t)(RT_PIPE_FLAG_FORCE_WR | RT_PIPE_FLAG_BLOCK_RD),
buffer,
RT_AUDIO_RECORD_PIPE_SIZE);
record->activated = RT_FALSE;
audio->record = record;
}
/* initialize hardware configuration */
if (audio->ops->init)
audio->ops->init(audio);
/* get replay buffer information */
if (audio->ops->buffer_info)
audio->ops->buffer_info(audio, &audio->replay->buf_info);
return result;
}
static rt_err_t _audio_dev_open(struct rt_device *dev, rt_uint16_t oflag)
{
struct rt_audio_device *audio;
RT_ASSERT(dev != RT_NULL);
audio = (struct rt_audio_device *) dev;
/* check device flag with the open flag */
if ((oflag & RT_DEVICE_OFLAG_RDONLY) && !(dev->flag & RT_DEVICE_FLAG_RDONLY))
return -RT_EIO;
if ((oflag & RT_DEVICE_OFLAG_WRONLY) && !(dev->flag & RT_DEVICE_FLAG_WRONLY))
return -RT_EIO;
/* get open flags */
dev->open_flag = oflag & 0xff;
/* initialize the Rx/Tx structure according to open flag */
if (oflag & RT_DEVICE_OFLAG_WRONLY)
{
if (audio->replay->activated != RT_TRUE)
{
LOG_D("open audio replay device, oflag = %x\n", oflag);
audio->replay->write_index = 0;
audio->replay->read_index = 0;
audio->replay->pos = 0;
audio->replay->event = REPLAY_EVT_NONE;
}
dev->open_flag |= RT_DEVICE_OFLAG_WRONLY;
}
if (oflag & RT_DEVICE_OFLAG_RDONLY)
{
/* open record pipe */
if (audio->record->activated != RT_TRUE)
{
LOG_D("open audio record device ,oflag = %x\n", oflag);
_audio_record_start(audio);
audio->record->activated = RT_TRUE;
}
dev->open_flag |= RT_DEVICE_OFLAG_RDONLY;
}
return RT_EOK;
}
static rt_err_t _audio_dev_close(struct rt_device *dev)
{
struct rt_audio_device *audio;
RT_ASSERT(dev != RT_NULL);
audio = (struct rt_audio_device *) dev;
if (dev->open_flag & RT_DEVICE_OFLAG_WRONLY)
{
/* stop replay stream */
_aduio_replay_stop(audio);
dev->open_flag &= ~RT_DEVICE_OFLAG_WRONLY;
}
if (dev->open_flag & RT_DEVICE_OFLAG_RDONLY)
{
/* stop record stream */
_audio_record_stop(audio);
dev->open_flag &= ~RT_DEVICE_OFLAG_RDONLY;
}
return RT_EOK;
}
static rt_ssize_t _audio_dev_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size)
{
struct rt_audio_device *audio;
RT_ASSERT(dev != RT_NULL);
audio = (struct rt_audio_device *) dev;
if (!(dev->open_flag & RT_DEVICE_OFLAG_RDONLY) || (audio->record == RT_NULL))
return 0;
return rt_device_read(RT_DEVICE(&audio->record->pipe), pos, buffer, size);
}
static rt_ssize_t _audio_dev_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
struct rt_audio_device *audio;
rt_uint8_t *ptr;
rt_uint16_t block_size, remain_bytes, index = 0;
RT_ASSERT(dev != RT_NULL);
audio = (struct rt_audio_device *) dev;
if (!(dev->open_flag & RT_DEVICE_OFLAG_WRONLY) || (audio->replay == RT_NULL))
return 0;
/* push a new frame to replay data queue */
ptr = (rt_uint8_t *)buffer;
block_size = RT_AUDIO_REPLAY_MP_BLOCK_SIZE;
rt_mutex_take(&audio->replay->lock, RT_WAITING_FOREVER);
while (index < size)
{
/* request buffer from replay memory pool */
if (audio->replay->write_index % block_size == 0)
{
audio->replay->write_data = rt_mp_alloc(audio->replay->mp, RT_WAITING_FOREVER);
rt_memset(audio->replay->write_data, 0, block_size);
}
/* copy data to replay memory pool */
remain_bytes = MIN((block_size - audio->replay->write_index), (size - index));
rt_memcpy(&audio->replay->write_data[audio->replay->write_index], &ptr[index], remain_bytes);
index += remain_bytes;
audio->replay->write_index += remain_bytes;
audio->replay->write_index %= block_size;
if (audio->replay->write_index == 0)
{
rt_data_queue_push(&audio->replay->queue,
audio->replay->write_data,
block_size,
RT_WAITING_FOREVER);
}
}
rt_mutex_release(&audio->replay->lock);
/* check replay state */
if (audio->replay->activated != RT_TRUE)
{
_aduio_replay_start(audio);
audio->replay->activated = RT_TRUE;
}
return index;
}
static rt_err_t _audio_dev_control(struct rt_device *dev, int cmd, void *args)
{
rt_err_t result = RT_EOK;
struct rt_audio_device *audio;
RT_ASSERT(dev != RT_NULL);
audio = (struct rt_audio_device *) dev;
/* dev stat...*/
switch (cmd)
{
case AUDIO_CTL_GETCAPS:
{
struct rt_audio_caps *caps = (struct rt_audio_caps *) args;
LOG_D("AUDIO_CTL_GETCAPS: main_type = %d,sub_type = %d", caps->main_type, caps->sub_type);
if (audio->ops->getcaps != RT_NULL)
{
result = audio->ops->getcaps(audio, caps);
}
break;
}
case AUDIO_CTL_CONFIGURE:
{
struct rt_audio_caps *caps = (struct rt_audio_caps *) args;
LOG_D("AUDIO_CTL_CONFIGURE: main_type = %d,sub_type = %d", caps->main_type, caps->sub_type);
if (audio->ops->configure != RT_NULL)
{
result = audio->ops->configure(audio, caps);
}
break;
}
case AUDIO_CTL_START:
{
int stream = *(int *) args;
LOG_D("AUDIO_CTL_START: stream = %d", stream);
if (stream == AUDIO_STREAM_REPLAY)
{
result = _aduio_replay_start(audio);
}
else
{
result = _audio_record_start(audio);
}
break;
}
case AUDIO_CTL_STOP:
{
int stream = *(int *) args;
LOG_D("AUDIO_CTL_STOP: stream = %d", stream);
if (stream == AUDIO_STREAM_REPLAY)
{
result = _aduio_replay_stop(audio);
}
else
{
result = _audio_record_stop(audio);
}
break;
}
default:
break;
}
return result;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops audio_ops =
{
_audio_dev_init,
_audio_dev_open,
_audio_dev_close,
_audio_dev_read,
_audio_dev_write,
_audio_dev_control
};
#endif
rt_err_t rt_audio_register(struct rt_audio_device *audio, const char *name, rt_uint32_t flag, void *data)
{
rt_err_t result = RT_EOK;
struct rt_device *device;
RT_ASSERT(audio != RT_NULL);
device = &(audio->parent);
device->type = RT_Device_Class_Sound;
device->rx_indicate = RT_NULL;
device->tx_complete = RT_NULL;
#ifdef RT_USING_DEVICE_OPS
device->ops = &audio_ops;
#else
device->init = _audio_dev_init;
device->open = _audio_dev_open;
device->close = _audio_dev_close;
device->read = _audio_dev_read;
device->write = _audio_dev_write;
device->control = _audio_dev_control;
#endif
device->user_data = data;
/* register a character device */
result = rt_device_register(device, name, flag | RT_DEVICE_FLAG_REMOVABLE);
/* initialize audio device */
if (result == RT_EOK)
result = rt_device_init(device);
return result;
}
int rt_audio_samplerate_to_speed(rt_uint32_t bitValue)
{
int speed = 0;
switch (bitValue)
{
case AUDIO_SAMP_RATE_8K:
speed = 8000;
break;
case AUDIO_SAMP_RATE_11K:
speed = 11052;
break;
case AUDIO_SAMP_RATE_16K:
speed = 16000;
break;
case AUDIO_SAMP_RATE_22K:
speed = 22050;
break;
case AUDIO_SAMP_RATE_32K:
speed = 32000;
break;
case AUDIO_SAMP_RATE_44K:
speed = 44100;
break;
case AUDIO_SAMP_RATE_48K:
speed = 48000;
break;
case AUDIO_SAMP_RATE_96K:
speed = 96000;
break;
case AUDIO_SAMP_RATE_128K:
speed = 128000;
break;
case AUDIO_SAMP_RATE_160K:
speed = 160000;
break;
case AUDIO_SAMP_RATE_172K:
speed = 176400;
break;
case AUDIO_SAMP_RATE_192K:
speed = 192000;
break;
default:
break;
}
return speed;
}
void rt_audio_tx_complete(struct rt_audio_device *audio)
{
/* try to send next frame */
_audio_send_replay_frame(audio);
}
void rt_audio_rx_done(struct rt_audio_device *audio, rt_uint8_t *pbuf, rt_size_t len)
{
/* save data to record pipe */
rt_device_write(RT_DEVICE(&audio->record->pipe), 0, pbuf, len);
/* invoke callback */
if (audio->parent.rx_indicate != RT_NULL)
audio->parent.rx_indicate(&audio->parent, len);
}

View File

@@ -0,0 +1,296 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-09-30 Bernard first version.
*/
#include <rthw.h>
#include <rtdevice.h>
#include "audio_pipe.h"
static void _rt_pipe_resume_writer(struct rt_audio_pipe *pipe)
{
if (!rt_list_isempty(&pipe->suspended_write_list))
{
rt_thread_t thread;
RT_ASSERT(pipe->flag & RT_PIPE_FLAG_BLOCK_WR);
/* get suspended thread */
thread = RT_THREAD_LIST_NODE_ENTRY(pipe->suspended_write_list.next);
/* resume the write thread */
rt_thread_resume(thread);
rt_schedule();
}
}
static rt_ssize_t rt_pipe_read(rt_device_t dev,
rt_off_t pos,
void *buffer,
rt_size_t size)
{
rt_base_t level;
rt_thread_t thread;
struct rt_audio_pipe *pipe;
rt_size_t read_nbytes;
pipe = (struct rt_audio_pipe *)dev;
RT_ASSERT(pipe != RT_NULL);
if (!(pipe->flag & RT_PIPE_FLAG_BLOCK_RD))
{
level = rt_hw_interrupt_disable();
read_nbytes = rt_ringbuffer_get(&(pipe->ringbuffer), (rt_uint8_t *)buffer, size);
/* if the ringbuffer is empty, there won't be any writer waiting */
if (read_nbytes)
_rt_pipe_resume_writer(pipe);
rt_hw_interrupt_enable(level);
return read_nbytes;
}
thread = rt_thread_self();
/* current context checking */
RT_DEBUG_NOT_IN_INTERRUPT;
do
{
level = rt_hw_interrupt_disable();
read_nbytes = rt_ringbuffer_get(&(pipe->ringbuffer), (rt_uint8_t *)buffer, size);
if (read_nbytes == 0)
{
rt_thread_suspend(thread);
/* waiting on suspended read list */
rt_list_insert_before(&(pipe->suspended_read_list),
&RT_THREAD_LIST_NODE(thread));
rt_hw_interrupt_enable(level);
rt_schedule();
}
else
{
_rt_pipe_resume_writer(pipe);
rt_hw_interrupt_enable(level);
break;
}
}
while (read_nbytes == 0);
return read_nbytes;
}
static void _rt_pipe_resume_reader(struct rt_audio_pipe *pipe)
{
if (pipe->parent.rx_indicate)
pipe->parent.rx_indicate(&pipe->parent,
rt_ringbuffer_data_len(&pipe->ringbuffer));
if (!rt_list_isempty(&pipe->suspended_read_list))
{
rt_thread_t thread;
RT_ASSERT(pipe->flag & RT_PIPE_FLAG_BLOCK_RD);
/* get suspended thread */
thread = RT_THREAD_LIST_NODE_ENTRY(pipe->suspended_read_list.next);
/* resume the read thread */
rt_thread_resume(thread);
rt_schedule();
}
}
static rt_ssize_t rt_pipe_write(rt_device_t dev,
rt_off_t pos,
const void *buffer,
rt_size_t size)
{
rt_base_t level;
rt_thread_t thread;
struct rt_audio_pipe *pipe;
rt_size_t write_nbytes;
pipe = (struct rt_audio_pipe *)dev;
RT_ASSERT(pipe != RT_NULL);
if ((pipe->flag & RT_PIPE_FLAG_FORCE_WR) ||
!(pipe->flag & RT_PIPE_FLAG_BLOCK_WR))
{
level = rt_hw_interrupt_disable();
if (pipe->flag & RT_PIPE_FLAG_FORCE_WR)
write_nbytes = rt_ringbuffer_put_force(&(pipe->ringbuffer),
(const rt_uint8_t *)buffer, size);
else
write_nbytes = rt_ringbuffer_put(&(pipe->ringbuffer),
(const rt_uint8_t *)buffer, size);
_rt_pipe_resume_reader(pipe);
rt_hw_interrupt_enable(level);
return write_nbytes;
}
thread = rt_thread_self();
/* current context checking */
RT_DEBUG_NOT_IN_INTERRUPT;
do
{
level = rt_hw_interrupt_disable();
write_nbytes = rt_ringbuffer_put(&(pipe->ringbuffer), (const rt_uint8_t *)buffer, size);
if (write_nbytes == 0)
{
/* pipe full, waiting on suspended write list */
rt_thread_suspend(thread);
/* waiting on suspended read list */
rt_list_insert_before(&(pipe->suspended_write_list),
&RT_THREAD_LIST_NODE(thread));
rt_hw_interrupt_enable(level);
rt_schedule();
}
else
{
_rt_pipe_resume_reader(pipe);
rt_hw_interrupt_enable(level);
break;
}
}
while (write_nbytes == 0);
return write_nbytes;
}
static rt_err_t rt_pipe_control(rt_device_t dev, int cmd, void *args)
{
struct rt_audio_pipe *pipe;
pipe = (struct rt_audio_pipe *)dev;
if (cmd == PIPE_CTRL_GET_SPACE && args)
*(rt_size_t *)args = rt_ringbuffer_space_len(&pipe->ringbuffer);
return RT_EOK;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops audio_pipe_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
rt_pipe_read,
rt_pipe_write,
rt_pipe_control
};
#endif
/**
* This function will initialize a pipe device and put it under control of
* resource management.
*
* @param pipe the pipe device
* @param name the name of pipe device
* @param flag the attribute of the pipe device
* @param buf the buffer of pipe device
* @param size the size of pipe device buffer
*
* @return the operation status, RT_EOK on successful
*/
rt_err_t rt_audio_pipe_init(struct rt_audio_pipe *pipe,
const char *name,
rt_int32_t flag,
rt_uint8_t *buf,
rt_size_t size)
{
RT_ASSERT(pipe);
RT_ASSERT(buf);
/* initialize suspended list */
rt_list_init(&pipe->suspended_read_list);
rt_list_init(&pipe->suspended_write_list);
/* initialize ring buffer */
rt_ringbuffer_init(&pipe->ringbuffer, buf, size);
pipe->flag = flag;
/* create pipe */
pipe->parent.type = RT_Device_Class_Pipe;
#ifdef RT_USING_DEVICE_OPS
pipe->parent.ops = &audio_pipe_ops;
#else
pipe->parent.init = RT_NULL;
pipe->parent.open = RT_NULL;
pipe->parent.close = RT_NULL;
pipe->parent.read = rt_pipe_read;
pipe->parent.write = rt_pipe_write;
pipe->parent.control = rt_pipe_control;
#endif
return rt_device_register(&(pipe->parent), name, RT_DEVICE_FLAG_RDWR);
}
/**
* This function will detach a pipe device from resource management
*
* @param pipe the pipe device
*
* @return the operation status, RT_EOK on successful
*/
rt_err_t rt_audio_pipe_detach(struct rt_audio_pipe *pipe)
{
return rt_device_unregister(&pipe->parent);
}
#ifdef RT_USING_HEAP
rt_err_t rt_audio_pipe_create(const char *name, rt_int32_t flag, rt_size_t size)
{
rt_uint8_t *rb_memptr = RT_NULL;
struct rt_audio_pipe *pipe = RT_NULL;
/* get aligned size */
size = RT_ALIGN(size, RT_ALIGN_SIZE);
pipe = (struct rt_audio_pipe *)rt_calloc(1, sizeof(struct rt_audio_pipe));
if (pipe == RT_NULL)
return -RT_ENOMEM;
/* create ring buffer of pipe */
rb_memptr = (rt_uint8_t *)rt_malloc(size);
if (rb_memptr == RT_NULL)
{
rt_free(pipe);
return -RT_ENOMEM;
}
return rt_audio_pipe_init(pipe, name, flag, rb_memptr, size);
}
void rt_audio_pipe_destroy(struct rt_audio_pipe *pipe)
{
if (pipe == RT_NULL)
return;
/* un-register pipe device */
rt_audio_pipe_detach(pipe);
/* release memory */
rt_free(pipe->ringbuffer.buffer_ptr);
rt_free(pipe);
return;
}
#endif /* RT_USING_HEAP */

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#ifndef __AUDIO_PIPE_H__
#define __AUDIO_PIPE_H__
/**
* Pipe Device
*/
#include <rtdevice.h>
#ifndef RT_PIPE_BUFSZ
#define PIPE_BUFSZ 512
#else
#define PIPE_BUFSZ RT_PIPE_BUFSZ
#endif
/* portal device */
struct rt_audio_portal_device
{
struct rt_device parent;
struct rt_device *write_dev;
struct rt_device *read_dev;
};
enum rt_audio_pipe_flag
{
/* both read and write won't block */
RT_PIPE_FLAG_NONBLOCK_RDWR = 0x00,
/* read would block */
RT_PIPE_FLAG_BLOCK_RD = 0x01,
/* write would block */
RT_PIPE_FLAG_BLOCK_WR = 0x02,
/* write to this pipe will discard some data when the pipe is full.
* When this flag is set, RT_PIPE_FLAG_BLOCK_WR will be ignored since write
* operation will always be success. */
RT_PIPE_FLAG_FORCE_WR = 0x04,
};
struct rt_audio_pipe
{
struct rt_device parent;
/* ring buffer in pipe device */
struct rt_ringbuffer ringbuffer;
rt_int32_t flag;
/* suspended list */
rt_list_t suspended_read_list;
rt_list_t suspended_write_list;
struct rt_audio_portal_device *write_portal;
struct rt_audio_portal_device *read_portal;
};
#define PIPE_CTRL_GET_SPACE 0x14 /**< get the remaining size of a pipe device */
rt_err_t rt_audio_pipe_init(struct rt_audio_pipe *pipe,
const char *name,
rt_int32_t flag,
rt_uint8_t *buf,
rt_size_t size);
rt_err_t rt_audio_pipe_detach(struct rt_audio_pipe *pipe);
#ifdef RT_USING_HEAP
rt_err_t rt_audio_pipe_create(const char *name, rt_int32_t flag, rt_size_t size);
void rt_audio_pipe_destroy(struct rt_audio_pipe *pipe);
#endif /* RT_USING_HEAP */
#endif /* __AUDIO_PIPE_H__ */

View File

@@ -0,0 +1,974 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2015-05-14 aubrcool@qq.com first version
* 2015-07-06 Bernard code cleanup and remove RT_CAN_USING_LED;
*/
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#define CAN_LOCK(can) rt_mutex_take(&(can->lock), RT_WAITING_FOREVER)
#define CAN_UNLOCK(can) rt_mutex_release(&(can->lock))
static rt_err_t rt_can_init(struct rt_device *dev)
{
rt_err_t result = RT_EOK;
struct rt_can_device *can;
RT_ASSERT(dev != RT_NULL);
can = (struct rt_can_device *)dev;
/* initialize rx/tx */
can->can_rx = RT_NULL;
can->can_tx = RT_NULL;
#ifdef RT_CAN_USING_HDR
can->hdr = RT_NULL;
#endif
/* apply configuration */
if (can->ops->configure)
result = can->ops->configure(can, &can->config);
else
result = -RT_ENOSYS;
return result;
}
/*
* can interrupt routines
*/
rt_inline rt_ssize_t _can_int_rx(struct rt_can_device *can, struct rt_can_msg *data, rt_ssize_t msgs)
{
rt_ssize_t size;
struct rt_can_rx_fifo *rx_fifo;
RT_ASSERT(can != RT_NULL);
size = msgs;
rx_fifo = (struct rt_can_rx_fifo *) can->can_rx;
RT_ASSERT(rx_fifo != RT_NULL);
/* read from software FIFO */
while (msgs / sizeof(struct rt_can_msg) > 0)
{
rt_base_t level;
#ifdef RT_CAN_USING_HDR
rt_int8_t hdr;
#endif /*RT_CAN_USING_HDR*/
struct rt_can_msg_list *listmsg = RT_NULL;
/* disable interrupt */
level = rt_hw_interrupt_disable();
#ifdef RT_CAN_USING_HDR
hdr = data->hdr_index;
if (hdr >= 0 && can->hdr && hdr < can->config.maxhdr && !rt_list_isempty(&can->hdr[hdr].list))
{
listmsg = rt_list_entry(can->hdr[hdr].list.next, struct rt_can_msg_list, hdrlist);
rt_list_remove(&listmsg->list);
rt_list_remove(&listmsg->hdrlist);
if (can->hdr[hdr].msgs)
{
can->hdr[hdr].msgs--;
}
listmsg->owner = RT_NULL;
}
else if (hdr == -1)
#endif /*RT_CAN_USING_HDR*/
{
if (!rt_list_isempty(&rx_fifo->uselist))
{
listmsg = rt_list_entry(rx_fifo->uselist.next, struct rt_can_msg_list, list);
rt_list_remove(&listmsg->list);
#ifdef RT_CAN_USING_HDR
rt_list_remove(&listmsg->hdrlist);
if (listmsg->owner != RT_NULL && listmsg->owner->msgs)
{
listmsg->owner->msgs--;
}
listmsg->owner = RT_NULL;
#endif /*RT_CAN_USING_HDR*/
}
else
{
/* no data, enable interrupt and break out */
rt_hw_interrupt_enable(level);
break;
}
}
/* enable interrupt */
rt_hw_interrupt_enable(level);
if (listmsg != RT_NULL)
{
rt_memcpy(data, &listmsg->data, sizeof(struct rt_can_msg));
level = rt_hw_interrupt_disable();
rt_list_insert_before(&rx_fifo->freelist, &listmsg->list);
rx_fifo->freenumbers++;
RT_ASSERT(rx_fifo->freenumbers <= can->config.msgboxsz);
rt_hw_interrupt_enable(level);
listmsg = RT_NULL;
}
else
{
break;
}
data ++;
msgs -= sizeof(struct rt_can_msg);
}
return (size - msgs);
}
rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *data, int msgs)
{
int size;
struct rt_can_tx_fifo *tx_fifo;
RT_ASSERT(can != RT_NULL);
size = msgs;
tx_fifo = (struct rt_can_tx_fifo *) can->can_tx;
RT_ASSERT(tx_fifo != RT_NULL);
while (msgs)
{
rt_base_t level;
rt_uint32_t no;
rt_uint32_t result;
struct rt_can_sndbxinx_list *tx_tosnd = RT_NULL;
rt_sem_take(&(tx_fifo->sem), RT_WAITING_FOREVER);
level = rt_hw_interrupt_disable();
tx_tosnd = rt_list_entry(tx_fifo->freelist.next, struct rt_can_sndbxinx_list, list);
RT_ASSERT(tx_tosnd != RT_NULL);
rt_list_remove(&tx_tosnd->list);
rt_hw_interrupt_enable(level);
no = ((rt_ubase_t)tx_tosnd - (rt_ubase_t)tx_fifo->buffer) / sizeof(struct rt_can_sndbxinx_list);
tx_tosnd->result = RT_CAN_SND_RESULT_WAIT;
rt_completion_init(&tx_tosnd->completion);
if (can->ops->sendmsg(can, data, no) != RT_EOK)
{
/* send failed. */
level = rt_hw_interrupt_disable();
rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list);
rt_hw_interrupt_enable(level);
rt_sem_release(&(tx_fifo->sem));
goto err_ret;
}
can->status.sndchange = 1;
rt_completion_wait(&(tx_tosnd->completion), RT_WAITING_FOREVER);
level = rt_hw_interrupt_disable();
result = tx_tosnd->result;
if (!rt_list_isempty(&tx_tosnd->list))
{
rt_list_remove(&tx_tosnd->list);
}
rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list);
rt_hw_interrupt_enable(level);
rt_sem_release(&(tx_fifo->sem));
if (result == RT_CAN_SND_RESULT_OK)
{
level = rt_hw_interrupt_disable();
can->status.sndpkg++;
rt_hw_interrupt_enable(level);
data ++;
msgs -= sizeof(struct rt_can_msg);
if (!msgs) break;
}
else
{
err_ret:
level = rt_hw_interrupt_disable();
can->status.dropedsndpkg++;
rt_hw_interrupt_enable(level);
break;
}
}
return (size - msgs);
}
rt_inline int _can_int_tx_priv(struct rt_can_device *can, const struct rt_can_msg *data, int msgs)
{
int size;
rt_base_t level;
rt_uint32_t no, result;
struct rt_can_tx_fifo *tx_fifo;
RT_ASSERT(can != RT_NULL);
size = msgs;
tx_fifo = (struct rt_can_tx_fifo *) can->can_tx;
RT_ASSERT(tx_fifo != RT_NULL);
while (msgs)
{
no = data->priv;
if (no >= can->config.sndboxnumber)
{
break;
}
level = rt_hw_interrupt_disable();
if ((tx_fifo->buffer[no].result != RT_CAN_SND_RESULT_OK))
{
rt_hw_interrupt_enable(level);
rt_completion_wait(&(tx_fifo->buffer[no].completion), RT_WAITING_FOREVER);
continue;
}
tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_WAIT;
rt_hw_interrupt_enable(level);
if (can->ops->sendmsg(can, data, no) != RT_EOK)
{
continue;
}
can->status.sndchange = 1;
rt_completion_wait(&(tx_fifo->buffer[no].completion), RT_WAITING_FOREVER);
result = tx_fifo->buffer[no].result;
if (result == RT_CAN_SND_RESULT_OK)
{
level = rt_hw_interrupt_disable();
can->status.sndpkg++;
rt_hw_interrupt_enable(level);
data ++;
msgs -= sizeof(struct rt_can_msg);
if (!msgs) break;
}
else
{
level = rt_hw_interrupt_disable();
can->status.dropedsndpkg++;
rt_hw_interrupt_enable(level);
break;
}
}
return (size - msgs);
}
static rt_err_t rt_can_open(struct rt_device *dev, rt_uint16_t oflag)
{
struct rt_can_device *can;
char tmpname[16];
RT_ASSERT(dev != RT_NULL);
can = (struct rt_can_device *)dev;
CAN_LOCK(can);
/* get open flags */
dev->open_flag = oflag & 0xff;
if (can->can_rx == RT_NULL)
{
if (oflag & RT_DEVICE_FLAG_INT_RX)
{
int i = 0;
struct rt_can_rx_fifo *rx_fifo;
rx_fifo = (struct rt_can_rx_fifo *) rt_malloc(sizeof(struct rt_can_rx_fifo) +
can->config.msgboxsz * sizeof(struct rt_can_msg_list));
RT_ASSERT(rx_fifo != RT_NULL);
rx_fifo->buffer = (struct rt_can_msg_list *)(rx_fifo + 1);
rt_memset(rx_fifo->buffer, 0, can->config.msgboxsz * sizeof(struct rt_can_msg_list));
rt_list_init(&rx_fifo->freelist);
rt_list_init(&rx_fifo->uselist);
rx_fifo->freenumbers = can->config.msgboxsz;
for (i = 0; i < can->config.msgboxsz; i++)
{
rt_list_insert_before(&rx_fifo->freelist, &rx_fifo->buffer[i].list);
#ifdef RT_CAN_USING_HDR
rt_list_init(&rx_fifo->buffer[i].hdrlist);
rx_fifo->buffer[i].owner = RT_NULL;
#endif
}
can->can_rx = rx_fifo;
dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
/* open can rx interrupt */
can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
}
}
if (can->can_tx == RT_NULL)
{
if (oflag & RT_DEVICE_FLAG_INT_TX)
{
int i = 0;
struct rt_can_tx_fifo *tx_fifo;
tx_fifo = (struct rt_can_tx_fifo *) rt_malloc(sizeof(struct rt_can_tx_fifo) +
can->config.sndboxnumber * sizeof(struct rt_can_sndbxinx_list));
RT_ASSERT(tx_fifo != RT_NULL);
tx_fifo->buffer = (struct rt_can_sndbxinx_list *)(tx_fifo + 1);
rt_memset(tx_fifo->buffer, 0,
can->config.sndboxnumber * sizeof(struct rt_can_sndbxinx_list));
rt_list_init(&tx_fifo->freelist);
for (i = 0; i < can->config.sndboxnumber; i++)
{
rt_list_insert_before(&tx_fifo->freelist, &tx_fifo->buffer[i].list);
rt_completion_init(&(tx_fifo->buffer[i].completion));
tx_fifo->buffer[i].result = RT_CAN_SND_RESULT_OK;
}
rt_sprintf(tmpname, "%stl", dev->parent.name);
rt_sem_init(&(tx_fifo->sem), tmpname, can->config.sndboxnumber, RT_IPC_FLAG_FIFO);
can->can_tx = tx_fifo;
dev->open_flag |= RT_DEVICE_FLAG_INT_TX;
/* open can tx interrupt */
can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX);
}
}
can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_CAN_INT_ERR);
#ifdef RT_CAN_USING_HDR
if (can->hdr == RT_NULL)
{
int i = 0;
struct rt_can_hdr *phdr;
phdr = (struct rt_can_hdr *) rt_malloc(can->config.maxhdr * sizeof(struct rt_can_hdr));
RT_ASSERT(phdr != RT_NULL);
rt_memset(phdr, 0, can->config.maxhdr * sizeof(struct rt_can_hdr));
for (i = 0; i < can->config.maxhdr; i++)
{
rt_list_init(&phdr[i].list);
}
can->hdr = phdr;
}
#endif
if (!can->timerinitflag)
{
can->timerinitflag = 1;
rt_timer_start(&can->timer);
}
CAN_UNLOCK(can);
return RT_EOK;
}
static rt_err_t rt_can_close(struct rt_device *dev)
{
struct rt_can_device *can;
RT_ASSERT(dev != RT_NULL);
can = (struct rt_can_device *)dev;
CAN_LOCK(can);
/* this device has more reference count */
if (dev->ref_count > 1)
{
CAN_UNLOCK(can);
return RT_EOK;
}
if (can->timerinitflag)
{
can->timerinitflag = 0;
rt_timer_stop(&can->timer);
}
can->status_indicate.ind = RT_NULL;
can->status_indicate.args = RT_NULL;
#ifdef RT_CAN_USING_HDR
if (can->hdr != RT_NULL)
{
rt_free(can->hdr);
can->hdr = RT_NULL;
}
#endif
if (dev->open_flag & RT_DEVICE_FLAG_INT_RX)
{
struct rt_can_rx_fifo *rx_fifo;
/* clear can rx interrupt */
can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX);
rx_fifo = (struct rt_can_rx_fifo *)can->can_rx;
RT_ASSERT(rx_fifo != RT_NULL);
rt_free(rx_fifo);
dev->open_flag &= ~RT_DEVICE_FLAG_INT_RX;
can->can_rx = RT_NULL;
}
if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
{
struct rt_can_tx_fifo *tx_fifo;
/* clear can tx interrupt */
can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_TX);
tx_fifo = (struct rt_can_tx_fifo *)can->can_tx;
RT_ASSERT(tx_fifo != RT_NULL);
rt_sem_detach(&(tx_fifo->sem));
rt_free(tx_fifo);
dev->open_flag &= ~RT_DEVICE_FLAG_INT_TX;
can->can_tx = RT_NULL;
}
can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_CAN_INT_ERR);
CAN_UNLOCK(can);
return RT_EOK;
}
static rt_ssize_t rt_can_read(struct rt_device *dev,
rt_off_t pos,
void *buffer,
rt_size_t size)
{
struct rt_can_device *can;
RT_ASSERT(dev != RT_NULL);
if (size == 0) return 0;
can = (struct rt_can_device *)dev;
if ((dev->open_flag & RT_DEVICE_FLAG_INT_RX) && (dev->ref_count > 0))
{
return _can_int_rx(can, buffer, size);
}
return 0;
}
static rt_ssize_t rt_can_write(struct rt_device *dev,
rt_off_t pos,
const void *buffer,
rt_size_t size)
{
struct rt_can_device *can;
RT_ASSERT(dev != RT_NULL);
if (size == 0) return 0;
can = (struct rt_can_device *)dev;
if ((dev->open_flag & RT_DEVICE_FLAG_INT_TX) && (dev->ref_count > 0))
{
if (can->config.privmode)
{
return _can_int_tx_priv(can, buffer, size);
}
else
{
return _can_int_tx(can, buffer, size);
}
}
return 0;
}
static rt_err_t rt_can_control(struct rt_device *dev,
int cmd,
void *args)
{
struct rt_can_device *can;
rt_err_t res;
res = RT_EOK;
RT_ASSERT(dev != RT_NULL);
can = (struct rt_can_device *)dev;
switch (cmd)
{
case RT_DEVICE_CTRL_SUSPEND:
/* suspend device */
dev->flag |= RT_DEVICE_FLAG_SUSPENDED;
break;
case RT_DEVICE_CTRL_RESUME:
/* resume device */
dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED;
break;
case RT_DEVICE_CTRL_CONFIG:
/* configure device */
res = can->ops->configure(can, (struct can_configure *)args);
break;
case RT_CAN_CMD_SET_PRIV:
/* configure device */
if ((rt_uint32_t)(rt_ubase_t)args != can->config.privmode)
{
int i;
rt_base_t level;
struct rt_can_tx_fifo *tx_fifo;
res = can->ops->control(can, cmd, args);
if (res != RT_EOK) return res;
tx_fifo = (struct rt_can_tx_fifo *) can->can_tx;
if (can->config.privmode)
{
for (i = 0; i < can->config.sndboxnumber; i++)
{
level = rt_hw_interrupt_disable();
if(rt_list_isempty(&tx_fifo->buffer[i].list))
{
rt_sem_release(&(tx_fifo->sem));
}
else
{
rt_list_remove(&tx_fifo->buffer[i].list);
}
rt_hw_interrupt_enable(level);
}
}
else
{
for (i = 0; i < can->config.sndboxnumber; i++)
{
level = rt_hw_interrupt_disable();
if (tx_fifo->buffer[i].result == RT_CAN_SND_RESULT_OK)
{
rt_list_insert_before(&tx_fifo->freelist, &tx_fifo->buffer[i].list);
}
rt_hw_interrupt_enable(level);
}
}
}
break;
case RT_CAN_CMD_SET_STATUS_IND:
can->status_indicate.ind = ((rt_can_status_ind_type_t)args)->ind;
can->status_indicate.args = ((rt_can_status_ind_type_t)args)->args;
break;
#ifdef RT_CAN_USING_HDR
case RT_CAN_CMD_SET_FILTER:
res = can->ops->control(can, cmd, args);
if (res != RT_EOK || can->hdr == RT_NULL)
{
return res;
}
struct rt_can_filter_config *pfilter;
struct rt_can_filter_item *pitem;
rt_uint32_t count;
rt_base_t level;
pfilter = (struct rt_can_filter_config *)args;
RT_ASSERT(pfilter);
count = pfilter->count;
pitem = pfilter->items;
if (pfilter->actived)
{
while (count)
{
if (pitem->hdr_bank >= can->config.maxhdr || pitem->hdr_bank < 0)
{
count--;
pitem++;
continue;
}
level = rt_hw_interrupt_disable();
if (!can->hdr[pitem->hdr_bank].connected)
{
rt_hw_interrupt_enable(level);
rt_memcpy(&can->hdr[pitem->hdr_bank].filter, pitem,
sizeof(struct rt_can_filter_item));
level = rt_hw_interrupt_disable();
can->hdr[pitem->hdr_bank].connected = 1;
can->hdr[pitem->hdr_bank].msgs = 0;
rt_list_init(&can->hdr[pitem->hdr_bank].list);
}
rt_hw_interrupt_enable(level);
count--;
pitem++;
}
}
else
{
while (count)
{
if (pitem->hdr_bank >= can->config.maxhdr || pitem->hdr_bank < 0)
{
count--;
pitem++;
continue;
}
level = rt_hw_interrupt_disable();
if (can->hdr[pitem->hdr_bank].connected)
{
can->hdr[pitem->hdr_bank].connected = 0;
can->hdr[pitem->hdr_bank].msgs = 0;
if (!rt_list_isempty(&can->hdr[pitem->hdr_bank].list))
{
rt_list_remove(can->hdr[pitem->hdr_bank].list.next);
}
rt_hw_interrupt_enable(level);
rt_memset(&can->hdr[pitem->hdr_bank].filter, 0,
sizeof(struct rt_can_filter_item));
}
else
{
rt_hw_interrupt_enable(level);
}
count--;
pitem++;
}
}
break;
#endif /*RT_CAN_USING_HDR*/
#ifdef RT_CAN_USING_BUS_HOOK
case RT_CAN_CMD_SET_BUS_HOOK:
can->bus_hook = (rt_can_bus_hook) args;
break;
#endif /*RT_CAN_USING_BUS_HOOK*/
default :
/* control device */
if (can->ops->control != RT_NULL)
{
res = can->ops->control(can, cmd, args);
}
else
{
res = -RT_ENOSYS;
}
break;
}
return res;
}
/*
* can timer
*/
static void cantimeout(void *arg)
{
rt_can_t can;
can = (rt_can_t)arg;
RT_ASSERT(can);
rt_device_control((rt_device_t)can, RT_CAN_CMD_GET_STATUS, (void *)&can->status);
if (can->status_indicate.ind != RT_NULL)
{
can->status_indicate.ind(can, can->status_indicate.args);
}
#ifdef RT_CAN_USING_BUS_HOOK
if(can->bus_hook)
{
can->bus_hook(can);
}
#endif /*RT_CAN_USING_BUS_HOOK*/
if (can->timerinitflag == 1)
{
can->timerinitflag = 0xFF;
}
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops can_device_ops =
{
rt_can_init,
rt_can_open,
rt_can_close,
rt_can_read,
rt_can_write,
rt_can_control
};
#endif
/*
* can register
*/
rt_err_t rt_hw_can_register(struct rt_can_device *can,
const char *name,
const struct rt_can_ops *ops,
void *data)
{
struct rt_device *device;
RT_ASSERT(can != RT_NULL);
device = &(can->parent);
device->type = RT_Device_Class_CAN;
device->rx_indicate = RT_NULL;
device->tx_complete = RT_NULL;
#ifdef RT_CAN_USING_HDR
can->hdr = RT_NULL;
#endif
can->can_rx = RT_NULL;
can->can_tx = RT_NULL;
rt_mutex_init(&(can->lock), "can", RT_IPC_FLAG_PRIO);
#ifdef RT_CAN_USING_BUS_HOOK
can->bus_hook = RT_NULL;
#endif /*RT_CAN_USING_BUS_HOOK*/
#ifdef RT_USING_DEVICE_OPS
device->ops = &can_device_ops;
#else
device->init = rt_can_init;
device->open = rt_can_open;
device->close = rt_can_close;
device->read = rt_can_read;
device->write = rt_can_write;
device->control = rt_can_control;
#endif
can->ops = ops;
can->status_indicate.ind = RT_NULL;
can->status_indicate.args = RT_NULL;
rt_memset(&can->status, 0, sizeof(can->status));
device->user_data = data;
can->timerinitflag = 0;
rt_timer_init(&can->timer,
name,
cantimeout,
(void *)can,
can->config.ticks,
RT_TIMER_FLAG_PERIODIC);
/* register a character device */
return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
}
/* ISR for can interrupt */
void rt_hw_can_isr(struct rt_can_device *can, int event)
{
switch (event & 0xff)
{
case RT_CAN_EVENT_RXOF_IND:
{
rt_base_t level;
level = rt_hw_interrupt_disable();
can->status.dropedrcvpkg++;
rt_hw_interrupt_enable(level);
}
case RT_CAN_EVENT_RX_IND:
{
struct rt_can_msg tmpmsg;
struct rt_can_rx_fifo *rx_fifo;
struct rt_can_msg_list *listmsg = RT_NULL;
#ifdef RT_CAN_USING_HDR
rt_int8_t hdr;
#endif
int ch = -1;
rt_base_t level;
rt_uint32_t no;
rx_fifo = (struct rt_can_rx_fifo *)can->can_rx;
RT_ASSERT(rx_fifo != RT_NULL);
/* interrupt mode receive */
RT_ASSERT(can->parent.open_flag & RT_DEVICE_FLAG_INT_RX);
no = event >> 8;
ch = can->ops->recvmsg(can, &tmpmsg, no);
if (ch == -1) break;
/* disable interrupt */
level = rt_hw_interrupt_disable();
can->status.rcvpkg++;
can->status.rcvchange = 1;
if (!rt_list_isempty(&rx_fifo->freelist))
{
listmsg = rt_list_entry(rx_fifo->freelist.next, struct rt_can_msg_list, list);
rt_list_remove(&listmsg->list);
#ifdef RT_CAN_USING_HDR
rt_list_remove(&listmsg->hdrlist);
if (listmsg->owner != RT_NULL && listmsg->owner->msgs)
{
listmsg->owner->msgs--;
}
listmsg->owner = RT_NULL;
#endif /*RT_CAN_USING_HDR*/
RT_ASSERT(rx_fifo->freenumbers > 0);
rx_fifo->freenumbers--;
}
else if (!rt_list_isempty(&rx_fifo->uselist))
{
listmsg = rt_list_entry(rx_fifo->uselist.next, struct rt_can_msg_list, list);
can->status.dropedrcvpkg++;
rt_list_remove(&listmsg->list);
#ifdef RT_CAN_USING_HDR
rt_list_remove(&listmsg->hdrlist);
if (listmsg->owner != RT_NULL && listmsg->owner->msgs)
{
listmsg->owner->msgs--;
}
listmsg->owner = RT_NULL;
#endif
}
/* enable interrupt */
rt_hw_interrupt_enable(level);
if (listmsg != RT_NULL)
{
rt_memcpy(&listmsg->data, &tmpmsg, sizeof(struct rt_can_msg));
level = rt_hw_interrupt_disable();
rt_list_insert_before(&rx_fifo->uselist, &listmsg->list);
#ifdef RT_CAN_USING_HDR
hdr = tmpmsg.hdr_index;
if (can->hdr != RT_NULL)
{
RT_ASSERT(hdr < can->config.maxhdr && hdr >= 0);
if (can->hdr[hdr].connected)
{
rt_list_insert_before(&can->hdr[hdr].list, &listmsg->hdrlist);
listmsg->owner = &can->hdr[hdr];
can->hdr[hdr].msgs++;
}
}
#endif
rt_hw_interrupt_enable(level);
}
/* invoke callback */
#ifdef RT_CAN_USING_HDR
if (can->hdr != RT_NULL && can->hdr[hdr].connected && can->hdr[hdr].filter.ind)
{
rt_size_t rx_length;
RT_ASSERT(hdr < can->config.maxhdr && hdr >= 0);
level = rt_hw_interrupt_disable();
rx_length = can->hdr[hdr].msgs * sizeof(struct rt_can_msg);
rt_hw_interrupt_enable(level);
if (rx_length)
{
can->hdr[hdr].filter.ind(&can->parent, can->hdr[hdr].filter.args, hdr, rx_length);
}
}
else
#endif
{
if (can->parent.rx_indicate != RT_NULL)
{
rt_size_t rx_length;
level = rt_hw_interrupt_disable();
/* get rx length */
rx_length = rt_list_len(&rx_fifo->uselist)* sizeof(struct rt_can_msg);
rt_hw_interrupt_enable(level);
if (rx_length)
{
can->parent.rx_indicate(&can->parent, rx_length);
}
}
}
break;
}
case RT_CAN_EVENT_TX_DONE:
case RT_CAN_EVENT_TX_FAIL:
{
struct rt_can_tx_fifo *tx_fifo;
rt_uint32_t no;
no = event >> 8;
tx_fifo = (struct rt_can_tx_fifo *) can->can_tx;
RT_ASSERT(tx_fifo != RT_NULL);
if ((event & 0xff) == RT_CAN_EVENT_TX_DONE)
{
tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_OK;
}
else
{
tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_ERR;
}
rt_completion_done(&(tx_fifo->buffer[no].completion));
break;
}
}
}
#ifdef RT_USING_FINSH
#include <finsh.h>
int cmd_canstat(int argc, void **argv)
{
static const char *ErrCode[] =
{
"No Error!",
"Warning !",
"Passive !",
"Bus Off !"
};
if (argc >= 2)
{
struct rt_can_status status;
rt_device_t candev = rt_device_find(argv[1]);
if (!candev)
{
rt_kprintf(" Can't find can device %s\n", argv[1]);
return -1;
}
rt_kprintf(" Found can device: %s...", argv[1]);
rt_device_control(candev, RT_CAN_CMD_GET_STATUS, &status);
rt_kprintf("\n Receive...error..count: %010ld. Send.....error....count: %010ld.",
status.rcverrcnt, status.snderrcnt);
rt_kprintf("\n Bit..pad..error..count: %010ld. Format...error....count: %010ld",
status.bitpaderrcnt, status.formaterrcnt);
rt_kprintf("\n Ack.......error..count: %010ld. Bit......error....count: %010ld.",
status.ackerrcnt, status.biterrcnt);
rt_kprintf("\n CRC.......error..count: %010ld. Error.code.[%010ld]: ",
status.crcerrcnt, status.errcode);
switch (status.errcode)
{
case 0:
rt_kprintf("%s.", ErrCode[0]);
break;
case 1:
rt_kprintf("%s.", ErrCode[1]);
break;
case 2:
case 3:
rt_kprintf("%s.", ErrCode[2]);
break;
case 4:
case 5:
case 6:
case 7:
rt_kprintf("%s.", ErrCode[3]);
break;
}
rt_kprintf("\n Total.receive.packages: %010ld. Dropped.receive.packages: %010ld.",
status.rcvpkg, status.dropedrcvpkg);
rt_kprintf("\n Total..send...packages: %010ld. Dropped...send..packages: %010ld.\n",
status.sndpkg + status.dropedsndpkg, status.dropedsndpkg);
}
else
{
rt_kprintf(" Invalid Call %s\n", argv[0]);
rt_kprintf(" Please using %s cannamex .Here canname is driver name and x is candrive number.\n", argv[0]);
}
return 0;
}
MSH_CMD_EXPORT_ALIAS(cmd_canstat, canstat, stat can device status);
#endif

View File

@@ -0,0 +1,464 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-04-25 weety first version
*/
#include <rtdevice.h>
#define DBG_TAG "I2C"
#ifdef RT_I2C_BITOPS_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif
#include <rtdbg.h>
#define SET_SDA(ops, val) ops->set_sda(ops->data, val)
#define SET_SCL(ops, val) ops->set_scl(ops->data, val)
#define GET_SDA(ops) ops->get_sda(ops->data)
#define GET_SCL(ops) ops->get_scl(ops->data)
rt_inline void i2c_delay(struct rt_i2c_bit_ops *ops)
{
ops->udelay((ops->delay_us + 1) >> 1);
}
rt_inline void i2c_delay2(struct rt_i2c_bit_ops *ops)
{
ops->udelay(ops->delay_us);
}
#define SDA_L(ops) SET_SDA(ops, 0)
#define SDA_H(ops) SET_SDA(ops, 1)
#define SCL_L(ops) SET_SCL(ops, 0)
/**
* release scl line, and wait scl line to high.
*/
static rt_err_t SCL_H(struct rt_i2c_bit_ops *ops)
{
rt_tick_t start;
SET_SCL(ops, 1);
if (!ops->get_scl)
goto done;
start = rt_tick_get();
while (!GET_SCL(ops))
{
if ((rt_tick_get() - start) > ops->timeout)
return -RT_ETIMEOUT;
i2c_delay(ops);
}
#ifdef RT_I2C_BITOPS_DEBUG
if (rt_tick_get() != start)
{
LOG_D("wait %ld tick for SCL line to go high",
rt_tick_get() - start);
}
#endif
done:
i2c_delay(ops);
return RT_EOK;
}
static void i2c_start(struct rt_i2c_bit_ops *ops)
{
#ifdef RT_I2C_BITOPS_DEBUG
if (ops->get_scl && !GET_SCL(ops))
{
LOG_E("I2C bus error, SCL line low");
}
if (ops->get_sda && !GET_SDA(ops))
{
LOG_E("I2C bus error, SDA line low");
}
#endif
SDA_L(ops);
i2c_delay(ops);
SCL_L(ops);
}
static void i2c_restart(struct rt_i2c_bit_ops *ops)
{
SDA_H(ops);
SCL_H(ops);
i2c_delay(ops);
SDA_L(ops);
i2c_delay(ops);
SCL_L(ops);
}
static void i2c_stop(struct rt_i2c_bit_ops *ops)
{
SDA_L(ops);
i2c_delay(ops);
SCL_H(ops);
i2c_delay(ops);
SDA_H(ops);
i2c_delay2(ops);
}
rt_inline rt_bool_t i2c_waitack(struct rt_i2c_bit_ops *ops)
{
rt_bool_t ack;
SDA_H(ops);
i2c_delay(ops);
if (SCL_H(ops) < 0)
{
LOG_W("wait ack timeout");
return -RT_ETIMEOUT;
}
ack = !GET_SDA(ops); /* ACK : SDA pin is pulled low */
LOG_D("%s", ack ? "ACK" : "NACK");
SCL_L(ops);
return ack;
}
static rt_int32_t i2c_writeb(struct rt_i2c_bus_device *bus, rt_uint8_t data)
{
rt_int32_t i;
rt_uint8_t bit;
struct rt_i2c_bit_ops *ops = (struct rt_i2c_bit_ops *)bus->priv;
for (i = 7; i >= 0; i--)
{
SCL_L(ops);
bit = (data >> i) & 1;
SET_SDA(ops, bit);
i2c_delay(ops);
if (SCL_H(ops) < 0)
{
LOG_D("i2c_writeb: 0x%02x, "
"wait scl pin high timeout at bit %d",
data, i);
return -RT_ETIMEOUT;
}
}
SCL_L(ops);
i2c_delay(ops);
return i2c_waitack(ops);
}
static rt_int32_t i2c_readb(struct rt_i2c_bus_device *bus)
{
rt_uint8_t i;
rt_uint8_t data = 0;
struct rt_i2c_bit_ops *ops = (struct rt_i2c_bit_ops *)bus->priv;
SDA_H(ops);
i2c_delay(ops);
for (i = 0; i < 8; i++)
{
data <<= 1;
if (SCL_H(ops) < 0)
{
LOG_D("i2c_readb: wait scl pin high "
"timeout at bit %d", 7 - i);
return -RT_ETIMEOUT;
}
if (GET_SDA(ops))
data |= 1;
SCL_L(ops);
i2c_delay2(ops);
}
return data;
}
static rt_ssize_t i2c_send_bytes(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg *msg)
{
rt_int32_t ret;
rt_size_t bytes = 0;
const rt_uint8_t *ptr = msg->buf;
rt_int32_t count = msg->len;
rt_uint16_t ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
while (count > 0)
{
ret = i2c_writeb(bus, *ptr);
if ((ret > 0) || (ignore_nack && (ret == 0)))
{
count --;
ptr ++;
bytes ++;
}
else if (ret == 0)
{
LOG_D("send bytes: NACK.");
return 0;
}
else
{
LOG_E("send bytes: error %d", ret);
return ret;
}
}
return bytes;
}
static rt_err_t i2c_send_ack_or_nack(struct rt_i2c_bus_device *bus, int ack)
{
struct rt_i2c_bit_ops *ops = (struct rt_i2c_bit_ops *)bus->priv;
if (ack)
SET_SDA(ops, 0);
i2c_delay(ops);
if (SCL_H(ops) < 0)
{
LOG_E("ACK or NACK timeout.");
return -RT_ETIMEOUT;
}
SCL_L(ops);
return RT_EOK;
}
static rt_ssize_t i2c_recv_bytes(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg *msg)
{
rt_int32_t val;
rt_int32_t bytes = 0; /* actual bytes */
rt_uint8_t *ptr = msg->buf;
rt_int32_t count = msg->len;
const rt_uint32_t flags = msg->flags;
while (count > 0)
{
val = i2c_readb(bus);
if (val >= 0)
{
*ptr = val;
bytes ++;
}
else
{
break;
}
ptr ++;
count --;
LOG_D("recieve bytes: 0x%02x, %s",
val, (flags & RT_I2C_NO_READ_ACK) ?
"(No ACK/NACK)" : (count ? "ACK" : "NACK"));
if (!(flags & RT_I2C_NO_READ_ACK))
{
val = i2c_send_ack_or_nack(bus, count);
if (val < 0)
return val;
}
}
return bytes;
}
static rt_int32_t i2c_send_address(struct rt_i2c_bus_device *bus,
rt_uint8_t addr,
rt_int32_t retries)
{
struct rt_i2c_bit_ops *ops = (struct rt_i2c_bit_ops *)bus->priv;
rt_int32_t i;
rt_err_t ret = 0;
for (i = 0; i <= retries; i++)
{
ret = i2c_writeb(bus, addr);
if (ret == 1 || i == retries)
break;
LOG_D("send stop condition");
i2c_stop(ops);
i2c_delay2(ops);
LOG_D("send start condition");
i2c_start(ops);
}
return ret;
}
static rt_err_t i2c_bit_send_address(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg *msg)
{
rt_uint16_t flags = msg->flags;
rt_uint16_t ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
struct rt_i2c_bit_ops *ops = (struct rt_i2c_bit_ops *)bus->priv;
rt_uint8_t addr1, addr2;
rt_int32_t retries;
rt_err_t ret;
retries = ignore_nack ? 0 : bus->retries;
if (flags & RT_I2C_ADDR_10BIT)
{
addr1 = 0xf0 | ((msg->addr >> 7) & 0x06);
addr2 = msg->addr & 0xff;
LOG_D("addr1: %d, addr2: %d", addr1, addr2);
ret = i2c_send_address(bus, addr1, retries);
if ((ret != 1) && !ignore_nack)
{
LOG_W("NACK: sending first addr");
return -RT_EIO;
}
ret = i2c_writeb(bus, addr2);
if ((ret != 1) && !ignore_nack)
{
LOG_W("NACK: sending second addr");
return -RT_EIO;
}
if (flags & RT_I2C_RD)
{
LOG_D("send repeated start condition");
i2c_restart(ops);
addr1 |= 0x01;
ret = i2c_send_address(bus, addr1, retries);
if ((ret != 1) && !ignore_nack)
{
LOG_E("NACK: sending repeated addr");
return -RT_EIO;
}
}
}
else
{
/* 7-bit addr */
addr1 = msg->addr << 1;
if (flags & RT_I2C_RD)
addr1 |= 1;
ret = i2c_send_address(bus, addr1, retries);
if ((ret != 1) && !ignore_nack)
return -RT_EIO;
}
return RT_EOK;
}
static rt_ssize_t i2c_bit_xfer(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num)
{
struct rt_i2c_msg *msg;
struct rt_i2c_bit_ops *ops = (struct rt_i2c_bit_ops *)bus->priv;
rt_int32_t ret;
rt_uint32_t i;
rt_uint16_t ignore_nack;
if((ops->i2c_pin_init_flag == RT_FALSE) && (ops->pin_init != RT_NULL))
{
ops->pin_init();
ops->i2c_pin_init_flag = RT_TRUE;
}
if (num == 0) return 0;
for (i = 0; i < num; i++)
{
msg = &msgs[i];
ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
if (!(msg->flags & RT_I2C_NO_START))
{
if (i)
{
i2c_restart(ops);
}
else
{
LOG_D("send start condition");
i2c_start(ops);
}
ret = i2c_bit_send_address(bus, msg);
if ((ret != RT_EOK) && !ignore_nack)
{
LOG_D("receive NACK from device addr 0x%02x msg %d",
msgs[i].addr, i);
goto out;
}
}
if (msg->flags & RT_I2C_RD)
{
ret = i2c_recv_bytes(bus, msg);
if (ret >= 1)
{
LOG_D("read %d byte%s", ret, ret == 1 ? "" : "s");
}
if (ret < msg->len)
{
if (ret >= 0)
ret = -RT_EIO;
goto out;
}
}
else
{
ret = i2c_send_bytes(bus, msg);
if (ret >= 1)
{
LOG_D("write %d byte%s", ret, ret == 1 ? "" : "s");
}
if (ret < msg->len)
{
if (ret >= 0)
ret = -RT_ERROR;
goto out;
}
}
}
ret = i;
out:
if (!(msg->flags & RT_I2C_NO_STOP))
{
LOG_D("send stop condition");
i2c_stop(ops);
}
return ret;
}
static const struct rt_i2c_bus_device_ops i2c_bit_bus_ops =
{
i2c_bit_xfer,
RT_NULL,
RT_NULL
};
rt_err_t rt_i2c_bit_add_bus(struct rt_i2c_bus_device *bus,
const char *bus_name)
{
bus->ops = &i2c_bit_bus_ops;
return rt_i2c_bus_device_register(bus, bus_name);
}

View File

@@ -0,0 +1,182 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-12-06 GuEe-GUI first version
*/
#include <rtdevice.h>
#define DBG_TAG "i2c.bus"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
static struct rt_bus i2c_bus;
void i2c_bus_scan_clients(struct rt_i2c_bus_device *bus)
{
#ifdef RT_USING_OFW
if (bus->parent.ofw_node)
{
struct rt_ofw_node *np = bus->parent.ofw_node, *child_np, *i2c_client_np;
rt_ofw_foreach_available_child_node(np, child_np)
{
rt_uint32_t client_addr;
struct rt_i2c_client *client;
if (rt_ofw_prop_read_bool(child_np, "compatible"))
{
i2c_client_np = child_np;
}
else
{
/* Maybe in i2c-mux */
i2c_client_np = rt_ofw_get_next_child(child_np, RT_NULL);
if (!rt_ofw_prop_read_bool(i2c_client_np, "compatible"))
{
continue;
}
}
client = rt_calloc(1, sizeof(*client));
if (!client)
{
rt_ofw_node_put(i2c_client_np);
LOG_E("Not memory to create i2c client: %s",
rt_ofw_node_full_name(i2c_client_np));
return;
}
rt_ofw_prop_read_u32(i2c_client_np, "reg", &client_addr);
client->parent.ofw_node = i2c_client_np;
client->name = rt_ofw_node_name(i2c_client_np);
client->bus = bus;
client->client_addr = client_addr;
rt_i2c_device_register(client);
if (i2c_client_np != child_np)
{
rt_ofw_node_put(i2c_client_np);
}
}
}
#endif /* RT_USING_OFW */
}
rt_err_t rt_i2c_driver_register(struct rt_i2c_driver *driver)
{
RT_ASSERT(driver != RT_NULL);
driver->parent.bus = &i2c_bus;
return rt_driver_register(&driver->parent);
}
rt_err_t rt_i2c_device_register(struct rt_i2c_client *client)
{
RT_ASSERT(client != RT_NULL);
return rt_bus_add_device(&i2c_bus, &client->parent);
}
static rt_bool_t i2c_match(rt_driver_t drv, rt_device_t dev)
{
const struct rt_i2c_device_id *id;
struct rt_i2c_driver *driver = rt_container_of(drv, struct rt_i2c_driver, parent);
struct rt_i2c_client *client = rt_container_of(dev, struct rt_i2c_client, parent);
if ((id = driver->ids))
{
for (; id->name[0]; ++id)
{
if (!rt_strcmp(id->name, client->name))
{
client->id = id;
client->ofw_id = RT_NULL;
return RT_TRUE;
}
}
}
#ifdef RT_USING_OFW
client->ofw_id = rt_ofw_node_match(client->parent.ofw_node, driver->ofw_ids);
if (client->ofw_id)
{
client->id = RT_NULL;
return RT_TRUE;
}
#endif
return RT_FALSE;
}
static rt_err_t i2c_probe(rt_device_t dev)
{
rt_err_t err;
struct rt_i2c_driver *driver = rt_container_of(dev->drv, struct rt_i2c_driver, parent);
struct rt_i2c_client *client = rt_container_of(dev, struct rt_i2c_client, parent);
if (!client->bus)
{
return -RT_EINVAL;
}
err = driver->probe(client);
return err;
}
static rt_err_t i2c_remove(rt_device_t dev)
{
struct rt_i2c_driver *driver = rt_container_of(dev->drv, struct rt_i2c_driver, parent);
struct rt_i2c_client *client = rt_container_of(dev, struct rt_i2c_client, parent);
if (driver && driver->remove)
{
driver->remove(client);
}
return RT_EOK;
}
static rt_err_t i2c_shutdown(rt_device_t dev)
{
struct rt_i2c_driver *driver = rt_container_of(dev->drv, struct rt_i2c_driver, parent);
struct rt_i2c_client *client = rt_container_of(dev, struct rt_i2c_client, parent);
if (driver && driver->shutdown)
{
driver->shutdown(client);
}
return RT_EOK;
}
static struct rt_bus i2c_bus =
{
.name = "i2c",
.match = i2c_match,
.probe = i2c_probe,
.remove = i2c_remove,
.shutdown = i2c_shutdown,
};
static int i2c_bus_init(void)
{
rt_bus_register(&i2c_bus);
return 0;
}
INIT_CORE_EXPORT(i2c_bus_init);

View File

@@ -0,0 +1,153 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-04-25 weety first version
* 2021-04-20 RiceChen added support for bus control api
*/
#include <rtdevice.h>
#define DBG_TAG "I2C"
#ifdef RT_I2C_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif
#include <rtdbg.h>
rt_err_t rt_i2c_bus_device_register(struct rt_i2c_bus_device *bus,
const char *bus_name)
{
rt_err_t res = RT_EOK;
rt_mutex_init(&bus->lock, "i2c_bus_lock", RT_IPC_FLAG_PRIO);
if (bus->timeout == 0) bus->timeout = RT_TICK_PER_SECOND;
res = rt_i2c_bus_device_device_init(bus, bus_name);
LOG_I("I2C bus [%s] registered", bus_name);
#ifdef RT_USING_DM
if (!res)
{
i2c_bus_scan_clients(bus);
}
#endif
return res;
}
struct rt_i2c_bus_device *rt_i2c_bus_device_find(const char *bus_name)
{
struct rt_i2c_bus_device *bus;
rt_device_t dev = rt_device_find(bus_name);
if (dev == RT_NULL || dev->type != RT_Device_Class_I2CBUS)
{
LOG_E("I2C bus %s not exist", bus_name);
return RT_NULL;
}
bus = (struct rt_i2c_bus_device *)dev->user_data;
return bus;
}
rt_ssize_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num)
{
rt_ssize_t ret;
rt_err_t err;
if (bus->ops->master_xfer)
{
#ifdef RT_I2C_DEBUG
for (ret = 0; ret < num; ret++)
{
LOG_D("msgs[%d] %c, addr=0x%02x, len=%d", ret,
(msgs[ret].flags & RT_I2C_RD) ? 'R' : 'W',
msgs[ret].addr, msgs[ret].len);
}
#endif
err = rt_mutex_take(&bus->lock, RT_WAITING_FOREVER);
if (err != RT_EOK)
{
return (rt_ssize_t)err;
}
ret = bus->ops->master_xfer(bus, msgs, num);
err = rt_mutex_release(&bus->lock);
if (err != RT_EOK)
{
return (rt_ssize_t)err;
}
return ret;
}
else
{
LOG_E("I2C bus operation not supported");
return -RT_EINVAL;
}
}
rt_err_t rt_i2c_control(struct rt_i2c_bus_device *bus,
int cmd,
void *args)
{
rt_err_t ret;
if(bus->ops->i2c_bus_control)
{
ret = bus->ops->i2c_bus_control(bus, cmd, args);
return ret;
}
else
{
LOG_E("I2C bus operation not supported");
return -RT_EINVAL;
}
}
rt_ssize_t rt_i2c_master_send(struct rt_i2c_bus_device *bus,
rt_uint16_t addr,
rt_uint16_t flags,
const rt_uint8_t *buf,
rt_uint32_t count)
{
rt_ssize_t ret;
struct rt_i2c_msg msg;
msg.addr = addr;
msg.flags = flags;
msg.len = count;
msg.buf = (rt_uint8_t *)buf;
ret = rt_i2c_transfer(bus, &msg, 1);
return (ret == 1) ? count : ret;
}
rt_ssize_t rt_i2c_master_recv(struct rt_i2c_bus_device *bus,
rt_uint16_t addr,
rt_uint16_t flags,
rt_uint8_t *buf,
rt_uint32_t count)
{
rt_ssize_t ret;
struct rt_i2c_msg msg;
RT_ASSERT(bus != RT_NULL);
msg.addr = addr;
msg.flags = flags | RT_I2C_RD;
msg.len = count;
msg.buf = buf;
ret = rt_i2c_transfer(bus, &msg, 1);
return (ret == 1) ? count : ret;
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-04-25 weety first version
* 2014-08-03 bernard fix some compiling warning
* 2021-04-20 RiceChen added support for bus clock control
*/
#include <rtdevice.h>
#define DBG_TAG "I2C"
#ifdef RT_I2C_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif
#include <rtdbg.h>
static rt_ssize_t i2c_bus_device_read(rt_device_t dev,
rt_off_t pos,
void *buffer,
rt_size_t count)
{
rt_uint16_t addr;
rt_uint16_t flags;
struct rt_i2c_bus_device *bus = (struct rt_i2c_bus_device *)dev->user_data;
RT_ASSERT(bus != RT_NULL);
RT_ASSERT(buffer != RT_NULL);
LOG_D("I2C bus dev [%s] reading %u bytes.", dev->parent.name, count);
addr = pos & 0xffff;
flags = (pos >> 16) & 0xffff;
return rt_i2c_master_recv(bus, addr, flags, (rt_uint8_t *)buffer, count);
}
static rt_ssize_t i2c_bus_device_write(rt_device_t dev,
rt_off_t pos,
const void *buffer,
rt_size_t count)
{
rt_uint16_t addr;
rt_uint16_t flags;
struct rt_i2c_bus_device *bus = (struct rt_i2c_bus_device *)dev->user_data;
RT_ASSERT(bus != RT_NULL);
RT_ASSERT(buffer != RT_NULL);
LOG_D("I2C bus dev [%s] writing %u bytes.", dev->parent.name, count);
addr = pos & 0xffff;
flags = (pos >> 16) & 0xffff;
return rt_i2c_master_send(bus, addr, flags, (const rt_uint8_t *)buffer, count);
}
static rt_err_t i2c_bus_device_control(rt_device_t dev,
int cmd,
void *args)
{
rt_err_t ret;
struct rt_i2c_priv_data *priv_data;
struct rt_i2c_bus_device *bus = (struct rt_i2c_bus_device *)dev->user_data;
RT_ASSERT(bus != RT_NULL);
switch (cmd)
{
/* set 10-bit addr mode */
case RT_I2C_DEV_CTRL_10BIT:
bus->flags |= RT_I2C_ADDR_10BIT;
break;
case RT_I2C_DEV_CTRL_TIMEOUT:
bus->timeout = *(rt_uint32_t *)args;
break;
case RT_I2C_DEV_CTRL_RW:
priv_data = (struct rt_i2c_priv_data *)args;
ret = rt_i2c_transfer(bus, priv_data->msgs, priv_data->number);
if (ret < 0)
{
return -RT_EIO;
}
break;
default:
return rt_i2c_control(bus, cmd, args);
}
return RT_EOK;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops i2c_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
i2c_bus_device_read,
i2c_bus_device_write,
i2c_bus_device_control
};
#endif
rt_err_t rt_i2c_bus_device_device_init(struct rt_i2c_bus_device *bus,
const char *name)
{
struct rt_device *device;
RT_ASSERT(bus != RT_NULL);
device = &bus->parent;
device->user_data = bus;
/* set device type */
device->type = RT_Device_Class_I2CBUS;
/* initialize device interface */
#ifdef RT_USING_DEVICE_OPS
device->ops = &i2c_ops;
#else
device->init = RT_NULL;
device->open = RT_NULL;
device->close = RT_NULL;
device->read = i2c_bus_device_read;
device->write = i2c_bus_device_write;
device->control = i2c_bus_device_control;
#endif
/* register to device manager */
rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
return RT_EOK;
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-12-06 GuEe-GUI first version
*/
#include <rtdevice.h>
#define DBG_TAG "i2c.dm"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#ifdef RT_USING_OFW
static void i2c_parse_timing(struct rt_ofw_node *dev_np, const char *propname,
rt_uint32_t *out_value, rt_uint32_t def_value, rt_bool_t use_defaults)
{
if (rt_ofw_prop_read_u32(dev_np, propname, out_value) && use_defaults)
{
*out_value = def_value;
}
}
rt_err_t i2c_timings_ofw_parse(struct rt_ofw_node *dev_np, struct i2c_timings *timings,
rt_bool_t use_defaults)
{
rt_ubase_t def;
rt_bool_t udef = use_defaults;
struct i2c_timings *t = timings;
i2c_parse_timing(dev_np, "clock-frequency", &t->bus_freq_hz, I2C_MAX_STANDARD_MODE_FREQ, udef);
def = t->bus_freq_hz <= I2C_MAX_STANDARD_MODE_FREQ ? 1000 : t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ ? 300 : 120;
i2c_parse_timing(dev_np, "i2c-scl-rising-time-ns", &t->scl_rise_ns, def, udef);
def = t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ ? 300 : 120;
i2c_parse_timing(dev_np, "i2c-scl-falling-time-ns", &t->scl_fall_ns, def, udef);
i2c_parse_timing(dev_np, "i2c-scl-internal-delay-ns", &t->scl_int_delay_ns, 0, udef);
i2c_parse_timing(dev_np, "i2c-sda-falling-time-ns", &t->sda_fall_ns, t->scl_fall_ns, udef);
i2c_parse_timing(dev_np, "i2c-sda-hold-time-ns", &t->sda_hold_ns, 0, udef);
i2c_parse_timing(dev_np, "i2c-digital-filter-width-ns", &t->digital_filter_width_ns, 0, udef);
i2c_parse_timing(dev_np, "i2c-analog-filter-cutoff-frequency", &t->analog_filter_cutoff_freq_hz, 0, udef);
return RT_EOK;
}
#endif /* RT_USING_OFW */

View File

@@ -0,0 +1,264 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-07-30 sp-cai first version
*/
#include <rtdevice.h>
#ifdef RT_USING_SOFT_I2C
#if !defined(RT_USING_SOFT_I2C1) && !defined(RT_USING_SOFT_I2C2) &&\
!defined(RT_USING_SOFT_I2C3) && !defined(RT_USING_SOFT_I2C4) &&\
!defined(RT_USING_SOFT_I2C5) && !defined(RT_USING_SOFT_I2C6) &&\
!defined(RT_USING_SOFT_I2C7) && !defined(RT_USING_SOFT_I2C8)
#error "Please define at least one RT_USING_SOFT_I2Cx"
/*
This driver can be disabled at:
menuconfig -> RT-Thread Components -> Device Drivers -> Using I2C device drivers
*/
#endif
#define DBG_ENABLE
#define DBG_TAG "I2C_S"
#ifdef RT_I2C_BITOPS_DEBUG
#define DBG_LEVEL DBG_LOG
#endif
#include <rtdbg.h>
/* i2c config class */
struct soft_i2c_config
{
rt_base_t scl_pin;
rt_base_t sda_pin;
const char *bus_name;
rt_uint16_t timing_delay; /* scl and sda line delay */
rt_uint16_t timing_timeout; /* in tick */
};
/* i2c dirver class */
struct rt_soft_i2c
{
struct rt_i2c_bus_device i2c_bus;
struct rt_i2c_bit_ops ops;
};
struct soft_i2c_config i2c_cfg[] =
{
#ifdef RT_USING_SOFT_I2C1
{
.scl_pin = RT_SOFT_I2C1_SCL_PIN,
.sda_pin = RT_SOFT_I2C1_SDA_PIN,
.bus_name = RT_SOFT_I2C1_BUS_NAME,
.timing_delay = RT_SOFT_I2C1_TIMING_DELAY,
.timing_timeout = RT_SOFT_I2C1_TIMING_TIMEOUT,
},
#endif //RT_USING_SOFT_I2C1
#ifdef RT_USING_SOFT_I2C2
{
.scl_pin = RT_SOFT_I2C2_SCL_PIN,
.sda_pin = RT_SOFT_I2C2_SDA_PIN,
.bus_name = RT_SOFT_I2C2_BUS_NAME,
.timing_delay = RT_SOFT_I2C2_TIMING_DELAY,
.timing_timeout = RT_SOFT_I2C2_TIMING_TIMEOUT,
},
#endif //RT_USING_SOFT_I2C2
#ifdef RT_USING_SOFT_I2C3
{
.scl_pin = RT_SOFT_I2C3_SCL_PIN,
.sda_pin = RT_SOFT_I2C3_SDA_PIN,
.bus_name = RT_SOFT_I2C3_BUS_NAME,
.timing_delay = RT_SOFT_I2C3_TIMING_DELAY,
.timing_timeout = RT_SOFT_I2C3_TIMING_TIMEOUT,
},
#endif //RT_USING_SOFT_I2C3
#ifdef RT_USING_SOFT_I2C4
{
.scl_pin = RT_SOFT_I2C4_SCL_PIN,
.sda_pin = RT_SOFT_I2C4_SDA_PIN,
.bus_name = RT_SOFT_I2C4_BUS_NAME,
.timing_delay = RT_SOFT_I2C4_TIMING_DELAY,
.timing_timeout = RT_SOFT_I2C4_TIMING_TIMEOUT,
},
#endif //RT_USING_SOFT_I2C4
#ifdef RT_USING_SOFT_I2C5
{
.scl_pin = RT_SOFT_I2C5_SCL_PIN,
.sda_pin = RT_SOFT_I2C5_SDA_PIN,
.bus_name = RT_SOFT_I2C5_BUS_NAME,
.timing_delay = RT_SOFT_I2C5_TIMING_DELAY,
.timing_timeout = RT_SOFT_I2C5_TIMING_TIMEOUT,
},
#endif //RT_USING_SOFT_I2C5
#ifdef RT_USING_SOFT_I2C6
{
.scl_pin = RT_SOFT_I2C6_SCL_PIN,
.sda_pin = RT_SOFT_I2C6_SDA_PIN,
.bus_name = RT_SOFT_I2C6_BUS_NAME,
.timing_delay = RT_SOFT_I2C6_TIMING_DELAY,
.timing_timeout = RT_SOFT_I2C6_TIMING_TIMEOUT,
},
#endif //RT_USING_SOFT_I2C6
#ifdef RT_USING_SOFT_I2C7
{
.scl_pin = RT_SOFT_I2C7_SCL_PIN,
.sda_pin = RT_SOFT_I2C7_SDA_PIN,
.bus_name = RT_SOFT_I2C7_BUS_NAME,
.timing_delay = RT_SOFT_I2C7_TIMING_DELAY,
.timing_timeout = RT_SOFT_I2C7_TIMING_TIMEOUT,
},
#endif //RT_USING_SOFT_I2C7
#ifdef RT_USING_SOFT_I2C8
{
.scl_pin = RT_SOFT_I2C8_SCL_PIN,
.sda_pin = RT_SOFT_I2C8_SDA_PIN,
.bus_name = RT_SOFT_I2C8_BUS_NAME,
.timing_delay = RT_SOFT_I2C8_TIMING_DELAY,
.timing_timeout = RT_SOFT_I2C8_TIMING_TIMEOUT,
},
#endif //RT_USING_SOFT_I2C8
};
static struct rt_soft_i2c i2c_bus_obj[sizeof(i2c_cfg) / sizeof(i2c_cfg[0])] =
{ 0 };
/**
* This function initializes the i2c pin.
* @param i2c config class.
*/
static void pin_init(const struct soft_i2c_config *cfg)
{
rt_pin_mode(cfg->scl_pin, PIN_MODE_OUTPUT_OD);
rt_pin_mode(cfg->sda_pin, PIN_MODE_OUTPUT_OD);
rt_pin_write(cfg->scl_pin, PIN_HIGH);
rt_pin_write(cfg->sda_pin, PIN_HIGH);
}
/**
* This function sets the sda pin.
* @param i2c config class.
* @param The sda pin state.
*/
static void set_sda(void *cfg, rt_int32_t value)
{
rt_pin_write(((const struct soft_i2c_config*)cfg)->sda_pin, value);
}
/**
* This function sets the scl pin.
* @param i2c config class.
* @param The sda pin state.
*/
static void set_scl(void *cfg, rt_int32_t value)
{
rt_pin_write(((const struct soft_i2c_config*)cfg)->scl_pin, value);
}
/**
* This function gets the sda pin state.
* @param i2c config class.
*/
static rt_int32_t get_sda(void *cfg)
{
return rt_pin_read(((const struct soft_i2c_config*)cfg)->sda_pin);
}
/**
* This function gets the scl pin state.
* @param i2c config class.
*/
static rt_int32_t get_scl(void *cfg)
{
return rt_pin_read(((const struct soft_i2c_config*)cfg)->scl_pin);
}
static const struct rt_i2c_bit_ops soft_i2c_ops =
{
.set_sda = set_sda,
.set_scl = set_scl,
.get_sda = get_sda,
.get_scl = get_scl,
.udelay = rt_hw_us_delay,
};
/**
* if i2c is locked, this function will unlock it
*
* @param i2c config class.
*
* @return RT_EOK indicates successful unlock.
*/
static rt_err_t i2c_bus_unlock(const struct soft_i2c_config *cfg)
{
rt_ubase_t i = 0;
if(PIN_LOW == rt_pin_read(cfg->sda_pin))
{
while(i++ < 9)
{
rt_pin_write(cfg->scl_pin, PIN_HIGH);
rt_hw_us_delay(cfg->timing_delay);
rt_pin_write(cfg->scl_pin, PIN_LOW);
rt_hw_us_delay(cfg->timing_delay);
}
}
if(PIN_LOW == rt_pin_read(cfg->sda_pin))
{
return -RT_ERROR;
}
return RT_EOK;
}
/* I2C initialization function */
int rt_soft_i2c_init(void)
{
int err = RT_EOK;
struct rt_soft_i2c *obj;
int i;
for(i = 0; i < sizeof(i2c_bus_obj) / sizeof(i2c_bus_obj[0]); i++)
{
struct soft_i2c_config *cfg = &i2c_cfg[i];
pin_init(cfg);
obj = &i2c_bus_obj[i];
obj->ops = soft_i2c_ops;
obj->ops.data = cfg;
obj->i2c_bus.priv = &obj->ops;
obj->ops.delay_us = cfg->timing_delay;
obj->ops.timeout = cfg->timing_timeout;
if(rt_i2c_bit_add_bus(&obj->i2c_bus, cfg->bus_name) == RT_EOK)
{
i2c_bus_unlock(cfg);
LOG_D("Software simulation %s init done"
", SCL pin: 0x%02X, SDA pin: 0x%02X"
, cfg->bus_name
, cfg->scl_pin
, cfg->sda_pin
);
}
else
{
err++;
LOG_E("Software simulation %s init fail"
", SCL pin: 0x%02X, SDA pin: 0x%02X"
, cfg->bus_name
, cfg->scl_pin
, cfg->sda_pin
);
}
}
return err;
}
INIT_PREV_EXPORT(rt_soft_i2c_init);
#endif // RT_USING_SOFT_I2C

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-10-27 heyuanjie87 first version.
* 2013-05-17 aozima initial alarm event & mutex in system init.
* 2020-10-15 zhangsz add alarm flags hour minute second.
*/
#ifndef __ALARM_H__
#define __ALARM_H__
#include <sys/time.h>
#include <rtdef.h>
#define RT_ALARM_TM_NOW -1 /* set the alarm tm_day,tm_mon,tm_sec,etc.
to now.we also call it "don't care" value */
/* alarm flags */
#define RT_ALARM_ONESHOT 0x000 /* only alarm once */
#define RT_ALARM_DAILY 0x100 /* alarm everyday */
#define RT_ALARM_WEEKLY 0x200 /* alarm weekly at Monday or Friday etc. */
#define RT_ALARM_MONTHLY 0x400 /* alarm monthly at someday */
#define RT_ALARM_YAERLY 0x800 /* alarm yearly at a certain date */
#define RT_ALARM_HOUR 0x1000 /* alarm each hour at a certain min:second */
#define RT_ALARM_MINUTE 0x2000 /* alarm each minute at a certain second */
#define RT_ALARM_SECOND 0x4000 /* alarm each second */
#define RT_ALARM_STATE_INITED 0x02
#define RT_ALARM_STATE_START 0x01
#define RT_ALARM_STATE_STOP 0x00
/* alarm control cmd */
#define RT_ALARM_CTRL_MODIFY 1 /* modify alarm time or alarm flag */
typedef struct rt_alarm *rt_alarm_t;
typedef void (*rt_alarm_callback_t)(rt_alarm_t alarm, time_t timestamp);
struct rt_alarm
{
rt_list_t list;
rt_uint32_t flag;
rt_alarm_callback_t callback;
struct tm wktime;
void *user_data;
};
struct rt_alarm_setup
{
rt_uint32_t flag; /* alarm flag */
struct tm wktime; /* when will the alarm wake up user */
};
struct rt_alarm_container
{
rt_list_t head;
struct rt_mutex mutex;
struct rt_event event;
struct rt_alarm *current;
};
rt_alarm_t rt_alarm_create(rt_alarm_callback_t callback,
struct rt_alarm_setup *setup);
rt_err_t rt_alarm_control(rt_alarm_t alarm, int cmd, void *arg);
void rt_alarm_update(rt_device_t dev, rt_uint32_t event);
rt_err_t rt_alarm_delete(rt_alarm_t alarm);
rt_err_t rt_alarm_start(rt_alarm_t alarm);
rt_err_t rt_alarm_stop(rt_alarm_t alarm);
int rt_alarm_system_init(void);
#endif /* __ALARM_H__ */

View File

@@ -0,0 +1,176 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-05-09 Urey first version
* 2019-07-09 Zero-Free improve device ops interface and data flows
*
*/
#ifndef __AUDIO_H__
#define __AUDIO_H__
#include "audio_pipe.h"
/* AUDIO command */
#define _AUDIO_CTL(a) (RT_DEVICE_CTRL_BASE(Sound) + a)
#define AUDIO_CTL_GETCAPS _AUDIO_CTL(1)
#define AUDIO_CTL_CONFIGURE _AUDIO_CTL(2)
#define AUDIO_CTL_START _AUDIO_CTL(3)
#define AUDIO_CTL_STOP _AUDIO_CTL(4)
#define AUDIO_CTL_GETBUFFERINFO _AUDIO_CTL(5)
/* Audio Device Types */
#define AUDIO_TYPE_QUERY 0x00
#define AUDIO_TYPE_INPUT 0x01
#define AUDIO_TYPE_OUTPUT 0x02
#define AUDIO_TYPE_MIXER 0x04
/* Supported Sampling Rates */
#define AUDIO_SAMP_RATE_8K 0x0001
#define AUDIO_SAMP_RATE_11K 0x0002
#define AUDIO_SAMP_RATE_16K 0x0004
#define AUDIO_SAMP_RATE_22K 0x0008
#define AUDIO_SAMP_RATE_32K 0x0010
#define AUDIO_SAMP_RATE_44K 0x0020
#define AUDIO_SAMP_RATE_48K 0x0040
#define AUDIO_SAMP_RATE_96K 0x0080
#define AUDIO_SAMP_RATE_128K 0x0100
#define AUDIO_SAMP_RATE_160K 0x0200
#define AUDIO_SAMP_RATE_172K 0x0400
#define AUDIO_SAMP_RATE_192K 0x0800
/* Supported Bit Rates */
#define AUDIO_BIT_RATE_22K 0x01
#define AUDIO_BIT_RATE_44K 0x02
#define AUDIO_BIT_RATE_48K 0x04
#define AUDIO_BIT_RATE_96K 0x08
#define AUDIO_BIT_RATE_128K 0x10
#define AUDIO_BIT_RATE_160K 0x20
#define AUDIO_BIT_RATE_172K 0x40
#define AUDIO_BIT_RATE_192K 0x80
/* Support Dsp(input/output) Units controls */
#define AUDIO_DSP_PARAM 0 /* get/set all params */
#define AUDIO_DSP_SAMPLERATE 1 /* samplerate */
#define AUDIO_DSP_CHANNELS 2 /* channels */
#define AUDIO_DSP_SAMPLEBITS 3 /* sample bits width */
/* Supported Mixer Units controls */
#define AUDIO_MIXER_QUERY 0x0000
#define AUDIO_MIXER_MUTE 0x0001
#define AUDIO_MIXER_VOLUME 0x0002
#define AUDIO_MIXER_BASS 0x0004
#define AUDIO_MIXER_MID 0x0008
#define AUDIO_MIXER_TREBLE 0x0010
#define AUDIO_MIXER_EQUALIZER 0x0020
#define AUDIO_MIXER_LINE 0x0040
#define AUDIO_MIXER_DIGITAL 0x0080
#define AUDIO_MIXER_MIC 0x0100
#define AUDIO_MIXER_VITURAL 0x0200
#define AUDIO_MIXER_EXTEND 0x8000 /* extend mixer command */
#define AUDIO_VOLUME_MAX (100)
#define AUDIO_VOLUME_MIN (0)
#define CFG_AUDIO_REPLAY_QUEUE_COUNT 4
enum
{
AUDIO_STREAM_REPLAY = 0,
AUDIO_STREAM_RECORD,
AUDIO_STREAM_LAST = AUDIO_STREAM_RECORD,
};
/* the preferred number and size of audio pipeline buffer for the audio device */
struct rt_audio_buf_info
{
rt_uint8_t *buffer;
rt_uint16_t block_size;
rt_uint16_t block_count;
rt_uint32_t total_size;
};
struct rt_audio_device;
struct rt_audio_caps;
struct rt_audio_configure;
struct rt_audio_ops
{
rt_err_t (*getcaps)(struct rt_audio_device *audio, struct rt_audio_caps *caps);
rt_err_t (*configure)(struct rt_audio_device *audio, struct rt_audio_caps *caps);
rt_err_t (*init)(struct rt_audio_device *audio);
rt_err_t (*start)(struct rt_audio_device *audio, int stream);
rt_err_t (*stop)(struct rt_audio_device *audio, int stream);
rt_ssize_t (*transmit)(struct rt_audio_device *audio, const void *writeBuf, void *readBuf, rt_size_t size);
/* get page size of codec or private buffer's info */
void (*buffer_info)(struct rt_audio_device *audio, struct rt_audio_buf_info *info);
};
struct rt_audio_configure
{
rt_uint32_t samplerate;
rt_uint16_t channels;
rt_uint16_t samplebits;
};
struct rt_audio_caps
{
int main_type;
int sub_type;
union
{
rt_uint32_t mask;
int value;
struct rt_audio_configure config;
} udata;
};
struct rt_audio_replay
{
struct rt_mempool *mp;
struct rt_data_queue queue;
struct rt_mutex lock;
struct rt_completion cmp;
struct rt_audio_buf_info buf_info;
rt_uint8_t *write_data;
rt_uint16_t write_index;
rt_uint16_t read_index;
rt_uint32_t pos;
rt_uint8_t event;
rt_bool_t activated;
};
struct rt_audio_record
{
struct rt_audio_pipe pipe;
rt_bool_t activated;
};
struct rt_audio_device
{
struct rt_device parent;
struct rt_audio_ops *ops;
struct rt_audio_replay *replay;
struct rt_audio_record *record;
};
rt_err_t rt_audio_register(struct rt_audio_device *audio, const char *name, rt_uint32_t flag, void *data);
void rt_audio_tx_complete(struct rt_audio_device *audio);
void rt_audio_rx_done(struct rt_audio_device *audio, rt_uint8_t *pbuf, rt_size_t len);
/* Device Control Commands */
#define CODEC_CMD_RESET 0
#define CODEC_CMD_SET_VOLUME 1
#define CODEC_CMD_GET_VOLUME 2
#define CODEC_CMD_SAMPLERATE 3
#define CODEC_CMD_EQ 4
#define CODEC_CMD_3D 5
#define CODEC_VOLUME_MAX (63)
#endif /* __AUDIO_H__ */

View File

@@ -0,0 +1,364 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2015-05-14 aubrcool@qq.com first version
* 2015-07-06 Bernard remove RT_CAN_USING_LED.
* 2022-05-08 hpmicro add CANFD support, fixed typos
*/
#ifndef CAN_H_
#define CAN_H_
#include <rtthread.h>
#ifndef RT_CANMSG_BOX_SZ
#define RT_CANMSG_BOX_SZ 16
#endif
#ifndef RT_CANSND_BOX_NUM
#define RT_CANSND_BOX_NUM 1
#endif
enum CAN_DLC
{
CAN_MSG_0BYTE = 0,
CAN_MSG_1BYTE,
CAN_MSG_2BYTES,
CAN_MSG_3BYTES,
CAN_MSG_4BYTES,
CAN_MSG_5BYTES,
CAN_MSG_6BYTES,
CAN_MSG_7BYTES,
CAN_MSG_8BYTES,
CAN_MSG_12BYTES,
CAN_MSG_16BYTES,
CAN_MSG_20BYTES,
CAN_MSG_24BYTES,
CAN_MSG_32BYTES,
CAN_MSG_48BYTES,
CAN_MSG_64BYTES,
};
enum CANBAUD
{
CAN1MBaud = 1000UL * 1000,/* 1 MBit/sec */
CAN800kBaud = 1000UL * 800, /* 800 kBit/sec */
CAN500kBaud = 1000UL * 500, /* 500 kBit/sec */
CAN250kBaud = 1000UL * 250, /* 250 kBit/sec */
CAN125kBaud = 1000UL * 125, /* 125 kBit/sec */
CAN100kBaud = 1000UL * 100, /* 100 kBit/sec */
CAN50kBaud = 1000UL * 50, /* 50 kBit/sec */
CAN20kBaud = 1000UL * 20, /* 20 kBit/sec */
CAN10kBaud = 1000UL * 10 /* 10 kBit/sec */
};
#define RT_CAN_MODE_NORMAL 0
#define RT_CAN_MODE_LISTEN 1
#define RT_CAN_MODE_LOOPBACK 2
#define RT_CAN_MODE_LOOPBACKANLISTEN 3
#define RT_CAN_MODE_PRIV 0x01
#define RT_CAN_MODE_NOPRIV 0x00
/** @defgroup CAN_receive_FIFO_number CAN Receive FIFO Number
* @{
*/
#define CAN_RX_FIFO0 (0x00000000U) /*!< CAN receive FIFO 0 */
#define CAN_RX_FIFO1 (0x00000001U) /*!< CAN receive FIFO 1 */
struct rt_can_filter_item
{
rt_uint32_t id : 29;
rt_uint32_t ide : 1;
rt_uint32_t rtr : 1;
rt_uint32_t mode : 1;
rt_uint32_t mask;
rt_int32_t hdr_bank;/*Should be defined as:rx.FilterBank,which should be changed to rt_int32_t hdr_bank*/
rt_uint32_t rxfifo;/*Add a configuration item that CAN_RX_FIFO0/CAN_RX_FIFO1*/
#ifdef RT_CAN_USING_HDR
rt_err_t (*ind)(rt_device_t dev, void *args , rt_int32_t hdr, rt_size_t size);
void *args;
#endif /*RT_CAN_USING_HDR*/
};
#ifdef RT_CAN_USING_HDR
#define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask,ind,args) \
{(id), (ide), (rtr), (mode),(mask), -1, CAN_RX_FIFO0,(ind), (args)}/*0:CAN_RX_FIFO0*/
#define RT_CAN_FILTER_STD_INIT(id,ind,args) \
RT_CAN_FILTER_ITEM_INIT(id,0,0,0,0xFFFFFFFF,ind,args)
#define RT_CAN_FILTER_EXT_INIT(id,ind,args) \
RT_CAN_FILTER_ITEM_INIT(id,1,0,0,0xFFFFFFFF,ind,args)
#define RT_CAN_STD_RMT_FILTER_INIT(id,ind,args) \
RT_CAN_FILTER_ITEM_INIT(id,0,1,0,0xFFFFFFFF,ind,args)
#define RT_CAN_EXT_RMT_FILTER_INIT(id,ind,args) \
RT_CAN_FILTER_ITEM_INIT(id,1,1,0,0xFFFFFFFF,ind,args)
#define RT_CAN_STD_RMT_DATA_FILTER_INIT(id,ind,args) \
RT_CAN_FILTER_ITEM_INIT(id,0,0,1,0xFFFFFFFF,ind,args)
#define RT_CAN_EXT_RMT_DATA_FILTER_INIT(id,ind,args) \
RT_CAN_FILTER_ITEM_INIT(id,1,0,1,0xFFFFFFFF,ind,args)
#else
#define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask) \
{(id), (ide), (rtr), (mode), (mask), -1, CAN_RX_FIFO0 }/*0:CAN_RX_FIFO0*/
#define RT_CAN_FILTER_STD_INIT(id) \
RT_CAN_FILTER_ITEM_INIT(id,0,0,0,0xFFFFFFFF)
#define RT_CAN_FILTER_EXT_INIT(id) \
RT_CAN_FILTER_ITEM_INIT(id,1,0,0,0xFFFFFFFF)
#define RT_CAN_STD_RMT_FILTER_INIT(id) \
RT_CAN_FILTER_ITEM_INIT(id,0,1,0,0xFFFFFFFF)
#define RT_CAN_EXT_RMT_FILTER_INIT(id) \
RT_CAN_FILTER_ITEM_INIT(id,1,1,0,0xFFFFFFFF)
#define RT_CAN_STD_RMT_DATA_FILTER_INIT(id) \
RT_CAN_FILTER_ITEM_INIT(id,0,0,1,0xFFFFFFFF)
#define RT_CAN_EXT_RMT_DATA_FILTER_INIT(id) \
RT_CAN_FILTER_ITEM_INIT(id,1,0,1,0xFFFFFFFF)
#endif
struct rt_can_filter_config
{
rt_uint32_t count;
rt_uint32_t actived;
struct rt_can_filter_item *items;
};
struct rt_can_bit_timing
{
rt_uint16_t prescaler; /* Pre-scaler */
rt_uint16_t num_seg1; /* Bit Timing Segment 1, in terms of Tq */
rt_uint16_t num_seg2; /* Bit Timing Segment 2, in terms of Tq */
rt_uint8_t num_sjw; /* Synchronization Jump Width, in terms of Tq */
rt_uint8_t num_sspoff; /* Secondary Sample Point Offset, in terms of Tq */
};
/**
* CAN bit timing configuration list
* NOTE:
* items[0] always for CAN2.0/CANFD Arbitration Phase
* items[1] always for CANFD (if it exists)
*/
struct rt_can_bit_timing_config
{
rt_uint32_t count;
struct rt_can_bit_timing *items;
};
struct can_configure
{
rt_uint32_t baud_rate;
rt_uint32_t msgboxsz;
rt_uint32_t sndboxnumber;
rt_uint32_t mode : 8;
rt_uint32_t privmode : 8;
rt_uint32_t reserved : 16;
rt_uint32_t ticks;
#ifdef RT_CAN_USING_HDR
rt_uint32_t maxhdr;
#endif
#ifdef RT_CAN_USING_CANFD
rt_uint32_t baud_rate_fd; /* CANFD data bit rate*/
rt_uint32_t use_bit_timing: 8; /* Use the bit timing for CAN timing configuration */
rt_uint32_t enable_canfd : 8; /* Enable CAN-FD mode */
rt_uint32_t reserved1 : 16;
/* The below fields take effect only if use_bit_timing is non-zero */
struct rt_can_bit_timing can_timing; /* CAN bit-timing /CANFD bit-timing for arbitration phase */
struct rt_can_bit_timing canfd_timing; /* CANFD bit-timing for datat phase */
#endif
};
#define CANDEFAULTCONFIG \
{\
CAN1MBaud,\
RT_CANMSG_BOX_SZ,\
RT_CANSND_BOX_NUM,\
RT_CAN_MODE_NORMAL,\
};
struct rt_can_ops;
#define RT_CAN_CMD_SET_FILTER 0x13
#define RT_CAN_CMD_SET_BAUD 0x14
#define RT_CAN_CMD_SET_MODE 0x15
#define RT_CAN_CMD_SET_PRIV 0x16
#define RT_CAN_CMD_GET_STATUS 0x17
#define RT_CAN_CMD_SET_STATUS_IND 0x18
#define RT_CAN_CMD_SET_BUS_HOOK 0x19
#define RT_CAN_CMD_SET_CANFD 0x1A
#define RT_CAN_CMD_SET_BAUD_FD 0x1B
#define RT_CAN_CMD_SET_BITTIMING 0x1C
#define RT_DEVICE_CAN_INT_ERR 0x1000
enum RT_CAN_STATUS_MODE
{
NORMAL = 0,
ERRWARNING = 1,
ERRPASSIVE = 2,
BUSOFF = 4,
};
enum RT_CAN_BUS_ERR
{
RT_CAN_BUS_NO_ERR = 0,
RT_CAN_BUS_BIT_PAD_ERR = 1,
RT_CAN_BUS_FORMAT_ERR = 2,
RT_CAN_BUS_ACK_ERR = 3,
RT_CAN_BUS_IMPLICIT_BIT_ERR = 4,
RT_CAN_BUS_EXPLICIT_BIT_ERR = 5,
RT_CAN_BUS_CRC_ERR = 6,
};
struct rt_can_status
{
rt_uint32_t rcverrcnt;
rt_uint32_t snderrcnt;
rt_uint32_t errcode;
rt_uint32_t rcvpkg;
rt_uint32_t dropedrcvpkg;
rt_uint32_t sndpkg;
rt_uint32_t dropedsndpkg;
rt_uint32_t bitpaderrcnt;
rt_uint32_t formaterrcnt;
rt_uint32_t ackerrcnt;
rt_uint32_t biterrcnt;
rt_uint32_t crcerrcnt;
rt_uint32_t rcvchange;
rt_uint32_t sndchange;
rt_uint32_t lasterrtype;
};
#ifdef RT_CAN_USING_HDR
struct rt_can_hdr
{
rt_uint32_t connected;
rt_uint32_t msgs;
struct rt_can_filter_item filter;
struct rt_list_node list;
};
#endif
struct rt_can_device;
typedef rt_err_t (*rt_canstatus_ind)(struct rt_can_device *, void *);
typedef struct rt_can_status_ind_type
{
rt_canstatus_ind ind;
void *args;
} *rt_can_status_ind_type_t;
typedef void (*rt_can_bus_hook)(struct rt_can_device *);
struct rt_can_device
{
struct rt_device parent;
const struct rt_can_ops *ops;
struct can_configure config;
struct rt_can_status status;
rt_uint32_t timerinitflag;
struct rt_timer timer;
struct rt_can_status_ind_type status_indicate;
#ifdef RT_CAN_USING_HDR
struct rt_can_hdr *hdr;
#endif
#ifdef RT_CAN_USING_BUS_HOOK
rt_can_bus_hook bus_hook;
#endif /*RT_CAN_USING_BUS_HOOK*/
struct rt_mutex lock;
void *can_rx;
void *can_tx;
};
typedef struct rt_can_device *rt_can_t;
#define RT_CAN_STDID 0
#define RT_CAN_EXTID 1
#define RT_CAN_DTR 0
#define RT_CAN_RTR 1
typedef struct rt_can_status *rt_can_status_t;
struct rt_can_msg
{
rt_uint32_t id : 29;
rt_uint32_t ide : 1;
rt_uint32_t rtr : 1;
rt_uint32_t rsv : 1;
rt_uint32_t len : 8;
rt_uint32_t priv : 8;
rt_int32_t hdr_index : 8;/*Should be defined as:rx.FilterMatchIndex,which should be changed to rt_int32_t hdr_index : 8*/
#ifdef RT_CAN_USING_CANFD
rt_uint32_t fd_frame : 1;
rt_uint32_t brs : 1;
rt_uint32_t rxfifo : 2;/*Redefined to return :CAN RX FIFO0/CAN RX FIFO1*/
rt_uint32_t reserved : 4;
#else
rt_uint32_t rxfifo : 2;/*Redefined to return :CAN RX FIFO0/CAN RX FIFO1*/
rt_uint32_t reserved : 6;
#endif
#ifdef RT_CAN_USING_CANFD
rt_uint8_t data[64];
#else
rt_uint8_t data[8];
#endif
};
typedef struct rt_can_msg *rt_can_msg_t;
struct rt_can_msg_list
{
struct rt_list_node list;
#ifdef RT_CAN_USING_HDR
struct rt_list_node hdrlist;
struct rt_can_hdr *owner;
#endif
struct rt_can_msg data;
};
struct rt_can_rx_fifo
{
/* software fifo */
struct rt_can_msg_list *buffer;
rt_uint32_t freenumbers;
struct rt_list_node freelist;
struct rt_list_node uselist;
};
#define RT_CAN_SND_RESULT_OK 0
#define RT_CAN_SND_RESULT_ERR 1
#define RT_CAN_SND_RESULT_WAIT 2
#define RT_CAN_EVENT_RX_IND 0x01 /* Rx indication */
#define RT_CAN_EVENT_TX_DONE 0x02 /* Tx complete */
#define RT_CAN_EVENT_TX_FAIL 0x03 /* Tx fail */
#define RT_CAN_EVENT_RX_TIMEOUT 0x05 /* Rx timeout */
#define RT_CAN_EVENT_RXOF_IND 0x06 /* Rx overflow */
struct rt_can_sndbxinx_list
{
struct rt_list_node list;
struct rt_completion completion;
rt_uint32_t result;
};
struct rt_can_tx_fifo
{
struct rt_can_sndbxinx_list *buffer;
struct rt_semaphore sem;
struct rt_list_node freelist;
};
struct rt_can_ops
{
rt_err_t (*configure)(struct rt_can_device *can, struct can_configure *cfg);
rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg);
rt_ssize_t (*sendmsg)(struct rt_can_device *can, const void *buf, rt_uint32_t boxno);
rt_ssize_t (*recvmsg)(struct rt_can_device *can, void *buf, rt_uint32_t boxno);
};
rt_err_t rt_hw_can_register(struct rt_can_device *can,
const char *name,
const struct rt_can_ops *ops,
void *data);
void rt_hw_can_isr(struct rt_can_device *can, int event);
#endif /*_CAN_H*/

View File

@@ -0,0 +1,132 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-05-05 linzhenxing first version
*/
#ifndef __GPT_H
#define __GPT_H
#include <rtthread.h>
#include <stdint.h>
typedef struct
{
uint8_t b[16]; /* GUID 16 bytes*/
} guid_t;
#define MSDOS_MBR_SIGNATURE 0xaa55
#define EFI_PMBR_OSTYPE_EFI 0xEF
#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
#define GPT_MBR_PROTECTIVE 1
#define GPT_MBR_HYBRID 2
#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
#define GPT_HEADER_REVISION_V1 0x00010000
#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
typedef guid_t gpt_guid_t __attribute__ ((aligned (4)));
#define EFI_GUID(a, b, c, d...) (gpt_guid_t){ { \
(a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
(b) & 0xff, ((b) >> 8) & 0xff, \
(c) & 0xff, ((c) >> 8) & 0xff, d } }
#define NULL_GUID \
EFI_GUID(0x00000000, 0x0000, 0x0000,\
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
#define PARTITION_SYSTEM_GUID \
EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \
0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B)
#define LEGACY_MBR_PARTITION_GUID \
EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \
0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F)
#define PARTITION_MSFT_RESERVED_GUID \
EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \
0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE)
#define PARTITION_BASIC_DATA_GUID \
EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \
0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7)
#define PARTITION_LINUX_RAID_GUID \
EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \
0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e)
#define PARTITION_LINUX_SWAP_GUID \
EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \
0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f)
#define PARTITION_LINUX_LVM_GUID \
EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \
0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
#pragma pack(push, 1)
typedef struct _gpt_header
{
uint64_t signature;
uint32_t revision;
uint32_t header_size;
uint32_t header_crc32;
uint32_t reserved1;
uint64_t start_lba; /*GPT head start sector*/
uint64_t alternate_lba; /*GPT head alternate sector*/
uint64_t first_usable_lba;
uint64_t last_usable_lba;
gpt_guid_t disk_guid;
uint64_t partition_entry_lba;
uint32_t num_partition_entries;
uint32_t sizeof_partition_entry;
uint32_t partition_entry_array_crc32;
/* The rest of the logical block is reserved by UEFI and must be zero.
* EFI standard handles this by:
*
* uint8_t reserved2[ BlockSize - 92 ];
*/
} gpt_header;
typedef struct _gpt_entry_attributes
{
uint64_t required_to_function:1;
uint64_t reserved:47;
uint64_t type_guid_specific:16;
} gpt_entry_attributes;
typedef struct _gpt_entry
{
gpt_guid_t partition_type_guid;
gpt_guid_t unique_partition_guid;
uint64_t starting_lba;
uint64_t ending_lba;
gpt_entry_attributes attributes;
uint16_t partition_name[72/sizeof(uint16_t)];
} gpt_entry;
typedef struct _gpt_mbr_record
{
uint8_t boot_indicator; /* unused by EFI, set to 0x80 for bootable */
uint8_t start_head; /* unused by EFI, pt start in CHS */
uint8_t start_sector; /* unused by EFI, pt start in CHS */
uint8_t start_track;
uint8_t os_type; /* EFI and legacy non-EFI OS types */
uint8_t end_head; /* unused by EFI, pt end in CHS */
uint8_t end_sector; /* unused by EFI, pt end in CHS */
uint8_t end_track; /* unused by EFI, pt end in CHS */
uint32_t starting_lba; /* used by EFI - start addr of the on disk pt */
uint32_t size_in_lba; /* used by EFI - size of pt in LBA */
} gpt_mbr_record;
typedef struct _legacy_mbr
{
uint8_t boot_code[440];
uint32_t unique_mbr_signature;
uint16_t unknown;
gpt_mbr_record partition_record[4];
uint16_t signature;
} legacy_mbr;
#pragma pack(pop)
int check_gpt(struct rt_mmcsd_card *card);
int gpt_get_partition_param(struct rt_mmcsd_card *card, struct dfs_partition *part, uint32_t pindex);
void gpt_free(void);
#endif /*__GPT_H*/

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-04-25 weety first version
*/
#ifndef __I2C_BIT_OPS_H__
#define __I2C_BIT_OPS_H__
#ifdef __cplusplus
extern "C" {
#endif
struct rt_i2c_bit_ops
{
void *data; /* private data for lowlevel routines */
void (*set_sda)(void *data, rt_int32_t state);
void (*set_scl)(void *data, rt_int32_t state);
rt_int32_t (*get_sda)(void *data);
rt_int32_t (*get_scl)(void *data);
void (*udelay)(rt_uint32_t us);
rt_uint32_t delay_us; /* scl and sda line delay */
rt_uint32_t timeout; /* in tick */
void (*pin_init)(void);
rt_bool_t i2c_pin_init_flag;
};
rt_err_t rt_i2c_bit_add_bus(struct rt_i2c_bus_device *bus,
const char *bus_name);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,136 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-04-25 weety first version
* 2021-04-20 RiceChen added support for bus control api
*/
#ifndef __I2C_H__
#define __I2C_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
#define RT_I2C_WR 0x0000
#define RT_I2C_RD (1u << 0)
#define RT_I2C_ADDR_10BIT (1u << 2) /* this is a ten bit chip address */
#define RT_I2C_NO_START (1u << 4)
#define RT_I2C_IGNORE_NACK (1u << 5)
#define RT_I2C_NO_READ_ACK (1u << 6) /* when I2C reading, we do not ACK */
#define RT_I2C_NO_STOP (1u << 7)
struct rt_i2c_msg
{
rt_uint16_t addr;
rt_uint16_t flags;
rt_uint16_t len;
rt_uint8_t *buf;
};
struct rt_i2c_bus_device;
struct rt_i2c_bus_device_ops
{
rt_ssize_t (*master_xfer)(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num);
rt_ssize_t (*slave_xfer)(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num);
rt_err_t (*i2c_bus_control)(struct rt_i2c_bus_device *bus,
int cmd,
void *args);
};
/*for i2c bus driver*/
struct rt_i2c_bus_device
{
struct rt_device parent;
const struct rt_i2c_bus_device_ops *ops;
rt_uint16_t flags;
struct rt_mutex lock;
rt_uint32_t timeout;
rt_uint32_t retries;
void *priv;
};
struct rt_i2c_client
{
#ifdef RT_USING_DM
struct rt_device parent;
const char *name;
const struct rt_i2c_device_id *id;
const struct rt_ofw_node_id *ofw_id;
#endif
struct rt_i2c_bus_device *bus;
rt_uint16_t client_addr;
};
#ifdef RT_USING_DM
struct rt_i2c_device_id
{
char name[20];
void *data;
};
struct rt_i2c_driver
{
struct rt_driver parent;
const struct rt_i2c_device_id *ids;
const struct rt_ofw_node_id *ofw_ids;
rt_err_t (*probe)(struct rt_i2c_client *client);
rt_err_t (*remove)(struct rt_i2c_client *client);
rt_err_t (*shutdown)(struct rt_i2c_client *client);
};
rt_err_t rt_i2c_driver_register(struct rt_i2c_driver *driver);
rt_err_t rt_i2c_device_register(struct rt_i2c_client *client);
#define RT_I2C_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, i2c, BUILIN)
#endif /* RT_USING_DM */
rt_err_t rt_i2c_bus_device_register(struct rt_i2c_bus_device *bus,
const char *bus_name);
struct rt_i2c_bus_device *rt_i2c_bus_device_find(const char *bus_name);
rt_ssize_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num);
rt_err_t rt_i2c_control(struct rt_i2c_bus_device *bus,
int cmd,
void *args);
rt_ssize_t rt_i2c_master_send(struct rt_i2c_bus_device *bus,
rt_uint16_t addr,
rt_uint16_t flags,
const rt_uint8_t *buf,
rt_uint32_t count);
rt_ssize_t rt_i2c_master_recv(struct rt_i2c_bus_device *bus,
rt_uint16_t addr,
rt_uint16_t flags,
rt_uint8_t *buf,
rt_uint32_t count);
rt_inline rt_err_t rt_i2c_bus_lock(struct rt_i2c_bus_device *bus, rt_tick_t timeout)
{
return rt_mutex_take(&bus->lock, timeout);
}
rt_inline rt_err_t rt_i2c_bus_unlock(struct rt_i2c_bus_device *bus)
{
return rt_mutex_release(&bus->lock);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-04-25 weety first version
* 2021-04-20 RiceChen added bus clock command
*/
#ifndef __I2C_DEV_H__
#define __I2C_DEV_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
#define RT_I2C_DEV_CTRL_10BIT (RT_DEVICE_CTRL_BASE(I2CBUS) + 0x01)
#define RT_I2C_DEV_CTRL_ADDR (RT_DEVICE_CTRL_BASE(I2CBUS) + 0x02)
#define RT_I2C_DEV_CTRL_TIMEOUT (RT_DEVICE_CTRL_BASE(I2CBUS) + 0x03)
#define RT_I2C_DEV_CTRL_RW (RT_DEVICE_CTRL_BASE(I2CBUS) + 0x04)
#define RT_I2C_DEV_CTRL_CLK (RT_DEVICE_CTRL_BASE(I2CBUS) + 0x05)
#define RT_I2C_DEV_CTRL_UNLOCK (RT_DEVICE_CTRL_BASE(I2CBUS) + 0x06)
#define RT_I2C_DEV_CTRL_GET_STATE (RT_DEVICE_CTRL_BASE(I2CBUS) + 0x07)
#define RT_I2C_DEV_CTRL_GET_MODE (RT_DEVICE_CTRL_BASE(I2CBUS) + 0x08)
#define RT_I2C_DEV_CTRL_GET_ERROR (RT_DEVICE_CTRL_BASE(I2CBUS) + 0x09)
struct rt_i2c_priv_data
{
struct rt_i2c_msg *msgs;
rt_size_t number;
};
rt_err_t rt_i2c_bus_device_device_init(struct rt_i2c_bus_device *bus,
const char *name);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-11-26 GuEe-GUI first version
*/
#ifndef __I2C_DM_H__
#define __I2C_DM_H__
#include <rthw.h>
#include <rtthread.h>
#include <drivers/core/bus.h>
/* I2C Frequency Modes */
#define I2C_MAX_STANDARD_MODE_FREQ 100000
#define I2C_MAX_FAST_MODE_FREQ 400000
#define I2C_MAX_FAST_MODE_PLUS_FREQ 1000000
#define I2C_MAX_TURBO_MODE_FREQ 1400000
#define I2C_MAX_HIGH_SPEED_MODE_FREQ 3400000
#define I2C_MAX_ULTRA_FAST_MODE_FREQ 5000000
struct i2c_timings
{
rt_uint32_t bus_freq_hz; /* the bus frequency in Hz */
rt_uint32_t scl_rise_ns; /* time SCL signal takes to rise in ns; t(r) in the I2C specification */
rt_uint32_t scl_fall_ns; /* time SCL signal takes to fall in ns; t(f) in the I2C specification */
rt_uint32_t scl_int_delay_ns; /* time IP core additionally needs to setup SCL in ns */
rt_uint32_t sda_fall_ns; /* time SDA signal takes to fall in ns; t(f) in the I2C specification */
rt_uint32_t sda_hold_ns; /* time IP core additionally needs to hold SDA in ns */
rt_uint32_t digital_filter_width_ns; /* width in ns of spikes on i2c lines that the IP core digital filter can filter out */
rt_uint32_t analog_filter_cutoff_freq_hz; /* threshold frequency for the low pass IP core analog filter */
};
#ifdef RT_USING_OFW
rt_err_t i2c_timings_ofw_parse(struct rt_ofw_node *dev_np, struct i2c_timings *timings,
rt_bool_t use_defaults);
#else
rt_inline rt_err_t i2c_timings_ofw_parse(struct rt_ofw_node *dev_np, struct i2c_timings *timings,
rt_bool_t use_defaults)
{
return RT_EOK;
}
#endif /* RT_USING_OFW */
void i2c_bus_scan_clients(struct rt_i2c_bus_device *bus);
#endif /* __I2C_DM_H__ */

View File

@@ -0,0 +1,195 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2015-06-15 hichard first version
* 2024-05-25 HPMicro add strobe support
*/
#ifndef __MMC_H__
#define __MMC_H__
#include <rtthread.h>
#include <drivers/mmcsd_host.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* EXT_CSD fields
*/
#define EXT_CSD_FLUSH_CACHE 32 /* W */
#define EXT_CSD_CACHE_CTRL 33 /* R/W */
#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */
#define EXT_CSD_PACKED_FAILURE_INDEX 35 /* RO */
#define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */
#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */
#define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */
#define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */
#define EXT_CSD_GP_SIZE_MULT 143 /* R/W */
#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */
#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */
#define EXT_CSD_HPI_MGMT 161 /* R/W */
#define EXT_CSD_RST_N_FUNCTION 162 /* R/W */
#define EXT_CSD_BKOPS_EN 163 /* R/W */
#define EXT_CSD_BKOPS_START 164 /* W */
#define EXT_CSD_SANITIZE_START 165 /* W */
#define EXT_CSD_WR_REL_PARAM 166 /* RO */
#define EXT_CSD_RPMB_MULT 168 /* RO */
#define EXT_CSD_BOOT_WP 173 /* R/W */
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
#define EXT_CSD_PART_CONFIG 179 /* R/W */
#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
#define EXT_CSD_STROBE_SUPPORT 184 /* RO */
#define EXT_CSD_HS_TIMING 185 /* R/W */
#define EXT_CSD_POWER_CLASS 187 /* R/W */
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_STRUCTURE 194 /* RO */
#define EXT_CSD_CARD_TYPE 196 /* RO */
#define EXT_CSD_OUT_OF_INTERRUPT_TIME 198 /* RO */
#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */
#define EXT_CSD_PWR_CL_52_195 200 /* RO */
#define EXT_CSD_PWR_CL_26_195 201 /* RO */
#define EXT_CSD_PWR_CL_52_360 202 /* RO */
#define EXT_CSD_PWR_CL_26_360 203 /* RO */
#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
#define EXT_CSD_S_A_TIMEOUT 217 /* RO */
#define EXT_CSD_REL_WR_SEC_C 222 /* RO */
#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */
#define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */
#define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */
#define EXT_CSD_BOOT_MULT 226 /* RO */
#define EXT_CSD_SEC_TRIM_MULT 229 /* RO */
#define EXT_CSD_SEC_ERASE_MULT 230 /* RO */
#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */
#define EXT_CSD_TRIM_MULT 232 /* RO */
#define EXT_CSD_PWR_CL_200_195 236 /* RO */
#define EXT_CSD_PWR_CL_200_360 237 /* RO */
#define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */
#define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */
#define EXT_CSD_BKOPS_STATUS 246 /* RO */
#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */
#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
#define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */
#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */
#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */
#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */
#define EXT_CSD_MAX_PACKED_READS 501 /* RO */
#define EXT_CSD_BKOPS_SUPPORT 502 /* RO */
#define EXT_CSD_HPI_FEATURES 503 /* RO */
/*
* EXT_CSD field definitions
*/
#define EXT_CSD_WR_REL_PARAM_EN (1<<2)
#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40)
#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10)
#define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04)
#define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01)
#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7)
#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1)
#define EXT_CSD_PART_CONFIG_ACC_RPMB (0x3)
#define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4)
#define EXT_CSD_PART_SUPPORT_PART_EN (0x1)
#define EXT_CSD_CMD_SET_NORMAL (1<<0)
#define EXT_CSD_CMD_SET_SECURE (1<<1)
#define EXT_CSD_CMD_SET_CPSECURE (1<<2)
#define EXT_CSD_CARD_TYPE_HS_26 (1<<0) /* Card can run at 26MHz */
#define EXT_CSD_CARD_TYPE_HS_52 (1<<1) /* Card can run at 52MHz */
#define EXT_CSD_CARD_TYPE_HS (EXT_CSD_CARD_TYPE_HS_26 | \
EXT_CSD_CARD_TYPE_HS_52)
#define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */
/* DDR mode @1.8V or 3V I/O */
#define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */
/* DDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \
| EXT_CSD_CARD_TYPE_DDR_1_2V)
#define EXT_CSD_CARD_TYPE_HS200_1_8V (1<<4) /* Card can run at 200MHz */
#define EXT_CSD_CARD_TYPE_HS200_1_2V (1<<5) /* Card can run at 200MHz */
/* SDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_HS200 (EXT_CSD_CARD_TYPE_HS200_1_8V | \
EXT_CSD_CARD_TYPE_HS200_1_2V)
#define EXT_CSD_CARD_TYPE_HS400_1_8V (1<<6) /* Card can run at 200MHz DDR, 1.8V */
#define EXT_CSD_CARD_TYPE_HS400_1_2V (1<<7) /* Card can run at 200MHz DDR, 1.2V */
#define EXT_CSD_CARD_TYPE_HS400 (EXT_CSD_CARD_TYPE_HS400_1_8V | \
EXT_CSD_CARD_TYPE_HS400_1_2V)
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
#define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */
#define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */
#define EXT_CSD_DDR_BUS_WIDTH_8_EH_DS 0x86/* Card is in 8 bit DDR mode with Enhanced Data Strobe */
#define EXT_CSD_TIMING_BC 0 /* Backwards compatibility */
#define EXT_CSD_TIMING_HS 1 /* High speed */
#define EXT_CSD_TIMING_HS200 2 /* HS200 */
#define EXT_CSD_TIMING_HS400 3 /* HS400 */
#define EXT_CSD_SEC_ER_EN BIT(0)
#define EXT_CSD_SEC_BD_BLK_EN BIT(2)
#define EXT_CSD_SEC_GB_CL_EN BIT(4)
#define EXT_CSD_SEC_SANITIZE BIT(6) /* v4.5 only */
#define EXT_CSD_RST_N_EN_MASK 0x3
#define EXT_CSD_RST_N_ENABLED 1 /* RST_n is enabled on card */
#define EXT_CSD_NO_POWER_NOTIFICATION 0
#define EXT_CSD_POWER_ON 1
#define EXT_CSD_POWER_OFF_SHORT 2
#define EXT_CSD_POWER_OFF_LONG 3
#define EXT_CSD_PWR_CL_8BIT_MASK 0xF0 /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_4BIT_MASK 0x0F /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_8BIT_SHIFT 4
#define EXT_CSD_PWR_CL_4BIT_SHIFT 0
#define EXT_CSD_PACKED_EVENT_EN BIT(3)
/*
* EXCEPTION_EVENT_STATUS field
*/
#define EXT_CSD_URGENT_BKOPS BIT(0)
#define EXT_CSD_DYNCAP_NEEDED BIT(1)
#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2)
#define EXT_CSD_PACKED_FAILURE BIT(3)
#define EXT_CSD_PACKED_GENERIC_ERROR BIT(0)
#define EXT_CSD_PACKED_INDEXED_ERROR BIT(1)
/*
* BKOPS status level
*/
#define EXT_CSD_BKOPS_LEVEL_2 0x2
/*
* MMC_SWITCH access modes
*/
#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */
#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */
#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */
/*
* extern function
*/
rt_err_t mmc_send_op_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr, rt_uint32_t *rocr);
rt_int32_t init_mmc(struct rt_mmcsd_host *host, rt_uint32_t ocr);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,262 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-07-25 weety first version
*/
#ifndef __CORE_H__
#define __CORE_H__
#include <rtthread.h>
#include <drivers/mmcsd_host.h>
#include <drivers/mmcsd_card.h>
#include <drivers/mmcsd_cmd.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef RT_MMCSD_DBG
#define mmcsd_dbg(fmt, ...) rt_kprintf(fmt, ##__VA_ARGS__)
#else
#define mmcsd_dbg(fmt, ...)
#endif
struct rt_mmcsd_data
{
rt_uint32_t blksize;
rt_uint32_t blks;
rt_uint32_t *buf;
rt_int32_t err;
rt_uint32_t flags;
#define DATA_DIR_WRITE (1 << 0)
#define DATA_DIR_READ (1 << 1)
#define DATA_STREAM (1 << 2)
unsigned int bytes_xfered;
struct rt_mmcsd_cmd *stop; /* stop command */
struct rt_mmcsd_req *mrq; /* associated request */
rt_uint32_t timeout_ns;
rt_uint32_t timeout_clks;
void *sg; /* scatter list */
rt_uint16_t sg_len; /* size of scatter list */
rt_int16_t sg_count; /* mapped sg entries */
rt_ubase_t host_cookie; /* host driver private data */
};
struct rt_mmcsd_cmd
{
rt_uint32_t cmd_code;
rt_uint32_t arg;
rt_uint32_t resp[4];
rt_uint32_t flags;
/*rsponse types
*bits:0~3
*/
#define RESP_MASK (0xF)
#define RESP_NONE (0)
#define RESP_R1 (1 << 0)
#define RESP_R1B (2 << 0)
#define RESP_R2 (3 << 0)
#define RESP_R3 (4 << 0)
#define RESP_R4 (5 << 0)
#define RESP_R6 (6 << 0)
#define RESP_R7 (7 << 0)
#define RESP_R5 (8 << 0) /*SDIO command response type*/
/*command types
*bits:4~5
*/
#define CMD_MASK (3 << 4) /* command type */
#define CMD_AC (0 << 4)
#define CMD_ADTC (1 << 4)
#define CMD_BC (2 << 4)
#define CMD_BCR (3 << 4)
#define resp_type(cmd) ((cmd)->flags & RESP_MASK)
/*spi rsponse types
*bits:6~8
*/
#define RESP_SPI_MASK (0x7 << 6)
#define RESP_SPI_R1 (1 << 6)
#define RESP_SPI_R1B (2 << 6)
#define RESP_SPI_R2 (3 << 6)
#define RESP_SPI_R3 (4 << 6)
#define RESP_SPI_R4 (5 << 6)
#define RESP_SPI_R5 (6 << 6)
#define RESP_SPI_R7 (7 << 6)
#define spi_resp_type(cmd) ((cmd)->flags & RESP_SPI_MASK)
/*
* These are the command types.
*/
#define cmd_type(cmd) ((cmd)->flags & CMD_MASK)
rt_int32_t retries; /* max number of retries */
rt_int32_t err;
unsigned int busy_timeout; /* busy detect timeout in ms */
struct rt_mmcsd_data *data;
struct rt_mmcsd_req *mrq; /* associated request */
};
struct rt_mmcsd_req
{
struct rt_mmcsd_data *data;
struct rt_mmcsd_cmd *cmd;
struct rt_mmcsd_cmd *stop;
struct rt_mmcsd_cmd *sbc; /* SET_BLOCK_COUNT for multiblock */
/* Allow other commands during this ongoing data transfer or busy wait */
int cap_cmd_during_tfr;
};
/*the following is response bit*/
#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */
#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */
#define R1_ERASE_PARAM (1 << 27) /* ex, c */
#define R1_WP_VIOLATION (1 << 26) /* erx, c */
#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */
#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */
#define R1_COM_CRC_ERROR (1 << 23) /* er, b */
#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */
#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */
#define R1_CC_ERROR (1 << 20) /* erx, c */
#define R1_ERROR (1 << 19) /* erx, c */
#define R1_UNDERRUN (1 << 18) /* ex, c */
#define R1_OVERRUN (1 << 17) /* ex, c */
#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */
#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */
#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */
#define R1_ERASE_RESET (1 << 13) /* sr, c */
#define R1_STATUS(x) (x & 0xFFFFE000)
#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
#define R1_APP_CMD (1 << 5) /* sr, c */
#define R1_SPI_IDLE (1 << 0)
#define R1_SPI_ERASE_RESET (1 << 1)
#define R1_SPI_ILLEGAL_COMMAND (1 << 2)
#define R1_SPI_COM_CRC (1 << 3)
#define R1_SPI_ERASE_SEQ (1 << 4)
#define R1_SPI_ADDRESS (1 << 5)
#define R1_SPI_PARAMETER (1 << 6)
/* R1 bit 7 is always zero */
#define R2_SPI_CARD_LOCKED (1 << 8)
#define R2_SPI_WP_ERASE_SKIP (1 << 9) /* or lock/unlock fail */
#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP
#define R2_SPI_ERROR (1 << 10)
#define R2_SPI_CC_ERROR (1 << 11)
#define R2_SPI_CARD_ECC_ERROR (1 << 12)
#define R2_SPI_WP_VIOLATION (1 << 13)
#define R2_SPI_ERASE_PARAM (1 << 14)
#define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */
#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE
#define CARD_BUSY 0x80000000 /* Card Power up status bit */
/* R5 response bits */
#define R5_COM_CRC_ERROR (1 << 15)
#define R5_ILLEGAL_COMMAND (1 << 14)
#define R5_ERROR (1 << 11)
#define R5_FUNCTION_NUMBER (1 << 9)
#define R5_OUT_OF_RANGE (1 << 8)
#define R5_STATUS(x) (x & 0xCB00)
#define R5_IO_CURRENT_STATE(x) ((x & 0x3000) >> 12)
/**
* fls - find last (most-significant) bit set
* @x: the word to search
*
* This is defined the same way as ffs.
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
*/
rt_inline rt_uint32_t __rt_fls(rt_uint32_t val)
{
rt_uint32_t bit = 32;
if (!val)
return 0;
if (!(val & 0xffff0000u))
{
val <<= 16;
bit -= 16;
}
if (!(val & 0xff000000u))
{
val <<= 8;
bit -= 8;
}
if (!(val & 0xf0000000u))
{
val <<= 4;
bit -= 4;
}
if (!(val & 0xc0000000u))
{
val <<= 2;
bit -= 2;
}
if (!(val & 0x80000000u))
{
bit -= 1;
}
return bit;
}
#define MMCSD_HOST_PLUGED 0
#define MMCSD_HOST_UNPLUGED 1
rt_int32_t mmcsd_excute_tuning(struct rt_mmcsd_card *card);
int mmcsd_wait_cd_changed(rt_int32_t timeout);
void mmcsd_host_lock(struct rt_mmcsd_host *host);
void mmcsd_host_unlock(struct rt_mmcsd_host *host);
void mmcsd_req_complete(struct rt_mmcsd_host *host);
void mmcsd_send_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req);
rt_int32_t mmcsd_send_cmd(struct rt_mmcsd_host *host, struct rt_mmcsd_cmd *cmd, int retries);
rt_int32_t mmcsd_go_idle(struct rt_mmcsd_host *host);
rt_int32_t mmcsd_spi_read_ocr(struct rt_mmcsd_host *host, rt_int32_t high_capacity, rt_uint32_t *ocr);
rt_int32_t mmcsd_all_get_cid(struct rt_mmcsd_host *host, rt_uint32_t *cid);
rt_int32_t mmcsd_get_cid(struct rt_mmcsd_host *host, rt_uint32_t *cid);
rt_int32_t mmcsd_get_csd(struct rt_mmcsd_card *card, rt_uint32_t *csd);
rt_int32_t mmcsd_select_card(struct rt_mmcsd_card *card);
rt_int32_t mmcsd_deselect_cards(struct rt_mmcsd_card *host);
rt_int32_t mmcsd_spi_use_crc(struct rt_mmcsd_host *host, rt_int32_t use_crc);
void mmcsd_set_chip_select(struct rt_mmcsd_host *host, rt_int32_t mode);
void mmcsd_set_clock(struct rt_mmcsd_host *host, rt_uint32_t clk);
void mmcsd_set_bus_mode(struct rt_mmcsd_host *host, rt_uint32_t mode);
void mmcsd_set_bus_width(struct rt_mmcsd_host *host, rt_uint32_t width);
void mmcsd_set_timing(struct rt_mmcsd_host *host, rt_uint32_t timing);
void mmcsd_set_data_timeout(struct rt_mmcsd_data *data, const struct rt_mmcsd_card *card);
rt_uint32_t mmcsd_select_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr);
void mmcsd_change(struct rt_mmcsd_host *host);
void mmcsd_detect(void *param);
void mmcsd_host_init(struct rt_mmcsd_host *host);
struct rt_mmcsd_host *mmcsd_alloc_host(void);
void mmcsd_free_host(struct rt_mmcsd_host *host);
int rt_mmcsd_core_init(void);
int rt_mmcsd_blk_init(void);
rt_int32_t read_lba(struct rt_mmcsd_card *card, size_t lba, uint8_t *buffer, size_t count);
rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card);
void rt_mmcsd_blk_remove(struct rt_mmcsd_card *card);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-10-14 wangqiang the first version
*/
#ifndef __MDIO_H__
#define __MDIO_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C"
{
#endif
struct rt_mdio_bus_ops
{
rt_bool_t (*init)(void *bus, rt_uint32_t src_clock_hz);
rt_size_t (*read)(void *bus, rt_uint32_t addr, rt_uint32_t reg, void *data, rt_uint32_t size);
rt_size_t (*write)(void *bus, rt_uint32_t addr, rt_uint32_t reg, void *data, rt_uint32_t size);
rt_bool_t (*uninit)(void *bus);
};
struct rt_mdio_bus
{
void *hw_obj;
char *name;
struct rt_mdio_bus_ops *ops;
};
typedef struct rt_mdio_bus rt_mdio_t;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,178 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2015-01-20 Bernard the first version
* 2017-10-20 ZYH add mode open drain and input pull down
*/
#ifndef PIN_H__
#define PIN_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef RT_USING_DM
#include <drivers/pic.h>
struct rt_pin_irqchip
{
struct rt_pic parent;
int irq;
rt_base_t pin_range[2];
};
#endif /* RT_USING_DM */
/* pin device and operations for RT-Thread */
struct rt_device_pin
{
struct rt_device parent;
#ifdef RT_USING_DM
struct rt_pin_irqchip irqchip;
#endif /* RT_USING_DM */
const struct rt_pin_ops *ops;
};
#define PIN_NONE (-1)
#define PIN_LOW 0x00
#define PIN_HIGH 0x01
#define PIN_MODE_OUTPUT 0x00
#define PIN_MODE_INPUT 0x01
#define PIN_MODE_INPUT_PULLUP 0x02
#define PIN_MODE_INPUT_PULLDOWN 0x03
#define PIN_MODE_OUTPUT_OD 0x04
#ifdef RT_USING_PINCTRL
enum
{
PIN_CONFIG_BIAS_BUS_HOLD,
PIN_CONFIG_BIAS_DISABLE,
PIN_CONFIG_BIAS_HIGH_IMPEDANCE,
PIN_CONFIG_BIAS_PULL_DOWN,
PIN_CONFIG_BIAS_PULL_PIN_DEFAULT,
PIN_CONFIG_BIAS_PULL_UP,
PIN_CONFIG_DRIVE_OPEN_DRAIN,
PIN_CONFIG_DRIVE_OPEN_SOURCE,
PIN_CONFIG_DRIVE_PUSH_PULL,
PIN_CONFIG_DRIVE_STRENGTH,
PIN_CONFIG_DRIVE_STRENGTH_UA,
PIN_CONFIG_INPUT_DEBOUNCE,
PIN_CONFIG_INPUT_ENABLE,
PIN_CONFIG_INPUT_SCHMITT,
PIN_CONFIG_INPUT_SCHMITT_ENABLE,
PIN_CONFIG_MODE_LOW_POWER,
PIN_CONFIG_MODE_PWM,
PIN_CONFIG_OUTPUT,
PIN_CONFIG_OUTPUT_ENABLE,
PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS,
PIN_CONFIG_PERSIST_STATE,
PIN_CONFIG_POWER_SOURCE,
PIN_CONFIG_SKEW_DELAY,
PIN_CONFIG_SLEEP_HARDWARE_STATE,
PIN_CONFIG_SLEW_RATE,
PIN_CONFIG_END = 0x7f,
PIN_CONFIG_MAX = 0xff,
};
#endif /* RT_USING_PINCTRL */
#define PIN_IRQ_MODE_RISING 0x00
#define PIN_IRQ_MODE_FALLING 0x01
#define PIN_IRQ_MODE_RISING_FALLING 0x02
#define PIN_IRQ_MODE_HIGH_LEVEL 0x03
#define PIN_IRQ_MODE_LOW_LEVEL 0x04
#define PIN_IRQ_DISABLE 0x00
#define PIN_IRQ_ENABLE 0x01
#define PIN_IRQ_PIN_NONE PIN_NONE
struct rt_device_pin_mode
{
rt_base_t pin;
rt_uint8_t mode; /* e.g. PIN_MODE_OUTPUT */
};
struct rt_device_pin_value
{
rt_base_t pin;
rt_uint8_t value; /* PIN_LOW or PIN_HIGH */
};
struct rt_pin_irq_hdr
{
rt_base_t pin;
rt_uint8_t mode; /* e.g. PIN_IRQ_MODE_RISING */
void (*hdr)(void *args);
void *args;
};
#ifdef RT_USING_PINCTRL
struct rt_pin_ctrl_conf_params
{
const char *propname;
rt_uint32_t param;
rt_uint32_t default_value;
};
#endif /* RT_USING_PINCTRL */
struct rt_pin_ops
{
void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_uint8_t mode);
void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_uint8_t value);
rt_ssize_t (*pin_read)(struct rt_device *device, rt_base_t pin);
rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_base_t pin,
rt_uint8_t mode, void (*hdr)(void *args), void *args);
rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_base_t pin);
rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled);
rt_base_t (*pin_get)(const char *name);
#ifdef RT_USING_DM
rt_err_t (*pin_irq_mode)(struct rt_device *device, rt_base_t pin, rt_uint8_t mode);
rt_ssize_t (*pin_parse)(struct rt_device *device, struct rt_ofw_cell_args *args, rt_uint32_t *flags);
#endif
#ifdef RT_USING_PINCTRL
rt_err_t (*pin_ctrl_confs_apply)(struct rt_device *device, void *fw_conf_np);
#endif /* RT_USING_PINCTRL */
};
int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data);
void rt_pin_mode(rt_base_t pin, rt_uint8_t mode);
void rt_pin_write(rt_base_t pin, rt_ssize_t value);
rt_ssize_t rt_pin_read(rt_base_t pin);
rt_base_t rt_pin_get(const char *name);
rt_err_t rt_pin_attach_irq(rt_base_t pin, rt_uint8_t mode,
void (*hdr)(void *args), void *args);
rt_err_t rt_pin_detach_irq(rt_base_t pin);
rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint8_t enabled);
#ifdef RT_USING_DM
rt_ssize_t rt_pin_get_named_pin(struct rt_device *dev, const char *propname, int index,
rt_uint8_t *out_mode, rt_uint8_t *out_value);
rt_ssize_t rt_pin_get_named_pin_count(struct rt_device *dev, const char *propname);
#ifdef RT_USING_OFW
rt_ssize_t rt_ofw_get_named_pin(struct rt_ofw_node *np, const char *propname, int index,
rt_uint8_t *out_mode, rt_uint8_t *out_value);
rt_ssize_t rt_ofw_get_named_pin_count(struct rt_ofw_node *np, const char *propname);
#endif
#endif /* RT_USING_DM */
#ifdef RT_USING_PINCTRL
rt_ssize_t rt_pin_ctrl_confs_lookup(struct rt_device *device, const char *name);
rt_err_t rt_pin_ctrl_confs_apply(struct rt_device *device, int index);
rt_err_t rt_pin_ctrl_confs_apply_by_name(struct rt_device *device, const char *name);
#endif /* RT_USING_PINCTRL */
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-05-07 aozima the first version
* 2022-09-24 yuqi add phase and dead time configuration
*/
#ifndef __DRV_PWM_H_INCLUDE__
#define __DRV_PWM_H_INCLUDE__
#include <rtthread.h>
#define PWM_CMD_ENABLE (RT_DEVICE_CTRL_BASE(PWM) + 0)
#define PWM_CMD_DISABLE (RT_DEVICE_CTRL_BASE(PWM) + 1)
#define PWM_CMD_SET (RT_DEVICE_CTRL_BASE(PWM) + 2)
#define PWM_CMD_GET (RT_DEVICE_CTRL_BASE(PWM) + 3)
#define PWMN_CMD_ENABLE (RT_DEVICE_CTRL_BASE(PWM) + 4)
#define PWMN_CMD_DISABLE (RT_DEVICE_CTRL_BASE(PWM) + 5)
#define PWM_CMD_SET_PERIOD (RT_DEVICE_CTRL_BASE(PWM) + 6)
#define PWM_CMD_SET_PULSE (RT_DEVICE_CTRL_BASE(PWM) + 7)
#define PWM_CMD_SET_DEAD_TIME (RT_DEVICE_CTRL_BASE(PWM) + 8)
#define PWM_CMD_SET_PHASE (RT_DEVICE_CTRL_BASE(PWM) + 9)
#define PWM_CMD_ENABLE_IRQ (RT_DEVICE_CTRL_BASE(PWM) + 10)
#define PWM_CMD_DISABLE_IRQ (RT_DEVICE_CTRL_BASE(PWM) + 11)
struct rt_pwm_configuration
{
rt_uint32_t channel; /* 0 ~ n or 0 ~ -n, which depends on specific MCU requirements */
rt_uint32_t period; /* unit:ns 1ns~4.29s:1Ghz~0.23hz */
rt_uint32_t pulse; /* unit:ns (pulse<=period) */
rt_uint32_t dead_time; /* unit:ns */
rt_uint32_t phase; /*unit: degree, 0~360, which is the phase of pwm output, */
/*
* RT_TRUE : The channel of pwm is complememtary.
* RT_FALSE : The channel of pwm is nomal.
*/
rt_bool_t complementary;
};
struct rt_device_pwm;
struct rt_pwm_ops
{
rt_err_t (*control)(struct rt_device_pwm *device, int cmd, void *arg);
};
struct rt_device_pwm
{
struct rt_device parent;
const struct rt_pwm_ops *ops;
};
rt_err_t rt_device_pwm_register(struct rt_device_pwm *device, const char *name, const struct rt_pwm_ops *ops, const void *user_data);
rt_err_t rt_pwm_enable(struct rt_device_pwm *device, int channel);
rt_err_t rt_pwm_disable(struct rt_device_pwm *device, int channel);
rt_err_t rt_pwm_set(struct rt_device_pwm *device, int channel, rt_uint32_t period, rt_uint32_t pulse);
rt_err_t rt_pwm_set_period(struct rt_device_pwm *device, int channel, rt_uint32_t period);
rt_err_t rt_pwm_set_pulse(struct rt_device_pwm *device, int channel, rt_uint32_t pulse);
rt_err_t rt_pwm_set_dead_time(struct rt_device_pwm *device, int channel, rt_uint32_t dead_time);
rt_err_t rt_pwm_set_phase(struct rt_device_pwm *device, int channel, rt_uint32_t phase);
#endif /* __DRV_PWM_H_INCLUDE__ */

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-10-10 aozima first version.
* 2021-06-11 iysheng implement RTC framework V2.0
* 2021-07-30 Meco Man move rtc_core.h to rtc.h
* 2022-04-05 tyx add timestamp function
*/
#ifndef __RTC_H__
#define __RTC_H__
#include <rtdef.h>
#include <sys/time.h>
#ifdef __cplusplus
extern "C" {
#endif
#define RT_DEVICE_CTRL_RTC_GET_TIME (RT_DEVICE_CTRL_BASE(RTC) + 0x01) /**< get second time */
#define RT_DEVICE_CTRL_RTC_SET_TIME (RT_DEVICE_CTRL_BASE(RTC) + 0x02) /**< set second time */
#define RT_DEVICE_CTRL_RTC_GET_TIMEVAL (RT_DEVICE_CTRL_BASE(RTC) + 0x03) /**< get timeval for gettimeofday */
#define RT_DEVICE_CTRL_RTC_SET_TIMEVAL (RT_DEVICE_CTRL_BASE(RTC) + 0x04) /**< set timeval for gettimeofday */
#define RT_DEVICE_CTRL_RTC_GET_ALARM (RT_DEVICE_CTRL_BASE(RTC) + 0x05) /**< get alarm */
#define RT_DEVICE_CTRL_RTC_SET_ALARM (RT_DEVICE_CTRL_BASE(RTC) + 0x06) /**< set alarm */
#define RT_DEVICE_CTRL_RTC_GET_TIMESPEC (RT_DEVICE_CTRL_BASE(RTC) + 0x07) /**< get timespec for clock_gettime */
#define RT_DEVICE_CTRL_RTC_SET_TIMESPEC (RT_DEVICE_CTRL_BASE(RTC) + 0x08) /**< set timespec for clock_settime */
#define RT_DEVICE_CTRL_RTC_GET_TIMERES (RT_DEVICE_CTRL_BASE(RTC) + 0x09) /**< get resolution for clock_getres */
/* used for alarm function */
struct rt_rtc_wkalarm
{
rt_bool_t enable; /* 0 = alarm disabled, 1 = alarm enabled */
rt_int32_t tm_sec; /* alarm at tm_sec */
rt_int32_t tm_min; /* alarm at tm_min */
rt_int32_t tm_hour; /* alarm at tm_hour */
rt_int32_t tm_mday; /* alarm at tm_mday */
rt_int32_t tm_mon; /* alarm at tm_mon */
rt_int32_t tm_year; /* alarm at tm_year */
};
struct rt_rtc_ops
{
rt_err_t (*init)(void);
rt_err_t (*get_secs)(time_t *sec);
rt_err_t (*set_secs)(time_t *sec);
rt_err_t (*get_alarm)(struct rt_rtc_wkalarm *alarm);
rt_err_t (*set_alarm)(struct rt_rtc_wkalarm *alarm);
rt_err_t (*get_timeval)(struct timeval *tv);
rt_err_t (*set_timeval)(struct timeval *tv);
};
typedef struct rt_rtc_device
{
struct rt_device parent;
const struct rt_rtc_ops *ops;
} rt_rtc_dev_t;
rt_err_t rt_hw_rtc_register(rt_rtc_dev_t *rtc,
const char *name,
rt_uint32_t flag,
void *data);
rt_err_t set_date(rt_uint32_t year, rt_uint32_t month, rt_uint32_t day);
rt_err_t set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second);
rt_err_t set_timestamp(time_t timestamp);
rt_err_t get_timestamp(time_t *timestamp);
#ifdef RT_USING_SYSTEM_WORKQUEUE
rt_err_t rt_soft_rtc_sync(void);
rt_err_t rt_soft_rtc_set_source(const char *name);
#endif
#ifdef __cplusplus
}
#endif
#endif /* __RTC_H__ */

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-07-25 weety first version
* 2024-05-26 HPMicro Add UHS-I support
*/
#ifndef __SD_H__
#define __SD_H__
#include <rtthread.h>
#include <drivers/mmcsd_host.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* SWITCH_FUNC timing
*/
#define SD_SWITCH_FUNC_TIMING_DEFAULT 0
#define SD_SWITCH_FUNC_TIMING_HS 1
#define SD_SWITCH_FUNC_TIMING_SDR50 2
#define SD_SWITCH_FUNC_TIMING_SDR104 3
#define SD_SWITCH_FUNC_TIMING_DDR50 4
rt_err_t mmcsd_send_if_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr);
rt_err_t mmcsd_send_app_op_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr, rt_uint32_t *rocr);
rt_err_t mmcsd_get_card_addr(struct rt_mmcsd_host *host, rt_uint32_t *rca);
rt_int32_t mmcsd_get_scr(struct rt_mmcsd_card *card, rt_uint32_t *scr);
rt_int32_t init_sd(struct rt_mmcsd_host *host, rt_uint32_t ocr);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,231 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-01-15 weety first version
*/
#ifndef __SDIO_H__
#define __SDIO_H__
#include <rtthread.h>
#include <drivers/mmcsd_host.h>
#include <drivers/mmcsd_card.h>
#include <drivers/sdio_func_ids.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Card Common Control Registers (CCCR)
*/
#define SDIO_REG_CCCR_CCCR_REV 0x00
#define SDIO_CCCR_REV_1_00 0 /* CCCR/FBR Version 1.00 */
#define SDIO_CCCR_REV_1_10 1 /* CCCR/FBR Version 1.10 */
#define SDIO_CCCR_REV_1_20 2 /* CCCR/FBR Version 1.20 */
#define SDIO_CCCR_REV_3_00 3 /* CCCR/FBR Version 2.00 */
#define SDIO_SDIO_REV_1_00 0 /* SDIO Spec Version 1.00 */
#define SDIO_SDIO_REV_1_10 1 /* SDIO Spec Version 1.10 */
#define SDIO_SDIO_REV_1_20 2 /* SDIO Spec Version 1.20 */
#define SDIO_SDIO_REV_2_00 3 /* SDIO Spec Version 2.00 */
#define SDIO_REG_CCCR_SD_REV 0x01
#define SDIO_SD_REV_1_01 0 /* SD Physical Spec Version 1.01 */
#define SDIO_SD_REV_1_10 1 /* SD Physical Spec Version 1.10 */
#define SDIO_SD_REV_2_00 2 /* SD Physical Spec Version 2.00 */
#define SDIO_REG_CCCR_IO_EN 0x02
#define SDIO_REG_CCCR_IO_RDY 0x03
#define SDIO_REG_CCCR_INT_EN 0x04 /* Function/Master Interrupt Enable */
#define SDIO_REG_CCCR_INT_PEND 0x05 /* Function Interrupt Pending */
#define SDIO_REG_CCCR_IO_ABORT 0x06 /* function abort/card reset */
#define SDIO_REG_CCCR_BUS_IF 0x07 /* bus interface controls */
#define SDIO_BUS_WIDTH_1BIT 0x00
#define SDIO_BUS_WIDTH_4BIT 0x02
#define SDIO_BUS_ECSI 0x20 /* Enable continuous SPI interrupt */
#define SDIO_BUS_SCSI 0x40 /* Support continuous SPI interrupt */
#define SDIO_BUS_ASYNC_INT 0x20
#define SDIO_BUS_CD_DISABLE 0x80 /* disable pull-up on DAT3 (pin 1) */
#define SDIO_REG_CCCR_CARD_CAPS 0x08
#define SDIO_CCCR_CAP_SDC 0x01 /* can do CMD52 while data transfer */
#define SDIO_CCCR_CAP_SMB 0x02 /* can do multi-block xfers (CMD53) */
#define SDIO_CCCR_CAP_SRW 0x04 /* supports read-wait protocol */
#define SDIO_CCCR_CAP_SBS 0x08 /* supports suspend/resume */
#define SDIO_CCCR_CAP_S4MI 0x10 /* interrupt during 4-bit CMD53 */
#define SDIO_CCCR_CAP_E4MI 0x20 /* enable ints during 4-bit CMD53 */
#define SDIO_CCCR_CAP_LSC 0x40 /* low speed card */
#define SDIO_CCCR_CAP_4BLS 0x80 /* 4 bit low speed card */
#define SDIO_REG_CCCR_CIS_PTR 0x09 /* common CIS pointer (3 bytes) */
/* Following 4 regs are valid only if SBS is set */
#define SDIO_REG_CCCR_BUS_SUSPEND 0x0c
#define SDIO_REG_CCCR_FUNC_SEL 0x0d
#define SDIO_REG_CCCR_EXEC_FLAG 0x0e
#define SDIO_REG_CCCR_READY_FLAG 0x0f
#define SDIO_REG_CCCR_FN0_BLKSIZE 0x10 /* 2bytes, 0x10~0x11 */
#define SDIO_REG_CCCR_POWER_CTRL 0x12
#define SDIO_POWER_SMPC 0x01 /* Supports Master Power Control */
#define SDIO_POWER_EMPC 0x02 /* Enable Master Power Control */
#define SDIO_REG_CCCR_SPEED 0x13
#define SDIO_SPEED_SHS 0x01 /* Supports High-Speed mode */
#define SDIO_SPEED_EHS 0x02 /* Enable High-Speed mode */
/*
* Function Basic Registers (FBR)
*/
#define SDIO_REG_FBR_BASE(f) ((f) * 0x100) /* base of function f's FBRs */
#define SDIO_REG_FBR_STD_FUNC_IF 0x00
#define SDIO_FBR_SUPPORTS_CSA 0x40 /* supports Code Storage Area */
#define SDIO_FBR_ENABLE_CSA 0x80 /* enable Code Storage Area */
#define SDIO_REG_FBR_STD_IF_EXT 0x01
#define SDIO_REG_FBR_POWER 0x02
#define SDIO_FBR_POWER_SPS 0x01 /* Supports Power Selection */
#define SDIO_FBR_POWER_EPS 0x02 /* Enable (low) Power Selection */
#define SDIO_REG_FBR_CIS 0x09 /* CIS pointer (3 bytes) */
#define SDIO_REG_FBR_CSA 0x0C /* CSA pointer (3 bytes) */
#define SDIO_REG_FBR_CSA_DATA 0x0F
#define SDIO_REG_FBR_BLKSIZE 0x10 /* block size (2 bytes) */
/* SDIO CIS Tuple code */
#define CISTPL_NULL 0x00
#define CISTPL_CHECKSUM 0x10
#define CISTPL_VERS_1 0x15
#define CISTPL_ALTSTR 0x16
#define CISTPL_MANFID 0x20
#define CISTPL_FUNCID 0x21
#define CISTPL_FUNCE 0x22
#define CISTPL_SDIO_STD 0x91
#define CISTPL_SDIO_EXT 0x92
#define CISTPL_END 0xff
/* SDIO device id */
#define SDIO_ANY_FUNC_ID 0xff
#define SDIO_ANY_MAN_ID 0xffff
#define SDIO_ANY_PROD_ID 0xffff
struct rt_sdio_device_id
{
rt_uint8_t func_code;
rt_uint16_t manufacturer;
rt_uint16_t product;
};
struct rt_sdio_driver
{
char *name;
rt_int32_t (*probe)(struct rt_mmcsd_card *card);
rt_int32_t (*remove)(struct rt_mmcsd_card *card);
struct rt_sdio_device_id *id;
};
rt_int32_t sdio_io_send_op_cond(struct rt_mmcsd_host *host,
rt_uint32_t ocr,
rt_uint32_t *cmd5_resp);
rt_int32_t sdio_io_rw_direct(struct rt_mmcsd_card *card,
rt_int32_t rw,
rt_uint32_t fn,
rt_uint32_t reg_addr,
rt_uint8_t *pdata,
rt_uint8_t raw);
rt_int32_t sdio_io_rw_extended(struct rt_mmcsd_card *card,
rt_int32_t rw,
rt_uint32_t fn,
rt_uint32_t addr,
rt_int32_t op_code,
rt_uint8_t *buf,
rt_uint32_t blocks,
rt_uint32_t blksize);
rt_int32_t sdio_io_rw_extended_block(struct rt_sdio_function *func,
rt_int32_t rw,
rt_uint32_t addr,
rt_int32_t op_code,
rt_uint8_t *buf,
rt_uint32_t len);
rt_uint8_t sdio_io_readb(struct rt_sdio_function *func,
rt_uint32_t reg,
rt_int32_t *err);
rt_int32_t sdio_io_writeb(struct rt_sdio_function *func,
rt_uint32_t reg,
rt_uint8_t data);
rt_uint16_t sdio_io_readw(struct rt_sdio_function *func,
rt_uint32_t addr,
rt_int32_t *err);
rt_int32_t sdio_io_writew(struct rt_sdio_function *func,
rt_uint16_t data,
rt_uint32_t addr);
rt_uint32_t sdio_io_readl(struct rt_sdio_function *func,
rt_uint32_t addr,
rt_int32_t *err);
rt_int32_t sdio_io_writel(struct rt_sdio_function *func,
rt_uint32_t data,
rt_uint32_t addr);
rt_int32_t sdio_io_read_multi_fifo_b(struct rt_sdio_function *func,
rt_uint32_t addr,
rt_uint8_t *buf,
rt_uint32_t len);
rt_int32_t sdio_io_write_multi_fifo_b(struct rt_sdio_function *func,
rt_uint32_t addr,
rt_uint8_t *buf,
rt_uint32_t len);
rt_int32_t sdio_io_read_multi_incr_b(struct rt_sdio_function *func,
rt_uint32_t addr,
rt_uint8_t *buf,
rt_uint32_t len);
rt_int32_t sdio_io_write_multi_incr_b(struct rt_sdio_function *func,
rt_uint32_t addr,
rt_uint8_t *buf,
rt_uint32_t len);
rt_int32_t init_sdio(struct rt_mmcsd_host *host, rt_uint32_t ocr);
rt_int32_t sdio_attach_irq(struct rt_sdio_function *func,
rt_sdio_irq_handler_t *handler);
rt_int32_t sdio_detach_irq(struct rt_sdio_function *func);
void sdio_irq_wakeup(struct rt_mmcsd_host *host);
rt_int32_t sdio_enable_func(struct rt_sdio_function *func);
rt_int32_t sdio_disable_func(struct rt_sdio_function *func);
void sdio_set_drvdata(struct rt_sdio_function *func, void *data);
void* sdio_get_drvdata(struct rt_sdio_function *func);
rt_int32_t sdio_set_block_size(struct rt_sdio_function *func,
rt_uint32_t blksize);
rt_int32_t sdio_register_driver(struct rt_sdio_driver *driver);
rt_int32_t sdio_unregister_driver(struct rt_sdio_driver *driver);
void rt_sdio_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,198 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-05-15 lgnq first version.
* 2012-05-28 bernard change interfaces
* 2013-02-20 bernard use RT_SERIAL_RB_BUFSZ to define
* the size of ring buffer.
*/
#ifndef __SERIAL_H__
#define __SERIAL_H__
#include <rtthread.h>
#define BAUD_RATE_2400 2400
#define BAUD_RATE_4800 4800
#define BAUD_RATE_9600 9600
#define BAUD_RATE_19200 19200
#define BAUD_RATE_38400 38400
#define BAUD_RATE_57600 57600
#define BAUD_RATE_115200 115200
#define BAUD_RATE_230400 230400
#define BAUD_RATE_460800 460800
#define BAUD_RATE_500000 500000
#define BAUD_RATE_576000 576000
#define BAUD_RATE_921600 921600
#define BAUD_RATE_1000000 1000000
#define BAUD_RATE_1152000 1152000
#define BAUD_RATE_1500000 1500000
#define BAUD_RATE_2000000 2000000
#define BAUD_RATE_2500000 2500000
#define BAUD_RATE_3000000 3000000
#define BAUD_RATE_3500000 3500000
#define BAUD_RATE_4000000 4000000
#define DATA_BITS_5 5
#define DATA_BITS_6 6
#define DATA_BITS_7 7
#define DATA_BITS_8 8
#define DATA_BITS_9 9
#define STOP_BITS_1 0
#define STOP_BITS_2 1
#define STOP_BITS_3 2
#define STOP_BITS_4 3
#ifdef _WIN32
#include <windows.h>
#else
#define PARITY_NONE 0
#define PARITY_ODD 1
#define PARITY_EVEN 2
#endif
#define BIT_ORDER_LSB 0
#define BIT_ORDER_MSB 1
#define NRZ_NORMAL 0 /* Non Return to Zero : normal mode */
#define NRZ_INVERTED 1 /* Non Return to Zero : inverted mode */
#ifndef RT_SERIAL_RB_BUFSZ
#define RT_SERIAL_RB_BUFSZ 64
#endif
#define RT_SERIAL_EVENT_RX_IND 0x01 /* Rx indication */
#define RT_SERIAL_EVENT_TX_DONE 0x02 /* Tx complete */
#define RT_SERIAL_EVENT_RX_DMADONE 0x03 /* Rx DMA transfer done */
#define RT_SERIAL_EVENT_TX_DMADONE 0x04 /* Tx DMA transfer done */
#define RT_SERIAL_EVENT_RX_TIMEOUT 0x05 /* Rx timeout */
#define RT_SERIAL_DMA_RX 0x01
#define RT_SERIAL_DMA_TX 0x02
#define RT_SERIAL_RX_INT 0x01
#define RT_SERIAL_TX_INT 0x02
#define RT_SERIAL_ERR_OVERRUN 0x01
#define RT_SERIAL_ERR_FRAMING 0x02
#define RT_SERIAL_ERR_PARITY 0x03
#define RT_SERIAL_TX_DATAQUEUE_SIZE 2048
#define RT_SERIAL_TX_DATAQUEUE_LWM 30
#define RT_SERIAL_FLOWCONTROL_CTSRTS 1
#define RT_SERIAL_FLOWCONTROL_NONE 0
/* Default config for serial_configure structure */
#define RT_SERIAL_CONFIG_DEFAULT \
{ \
BAUD_RATE_115200, /* 115200 bits/s */ \
DATA_BITS_8, /* 8 databits */ \
STOP_BITS_1, /* 1 stopbit */ \
PARITY_NONE, /* No parity */ \
BIT_ORDER_LSB, /* LSB first sent */ \
NRZ_NORMAL, /* Normal mode */ \
RT_SERIAL_RB_BUFSZ, /* Buffer size */ \
RT_SERIAL_FLOWCONTROL_NONE, /* Off flowcontrol */ \
0 \
}
/**
* @brief Sets a hook function when RX indicate is called
*
* @param thread is the target thread that initializing
*/
typedef void (*rt_hw_serial_rxind_hookproto_t)(rt_device_t dev, rt_size_t size);
RT_OBJECT_HOOKLIST_DECLARE(rt_hw_serial_rxind_hookproto_t, rt_hw_serial_rxind);
struct serial_configure
{
rt_uint32_t baud_rate;
rt_uint32_t data_bits :4;
rt_uint32_t stop_bits :2;
rt_uint32_t parity :2;
rt_uint32_t bit_order :1;
rt_uint32_t invert :1;
rt_uint32_t bufsz :16;
rt_uint32_t flowcontrol :1;
rt_uint32_t reserved :5;
};
/*
* Serial FIFO mode
*/
struct rt_serial_rx_fifo
{
/* software fifo */
rt_uint8_t *buffer;
rt_uint16_t put_index, get_index;
rt_bool_t is_full;
};
struct rt_serial_tx_fifo
{
struct rt_completion completion;
};
/*
* Serial DMA mode
*/
struct rt_serial_rx_dma
{
rt_bool_t activated;
};
struct rt_serial_tx_dma
{
rt_bool_t activated;
struct rt_data_queue data_queue;
};
struct rt_serial_device
{
struct rt_device parent;
const struct rt_uart_ops *ops;
struct serial_configure config;
void *serial_rx;
void *serial_tx;
struct rt_spinlock spinlock;
struct rt_device_notify rx_notify;
};
typedef struct rt_serial_device rt_serial_t;
/**
* uart operators
*/
struct rt_uart_ops
{
rt_err_t (*configure)(struct rt_serial_device *serial, struct serial_configure *cfg);
rt_err_t (*control)(struct rt_serial_device *serial, int cmd, void *arg);
int (*putc)(struct rt_serial_device *serial, char c);
int (*getc)(struct rt_serial_device *serial);
rt_ssize_t (*dma_transmit)(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction);
};
void rt_hw_serial_isr(struct rt_serial_device *serial, int event);
rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
const char *name,
rt_uint32_t flag,
void *data);
rt_err_t rt_hw_serial_register_tty(struct rt_serial_device *serial);
#endif

View File

@@ -0,0 +1,203 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-06-01 KyleChan first version
*/
#ifndef __SERIAL_V2_H__
#define __SERIAL_V2_H__
#include <rtthread.h>
#define BAUD_RATE_2400 2400
#define BAUD_RATE_4800 4800
#define BAUD_RATE_9600 9600
#define BAUD_RATE_19200 19200
#define BAUD_RATE_38400 38400
#define BAUD_RATE_57600 57600
#define BAUD_RATE_115200 115200
#define BAUD_RATE_230400 230400
#define BAUD_RATE_460800 460800
#define BAUD_RATE_500000 500000
#define BAUD_RATE_921600 921600
#define BAUD_RATE_2000000 2000000
#define BAUD_RATE_2500000 2500000
#define BAUD_RATE_3000000 3000000
#define DATA_BITS_5 5
#define DATA_BITS_6 6
#define DATA_BITS_7 7
#define DATA_BITS_8 8
#define DATA_BITS_9 9
#define STOP_BITS_1 0
#define STOP_BITS_2 1
#define STOP_BITS_3 2
#define STOP_BITS_4 3
#ifdef _WIN32
#include <windows.h>
#else
#define PARITY_NONE 0
#define PARITY_ODD 1
#define PARITY_EVEN 2
#endif
#define BIT_ORDER_LSB 0
#define BIT_ORDER_MSB 1
#define NRZ_NORMAL 0 /* Non Return to Zero : normal mode */
#define NRZ_INVERTED 1 /* Non Return to Zero : inverted mode */
#define RT_DEVICE_FLAG_RX_BLOCKING 0x1000
#define RT_DEVICE_FLAG_RX_NON_BLOCKING 0x2000
#define RT_DEVICE_FLAG_TX_BLOCKING 0x4000
#define RT_DEVICE_FLAG_TX_NON_BLOCKING 0x8000
#define RT_SERIAL_RX_BLOCKING RT_DEVICE_FLAG_RX_BLOCKING
#define RT_SERIAL_RX_NON_BLOCKING RT_DEVICE_FLAG_RX_NON_BLOCKING
#define RT_SERIAL_TX_BLOCKING RT_DEVICE_FLAG_TX_BLOCKING
#define RT_SERIAL_TX_NON_BLOCKING RT_DEVICE_FLAG_TX_NON_BLOCKING
#define RT_DEVICE_CHECK_OPTMODE 0x20
#define RT_SERIAL_EVENT_RX_IND 0x01 /* Rx indication */
#define RT_SERIAL_EVENT_TX_DONE 0x02 /* Tx complete */
#define RT_SERIAL_EVENT_RX_DMADONE 0x03 /* Rx DMA transfer done */
#define RT_SERIAL_EVENT_TX_DMADONE 0x04 /* Tx DMA transfer done */
#define RT_SERIAL_EVENT_RX_TIMEOUT 0x05 /* Rx timeout */
#define RT_SERIAL_ERR_OVERRUN 0x01
#define RT_SERIAL_ERR_FRAMING 0x02
#define RT_SERIAL_ERR_PARITY 0x03
#define RT_SERIAL_TX_DATAQUEUE_SIZE 2048
#define RT_SERIAL_TX_DATAQUEUE_LWM 30
#define RT_SERIAL_RX_MINBUFSZ 64
#define RT_SERIAL_TX_MINBUFSZ 64
#define RT_SERIAL_TX_BLOCKING_BUFFER 1
#define RT_SERIAL_TX_BLOCKING_NO_BUFFER 0
#define RT_SERIAL_FLOWCONTROL_CTSRTS 1
#define RT_SERIAL_FLOWCONTROL_NONE 0
/* Default config for serial_configure structure */
#define RT_SERIAL_CONFIG_DEFAULT \
{ \
BAUD_RATE_115200, /* 115200 bits/s */ \
DATA_BITS_8, /* 8 databits */ \
STOP_BITS_1, /* 1 stopbit */ \
PARITY_NONE, /* No parity */ \
BIT_ORDER_LSB, /* LSB first sent */ \
NRZ_NORMAL, /* Normal mode */ \
RT_SERIAL_RX_MINBUFSZ, /* rxBuf size */ \
RT_SERIAL_TX_MINBUFSZ, /* txBuf size */ \
RT_SERIAL_FLOWCONTROL_NONE, /* Off flowcontrol */ \
0 \
}
/**
* @brief Sets a hook function when RX indicate is called
*
* @param thread is the target thread that initializing
*/
typedef void (*rt_hw_serial_rxind_hookproto_t)(rt_device_t dev, rt_size_t size);
RT_OBJECT_HOOKLIST_DECLARE(rt_hw_serial_rxind_hookproto_t, rt_hw_serial_rxind);
struct serial_configure
{
rt_uint32_t baud_rate;
rt_uint32_t data_bits :4;
rt_uint32_t stop_bits :2;
rt_uint32_t parity :2;
rt_uint32_t bit_order :1;
rt_uint32_t invert :1;
rt_uint32_t rx_bufsz :16;
rt_uint32_t tx_bufsz :16;
rt_uint32_t flowcontrol :1;
rt_uint32_t reserved :5;
};
/*
* Serial Receive FIFO mode
*/
struct rt_serial_rx_fifo
{
struct rt_ringbuffer rb;
struct rt_completion rx_cpt;
rt_uint16_t rx_cpt_index;
/* software fifo */
rt_uint8_t buffer[];
};
/*
* Serial Transmit FIFO mode
*/
struct rt_serial_tx_fifo
{
struct rt_ringbuffer rb;
rt_size_t put_size;
rt_bool_t activated;
struct rt_completion tx_cpt;
/* software fifo */
rt_uint8_t buffer[];
};
struct rt_serial_device
{
struct rt_device parent;
const struct rt_uart_ops *ops;
struct serial_configure config;
void *serial_rx;
void *serial_tx;
struct rt_device_notify rx_notify;
};
/**
* uart operators
*/
struct rt_uart_ops
{
rt_err_t (*configure)(struct rt_serial_device *serial,
struct serial_configure *cfg);
rt_err_t (*control)(struct rt_serial_device *serial,
int cmd,
void *arg);
int (*putc)(struct rt_serial_device *serial, char c);
int (*getc)(struct rt_serial_device *serial);
rt_ssize_t (*transmit)(struct rt_serial_device *serial,
rt_uint8_t *buf,
rt_size_t size,
rt_uint32_t tx_flag);
};
void rt_hw_serial_isr(struct rt_serial_device *serial, int event);
rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
const char *name,
rt_uint32_t flag,
void *data);
rt_err_t rt_hw_serial_register_tty(struct rt_serial_device *serial);
#endif

View File

@@ -0,0 +1,373 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-11-23 Bernard Add extern "C"
* 2020-06-13 armink fix the 3 wires issue
* 2022-09-01 liYony fix api rt_spi_sendrecv16 about MSB and LSB bug
*/
#ifndef __SPI_H__
#define __SPI_H__
#include <stdlib.h>
#include <rtthread.h>
#include <drivers/pin.h>
#ifdef __cplusplus
extern "C"{
#endif
/**
* At CPOL=0 the base value of the clock is zero
* - For CPHA=0, data are captured on the clock's rising edge (low->high transition)
* and data are propagated on a falling edge (high->low clock transition).
* - For CPHA=1, data are captured on the clock's falling edge and data are
* propagated on a rising edge.
* At CPOL=1 the base value of the clock is one (inversion of CPOL=0)
* - For CPHA=0, data are captured on clock's falling edge and data are propagated
* on a rising edge.
* - For CPHA=1, data are captured on clock's rising edge and data are propagated
* on a falling edge.
*/
#define RT_SPI_CPHA (1<<0) /* bit[0]:CPHA, clock phase */
#define RT_SPI_CPOL (1<<1) /* bit[1]:CPOL, clock polarity */
#define RT_SPI_LSB (0<<2) /* bit[2]: 0-LSB */
#define RT_SPI_MSB (1<<2) /* bit[2]: 1-MSB */
#define RT_SPI_MASTER (0<<3) /* SPI master device */
#define RT_SPI_SLAVE (1<<3) /* SPI slave device */
#define RT_SPI_CS_HIGH (1<<4) /* Chipselect active high */
#define RT_SPI_NO_CS (1<<5) /* No chipselect */
#define RT_SPI_3WIRE (1<<6) /* SI/SO pin shared */
#define RT_SPI_READY (1<<7) /* Slave pulls low to pause */
#define RT_SPI_MODE_MASK (RT_SPI_CPHA | RT_SPI_CPOL | RT_SPI_MSB | RT_SPI_SLAVE | RT_SPI_CS_HIGH | RT_SPI_NO_CS | RT_SPI_3WIRE | RT_SPI_READY)
#define RT_SPI_MODE_0 (0 | 0) /* CPOL = 0, CPHA = 0 */
#define RT_SPI_MODE_1 (0 | RT_SPI_CPHA) /* CPOL = 0, CPHA = 1 */
#define RT_SPI_MODE_2 (RT_SPI_CPOL | 0) /* CPOL = 1, CPHA = 0 */
#define RT_SPI_MODE_3 (RT_SPI_CPOL | RT_SPI_CPHA) /* CPOL = 1, CPHA = 1 */
#define RT_SPI_BUS_MODE_SPI (1<<0)
#define RT_SPI_BUS_MODE_QSPI (1<<1)
/**
* SPI message structure
*/
struct rt_spi_message
{
const void *send_buf;
void *recv_buf;
rt_size_t length;
struct rt_spi_message *next;
unsigned cs_take : 1;
unsigned cs_release : 1;
};
/**
* SPI configuration structure
*/
struct rt_spi_configuration
{
rt_uint8_t mode;
rt_uint8_t data_width;
rt_uint16_t reserved;
rt_uint32_t max_hz;
};
struct rt_spi_ops;
struct rt_spi_bus
{
struct rt_device parent;
rt_uint8_t mode;
const struct rt_spi_ops *ops;
struct rt_mutex lock;
struct rt_spi_device *owner;
};
/**
* SPI operators
*/
struct rt_spi_ops
{
rt_err_t (*configure)(struct rt_spi_device *device, struct rt_spi_configuration *configuration);
rt_ssize_t (*xfer)(struct rt_spi_device *device, struct rt_spi_message *message);
};
/**
* SPI Virtual BUS, one device must connected to a virtual BUS
*/
struct rt_spi_device
{
struct rt_device parent;
struct rt_spi_bus *bus;
struct rt_spi_configuration config;
rt_base_t cs_pin;
void *user_data;
};
struct rt_qspi_message
{
struct rt_spi_message parent;
/* instruction stage */
struct
{
rt_uint8_t content;
rt_uint8_t qspi_lines;
} instruction;
/* address and alternate_bytes stage */
struct
{
rt_uint32_t content;
rt_uint8_t size;
rt_uint8_t qspi_lines;
} address, alternate_bytes;
/* dummy_cycles stage */
rt_uint32_t dummy_cycles;
/* number of lines in qspi data stage, the other configuration items are in parent */
rt_uint8_t qspi_data_lines;
};
struct rt_qspi_configuration
{
struct rt_spi_configuration parent;
/* The size of medium */
rt_uint32_t medium_size;
/* double data rate mode */
rt_uint8_t ddr_mode;
/* the data lines max width which QSPI bus supported, such as 1, 2, 4 */
rt_uint8_t qspi_dl_width ;
};
struct rt_qspi_device
{
struct rt_spi_device parent;
struct rt_qspi_configuration config;
void (*enter_qspi_mode)(struct rt_qspi_device *device);
void (*exit_qspi_mode)(struct rt_qspi_device *device);
};
#define SPI_DEVICE(dev) ((struct rt_spi_device *)(dev))
/* register a SPI bus */
rt_err_t rt_spi_bus_register(struct rt_spi_bus *bus,
const char *name,
const struct rt_spi_ops *ops);
/* attach a device on SPI bus */
rt_err_t rt_spi_bus_attach_device(struct rt_spi_device *device,
const char *name,
const char *bus_name,
void *user_data);
/* attach a device on SPI bus with CS pin */
rt_err_t rt_spi_bus_attach_device_cspin(struct rt_spi_device *device,
const char *name,
const char *bus_name,
rt_base_t cs_pin,
void *user_data);
/* re-configure SPI bus */
rt_err_t rt_spi_bus_configure(struct rt_spi_device *device);
/**
* This function takes SPI bus.
*
* @param device the SPI device attached to SPI bus
*
* @return RT_EOK on taken SPI bus successfully. others on taken SPI bus failed.
*/
rt_err_t rt_spi_take_bus(struct rt_spi_device *device);
/**
* This function releases SPI bus.
*
* @param device the SPI device attached to SPI bus
*
* @return RT_EOK on release SPI bus successfully.
*/
rt_err_t rt_spi_release_bus(struct rt_spi_device *device);
/**
* This function take SPI device (takes CS of SPI device).
*
* @param device the SPI device attached to SPI bus
*
* @return RT_EOK on release SPI bus successfully. others on taken SPI bus failed.
*/
rt_err_t rt_spi_take(struct rt_spi_device *device);
/**
* This function releases SPI device (releases CS of SPI device).
*
* @param device the SPI device attached to SPI bus
*
* @return RT_EOK on release SPI device successfully.
*/
rt_err_t rt_spi_release(struct rt_spi_device *device);
/* set configuration on SPI device */
rt_err_t rt_spi_configure(struct rt_spi_device *device,
struct rt_spi_configuration *cfg);
/* send data then receive data from SPI device */
rt_err_t rt_spi_send_then_recv(struct rt_spi_device *device,
const void *send_buf,
rt_size_t send_length,
void *recv_buf,
rt_size_t recv_length);
rt_err_t rt_spi_send_then_send(struct rt_spi_device *device,
const void *send_buf1,
rt_size_t send_length1,
const void *send_buf2,
rt_size_t send_length2);
/**
* This function transmits data to SPI device.
*
* @param device the SPI device attached to SPI bus
* @param send_buf the buffer to be transmitted to SPI device.
* @param recv_buf the buffer to save received data from SPI device.
* @param length the length of transmitted data.
*
* @return the actual length of transmitted.
*/
rt_ssize_t rt_spi_transfer(struct rt_spi_device *device,
const void *send_buf,
void *recv_buf,
rt_size_t length);
rt_err_t rt_spi_sendrecv8(struct rt_spi_device *device,
rt_uint8_t senddata,
rt_uint8_t *recvdata);
rt_err_t rt_spi_sendrecv16(struct rt_spi_device *device,
rt_uint16_t senddata,
rt_uint16_t *recvdata);
/**
* This function transfers a message list to the SPI device.
*
* @param device the SPI device attached to SPI bus
* @param message the message list to be transmitted to SPI device
*
* @return RT_NULL if transmits message list successfully,
* SPI message which be transmitted failed.
*/
struct rt_spi_message *rt_spi_transfer_message(struct rt_spi_device *device,
struct rt_spi_message *message);
rt_inline rt_size_t rt_spi_recv(struct rt_spi_device *device,
void *recv_buf,
rt_size_t length)
{
return rt_spi_transfer(device, RT_NULL, recv_buf, length);
}
rt_inline rt_size_t rt_spi_send(struct rt_spi_device *device,
const void *send_buf,
rt_size_t length)
{
return rt_spi_transfer(device, send_buf, RT_NULL, length);
}
/**
* This function appends a message to the SPI message list.
*
* @param list the SPI message list header.
* @param message the message pointer to be appended to the message list.
*/
rt_inline void rt_spi_message_append(struct rt_spi_message *list,
struct rt_spi_message *message)
{
RT_ASSERT(list != RT_NULL);
if (message == RT_NULL)
return; /* not append */
while (list->next != RT_NULL)
{
list = list->next;
}
list->next = message;
message->next = RT_NULL;
}
/**
* This function can set configuration on QSPI device.
*
* @param device the QSPI device attached to QSPI bus.
* @param cfg the configuration pointer.
*
* @return the actual length of transmitted.
*/
rt_err_t rt_qspi_configure(struct rt_qspi_device *device, struct rt_qspi_configuration *cfg);
/**
* This function can register a SPI bus for QSPI mode.
*
* @param bus the SPI bus for QSPI mode.
* @param name The name of the spi bus.
* @param ops the SPI bus instance to be registered.
*
* @return the actual length of transmitted.
*/
rt_err_t rt_qspi_bus_register(struct rt_spi_bus *bus, const char *name, const struct rt_spi_ops *ops);
/**
* This function transmits data to QSPI device.
*
* @param device the QSPI device attached to QSPI bus.
* @param message the message pointer.
*
* @return the actual length of transmitted.
*/
rt_size_t rt_qspi_transfer_message(struct rt_qspi_device *device, struct rt_qspi_message *message);
/**
* This function can send data then receive data from QSPI device
*
* @param device the QSPI device attached to QSPI bus.
* @param send_buf the buffer to be transmitted to QSPI device.
* @param send_length the number of data to be transmitted.
* @param recv_buf the buffer to be recivied from QSPI device.
* @param recv_length the data to be recivied.
*
* @return the status of transmit.
*/
rt_err_t rt_qspi_send_then_recv(struct rt_qspi_device *device, const void *send_buf, rt_size_t send_length,void *recv_buf, rt_size_t recv_length);
/**
* This function can send data to QSPI device
*
* @param device the QSPI device attached to QSPI bus.
* @param send_buf the buffer to be transmitted to QSPI device.
* @param send_length the number of data to be transmitted.
*
* @return the status of transmit.
*/
rt_err_t rt_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,113 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-05-20 tyustli the first version
*/
#ifndef __TOUCH_H__
#define __TOUCH_H__
#include <rtthread.h>
#include "pin.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef RT_USING_RTC
#define rt_touch_get_ts() time(RT_NULL) /* API for the touch to get the timestamp */
#else
#define rt_touch_get_ts() rt_tick_get() /* API for the touch to get the timestamp */
#endif
/* Touch vendor types */
#define RT_TOUCH_VENDOR_UNKNOWN (0) /* unknown */
#define RT_TOUCH_VENDOR_GT (1) /* GTxx series */
#define RT_TOUCH_VENDOR_FT (2) /* FTxx series */
/* Touch ic type*/
#define RT_TOUCH_TYPE_NONE (0) /* touch ic none */
#define RT_TOUCH_TYPE_CAPACITANCE (1) /* capacitance ic */
#define RT_TOUCH_TYPE_RESISTANCE (2) /* resistance ic */
/* Touch control cmd types */
#define RT_TOUCH_CTRL_GET_ID (RT_DEVICE_CTRL_BASE(Touch) + 0) /* Get device id */
#define RT_TOUCH_CTRL_GET_INFO (RT_DEVICE_CTRL_BASE(Touch) + 1) /* Get touch info */
#define RT_TOUCH_CTRL_SET_MODE (RT_DEVICE_CTRL_BASE(Touch) + 2) /* Set touch's work mode. ex. RT_TOUCH_MODE_POLLING,RT_TOUCH_MODE_INT */
#define RT_TOUCH_CTRL_SET_X_RANGE (RT_DEVICE_CTRL_BASE(Touch) + 3) /* Set x coordinate range */
#define RT_TOUCH_CTRL_SET_Y_RANGE (RT_DEVICE_CTRL_BASE(Touch) + 4) /* Set y coordinate range */
#define RT_TOUCH_CTRL_SET_X_TO_Y (RT_DEVICE_CTRL_BASE(Touch) + 5) /* Set X Y coordinate exchange */
#define RT_TOUCH_CTRL_DISABLE_INT (RT_DEVICE_CTRL_BASE(Touch) + 6) /* Disable interrupt */
#define RT_TOUCH_CTRL_ENABLE_INT (RT_DEVICE_CTRL_BASE(Touch) + 7) /* Enable interrupt */
#define RT_TOUCH_CTRL_POWER_ON (RT_DEVICE_CTRL_BASE(Touch) + 8) /* Touch Power On */
#define RT_TOUCH_CTRL_POWER_OFF (RT_DEVICE_CTRL_BASE(Touch) + 9) /* Touch Power Off */
#define RT_TOUCH_CTRL_GET_STATUS (RT_DEVICE_CTRL_BASE(Touch) + 10) /* Get Touch Power Status */
/* Touch event */
#define RT_TOUCH_EVENT_NONE (0) /* Touch none */
#define RT_TOUCH_EVENT_UP (1) /* Touch up event */
#define RT_TOUCH_EVENT_DOWN (2) /* Touch down event */
#define RT_TOUCH_EVENT_MOVE (3) /* Touch move event */
struct rt_touch_info
{
rt_uint8_t type; /* The touch type */
rt_uint8_t vendor; /* Vendor of touchs */
rt_uint8_t point_num; /* Support point num */
rt_int32_t range_x; /* X coordinate range */
rt_int32_t range_y; /* Y coordinate range */
};
struct rt_touch_config
{
#ifdef RT_TOUCH_PIN_IRQ
struct rt_device_pin_mode irq_pin; /* Interrupt pin, The purpose of this pin is to notification read data */
#endif
char *dev_name; /* The name of the communication device */
void *user_data;
};
typedef struct rt_touch_device *rt_touch_t;
struct rt_touch_device
{
struct rt_device parent; /* The standard device */
struct rt_touch_info info; /* The touch info data */
struct rt_touch_config config; /* The touch config data */
const struct rt_touch_ops *ops; /* The touch ops */
rt_err_t (*irq_handle)(rt_touch_t touch); /* Called when an interrupt is generated, registered by the driver */
};
struct rt_touch_data
{
rt_uint8_t event; /* The touch event of the data */
rt_uint8_t track_id; /* Track id of point */
rt_uint8_t width; /* Point of width */
rt_uint16_t x_coordinate; /* Point of x coordinate */
rt_uint16_t y_coordinate; /* Point of y coordinate */
rt_tick_t timestamp; /* The timestamp when the data was received */
};
struct rt_touch_ops
{
rt_size_t (*touch_readpoint)(struct rt_touch_device *touch, void *buf, rt_size_t touch_num);
rt_err_t (*touch_control)(struct rt_touch_device *touch, int cmd, void *arg);
};
int rt_hw_touch_register(rt_touch_t touch,
const char *name,
rt_uint32_t flag,
void *data);
/* if you doesn't use pin device. you must call this function in your touch irq callback */
void rt_hw_touch_isr(rt_touch_t touch);
#ifdef __cplusplus
}
#endif
#endif /* __TOUCH_H__ */

View File

@@ -0,0 +1,42 @@
/*
* COPYRIGHT (C) 2011-2023, Real-Thread Information Technology Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-09-12 heyuanjie87 first version.
*/
#ifndef __WATCHDOG_H__
#define __WATCHDOG_H__
#include <rtthread.h>
#define RT_DEVICE_CTRL_WDT_GET_TIMEOUT (RT_DEVICE_CTRL_BASE(WDT) + 1) /* get timeout(in seconds) */
#define RT_DEVICE_CTRL_WDT_SET_TIMEOUT (RT_DEVICE_CTRL_BASE(WDT) + 2) /* set timeout(in seconds) */
#define RT_DEVICE_CTRL_WDT_GET_TIMELEFT (RT_DEVICE_CTRL_BASE(WDT) + 3) /* get the left time before reboot(in seconds) */
#define RT_DEVICE_CTRL_WDT_KEEPALIVE (RT_DEVICE_CTRL_BASE(WDT) + 4) /* refresh watchdog */
#define RT_DEVICE_CTRL_WDT_START (RT_DEVICE_CTRL_BASE(WDT) + 5) /* start watchdog */
#define RT_DEVICE_CTRL_WDT_STOP (RT_DEVICE_CTRL_BASE(WDT) + 6) /* stop watchdog */
struct rt_watchdog_ops;
struct rt_watchdog_device
{
struct rt_device parent;
const struct rt_watchdog_ops *ops;
};
typedef struct rt_watchdog_device rt_watchdog_t;
struct rt_watchdog_ops
{
rt_err_t (*init)(rt_watchdog_t *wdt);
rt_err_t (*control)(rt_watchdog_t *wdt, int cmd, void *arg);
};
rt_err_t rt_hw_watchdog_register(rt_watchdog_t *wdt,
const char *name,
rt_uint32_t flag,
void *data);
#endif /* __WATCHDOG_H__ */

View File

@@ -0,0 +1,373 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2015-01-20 Bernard the first version
* 2021-02-06 Meco Man fix RT_ENOSYS code in negative
* 2022-04-29 WangQiang add pin operate command in MSH
*/
#include <drivers/pin.h>
static struct rt_device_pin _hw_pin;
static rt_ssize_t _pin_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
struct rt_device_pin_value *value;
struct rt_device_pin *pin = (struct rt_device_pin *)dev;
/* check parameters */
RT_ASSERT(pin != RT_NULL);
value = (struct rt_device_pin_value *)buffer;
if (value == RT_NULL || size != sizeof(*value))
return 0;
value->value = pin->ops->pin_read(dev, value->pin);
return size;
}
static rt_ssize_t _pin_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
struct rt_device_pin_value *value;
struct rt_device_pin *pin = (struct rt_device_pin *)dev;
/* check parameters */
RT_ASSERT(pin != RT_NULL);
value = (struct rt_device_pin_value *)buffer;
if (value == RT_NULL || size != sizeof(*value))
return 0;
pin->ops->pin_write(dev, (rt_base_t)value->pin, (rt_base_t)value->value);
return size;
}
static rt_err_t _pin_control(rt_device_t dev, int cmd, void *args)
{
struct rt_device_pin_mode *mode;
struct rt_device_pin *pin = (struct rt_device_pin *)dev;
/* check parameters */
RT_ASSERT(pin != RT_NULL);
mode = (struct rt_device_pin_mode *)args;
if (mode == RT_NULL)
return -RT_ERROR;
pin->ops->pin_mode(dev, (rt_base_t)mode->pin, (rt_base_t)mode->mode);
return 0;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops pin_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
_pin_read,
_pin_write,
_pin_control
};
#endif
int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
{
_hw_pin.parent.type = RT_Device_Class_Pin;
_hw_pin.parent.rx_indicate = RT_NULL;
_hw_pin.parent.tx_complete = RT_NULL;
#ifdef RT_USING_DEVICE_OPS
_hw_pin.parent.ops = &pin_ops;
#else
_hw_pin.parent.init = RT_NULL;
_hw_pin.parent.open = RT_NULL;
_hw_pin.parent.close = RT_NULL;
_hw_pin.parent.read = _pin_read;
_hw_pin.parent.write = _pin_write;
_hw_pin.parent.control = _pin_control;
#endif
_hw_pin.ops = ops;
_hw_pin.parent.user_data = user_data;
/* register a character device */
rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);
return 0;
}
rt_err_t rt_pin_attach_irq(rt_base_t pin, rt_uint8_t mode,
void (*hdr)(void *args), void *args)
{
RT_ASSERT(_hw_pin.ops != RT_NULL);
if (_hw_pin.ops->pin_attach_irq)
{
return _hw_pin.ops->pin_attach_irq(&_hw_pin.parent, pin, mode, hdr, args);
}
return -RT_ENOSYS;
}
rt_err_t rt_pin_detach_irq(rt_base_t pin)
{
RT_ASSERT(_hw_pin.ops != RT_NULL);
if (_hw_pin.ops->pin_detach_irq)
{
return _hw_pin.ops->pin_detach_irq(&_hw_pin.parent, pin);
}
return -RT_ENOSYS;
}
rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint8_t enabled)
{
RT_ASSERT(_hw_pin.ops != RT_NULL);
if (_hw_pin.ops->pin_irq_enable)
{
return _hw_pin.ops->pin_irq_enable(&_hw_pin.parent, pin, enabled);
}
return -RT_ENOSYS;
}
/* RT-Thread Hardware PIN APIs */
void rt_pin_mode(rt_base_t pin, rt_uint8_t mode)
{
RT_ASSERT(_hw_pin.ops != RT_NULL);
_hw_pin.ops->pin_mode(&_hw_pin.parent, pin, mode);
}
void rt_pin_write(rt_base_t pin, rt_ssize_t value)
{
RT_ASSERT(_hw_pin.ops != RT_NULL);
_hw_pin.ops->pin_write(&_hw_pin.parent, pin, value);
}
rt_ssize_t rt_pin_read(rt_base_t pin)
{
RT_ASSERT(_hw_pin.ops != RT_NULL);
return _hw_pin.ops->pin_read(&_hw_pin.parent, pin);
}
/* Get pin number by name, such as PA.0, P0.12 */
rt_base_t rt_pin_get(const char *name)
{
RT_ASSERT(_hw_pin.ops != RT_NULL);
if (_hw_pin.ops->pin_get == RT_NULL)
{
return -RT_ENOSYS;
}
return _hw_pin.ops->pin_get(name);
}
#ifdef RT_USING_FINSH
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <finsh.h>
#include <msh_parse.h>
/*
* convert function for port name
*/
static rt_base_t _pin_cmd_conv(const char *name)
{
return rt_pin_get(name);
}
static void _pin_cmd_print_usage(void)
{
rt_kprintf("pin [option] GPIO\n");
rt_kprintf(" num: get pin number from hardware pin\n");
rt_kprintf(" mode: set pin mode to output/input/input_pullup/input_pulldown/output_od\n");
rt_kprintf(" e.g. MSH >pin mode GPIO output\n");
rt_kprintf(" read: read pin level of hardware pin\n");
rt_kprintf(" e.g. MSH >pin read GPIO\n");
rt_kprintf(" write: write pin level(high/low or on/off) to hardware pin\n");
rt_kprintf(" e.g. MSH >pin write GPIO high\n");
rt_kprintf(" help: this help list\n");
rt_kprintf("GPIO e.g.:");
rt_pin_get(" ");
}
/* e.g. MSH >pin num PA.16 */
static void _pin_cmd_get(int argc, char *argv[])
{
rt_base_t pin;
if (argc < 3)
{
_pin_cmd_print_usage();
return;
}
pin = _pin_cmd_conv(argv[2]);
if (pin < 0)
{
rt_kprintf("Parameter invalid : %s!\n", argv[2]);
_pin_cmd_print_usage();
return ;
}
rt_kprintf("%s : %d\n", argv[2], pin);
}
/* e.g. MSH >pin mode PA.16 output */
static void _pin_cmd_mode(int argc, char *argv[])
{
rt_base_t pin;
rt_base_t mode;
if (argc < 4)
{
_pin_cmd_print_usage();
return;
}
if (!msh_isint(argv[2]))
{
pin = _pin_cmd_conv(argv[2]);
if (pin < 0)
{
rt_kprintf("Parameter invalid : %s!\n", argv[2]);
_pin_cmd_print_usage();
return;
}
}
else
{
pin = atoi(argv[2]);
}
if (0 == rt_strcmp("output", argv[3]))
{
mode = PIN_MODE_OUTPUT;
}
else if (0 == rt_strcmp("input", argv[3]))
{
mode = PIN_MODE_INPUT;
}
else if (0 == rt_strcmp("input_pullup", argv[3]))
{
mode = PIN_MODE_INPUT_PULLUP;
}
else if (0 == rt_strcmp("input_pulldown", argv[3]))
{
mode = PIN_MODE_INPUT_PULLDOWN;
}
else if (0 == rt_strcmp("output_od", argv[3]))
{
mode = PIN_MODE_OUTPUT_OD;
}
else
{
_pin_cmd_print_usage();
return;
}
rt_pin_mode(pin, mode);
}
/* e.g. MSH >pin read PA.16 */
static void _pin_cmd_read(int argc, char *argv[])
{
rt_base_t pin;
rt_uint8_t value;
if (argc < 3)
{
_pin_cmd_print_usage();
return;
}
if (!msh_isint(argv[2]))
{
pin = _pin_cmd_conv(argv[2]);
if (pin < 0)
{
rt_kprintf("Parameter invalid : %s!\n", argv[2]);
_pin_cmd_print_usage();
return;
}
}
else
{
pin = atoi(argv[2]);
}
value = rt_pin_read(pin);
if (value == PIN_HIGH)
{
rt_kprintf("pin[%d] = high\n", pin);
}
else
{
rt_kprintf("pin[%d] = low\n", pin);
}
}
/* e.g. MSH >pin write PA.16 high */
static void _pin_cmd_write(int argc, char *argv[])
{
rt_base_t pin;
rt_uint8_t value;
if (argc < 4)
{
_pin_cmd_print_usage();
return;
}
if (!msh_isint(argv[2]))
{
pin = _pin_cmd_conv(argv[2]);
if (pin < 0)
{
rt_kprintf("Parameter invalid : %s!\n", argv[2]);
_pin_cmd_print_usage();
return;
}
}
else
{
pin = atoi(argv[2]);
}
if ((0 == rt_strcmp("high", argv[3])) || (0 == rt_strcmp("on", argv[3])))
{
value = PIN_HIGH;
}
else if ((0 == rt_strcmp("low", argv[3])) || (0 == rt_strcmp("off", argv[3])))
{
value = PIN_LOW;
}
else
{
_pin_cmd_print_usage();
return;
}
rt_pin_write(pin, value);
}
static void _pin_cmd(int argc, char *argv[])
{
if (argc < 3)
{
_pin_cmd_print_usage();
return ;
}
if (0 == rt_strcmp("num", argv[1]))
{
_pin_cmd_get(argc, argv);
}
else if (0 == rt_strcmp("mode", argv[1]))
{
_pin_cmd_mode(argc, argv);
}
else if (0 == rt_strcmp("read", argv[1]))
{
_pin_cmd_read(argc, argv);
}
else if (0 == rt_strcmp("write", argv[1]))
{
_pin_cmd_write(argc, argv);
}
else
{
_pin_cmd_print_usage();
return;
}
}
MSH_CMD_EXPORT_ALIAS(_pin_cmd, pin, pin [option]);
#endif /* RT_USING_FINSH */

View File

@@ -0,0 +1,220 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-11-26 GuEe-GUI first version
*/
#include "pin_dm.h"
static void pin_dm_irq_mask(struct rt_pic_irq *pirq)
{
struct rt_device_pin *gpio = pirq->pic->priv_data;
gpio->ops->pin_irq_enable(&gpio->parent, pirq->hwirq, 0);
}
static void pin_dm_irq_unmask(struct rt_pic_irq *pirq)
{
struct rt_device_pin *gpio = pirq->pic->priv_data;
gpio->ops->pin_irq_enable(&gpio->parent, pirq->hwirq, 1);
}
static rt_err_t pin_dm_irq_set_triger_mode(struct rt_pic_irq *pirq, rt_uint32_t mode)
{
rt_uint8_t pin_mode;
struct rt_device_pin *gpio = pirq->pic->priv_data;
switch (mode)
{
case RT_IRQ_MODE_EDGE_RISING:
pin_mode = PIN_IRQ_MODE_RISING;
break;
case RT_IRQ_MODE_EDGE_FALLING:
pin_mode = PIN_IRQ_MODE_FALLING;
break;
case RT_IRQ_MODE_EDGE_BOTH:
pin_mode = PIN_IRQ_MODE_RISING_FALLING;
break;
case RT_IRQ_MODE_LEVEL_HIGH:
pin_mode = PIN_IRQ_MODE_HIGH_LEVEL;
break;
case RT_IRQ_MODE_LEVEL_LOW:
pin_mode = PIN_IRQ_MODE_LOW_LEVEL;
break;
default:
return -RT_ENOSYS;
}
return gpio->ops->pin_irq_mode(&gpio->parent, pirq->hwirq, pin_mode);
}
static int pin_dm_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode)
{
int irq = -1;
struct rt_device_pin *gpio = pic->priv_data;
struct rt_pic_irq *pirq = rt_pic_find_irq(pic, hwirq);
if (pirq)
{
irq = rt_pic_config_irq(pic, hwirq, hwirq);
if (irq >= 0)
{
rt_pic_cascade(pirq, gpio->irqchip.irq);
rt_pic_irq_set_triger_mode(irq, mode);
}
}
return irq;
}
static rt_err_t pin_dm_irq_parse(struct rt_pic *pic, struct rt_ofw_cell_args *args, struct rt_pic_irq *out_pirq)
{
rt_err_t err = RT_EOK;
if (args->args_count == 2)
{
out_pirq->hwirq = args->args[0];
out_pirq->mode = args->args[1] & RT_IRQ_MODE_MASK;
}
else
{
err = -RT_EINVAL;
}
return err;
}
static struct rt_pic_ops pin_dm_ops =
{
.name = "GPIO",
.irq_enable = pin_dm_irq_mask,
.irq_disable = pin_dm_irq_unmask,
.irq_mask = pin_dm_irq_mask,
.irq_unmask = pin_dm_irq_unmask,
.irq_set_triger_mode = pin_dm_irq_set_triger_mode,
.irq_map = pin_dm_irq_map,
.irq_parse = pin_dm_irq_parse,
};
rt_err_t pin_pic_handle_isr(struct rt_device_pin *gpio, rt_base_t pin)
{
rt_err_t err;
if (gpio)
{
struct rt_pin_irqchip *irqchip = &gpio->irqchip;
if (pin >= irqchip->pin_range[0] && pin <= irqchip->pin_range[1])
{
struct rt_pic_irq *pirq;
pirq = rt_pic_find_irq(&irqchip->parent, pin - irqchip->pin_range[0]);
if (pirq->irq >= 0)
{
err = rt_pic_handle_isr(pirq);
}
else
{
err = -RT_EINVAL;
}
}
else
{
err = -RT_EINVAL;
}
}
else
{
err = -RT_EINVAL;
}
return err;
}
rt_err_t pin_pic_init(struct rt_device_pin *gpio)
{
rt_err_t err;
if (gpio)
{
struct rt_pin_irqchip *irqchip = &gpio->irqchip;
if (irqchip->pin_range[0] >= 0 && irqchip->pin_range[1] >= irqchip->pin_range[0])
{
struct rt_pic *pic = &irqchip->parent;
rt_size_t pin_nr = irqchip->pin_range[1] - irqchip->pin_range[0] + 1;
pic->priv_data = gpio;
pic->ops = &pin_dm_ops;
/* Make sure the type of gpio for pic */
gpio->parent.parent.type = RT_Object_Class_Device;
rt_pic_default_name(&irqchip->parent);
err = rt_pic_linear_irq(pic, pin_nr);
rt_pic_user_extends(pic);
}
else
{
err = -RT_EINVAL;
}
}
else
{
err = -RT_EINVAL;
}
return err;
}
rt_ssize_t rt_pin_get_named_pin(struct rt_device *dev, const char *propname, int index,
rt_uint8_t *out_mode, rt_uint8_t *out_value)
{
rt_ssize_t res = -RT_ENOSYS;
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
res = rt_ofw_get_named_pin(dev->ofw_node, propname, index, out_mode, out_value);
}
else
{
res = -RT_EINVAL;
}
#endif /* RT_USING_OFW */
return res;
}
rt_ssize_t rt_pin_get_named_pin_count(struct rt_device *dev, const char *propname)
{
rt_ssize_t count = -RT_ENOSYS;
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
count = rt_ofw_get_named_pin_count(dev->ofw_node, propname);
}
else
{
count = -RT_EINVAL;
}
#endif /* RT_USING_OFW */
return count;
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-11-26 GuEe-GUI first version
*/
#ifndef __PIN_DM_H__
#define __PIN_DM_H__
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
rt_err_t pin_pic_handle_isr(struct rt_device_pin *gpio, rt_base_t pin);
rt_err_t pin_pic_init(struct rt_device_pin *gpio);
#endif /* __PIN_DM_H__ */

View File

@@ -0,0 +1,170 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-11-26 GuEe-GUI first version
*/
#include <dt-bindings/pin/pin.h>
#include "pin_dm.h"
static const char * const gpio_suffixes[] =
{
"gpios", "gpio"
};
rt_ssize_t rt_ofw_get_named_pin(struct rt_ofw_node *np, const char *propname, int index,
rt_uint8_t *out_mode, rt_uint8_t *out_value)
{
rt_ssize_t pin = -1;
rt_uint8_t mode;
rt_uint8_t value;
rt_uint32_t flags;
char gpios_name[64];
struct rt_device_pin *pin_dev = 0;
struct rt_ofw_node *pin_dev_np = 0;
struct rt_ofw_cell_args pin_args = {0};
if (!np && index < 0)
{
return -RT_EINVAL;
}
for (int i = 0; i < RT_ARRAY_SIZE(gpio_suffixes); ++i)
{
if (propname)
{
rt_snprintf(gpios_name, sizeof(gpios_name), "%s-%s", propname, gpio_suffixes[i]);
}
else
{
rt_snprintf(gpios_name, sizeof(gpios_name), "%s", gpio_suffixes[i]);
}
pin = rt_ofw_parse_phandle_cells(np, gpios_name, "#gpio-cells", index, &pin_args);
if (pin >= 0)
{
break;
}
}
if (pin < 0)
{
return pin;
}
pin_dev_np = pin_args.data;
pin_dev = rt_ofw_data(pin_dev_np);
if (!pin_dev)
{
pin = -RT_ERROR;
goto _out_converts;
}
value = PIN_LOW;
mode = PIN_MODE_OUTPUT;
if (pin_dev->ops->pin_parse)
{
pin = pin_dev->ops->pin_parse(&pin_dev->parent, &pin_args, &flags);
}
else
{
/*
* We always assume that the args[0] is the pin number if driver not
* implemented `pin_parse`.
*/
pin = pin_args.args[0];
goto _out_converts;
}
if (out_mode)
{
if (flags & PIN_OPEN_DRAIN)
{
mode = PIN_MODE_OUTPUT_OD;
}
switch (flags & RT_GENMASK(6, 4))
{
case PIN_PULL_UP:
mode = PIN_MODE_INPUT_PULLUP;
break;
case PIN_PULL_DOWN:
mode = PIN_MODE_INPUT_PULLDOWN;
break;
case PIN_PULL_DISABLE:
mode = PIN_MODE_INPUT;
break;
}
}
if (out_value)
{
if (flags == (PIN_ACTIVE_HIGH | PIN_PUSH_PULL))
{
value = PIN_HIGH;
}
else if (flags == (PIN_ACTIVE_LOW | PIN_PUSH_PULL))
{
value = PIN_LOW;
}
}
_out_converts:
rt_ofw_node_put(pin_dev_np);
if (out_mode)
{
*out_mode = mode;
}
if (out_value)
{
*out_value = value;
}
return pin;
}
rt_ssize_t rt_ofw_get_named_pin_count(struct rt_ofw_node *np, const char *propname)
{
char gpios_name[64];
rt_ssize_t count = 0;
if (!np || !propname)
{
return -RT_EINVAL;
}
for (int i = 0; i < RT_ARRAY_SIZE(gpio_suffixes); ++i)
{
if (propname)
{
rt_snprintf(gpios_name, sizeof(gpios_name), "%s-%s", propname, gpio_suffixes[i]);
}
else
{
rt_snprintf(gpios_name, sizeof(gpios_name), "%s", gpio_suffixes[i]);
}
count = rt_ofw_count_phandle_cells(np, propname, "#gpio-cells");
if (count > 0)
{
break;
}
}
return count;
}

View File

@@ -0,0 +1,800 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-10-27 heyuanjie87 first version.
* 2013-05-17 aozima initial alarm event & mutex in system init.
* 2020-10-15 zhangsz add alarm flags hour minute second.
* 2020-11-09 zhangsz fix alarm set when modify rtc time.
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <sys/time.h>
#define RT_RTC_YEARS_MAX 137
#ifdef RT_USING_SOFT_RTC
#define RT_ALARM_DELAY 0
#else
#define RT_ALARM_DELAY 2
#endif
#if (defined(RT_USING_RTC) && defined(RT_USING_ALARM))
static struct rt_alarm_container _container;
rt_inline rt_uint32_t alarm_mkdaysec(struct tm *time)
{
rt_uint32_t sec;
sec = time->tm_sec;
sec += time->tm_min * 60;
sec += time->tm_hour * 3600;
return (sec);
}
static rt_err_t alarm_set(struct rt_alarm *alarm)
{
rt_device_t device;
struct rt_rtc_wkalarm wkalarm;
rt_err_t ret;
device = rt_device_find("rtc");
if (device == RT_NULL)
{
return (RT_ERROR);
}
if (alarm->flag & RT_ALARM_STATE_START)
wkalarm.enable = RT_TRUE;
else
wkalarm.enable = RT_FALSE;
wkalarm.tm_sec = alarm->wktime.tm_sec;
wkalarm.tm_min = alarm->wktime.tm_min;
wkalarm.tm_hour = alarm->wktime.tm_hour;
wkalarm.tm_mday = alarm->wktime.tm_mday;
wkalarm.tm_mon = alarm->wktime.tm_mon;
wkalarm.tm_year = alarm->wktime.tm_year;
ret = rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_ALARM, &wkalarm);
if ((ret == RT_EOK) && wkalarm.enable)
{
ret = rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_ALARM, &wkalarm);
if (ret == RT_EOK)
{
/*
some RTC device like RX8025,it's alarms precision is 1 minute.
in this case,low level RTC driver should set wkalarm->tm_sec to 0.
*/
alarm->wktime.tm_sec = wkalarm.tm_sec;
alarm->wktime.tm_min = wkalarm.tm_min;
alarm->wktime.tm_hour = wkalarm.tm_hour;
alarm->wktime.tm_mday = wkalarm.tm_mday;
alarm->wktime.tm_mon = wkalarm.tm_mon;
alarm->wktime.tm_year = wkalarm.tm_year;
}
}
return (ret);
}
static void alarm_wakeup(struct rt_alarm *alarm, struct tm *now)
{
rt_uint32_t sec_alarm, sec_now;
rt_bool_t wakeup = RT_FALSE;
time_t timestamp;
sec_alarm = alarm_mkdaysec(&alarm->wktime);
sec_now = alarm_mkdaysec(now);
if (alarm->flag & RT_ALARM_STATE_START)
{
switch (alarm->flag & 0xFF00)
{
case RT_ALARM_ONESHOT:
{
sec_alarm = timegm(&alarm->wktime);
sec_now = timegm(now);
if (((sec_now - sec_alarm) <= RT_ALARM_DELAY) && (sec_now >= sec_alarm))
{
/* stop alarm */
alarm->flag &= ~RT_ALARM_STATE_START;
alarm_set(alarm);
wakeup = RT_TRUE;
}
}
break;
case RT_ALARM_SECOND:
{
alarm->wktime.tm_hour = now->tm_hour;
alarm->wktime.tm_min = now->tm_min;
alarm->wktime.tm_sec = now->tm_sec + 1;
if (alarm->wktime.tm_sec > 59)
{
alarm->wktime.tm_sec = 0;
alarm->wktime.tm_min = alarm->wktime.tm_min + 1;
if (alarm->wktime.tm_min > 59)
{
alarm->wktime.tm_min = 0;
alarm->wktime.tm_hour = alarm->wktime.tm_hour + 1;
if (alarm->wktime.tm_hour > 23)
{
alarm->wktime.tm_hour = 0;
}
}
}
wakeup = RT_TRUE;
}
break;
case RT_ALARM_MINUTE:
{
alarm->wktime.tm_hour = now->tm_hour;
if (alarm->wktime.tm_sec == now->tm_sec)
{
alarm->wktime.tm_min = now->tm_min + 1;
if (alarm->wktime.tm_min > 59)
{
alarm->wktime.tm_min = 0;
alarm->wktime.tm_hour = alarm->wktime.tm_hour + 1;
if (alarm->wktime.tm_hour > 23)
{
alarm->wktime.tm_hour = 0;
}
}
wakeup = RT_TRUE;
}
}
break;
case RT_ALARM_HOUR:
{
if ((alarm->wktime.tm_min == now->tm_min) &&
(alarm->wktime.tm_sec == now->tm_sec))
{
alarm->wktime.tm_hour = now->tm_hour + 1;
if (alarm->wktime.tm_hour > 23)
{
alarm->wktime.tm_hour = 0;
}
wakeup = RT_TRUE;
}
}
break;
case RT_ALARM_DAILY:
{
if (((sec_now - sec_alarm) <= RT_ALARM_DELAY) && (sec_now >= sec_alarm))
wakeup = RT_TRUE;
}
break;
case RT_ALARM_WEEKLY:
{
/* alarm at wday */
if (alarm->wktime.tm_wday == now->tm_wday)
{
sec_alarm += alarm->wktime.tm_wday * 24 * 3600;
sec_now += now->tm_wday * 24 * 3600;
if (sec_now == sec_alarm)
wakeup = RT_TRUE;
}
}
break;
case RT_ALARM_MONTHLY:
{
/* monthly someday generate alarm signals */
if (alarm->wktime.tm_mday == now->tm_mday)
{
if ((sec_now - sec_alarm) <= RT_ALARM_DELAY)
wakeup = RT_TRUE;
}
}
break;
case RT_ALARM_YAERLY:
{
if ((alarm->wktime.tm_mday == now->tm_mday) && \
(alarm->wktime.tm_mon == now->tm_mon))
{
if ((sec_now - sec_alarm) <= RT_ALARM_DELAY)
wakeup = RT_TRUE;
}
}
break;
}
if ((wakeup == RT_TRUE) && (alarm->callback != RT_NULL))
{
timestamp = (time_t)0;
get_timestamp(&timestamp);
alarm->callback(alarm, timestamp);
}
}
}
static void alarm_update(rt_uint32_t event)
{
struct rt_alarm *alm_prev = RT_NULL, *alm_next = RT_NULL;
struct rt_alarm *alarm;
rt_int32_t sec_now, sec_alarm, sec_tmp;
rt_int32_t sec_next = 24 * 3600, sec_prev = 0;
time_t timestamp = (time_t)0;
struct tm now;
rt_list_t *next;
rt_mutex_take(&_container.mutex, RT_WAITING_FOREVER);
if (!rt_list_isempty(&_container.head))
{
/* get time of now */
get_timestamp(&timestamp);
gmtime_r(&timestamp, &now);
for (next = _container.head.next; next != &_container.head; next = next->next)
{
alarm = rt_list_entry(next, struct rt_alarm, list);
/* check the overtime alarm */
alarm_wakeup(alarm, &now);
}
/* get time of now */
get_timestamp(&timestamp);
gmtime_r(&timestamp, &now);
sec_now = alarm_mkdaysec(&now);
for (next = _container.head.next; next != &_container.head; next = next->next)
{
alarm = rt_list_entry(next, struct rt_alarm, list);
/* calculate seconds from 00:00:00 */
sec_alarm = alarm_mkdaysec(&alarm->wktime);
if (alarm->flag & RT_ALARM_STATE_START)
{
sec_tmp = sec_alarm - sec_now;
if (sec_tmp > 0)
{
/* find alarm after now(now to 23:59:59) and the most recent */
if (sec_tmp < sec_next)
{
sec_next = sec_tmp;
alm_next = alarm;
}
}
else
{
/* find alarm before now(00:00:00 to now) and furthest from now */
if (sec_tmp < sec_prev)
{
sec_prev = sec_tmp;
alm_prev = alarm;
}
}
}
}
/* enable the alarm after now first */
if (sec_next < 24 * 3600)
{
if (alarm_set(alm_next) == RT_EOK)
_container.current = alm_next;
}
else if (sec_prev < 0)
{
/* enable the alarm before now */
if (alarm_set(alm_prev) == RT_EOK)
_container.current = alm_prev;
}
else
{
if (_container.current != RT_NULL)
{
alarm_set(_container.current);
if (!(_container.current->flag & RT_ALARM_STATE_START))
_container.current = RT_NULL;
}
}
}
rt_mutex_release(&_container.mutex);
}
static int days_of_year_month(int tm_year, int tm_mon)
{
int ret, year;
year = tm_year + 1900;
if (tm_mon == 1)
{
ret = 28 + ((!(year % 4) && (year % 100)) || !(year % 400));
}
else if (((tm_mon <= 6) && (tm_mon % 2 == 0)) || ((tm_mon > 6) && (tm_mon % 2 == 1)))
{
ret = 31;
}
else
{
ret = 30;
}
return (ret);
}
static rt_bool_t is_valid_date(struct tm *date)
{
if ((date->tm_year < 0) || (date->tm_year > RT_RTC_YEARS_MAX))
{
return (RT_FALSE);
}
if ((date->tm_mon < 0) || (date->tm_mon > 11))
{
return (RT_FALSE);
}
if ((date->tm_mday < 1) || \
(date->tm_mday > days_of_year_month(date->tm_year, date->tm_mon)))
{
return (RT_FALSE);
}
return (RT_TRUE);
}
static rt_err_t alarm_setup(rt_alarm_t alarm, struct tm *wktime)
{
rt_err_t ret = -RT_ERROR;
time_t timestamp = (time_t)0;
struct tm *setup, now;
setup = &alarm->wktime;
*setup = *wktime;
/* get time of now */
get_timestamp(&timestamp);
gmtime_r(&timestamp, &now);
/* if these are a "don't care" value,we set them to now*/
if ((setup->tm_sec > 59) || (setup->tm_sec < 0))
setup->tm_sec = now.tm_sec;
if ((setup->tm_min > 59) || (setup->tm_min < 0))
setup->tm_min = now.tm_min;
if ((setup->tm_hour > 23) || (setup->tm_hour < 0))
setup->tm_hour = now.tm_hour;
switch (alarm->flag & 0xFF00)
{
case RT_ALARM_SECOND:
{
alarm->wktime.tm_hour = now.tm_hour;
alarm->wktime.tm_min = now.tm_min;
alarm->wktime.tm_sec = now.tm_sec + 1;
if (alarm->wktime.tm_sec > 59)
{
alarm->wktime.tm_sec = 0;
alarm->wktime.tm_min = alarm->wktime.tm_min + 1;
if (alarm->wktime.tm_min > 59)
{
alarm->wktime.tm_min = 0;
alarm->wktime.tm_hour = alarm->wktime.tm_hour + 1;
if (alarm->wktime.tm_hour > 23)
{
alarm->wktime.tm_hour = 0;
}
}
}
}
break;
case RT_ALARM_MINUTE:
{
alarm->wktime.tm_hour = now.tm_hour;
alarm->wktime.tm_min = now.tm_min + 1;
if (alarm->wktime.tm_min > 59)
{
alarm->wktime.tm_min = 0;
alarm->wktime.tm_hour = alarm->wktime.tm_hour + 1;
if (alarm->wktime.tm_hour > 23)
{
alarm->wktime.tm_hour = 0;
}
}
}
break;
case RT_ALARM_HOUR:
{
alarm->wktime.tm_hour = now.tm_hour + 1;
if (alarm->wktime.tm_hour > 23)
{
alarm->wktime.tm_hour = 0;
}
}
break;
case RT_ALARM_DAILY:
{
/* do nothing but needed */
}
break;
case RT_ALARM_ONESHOT:
{
/* if these are "don't care" value we set them to now */
if (setup->tm_year == RT_ALARM_TM_NOW)
setup->tm_year = now.tm_year;
if (setup->tm_mon == RT_ALARM_TM_NOW)
setup->tm_mon = now.tm_mon;
if (setup->tm_mday == RT_ALARM_TM_NOW)
setup->tm_mday = now.tm_mday;
/* make sure the setup is valid */
if (!is_valid_date(setup))
goto _exit;
}
break;
case RT_ALARM_WEEKLY:
{
/* if tm_wday is a "don't care" value we set it to now */
if ((setup->tm_wday < 0) || (setup->tm_wday > 6))
setup->tm_wday = now.tm_wday;
}
break;
case RT_ALARM_MONTHLY:
{
/* if tm_mday is a "don't care" value we set it to now */
if ((setup->tm_mday < 1) || (setup->tm_mday > 31))
setup->tm_mday = now.tm_mday;
}
break;
case RT_ALARM_YAERLY:
{
/* if tm_mon is a "don't care" value we set it to now */
if ((setup->tm_mon < 0) || (setup->tm_mon > 11))
setup->tm_mon = now.tm_mon;
if (setup->tm_mon == 1)
{
/* tm_mon is February */
/* tm_mday should be 1~29.otherwise,it's a "don't care" value */
if ((setup->tm_mday < 1) || (setup->tm_mday > 29))
setup->tm_mday = now.tm_mday;
}
else if (((setup->tm_mon <= 6) && (setup->tm_mon % 2 == 0)) || \
((setup->tm_mon > 6) && (setup->tm_mon % 2 == 1)))
{
/* Jan,Mar,May,Jul,Aug,Oct,Dec */
/* tm_mday should be 1~31.otherwise,it's a "don't care" value */
if ((setup->tm_mday < 1) || (setup->tm_mday > 31))
setup->tm_mday = now.tm_mday;
}
else
{
/* tm_mday should be 1~30.otherwise,it's a "don't care" value */
if ((setup->tm_mday < 1) || (setup->tm_mday > 30))
setup->tm_mday = now.tm_mday;
}
}
break;
default:
{
goto _exit;
}
}
if ((setup->tm_hour == 23) && (setup->tm_min == 59) && (setup->tm_sec == 59))
{
/*
for insurance purposes, we will generate an alarm
signal two seconds ahead of.
*/
setup->tm_sec = 60 - RT_ALARM_DELAY;
}
/* set initialized state */
alarm->flag |= RT_ALARM_STATE_INITED;
ret = RT_EOK;
_exit:
return (ret);
}
/** \brief send a rtc alarm event
*
* \param dev pointer to RTC device(currently unused,you can ignore it)
* \param event RTC event(currently unused)
* \return none
*/
void rt_alarm_update(rt_device_t dev, rt_uint32_t event)
{
rt_event_send(&_container.event, 1);
}
/** \brief modify the alarm setup
*
* \param alarm pointer to alarm
* \param cmd control command
* \param arg argument
*/
rt_err_t rt_alarm_control(rt_alarm_t alarm, int cmd, void *arg)
{
rt_err_t ret = -RT_ERROR;
RT_ASSERT(alarm != RT_NULL);
rt_mutex_take(&_container.mutex, RT_WAITING_FOREVER);
switch (cmd)
{
case RT_ALARM_CTRL_MODIFY:
{
struct rt_alarm_setup *setup;
RT_ASSERT(arg != RT_NULL);
setup = arg;
rt_alarm_stop(alarm);
alarm->flag = setup->flag & 0xFF00;
alarm->wktime = setup->wktime;
ret = alarm_setup(alarm, &alarm->wktime);
}
break;
}
rt_mutex_release(&_container.mutex);
return (ret);
}
/** \brief start an alarm
*
* \param alarm pointer to alarm
* \return RT_EOK
*/
rt_err_t rt_alarm_start(rt_alarm_t alarm)
{
rt_int32_t sec_now, sec_old, sec_new;
rt_err_t ret = RT_EOK;
time_t timestamp = (time_t)0;
struct tm now;
if (alarm == RT_NULL)
return (RT_ERROR);
rt_mutex_take(&_container.mutex, RT_WAITING_FOREVER);
if (!(alarm->flag & RT_ALARM_STATE_START))
{
if (alarm_setup(alarm, &alarm->wktime) != RT_EOK)
{
ret = -RT_ERROR;
goto _exit;
}
/* get time of now */
get_timestamp(&timestamp);
gmtime_r(&timestamp, &now);
alarm->flag |= RT_ALARM_STATE_START;
/* set alarm */
if (_container.current == RT_NULL)
{
ret = alarm_set(alarm);
}
else
{
sec_now = alarm_mkdaysec(&now);
sec_old = alarm_mkdaysec(&_container.current->wktime);
sec_new = alarm_mkdaysec(&alarm->wktime);
if ((sec_new < sec_old) && (sec_new > sec_now))
{
ret = alarm_set(alarm);
}
else if ((sec_new > sec_now) && (sec_old < sec_now))
{
ret = alarm_set(alarm);
}
else if ((sec_new < sec_old) && (sec_old < sec_now))
{
ret = alarm_set(alarm);
}
else
{
ret = RT_EOK;
goto _exit;
}
}
if (ret == RT_EOK)
{
_container.current = alarm;
}
}
_exit:
rt_mutex_release(&_container.mutex);
return (ret);
}
/** \brief stop an alarm
*
* \param alarm pointer to alarm
* \return RT_EOK
*/
rt_err_t rt_alarm_stop(rt_alarm_t alarm)
{
rt_err_t ret = RT_EOK;
if (alarm == RT_NULL)
return (RT_ERROR);
rt_mutex_take(&_container.mutex, RT_WAITING_FOREVER);
if (!(alarm->flag & RT_ALARM_STATE_START))
goto _exit;
/* stop alarm */
alarm->flag &= ~RT_ALARM_STATE_START;
if (_container.current == alarm)
{
ret = alarm_set(alarm);
_container.current = RT_NULL;
}
if (ret == RT_EOK)
alarm_update(0);
_exit:
rt_mutex_release(&_container.mutex);
return (ret);
}
/** \brief delete an alarm
*
* \param alarm pointer to alarm
* \return RT_EOK
*/
rt_err_t rt_alarm_delete(rt_alarm_t alarm)
{
rt_err_t ret = RT_EOK;
if (alarm == RT_NULL)
return -RT_ERROR;
rt_mutex_take(&_container.mutex, RT_WAITING_FOREVER);
/* stop the alarm */
alarm->flag &= ~RT_ALARM_STATE_START;
if (_container.current == alarm)
{
ret = alarm_set(alarm);
_container.current = RT_NULL;
/* set new alarm if necessary */
alarm_update(0);
}
rt_list_remove(&alarm->list);
rt_free(alarm);
rt_mutex_release(&_container.mutex);
return (ret);
}
/** \brief create an alarm
*
* \param flag set alarm mode e.g: RT_ALARM_DAILY
* \param setup pointer to setup infomation
*/
rt_alarm_t rt_alarm_create(rt_alarm_callback_t callback, struct rt_alarm_setup *setup)
{
struct rt_alarm *alarm;
if (setup == RT_NULL)
return (RT_NULL);
alarm = rt_malloc(sizeof(struct rt_alarm));
if (alarm == RT_NULL)
return (RT_NULL);
rt_list_init(&alarm->list);
alarm->wktime = setup->wktime;
alarm->flag = setup->flag & 0xFF00;
alarm->callback = callback;
rt_mutex_take(&_container.mutex, RT_WAITING_FOREVER);
rt_list_insert_after(&_container.head, &alarm->list);
rt_mutex_release(&_container.mutex);
return (alarm);
}
/** \brief rtc alarm service thread entry
*
*/
static void rt_alarmsvc_thread_init(void *param)
{
rt_uint32_t recv;
_container.current = RT_NULL;
while (1)
{
if (rt_event_recv(&_container.event, 0xFFFF,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER, &recv) == RT_EOK)
{
alarm_update(recv);
}
}
}
struct _alarm_flag
{
const char* name;
rt_uint32_t flag;
};
static const struct _alarm_flag _alarm_flag_tbl[] =
{
{"N", 0xffff}, /* none */
{"O", RT_ALARM_ONESHOT}, /* only alarm once */
{"D", RT_ALARM_DAILY}, /* alarm everyday */
{"W", RT_ALARM_WEEKLY}, /* alarm weekly at Monday or Friday etc. */
{"Mo", RT_ALARM_MONTHLY}, /* alarm monthly at someday */
{"Y", RT_ALARM_YAERLY}, /* alarm yearly at a certain date */
{"H", RT_ALARM_HOUR}, /* alarm each hour at a certain min:second */
{"M", RT_ALARM_MINUTE}, /* alarm each minute at a certain second */
{"S", RT_ALARM_SECOND}, /* alarm each second */
};
static rt_uint8_t _alarm_flag_tbl_size = sizeof(_alarm_flag_tbl) / sizeof(_alarm_flag_tbl[0]);
static rt_uint8_t get_alarm_flag_index(rt_uint32_t alarm_flag)
{
for (rt_uint8_t index = 0; index < _alarm_flag_tbl_size; index++)
{
alarm_flag &= 0xff00;
if (alarm_flag == _alarm_flag_tbl[index].flag)
{
return index;
}
}
return 0;
}
void rt_alarm_dump(void)
{
rt_list_t *next;
rt_alarm_t alarm;
rt_kprintf("| hh:mm:ss | week | flag | en |\n");
rt_kprintf("+----------+------+------+----+\n");
for (next = _container.head.next; next != &_container.head; next = next->next)
{
alarm = rt_list_entry(next, struct rt_alarm, list);
rt_uint8_t flag_index = get_alarm_flag_index(alarm->flag);
rt_kprintf("| %02d:%02d:%02d | %2d | %2s | %2d |\n",
alarm->wktime.tm_hour, alarm->wktime.tm_min, alarm->wktime.tm_sec,
alarm->wktime.tm_wday, _alarm_flag_tbl[flag_index].name, alarm->flag & RT_ALARM_STATE_START);
}
rt_kprintf("+----------+------+------+----+\n");
}
MSH_CMD_EXPORT_ALIAS(rt_alarm_dump, list_alarm, list alarm info);
/** \brief initialize alarm service system
*
* \param none
* \return none
*/
int rt_alarm_system_init(void)
{
rt_thread_t tid;
rt_list_init(&_container.head);
rt_event_init(&_container.event, "alarmsvc", RT_IPC_FLAG_FIFO);
rt_mutex_init(&_container.mutex, "alarmsvc", RT_IPC_FLAG_PRIO);
tid = rt_thread_create("alarmsvc",
rt_alarmsvc_thread_init, RT_NULL,
2048, 10, 5);
if (tid != RT_NULL)
rt_thread_startup(tid);
return 0;
}
INIT_PREV_EXPORT(rt_alarm_system_init);
#endif

View File

@@ -0,0 +1,375 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-01-29 aozima first version.
* 2012-04-12 aozima optimization: find rtc device only first.
* 2012-04-16 aozima add scheduler lock for set_date and set_time.
* 2018-02-16 armink add auto sync time by NTP
* 2021-05-09 Meco Man remove NTP
* 2021-06-11 iysheng implement RTC framework V2.0
* 2021-07-30 Meco Man move rtc_core.c to rtc.c
*/
#include <string.h>
#include <stdlib.h>
#include <rtthread.h>
#include <drivers/rtc.h>
#ifdef RT_USING_RTC
static rt_device_t _rtc_device;
/*
* This function initializes rtc_core
*/
static rt_err_t rt_rtc_init(struct rt_device *dev)
{
rt_rtc_dev_t *rtc_core;
RT_ASSERT(dev != RT_NULL);
rtc_core = (rt_rtc_dev_t *)dev;
if (rtc_core->ops->init)
{
return (rtc_core->ops->init());
}
return -RT_ENOSYS;
}
static rt_err_t rt_rtc_open(struct rt_device *dev, rt_uint16_t oflag)
{
return RT_EOK;
}
static rt_err_t rt_rtc_close(struct rt_device *dev)
{
/* Add close member function in rt_rtc_ops when need,
* then call that function here.
* */
return RT_EOK;
}
static rt_err_t rt_rtc_control(struct rt_device *dev, int cmd, void *args)
{
#define TRY_DO_RTC_FUNC(rt_rtc_dev, func_name, args) \
rt_rtc_dev->ops->func_name ? rt_rtc_dev->ops->func_name(args) : -RT_EINVAL;
rt_rtc_dev_t *rtc_device;
rt_err_t ret = -RT_EINVAL;
RT_ASSERT(dev != RT_NULL);
rtc_device = (rt_rtc_dev_t *)dev;
switch (cmd)
{
case RT_DEVICE_CTRL_RTC_GET_TIME:
ret = TRY_DO_RTC_FUNC(rtc_device, get_secs, args);
break;
case RT_DEVICE_CTRL_RTC_SET_TIME:
ret = TRY_DO_RTC_FUNC(rtc_device, set_secs, args);
break;
case RT_DEVICE_CTRL_RTC_GET_TIMEVAL:
ret = TRY_DO_RTC_FUNC(rtc_device, get_timeval, args);
break;
case RT_DEVICE_CTRL_RTC_SET_TIMEVAL:
ret = TRY_DO_RTC_FUNC(rtc_device, set_timeval, args);
break;
case RT_DEVICE_CTRL_RTC_GET_ALARM:
ret = TRY_DO_RTC_FUNC(rtc_device, get_alarm, args);
break;
case RT_DEVICE_CTRL_RTC_SET_ALARM:
ret = TRY_DO_RTC_FUNC(rtc_device, set_alarm, args);
break;
default:
break;
}
return ret;
#undef TRY_DO_RTC_FUNC
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops rtc_core_ops =
{
rt_rtc_init,
rt_rtc_open,
rt_rtc_close,
RT_NULL,
RT_NULL,
rt_rtc_control,
};
#endif /* RT_USING_DEVICE_OPS */
rt_err_t rt_hw_rtc_register(rt_rtc_dev_t *rtc,
const char *name,
rt_uint32_t flag,
void *data)
{
struct rt_device *device;
RT_ASSERT(rtc != RT_NULL);
device = &(rtc->parent);
device->type = RT_Device_Class_RTC;
device->rx_indicate = RT_NULL;
device->tx_complete = RT_NULL;
#ifdef RT_USING_DEVICE_OPS
device->ops = &rtc_core_ops;
#else
device->init = rt_rtc_init;
device->open = rt_rtc_open;
device->close = rt_rtc_close;
device->read = RT_NULL;
device->write = RT_NULL;
device->control = rt_rtc_control;
#endif /* RT_USING_DEVICE_OPS */
device->user_data = data;
/* register a character device */
return rt_device_register(device, name, flag);
}
/**
* Set system date(time not modify, local timezone).
*
* @param rt_uint32_t year e.g: 2012.
* @param rt_uint32_t month e.g: 12 (1~12).
* @param rt_uint32_t day e.g: 31.
*
* @return rt_err_t if set success, return RT_EOK.
*/
rt_err_t set_date(rt_uint32_t year, rt_uint32_t month, rt_uint32_t day)
{
time_t now, old_timestamp = 0;
struct tm tm_new = {0};
rt_err_t ret = -RT_ERROR;
if (_rtc_device == RT_NULL)
{
_rtc_device = rt_device_find("rtc");
if (_rtc_device == RT_NULL)
{
return -RT_ERROR;
}
}
/* get current time */
ret = rt_device_control(_rtc_device, RT_DEVICE_CTRL_RTC_GET_TIME, &old_timestamp);
if (ret != RT_EOK)
{
return ret;
}
/* converts calendar time into local time. */
localtime_r(&old_timestamp, &tm_new);
/* update date. */
tm_new.tm_year = year - 1900;
tm_new.tm_mon = month - 1; /* tm_mon: 0~11 */
tm_new.tm_mday = day;
/* converts the local time into the calendar time. */
now = mktime(&tm_new);
/* update to RTC device. */
ret = rt_device_control(_rtc_device, RT_DEVICE_CTRL_RTC_SET_TIME, &now);
return ret;
}
/**
* Set system time(date not modify, local timezone).
*
* @param rt_uint32_t hour e.g: 0~23.
* @param rt_uint32_t minute e.g: 0~59.
* @param rt_uint32_t second e.g: 0~59.
*
* @return rt_err_t if set success, return RT_EOK.
*/
rt_err_t set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second)
{
time_t now, old_timestamp = 0;
struct tm tm_new = {0};
rt_err_t ret = -RT_ERROR;
if (_rtc_device == RT_NULL)
{
_rtc_device = rt_device_find("rtc");
if (_rtc_device == RT_NULL)
{
return -RT_ERROR;
}
}
/* get current time */
ret = rt_device_control(_rtc_device, RT_DEVICE_CTRL_RTC_GET_TIME, &old_timestamp);
if (ret != RT_EOK)
{
return ret;
}
/* converts calendar time into local time. */
localtime_r(&old_timestamp, &tm_new);
/* update time. */
tm_new.tm_hour = hour;
tm_new.tm_min = minute;
tm_new.tm_sec = second;
/* converts the local time into the calendar time. */
now = mktime(&tm_new);
/* update to RTC device. */
ret = rt_device_control(_rtc_device, RT_DEVICE_CTRL_RTC_SET_TIME, &now);
return ret;
}
/**
* Set timestamp(UTC).
*
* @param time_t timestamp
*
* @return rt_err_t if set success, return RT_EOK.
*/
rt_err_t set_timestamp(time_t timestamp)
{
if (_rtc_device == RT_NULL)
{
_rtc_device = rt_device_find("rtc");
if (_rtc_device == RT_NULL)
{
return -RT_ERROR;
}
}
/* update to RTC device. */
return rt_device_control(_rtc_device, RT_DEVICE_CTRL_RTC_SET_TIME, &timestamp);
}
/**
* Get timestamp(UTC).
*
* @param time_t* timestamp
*
* @return rt_err_t if set success, return RT_EOK.
*/
rt_err_t get_timestamp(time_t *timestamp)
{
if (_rtc_device == RT_NULL)
{
_rtc_device = rt_device_find("rtc");
if (_rtc_device == RT_NULL)
{
return -RT_ERROR;
}
}
/* Get timestamp from RTC device. */
return rt_device_control(_rtc_device, RT_DEVICE_CTRL_RTC_GET_TIME, timestamp);
}
#ifdef RT_USING_FINSH
#include <finsh.h>
/**
* get date and time or set (local timezone) [year month day hour min sec]
*/
static void date(int argc, char **argv)
{
time_t now = (time_t)0;
if (argc == 1)
{
struct timeval tv = { 0 };
int32_t tz_offset_sec = 0;
uint32_t abs_tz_offset_sec = 0U;
#if defined(RT_LIBC_USING_LIGHT_TZ_DST)
tz_offset_sec = rt_tz_get();
#endif /* RT_LIBC_USING_LIGHT_TZ_DST */
gettimeofday(&tv, RT_NULL);
now = tv.tv_sec;
abs_tz_offset_sec = tz_offset_sec > 0 ? tz_offset_sec : -tz_offset_sec;
/* output current time */
rt_kprintf("local time: %.*s", 25U, ctime(&now));
rt_kprintf("timestamps: %ld\n", (long)tv.tv_sec);
rt_kprintf("timezone: UTC%c%02d:%02d:%02d\n",
tz_offset_sec > 0 ? '+' : '-', abs_tz_offset_sec / 3600U, abs_tz_offset_sec % 3600U / 60U, abs_tz_offset_sec % 3600U % 60U);
}
else if (argc >= 7)
{
/* set time and date */
struct tm tm_new = {0};
time_t old = (time_t)0;
rt_err_t err;
tm_new.tm_year = atoi(argv[1]) - 1900;
tm_new.tm_mon = atoi(argv[2]) - 1; /* .tm_min's range is [0-11] */
tm_new.tm_mday = atoi(argv[3]);
tm_new.tm_hour = atoi(argv[4]);
tm_new.tm_min = atoi(argv[5]);
tm_new.tm_sec = atoi(argv[6]);
if (tm_new.tm_year <= 0)
{
rt_kprintf("year is out of range [1900-]\n");
return;
}
if (tm_new.tm_mon > 11) /* .tm_min's range is [0-11] */
{
rt_kprintf("month is out of range [1-12]\n");
return;
}
if (tm_new.tm_mday == 0 || tm_new.tm_mday > 31)
{
rt_kprintf("day is out of range [1-31]\n");
return;
}
if (tm_new.tm_hour > 23)
{
rt_kprintf("hour is out of range [0-23]\n");
return;
}
if (tm_new.tm_min > 59)
{
rt_kprintf("minute is out of range [0-59]\n");
return;
}
if (tm_new.tm_sec > 60)
{
rt_kprintf("second is out of range [0-60]\n");
return;
}
/* save old timestamp */
err = get_timestamp(&old);
if (err != RT_EOK)
{
rt_kprintf("Get current timestamp failed. %d\n", err);
return;
}
/* converts the local time into the calendar time. */
now = mktime(&tm_new);
err = set_timestamp(now);
if (err != RT_EOK)
{
rt_kprintf("set date failed. %d\n", err);
return;
}
get_timestamp(&now); /* get new timestamp */
rt_kprintf("old: %.*s", 25, ctime(&old));
rt_kprintf("now: %.*s", 25, ctime(&now));
}
else
{
rt_kprintf("please input: date [year month day hour min sec] or date\n");
rt_kprintf("e.g: date 2018 01 01 23 59 59 or date\n");
}
}
MSH_CMD_EXPORT(date, get date and time or set (local timezone) [year month day hour min sec])
#endif /* RT_USING_FINSH */
#endif /* RT_USING_RTC */

View File

@@ -0,0 +1,325 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-01-30 armink the first version
*/
#include <sys/time.h>
#include <string.h>
#include <rtthread.h>
#include <rtdevice.h>
#ifdef RT_USING_KTIME
#include <ktime.h>
#endif
#ifdef RT_USING_SOFT_RTC
/* 2018-01-30 14:44:50 = RTC_TIME_INIT(2018, 1, 30, 14, 44, 50) */
#define RTC_TIME_INIT(year, month, day, hour, minute, second) \
{.tm_year = year - 1900, .tm_mon = month - 1, .tm_mday = day, .tm_hour = hour, .tm_min = minute, .tm_sec = second}
#ifndef SOFT_RTC_TIME_DEFAULT
#define SOFT_RTC_TIME_DEFAULT RTC_TIME_INIT(2018, 1, 1, 0, 0 ,0)
#endif
#ifndef RTC_AUTO_SYNC_FIRST_DELAY
#define RTC_AUTO_SYNC_FIRST_DELAY 25
#endif
#ifndef RTC_AUTO_SYNC_PERIOD
#define RTC_AUTO_SYNC_PERIOD 3600
#endif
static struct rt_work rtc_sync_work;
static rt_device_t source_device = RT_NULL;
static struct rt_device soft_rtc_dev;
static rt_tick_t init_tick;
static time_t init_time;
static struct timeval init_tv = {0};
#ifdef RT_USING_KTIME
static struct timespec init_ts = {0};
#endif
#ifdef RT_USING_ALARM
static struct rt_rtc_wkalarm wkalarm;
static struct rt_timer alarm_time;
static void alarm_timeout(void *param)
{
rt_alarm_update(param, 1);
}
static void soft_rtc_alarm_update(struct rt_rtc_wkalarm *palarm)
{
rt_tick_t next_tick;
if (palarm->enable)
{
next_tick = RT_TICK_PER_SECOND;
rt_timer_control(&alarm_time, RT_TIMER_CTRL_SET_TIME, &next_tick);
rt_timer_start(&alarm_time);
}
else
{
rt_timer_stop(&alarm_time);
}
}
#endif
static void set_rtc_time(time_t t)
{
init_time = t - (rt_tick_get() - init_tick) / RT_TICK_PER_SECOND;
#ifdef RT_USING_ALARM
soft_rtc_alarm_update(&wkalarm);
#endif
}
static void _source_device_control(int cmd, void *args)
{
if (source_device == RT_NULL)
return;
if (rt_device_open(source_device, 0) == RT_EOK)
{
rt_device_control(source_device, cmd, args);
rt_device_close(source_device);
}
}
static rt_err_t soft_rtc_control(rt_device_t dev, int cmd, void *args)
{
time_t *t;
struct tm time_temp;
RT_ASSERT(dev != RT_NULL);
rt_memset(&time_temp, 0, sizeof(struct tm));
switch (cmd)
{
case RT_DEVICE_CTRL_RTC_GET_TIME:
{
t = (time_t *) args;
*t = init_time + (rt_tick_get() - init_tick) / RT_TICK_PER_SECOND;
break;
}
case RT_DEVICE_CTRL_RTC_SET_TIME:
{
t = (time_t *) args;
set_rtc_time(*t);
_source_device_control(RT_DEVICE_CTRL_RTC_SET_TIME, t);
break;
}
#ifdef RT_USING_ALARM
case RT_DEVICE_CTRL_RTC_GET_ALARM:
*((struct rt_rtc_wkalarm *)args) = wkalarm;
break;
case RT_DEVICE_CTRL_RTC_SET_ALARM:
wkalarm = *((struct rt_rtc_wkalarm *)args);
soft_rtc_alarm_update(&wkalarm);
break;
#endif
#ifdef RT_USING_KTIME
case RT_DEVICE_CTRL_RTC_GET_TIMEVAL:
{
struct timeval _tv;
struct timeval *tv = (struct timeval *)args;
rt_ktime_boottime_get_us(&_tv);
tv->tv_sec = init_time + _tv.tv_sec;
tv->tv_usec = init_tv.tv_usec + _tv.tv_usec;
break;
}
case RT_DEVICE_CTRL_RTC_SET_TIMEVAL:
{
struct timeval _tv;
struct timeval *tv = (struct timeval *)args;
rt_ktime_boottime_get_us(&_tv);
set_rtc_time(tv->tv_sec);
init_tv.tv_usec = tv->tv_usec - _tv.tv_usec;
_source_device_control(RT_DEVICE_CTRL_RTC_SET_TIME, &(tv->tv_sec));
break;
}
case RT_DEVICE_CTRL_RTC_GET_TIMESPEC:
{
struct timespec _ts;
struct timespec *ts = (struct timespec *)args;
rt_ktime_boottime_get_ns(&_ts);
ts->tv_sec = init_time + _ts.tv_sec;
ts->tv_nsec = init_ts.tv_nsec + _ts.tv_nsec;
break;
}
case RT_DEVICE_CTRL_RTC_SET_TIMESPEC:
{
struct timespec _ts;
struct timespec *ts = (struct timespec *)args;
rt_ktime_boottime_get_ns(&_ts);
set_rtc_time(ts->tv_sec);
init_ts.tv_nsec = ts->tv_nsec - _ts.tv_nsec;
_source_device_control(RT_DEVICE_CTRL_RTC_SET_TIME, &(ts->tv_sec));
break;
}
case RT_DEVICE_CTRL_RTC_GET_TIMERES:
{
struct timespec *ts = (struct timespec *)args;
ts->tv_sec = 0;
ts->tv_nsec = (rt_ktime_cputimer_getres() / RT_KTIME_RESMUL);
break;
}
#else
case RT_DEVICE_CTRL_RTC_GET_TIMEVAL:
{
struct timeval *tv = (struct timeval *)args;
rt_tick_t tick = rt_tick_get() - init_tick;
tv->tv_sec = init_time + tick / RT_TICK_PER_SECOND;
tv->tv_usec = init_tv.tv_usec + ((tick % RT_TICK_PER_SECOND) * (1000000 / RT_TICK_PER_SECOND));
break;
}
case RT_DEVICE_CTRL_RTC_SET_TIMEVAL:
{
struct timeval *tv = (struct timeval *)args;
rt_tick_t tick = rt_tick_get() - init_tick;
set_rtc_time(tv->tv_sec);
init_tv.tv_usec = tv->tv_usec - ((tick % RT_TICK_PER_SECOND) * (1000000 / RT_TICK_PER_SECOND));
_source_device_control(RT_DEVICE_CTRL_RTC_SET_TIME, &(tv->tv_sec));
break;
}
case RT_DEVICE_CTRL_RTC_GET_TIMERES:
{
struct timespec *ts = (struct timespec *)args;
ts->tv_sec = 0;
ts->tv_nsec = (1000UL * 1000 * 1000) / RT_TICK_PER_SECOND;
break;
}
#endif /* RT_USING_KTIME */
default:
return -RT_EINVAL;
}
return RT_EOK;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops soft_rtc_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
soft_rtc_control
};
#endif
static int rt_soft_rtc_init(void)
{
static rt_bool_t init_ok = RT_FALSE;
struct tm time_new = SOFT_RTC_TIME_DEFAULT;
if (init_ok)
{
return 0;
}
/* make sure only one 'rtc' device */
RT_ASSERT(!rt_device_find("rtc"));
#ifdef RT_USING_ALARM
rt_timer_init(&alarm_time,
"alarm",
alarm_timeout,
&soft_rtc_dev,
0,
RT_TIMER_FLAG_SOFT_TIMER|RT_TIMER_FLAG_ONE_SHOT);
#endif
init_tick = rt_tick_get();
init_time = timegm(&time_new);
soft_rtc_dev.type = RT_Device_Class_RTC;
/* register rtc device */
#ifdef RT_USING_DEVICE_OPS
soft_rtc_dev.ops = &soft_rtc_ops;
#else
soft_rtc_dev.init = RT_NULL;
soft_rtc_dev.open = RT_NULL;
soft_rtc_dev.close = RT_NULL;
soft_rtc_dev.read = RT_NULL;
soft_rtc_dev.write = RT_NULL;
soft_rtc_dev.control = soft_rtc_control;
#endif
/* no private */
soft_rtc_dev.user_data = RT_NULL;
rt_device_register(&soft_rtc_dev, "rtc", RT_DEVICE_FLAG_RDWR);
init_ok = RT_TRUE;
return 0;
}
INIT_DEVICE_EXPORT(rt_soft_rtc_init);
#ifdef RT_USING_SYSTEM_WORKQUEUE
rt_err_t rt_soft_rtc_sync(void)
{
time_t time = 0;
if (source_device == RT_NULL)
{
rt_kprintf("error: rtc source not found, please set it!!!\n");
return RT_ENOSYS;
}
_source_device_control(RT_DEVICE_CTRL_RTC_GET_TIME, &time);
set_rtc_time(time);
return RT_EOK;
}
static void rtc_sync_work_func(struct rt_work *work, void *work_data)
{
rt_soft_rtc_sync();
rt_work_submit(work, rt_tick_from_millisecond(RTC_AUTO_SYNC_PERIOD * 1000));
}
rt_err_t rt_soft_rtc_set_source(const char *name)
{
RT_ASSERT(name != RT_NULL);
RT_ASSERT(rt_device_find(name)); // make sure source is exist
source_device = rt_device_find(name);
rt_work_init(&rtc_sync_work, rtc_sync_work_func, RT_NULL);
rt_work_submit(&rtc_sync_work, rt_tick_from_millisecond(RTC_AUTO_SYNC_FIRST_DELAY * 1000));
return RT_EOK;
}
#ifdef FINSH_USING_MSH
#include <finsh.h>
static void cmd_rtc_sync(int argc, char **argv)
{
struct timeval tv = {0};
struct timezone tz = {0};
time_t now = (time_t)0;
rt_soft_rtc_sync();
gettimeofday(&tv, &tz);
now = tv.tv_sec;
/* output current time */
rt_kprintf("local time: %.*s", 25, ctime(&now));
rt_kprintf("timestamps: %ld\n", (long)tv.tv_sec);
}
MSH_CMD_EXPORT_ALIAS(cmd_rtc_sync, rtc_sync, Update time by real rtc);
#endif
#endif /* RT_USING_SYSTEM_WORKQUEUE */
#endif /* RT_USING_SOFT_RTC */

View File

@@ -0,0 +1,952 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-07-25 weety first version
*/
#include <rtthread.h>
#include <dfs_fs.h>
#include <dfs_file.h>
#include <drivers/mmcsd_core.h>
#include <drivers/gpt.h>
#define DBG_TAG "SDIO"
#ifdef RT_SDIO_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif /* RT_SDIO_DEBUG */
#include <rtdbg.h>
static rt_list_t blk_devices = RT_LIST_OBJECT_INIT(blk_devices);
#define BLK_MIN(a, b) ((a) < (b) ? (a) : (b))
#define RT_DEVICE_CTRL_BLK_SSIZEGET 0x1268 /**< get number of bytes per sector */
#define RT_DEVICE_CTRL_ALL_BLK_SSIZEGET 0x80081272 /**< get number of bytes per sector * sector counts*/
struct mmcsd_blk_device
{
struct rt_mmcsd_card *card;
rt_list_t list;
struct rt_device dev;
struct dfs_partition part;
struct rt_device_blk_geometry geometry;
rt_size_t max_req_size;
};
#ifndef RT_MMCSD_MAX_PARTITION
#define RT_MMCSD_MAX_PARTITION 16
#endif
#define RT_GPT_PARTITION_MAX 128
static int __send_status(struct rt_mmcsd_card *card, rt_uint32_t *status, unsigned retries)
{
int err;
struct rt_mmcsd_cmd cmd;
cmd.busy_timeout = 0;
cmd.cmd_code = SEND_STATUS;
cmd.arg = card->rca << 16;
cmd.flags = RESP_R1 | CMD_AC;
err = mmcsd_send_cmd(card->host, &cmd, retries);
if (err)
return err;
if (status)
*status = cmd.resp[0];
return 0;
}
static int card_busy_detect(struct rt_mmcsd_card *card, unsigned int timeout_ms,
rt_uint32_t *resp_errs)
{
int timeout = rt_tick_from_millisecond(timeout_ms);
int err = 0;
rt_uint32_t status;
rt_tick_t start;
start = rt_tick_get();
do
{
rt_bool_t out = (int)(rt_tick_get() - start) > timeout;
err = __send_status(card, &status, 5);
if (err)
{
LOG_E("error %d requesting status", err);
return err;
}
/* Accumulate any response error bits seen */
if (resp_errs)
*resp_errs |= status;
if (out)
{
LOG_E("wait card busy timeout");
return -RT_ETIMEOUT;
}
/*
* Some cards mishandle the status bits,
* so make sure to check both the busy
* indication and the card state.
*/
}
while (!(status & R1_READY_FOR_DATA) ||
(R1_CURRENT_STATE(status) == 7));
return err;
}
rt_int32_t mmcsd_num_wr_blocks(struct rt_mmcsd_card *card)
{
rt_int32_t err;
rt_uint32_t blocks;
struct rt_mmcsd_req req;
struct rt_mmcsd_cmd cmd;
struct rt_mmcsd_data data;
rt_uint32_t timeout_us;
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = APP_CMD;
cmd.arg = card->rca << 16;
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_AC;
err = mmcsd_send_cmd(card->host, &cmd, 0);
if (err)
return -RT_ERROR;
if (!controller_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
return -RT_ERROR;
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = SD_APP_SEND_NUM_WR_BLKS;
cmd.arg = 0;
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
data.timeout_ns = card->tacc_ns * 100;
data.timeout_clks = card->tacc_clks * 100;
timeout_us = data.timeout_ns / 1000;
timeout_us += data.timeout_clks * 1000 /
(card->host->io_cfg.clock / 1000);
if (timeout_us > 100000)
{
data.timeout_ns = 100000000;
data.timeout_clks = 0;
}
data.blksize = 4;
data.blks = 1;
data.flags = DATA_DIR_READ;
data.buf = &blocks;
rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
req.cmd = &cmd;
req.data = &data;
mmcsd_send_request(card->host, &req);
if (cmd.err || data.err)
return -RT_ERROR;
return blocks;
}
static rt_err_t rt_mmcsd_req_blk(struct rt_mmcsd_card *card,
rt_uint32_t sector,
void *buf,
rt_size_t blks,
rt_uint8_t dir)
{
struct rt_mmcsd_cmd cmd, stop;
struct rt_mmcsd_data data;
struct rt_mmcsd_req req;
struct rt_mmcsd_host *host = card->host;
rt_uint32_t r_cmd, w_cmd;
mmcsd_host_lock(host);
rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
rt_memset(&stop, 0, sizeof(struct rt_mmcsd_cmd));
rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
req.cmd = &cmd;
req.data = &data;
cmd.arg = sector;
if (!(card->flags & CARD_FLAG_SDHC))
{
cmd.arg <<= 9;
}
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
data.blksize = SECTOR_SIZE;
data.blks = blks;
if (blks > 1)
{
if (!controller_is_spi(card->host) || !dir)
{
req.stop = &stop;
stop.cmd_code = STOP_TRANSMISSION;
stop.arg = 0;
stop.flags = RESP_SPI_R1B | RESP_R1B | CMD_AC;
}
r_cmd = READ_MULTIPLE_BLOCK;
w_cmd = WRITE_MULTIPLE_BLOCK;
}
else
{
req.stop = RT_NULL;
r_cmd = READ_SINGLE_BLOCK;
w_cmd = WRITE_BLOCK;
}
if (!controller_is_spi(card->host) && (card->flags & 0x8000))
{
/* last request is WRITE,need check busy */
card_busy_detect(card, 10000, RT_NULL);
}
if (!dir)
{
cmd.cmd_code = r_cmd;
data.flags |= DATA_DIR_READ;
card->flags &= 0x7fff;
}
else
{
cmd.cmd_code = w_cmd;
data.flags |= DATA_DIR_WRITE;
card->flags |= 0x8000;
}
mmcsd_set_data_timeout(&data, card);
data.buf = buf;
mmcsd_send_request(host, &req);
mmcsd_host_unlock(host);
if (cmd.err || data.err || stop.err)
{
LOG_E("mmcsd request blocks error");
LOG_E("%d,%d,%d, 0x%08x,0x%08x",
cmd.err, data.err, stop.err, data.flags, sector);
return -RT_ERROR;
}
return RT_EOK;
}
static rt_err_t rt_mmcsd_init(rt_device_t dev)
{
return RT_EOK;
}
static rt_err_t rt_mmcsd_open(rt_device_t dev, rt_uint16_t oflag)
{
return RT_EOK;
}
static rt_err_t rt_mmcsd_close(rt_device_t dev)
{
return RT_EOK;
}
static rt_err_t rt_mmcsd_control(rt_device_t dev, int cmd, void *args)
{
struct mmcsd_blk_device *blk_dev = (struct mmcsd_blk_device *)dev->user_data;
switch (cmd)
{
case RT_DEVICE_CTRL_BLK_GETGEOME:
rt_memcpy(args, &blk_dev->geometry, sizeof(struct rt_device_blk_geometry));
break;
case RT_DEVICE_CTRL_BLK_PARTITION:
rt_memcpy(args, &blk_dev->part, sizeof(struct dfs_partition));
break;
case RT_DEVICE_CTRL_BLK_SSIZEGET:
rt_memcpy(args, &blk_dev->geometry.bytes_per_sector, sizeof(rt_uint32_t));
break;
case RT_DEVICE_CTRL_ALL_BLK_SSIZEGET:
{
rt_uint64_t count_mul_per = blk_dev->geometry.bytes_per_sector * blk_dev->geometry.sector_count;
rt_memcpy(args, &count_mul_per, sizeof(rt_uint64_t));
}
break;
default:
break;
}
return RT_EOK;
}
static rt_ssize_t rt_mmcsd_read(rt_device_t dev,
rt_off_t pos,
void *buffer,
rt_size_t size)
{
rt_err_t err = 0;
rt_size_t offset = 0;
rt_size_t req_size = 0;
rt_size_t remain_size = size;
void *rd_ptr = (void *)buffer;
struct mmcsd_blk_device *blk_dev = (struct mmcsd_blk_device *)dev->user_data;
struct dfs_partition *part = &blk_dev->part;
if (dev == RT_NULL)
{
rt_set_errno(-EINVAL);
return 0;
}
rt_sem_take(part->lock, RT_WAITING_FOREVER);
while (remain_size)
{
req_size = (remain_size > blk_dev->max_req_size) ? blk_dev->max_req_size : remain_size;
err = rt_mmcsd_req_blk(blk_dev->card, part->offset + pos + offset, rd_ptr, req_size, 0);
if (err)
break;
offset += req_size;
rd_ptr = (void *)((rt_uint8_t *)rd_ptr + (req_size << 9));
remain_size -= req_size;
}
rt_sem_release(part->lock);
/* the length of reading must align to SECTOR SIZE */
if (err)
{
rt_set_errno(-EIO);
return 0;
}
return size - remain_size;
}
static rt_ssize_t rt_mmcsd_write(rt_device_t dev,
rt_off_t pos,
const void *buffer,
rt_size_t size)
{
rt_err_t err = 0;
rt_size_t offset = 0;
rt_size_t req_size = 0;
rt_size_t remain_size = size;
void *wr_ptr = (void *)buffer;
struct mmcsd_blk_device *blk_dev = (struct mmcsd_blk_device *)dev->user_data;
struct dfs_partition *part = &blk_dev->part;
if (dev == RT_NULL)
{
rt_set_errno(-EINVAL);
return 0;
}
rt_sem_take(part->lock, RT_WAITING_FOREVER);
while (remain_size)
{
req_size = (remain_size > blk_dev->max_req_size) ? blk_dev->max_req_size : remain_size;
err = rt_mmcsd_req_blk(blk_dev->card, part->offset + pos + offset, wr_ptr, req_size, 1);
if (err)
break;
offset += req_size;
wr_ptr = (void *)((rt_uint8_t *)wr_ptr + (req_size << 9));
remain_size -= req_size;
}
rt_sem_release(part->lock);
/* the length of reading must align to SECTOR SIZE */
if (err)
{
rt_set_errno(-EIO);
return 0;
}
return size - remain_size;
}
static rt_int32_t mmcsd_set_blksize(struct rt_mmcsd_card *card)
{
struct rt_mmcsd_cmd cmd;
int err;
/* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
if (card->flags & CARD_FLAG_SDHC)
return 0;
mmcsd_host_lock(card->host);
cmd.cmd_code = SET_BLOCKLEN;
cmd.arg = 512;
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_AC;
err = mmcsd_send_cmd(card->host, &cmd, 5);
mmcsd_host_unlock(card->host);
if (err)
{
LOG_E("MMCSD: unable to set block size to %d: %d", cmd.arg, err);
return -RT_ERROR;
}
return 0;
}
rt_int32_t read_lba(struct rt_mmcsd_card *card, size_t lba, uint8_t *buffer, size_t count)
{
rt_uint8_t status = 0;
status = mmcsd_set_blksize(card);
if (status)
{
return status;
}
rt_thread_mdelay(1);
status = rt_mmcsd_req_blk(card, lba, buffer, count, 0);
return status;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops mmcsd_blk_ops =
{
rt_mmcsd_init,
rt_mmcsd_open,
rt_mmcsd_close,
rt_mmcsd_read,
rt_mmcsd_write,
rt_mmcsd_control
};
#endif
#ifdef RT_USING_DFS_V2
static ssize_t rt_mmcsd_fops_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
{
int result = 0;
rt_device_t dev = (rt_device_t)file->vnode->data;
struct mmcsd_blk_device *blk_dev = (struct mmcsd_blk_device *)dev->user_data;
int bytes_per_sector = blk_dev->geometry.bytes_per_sector;
int blk_pos = *pos / bytes_per_sector;
int first_offs = *pos % bytes_per_sector;
char *rbuf;
int rsize = 0;
rbuf = rt_malloc(bytes_per_sector);
if (!rbuf)
{
return 0;
}
/*
** #1: read first unalign block size.
*/
result = rt_mmcsd_read(dev, blk_pos, rbuf, 1);
if (result != 1)
{
rt_free(rbuf);
return 0;
}
if (count > bytes_per_sector - first_offs)
{
rsize = bytes_per_sector - first_offs;
}
else
{
rsize = count;
}
rt_memcpy(buf, rbuf + first_offs, rsize);
blk_pos++;
/*
** #2: read continuous block size.
*/
while (rsize < count)
{
result = rt_mmcsd_read(dev, blk_pos++, rbuf, 1);
if (result != 1)
{
break;
}
if (count - rsize >= bytes_per_sector)
{
rt_memcpy(buf + rsize, rbuf, bytes_per_sector);
rsize += bytes_per_sector;
}
else
{
rt_memcpy(buf + rsize, rbuf, count - rsize);
rsize = count;
}
}
rt_free(rbuf);
*pos += rsize;
return rsize;
}
static int rt_mmcsd_fops_ioctl(struct dfs_file *file, int cmd, void *arg)
{
rt_device_t dev = (rt_device_t)file->vnode->data;
return rt_mmcsd_control(dev,cmd,arg);
}
static int rt_mmcsd_fops_open(struct dfs_file *file)
{
rt_device_t dev = (rt_device_t)file->vnode->data;
rt_mmcsd_control(dev, RT_DEVICE_CTRL_ALL_BLK_SSIZEGET, &file->vnode->size);
return RT_EOK;
}
static int rt_mmcsd_fops_close(struct dfs_file *file)
{
return RT_EOK;
}
static ssize_t rt_mmcsd_fops_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos)
{
int result = 0;
rt_device_t dev = (rt_device_t)file->vnode->data;
struct mmcsd_blk_device *blk_dev = (struct mmcsd_blk_device *)dev->user_data;
int bytes_per_sector = blk_dev->geometry.bytes_per_sector;
int blk_pos = *pos / bytes_per_sector;
int first_offs = *pos % bytes_per_sector;
char *rbuf = 0;
int wsize = 0;
/*
** #1: write first unalign block size.
*/
if (first_offs != 0)
{
if (count > bytes_per_sector - first_offs)
{
wsize = bytes_per_sector - first_offs;
}
else
{
wsize = count;
}
rbuf = rt_malloc(bytes_per_sector);
if (!rbuf)
{
return 0;
}
result = rt_mmcsd_read(dev, blk_pos, rbuf, 1);
if (result != 1)
{
rt_free(rbuf);
return 0;
}
rt_memcpy(rbuf + first_offs, buf, wsize);
result = rt_mmcsd_write(dev, blk_pos, rbuf, 1);
if (result != 1)
{
rt_free(rbuf);
return 0;
}
rt_free(rbuf);
blk_pos += 1;
}
/*
** #2: write continuous block size.
*/
if ((count - wsize) / bytes_per_sector != 0)
{
result = rt_mmcsd_write(dev, blk_pos, buf + wsize, (count - wsize) / bytes_per_sector);
wsize += result * bytes_per_sector;
blk_pos += result;
if (result != (count - wsize) / bytes_per_sector)
{
*pos += wsize;
return wsize;
}
}
/*
** # 3: write last unalign block size.
*/
if ((count - wsize) != 0)
{
rbuf = rt_malloc(bytes_per_sector);
if (rbuf != RT_NULL)
{
result = rt_mmcsd_read(dev, blk_pos, rbuf, 1);
if (result == 1)
{
rt_memcpy(rbuf, buf + wsize, count - wsize);
result = rt_mmcsd_write(dev, blk_pos, rbuf, 1);
if (result == 1)
{
wsize += count - wsize;
}
}
rt_free(rbuf);
}
}
*pos += wsize;
return wsize;
}
static int rt_mmcsd_fops_poll(struct dfs_file *file, struct rt_pollreq *req)
{
int mask = 0;
return mask;
}
static int rt_mmcsd_fops_flush(struct dfs_file *file)
{
return RT_EOK;
}
const static struct dfs_file_ops mmcsd_blk_fops =
{
rt_mmcsd_fops_open,
rt_mmcsd_fops_close,
rt_mmcsd_fops_ioctl,
rt_mmcsd_fops_read,
rt_mmcsd_fops_write,
rt_mmcsd_fops_flush,
generic_dfs_lseek,
RT_NULL,
RT_NULL,
rt_mmcsd_fops_poll
};
#endif
rt_int32_t gpt_device_probe(struct rt_mmcsd_card *card)
{
rt_int32_t err = RT_EOK;
rt_uint8_t i, status;
char dname[10];
char sname[16];
struct mmcsd_blk_device *blk_dev = RT_NULL;
blk_dev = rt_calloc(1, sizeof(struct mmcsd_blk_device));
if (!blk_dev)
{
LOG_E("mmcsd:malloc memory failed!");
return -1;
}
blk_dev->max_req_size = BLK_MIN((card->host->max_dma_segs *
card->host->max_seg_size) >> 9,
(card->host->max_blk_count *
card->host->max_blk_size) >> 9);
blk_dev->part.offset = 0;
blk_dev->part.size = 0;
rt_snprintf(sname, sizeof(sname) - 1, "sem_%s%d", card->host->name, 0);
blk_dev->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
/* register mmcsd device */
blk_dev->dev.type = RT_Device_Class_Block;
#ifdef RT_USING_DEVICE_OPS
blk_dev->dev.ops = &mmcsd_blk_ops;
#else
blk_dev->dev.init = rt_mmcsd_init;
blk_dev->dev.open = rt_mmcsd_open;
blk_dev->dev.close = rt_mmcsd_close;
blk_dev->dev.read = rt_mmcsd_read;
blk_dev->dev.write = rt_mmcsd_write;
blk_dev->dev.control = rt_mmcsd_control;
#endif
blk_dev->card = card;
blk_dev->geometry.bytes_per_sector = 1 << 9;
blk_dev->geometry.block_size = card->card_blksize;
blk_dev->geometry.sector_count =
card->card_capacity * (1024 / 512);
blk_dev->dev.user_data = blk_dev;
rt_device_register(&(blk_dev->dev), card->host->name,
RT_DEVICE_FLAG_RDWR);
#ifdef RT_USING_POSIX_DEVIO
#ifdef RT_USING_DFS_V2
blk_dev->dev.fops = &mmcsd_blk_fops;
#endif
#endif
rt_list_insert_after(&blk_devices, &blk_dev->list);
for (i = 0; i < RT_GPT_PARTITION_MAX; i++)
{
blk_dev = rt_calloc(1, sizeof(struct mmcsd_blk_device));
if (!blk_dev)
{
LOG_E("mmcsd:malloc memory failed!");
break;
}
blk_dev->max_req_size = BLK_MIN((card->host->max_dma_segs *
card->host->max_seg_size) >> 9,
(card->host->max_blk_count *
card->host->max_blk_size) >> 9);
/* get the first partition */
status = gpt_get_partition_param(card, &blk_dev->part, i);
if (status == RT_EOK)
{
rt_snprintf(dname, sizeof(dname) - 1, "%s%d", card->host->name, i);
rt_snprintf(sname, sizeof(sname) - 1, "sem_%s%d", card->host->name, i + 1);
blk_dev->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
/* register mmcsd device */
blk_dev->dev.type = RT_Device_Class_Block;
#ifdef RT_USING_DEVICE_OPS
blk_dev->dev.ops = &mmcsd_blk_ops;
#else
blk_dev->dev.init = rt_mmcsd_init;
blk_dev->dev.open = rt_mmcsd_open;
blk_dev->dev.close = rt_mmcsd_close;
blk_dev->dev.read = rt_mmcsd_read;
blk_dev->dev.write = rt_mmcsd_write;
blk_dev->dev.control = rt_mmcsd_control;
#endif
blk_dev->card = card;
blk_dev->geometry.bytes_per_sector = 1 << 9;
blk_dev->geometry.block_size = card->card_blksize;
blk_dev->geometry.sector_count = blk_dev->part.size;
blk_dev->dev.user_data = blk_dev;
rt_device_register(&(blk_dev->dev), dname,
RT_DEVICE_FLAG_RDWR);
#ifdef RT_USING_POSIX_DEVIO
#ifdef RT_USING_DFS_V2
blk_dev->dev.fops = &mmcsd_blk_fops;
#endif
#endif
rt_list_insert_after(&blk_devices, &blk_dev->list);
}
else
{
rt_free(blk_dev);
blk_dev = RT_NULL;
break;
}
#ifdef RT_USING_DFS_MNTTABLE
if (blk_dev)
{
LOG_I("try to mount file system!");
/* try to mount file system on this block device */
dfs_mount_device(&(blk_dev->dev));
}
#endif
}
gpt_free();
return err;
}
rt_int32_t mbr_device_probe(struct rt_mmcsd_card *card)
{
rt_int32_t err = 0;
rt_uint8_t i, status;
rt_uint8_t *sector;
char dname[10];
char sname[16];
struct mmcsd_blk_device *blk_dev = RT_NULL;
err = mmcsd_set_blksize(card);
if (err)
{
return err;
}
rt_thread_mdelay(1);
/* get the first sector to read partition table */
sector = (rt_uint8_t *)rt_malloc(SECTOR_SIZE);
if (sector == RT_NULL)
{
LOG_E("allocate partition sector buffer failed!");
return -RT_ENOMEM;
}
status = rt_mmcsd_req_blk(card, 0, sector, 1, 0);
if (status == RT_EOK)
{
blk_dev = rt_calloc(1, sizeof(struct mmcsd_blk_device));
if (!blk_dev)
{
LOG_E("mmcsd:malloc memory failed!");
return -1;
}
blk_dev->max_req_size = BLK_MIN((card->host->max_dma_segs *
card->host->max_seg_size) >> 9,
(card->host->max_blk_count *
card->host->max_blk_size) >> 9);
blk_dev->part.offset = 0;
blk_dev->part.size = 0;
rt_snprintf(sname, sizeof(sname) - 1, "sem_%s%d", card->host->name, 0);
blk_dev->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
/* register mmcsd device */
blk_dev->dev.type = RT_Device_Class_Block;
#ifdef RT_USING_DEVICE_OPS
blk_dev->dev.ops = &mmcsd_blk_ops;
#else
blk_dev->dev.init = rt_mmcsd_init;
blk_dev->dev.open = rt_mmcsd_open;
blk_dev->dev.close = rt_mmcsd_close;
blk_dev->dev.read = rt_mmcsd_read;
blk_dev->dev.write = rt_mmcsd_write;
blk_dev->dev.control = rt_mmcsd_control;
#endif
blk_dev->card = card;
blk_dev->geometry.bytes_per_sector = 1 << 9;
blk_dev->geometry.block_size = card->card_blksize;
blk_dev->geometry.sector_count =
card->card_capacity * (1024 / 512);
blk_dev->dev.user_data = blk_dev;
rt_device_register(&(blk_dev->dev), card->host->name,
RT_DEVICE_FLAG_RDWR);
rt_list_insert_after(&blk_devices, &blk_dev->list);
for (i = 0; i < RT_MMCSD_MAX_PARTITION; i++)
{
blk_dev = rt_calloc(1, sizeof(struct mmcsd_blk_device));
if (!blk_dev)
{
LOG_E("mmcsd:malloc memory failed!");
break;
}
blk_dev->max_req_size = BLK_MIN((card->host->max_dma_segs *
card->host->max_seg_size) >> 9,
(card->host->max_blk_count *
card->host->max_blk_size) >> 9);
/* get the first partition */
status = dfs_filesystem_get_partition(&blk_dev->part, sector, i);
if (status == RT_EOK)
{
rt_snprintf(dname, sizeof(dname) - 1, "%s%d", card->host->name, i);
rt_snprintf(sname, sizeof(sname) - 1, "sem_%s%d", card->host->name, i + 1);
blk_dev->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
/* register mmcsd device */
blk_dev->dev.type = RT_Device_Class_Block;
#ifdef RT_USING_DEVICE_OPS
blk_dev->dev.ops = &mmcsd_blk_ops;
#else
blk_dev->dev.init = rt_mmcsd_init;
blk_dev->dev.open = rt_mmcsd_open;
blk_dev->dev.close = rt_mmcsd_close;
blk_dev->dev.read = rt_mmcsd_read;
blk_dev->dev.write = rt_mmcsd_write;
blk_dev->dev.control = rt_mmcsd_control;
#endif
blk_dev->card = card;
blk_dev->geometry.bytes_per_sector = 1 << 9;
blk_dev->geometry.block_size = card->card_blksize;
blk_dev->geometry.sector_count = blk_dev->part.size;
blk_dev->dev.user_data = blk_dev;
rt_device_register(&(blk_dev->dev), dname,
RT_DEVICE_FLAG_RDWR);
rt_list_insert_after(&blk_devices, &blk_dev->list);
}
else
{
rt_free(blk_dev);
blk_dev = RT_NULL;
break;
}
#ifdef RT_USING_DFS_MNTTABLE
if (blk_dev)
{
LOG_I("try to mount file system!");
/* try to mount file system on this block device */
dfs_mount_device(&(blk_dev->dev));
}
#endif
}
}
else
{
LOG_E("read mmcsd first sector failed");
err = -RT_ERROR;
}
/* release sector buffer */
rt_free(sector);
return err;
}
rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card)
{
uint32_t err = 0;
LOG_D("probe mmcsd block device!");
if (check_gpt(card) != 0)
{
err = gpt_device_probe(card);
}
else
{
err = mbr_device_probe(card);
}
return err;
}
void rt_mmcsd_blk_remove(struct rt_mmcsd_card *card)
{
rt_list_t *l, *n;
struct mmcsd_blk_device *blk_dev;
for (l = (&blk_devices)->next, n = l->next; l != &blk_devices; l = n, n = n->next)
{
blk_dev = (struct mmcsd_blk_device *)rt_list_entry(l, struct mmcsd_blk_device, list);
if (blk_dev->card == card)
{
/* unmount file system */
const char *mounted_path = dfs_filesystem_get_mounted_path(&(blk_dev->dev));
if (mounted_path)
{
dfs_unmount(mounted_path);
LOG_D("unmount file system %s for device %s.\r\n", mounted_path, blk_dev->dev.parent.name);
}
rt_sem_delete(blk_dev->part.lock);
rt_device_unregister(&blk_dev->dev);
rt_list_remove(&blk_dev->list);
rt_free(blk_dev);
}
}
}
/*
* This function will initialize block device on the mmc/sd.
*
* @deprecated since 2.1.0, this function does not need to be invoked
* in the system initialization.
*/
int rt_mmcsd_blk_init(void)
{
/* nothing */
return 0;
}

View File

@@ -0,0 +1,563 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-05-05 linzhenxing first version
*/
#include <rtthread.h>
#include <dfs_fs.h>
#include <drivers/gpt.h>
#include <drivers/mmcsd_core.h>
#define DBG_TAG "GPT"
#ifdef RT_SDIO_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif /* RT_SDIO_DEBUG */
#include <rtdbg.h>
#define min(a, b) a < b ? a : b
static int force_gpt = 0;
static gpt_header *_gpt;
static gpt_entry *_ptes;
#define GPT_TYPE 1
#define MBR_TYPE 0
static inline int efi_guidcmp (gpt_guid_t left, gpt_guid_t right)
{
return rt_memcmp(&left, &right, sizeof (gpt_guid_t));
}
static uint32_t last_lba(struct rt_mmcsd_card *card)
{
RT_ASSERT(card != RT_NULL);
return (card->card_sec_cnt) - 1;
}
static inline int pmbr_part_valid(gpt_mbr_record *part)
{
if (part->os_type != EFI_PMBR_OSTYPE_EFI_GPT)
{
goto invalid;
}
/* set to 0x00000001 (i.e., the LBA of the GPT Partition Header) */
if ((uint32_t)(part->starting_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA)
{
goto invalid;
}
return GPT_MBR_PROTECTIVE;
invalid:
return 0;
}
/*
*
* return ret
* ret = 0, invalid mbr
* ret = 1, protect mbr
* ret = 2, hybrid mbr
*/
int is_pmbr_valid(legacy_mbr *mbr, uint64_t total_sectors)
{
uint32_t sz = 0;
int i, part = 0, ret = 0; /* invalid by default */
if (!mbr || (uint16_t)(mbr->signature) != MSDOS_MBR_SIGNATURE)
{
goto done;
}
for (i = 0; i < 4; i++)
{
ret = pmbr_part_valid(&mbr->partition_record[i]);
if (ret == GPT_MBR_PROTECTIVE)
{
part = i;
/*
* Ok, we at least know that there's a protective MBR,
* now check if there are other partition types for
* hybrid MBR.
*/
goto check_hybrid;
}
}
if (ret != GPT_MBR_PROTECTIVE)
{
goto done;
}
check_hybrid:
for (i = 0; i < 4; i++)
{
if ((mbr->partition_record[i].os_type !=
EFI_PMBR_OSTYPE_EFI_GPT) &&
(mbr->partition_record[i].os_type != 0x00))
{
ret = GPT_MBR_HYBRID;
}
}
/*
* Protective MBRs take up the lesser of the whole disk
* or 2 TiB (32bit LBA), ignoring the rest of the disk.
* Some partitioning programs, nonetheless, choose to set
* the size to the maximum 32-bit limitation, disregarding
* the disk size.
*
* Hybrid MBRs do not necessarily comply with this.
*
* Consider a bad value here to be a warning to support dd'ing
* an image from a smaller disk to a larger disk.
*/
if (ret == GPT_MBR_PROTECTIVE)
{
sz = (uint32_t)(mbr->partition_record[part].size_in_lba);
if (sz != (uint32_t) total_sectors - 1 && sz != 0xFFFFFFFF)
{
LOG_I("GPT: mbr size in lba (%u) different than whole disk (%u).",
sz, min(total_sectors - 1, 0xFFFFFFFF));
}
}
done:
return ret;
}
static gpt_entry *alloc_read_gpt_entries(struct rt_mmcsd_card *card, gpt_header *gpt)
{
size_t count;
gpt_entry *pte;
if (!gpt)
{
return RT_NULL;
}
count = (size_t)(gpt->num_partition_entries) * (gpt->sizeof_partition_entry);
if (!count)
{
return RT_NULL;
}
pte = rt_malloc(count);
if (!pte)
return RT_NULL;
if (read_lba(card, (size_t)(gpt->partition_entry_lba),(uint8_t *)pte, count/512) != RT_EOK)
{
rt_free(pte);
return RT_NULL;
}
return pte;
}
static gpt_header *alloc_read_gpt_header(struct rt_mmcsd_card *card, size_t lba)
{
gpt_header *gpt;
void *buf;
buf = rt_malloc(512);
if (!buf)
{
return RT_NULL;
}
if (read_lba(card, lba, (uint8_t *)buf, 1) != RT_EOK)
{
rt_free(buf);
return RT_NULL;
}
gpt = (gpt_header *)buf;
return gpt;
}
static int is_gpt_valid(struct rt_mmcsd_card *card, size_t lba, gpt_header **gpt, gpt_entry **ptes)
{
size_t lastlba;
if (!ptes || !gpt)
{
return 0;
}
*gpt = alloc_read_gpt_header(card, lba);
if (!(*gpt))
{
return 0;
}
/* Check the GUID Partition Table signature */
if ((uint64_t)((*gpt)->signature) != GPT_HEADER_SIGNATURE)
{
LOG_E("GUID Partition Table Header signature is wrong:"
"%ld != %ld",(uint64_t)((*gpt)->signature),(uint64_t)GPT_HEADER_SIGNATURE);
goto fail;
}
/* Check the GUID Partition Table header size is too small */
if ((uint32_t)((*gpt)->header_size) < sizeof(gpt_header))
{
LOG_E("GUID Partition Table Header size is too small: %u < %zu",
(uint32_t)((*gpt)->header_size),sizeof(gpt_header));
goto fail;
}
/* Check that the start_lba entry points to the LBA that contains
* the GUID Partition Table */
if ((uint64_t)((*gpt)->start_lba) != lba)
{
LOG_E("GPT start_lba incorrect: %ld != %ld",
(uint64_t)((*gpt)->start_lba),
(uint64_t)lba);
goto fail;
}
/* Check the first_usable_lba and last_usable_lba are
* within the disk.
*/
lastlba = last_lba(card);
if ((uint64_t)((*gpt)->first_usable_lba) > lastlba)
{
LOG_E("GPT: first_usable_lba incorrect: %ld > %ld",
((uint64_t)((*gpt)->first_usable_lba)),
(size_t)lastlba);
goto fail;
}
if ((uint64_t)((*gpt)->last_usable_lba) > lastlba)
{
LOG_E("GPT: last_usable_lba incorrect: %ld > %ld",
(uint64_t)((*gpt)->last_usable_lba),
(size_t)lastlba);
goto fail;
}
if ((uint64_t)((*gpt)->last_usable_lba) < (uint64_t)((*gpt)->first_usable_lba))
{
LOG_E("GPT: last_usable_lba incorrect: %ld > %ld",
(uint64_t)((*gpt)->last_usable_lba),
(uint64_t)((*gpt)->first_usable_lba));
goto fail;
}
/* Check that sizeof_partition_entry has the correct value */
if ((uint32_t)((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry)) {
LOG_E("GUID Partition Entry Size check failed.");
goto fail;
}
*ptes = alloc_read_gpt_entries(card, *gpt);
if (!(*ptes))
{
goto fail;
}
/* We're done, all's well */
return 1;
fail:
rt_free(*gpt);
*gpt = RT_NULL;
return 0;
}
/**
* is_pte_valid() - tests one PTE for validity
* pte:pte to check
* lastlba: last lba of the disk
*
* Description: returns 1 if valid, 0 on error.
*/
static inline int is_pte_valid(const gpt_entry *pte, const size_t lastlba)
{
if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
(uint64_t)(pte->starting_lba) > lastlba ||
(uint64_t)(pte->ending_lba) > lastlba)
{
return 0;
}
return 1;
}
/**
* compare_gpts() - Search disk for valid GPT headers and PTEs
* pgpt: primary GPT header
* agpt: alternate GPT header
* lastlba: last LBA number
*
* Description: Returns nothing. Sanity checks pgpt and agpt fields
* and prints warnings on discrepancies.
*
*/
static void compare_gpts(gpt_header *pgpt, gpt_header *agpt, size_t lastlba)
{
int error_found = 0;
if (!pgpt || !agpt)
{
return;
}
if ((uint64_t)(pgpt->start_lba) != (uint64_t)(agpt->alternate_lba))
{
LOG_I("GPT:Primary header LBA != Alt. header alternate_lba");
LOG_I("GPT:%lld != %lld",
(uint64_t)(pgpt->start_lba),
(uint64_t)(agpt->alternate_lba));
error_found++;
}
if ((uint64_t)(pgpt->alternate_lba) != (uint64_t)(agpt->start_lba))
{
LOG_I("GPT:Primary header alternate_lba != Alt. header start_lba");
LOG_I("GPT:%lld != %lld",
(uint64_t)(pgpt->alternate_lba),
(uint64_t)(agpt->start_lba));
error_found++;
}
if ((uint64_t)(pgpt->first_usable_lba) != (uint64_t)(agpt->first_usable_lba))
{
LOG_I("GPT:first_usable_lbas don't match.");
LOG_I("GPT:%lld != %lld",
(uint64_t)(pgpt->first_usable_lba),
(uint64_t)(agpt->first_usable_lba));
error_found++;
}
if ((uint64_t)(pgpt->last_usable_lba) != (uint64_t)(agpt->last_usable_lba))
{
LOG_I("GPT:last_usable_lbas don't match.");
LOG_I("GPT:%lld != %lld",
(uint64_t)(pgpt->last_usable_lba),
(uint64_t)(agpt->last_usable_lba));
error_found++;
}
if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid))
{
LOG_I("GPT:disk_guids don't match.");
error_found++;
}
if ((pgpt->num_partition_entries) != (agpt->num_partition_entries))
{
LOG_I("GPT:num_partition_entries don't match: "
"0x%x != 0x%x",
(pgpt->num_partition_entries),
(agpt->num_partition_entries));
error_found++;
}
if ((pgpt->sizeof_partition_entry) != (agpt->sizeof_partition_entry))
{
LOG_I("GPT:sizeof_partition_entry values don't match: "
"0x%x != 0x%x",
(pgpt->sizeof_partition_entry),
(agpt->sizeof_partition_entry));
error_found++;
}
if ((pgpt->partition_entry_array_crc32) != (agpt->partition_entry_array_crc32))
{
LOG_I("GPT:partition_entry_array_crc32 values don't match: "
"0x%x != 0x%x",
(pgpt->partition_entry_array_crc32),
(agpt->partition_entry_array_crc32));
error_found++;
}
if ((pgpt->alternate_lba) != lastlba)
{
LOG_I("GPT:Primary header thinks Alt. header is not at the end of the disk.");
LOG_I("GPT:%lld != %lld",
(uint64_t)(pgpt->alternate_lba),
(size_t)lastlba);
error_found++;
}
if ((agpt->start_lba) != lastlba)
{
LOG_I("GPT:Alternate GPT header not at the end of the disk.");
LOG_I("GPT:%lld != %lld",
(uint64_t)(agpt->start_lba),
(size_t)lastlba);
error_found++;
}
if (error_found)
{
LOG_I("GPT: Use GNU Parted to correct GPT errors.");
}
return;
}
/**
* find_valid_gpt() - Search disk for valid GPT headers and PTEs
* state: disk parsed partitions
* gpt: GPT header ptr, filled on return.
* ptes: PTEs ptr, filled on return.
*
* Description: Returns 1 if valid, 0 on error.
* If valid, returns pointers to newly allocated GPT header and PTEs.
* Validity depends on PMBR being valid (or being overridden by the
* 'gpt' kernel command line option) and finding either the Primary
* GPT header and PTEs valid, or the Alternate GPT header and PTEs
* valid. If the Primary GPT header is not valid, the Alternate GPT header
* is not checked unless the 'gpt' kernel command line option is passed.
* This protects against devices which misreport their size, and forces
* the user to decide to use the Alternate GPT.
*/
static int find_valid_gpt(struct rt_mmcsd_card *card, gpt_header **gpt,
gpt_entry **ptes)
{
int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
gpt_header *pgpt = RT_NULL, *agpt = RT_NULL;
gpt_entry *pptes = RT_NULL, *aptes = RT_NULL;
legacy_mbr *legacymbr;
size_t total_sectors = last_lba(card) + 1;
size_t lastlba;
int status = 0;
if (!ptes)
{
return 0;
}
lastlba = last_lba(card);
if (!force_gpt)
{
/* This will be added to the EFI Spec. per Intel after v1.02. */
legacymbr = rt_malloc(512);
if (!legacymbr)
{
goto fail;
}
status = read_lba(card, 0, (uint8_t *)legacymbr, 1);
if (status)
{
LOG_I("status:%d", status);
goto fail;
}
good_pmbr = is_pmbr_valid(legacymbr, total_sectors);
rt_free(legacymbr);
if (!good_pmbr)
{
goto fail;
}
rt_kprintf("Device has a %s MBR\n",
good_pmbr == GPT_MBR_PROTECTIVE ?
"protective" : "hybrid");
}
good_pgpt = is_gpt_valid(card, GPT_PRIMARY_PARTITION_TABLE_LBA,
&pgpt, &pptes);
if (good_pgpt)
{
good_agpt = is_gpt_valid(card, (pgpt->alternate_lba), &agpt, &aptes);
if (!good_agpt && force_gpt)
{
good_agpt = is_gpt_valid(card, lastlba, &agpt, &aptes);
}
/* The obviously unsuccessful case */
if (!good_pgpt && !good_agpt)
{
goto fail;
}
compare_gpts(pgpt, agpt, lastlba);
/* The good cases */
if (good_pgpt)
{
*gpt = pgpt;
*ptes = pptes;
rt_free(agpt);
rt_free(aptes);
if (!good_agpt)
{
LOG_D("Alternate GPT is invalid, using primary GPT.");
}
return 1;
}
else if (good_agpt)
{
*gpt = agpt;
*ptes = aptes;
rt_free(pgpt);
rt_free(pptes);
LOG_D("Primary GPT is invalid, using alternate GPT.");
return 1;
}
}
fail:
rt_free(pgpt);
rt_free(agpt);
rt_free(pptes);
rt_free(aptes);
*gpt = RT_NULL;
*ptes = RT_NULL;
return 0;
}
int check_gpt(struct rt_mmcsd_card *card)
{
if (!find_valid_gpt(card, &_gpt, &_ptes) || !_gpt || !_ptes)
{
rt_free(_gpt);
rt_free(_ptes);
return MBR_TYPE;
}
return GPT_TYPE;
}
int gpt_get_partition_param(struct rt_mmcsd_card *card, struct dfs_partition *part, uint32_t pindex)
{
if (!is_pte_valid(&_ptes[pindex], last_lba(card)))
{
return -1;
}
part->offset = (off_t)(_ptes[pindex].starting_lba);
part->size = (_ptes[pindex].ending_lba) - (_ptes[pindex].starting_lba) + 1ULL;
rt_kprintf("found part[%d], begin(sector): %d, end(sector):%d size: ",
pindex, _ptes[pindex].starting_lba, _ptes[pindex].ending_lba);
if ((part->size >> 11) == 0)
{
rt_kprintf("%d%s", part->size >> 1, "KB\n"); /* KB */
}
else
{
unsigned int part_size;
part_size = part->size >> 11; /* MB */
if ((part_size >> 10) == 0)
rt_kprintf("%d.%d%s", part_size, (part->size >> 1) & 0x3FF, "MB\n");
else
rt_kprintf("%d.%d%s", part_size >> 10, part_size & 0x3FF, "GB\n");
}
return 0;
}
void gpt_free(void)
{
rt_free(_ptes);
rt_free(_gpt);
}

View File

@@ -0,0 +1,792 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2015-06-15 hichard first version
* 2024-05-25 HPMicro add HS400 support
*/
#include <drivers/mmcsd_core.h>
#include <drivers/mmc.h>
#define DBG_TAG "SDIO"
#ifdef RT_SDIO_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif /* RT_SDIO_DEBUG */
#include <rtdbg.h>
static const rt_uint32_t tran_unit[] =
{
10000, 100000, 1000000, 10000000,
0, 0, 0, 0
};
static const rt_uint8_t tran_value[] =
{
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
static const rt_uint32_t tacc_uint[] =
{
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
};
static const rt_uint8_t tacc_value[] =
{
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
rt_inline rt_uint32_t GET_BITS(rt_uint32_t *resp,
rt_uint32_t start,
rt_uint32_t size)
{
const rt_int32_t __size = size;
const rt_uint32_t __mask = (__size < 32 ? 1 << __size : 0) - 1;
const rt_int32_t __off = 3 - ((start) / 32);
const rt_int32_t __shft = (start) & 31;
rt_uint32_t __res;
__res = resp[__off] >> __shft;
if (__size + __shft > 32)
__res |= resp[__off - 1] << ((32 - __shft) % 32);
return __res & __mask;
}
/*
* Given a 128-bit response, decode to our card CSD structure.
*/
static rt_int32_t mmcsd_parse_csd(struct rt_mmcsd_card *card)
{
rt_uint32_t a, b;
struct rt_mmcsd_csd *csd = &card->csd;
rt_uint32_t *resp = card->resp_csd;
/*
* We only understand CSD structure v1.1 and v1.2.
* v1.2 has extra information in bits 15, 11 and 10.
* We also support eMMC v4.4 & v4.41.
*/
csd->csd_structure = GET_BITS(resp, 126, 2);
if (csd->csd_structure == 0)
{
LOG_E("unrecognised CSD structure version %d!", csd->csd_structure);
return -RT_ERROR;
}
csd->taac = GET_BITS(resp, 112, 8);
csd->nsac = GET_BITS(resp, 104, 8);
csd->tran_speed = GET_BITS(resp, 96, 8);
csd->card_cmd_class = GET_BITS(resp, 84, 12);
csd->rd_blk_len = GET_BITS(resp, 80, 4);
csd->rd_blk_part = GET_BITS(resp, 79, 1);
csd->wr_blk_misalign = GET_BITS(resp, 78, 1);
csd->rd_blk_misalign = GET_BITS(resp, 77, 1);
csd->dsr_imp = GET_BITS(resp, 76, 1);
csd->c_size = GET_BITS(resp, 62, 12);
csd->c_size_mult = GET_BITS(resp, 47, 3);
csd->r2w_factor = GET_BITS(resp, 26, 3);
csd->wr_blk_len = GET_BITS(resp, 22, 4);
csd->wr_blk_partial = GET_BITS(resp, 21, 1);
csd->csd_crc = GET_BITS(resp, 1, 7);
card->card_blksize = 1 << csd->rd_blk_len;
card->tacc_clks = csd->nsac * 100;
card->tacc_ns = (tacc_uint[csd->taac & 0x07] * tacc_value[(csd->taac & 0x78) >> 3] + 9) / 10;
card->max_data_rate = tran_unit[csd->tran_speed & 0x07] * tran_value[(csd->tran_speed & 0x78) >> 3];
if (csd->wr_blk_len >= 9)
{
a = GET_BITS(resp, 42, 5);
b = GET_BITS(resp, 37, 5);
card->erase_size = (a + 1) * (b + 1);
card->erase_size <<= csd->wr_blk_len - 9;
}
return 0;
}
/*
* Read extended CSD.
*/
static int mmc_get_ext_csd(struct rt_mmcsd_card *card, rt_uint8_t **new_ext_csd)
{
void *ext_csd;
struct rt_mmcsd_req req;
struct rt_mmcsd_cmd cmd;
struct rt_mmcsd_data data;
*new_ext_csd = RT_NULL;
if (GET_BITS(card->resp_csd, 122, 4) < 4)
return 0;
/*
* As the ext_csd is so large and mostly unused, we don't store the
* raw block in mmc_card.
*/
ext_csd = rt_malloc(512);
if (!ext_csd)
{
LOG_E("alloc memory failed when get ext csd!");
return -RT_ENOMEM;
}
rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
req.cmd = &cmd;
req.data = &data;
cmd.cmd_code = SEND_EXT_CSD;
cmd.arg = 0;
/* NOTE HACK: the RESP_SPI_R1 is always correct here, but we
* rely on callers to never use this with "native" calls for reading
* CSD or CID. Native versions of those commands use the R2 type,
* not R1 plus a data block.
*/
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
data.blksize = 512;
data.blks = 1;
data.flags = DATA_DIR_READ;
data.buf = ext_csd;
/*
* Some cards require longer data read timeout than indicated in CSD.
* Address this by setting the read timeout to a "reasonably high"
* value. For the cards tested, 300ms has proven enough. If necessary,
* this value can be increased if other problematic cards require this.
*/
data.timeout_ns = 300000000;
data.timeout_clks = 0;
mmcsd_send_request(card->host, &req);
if (cmd.err)
return cmd.err;
if (data.err)
return data.err;
*new_ext_csd = ext_csd;
return 0;
}
/*
* Decode extended CSD.
*/
static int mmc_parse_ext_csd(struct rt_mmcsd_card *card, rt_uint8_t *ext_csd)
{
rt_uint64_t card_capacity = 0;
struct rt_mmcsd_host *host;
if (card == RT_NULL || ext_csd == RT_NULL)
{
LOG_E("emmc parse ext csd fail, invaild args");
return -1;
}
host = card->host;
uint8_t device_type = ext_csd[EXT_CSD_CARD_TYPE];
if ((host->flags & MMCSD_SUP_HS400) && (device_type & EXT_CSD_CARD_TYPE_HS400))
{
card->flags |= CARD_FLAG_HS400;
card->max_data_rate = 200000000;
}
else if ((host->flags & MMCSD_SUP_HS200) && (device_type & EXT_CSD_CARD_TYPE_HS200))
{
card->flags |= CARD_FLAG_HS200;
card->max_data_rate = 200000000;
}
else if ((host->flags & MMCSD_SUP_HIGHSPEED_DDR) && (device_type & EXT_CSD_CARD_TYPE_DDR_52))
{
card->flags |= CARD_FLAG_HIGHSPEED_DDR;
card->hs_max_data_rate = 52000000;
}
else
{
card->flags |= CARD_FLAG_HIGHSPEED;
card->hs_max_data_rate = 52000000;
}
if (ext_csd[EXT_CSD_STROBE_SUPPORT] != 0)
{
card->ext_csd.enhanced_data_strobe = 1;
}
card->ext_csd.cache_size =
ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 |
ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;
card_capacity = *((rt_uint32_t *)&ext_csd[EXT_CSD_SEC_CNT]);
card->card_sec_cnt = card_capacity;
card_capacity *= card->card_blksize;
card_capacity >>= 10; /* unit:KB */
card->card_capacity = card_capacity;
LOG_I("emmc card capacity %d KB, card sec count:%d.", card->card_capacity, card->card_sec_cnt);
return 0;
}
/**
* mmc_switch - modify EXT_CSD register
* @card: the MMC card associated with the data transfer
* @set: cmd set values
* @index: EXT_CSD register index
* @value: value to program into EXT_CSD register
*
* Modifies the EXT_CSD register for selected card.
*/
static int mmc_switch(struct rt_mmcsd_card *card, rt_uint8_t set,
rt_uint8_t index, rt_uint8_t value)
{
int err;
struct rt_mmcsd_host *host = card->host;
struct rt_mmcsd_cmd cmd = {0};
cmd.cmd_code = SWITCH;
cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
(index << 16) | (value << 8) | set;
cmd.flags = RESP_R1B | CMD_AC;
err = mmcsd_send_cmd(host, &cmd, 3);
if (err)
return err;
return 0;
}
static int mmc_compare_ext_csds(struct rt_mmcsd_card *card,
rt_uint8_t *ext_csd, rt_uint32_t bus_width)
{
rt_uint8_t *bw_ext_csd;
int err;
if (bus_width == MMCSD_BUS_WIDTH_1)
return 0;
err = mmc_get_ext_csd(card, &bw_ext_csd);
if (err || bw_ext_csd == RT_NULL)
{
err = -RT_ERROR;
goto out;
}
/* only compare read only fields */
err = !((ext_csd[EXT_CSD_PARTITION_SUPPORT] == bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
(ext_csd[EXT_CSD_ERASED_MEM_CONT] == bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
(ext_csd[EXT_CSD_REV] == bw_ext_csd[EXT_CSD_REV]) &&
(ext_csd[EXT_CSD_STRUCTURE] == bw_ext_csd[EXT_CSD_STRUCTURE]) &&
(ext_csd[EXT_CSD_CARD_TYPE] == bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
(ext_csd[EXT_CSD_S_A_TIMEOUT] == bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
(ext_csd[EXT_CSD_HC_WP_GRP_SIZE] == bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
(ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] == bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
(ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] == bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
(ext_csd[EXT_CSD_SEC_TRIM_MULT] == bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
(ext_csd[EXT_CSD_SEC_ERASE_MULT] == bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
(ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] == bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
(ext_csd[EXT_CSD_TRIM_MULT] == bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
(ext_csd[EXT_CSD_SEC_CNT + 0] == bw_ext_csd[EXT_CSD_SEC_CNT + 0]) &&
(ext_csd[EXT_CSD_SEC_CNT + 1] == bw_ext_csd[EXT_CSD_SEC_CNT + 1]) &&
(ext_csd[EXT_CSD_SEC_CNT + 2] == bw_ext_csd[EXT_CSD_SEC_CNT + 2]) &&
(ext_csd[EXT_CSD_SEC_CNT + 3] == bw_ext_csd[EXT_CSD_SEC_CNT + 3]) &&
(ext_csd[EXT_CSD_PWR_CL_52_195] == bw_ext_csd[EXT_CSD_PWR_CL_52_195]) &&
(ext_csd[EXT_CSD_PWR_CL_26_195] == bw_ext_csd[EXT_CSD_PWR_CL_26_195]) &&
(ext_csd[EXT_CSD_PWR_CL_52_360] == bw_ext_csd[EXT_CSD_PWR_CL_52_360]) &&
(ext_csd[EXT_CSD_PWR_CL_26_360] == bw_ext_csd[EXT_CSD_PWR_CL_26_360]) &&
(ext_csd[EXT_CSD_PWR_CL_200_195] == bw_ext_csd[EXT_CSD_PWR_CL_200_195]) &&
(ext_csd[EXT_CSD_PWR_CL_200_360] == bw_ext_csd[EXT_CSD_PWR_CL_200_360]) &&
(ext_csd[EXT_CSD_PWR_CL_DDR_52_195] == bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
(ext_csd[EXT_CSD_PWR_CL_DDR_52_360] == bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
(ext_csd[EXT_CSD_PWR_CL_DDR_200_360] == bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
if (err)
err = -RT_ERROR;
out:
rt_free(bw_ext_csd);
return err;
}
/*
* Select the bus width among 4-bit and 8-bit(SDR).
* If the bus width is changed successfully, return the selected width value.
* Zero is returned instead of error value if the wide width is not supported.
*/
static int mmc_select_bus_width(struct rt_mmcsd_card *card, rt_uint8_t *ext_csd)
{
rt_uint32_t ext_csd_bits[][2] =
{
{EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8},
{EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4},
{EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1},
};
rt_uint32_t bus_widths[] =
{
MMCSD_BUS_WIDTH_8,
MMCSD_BUS_WIDTH_4,
MMCSD_BUS_WIDTH_1
};
struct rt_mmcsd_host *host = card->host;
unsigned idx, bus_width = 0;
int err = 0, ddr = 0;
if (GET_BITS(card->resp_csd, 122, 4) < 4)
return 0;
if (card->flags & CARD_FLAG_HIGHSPEED_DDR)
{
ddr = 2;
}
/*
* Unlike SD, MMC cards don't have a configuration register to notify
* supported bus width. So bus test command should be run to identify
* the supported bus width or compare the EXT_CSD values of current
* bus width and EXT_CSD values of 1 bit mode read earlier.
*/
for (idx = 0; idx < sizeof(bus_widths) / sizeof(rt_uint32_t); idx++)
{
/*
* Determine BUS WIDTH mode according to the capability of host
*/
if (((ext_csd_bits[idx][0] == EXT_CSD_BUS_WIDTH_8) && ((host->flags & MMCSD_BUSWIDTH_8) == 0)) ||
((ext_csd_bits[idx][0] == EXT_CSD_BUS_WIDTH_4) && ((host->flags & MMCSD_BUSWIDTH_4) == 0)))
{
continue;
}
bus_width = bus_widths[idx];
if (bus_width == MMCSD_BUS_WIDTH_1)
{
ddr = 0;
}
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
ext_csd_bits[idx][0]);
if (err)
continue;
mmcsd_set_bus_width(host, bus_width);
err = mmc_compare_ext_csds(card, ext_csd, bus_width);
if (!err)
{
break;
}
else
{
switch (ext_csd_bits[idx][0])
{
case 0:
LOG_E("switch to bus width 1 bit failed!");
break;
case 1:
LOG_E("switch to bus width 4 bit failed!");
break;
case 2:
LOG_E("switch to bus width 8 bit failed!");
break;
default:
break;
}
}
}
if (!err && ddr)
{
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
ext_csd_bits[idx][1]);
}
if (!err)
{
if (card->flags & (CARD_FLAG_HIGHSPEED | CARD_FLAG_HIGHSPEED_DDR))
{
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING,
1);
}
}
return err;
}
rt_err_t mmc_send_op_cond(struct rt_mmcsd_host *host,
rt_uint32_t ocr, rt_uint32_t *rocr)
{
struct rt_mmcsd_cmd cmd;
rt_uint32_t i;
rt_err_t err = RT_EOK;
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = SEND_OP_COND;
cmd.arg = controller_is_spi(host) ? 0 : ocr;
cmd.flags = RESP_SPI_R1 | RESP_R3 | CMD_BCR;
for (i = 100; i; i--)
{
err = mmcsd_send_cmd(host, &cmd, 3);
if (err)
break;
/* if we're just probing, do a single pass */
if (ocr == 0)
break;
/* otherwise wait until reset completes */
if (controller_is_spi(host))
{
if (!(cmd.resp[0] & R1_SPI_IDLE))
break;
}
else
{
if (cmd.resp[0] & CARD_BUSY)
break;
}
err = -RT_ETIMEOUT;
rt_thread_mdelay(10); //delay 10ms
}
if (rocr && !controller_is_spi(host))
*rocr = cmd.resp[0];
return err;
}
static rt_err_t mmc_set_card_addr(struct rt_mmcsd_host *host, rt_uint32_t rca)
{
rt_err_t err;
struct rt_mmcsd_cmd cmd;
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = SET_RELATIVE_ADDR;
cmd.arg = rca << 16;
cmd.flags = RESP_R1 | CMD_AC;
err = mmcsd_send_cmd(host, &cmd, 3);
if (err)
return err;
return 0;
}
static int mmc_select_hs200(struct rt_mmcsd_card *card)
{
int ret;
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200);
if (ret)
return ret;
mmcsd_set_timing(card->host, MMCSD_TIMING_MMC_HS200);
mmcsd_set_clock(card->host, card->max_data_rate);
ret = mmcsd_excute_tuning(card);
return ret;
}
static int mmc_switch_to_hs400(struct rt_mmcsd_card *card)
{
struct rt_mmcsd_host *host = card->host;
int err;
rt_uint8_t ext_csd_bus_width;
rt_uint32_t hs_timing;
/* Switch to HS_TIMING to 0x01 (High Speed) */
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS);
if (err != RT_EOK)
{
return err;
}
mmcsd_set_timing(card->host, MMCSD_TIMING_MMC_HS);
/* Host changes frequency to <= 52MHz */
mmcsd_set_clock(card->host, 52000000);
rt_bool_t support_enhanced_ds = ((card->ext_csd.enhanced_data_strobe != 0) &&
((host->flags & MMCSD_SUP_ENH_DS) != 0));
/* Set the bus width to:
* 0x86 if enhanced data strobe is supported, or
* 0x06 if enhanced data strobe is not supported
*/
ext_csd_bus_width = support_enhanced_ds ?
EXT_CSD_DDR_BUS_WIDTH_8_EH_DS :
EXT_CSD_DDR_BUS_WIDTH_8;
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
ext_csd_bus_width);
if (err != RT_EOK)
{
return err;
}
/* Set HS_TIMING to 0x03 (HS400) */
err = mmc_switch(card,
EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING,
EXT_CSD_TIMING_HS400);
if (err != RT_EOK)
{
return err;
}
/* Change the Host timing accordingly */
hs_timing = support_enhanced_ds ?
MMCSD_TIMING_MMC_HS400_ENH_DS :
MMCSD_TIMING_MMC_HS400;
mmcsd_set_timing(host, hs_timing);
/* Host may changes frequency to <= 200MHz */
mmcsd_set_clock(card->host, card->max_data_rate);
return RT_EOK;
}
static int mmc_select_hs400(struct rt_mmcsd_card *card)
{
int ret;
struct rt_mmcsd_host *host = card->host;
/* if the card or host doesn't support enhanced data strobe, switch to HS200 and perform tuning process first */
if ((card->ext_csd.enhanced_data_strobe == 0) || ((host->flags & MMCSD_SUP_ENH_DS) == 0))
{
ret = mmc_select_hs200(card);
if (ret != RT_EOK)
{
return ret;
}
}
return mmc_switch_to_hs400(card);
}
static int mmc_select_timing(struct rt_mmcsd_card *card)
{
int ret = 0;
if (card->flags & CARD_FLAG_HS400)
{
LOG_I("emmc: switch to HS400 mode\n");
ret = mmc_select_hs400(card);
}
else if (card->flags & CARD_FLAG_HS200)
{
LOG_I("emmc: switch to HS200 mode\n");
ret = mmc_select_hs200(card);
}
else if (card->flags & CARD_FLAG_HIGHSPEED_DDR)
{
LOG_I("emmc: switch to HIGH Speed DDR mode\n");
mmcsd_set_timing(card->host, MMCSD_TIMING_MMC_DDR52);
mmcsd_set_clock(card->host, card->hs_max_data_rate);
}
else
{
LOG_I("emmc: switch to HIGH Speed mode\n");
mmcsd_set_timing(card->host, MMCSD_TIMING_MMC_HS);
mmcsd_set_clock(card->host, card->hs_max_data_rate);
}
return ret;
}
static rt_int32_t mmcsd_mmc_init_card(struct rt_mmcsd_host *host,
rt_uint32_t ocr)
{
rt_int32_t err;
rt_uint32_t resp[4];
rt_uint32_t rocr = 0;
rt_uint8_t *ext_csd = RT_NULL;
struct rt_mmcsd_card *card = RT_NULL;
mmcsd_go_idle(host);
/* The extra bit indicates that we support high capacity */
err = mmc_send_op_cond(host, ocr | (1 << 30), &rocr);
if (err)
goto err;
if (controller_is_spi(host))
{
err = mmcsd_spi_use_crc(host, 1);
if (err)
goto err1;
}
if (controller_is_spi(host))
err = mmcsd_get_cid(host, resp);
else
err = mmcsd_all_get_cid(host, resp);
if (err)
goto err;
card = rt_malloc(sizeof(struct rt_mmcsd_card));
if (!card)
{
LOG_E("malloc card failed!");
err = -RT_ENOMEM;
goto err;
}
rt_memset(card, 0, sizeof(struct rt_mmcsd_card));
card->card_type = CARD_TYPE_MMC;
card->host = host;
card->rca = 1;
rt_memcpy(card->resp_cid, resp, sizeof(card->resp_cid));
/*
* For native busses: get card RCA and quit open drain mode.
*/
if (!controller_is_spi(host))
{
err = mmc_set_card_addr(host, card->rca);
if (err)
goto err1;
mmcsd_set_bus_mode(host, MMCSD_BUSMODE_PUSHPULL);
}
err = mmcsd_get_csd(card, card->resp_csd);
if (err)
goto err1;
err = mmcsd_parse_csd(card);
if (err)
goto err1;
if (!controller_is_spi(host))
{
err = mmcsd_select_card(card);
if (err)
goto err1;
}
/*
* Fetch and process extended CSD.
*/
err = mmc_get_ext_csd(card, &ext_csd);
if (err)
goto err1;
err = mmc_parse_ext_csd(card, ext_csd);
if (err)
goto err1;
/* If doing byte addressing, check if required to do sector
* addressing. Handle the case of <2GB cards needing sector
* addressing. See section 8.1 JEDEC Standard JED84-A441;
* ocr register has bit 30 set for sector addressing.
*/
if (!(card->flags & CARD_FLAG_SDHC) && (rocr & (1 << 30)))
card->flags |= CARD_FLAG_SDHC;
/*switch bus width and bus mode*/
err = mmc_select_bus_width(card, ext_csd);
if (err)
{
LOG_E("mmc select buswidth fail");
goto err0;
}
err = mmc_select_timing(card);
if (err)
{
LOG_E("mmc select timing fail");
goto err0;
}
if (card->ext_csd.cache_size > 0)
{
mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_CACHE_CTRL, 1);
}
host->card = card;
rt_free(ext_csd);
return 0;
err0:
rt_free(ext_csd);
err1:
rt_free(card);
err:
return err;
}
/*
* Starting point for mmc card init.
*/
rt_int32_t init_mmc(struct rt_mmcsd_host *host, rt_uint32_t ocr)
{
rt_int32_t err;
rt_uint32_t current_ocr;
/*
* We need to get OCR a different way for SPI.
*/
if (controller_is_spi(host))
{
err = mmcsd_spi_read_ocr(host, 0, &ocr);
if (err)
goto err;
}
current_ocr = mmcsd_select_voltage(host, ocr);
/*
* Can we support the voltage(s) of the card(s)?
*/
if (!current_ocr)
{
err = -RT_ERROR;
goto err;
}
/*
* Detect and init the card.
*/
err = mmcsd_mmc_init_card(host, current_ocr);
if (err)
goto err;
mmcsd_host_unlock(host);
err = rt_mmcsd_blk_probe(host->card);
if (err)
goto remove_card;
mmcsd_host_lock(host);
return 0;
remove_card:
mmcsd_host_lock(host);
rt_mmcsd_blk_remove(host->card);
rt_free(host->card);
host->card = RT_NULL;
err:
LOG_E("init MMC card failed!");
return err;
}

View File

@@ -0,0 +1,781 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-07-25 weety first version
*/
#include <rtthread.h>
#include <drivers/mmcsd_core.h>
#include <drivers/sd.h>
#include <drivers/mmc.h>
#include <drivers/sdio.h>
#include <string.h>
#define DBG_TAG "SDIO"
#ifdef RT_SDIO_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif /* RT_SDIO_DEBUG */
#include <rtdbg.h>
#ifndef RT_MMCSD_STACK_SIZE
#define RT_MMCSD_STACK_SIZE 1024
#endif
#ifndef RT_MMCSD_THREAD_PREORITY
#if (RT_THREAD_PRIORITY_MAX == 32)
#define RT_MMCSD_THREAD_PREORITY 0x16
#else
#define RT_MMCSD_THREAD_PREORITY 0x40
#endif
#endif
//static struct rt_semaphore mmcsd_sem;
static struct rt_thread mmcsd_detect_thread;
static rt_uint8_t mmcsd_stack[RT_MMCSD_STACK_SIZE];
static struct rt_mailbox mmcsd_detect_mb;
static rt_uint32_t mmcsd_detect_mb_pool[4];
static struct rt_mailbox mmcsd_hotpluge_mb;
static rt_uint32_t mmcsd_hotpluge_mb_pool[4];
void mmcsd_host_lock(struct rt_mmcsd_host *host)
{
rt_mutex_take(&host->bus_lock, RT_WAITING_FOREVER);
}
void mmcsd_host_unlock(struct rt_mmcsd_host *host)
{
rt_mutex_release(&host->bus_lock);
}
void mmcsd_req_complete(struct rt_mmcsd_host *host)
{
rt_sem_release(&host->sem_ack);
}
void mmcsd_send_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
{
do
{
req->cmd->retries--;
req->cmd->err = 0;
req->cmd->mrq = req;
if (req->data)
{
req->cmd->data = req->data;
req->data->err = 0;
req->data->mrq = req;
if (req->stop)
{
req->data->stop = req->stop;
req->stop->err = 0;
req->stop->mrq = req;
}
}
host->ops->request(host, req);
rt_sem_take(&host->sem_ack, RT_WAITING_FOREVER);
}
while (req->cmd->err && (req->cmd->retries > 0));
}
rt_int32_t mmcsd_send_cmd(struct rt_mmcsd_host *host,
struct rt_mmcsd_cmd *cmd,
int retries)
{
struct rt_mmcsd_req req;
rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
rt_memset(cmd->resp, 0, sizeof(cmd->resp));
cmd->retries = retries;
req.cmd = cmd;
cmd->data = RT_NULL;
mmcsd_send_request(host, &req);
return cmd->err;
}
rt_int32_t mmcsd_go_idle(struct rt_mmcsd_host *host)
{
rt_int32_t err;
struct rt_mmcsd_cmd cmd;
if (!controller_is_spi(host))
{
mmcsd_set_chip_select(host, MMCSD_CS_HIGH);
rt_thread_mdelay(1);
}
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = GO_IDLE_STATE;
cmd.arg = 0;
cmd.flags = RESP_SPI_R1 | RESP_NONE | CMD_BC;
err = mmcsd_send_cmd(host, &cmd, 0);
rt_thread_mdelay(1);
if (!controller_is_spi(host))
{
mmcsd_set_chip_select(host, MMCSD_CS_IGNORE);
rt_thread_mdelay(1);
}
return err;
}
rt_int32_t mmcsd_spi_read_ocr(struct rt_mmcsd_host *host,
rt_int32_t high_capacity,
rt_uint32_t *ocr)
{
struct rt_mmcsd_cmd cmd;
rt_int32_t err;
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = SPI_READ_OCR;
cmd.arg = high_capacity ? (1 << 30) : 0;
cmd.flags = RESP_SPI_R3;
err = mmcsd_send_cmd(host, &cmd, 0);
*ocr = cmd.resp[1];
return err;
}
rt_int32_t mmcsd_all_get_cid(struct rt_mmcsd_host *host, rt_uint32_t *cid)
{
rt_int32_t err;
struct rt_mmcsd_cmd cmd;
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = ALL_SEND_CID;
cmd.arg = 0;
cmd.flags = RESP_R2 | CMD_BCR;
err = mmcsd_send_cmd(host, &cmd, 3);
if (err)
return err;
rt_memcpy(cid, cmd.resp, sizeof(rt_uint32_t) * 4);
return 0;
}
rt_int32_t mmcsd_get_cid(struct rt_mmcsd_host *host, rt_uint32_t *cid)
{
rt_int32_t err, i;
struct rt_mmcsd_req req;
struct rt_mmcsd_cmd cmd;
struct rt_mmcsd_data data;
rt_uint32_t *buf = RT_NULL;
if (!controller_is_spi(host))
{
if (!host->card)
return -RT_ERROR;
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = SEND_CID;
cmd.arg = host->card->rca << 16;
cmd.flags = RESP_R2 | CMD_AC;
err = mmcsd_send_cmd(host, &cmd, 3);
if (err)
return err;
rt_memcpy(cid, cmd.resp, sizeof(rt_uint32_t) * 4);
return 0;
}
buf = (rt_uint32_t *)rt_malloc(16);
if (!buf)
{
LOG_E("allocate memory failed!");
return -RT_ENOMEM;
}
rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
req.cmd = &cmd;
req.data = &data;
cmd.cmd_code = SEND_CID;
cmd.arg = 0;
/* NOTE HACK: the RESP_SPI_R1 is always correct here, but we
* rely on callers to never use this with "native" calls for reading
* CSD or CID. Native versions of those commands use the R2 type,
* not R1 plus a data block.
*/
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
data.blksize = 16;
data.blks = 1;
data.flags = DATA_DIR_READ;
data.buf = buf;
/*
* The spec states that CSR and CID accesses have a timeout
* of 64 clock cycles.
*/
data.timeout_ns = 0;
data.timeout_clks = 64;
mmcsd_send_request(host, &req);
if (cmd.err || data.err)
{
rt_free(buf);
return -RT_ERROR;
}
for (i = 0; i < 4; i++)
cid[i] = buf[i];
rt_free(buf);
return 0;
}
rt_int32_t mmcsd_get_csd(struct rt_mmcsd_card *card, rt_uint32_t *csd)
{
rt_int32_t err, i;
struct rt_mmcsd_req req;
struct rt_mmcsd_cmd cmd;
struct rt_mmcsd_data data;
rt_uint32_t *buf = RT_NULL;
if (!controller_is_spi(card->host))
{
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = SEND_CSD;
cmd.arg = card->rca << 16;
cmd.flags = RESP_R2 | CMD_AC;
err = mmcsd_send_cmd(card->host, &cmd, 3);
if (err)
return err;
rt_memcpy(csd, cmd.resp, sizeof(rt_uint32_t) * 4);
return 0;
}
buf = (rt_uint32_t *)rt_malloc(16);
if (!buf)
{
LOG_E("allocate memory failed!");
return -RT_ENOMEM;
}
rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
req.cmd = &cmd;
req.data = &data;
cmd.cmd_code = SEND_CSD;
cmd.arg = 0;
/* NOTE HACK: the RESP_SPI_R1 is always correct here, but we
* rely on callers to never use this with "native" calls for reading
* CSD or CID. Native versions of those commands use the R2 type,
* not R1 plus a data block.
*/
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
data.blksize = 16;
data.blks = 1;
data.flags = DATA_DIR_READ;
data.buf = buf;
/*
* The spec states that CSR and CID accesses have a timeout
* of 64 clock cycles.
*/
data.timeout_ns = 0;
data.timeout_clks = 64;
mmcsd_send_request(card->host, &req);
if (cmd.err || data.err)
{
rt_free(buf);
return -RT_ERROR;
}
for (i = 0; i < 4; i++)
csd[i] = buf[i];
rt_free(buf);
return 0;
}
static rt_int32_t _mmcsd_select_card(struct rt_mmcsd_host *host,
struct rt_mmcsd_card *card)
{
rt_int32_t err;
struct rt_mmcsd_cmd cmd;
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = SELECT_CARD;
if (card)
{
cmd.arg = card->rca << 16;
cmd.flags = RESP_R1 | CMD_AC;
}
else
{
cmd.arg = 0;
cmd.flags = RESP_NONE | CMD_AC;
}
err = mmcsd_send_cmd(host, &cmd, 3);
if (err)
return err;
return 0;
}
rt_int32_t mmcsd_select_card(struct rt_mmcsd_card *card)
{
return _mmcsd_select_card(card->host, card);
}
rt_int32_t mmcsd_deselect_cards(struct rt_mmcsd_card *card)
{
return _mmcsd_select_card(card->host, RT_NULL);
}
rt_int32_t mmcsd_spi_use_crc(struct rt_mmcsd_host *host, rt_int32_t use_crc)
{
struct rt_mmcsd_cmd cmd;
rt_int32_t err;
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = SPI_CRC_ON_OFF;
cmd.flags = RESP_SPI_R1;
cmd.arg = use_crc;
err = mmcsd_send_cmd(host, &cmd, 0);
if (!err)
host->spi_use_crc = use_crc;
return err;
}
rt_inline void mmcsd_set_iocfg(struct rt_mmcsd_host *host)
{
struct rt_mmcsd_io_cfg *io_cfg = &host->io_cfg;
mmcsd_dbg("clock %uHz busmode %u powermode %u cs %u Vdd %u "
"width %u \n",
io_cfg->clock, io_cfg->bus_mode,
io_cfg->power_mode, io_cfg->chip_select, io_cfg->vdd,
io_cfg->bus_width);
host->ops->set_iocfg(host, io_cfg);
}
/*
* Control chip select pin on a host.
*/
void mmcsd_set_chip_select(struct rt_mmcsd_host *host, rt_int32_t mode)
{
host->io_cfg.chip_select = mode;
mmcsd_set_iocfg(host);
}
/*
* Sets the host clock to the highest possible frequency that
* is below "hz".
*/
void mmcsd_set_clock(struct rt_mmcsd_host *host, rt_uint32_t clk)
{
if (clk < host->freq_min)
{
LOG_W("clock too low!");
}
host->io_cfg.clock = clk;
mmcsd_set_iocfg(host);
}
/*
* Change the bus mode (open drain/push-pull) of a host.
*/
void mmcsd_set_bus_mode(struct rt_mmcsd_host *host, rt_uint32_t mode)
{
host->io_cfg.bus_mode = mode;
mmcsd_set_iocfg(host);
}
/*
* Change data bus width of a host.
*/
void mmcsd_set_bus_width(struct rt_mmcsd_host *host, rt_uint32_t width)
{
host->io_cfg.bus_width = width;
mmcsd_set_iocfg(host);
}
void mmcsd_set_timing(struct rt_mmcsd_host *host, rt_uint32_t timing)
{
host->io_cfg.timing = timing;
mmcsd_set_iocfg(host);
}
void mmcsd_set_data_timeout(struct rt_mmcsd_data *data,
const struct rt_mmcsd_card *card)
{
rt_uint32_t mult;
if (card->card_type == CARD_TYPE_SDIO)
{
data->timeout_ns = 1000000000; /* SDIO card 1s */
data->timeout_clks = 0;
return;
}
/*
* SD cards use a 100 multiplier rather than 10
*/
mult = (card->card_type == CARD_TYPE_SD) ? 100 : 10;
/*
* Scale up the multiplier (and therefore the timeout) by
* the r2w factor for writes.
*/
if (data->flags & DATA_DIR_WRITE)
mult <<= card->csd.r2w_factor;
data->timeout_ns = card->tacc_ns * mult;
data->timeout_clks = card->tacc_clks * mult;
/*
* SD cards also have an upper limit on the timeout.
*/
if (card->card_type == CARD_TYPE_SD)
{
rt_uint32_t timeout_us, limit_us;
timeout_us = data->timeout_ns / 1000;
timeout_us += data->timeout_clks * 1000 /
(card->host->io_cfg.clock / 1000);
if (data->flags & DATA_DIR_WRITE)
/*
* The limit is really 250 ms, but that is
* insufficient for some crappy cards.
*/
limit_us = 300000;
else
limit_us = 100000;
/*
* SDHC cards always use these fixed values.
*/
if (timeout_us > limit_us || card->flags & CARD_FLAG_SDHC)
{
data->timeout_ns = limit_us * 1000; /* SDHC card fixed 250ms */
data->timeout_clks = 0;
}
}
if (controller_is_spi(card->host))
{
if (data->flags & DATA_DIR_WRITE)
{
if (data->timeout_ns < 1000000000)
data->timeout_ns = 1000000000; /* 1s */
}
else
{
if (data->timeout_ns < 100000000)
data->timeout_ns = 100000000; /* 100ms */
}
}
}
/*
* Mask off any voltages we don't support and select
* the lowest voltage
*/
rt_uint32_t mmcsd_select_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr)
{
int bit;
extern int __rt_ffs(int value);
ocr &= host->valid_ocr;
bit = __rt_ffs(ocr);
if (bit)
{
bit -= 1;
ocr &= 3 << bit;
host->io_cfg.vdd = bit;
mmcsd_set_iocfg(host);
}
else
{
LOG_W("host doesn't support card's voltages!");
ocr = 0;
}
return ocr;
}
static void mmcsd_power_up(struct rt_mmcsd_host *host)
{
int bit = __rt_fls(host->valid_ocr) - 1;
host->io_cfg.vdd = bit;
if (controller_is_spi(host))
{
host->io_cfg.chip_select = MMCSD_CS_HIGH;
host->io_cfg.bus_mode = MMCSD_BUSMODE_PUSHPULL;
}
else
{
host->io_cfg.chip_select = MMCSD_CS_IGNORE;
host->io_cfg.bus_mode = MMCSD_BUSMODE_OPENDRAIN;
}
host->io_cfg.power_mode = MMCSD_POWER_UP;
host->io_cfg.bus_width = MMCSD_BUS_WIDTH_1;
mmcsd_set_iocfg(host);
/*
* This delay should be sufficient to allow the power supply
* to reach the minimum voltage.
*/
rt_thread_mdelay(10);
host->io_cfg.clock = host->freq_min;
host->io_cfg.power_mode = MMCSD_POWER_ON;
mmcsd_set_iocfg(host);
/*
* This delay must be at least 74 clock sizes, or 1 ms, or the
* time required to reach a stable voltage.
*/
rt_thread_mdelay(10);
}
static void mmcsd_power_off(struct rt_mmcsd_host *host)
{
host->io_cfg.clock = 0;
host->io_cfg.vdd = 0;
if (!controller_is_spi(host))
{
host->io_cfg.bus_mode = MMCSD_BUSMODE_OPENDRAIN;
host->io_cfg.chip_select = MMCSD_CS_IGNORE;
}
host->io_cfg.power_mode = MMCSD_POWER_OFF;
host->io_cfg.bus_width = MMCSD_BUS_WIDTH_1;
mmcsd_set_iocfg(host);
}
int mmcsd_wait_cd_changed(rt_int32_t timeout)
{
struct rt_mmcsd_host *host;
if (rt_mb_recv(&mmcsd_hotpluge_mb, (rt_ubase_t *)&host, timeout) == RT_EOK)
{
if (host->card == RT_NULL)
{
return MMCSD_HOST_UNPLUGED;
}
else
{
return MMCSD_HOST_PLUGED;
}
}
return -RT_ETIMEOUT;
}
RTM_EXPORT(mmcsd_wait_cd_changed);
void mmcsd_change(struct rt_mmcsd_host *host)
{
rt_mb_send(&mmcsd_detect_mb, (rt_ubase_t)host);
}
void mmcsd_detect(void *param)
{
struct rt_mmcsd_host *host;
rt_uint32_t ocr;
rt_int32_t err;
while (1)
{
if (rt_mb_recv(&mmcsd_detect_mb, (rt_ubase_t *)&host, RT_WAITING_FOREVER) == RT_EOK)
{
if (host->card == RT_NULL)
{
mmcsd_host_lock(host);
mmcsd_power_up(host);
mmcsd_go_idle(host);
mmcsd_send_if_cond(host, host->valid_ocr);
err = sdio_io_send_op_cond(host, 0, &ocr);
if (!err)
{
if (init_sdio(host, ocr))
mmcsd_power_off(host);
mmcsd_host_unlock(host);
continue;
}
/*
* detect SD card
*/
err = mmcsd_send_app_op_cond(host, 0, &ocr);
if (!err)
{
if (init_sd(host, ocr))
mmcsd_power_off(host);
mmcsd_host_unlock(host);
rt_mb_send(&mmcsd_hotpluge_mb, (rt_ubase_t)host);
continue;
}
/*
* detect mmc card
*/
err = mmc_send_op_cond(host, 0, &ocr);
if (!err)
{
if (init_mmc(host, ocr))
mmcsd_power_off(host);
mmcsd_host_unlock(host);
rt_mb_send(&mmcsd_hotpluge_mb, (rt_ubase_t)host);
continue;
}
mmcsd_host_unlock(host);
}
else
{
/* card removed */
mmcsd_host_lock(host);
if (host->card->sdio_function_num != 0)
{
LOG_W("unsupport sdio card plug out!");
}
else
{
rt_mmcsd_blk_remove(host->card);
rt_free(host->card);
host->card = RT_NULL;
}
mmcsd_host_unlock(host);
rt_mb_send(&mmcsd_hotpluge_mb, (rt_ubase_t)host);
}
}
}
}
void mmcsd_host_init(struct rt_mmcsd_host *host)
{
rt_memset(host, 0, sizeof(struct rt_mmcsd_host));
strncpy(host->name, "sd", sizeof(host->name) - 1);
host->max_seg_size = 65535;
host->max_dma_segs = 1;
host->max_blk_size = 512;
host->max_blk_count = 4096;
rt_mutex_init(&host->bus_lock, "sd_bus_lock", RT_IPC_FLAG_FIFO);
rt_sem_init(&host->sem_ack, "sd_ack", 0, RT_IPC_FLAG_FIFO);
}
struct rt_mmcsd_host *mmcsd_alloc_host(void)
{
struct rt_mmcsd_host *host;
host = rt_malloc(sizeof(struct rt_mmcsd_host));
if (!host)
{
LOG_E("alloc host failed");
return RT_NULL;
}
mmcsd_host_init(host);
return host;
}
void mmcsd_free_host(struct rt_mmcsd_host *host)
{
rt_mutex_detach(&host->bus_lock);
rt_sem_detach(&host->sem_ack);
rt_free(host);
}
rt_int32_t mmcsd_excute_tuning(struct rt_mmcsd_card *card)
{
struct rt_mmcsd_host *host = card->host;
rt_int32_t opcode;
if (!host->ops->execute_tuning)
return RT_EOK;
if (card->card_type == CARD_TYPE_MMC)
opcode = SEND_TUNING_BLOCK_HS200;
else
opcode = SEND_TUNING_BLOCK;
return host->ops->execute_tuning(host, opcode);;
}
int rt_mmcsd_core_init(void)
{
rt_err_t ret;
/* initialize detect SD cart thread */
/* initialize mailbox and create detect SD card thread */
ret = rt_mb_init(&mmcsd_detect_mb, "mmcsdmb",
&mmcsd_detect_mb_pool[0], sizeof(mmcsd_detect_mb_pool) / sizeof(mmcsd_detect_mb_pool[0]),
RT_IPC_FLAG_FIFO);
RT_ASSERT(ret == RT_EOK);
ret = rt_mb_init(&mmcsd_hotpluge_mb, "mmcsdhotplugmb",
&mmcsd_hotpluge_mb_pool[0], sizeof(mmcsd_hotpluge_mb_pool) / sizeof(mmcsd_hotpluge_mb_pool[0]),
RT_IPC_FLAG_FIFO);
RT_ASSERT(ret == RT_EOK);
ret = rt_thread_init(&mmcsd_detect_thread, "mmcsd_detect", mmcsd_detect, RT_NULL,
&mmcsd_stack[0], RT_MMCSD_STACK_SIZE, RT_MMCSD_THREAD_PREORITY, 20);
if (ret == RT_EOK)
{
rt_thread_startup(&mmcsd_detect_thread);
}
rt_sdio_init();
return 0;
}
INIT_PREV_EXPORT(rt_mmcsd_core_init);

View File

@@ -0,0 +1,869 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-07-25 weety first version
* 2024-05-26 HPMicro add UHS-I support
*/
#include <drivers/mmcsd_core.h>
#include <drivers/sd.h>
#define DBG_TAG "SDIO"
#ifdef RT_SDIO_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif /* RT_SDIO_DEBUG */
#include <rtdbg.h>
static const rt_uint32_t tran_unit[] =
{
10000, 100000, 1000000, 10000000,
0, 0, 0, 0
};
static const rt_uint8_t tran_value[] =
{
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
static const rt_uint32_t tacc_uint[] =
{
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
};
static const rt_uint8_t tacc_value[] =
{
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
rt_inline rt_uint32_t GET_BITS(rt_uint32_t *resp,
rt_uint32_t start,
rt_uint32_t size)
{
const rt_int32_t __size = size;
const rt_uint32_t __mask = (__size < 32 ? 1 << __size : 0) - 1;
const rt_int32_t __off = 3 - ((start) / 32);
const rt_int32_t __shft = (start) & 31;
rt_uint32_t __res;
__res = resp[__off] >> __shft;
if (__size + __shft > 32)
__res |= resp[__off-1] << ((32 - __shft) % 32);
return __res & __mask;
}
static rt_int32_t mmcsd_parse_csd(struct rt_mmcsd_card *card)
{
struct rt_mmcsd_csd *csd = &card->csd;
rt_uint32_t *resp = card->resp_csd;
csd->csd_structure = GET_BITS(resp, 126, 2);
switch (csd->csd_structure)
{
case 0:
csd->taac = GET_BITS(resp, 112, 8);
csd->nsac = GET_BITS(resp, 104, 8);
csd->tran_speed = GET_BITS(resp, 96, 8);
csd->card_cmd_class = GET_BITS(resp, 84, 12);
csd->rd_blk_len = GET_BITS(resp, 80, 4);
csd->rd_blk_part = GET_BITS(resp, 79, 1);
csd->wr_blk_misalign = GET_BITS(resp, 78, 1);
csd->rd_blk_misalign = GET_BITS(resp, 77, 1);
csd->dsr_imp = GET_BITS(resp, 76, 1);
csd->c_size = GET_BITS(resp, 62, 12);
csd->c_size_mult = GET_BITS(resp, 47, 3);
csd->r2w_factor = GET_BITS(resp, 26, 3);
csd->wr_blk_len = GET_BITS(resp, 22, 4);
csd->wr_blk_partial = GET_BITS(resp, 21, 1);
csd->csd_crc = GET_BITS(resp, 1, 7);
card->card_blksize = 1 << csd->rd_blk_len;
card->card_capacity = (csd->c_size + 1) << (csd->c_size_mult + 2);
card->card_capacity *= card->card_blksize;
card->card_capacity >>= 10; /* unit:KB */
card->tacc_clks = csd->nsac * 100;
card->tacc_ns = (tacc_uint[csd->taac&0x07] * tacc_value[(csd->taac&0x78)>>3] + 9) / 10;
card->max_data_rate = tran_unit[csd->tran_speed&0x07] * tran_value[(csd->tran_speed&0x78)>>3];
break;
case 1:
card->flags |= CARD_FLAG_SDHC;
/*This field is fixed to 0Eh, which indicates 1 ms.
The host should not use TAAC, NSAC, and R2W_FACTOR
to calculate timeout and should uses fixed timeout
values for read and write operations*/
csd->taac = GET_BITS(resp, 112, 8);
csd->nsac = GET_BITS(resp, 104, 8);
csd->tran_speed = GET_BITS(resp, 96, 8);
csd->card_cmd_class = GET_BITS(resp, 84, 12);
csd->rd_blk_len = GET_BITS(resp, 80, 4);
csd->rd_blk_part = GET_BITS(resp, 79, 1);
csd->wr_blk_misalign = GET_BITS(resp, 78, 1);
csd->rd_blk_misalign = GET_BITS(resp, 77, 1);
csd->dsr_imp = GET_BITS(resp, 76, 1);
csd->c_size = GET_BITS(resp, 48, 22);
csd->r2w_factor = GET_BITS(resp, 26, 3);
csd->wr_blk_len = GET_BITS(resp, 22, 4);
csd->wr_blk_partial = GET_BITS(resp, 21, 1);
csd->csd_crc = GET_BITS(resp, 1, 7);
card->card_blksize = 512;
card->card_capacity = (csd->c_size + 1) * 512; /* unit:KB */
card->card_sec_cnt = card->card_capacity * 2;
card->tacc_clks = 0;
card->tacc_ns = 0;
card->max_data_rate = tran_unit[csd->tran_speed&0x07] * tran_value[(csd->tran_speed&0x78)>>3];
break;
default:
LOG_E("unrecognised CSD structure version %d!", csd->csd_structure);
return -RT_ERROR;
}
LOG_I("SD card capacity %d KB.", card->card_capacity);
return 0;
}
static rt_int32_t mmcsd_parse_scr(struct rt_mmcsd_card *card)
{
struct rt_sd_scr *scr = &card->scr;
rt_uint32_t resp[4];
resp[3] = card->resp_scr[1];
resp[2] = card->resp_scr[0];
scr->sd_version = GET_BITS(resp, 56, 4);
scr->sd_bus_widths = GET_BITS(resp, 48, 4);
return 0;
}
static rt_int32_t mmcsd_switch(struct rt_mmcsd_card *card)
{
rt_int32_t err;
struct rt_mmcsd_host *host = card->host;
struct rt_mmcsd_req req;
struct rt_mmcsd_cmd cmd;
struct rt_mmcsd_data data;
rt_uint8_t *buf;
buf = (rt_uint8_t*)rt_malloc(64);
if (!buf)
{
LOG_E("alloc memory failed!");
return -RT_ENOMEM;
}
if (card->card_type != CARD_TYPE_SD)
goto err;
if (card->scr.sd_version < SCR_SPEC_VER_1)
goto err;
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = SD_SWITCH;
cmd.arg = 0x00FFFFF1;
cmd.flags = RESP_R1 | CMD_ADTC;
rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
mmcsd_set_data_timeout(&data, card);
data.blksize = 64;
data.blks = 1;
data.flags = DATA_DIR_READ;
data.buf = (rt_uint32_t *)buf;
rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
req.cmd = &cmd;
req.data = &data;
mmcsd_send_request(host, &req);
if (cmd.err || data.err)
{
goto err1;
}
if (buf[13] & 0x02)
card->hs_max_data_rate = 50000000;
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = SD_SWITCH;
rt_uint32_t switch_func_timing;
if ((card->flags & CARD_FLAG_SDR104) && (card->host->flags & MMCSD_SUP_SDR104))
{
switch_func_timing = SD_SWITCH_FUNC_TIMING_SDR104;
}
else if ((card->flags & CARD_FLAG_SDR50) && (card->host->flags & MMCSD_SUP_SDR50))
{
switch_func_timing = SD_SWITCH_FUNC_TIMING_SDR50;
}
else if ((card->flags & CARD_FLAG_DDR50) && (card->host->flags & MMCSD_SUP_DDR50))
{
switch_func_timing = SD_SWITCH_FUNC_TIMING_DDR50;
}
else
{
switch_func_timing = SD_SWITCH_FUNC_TIMING_HS;
}
cmd.arg = 0x80FFFFF0 | switch_func_timing;
cmd.flags = RESP_R1 | CMD_ADTC;
rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
mmcsd_set_data_timeout(&data, card);
data.blksize = 64;
data.blks = 1;
data.flags = DATA_DIR_READ;
data.buf = (rt_uint32_t *)buf;
rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
req.cmd = &cmd;
req.data = &data;
mmcsd_send_request(host, &req);
if (cmd.err || data.err)
{
goto err1;
}
if ((buf[16] & 0xF) != switch_func_timing)
{
LOG_E("switching card to timing mode %d failed!", switch_func_timing);
goto err;
}
switch(switch_func_timing)
{
case SD_SWITCH_FUNC_TIMING_SDR104:
card->flags |= CARD_FLAG_SDR104;
break;
case SD_SWITCH_FUNC_TIMING_SDR50:
card->flags |= CARD_FLAG_SDR50;
break;
case SD_SWITCH_FUNC_TIMING_DDR50:
card->flags |= CARD_FLAG_DDR50;
break;
case SD_SWITCH_FUNC_TIMING_HS:
card->flags |= CARD_FLAG_HIGHSPEED;
break;
default:
/* Default speed */
break;
}
card->max_data_rate = 50000000;
if (switch_func_timing == SD_SWITCH_FUNC_TIMING_SDR104)
{
LOG_I("sd: switch to SDR104 mode\n");
mmcsd_set_timing(card->host, MMCSD_TIMING_UHS_SDR104);
mmcsd_set_clock(card->host, 208000000);
err = mmcsd_excute_tuning(card);
card->max_data_rate = 208000000;
}
else if (switch_func_timing == SD_SWITCH_FUNC_TIMING_SDR50)
{
LOG_I("sd: switch to SDR50 mode\n");
mmcsd_set_timing(card->host, MMCSD_TIMING_UHS_SDR50);
mmcsd_set_clock(card->host, 100000000);
err = mmcsd_excute_tuning(card);
card->max_data_rate = 10000000;
}
else if (switch_func_timing == SD_SWITCH_FUNC_TIMING_DDR50)
{
LOG_I("sd: switch to DDR50 mode\n");
mmcsd_set_timing(card->host, MMCSD_TIMING_UHS_DDR50);
mmcsd_set_clock(card->host, 50000000);
}
else
{
LOG_I("sd: switch to High Speed / SDR25 mode \n");
mmcsd_set_timing(card->host, MMCSD_TIMING_SD_HS);
mmcsd_set_clock(card->host, 50000000);
}
err:
rt_free(buf);
return 0;
err1:
if (cmd.err)
err = cmd.err;
if (data.err)
err = data.err;
return err;
}
static rt_err_t mmcsd_app_cmd(struct rt_mmcsd_host *host,
struct rt_mmcsd_card *card)
{
rt_err_t err;
struct rt_mmcsd_cmd cmd = {0};
cmd.cmd_code = APP_CMD;
if (card)
{
cmd.arg = card->rca << 16;
cmd.flags = RESP_R1 | CMD_AC;
}
else
{
cmd.arg = 0;
cmd.flags = RESP_R1 | CMD_BCR;
}
err = mmcsd_send_cmd(host, &cmd, 0);
if (err)
return err;
/* Check that card supported application commands */
if (!controller_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD))
return -RT_ERROR;
return RT_EOK;
}
rt_err_t mmcsd_send_app_cmd(struct rt_mmcsd_host *host,
struct rt_mmcsd_card *card,
struct rt_mmcsd_cmd *cmd,
int retry)
{
struct rt_mmcsd_req req;
int i;
rt_err_t err;
err = -RT_ERROR;
/*
* We have to resend MMC_APP_CMD for each attempt so
* we cannot use the retries field in mmc_command.
*/
for (i = 0; i <= retry; i++)
{
rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
err = mmcsd_app_cmd(host, card);
if (err)
{
/* no point in retrying; no APP commands allowed */
if (controller_is_spi(host))
{
if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
break;
}
continue;
}
rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
rt_memset(cmd->resp, 0, sizeof(cmd->resp));
req.cmd = cmd;
//cmd->data = NULL;
mmcsd_send_request(host, &req);
err = cmd->err;
if (!cmd->err)
break;
/* no point in retrying illegal APP commands */
if (controller_is_spi(host))
{
if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
break;
}
}
return err;
}
rt_err_t mmcsd_app_set_bus_width(struct rt_mmcsd_card *card, rt_int32_t width)
{
rt_err_t err;
struct rt_mmcsd_cmd cmd;
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = SD_APP_SET_BUS_WIDTH;
cmd.flags = RESP_R1 | CMD_AC;
switch (width)
{
case MMCSD_BUS_WIDTH_1:
cmd.arg = MMCSD_BUS_WIDTH_1;
break;
case MMCSD_BUS_WIDTH_4:
cmd.arg = MMCSD_BUS_WIDTH_4;
break;
default:
return -RT_ERROR;
}
err = mmcsd_send_app_cmd(card->host, card, &cmd, 3);
if (err)
return err;
return RT_EOK;
}
rt_err_t mmcsd_send_app_op_cond(struct rt_mmcsd_host *host,
rt_uint32_t ocr,
rt_uint32_t *rocr)
{
struct rt_mmcsd_cmd cmd;
rt_uint32_t i;
rt_err_t err = RT_EOK;
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = SD_APP_OP_COND;
if (controller_is_spi(host))
cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */
else
cmd.arg = ocr;
cmd.flags = RESP_SPI_R1 | RESP_R3 | CMD_BCR;
for (i = 1000; i; i--)
{
err = mmcsd_send_app_cmd(host, RT_NULL, &cmd, 3);
if (err)
break;
/* if we're just probing, do a single pass */
if (ocr == 0)
break;
/* otherwise wait until reset completes */
if (controller_is_spi(host))
{
if (!(cmd.resp[0] & R1_SPI_IDLE))
break;
}
else
{
if (cmd.resp[0] & CARD_BUSY)
break;
}
err = -RT_ETIMEOUT;
rt_thread_mdelay(10); //delay 10ms
}
if (rocr && !controller_is_spi(host))
*rocr = cmd.resp[0];
return err;
}
/*
* To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
* before SD_APP_OP_COND. This command will harmlessly fail for
* SD 1.0 cards.
*/
rt_err_t mmcsd_send_if_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr)
{
struct rt_mmcsd_cmd cmd;
rt_err_t err;
rt_uint8_t pattern;
cmd.cmd_code = SD_SEND_IF_COND;
cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | 0xAA;
cmd.flags = RESP_SPI_R7 | RESP_R7 | CMD_BCR;
err = mmcsd_send_cmd(host, &cmd, 0);
if (err)
return err;
if (controller_is_spi(host))
pattern = cmd.resp[1] & 0xFF;
else
pattern = cmd.resp[0] & 0xFF;
if (pattern != 0xAA)
return -RT_ERROR;
return RT_EOK;
}
rt_err_t mmcsd_get_card_addr(struct rt_mmcsd_host *host, rt_uint32_t *rca)
{
rt_err_t err;
struct rt_mmcsd_cmd cmd;
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = SD_SEND_RELATIVE_ADDR;
cmd.arg = 0;
cmd.flags = RESP_R6 | CMD_BCR;
err = mmcsd_send_cmd(host, &cmd, 3);
if (err)
return err;
*rca = cmd.resp[0] >> 16;
return RT_EOK;
}
#define be32_to_cpu(x) ((rt_uint32_t)( \
(((rt_uint32_t)(x) & (rt_uint32_t)0x000000ffUL) << 24) | \
(((rt_uint32_t)(x) & (rt_uint32_t)0x0000ff00UL) << 8) | \
(((rt_uint32_t)(x) & (rt_uint32_t)0x00ff0000UL) >> 8) | \
(((rt_uint32_t)(x) & (rt_uint32_t)0xff000000UL) >> 24)))
rt_int32_t mmcsd_get_scr(struct rt_mmcsd_card *card, rt_uint32_t *scr)
{
rt_int32_t err;
struct rt_mmcsd_req req;
struct rt_mmcsd_cmd cmd;
struct rt_mmcsd_data data;
err = mmcsd_app_cmd(card->host, card);
if (err)
return err;
rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
req.cmd = &cmd;
req.data = &data;
cmd.cmd_code = SD_APP_SEND_SCR;
cmd.arg = 0;
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
data.blksize = 8;
data.blks = 1;
data.flags = DATA_DIR_READ;
data.buf = scr;
mmcsd_set_data_timeout(&data, card);
mmcsd_send_request(card->host, &req);
if (cmd.err)
return cmd.err;
if (data.err)
return data.err;
scr[0] = be32_to_cpu(scr[0]);
scr[1] = be32_to_cpu(scr[1]);
return 0;
}
static rt_err_t mmcsd_read_sd_status(struct rt_mmcsd_card *card, rt_uint32_t *sd_status)
{
rt_int32_t err;
struct rt_mmcsd_req req;
struct rt_mmcsd_cmd cmd;
struct rt_mmcsd_data data;
err = mmcsd_app_cmd(card->host, card);
if (err)
return err;
rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
req.cmd = &cmd;
req.data = &data;
cmd.cmd_code = SEND_STATUS;
cmd.arg = 0;
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
data.blksize = 64;
data.blks = 1;
data.flags = DATA_DIR_READ;
data.buf = sd_status;
mmcsd_set_data_timeout(&data, card);
mmcsd_send_request(card->host, &req);
if (cmd.err)
return cmd.err;
if (data.err)
return data.err;
/* Convert endian */
for (uint32_t i=0; i < 8; i++)
{
uint32_t tmp = sd_status[i];
sd_status[i] = sd_status[15 - i];
sd_status[15 - i] = tmp;
}
for (uint32_t i=0; i < 16; i++)
{
sd_status[i] = be32_to_cpu(sd_status[i]);
}
return 0;
}
static rt_err_t sd_switch_voltage(struct rt_mmcsd_host *host)
{
rt_err_t err;
struct rt_mmcsd_cmd cmd = { 0 };
cmd.cmd_code = VOLTAGE_SWITCH;
cmd.arg = 0;
cmd.flags = RESP_R1 | CMD_AC;
err = mmcsd_send_cmd(host, &cmd, 0);
if (err)
return err;
return RT_EOK;
}
static rt_err_t sd_switch_uhs_voltage(struct rt_mmcsd_host *host)
{
if (host->ops->switch_uhs_voltage != RT_NULL)
{
return host->ops->switch_uhs_voltage(host);
}
return -ENOSYS;
}
static rt_int32_t mmcsd_sd_init_card(struct rt_mmcsd_host *host,
rt_uint32_t ocr)
{
struct rt_mmcsd_card *card;
rt_int32_t err;
rt_uint32_t resp[4];
rt_uint32_t max_data_rate;
mmcsd_go_idle(host);
/*
* If SD_SEND_IF_COND indicates an SD 2.0
* compliant card and we should set bit 30
* of the ocr to indicate that we can handle
* block-addressed SDHC cards.
*/
err = mmcsd_send_if_cond(host, ocr);
if (!err)
ocr |= 1 << 30;
/* Switch to UHS voltage if both Host and the Card support this feature */
if (((host->valid_ocr & VDD_165_195) != 0) && (host->ops->switch_uhs_voltage != RT_NULL))
{
ocr |= OCR_S18R;
}
err = mmcsd_send_app_op_cond(host, ocr, &ocr);
if (err)
goto err2;
/* Select voltage */
if (ocr & OCR_S18R)
{
ocr = VDD_165_195;
err = sd_switch_voltage(host);
if (err)
goto err2;
err = sd_switch_uhs_voltage(host);
if (err)
goto err2;
}
if (controller_is_spi(host))
err = mmcsd_get_cid(host, resp);
else
err = mmcsd_all_get_cid(host, resp);
if (err)
goto err2;
card = rt_malloc(sizeof(struct rt_mmcsd_card));
if (!card)
{
LOG_E("malloc card failed!");
err = -RT_ENOMEM;
goto err2;
}
rt_memset(card, 0, sizeof(struct rt_mmcsd_card));
card->card_type = CARD_TYPE_SD;
card->host = host;
rt_memcpy(card->resp_cid, resp, sizeof(card->resp_cid));
/*
* For native busses: get card RCA and quit open drain mode.
*/
if (!controller_is_spi(host))
{
err = mmcsd_get_card_addr(host, &card->rca);
if (err)
goto err1;
mmcsd_set_bus_mode(host, MMCSD_BUSMODE_PUSHPULL);
}
err = mmcsd_get_csd(card, card->resp_csd);
if (err)
goto err1;
err = mmcsd_parse_csd(card);
if (err)
goto err1;
if (!controller_is_spi(host))
{
err = mmcsd_select_card(card);
if (err)
goto err1;
}
err = mmcsd_get_scr(card, card->resp_scr);
if (err)
goto err1;
mmcsd_parse_scr(card);
if (controller_is_spi(host))
{
err = mmcsd_spi_use_crc(host, 1);
if (err)
goto err1;
}
mmcsd_set_timing(host, MMCSD_TIMING_LEGACY);
mmcsd_set_clock(host, 25000000);
/*switch bus width*/
if ((host->flags & MMCSD_BUSWIDTH_4) && (card->scr.sd_bus_widths & SD_SCR_BUS_WIDTH_4))
{
err = mmcsd_app_set_bus_width(card, MMCSD_BUS_WIDTH_4);
if (err)
goto err1;
mmcsd_set_bus_width(host, MMCSD_BUS_WIDTH_4);
}
/* Read and decode SD Status and check whether UHS mode is supported */
union rt_sd_status sd_status;
err = mmcsd_read_sd_status(card, sd_status.status_words);
if (err)
goto err1;
if ((sd_status.uhs_speed_grade > 0) && (ocr & VDD_165_195))
{
/* Assume the card supports all UHS-I modes because we cannot find any mainstreaming card
* that can support only part of the following modes.
*/
card->flags |= CARD_FLAG_SDR50 | CARD_FLAG_SDR104 | CARD_FLAG_DDR50;
}
/*
* change SD card to the highest supported speed
*/
err = mmcsd_switch(card);
if (err)
goto err1;
/* set bus speed */
max_data_rate = (unsigned int)-1;
if (max_data_rate < card->hs_max_data_rate)
{
max_data_rate = card->hs_max_data_rate;
}
if (max_data_rate < card->max_data_rate)
{
max_data_rate = card->max_data_rate;
}
mmcsd_set_clock(host, max_data_rate);
host->card = card;
return 0;
err1:
rt_free(card);
err2:
return err;
}
/*
* Starting point for SD card init.
*/
rt_int32_t init_sd(struct rt_mmcsd_host *host, rt_uint32_t ocr)
{
rt_int32_t err = -RT_EINVAL;
rt_uint32_t current_ocr;
/*
* We need to get OCR a different way for SPI.
*/
if (controller_is_spi(host))
{
mmcsd_go_idle(host);
err = mmcsd_spi_read_ocr(host, 0, &ocr);
if (err)
goto _err;
}
current_ocr = mmcsd_select_voltage(host, ocr);
/*
* Can we support the voltage(s) of the card(s)?
*/
if (!current_ocr)
{
err = -RT_ERROR;
goto _err;
}
/*
* Detect and init the card.
*/
err = mmcsd_sd_init_card(host, current_ocr);
if (err)
goto _err;
mmcsd_host_unlock(host);
err = rt_mmcsd_blk_probe(host->card);
if (err)
goto remove_card;
mmcsd_host_lock(host);
return 0;
remove_card:
mmcsd_host_lock(host);
rt_mmcsd_blk_remove(host->card);
rt_free(host->card);
host->card = RT_NULL;
_err:
LOG_D("init SD card failed!");
return err;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,279 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-11-16 zylx first version.
*/
#include <drivers/spi.h>
rt_err_t rt_qspi_configure(struct rt_qspi_device *device, struct rt_qspi_configuration *cfg)
{
RT_ASSERT(device != RT_NULL);
RT_ASSERT(cfg != RT_NULL);
/* reset the CS pin */
if (device->parent.cs_pin != PIN_NONE)
{
if (cfg->parent.mode & RT_SPI_CS_HIGH)
rt_pin_write(device->parent.cs_pin, PIN_LOW);
else
rt_pin_write(device->parent.cs_pin, PIN_HIGH);
}
/* If the configurations are the same, we don't need to set again. */
if (device->config.medium_size == cfg->medium_size &&
device->config.ddr_mode == cfg->ddr_mode &&
device->config.qspi_dl_width == cfg->qspi_dl_width &&
device->config.parent.data_width == cfg->parent.data_width &&
device->config.parent.mode == (cfg->parent.mode & RT_SPI_MODE_MASK) &&
device->config.parent.max_hz == cfg->parent.max_hz)
{
return RT_EOK;
}
/* copy configuration items */
device->config.parent.mode = cfg->parent.mode;
device->config.parent.max_hz = cfg->parent.max_hz;
device->config.parent.data_width = cfg->parent.data_width;
device->config.parent.reserved = cfg->parent.reserved;
device->config.medium_size = cfg->medium_size;
device->config.ddr_mode = cfg->ddr_mode;
device->config.qspi_dl_width = cfg->qspi_dl_width;
return rt_spi_bus_configure(&device->parent);
}
rt_err_t rt_qspi_bus_register(struct rt_spi_bus *bus, const char *name, const struct rt_spi_ops *ops)
{
rt_err_t result = RT_EOK;
result = rt_spi_bus_register(bus, name, ops);
if(result == RT_EOK)
{
/* set SPI bus to qspi modes */
bus->mode = RT_SPI_BUS_MODE_QSPI;
}
return result;
}
rt_size_t rt_qspi_transfer_message(struct rt_qspi_device *device, struct rt_qspi_message *message)
{
rt_err_t result;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(message != RT_NULL);
result = rt_mutex_take(&(device->parent.bus->lock), RT_WAITING_FOREVER);
if (result != RT_EOK)
{
rt_set_errno(-RT_EBUSY);
return 0;
}
/* reset errno */
rt_set_errno(RT_EOK);
/* configure SPI bus */
if (device->parent.bus->owner != &device->parent)
{
/* not the same owner as current, re-configure SPI bus */
result = device->parent.bus->ops->configure(&device->parent, &device->parent.config);
if (result == RT_EOK)
{
/* set SPI bus owner */
device->parent.bus->owner = &device->parent;
}
else
{
/* configure SPI bus failed */
rt_set_errno(-RT_EIO);
goto __exit;
}
}
/* transmit each SPI message */
result = device->parent.bus->ops->xfer(&device->parent, &message->parent);
if (result == 0)
{
rt_set_errno(-RT_EIO);
}
__exit:
/* release bus lock */
rt_mutex_release(&(device->parent.bus->lock));
return result;
}
rt_err_t rt_qspi_send_then_recv(struct rt_qspi_device *device, const void *send_buf, rt_size_t send_length, void *recv_buf, rt_size_t recv_length)
{
RT_ASSERT(send_buf);
RT_ASSERT(recv_buf);
RT_ASSERT(send_length != 0);
struct rt_qspi_message message;
unsigned char *ptr = (unsigned char *)send_buf;
rt_size_t count = 0;
rt_err_t result = 0;
message.instruction.content = ptr[0];
message.instruction.qspi_lines = 1;
count++;
/* get address */
if (send_length > 1)
{
if (device->config.medium_size > 0x1000000 && send_length >= 5)
{
/* medium size greater than 16Mb, address size is 4 Byte */
message.address.content = (ptr[1] << 24) | (ptr[2] << 16) | (ptr[3] << 8) | (ptr[4]);
message.address.size = 32;
count += 4;
}
else if (send_length >= 4)
{
/* address size is 3 Byte */
message.address.content = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);
message.address.size = 24;
count += 3;
}
else
{
return -RT_ERROR;
}
message.address.qspi_lines = 1;
}
else
{
/* no address stage */
message.address.content = 0 ;
message.address.qspi_lines = 0;
message.address.size = 0;
}
message.alternate_bytes.content = 0;
message.alternate_bytes.size = 0;
message.alternate_bytes.qspi_lines = 0;
/* set dummy cycles */
if (count != send_length)
{
message.dummy_cycles = (send_length - count) * 8;
}
else
{
message.dummy_cycles = 0;
}
/* set recv buf and recv size */
message.parent.recv_buf = recv_buf;
message.parent.send_buf = RT_NULL;
message.parent.length = recv_length;
message.parent.cs_take = 1;
message.parent.cs_release = 1;
message.qspi_data_lines = 1;
result = rt_qspi_transfer_message(device, &message);
if (result == 0)
{
result = -RT_EIO;
}
else
{
result = recv_length;
}
return result;
}
rt_err_t rt_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length)
{
RT_ASSERT(send_buf);
RT_ASSERT(length != 0);
struct rt_qspi_message message;
unsigned char *ptr = (unsigned char *)send_buf;
rt_size_t count = 0;
rt_err_t result = 0;
message.instruction.content = ptr[0];
message.instruction.qspi_lines = 1;
count++;
/* get address */
if (length > 1)
{
if (device->config.medium_size > 0x1000000 && length >= 5)
{
/* medium size greater than 16Mb, address size is 4 Byte */
message.address.content = (ptr[1] << 24) | (ptr[2] << 16) | (ptr[3] << 8) | (ptr[4]);
message.address.size = 32;
message.address.qspi_lines = 1;
count += 4;
}
else if (length >= 4)
{
/* address size is 3 Byte */
message.address.content = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);
message.address.size = 24;
message.address.qspi_lines = 1;
count += 3;
}
else
{
return -RT_ERROR;
}
}
else
{
/* no address stage */
message.address.content = 0 ;
message.address.qspi_lines = 0;
message.address.size = 0;
}
message.alternate_bytes.content = 0;
message.alternate_bytes.size = 0;
message.alternate_bytes.qspi_lines = 0;
message.dummy_cycles = 0;
/* determine if there is data to send */
if (length - count > 0)
{
message.qspi_data_lines = 1;
}
else
{
message.qspi_data_lines = 0;
}
/* set send buf and send size */
message.parent.send_buf = ptr + count;
message.parent.recv_buf = RT_NULL;
message.parent.length = length - count;
message.parent.cs_take = 1;
message.parent.cs_release = 1;
result = rt_qspi_transfer_message(device, &message);
if (result == 0)
{
result = -RT_EIO;
}
else
{
result = length;
}
return result;
}

View File

@@ -0,0 +1,530 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-10-11 kyle first version
*/
#include <spi-bit-ops.h>
#include <rtdevice.h>
#define DBG_TAG "SPI"
#ifdef RT_SPI_BITOPS_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_ERROR
#endif
#include <rtdbg.h>
#define TOG_SCLK(ops) ops->tog_sclk(ops->data)
#define SET_SCLK(ops, val) ops->set_sclk(ops->data, val)
#define SET_MOSI(ops, val) ops->set_mosi(ops->data, val)
#define SET_MISO(ops, val) ops->set_miso(ops->data, val)
#define GET_SCLK(ops) ops->get_sclk(ops->data)
#define GET_MOSI(ops) ops->get_mosi(ops->data)
#define GET_MISO(ops) ops->get_miso(ops->data)
#define DIR_MOSI(ops, val) ops->dir_mosi(ops->data, val)
#define DIR_MISO(ops, val) ops->dir_miso(ops->data, val)
rt_inline void spi_delay(struct rt_spi_bit_ops *ops)
{
ops->udelay((ops->delay_us + 1) >> 1);
}
rt_inline void spi_delay2(struct rt_spi_bit_ops *ops)
{
ops->udelay(ops->delay_us);
}
#define SCLK_H(ops) SET_SCLK(ops, 1)
#define SCLK_L(ops) SET_SCLK(ops, 0)
#define MOSI_H(ops) SET_MOSI(ops, 1)
#define MOSI_L(ops) SET_MOSI(ops, 0)
#define MOSI_IN(ops) DIR_MOSI(ops, 1)
#define MOSI_OUT(ops) DIR_MOSI(ops, 0)
#define MISO_IN(ops) DIR_MISO(ops, 1)
#define MISO_OUT(ops) DIR_MISO(ops, 0)
rt_inline rt_ssize_t spi_xfer_4line_data8(struct rt_spi_bit_ops *ops,
struct rt_spi_configuration *config,
const void *send_buf,
void *recv_buf,
rt_size_t length)
{
int i = 0;
RT_ASSERT(ops != RT_NULL);
RT_ASSERT(length != 0);
{
const rt_uint8_t *send_ptr = send_buf;
rt_uint8_t *recv_ptr = recv_buf;
rt_uint32_t size = length;
while (size--)
{
rt_uint8_t tx_data = 0xFF;
rt_uint8_t rx_data = 0xFF;
rt_uint8_t bit = 0;
if (send_buf != RT_NULL)
{
tx_data = *send_ptr++;
}
for (i = 0; i < 8; i++)
{
if (config->mode & RT_SPI_MSB) { bit = tx_data & (0x1 << (7 - i)); }
else { bit = tx_data & (0x1 << i); }
if (bit) MOSI_H(ops);
else MOSI_L(ops);
spi_delay2(ops);
TOG_SCLK(ops);
if (config->mode & RT_SPI_MSB) { rx_data <<= 1; bit = 0x01; }
else { rx_data >>= 1; bit = 0x80; }
if (GET_MISO(ops)) { rx_data |= bit; }
else { rx_data &= ~bit; }
spi_delay2(ops);
if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 7))
{
TOG_SCLK(ops);
}
}
if (recv_buf != RT_NULL)
{
*recv_ptr++ = rx_data;
}
}
}
return length;
}
rt_inline rt_ssize_t spi_xfer_4line_data16(struct rt_spi_bit_ops *ops,
struct rt_spi_configuration *config,
const void *send_buf,
void *recv_buf,
rt_size_t length)
{
int i = 0;
RT_ASSERT(ops != RT_NULL);
RT_ASSERT(length != 0);
{
const rt_uint16_t *send_ptr = send_buf;
rt_uint16_t *recv_ptr = recv_buf;
rt_uint32_t size = length;
while (size--)
{
rt_uint16_t tx_data = 0xFFFF;
rt_uint16_t rx_data = 0xFFFF;
rt_uint16_t bit = 0;
if (send_buf != RT_NULL)
{
tx_data = *send_ptr++;
}
for (i = 0; i < 16; i++)
{
if (config->mode & RT_SPI_MSB) { bit = tx_data & (0x1 << (15 - i)); }
else { bit = tx_data & (0x1 << i); }
if (bit) MOSI_H(ops);
else MOSI_L(ops);
spi_delay2(ops);
TOG_SCLK(ops);
if (config->mode & RT_SPI_MSB) { rx_data <<= 1; bit = 0x0001; }
else { rx_data >>= 1; bit = 0x8000; }
if (GET_MISO(ops)) { rx_data |= bit; }
else { rx_data &= ~bit; }
spi_delay2(ops);
if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 15))
{
TOG_SCLK(ops);
}
}
if (recv_buf != RT_NULL)
{
*recv_ptr++ = rx_data;
}
}
}
return length;
}
rt_inline rt_ssize_t spi_xfer_3line_data8(struct rt_spi_bit_ops *ops,
struct rt_spi_configuration *config,
const void *send_buf,
void *recv_buf,
rt_size_t length)
{
int i = 0;
RT_ASSERT(ops != RT_NULL);
RT_ASSERT(length != 0);
{
const rt_uint8_t *send_ptr = send_buf;
rt_uint8_t *recv_ptr = recv_buf;
rt_uint32_t size = length;
rt_uint8_t send_flg = 0;
if ((send_buf != RT_NULL) || (recv_buf == RT_NULL))
{
MOSI_OUT(ops);
send_flg = 1;
}
else
{
MOSI_IN(ops);
}
while (size--)
{
rt_uint8_t tx_data = 0xFF;
rt_uint8_t rx_data = 0xFF;
rt_uint8_t bit = 0;
if (send_buf != RT_NULL)
{
tx_data = *send_ptr++;
}
if (send_flg)
{
for (i = 0; i < 8; i++)
{
if (config->mode & RT_SPI_MSB) { bit = tx_data & (0x1 << (7 - i)); }
else { bit = tx_data & (0x1 << i); }
if (bit) MOSI_H(ops);
else MOSI_L(ops);
spi_delay2(ops);
TOG_SCLK(ops);
spi_delay2(ops);
if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 7))
{
TOG_SCLK(ops);
}
}
rx_data = tx_data;
}
else
{
for (i = 0; i < 8; i++)
{
spi_delay2(ops);
TOG_SCLK(ops);
if (config->mode & RT_SPI_MSB) { rx_data <<= 1; bit = 0x01; }
else { rx_data >>= 1; bit = 0x80; }
if (GET_MOSI(ops)) { rx_data |= bit; }
else { rx_data &= ~bit; }
spi_delay2(ops);
if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 7))
{
TOG_SCLK(ops);
}
}
}
if (recv_buf != RT_NULL)
{
*recv_ptr++ = rx_data;
}
}
if (!send_flg)
{
MOSI_OUT(ops);
}
}
return length;
}
rt_inline rt_ssize_t spi_xfer_3line_data16(struct rt_spi_bit_ops *ops,
struct rt_spi_configuration *config,
const void *send_buf,
void *recv_buf,
rt_size_t length)
{
int i = 0;
RT_ASSERT(ops != RT_NULL);
RT_ASSERT(length != 0);
{
const rt_uint16_t *send_ptr = send_buf;
rt_uint16_t *recv_ptr = recv_buf;
rt_uint32_t size = length;
rt_uint8_t send_flg = 0;
if ((send_buf != RT_NULL) || (recv_buf == RT_NULL))
{
MOSI_OUT(ops);
send_flg = 1;
}
else
{
MOSI_IN(ops);
}
while (size--)
{
rt_uint16_t tx_data = 0xFFFF;
rt_uint16_t rx_data = 0xFFFF;
rt_uint16_t bit = 0;
if (send_buf != RT_NULL)
{
tx_data = *send_ptr++;
}
if (send_flg)
{
for (i = 0; i < 16; i++)
{
if (config->mode & RT_SPI_MSB) { bit = tx_data & (0x1 << (15 - i)); }
else { bit = tx_data & (0x1 << i); }
if (bit) MOSI_H(ops);
else MOSI_L(ops);
spi_delay2(ops);
TOG_SCLK(ops);
spi_delay2(ops);
if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 15))
{
TOG_SCLK(ops);
}
}
rx_data = tx_data;
}
else
{
for (i = 0; i < 16; i++)
{
spi_delay2(ops);
TOG_SCLK(ops);
if (config->mode & RT_SPI_MSB) { rx_data <<= 1; bit = 0x0001; }
else { rx_data >>= 1; bit = 0x8000; }
if (GET_MOSI(ops)) { rx_data |= bit; }
else { rx_data &= ~bit; }
spi_delay2(ops);
if (!(config->mode & RT_SPI_CPHA) || (size != 0) || (i < 15))
{
TOG_SCLK(ops);
}
}
}
if (recv_buf != RT_NULL)
{
*recv_ptr++ = rx_data;
}
}
if (!send_flg)
{
MOSI_OUT(ops);
}
}
return length;
}
rt_err_t spi_bit_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration)
{
struct rt_spi_bit_obj *obj = rt_container_of(device->bus, struct rt_spi_bit_obj, bus);
struct rt_spi_bit_ops *ops = obj->ops;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(configuration != RT_NULL);
if(ops->pin_init != RT_NULL)
{
ops->pin_init();
}
if (configuration->mode & RT_SPI_SLAVE)
{
return -RT_EIO;
}
if (configuration->mode & RT_SPI_CPOL)
{
SCLK_H(ops);
}
else
{
SCLK_L(ops);
}
if (configuration->max_hz < 200000)
{
ops->delay_us = 1;
}
else
{
ops->delay_us = 0;
}
rt_memcpy(&obj->config, configuration, sizeof(struct rt_spi_configuration));
return RT_EOK;
}
rt_ssize_t spi_bit_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
{
struct rt_spi_bit_obj *obj = rt_container_of(device->bus, struct rt_spi_bit_obj, bus);
struct rt_spi_bit_ops *ops = obj->ops;
struct rt_spi_configuration *config = &obj->config;
rt_base_t cs_pin = device->cs_pin;
RT_ASSERT(device != NULL);
RT_ASSERT(message != NULL);
#ifdef RT_SPI_BITOPS_DEBUG
if (!ops->tog_sclk || !ops->set_sclk || !ops->get_sclk)
{
LOG_E("SPI bus error, SCLK line not defined");
}
if (!ops->set_mosi || !ops->get_mosi)
{
LOG_E("SPI bus error, MOSI line not defined");
}
if (!ops->set_miso || !ops->get_miso)
{
LOG_E("SPI bus error, MISO line not defined");
}
#endif
/* take CS */
if (message->cs_take && (cs_pin != PIN_NONE))
{
LOG_I("spi take cs\n");
rt_pin_write(cs_pin, PIN_LOW);
spi_delay(ops);
/* spi phase */
if (config->mode & RT_SPI_CPHA)
{
spi_delay(ops);
TOG_SCLK(ops);
}
}
if (config->mode & RT_SPI_3WIRE)
{
if (config->data_width <= 8)
{
spi_xfer_3line_data8(ops,
config,
message->send_buf,
message->recv_buf,
message->length);
}
else if (config->data_width <= 16)
{
spi_xfer_3line_data16(ops,
config,
message->send_buf,
message->recv_buf,
message->length);
}
}
else
{
if (config->data_width <= 8)
{
spi_xfer_4line_data8(ops,
config,
message->send_buf,
message->recv_buf,
message->length);
}
else if (config->data_width <= 16)
{
spi_xfer_4line_data16(ops,
config,
message->send_buf,
message->recv_buf,
message->length);
}
}
/* release CS */
if (message->cs_release && (cs_pin != PIN_NONE))
{
spi_delay(ops);
rt_pin_write(cs_pin, PIN_HIGH);
LOG_I("spi release cs\n");
}
return message->length;
}
static const struct rt_spi_ops spi_bit_bus_ops =
{
.configure = spi_bit_configure,
.xfer = spi_bit_xfer,
};
rt_err_t rt_spi_bit_add_bus(struct rt_spi_bit_obj *obj,
const char *bus_name,
struct rt_spi_bit_ops *ops)
{
obj->ops = ops;
obj->config.data_width = 8;
obj->config.max_hz = 1 * 1000 * 1000;
obj->config.mode = RT_SPI_MASTER | RT_SPI_MSB | RT_SPI_MODE_0;
/* idle status */
if (obj->config.mode & RT_SPI_CPOL) SCLK_H(ops);
else SCLK_L(ops);
return rt_spi_bus_register(&obj->bus, bus_name, &spi_bit_bus_ops);
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-10-11 kyle first version
* 2022-6-14 solar Remove the const attribute of private data in ops
*/
#ifndef __SPI_BIT_OPS_H__
#define __SPI_BIT_OPS_H__
#include <rtdevice.h>
#ifdef __cplusplus
extern "C" {
#endif
struct rt_spi_bit_ops
{
void *data; /* private data for lowlevel routines */
void (*const pin_init)(void);
void (*const tog_sclk)(void *data);
void (*const set_sclk)(void *data, rt_int32_t state);
void (*const set_mosi)(void *data, rt_int32_t state);
void (*const set_miso)(void *data, rt_int32_t state);
rt_int32_t (*const get_sclk)(void *data);
rt_int32_t (*const get_mosi)(void *data);
rt_int32_t (*const get_miso)(void *data);
void (*const dir_mosi)(void *data, rt_int32_t state);
void (*const dir_miso)(void *data, rt_int32_t state);
void (*const udelay)(rt_uint32_t us);
rt_uint32_t delay_us; /* sclk, mosi and miso line delay */
};
struct rt_spi_bit_obj
{
struct rt_spi_bus bus;
struct rt_spi_bit_ops *ops;
struct rt_spi_configuration config;
};
rt_err_t rt_spi_bit_add_bus(struct rt_spi_bit_obj *obj,
const char *bus_name,
struct rt_spi_bit_ops *ops);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,543 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-01-08 bernard first version.
* 2012-02-03 bernard add const attribute to the ops.
* 2012-05-15 dzzxzz fixed the return value in attach_device.
* 2012-05-18 bernard Changed SPI message to message list.
* Added take/release SPI device/bus interface.
* 2012-09-28 aozima fixed rt_spi_release_bus assert error.
*/
#include <drivers/spi.h>
#define DBG_TAG "spi.core"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
extern rt_err_t rt_spi_bus_device_init(struct rt_spi_bus *bus, const char *name);
extern rt_err_t rt_spidev_device_init(struct rt_spi_device *dev, const char *name);
rt_err_t rt_spi_bus_register(struct rt_spi_bus *bus,
const char *name,
const struct rt_spi_ops *ops)
{
rt_err_t result;
result = rt_spi_bus_device_init(bus, name);
if (result != RT_EOK)
return result;
/* initialize mutex lock */
rt_mutex_init(&(bus->lock), name, RT_IPC_FLAG_PRIO);
/* set ops */
bus->ops = ops;
/* initialize owner */
bus->owner = RT_NULL;
/* set bus mode */
bus->mode = RT_SPI_BUS_MODE_SPI;
return RT_EOK;
}
rt_err_t rt_spi_bus_attach_device_cspin(struct rt_spi_device *device,
const char *name,
const char *bus_name,
rt_base_t cs_pin,
void *user_data)
{
rt_err_t result;
rt_device_t bus;
/* get physical spi bus */
bus = rt_device_find(bus_name);
if (bus != RT_NULL && bus->type == RT_Device_Class_SPIBUS)
{
device->bus = (struct rt_spi_bus *)bus;
/* initialize spidev device */
result = rt_spidev_device_init(device, name);
if (result != RT_EOK)
return result;
if(cs_pin != PIN_NONE)
{
rt_pin_mode(cs_pin, PIN_MODE_OUTPUT);
}
rt_memset(&device->config, 0, sizeof(device->config));
device->parent.user_data = user_data;
device->cs_pin = cs_pin;
return RT_EOK;
}
/* not found the host bus */
return -RT_ERROR;
}
rt_err_t rt_spi_bus_attach_device(struct rt_spi_device *device,
const char *name,
const char *bus_name,
void *user_data)
{
return rt_spi_bus_attach_device_cspin(device, name, bus_name, PIN_NONE, user_data);
}
rt_err_t rt_spi_bus_configure(struct rt_spi_device *device)
{
rt_err_t result = -RT_ERROR;
if (device->bus != RT_NULL)
{
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
if (result == RT_EOK)
{
if (device->bus->owner == device)
{
/* current device is using, re-configure SPI bus */
result = device->bus->ops->configure(device, &device->config);
if (result != RT_EOK)
{
/* configure SPI bus failed */
LOG_E("SPI device %s configuration failed", device->parent.parent.name);
}
}
/* release lock */
rt_mutex_release(&(device->bus->lock));
}
}
else
{
result = RT_EOK;
}
return result;
}
rt_err_t rt_spi_configure(struct rt_spi_device *device,
struct rt_spi_configuration *cfg)
{
RT_ASSERT(device != RT_NULL);
RT_ASSERT(cfg != RT_NULL);
/* reset the CS pin */
if (device->cs_pin != PIN_NONE)
{
if (cfg->mode & RT_SPI_CS_HIGH)
rt_pin_write(device->cs_pin, PIN_LOW);
else
rt_pin_write(device->cs_pin, PIN_HIGH);
}
/* If the configurations are the same, we don't need to set again. */
if (device->config.data_width == cfg->data_width &&
device->config.mode == (cfg->mode & RT_SPI_MODE_MASK) &&
device->config.max_hz == cfg->max_hz)
{
return RT_EOK;
}
/* set configuration */
device->config.data_width = cfg->data_width;
device->config.mode = cfg->mode & RT_SPI_MODE_MASK;
device->config.max_hz = cfg->max_hz;
return rt_spi_bus_configure(device);
}
rt_err_t rt_spi_send_then_send(struct rt_spi_device *device,
const void *send_buf1,
rt_size_t send_length1,
const void *send_buf2,
rt_size_t send_length2)
{
rt_err_t result;
struct rt_spi_message message;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
if (result == RT_EOK)
{
if (device->bus->owner != device)
{
/* not the same owner as current, re-configure SPI bus */
result = device->bus->ops->configure(device, &device->config);
if (result == RT_EOK)
{
/* set SPI bus owner */
device->bus->owner = device;
}
else
{
/* configure SPI bus failed */
LOG_E("SPI device %s configuration failed", device->parent.parent.name);
goto __exit;
}
}
/* send data1 */
message.send_buf = send_buf1;
message.recv_buf = RT_NULL;
message.length = send_length1;
message.cs_take = 1;
message.cs_release = 0;
message.next = RT_NULL;
result = device->bus->ops->xfer(device, &message);
if (result < 0)
{
LOG_E("SPI device %s transfer failed", device->parent.parent.name);
goto __exit;
}
/* send data2 */
message.send_buf = send_buf2;
message.recv_buf = RT_NULL;
message.length = send_length2;
message.cs_take = 0;
message.cs_release = 1;
message.next = RT_NULL;
result = device->bus->ops->xfer(device, &message);
if (result < 0)
{
LOG_E("SPI device %s transfer failed", device->parent.parent.name);
goto __exit;
}
result = RT_EOK;
}
else
{
return -RT_EIO;
}
__exit:
rt_mutex_release(&(device->bus->lock));
return result;
}
rt_err_t rt_spi_send_then_recv(struct rt_spi_device *device,
const void *send_buf,
rt_size_t send_length,
void *recv_buf,
rt_size_t recv_length)
{
rt_err_t result;
struct rt_spi_message message;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
if (result == RT_EOK)
{
if (device->bus->owner != device)
{
/* not the same owner as current, re-configure SPI bus */
result = device->bus->ops->configure(device, &device->config);
if (result == RT_EOK)
{
/* set SPI bus owner */
device->bus->owner = device;
}
else
{
/* configure SPI bus failed */
LOG_E("SPI device %s configuration failed", device->parent.parent.name);
goto __exit;
}
}
/* send data */
message.send_buf = send_buf;
message.recv_buf = RT_NULL;
message.length = send_length;
message.cs_take = 1;
message.cs_release = 0;
message.next = RT_NULL;
result = device->bus->ops->xfer(device, &message);
if (result < 0)
{
LOG_E("SPI device %s transfer failed", device->parent.parent.name);
goto __exit;
}
/* recv data */
message.send_buf = RT_NULL;
message.recv_buf = recv_buf;
message.length = recv_length;
message.cs_take = 0;
message.cs_release = 1;
message.next = RT_NULL;
result = device->bus->ops->xfer(device, &message);
if (result < 0)
{
LOG_E("SPI device %s transfer failed", device->parent.parent.name);
goto __exit;
}
result = RT_EOK;
}
else
{
return -RT_EIO;
}
__exit:
rt_mutex_release(&(device->bus->lock));
return result;
}
rt_ssize_t rt_spi_transfer(struct rt_spi_device *device,
const void *send_buf,
void *recv_buf,
rt_size_t length)
{
rt_ssize_t result;
struct rt_spi_message message;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
if (result == RT_EOK)
{
if (device->bus->owner != device)
{
/* not the same owner as current, re-configure SPI bus */
result = device->bus->ops->configure(device, &device->config);
if (result == RT_EOK)
{
/* set SPI bus owner */
device->bus->owner = device;
}
else
{
/* configure SPI bus failed */
LOG_E("SPI device %s configuration failed", device->parent.parent.name);
goto __exit;
}
}
/* initial message */
message.send_buf = send_buf;
message.recv_buf = recv_buf;
message.length = length;
message.cs_take = 1;
message.cs_release = 1;
message.next = RT_NULL;
/* transfer message */
result = device->bus->ops->xfer(device, &message);
if (result < 0)
{
LOG_E("SPI device %s transfer failed", device->parent.parent.name);
goto __exit;
}
}
else
{
return -RT_EIO;
}
__exit:
rt_mutex_release(&(device->bus->lock));
return result;
}
rt_err_t rt_spi_sendrecv8(struct rt_spi_device *device,
rt_uint8_t senddata,
rt_uint8_t *recvdata)
{
rt_ssize_t len = rt_spi_transfer(device, &senddata, recvdata, 1);
if (len < 0)
{
return (rt_err_t)len;
}
else
{
return RT_EOK;
}
}
rt_err_t rt_spi_sendrecv16(struct rt_spi_device *device,
rt_uint16_t senddata,
rt_uint16_t *recvdata)
{
rt_ssize_t len;
rt_uint16_t tmp;
if (device->config.mode & RT_SPI_MSB)
{
tmp = ((senddata & 0xff00) >> 8) | ((senddata & 0x00ff) << 8);
senddata = tmp;
}
len = rt_spi_transfer(device, &senddata, recvdata, 2);
if(len < 0)
{
return (rt_err_t)len;
}
if (device->config.mode & RT_SPI_MSB)
{
tmp = ((*recvdata & 0xff00) >> 8) | ((*recvdata & 0x00ff) << 8);
*recvdata = tmp;
}
return RT_EOK;
}
struct rt_spi_message *rt_spi_transfer_message(struct rt_spi_device *device,
struct rt_spi_message *message)
{
rt_err_t result;
struct rt_spi_message *index;
RT_ASSERT(device != RT_NULL);
/* get first message */
index = message;
if (index == RT_NULL)
return index;
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
if (result != RT_EOK)
{
return index;
}
/* configure SPI bus */
if (device->bus->owner != device)
{
/* not the same owner as current, re-configure SPI bus */
result = device->bus->ops->configure(device, &device->config);
if (result == RT_EOK)
{
/* set SPI bus owner */
device->bus->owner = device;
}
else
{
/* configure SPI bus failed */
goto __exit;
}
}
/* transmit each SPI message */
while (index != RT_NULL)
{
/* transmit SPI message */
result = device->bus->ops->xfer(device, index);
if (result < 0)
{
break;
}
index = index->next;
}
__exit:
/* release bus lock */
rt_mutex_release(&(device->bus->lock));
return index;
}
rt_err_t rt_spi_take_bus(struct rt_spi_device *device)
{
rt_err_t result = RT_EOK;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
if (result != RT_EOK)
{
return -RT_EBUSY;
}
/* configure SPI bus */
if (device->bus->owner != device)
{
/* not the same owner as current, re-configure SPI bus */
result = device->bus->ops->configure(device, &device->config);
if (result == RT_EOK)
{
/* set SPI bus owner */
device->bus->owner = device;
}
else
{
/* configure SPI bus failed */
rt_mutex_release(&(device->bus->lock));
return result;
}
}
return result;
}
rt_err_t rt_spi_release_bus(struct rt_spi_device *device)
{
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
RT_ASSERT(device->bus->owner == device);
/* release lock */
return rt_mutex_release(&(device->bus->lock));
}
rt_err_t rt_spi_take(struct rt_spi_device *device)
{
rt_ssize_t result;
struct rt_spi_message message;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
rt_memset(&message, 0, sizeof(message));
message.cs_take = 1;
result = device->bus->ops->xfer(device, &message);
if(result < 0)
{
return (rt_err_t)result;
}
return RT_EOK;
}
rt_err_t rt_spi_release(struct rt_spi_device *device)
{
rt_ssize_t result;
struct rt_spi_message message;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
rt_memset(&message, 0, sizeof(message));
message.cs_release = 1;
result = device->bus->ops->xfer(device, &message);
if(result < 0)
{
return (rt_err_t)result;
}
return RT_EOK;
}

View File

@@ -0,0 +1,157 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#include <rtthread.h>
#include <drivers/spi.h>
/* SPI bus device interface, compatible with RT-Thread 0.3.x/1.0.x */
static rt_ssize_t _spi_bus_device_read(rt_device_t dev,
rt_off_t pos,
void *buffer,
rt_size_t size)
{
struct rt_spi_bus *bus;
bus = (struct rt_spi_bus *)dev;
RT_ASSERT(bus != RT_NULL);
RT_ASSERT(bus->owner != RT_NULL);
return rt_spi_transfer(bus->owner, RT_NULL, buffer, size);
}
static rt_ssize_t _spi_bus_device_write(rt_device_t dev,
rt_off_t pos,
const void *buffer,
rt_size_t size)
{
struct rt_spi_bus *bus;
bus = (struct rt_spi_bus *)dev;
RT_ASSERT(bus != RT_NULL);
RT_ASSERT(bus->owner != RT_NULL);
return rt_spi_transfer(bus->owner, buffer, RT_NULL, size);
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops spi_bus_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
_spi_bus_device_read,
_spi_bus_device_write,
RT_NULL
};
#endif
rt_err_t rt_spi_bus_device_init(struct rt_spi_bus *bus, const char *name)
{
struct rt_device *device;
RT_ASSERT(bus != RT_NULL);
device = &bus->parent;
/* set device type */
device->type = RT_Device_Class_SPIBUS;
/* initialize device interface */
#ifdef RT_USING_DEVICE_OPS
device->ops = &spi_bus_ops;
#else
device->init = RT_NULL;
device->open = RT_NULL;
device->close = RT_NULL;
device->read = _spi_bus_device_read;
device->write = _spi_bus_device_write;
device->control = RT_NULL;
#endif
/* register to device manager */
return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
}
/* SPI Dev device interface, compatible with RT-Thread 0.3.x/1.0.x */
static rt_ssize_t _spidev_device_read(rt_device_t dev,
rt_off_t pos,
void *buffer,
rt_size_t size)
{
struct rt_spi_device *device;
device = (struct rt_spi_device *)dev;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
return rt_spi_transfer(device, RT_NULL, buffer, size);
}
static rt_ssize_t _spidev_device_write(rt_device_t dev,
rt_off_t pos,
const void *buffer,
rt_size_t size)
{
struct rt_spi_device *device;
device = (struct rt_spi_device *)dev;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
return rt_spi_transfer(device, buffer, RT_NULL, size);
}
static rt_err_t _spidev_device_control(rt_device_t dev,
int cmd,
void *args)
{
switch (cmd)
{
case 0: /* set device */
break;
case 1:
break;
}
return RT_EOK;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops spi_device_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
_spidev_device_read,
_spidev_device_write,
_spidev_device_control
};
#endif
rt_err_t rt_spidev_device_init(struct rt_spi_device *dev, const char *name)
{
struct rt_device *device;
RT_ASSERT(dev != RT_NULL);
device = &(dev->parent);
/* set device type */
device->type = RT_Device_Class_SPIDevice;
#ifdef RT_USING_DEVICE_OPS
device->ops = &spi_device_ops;
#else
device->init = RT_NULL;
device->open = RT_NULL;
device->close = RT_NULL;
device->read = _spidev_device_read;
device->write = _spidev_device_write;
device->control = _spidev_device_control;
#endif
/* register to device manager */
return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2016/5/20 bernard the first version
* 2020/1/7 redoc add include
*/
#ifndef SPI_FLASH_H__
#define SPI_FLASH_H__
#include <rtdevice.h>
struct spi_flash_device
{
struct rt_device flash_device;
struct rt_device_blk_geometry geometry;
struct rt_spi_device * rt_spi_device;
struct rt_mutex lock;
void * user_data;
};
typedef struct spi_flash_device *rt_spi_flash_device_t;
#ifdef RT_USING_MTD_NOR
struct spi_flash_mtd
{
struct rt_mtd_nor_device mtd_device;
struct rt_spi_device * rt_spi_device;
struct rt_mutex lock;
void * user_data;
};
#endif
#endif

View File

@@ -0,0 +1,779 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2016-09-28 armink first version.
*/
#include <stdint.h>
#include <string.h>
#include <rtdevice.h>
#include "spi_flash.h"
#include "spi_flash_sfud.h"
#ifdef RT_USING_SFUD
#ifndef RT_SFUD_DEFAULT_SPI_CFG
#ifndef RT_SFUD_SPI_MAX_HZ
#define RT_SFUD_SPI_MAX_HZ 50000000
#endif
/* read the JEDEC SFDP command must run at 50 MHz or less */
#define RT_SFUD_DEFAULT_SPI_CFG \
{ \
.mode = RT_SPI_MODE_0 | RT_SPI_MSB, \
.data_width = 8, \
.max_hz = RT_SFUD_SPI_MAX_HZ, \
}
#endif /* RT_SFUD_DEFAULT_SPI_CFG */
#ifdef SFUD_USING_QSPI
#define RT_SFUD_DEFAULT_QSPI_CFG \
{ \
RT_SFUD_DEFAULT_SPI_CFG, \
.medium_size = 0x800000, \
.ddr_mode = 0, \
.qspi_dl_width = 4, \
}
#endif /* SFUD_USING_QSPI */
static rt_err_t rt_sfud_control(rt_device_t dev, int cmd, void *args) {
RT_ASSERT(dev);
switch (cmd) {
case RT_DEVICE_CTRL_BLK_GETGEOME: {
struct rt_device_blk_geometry *geometry = (struct rt_device_blk_geometry *) args;
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
if (rtt_dev == RT_NULL || geometry == RT_NULL) {
return -RT_ERROR;
}
geometry->bytes_per_sector = rtt_dev->geometry.bytes_per_sector;
geometry->sector_count = rtt_dev->geometry.sector_count;
geometry->block_size = rtt_dev->geometry.block_size;
break;
}
case RT_DEVICE_CTRL_BLK_ERASE: {
rt_uint32_t *addrs = (rt_uint32_t *) args, start_addr = addrs[0], end_addr = addrs[1], phy_start_addr;
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
rt_size_t phy_size;
if (addrs == RT_NULL || start_addr > end_addr || rtt_dev == RT_NULL || sfud_dev == RT_NULL) {
return -RT_ERROR;
}
if (end_addr == start_addr) {
end_addr ++;
}
phy_start_addr = start_addr * rtt_dev->geometry.bytes_per_sector;
phy_size = (end_addr - start_addr) * rtt_dev->geometry.bytes_per_sector;
if (sfud_erase(sfud_dev, phy_start_addr, phy_size) != SFUD_SUCCESS) {
return -RT_ERROR;
}
break;
}
}
return RT_EOK;
}
static rt_ssize_t rt_sfud_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) {
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
RT_ASSERT(dev);
RT_ASSERT(rtt_dev);
RT_ASSERT(sfud_dev);
/* change the block device's logic address to physical address */
rt_off_t phy_pos = pos * rtt_dev->geometry.bytes_per_sector;
rt_size_t phy_size = size * rtt_dev->geometry.bytes_per_sector;
if (sfud_read(sfud_dev, phy_pos, phy_size, buffer) != SFUD_SUCCESS) {
return 0;
} else {
return size;
}
}
static rt_ssize_t rt_sfud_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) {
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
RT_ASSERT(dev);
RT_ASSERT(rtt_dev);
RT_ASSERT(sfud_dev);
/* change the block device's logic address to physical address */
rt_off_t phy_pos = pos * rtt_dev->geometry.bytes_per_sector;
rt_size_t phy_size = size * rtt_dev->geometry.bytes_per_sector;
if (sfud_erase_write(sfud_dev, phy_pos, phy_size, buffer) != SFUD_SUCCESS) {
return 0;
} else {
return size;
}
}
/**
* SPI write data then read data
*/
static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
size_t read_size) {
sfud_err result = SFUD_SUCCESS;
sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
RT_ASSERT(spi);
RT_ASSERT(sfud_dev);
RT_ASSERT(rtt_dev);
#ifdef SFUD_USING_QSPI
struct rt_qspi_device *qspi_dev = RT_NULL;
#endif
if (write_size) {
RT_ASSERT(write_buf);
}
if (read_size) {
RT_ASSERT(read_buf);
}
#ifdef SFUD_USING_QSPI
if(rtt_dev->rt_spi_device->bus->mode & RT_SPI_BUS_MODE_QSPI) {
qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device);
if (write_size && read_size) {
if (rt_qspi_send_then_recv(qspi_dev, write_buf, write_size, read_buf, read_size) <= 0) {
result = SFUD_ERR_TIMEOUT;
}
} else if (write_size) {
if (rt_qspi_send(qspi_dev, write_buf, write_size) <= 0) {
result = SFUD_ERR_TIMEOUT;
}
}
}
else
#endif
{
if (write_size && read_size) {
if (rt_spi_send_then_recv(rtt_dev->rt_spi_device, write_buf, write_size, read_buf, read_size) != RT_EOK) {
result = SFUD_ERR_TIMEOUT;
}
} else if (write_size) {
if (rt_spi_send(rtt_dev->rt_spi_device, write_buf, write_size) <= 0) {
result = SFUD_ERR_TIMEOUT;
}
} else {
if (rt_spi_recv(rtt_dev->rt_spi_device, read_buf, read_size) <= 0) {
result = SFUD_ERR_TIMEOUT;
}
}
}
return result;
}
#ifdef SFUD_USING_QSPI
/**
* QSPI fast read data
*/
static sfud_err qspi_read(const struct __sfud_spi *spi, uint32_t addr, sfud_qspi_read_cmd_format *qspi_read_cmd_format, uint8_t *read_buf, size_t read_size) {
struct rt_qspi_message message;
sfud_err result = SFUD_SUCCESS;
sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
struct rt_qspi_device *qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device);
RT_ASSERT(spi);
RT_ASSERT(sfud_dev);
RT_ASSERT(rtt_dev);
RT_ASSERT(qspi_dev);
/* set message struct */
message.instruction.content = qspi_read_cmd_format->instruction;
message.instruction.qspi_lines = qspi_read_cmd_format->instruction_lines;
message.address.content = addr;
message.address.size = qspi_read_cmd_format->address_size;
message.address.qspi_lines = qspi_read_cmd_format->address_lines;
message.alternate_bytes.content = 0;
message.alternate_bytes.size = 0;
message.alternate_bytes.qspi_lines = 0;
message.dummy_cycles = qspi_read_cmd_format->dummy_cycles;
message.parent.send_buf = RT_NULL;
message.parent.recv_buf = read_buf;
message.parent.length = read_size;
message.parent.cs_release = 1;
message.parent.cs_take = 1;
message.qspi_data_lines = qspi_read_cmd_format->data_lines;
if (rt_qspi_transfer_message(qspi_dev, &message) != read_size) {
result = SFUD_ERR_TIMEOUT;
}
return result;
}
#endif
static void spi_lock(const sfud_spi *spi) {
sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
RT_ASSERT(spi);
RT_ASSERT(sfud_dev);
RT_ASSERT(rtt_dev);
rt_mutex_take(&(rtt_dev->lock), RT_WAITING_FOREVER);
}
static void spi_unlock(const sfud_spi *spi) {
sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
RT_ASSERT(spi);
RT_ASSERT(sfud_dev);
RT_ASSERT(rtt_dev);
rt_mutex_release(&(rtt_dev->lock));
}
static void retry_delay_100us(void) {
/* 100 microsecond delay */
rt_thread_delay((RT_TICK_PER_SECOND * 1 + 9999) / 10000);
}
sfud_err sfud_spi_port_init(sfud_flash *flash) {
sfud_err result = SFUD_SUCCESS;
RT_ASSERT(flash);
/* port SPI device interface */
flash->spi.wr = spi_write_read;
#ifdef SFUD_USING_QSPI
flash->spi.qspi_read = qspi_read;
#endif
flash->spi.lock = spi_lock;
flash->spi.unlock = spi_unlock;
flash->spi.user_data = flash;
if (RT_TICK_PER_SECOND < 1000) {
LOG_W("[SFUD] Warning: The OS tick(%d) is less than 1000. So the flash write will take more time.", RT_TICK_PER_SECOND);
}
/* 100 microsecond delay */
flash->retry.delay = retry_delay_100us;
/* 60 seconds timeout */
flash->retry.times = 60 * 10000;
return result;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops flash_device_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
rt_sfud_read,
rt_sfud_write,
rt_sfud_control
};
#endif
/**
* Probe SPI flash by SFUD (Serial Flash Universal Driver) driver library and though SPI device by specified configuration.
*
* @param spi_flash_dev_name the name which will create SPI flash device
* @param spi_dev_name using SPI device name
* @param spi_cfg SPI device configuration
* @param qspi_cfg QSPI device configuration
*
* @return probed SPI flash device, probe failed will return RT_NULL
*/
rt_spi_flash_device_t rt_sfud_flash_probe_ex(const char *spi_flash_dev_name, const char *spi_dev_name,
struct rt_spi_configuration *spi_cfg, struct rt_qspi_configuration *qspi_cfg)
{
rt_spi_flash_device_t rtt_dev = RT_NULL;
sfud_flash *sfud_dev = RT_NULL;
char *spi_flash_dev_name_bak = RT_NULL, *spi_dev_name_bak = RT_NULL;
extern sfud_err sfud_device_init(sfud_flash *flash);
#ifdef SFUD_USING_QSPI
struct rt_qspi_device *qspi_dev = RT_NULL;
#endif
RT_ASSERT(spi_flash_dev_name);
RT_ASSERT(spi_dev_name);
rtt_dev = (rt_spi_flash_device_t) rt_malloc(sizeof(struct spi_flash_device));
sfud_dev = (sfud_flash_t) rt_malloc(sizeof(sfud_flash));
spi_flash_dev_name_bak = (char *) rt_malloc(rt_strlen(spi_flash_dev_name) + 1);
spi_dev_name_bak = (char *) rt_malloc(rt_strlen(spi_dev_name) + 1);
if (rtt_dev) {
rt_memset(rtt_dev, 0, sizeof(struct spi_flash_device));
/* initialize lock */
rt_mutex_init(&(rtt_dev->lock), spi_flash_dev_name, RT_IPC_FLAG_PRIO);
}
if (rtt_dev && sfud_dev && spi_flash_dev_name_bak && spi_dev_name_bak) {
rt_memset(sfud_dev, 0, sizeof(sfud_flash));
rt_strncpy(spi_flash_dev_name_bak, spi_flash_dev_name, rt_strlen(spi_flash_dev_name));
rt_strncpy(spi_dev_name_bak, spi_dev_name, rt_strlen(spi_dev_name));
/* make string end sign */
spi_flash_dev_name_bak[rt_strlen(spi_flash_dev_name)] = '\0';
spi_dev_name_bak[rt_strlen(spi_dev_name)] = '\0';
/* SPI configure */
{
/* RT-Thread SPI device initialize */
rtt_dev->rt_spi_device = (struct rt_spi_device *) rt_device_find(spi_dev_name);
if (rtt_dev->rt_spi_device == RT_NULL || rtt_dev->rt_spi_device->parent.type != RT_Device_Class_SPIDevice) {
LOG_E("ERROR: SPI device %s not found!", spi_dev_name);
goto error;
}
sfud_dev->spi.name = spi_dev_name_bak;
#ifdef SFUD_USING_QSPI
/* set the qspi line number and configure the QSPI bus */
if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) {
qspi_dev = (struct rt_qspi_device *)rtt_dev->rt_spi_device;
qspi_cfg->qspi_dl_width = qspi_dev->config.qspi_dl_width;
rt_qspi_configure(qspi_dev, qspi_cfg);
}
else
#endif
rt_spi_configure(rtt_dev->rt_spi_device, spi_cfg);
}
/* SFUD flash device initialize */
{
sfud_dev->name = spi_flash_dev_name_bak;
/* accessed each other */
rtt_dev->user_data = sfud_dev;
rtt_dev->rt_spi_device->user_data = rtt_dev;
rtt_dev->flash_device.user_data = rtt_dev;
sfud_dev->user_data = rtt_dev;
/* initialize SFUD device */
if (sfud_device_init(sfud_dev) != SFUD_SUCCESS) {
LOG_E("ERROR: SPI flash probe failed by SPI device %s.", spi_dev_name);
goto error;
}
/* when initialize success, then copy SFUD flash device's geometry to RT-Thread SPI flash device */
rtt_dev->geometry.sector_count = sfud_dev->chip.capacity / sfud_dev->chip.erase_gran;
rtt_dev->geometry.bytes_per_sector = sfud_dev->chip.erase_gran;
rtt_dev->geometry.block_size = sfud_dev->chip.erase_gran;
#ifdef SFUD_USING_QSPI
/* reconfigure the QSPI bus for medium size */
if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) {
qspi_cfg->medium_size = sfud_dev->chip.capacity;
rt_qspi_configure(qspi_dev, qspi_cfg);
if(qspi_dev->enter_qspi_mode != RT_NULL)
qspi_dev->enter_qspi_mode(qspi_dev);
/* set data lines width */
sfud_qspi_fast_read_enable(sfud_dev, qspi_dev->config.qspi_dl_width);
}
#endif /* SFUD_USING_QSPI */
}
/* register device */
rtt_dev->flash_device.type = RT_Device_Class_Block;
#ifdef RT_USING_DEVICE_OPS
rtt_dev->flash_device.ops = &flash_device_ops;
#else
rtt_dev->flash_device.init = RT_NULL;
rtt_dev->flash_device.open = RT_NULL;
rtt_dev->flash_device.close = RT_NULL;
rtt_dev->flash_device.read = rt_sfud_read;
rtt_dev->flash_device.write = rt_sfud_write;
rtt_dev->flash_device.control = rt_sfud_control;
#endif
rt_device_register(&(rtt_dev->flash_device), spi_flash_dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
LOG_I("Probe SPI flash %s by SPI device %s success.",spi_flash_dev_name, spi_dev_name);
return rtt_dev;
} else {
LOG_E("ERROR: Low memory.");
goto error;
}
error:
if (rtt_dev) {
rt_mutex_detach(&(rtt_dev->lock));
}
/* may be one of objects memory was malloc success, so need free all */
rt_free(rtt_dev);
rt_free(sfud_dev);
rt_free(spi_flash_dev_name_bak);
rt_free(spi_dev_name_bak);
return RT_NULL;
}
/**
* Probe SPI flash by SFUD(Serial Flash Universal Driver) driver library and though SPI device.
*
* @param spi_flash_dev_name the name which will create SPI flash device
* @param spi_dev_name using SPI device name
*
* @return probed SPI flash device, probe failed will return RT_NULL
*/
rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const char *spi_dev_name)
{
struct rt_spi_configuration cfg = RT_SFUD_DEFAULT_SPI_CFG;
#ifndef SFUD_USING_QSPI
return rt_sfud_flash_probe_ex(spi_flash_dev_name, spi_dev_name, &cfg, RT_NULL);
#else
struct rt_qspi_configuration qspi_cfg = RT_SFUD_DEFAULT_QSPI_CFG;
return rt_sfud_flash_probe_ex(spi_flash_dev_name, spi_dev_name, &cfg, &qspi_cfg);
#endif
}
/**
* Delete SPI flash device
*
* @param spi_flash_dev SPI flash device
*
* @return the operation status, RT_EOK on successful
*/
rt_err_t rt_sfud_flash_delete(rt_spi_flash_device_t spi_flash_dev) {
sfud_flash *sfud_flash_dev = (sfud_flash *) (spi_flash_dev->user_data);
RT_ASSERT(spi_flash_dev);
RT_ASSERT(sfud_flash_dev);
rt_device_unregister(&(spi_flash_dev->flash_device));
rt_mutex_detach(&(spi_flash_dev->lock));
rt_free(sfud_flash_dev->spi.name);
rt_free(sfud_flash_dev->name);
rt_free(sfud_flash_dev);
rt_free(spi_flash_dev);
return RT_EOK;
}
sfud_flash_t rt_sfud_flash_find(const char *spi_dev_name)
{
rt_spi_flash_device_t rtt_dev = RT_NULL;
struct rt_spi_device *rt_spi_device = RT_NULL;
sfud_flash_t sfud_dev = RT_NULL;
rt_spi_device = (struct rt_spi_device *) rt_device_find(spi_dev_name);
if (rt_spi_device == RT_NULL || rt_spi_device->parent.type != RT_Device_Class_SPIDevice) {
LOG_E("ERROR: SPI device %s not found!", spi_dev_name);
goto __error;
}
rtt_dev = (rt_spi_flash_device_t) (rt_spi_device->user_data);
if (rtt_dev && rtt_dev->user_data) {
sfud_dev = (sfud_flash_t) (rtt_dev->user_data);
return sfud_dev;
} else {
LOG_E("ERROR: SFUD flash device not found!");
goto __error;
}
__error:
return RT_NULL;
}
sfud_flash_t rt_sfud_flash_find_by_dev_name(const char *flash_dev_name)
{
rt_spi_flash_device_t rtt_dev = RT_NULL;
sfud_flash_t sfud_dev = RT_NULL;
rtt_dev = (rt_spi_flash_device_t) rt_device_find(flash_dev_name);
if (rtt_dev == RT_NULL || rtt_dev->flash_device.type != RT_Device_Class_Block) {
LOG_E("ERROR: Flash device %s not found!", flash_dev_name);
goto __error;
}
if (rtt_dev->user_data) {
sfud_dev = (sfud_flash_t) (rtt_dev->user_data);
return sfud_dev;
} else {
LOG_E("ERROR: SFUD flash device not found!");
goto __error;
}
__error:
return RT_NULL;
}
#if defined(RT_USING_FINSH)
#include <finsh.h>
static void sf(uint8_t argc, char **argv) {
#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
#define HEXDUMP_WIDTH 16
#define CMD_PROBE_INDEX 0
#define CMD_READ_INDEX 1
#define CMD_WRITE_INDEX 2
#define CMD_ERASE_INDEX 3
#define CMD_RW_STATUS_INDEX 4
#define CMD_BENCH_INDEX 5
sfud_err result = SFUD_SUCCESS;
static const sfud_flash *sfud_dev = NULL;
static rt_spi_flash_device_t rtt_dev = NULL, rtt_dev_bak = NULL;
size_t i = 0, j = 0;
const char* sf_help_info[] = {
[CMD_PROBE_INDEX] = "sf probe [spi_device] - probe and init SPI flash by given 'spi_device'",
[CMD_READ_INDEX] = "sf read addr size - read 'size' bytes starting at 'addr'",
[CMD_WRITE_INDEX] = "sf write addr data1 ... dataN - write some bytes 'data' to flash starting at 'addr'",
[CMD_ERASE_INDEX] = "sf erase addr size - erase 'size' bytes starting at 'addr'",
[CMD_RW_STATUS_INDEX] = "sf status [<volatile> <status>] - read or write '1:volatile|0:non-volatile' 'status'",
[CMD_BENCH_INDEX] = "sf bench - full chip benchmark. DANGER: It will erase full chip!",
};
if (argc < 2) {
rt_kprintf("Usage:\n");
for (i = 0; i < sizeof(sf_help_info) / sizeof(char*); i++) {
rt_kprintf("%s\n", sf_help_info[i]);
}
rt_kprintf("\n");
} else {
const char *operator = argv[1];
uint32_t addr, size;
if (!strcmp(operator, "probe")) {
if (argc < 3) {
rt_kprintf("Usage: %s.\n", sf_help_info[CMD_PROBE_INDEX]);
} else {
char *spi_dev_name = argv[2];
rtt_dev_bak = rtt_dev;
/* delete the old SPI flash device */
if(rtt_dev_bak) {
rt_sfud_flash_delete(rtt_dev_bak);
}
rtt_dev = rt_sfud_flash_probe("sf_cmd", spi_dev_name);
if (!rtt_dev) {
return;
}
sfud_dev = (sfud_flash_t)rtt_dev->user_data;
if (sfud_dev->chip.capacity < 1024 * 1024) {
rt_kprintf("%d KB %s is current selected device.\n", sfud_dev->chip.capacity / 1024, sfud_dev->name);
} else {
rt_kprintf("%d MB %s is current selected device.\n", sfud_dev->chip.capacity / 1024 / 1024,
sfud_dev->name);
}
}
} else {
if (!sfud_dev) {
rt_kprintf("No flash device selected. Please run 'sf probe'.\n");
return;
}
if (!rt_strcmp(operator, "read")) {
if (argc < 4) {
rt_kprintf("Usage: %s.\n", sf_help_info[CMD_READ_INDEX]);
return;
} else {
addr = strtol(argv[2], NULL, 0);
size = strtol(argv[3], NULL, 0);
uint8_t *data = rt_malloc(size);
if (data) {
result = sfud_read(sfud_dev, addr, size, data);
if (result == SFUD_SUCCESS) {
rt_kprintf("Read the %s flash data success. Start from 0x%08X, size is %ld. The data is:\n",
sfud_dev->name, addr, size);
rt_kprintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
for (i = 0; i < size; i += HEXDUMP_WIDTH)
{
rt_kprintf("[%08X] ", addr + i);
/* dump hex */
for (j = 0; j < HEXDUMP_WIDTH; j++) {
if (i + j < size) {
rt_kprintf("%02X ", data[i + j]);
} else {
rt_kprintf(" ");
}
}
/* dump char for hex */
for (j = 0; j < HEXDUMP_WIDTH; j++) {
if (i + j < size) {
rt_kprintf("%c", __is_print(data[i + j]) ? data[i + j] : '.');
}
}
rt_kprintf("\n");
}
rt_kprintf("\n");
}
rt_free(data);
} else {
rt_kprintf("Low memory!\n");
}
}
} else if (!rt_strcmp(operator, "write")) {
if (argc < 4) {
rt_kprintf("Usage: %s.\n", sf_help_info[CMD_WRITE_INDEX]);
return;
} else {
addr = strtol(argv[2], NULL, 0);
size = argc - 3;
uint8_t *data = rt_malloc(size);
if (data) {
for (i = 0; i < size; i++) {
data[i] = strtol(argv[3 + i], NULL, 0);
}
result = sfud_write(sfud_dev, addr, size, data);
if (result == SFUD_SUCCESS) {
rt_kprintf("Write the %s flash data success. Start from 0x%08X, size is %ld.\n",
sfud_dev->name, addr, size);
rt_kprintf("Write data: ");
for (i = 0; i < size; i++) {
rt_kprintf("%d ", data[i]);
}
rt_kprintf(".\n");
}
rt_free(data);
} else {
rt_kprintf("Low memory!\n");
}
}
} else if (!rt_strcmp(operator, "erase")) {
if (argc < 4) {
rt_kprintf("Usage: %s.\n", sf_help_info[CMD_ERASE_INDEX]);
return;
} else {
addr = strtol(argv[2], NULL, 0);
size = strtol(argv[3], NULL, 0);
result = sfud_erase(sfud_dev, addr, size);
if (result == SFUD_SUCCESS) {
rt_kprintf("Erase the %s flash data success. Start from 0x%08X, size is %ld.\n", sfud_dev->name,
addr, size);
}
}
} else if (!rt_strcmp(operator, "status")) {
if (argc < 3) {
uint8_t status;
result = sfud_read_status(sfud_dev, &status);
if (result == SFUD_SUCCESS) {
rt_kprintf("The %s flash status register current value is 0x%02X.\n", sfud_dev->name, status);
}
} else if (argc == 4) {
bool is_volatile = strtol(argv[2], NULL, 0);
uint8_t status = strtol(argv[3], NULL, 0);
result = sfud_write_status(sfud_dev, is_volatile, status);
if (result == SFUD_SUCCESS) {
rt_kprintf("Write the %s flash status register to 0x%02X success.\n", sfud_dev->name, status);
}
} else {
rt_kprintf("Usage: %s.\n", sf_help_info[CMD_RW_STATUS_INDEX]);
return;
}
} else if (!rt_strcmp(operator, "bench")) {
if ((argc > 2 && rt_strcmp(argv[2], "yes")) || argc < 3) {
rt_kprintf("DANGER: It will erase full chip! Please run 'sf bench yes'.\n");
return;
}
/* full chip benchmark test */
addr = 0;
size = sfud_dev->chip.capacity;
uint32_t start_time, time_cast;
size_t write_size = SFUD_WRITE_MAX_PAGE_SIZE, read_size = SFUD_WRITE_MAX_PAGE_SIZE, cur_op_size;
uint8_t *write_data = rt_malloc(write_size), *read_data = rt_malloc(read_size);
if (write_data && read_data) {
for (i = 0; i < write_size; i ++) {
write_data[i] = i & 0xFF;
}
/* benchmark testing */
rt_kprintf("Erasing the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
start_time = rt_tick_get();
result = sfud_erase(sfud_dev, addr, size);
if (result == SFUD_SUCCESS) {
time_cast = rt_tick_get() - start_time;
rt_kprintf("Erase benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
} else {
rt_kprintf("Erase benchmark has an error. Error code: %d.\n", result);
}
/* write test */
rt_kprintf("Writing the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
start_time = rt_tick_get();
for (i = 0; i < size; i += write_size) {
if (i + write_size <= size) {
cur_op_size = write_size;
} else {
cur_op_size = size - i;
}
result = sfud_write(sfud_dev, addr + i, cur_op_size, write_data);
if (result != SFUD_SUCCESS) {
rt_kprintf("Writing %s failed, already wr for %lu bytes, write %d each time\n", sfud_dev->name, i, write_size);
break;
}
}
if (result == SFUD_SUCCESS) {
time_cast = rt_tick_get() - start_time;
rt_kprintf("Write benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
} else {
rt_kprintf("Write benchmark has an error. Error code: %d.\n", result);
}
/* read test */
rt_kprintf("Reading the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
start_time = rt_tick_get();
for (i = 0; i < size; i += read_size) {
if (i + read_size <= size) {
cur_op_size = read_size;
} else {
cur_op_size = size - i;
}
result = sfud_read(sfud_dev, addr + i, cur_op_size, read_data);
/* data check */
if (memcmp(write_data, read_data, cur_op_size))
{
rt_kprintf("Data check ERROR! Please check you flash by other command.\n");
result = SFUD_ERR_READ;
}
if (result != SFUD_SUCCESS) {
rt_kprintf("Read %s failed, already rd for %lu bytes, read %d each time\n", sfud_dev->name, i, read_size);
break;
}
}
if (result == SFUD_SUCCESS) {
time_cast = rt_tick_get() - start_time;
rt_kprintf("Read benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
} else {
rt_kprintf("Read benchmark has an error. Error code: %d.\n", result);
}
} else {
rt_kprintf("Low memory!\n");
}
rt_free(write_data);
rt_free(read_data);
} else {
rt_kprintf("Usage:\n");
for (i = 0; i < sizeof(sf_help_info) / sizeof(char*); i++) {
rt_kprintf("%s\n", sf_help_info[i]);
}
rt_kprintf("\n");
return;
}
if (result != SFUD_SUCCESS) {
rt_kprintf("This flash operate has an error. Error code: %d.\n", result);
}
}
}
}
MSH_CMD_EXPORT(sf, SPI Flash operate.);
#endif /* defined(RT_USING_FINSH) */
#endif /* RT_USING_SFUD */

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2016-09-28 armink first version.
*/
#ifndef _SPI_FLASH_SFUD_H_
#define _SPI_FLASH_SFUD_H_
#include <rtthread.h>
#include <rtdevice.h>
#include "./sfud/inc/sfud.h"
#include "spi_flash.h"
/**
* Probe SPI flash by SFUD(Serial Flash Universal Driver) driver library and though SPI device.
*
* @param spi_flash_dev_name the name which will create SPI flash device
* @param spi_dev_name using SPI device name
*
* @return probed SPI flash device, probe failed will return RT_NULL
*/
rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const char *spi_dev_name);
/**
* Probe SPI flash by SFUD (Serial Flash Universal Driver) driver library and though SPI device by specified configuration.
*
* @param spi_flash_dev_name the name which will create SPI flash device
* @param spi_dev_name using SPI device name
* @param spi_cfg SPI device configuration
* @param qspi_cfg QSPI device configuration
*
* @return probed SPI flash device, probe failed will return RT_NULL
*/
rt_spi_flash_device_t rt_sfud_flash_probe_ex(const char *spi_flash_dev_name, const char *spi_dev_name,
struct rt_spi_configuration *spi_cfg, struct rt_qspi_configuration *qspi_cfg);
/**
* Delete SPI flash device
*
* @param spi_flash_dev SPI flash device
*
* @return the operation status, RT_EOK on successful
*/
rt_err_t rt_sfud_flash_delete(rt_spi_flash_device_t spi_flash_dev);
/**
* Find sfud flash device by SPI device name
*
* @param spi_dev_name using SPI device name
*
* @return sfud flash device if success, otherwise return RT_NULL
*/
sfud_flash_t rt_sfud_flash_find(const char *spi_dev_name);
/**
* Find sfud flash device by flash device name
*
* @param flash_dev_name using flash device name
*
* @return sfud flash device if success, otherwise return RT_NULL
*/
sfud_flash_t rt_sfud_flash_find_by_dev_name(const char *flash_dev_name);
#endif /* _SPI_FLASH_SFUD_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,128 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2009-04-17 Bernard first version.
*/
#ifndef SPI_MSD_H_INCLUDED
#define SPI_MSD_H_INCLUDED
#include <stdint.h>
#include <rtdevice.h>
#include <drivers/spi.h>
/* SD command (SPI mode) */
#define GO_IDLE_STATE 0 /* CMD0 R1 */
#define SEND_OP_COND 1 /* CMD1 R1 */
#define SWITCH_FUNC 6 /* CMD6 R1 */
#define SEND_IF_COND 8 /* CMD8 R7 */
#define SEND_CSD 9 /* CMD9 R1 */
#define SEND_CID 10 /* CMD10 R1 */
#define STOP_TRANSMISSION 12 /* CMD12 R1B */
#define SEND_STATUS 13 /* CMD13 R2 */
#define SET_BLOCKLEN 16 /* CMD16 R1 */
#define READ_SINGLE_BLOCK 17 /* CMD17 R1 */
#define READ_MULTIPLE_BLOCK 18 /* CMD18 R1 */
#define WRITE_BLOCK 24 /* CMD24 R1 */
#define WRITE_MULTIPLE_BLOCK 25 /* CMD25 R1 */
#define PROGRAM_CSD 27 /* CMD27 R1 */
#define SET_WRITE_PROT 28 /* CMD28 R1B */
#define CLR_WRITE_PROT 29 /* CMD29 R1B */
#define SEND_WRITE_PROT 30 /* CMD30 R1 */
#define ERASE_WR_BLK_START_ADDR 32 /* CMD32 R1 */
#define ERASE_WR_BLK_END_ADDR 33 /* CMD33 R1 */
#define ERASE 38 /* CMD38 R1B */
#define LOCK_UNLOCK 42 /* CMD42 R1 */
#define APP_CMD 55 /* CMD55 R1 */
#define GEN_CMD 56 /* CMD56 R1 */
#define READ_OCR 58 /* CMD58 R3 */
#define CRC_ON_OFF 59 /* CMD59 R1 */
/* Application-Specific Command */
#define SD_STATUS 13 /* ACMD13 R2 */
#define SEND_NUM_WR_BLOCKS 22 /* ACMD22 R1 */
#define SET_WR_BLK_ERASE_COUNT 23 /* ACMD23 R1 */
#define SD_SEND_OP_COND 41 /* ACMD41 R1 */
#define SET_CLR_CARD_DETECT 42 /* ACMD42 R1 */
#define SEND_SCR 51 /* ACMD51 R1 */
/* Start Data tokens */
/* Tokens (necessary because at nop/idle (and CS active) only 0xff is on the data/command line) */
#define MSD_TOKEN_READ_START 0xFE /* Data token start byte, Start Single Block Read */
#define MSD_TOKEN_WRITE_SINGLE_START 0xFE /* Data token start byte, Start Single Block Write */
#define MSD_TOKEN_WRITE_MULTIPLE_START 0xFC /* Data token start byte, Start Multiple Block Write */
#define MSD_TOKEN_WRITE_MULTIPLE_STOP 0xFD /* Data toke stop byte, Stop Multiple Block Write */
/* MSD reponses and error flags */
#define MSD_RESPONSE_NO_ERROR 0x00
#define MSD_IN_IDLE_STATE 0x01
#define MSD_ERASE_RESET 0x02
#define MSD_ILLEGAL_COMMAND 0x04
#define MSD_COM_CRC_ERROR 0x08
#define MSD_ERASE_SEQUENCE_ERROR 0x10
#define MSD_ADDRESS_ERROR 0x20
#define MSD_PARAMETER_ERROR 0x40
#define MSD_RESPONSE_FAILURE 0xFF
/* Data response error */
#define MSD_DATA_OK 0x05
#define MSD_DATA_CRC_ERROR 0x0B
#define MSD_DATA_WRITE_ERROR 0x0D
#define MSD_DATA_OTHER_ERROR 0xFF
#define MSD_DATA_RESPONSE_MASK 0x1F
#define MSD_GET_DATA_RESPONSE(res) (res & MSD_DATA_RESPONSE_MASK)
#define MSD_CMD_LEN 6 /**< command, arg and crc. */
#define MSD_RESPONSE_MAX_LEN 5 /**< response max len */
#define MSD_CSD_LEN 16 /**< SD crad CSD register len */
#define SECTOR_SIZE 512 /**< sector size, default 512byte */
/* card try timeout, unit: ms */
#define CARD_TRY_TIMES 3000
#define CARD_TRY_TIMES_ACMD41 800
#define CARD_WAIT_TOKEN_TIMES 800
#define MSD_USE_PRE_ERASED /**< id define MSD_USE_PRE_ERASED, before CMD25, send ACMD23 */
/**
* SD/MMC card type
*/
typedef enum
{
MSD_CARD_TYPE_UNKNOWN = 0, /**< unknown */
MSD_CARD_TYPE_MMC, /**< MultiMedia Card */
MSD_CARD_TYPE_SD_V1_X, /**< Ver 1.X Standard Capacity SD Memory Card */
MSD_CARD_TYPE_SD_V2_X, /**< Ver 2.00 or later Standard Capacity SD Memory Card */
MSD_CARD_TYPE_SD_SDHC, /**< High Capacity SD Memory Card */
MSD_CARD_TYPE_SD_SDXC, /**< later Extended Capacity SD Memory Card */
}msd_card_type;
typedef enum
{
response_type_unknown = 0,
response_r1,
response_r1b,
response_r2,
response_r3,
response_r4,
response_r5,
response_r7,
}response_type;
struct msd_device
{
struct rt_device parent; /**< RT-Thread device struct */
struct rt_device_blk_geometry geometry; /**< sector size, sector count */
struct rt_spi_device * spi_device; /**< SPI interface */
msd_card_type card_type; /**< card type: MMC SD1.x SD2.0 SDHC SDXC */
uint32_t max_clock; /**< MAX SPI clock */
};
extern rt_err_t msd_init(const char * sd_device_name, const char * spi_device_name);
#endif // SPI_MSD_H_INCLUDED

View File

@@ -0,0 +1,852 @@
/*
* COPYRIGHT (C) 2011-2023, Real-Thread Information Technology Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2014-07-31 aozima the first version
* 2014-09-18 aozima update command & response.
* 2017-07-28 armink fix auto reconnect feature
*/
#include <rtthread.h>
#include <drivers/spi.h>
#include <netif/ethernetif.h>
#include <netif/etharp.h>
#include <lwip/icmp.h>
#include "lwipopts.h"
#define WIFI_DEBUG_ON
// #define ETH_RX_DUMP
// #define ETH_TX_DUMP
#ifdef WIFI_DEBUG_ON
#define WIFI_DEBUG rt_kprintf("[RW009] ");rt_kprintf
//#define SPI_DEBUG rt_kprintf("[SPI] ");rt_kprintf
#define SPI_DEBUG(...)
#else
#define WIFI_DEBUG(...)
#define SPI_DEBUG(...)
#endif /* #ifdef WIFI_DEBUG_ON */
/********************************* RW009 **************************************/
#include "spi_wifi_rw009.h"
/* tools */
#define node_entry(node, type, member) \
((type *)((char *)(node) - (unsigned long)(&((type *)0)->member)))
#define member_offset(type, member) \
((unsigned long)(&((type *)0)->member))
#define MAX_SPI_PACKET_SIZE (member_offset(struct spi_data_packet, buffer) + SPI_MAX_DATA_LEN)
#define MAX_SPI_BUFFER_SIZE (sizeof(struct spi_response) + MAX_SPI_PACKET_SIZE)
#define MAX_ADDR_LEN 6
struct rw009_wifi
{
/* inherit from ethernet device */
struct eth_device parent;
struct rt_spi_device *rt_spi_device;
/* interface address info. */
rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */
rt_uint8_t active;
struct rt_mempool spi_tx_mp;
struct rt_mempool spi_rx_mp;
struct rt_mailbox spi_tx_mb;
struct rt_mailbox eth_rx_mb;
int spi_tx_mb_pool[SPI_TX_POOL_SIZE + 1];
int eth_rx_mb_pool[SPI_RX_POOL_SIZE + 1];
int rw009_cmd_mb_pool[3];
struct rt_mailbox rw009_cmd_mb;
uint32_t last_cmd;
rt_align(4)
rt_uint8_t spi_tx_mempool[(sizeof(struct spi_data_packet) + 4) * SPI_TX_POOL_SIZE];
rt_align(4)
rt_uint8_t spi_rx_mempool[(sizeof(struct spi_data_packet) + 4) * SPI_RX_POOL_SIZE];
rt_align(4)
uint8_t spi_hw_rx_buffer[MAX_SPI_BUFFER_SIZE];
/* status for RW009 */
rw009_ap_info ap_info; /* AP info for conn. */
rw009_ap_info *ap_scan; /* AP list for SCAN. */
uint32_t ap_scan_count;
};
static struct rw009_wifi rw009_wifi_device;
static struct rt_event spi_wifi_data_event;
static void resp_handler(struct rw009_wifi *wifi_device, struct rw009_resp *resp)
{
struct rw009_resp *resp_return = RT_NULL;
switch (resp->cmd)
{
case RW009_CMD_INIT:
WIFI_DEBUG("resp_handler RW009_CMD_INIT\n");
resp_return = (struct rw009_resp *)rt_malloc(member_offset(struct rw009_resp, resp) + sizeof(rw009_resp_init)); //TODO:
if(resp_return == RT_NULL) break;
rt_memcpy(resp_return, resp, member_offset(struct rw009_resp, resp) + sizeof(rw009_resp_init));
WIFI_DEBUG("sn:%-*.*s\n", sizeof(resp->resp.init.sn), sizeof(resp->resp.init.sn), resp->resp.init.sn);
WIFI_DEBUG("version:%-*.*s\n", sizeof(resp->resp.init.version), sizeof(resp->resp.init.version), resp->resp.init.version);
rt_memcpy(wifi_device->dev_addr, resp->resp.init.mac, 6);
break;
case RW009_CMD_SCAN:
if( resp->len == sizeof(rw009_ap_info) )
{
rw009_ap_info *ap_scan = rt_realloc(wifi_device->ap_scan, sizeof(rw009_ap_info) * (wifi_device->ap_scan_count + 1) );
if(ap_scan != RT_NULL)
{
rt_memcpy( &ap_scan[wifi_device->ap_scan_count], &resp->resp.ap_info, sizeof(rw009_ap_info) );
//dump
if(1)
{
#ifdef WIFI_DEBUG_ON
rw009_ap_info *ap_info = &resp->resp.ap_info;
WIFI_DEBUG("SCAN SSID:%-32.32s\n", ap_info->ssid);
WIFI_DEBUG("SCAN BSSID:%02X-%02X-%02X-%02X-%02X-%02X\n",
ap_info->bssid[0],
ap_info->bssid[1],
ap_info->bssid[2],
ap_info->bssid[3],
ap_info->bssid[4],
ap_info->bssid[5]);
WIFI_DEBUG("SCAN rssi:%ddBm\n", ap_info->rssi);
WIFI_DEBUG("SCAN rate:%dMbps\n", ap_info->max_data_rate/1000);
WIFI_DEBUG("SCAN channel:%d\n", ap_info->channel);
WIFI_DEBUG("SCAN security:%08X\n\n", ap_info->security);
#endif /* WIFI_DEBUG_ON */
}
wifi_device->ap_scan_count++;
wifi_device->ap_scan = ap_scan;
}
return; /* wait for next ap */
}
break;
case RW009_CMD_JOIN:
case RW009_CMD_EASY_JOIN:
WIFI_DEBUG("resp_handler RW009_CMD_EASY_JOIN\n");
resp_return = (struct rw009_resp *)rt_malloc(member_offset(struct rw009_resp, resp) + sizeof(rw009_resp_join)); //TODO:
if(resp_return == RT_NULL) break;
rt_memcpy(resp_return, resp, member_offset(struct rw009_resp, resp) + sizeof(rw009_resp_join));
if( resp->result == 0 )
{
rt_memcpy(&wifi_device->ap_info, &resp_return->resp.ap_info, sizeof(rw009_resp_join));
wifi_device->active = 1;
eth_device_linkchange(&wifi_device->parent, RT_TRUE);
}
else
{
wifi_device->active = 1;
eth_device_linkchange(&wifi_device->parent, RT_FALSE);
WIFI_DEBUG("RW009_CMD_EASY_JOIN result: %d\n", resp->result );
}
//dupm
if(1)
{
#ifdef WIFI_DEBUG_ON
rw009_ap_info *ap_info = &resp->resp.ap_info;
WIFI_DEBUG("JOIN SSID:%-32.32s\n", ap_info->ssid);
WIFI_DEBUG("JOIN BSSID:%02X-%02X-%02X-%02X-%02X-%02X\n",
ap_info->bssid[0],
ap_info->bssid[1],
ap_info->bssid[2],
ap_info->bssid[3],
ap_info->bssid[4],
ap_info->bssid[5]);
WIFI_DEBUG("JOIN rssi:%ddBm\n", ap_info->rssi);
WIFI_DEBUG("JOIN rate:%dMbps\n", ap_info->max_data_rate/1000);
WIFI_DEBUG("JOIN channel:%d\n", ap_info->channel);
WIFI_DEBUG("JOIN security:%08X\n\n", ap_info->security);
#endif /* WIFI_DEBUG_ON */
}
break;
case RW009_CMD_RSSI:
// TODO: client RSSI.
{
rw009_ap_info *ap_info = &resp->resp.ap_info;
wifi_device->ap_info.rssi = ap_info->rssi;
WIFI_DEBUG("current RSSI: %d\n", wifi_device->ap_info.rssi);
}
break;
case RW009_CMD_SOFTAP:
{
if( resp->result == 0 )
{
;
wifi_device->active = 1;
eth_device_linkchange(&wifi_device->parent, RT_TRUE);
}
else
{
WIFI_DEBUG("RW009_CMD_EASY_JOIN result: %d\n", resp->result );
}
}
break;
default:
WIFI_DEBUG("resp_handler %d\n", resp->cmd);
break;
}
if(resp->cmd == wifi_device->last_cmd)
{
rt_mb_send(&wifi_device->rw009_cmd_mb, (rt_uint32_t)resp_return);
return;
}
else
{
rt_free(resp_return);
}
}
static rt_err_t rw009_cmd(struct rw009_wifi *wifi_device, uint32_t cmd, void *args)
{
rt_err_t result = RT_EOK;
rt_int32_t timeout = RW009_CMD_TIMEOUT;
struct spi_data_packet *data_packet;
struct rw009_cmd *wifi_cmd = RT_NULL;
struct rw009_resp *resp = RT_NULL;
wifi_device->last_cmd = cmd;
data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER);
wifi_cmd = (struct rw009_cmd *)data_packet->buffer;
wifi_cmd->cmd = cmd;
wifi_cmd->len = 0;
if( cmd == RW009_CMD_INIT )
{
wifi_cmd->len = sizeof(rw009_cmd_init);
}
else if( cmd == RW009_CMD_SCAN )
{
wifi_cmd->len = 0;
timeout += RT_TICK_PER_SECOND*10;
if(wifi_device->ap_scan)
{
rt_free(wifi_device->ap_scan);
wifi_device->ap_scan = RT_NULL;
wifi_device->ap_scan_count = 0;
}
}
else if( cmd == RW009_CMD_JOIN )
{
wifi_cmd->len = sizeof(rw009_cmd_join);
}
else if( cmd == RW009_CMD_EASY_JOIN )
{
wifi_cmd->len = sizeof(rw009_cmd_easy_join);
timeout += RT_TICK_PER_SECOND*5;
}
else if( cmd == RW009_CMD_RSSI )
{
wifi_cmd->len = sizeof(rw009_cmd_rssi);
}
else if( cmd == RW009_CMD_SOFTAP )
{
wifi_cmd->len = sizeof(rw009_cmd_softap);
}
else
{
WIFI_DEBUG("unkown RW009 CMD %d\n", cmd);
result = -RT_ENOSYS;
rt_mp_free(data_packet);
data_packet = RT_NULL;
}
if(data_packet == RT_NULL)
{
goto _exit;
}
if(wifi_cmd->len)
rt_memcpy(&wifi_cmd->params, args, wifi_cmd->len);
data_packet->data_type = data_type_cmd;
data_packet->data_len = member_offset(struct rw009_cmd, params) + wifi_cmd->len;
rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet);
rt_event_send(&spi_wifi_data_event, 1);
result = rt_mb_recv(&wifi_device->rw009_cmd_mb,
(rt_uint32_t *)&resp,
timeout);
if ( result != RT_EOK )
{
WIFI_DEBUG("CMD %d error, resultL %d\n", cmd, result );
}
if(resp != RT_NULL)
result = resp->result;
_exit:
wifi_device->last_cmd = 0;
if(resp) rt_free(resp);
return result;
}
static rt_err_t spi_wifi_transfer(struct rw009_wifi *dev)
{
struct pbuf *p = RT_NULL;
struct spi_cmd_request cmd;
struct spi_response resp;
rt_err_t result;
const struct spi_data_packet *data_packet = RT_NULL;
struct rw009_wifi *wifi_device = (struct rw009_wifi *)dev;
struct rt_spi_device *rt_spi_device = wifi_device->rt_spi_device;
spi_wifi_int_cmd(0);
while (spi_wifi_is_busy());
SPI_DEBUG("sequence start!\n");
rt_memset(&cmd, 0, sizeof(struct spi_cmd_request));
cmd.magic1 = CMD_MAGIC1;
cmd.magic2 = CMD_MAGIC2;
cmd.flag |= CMD_FLAG_MRDY;
result = rt_mb_recv(&wifi_device->spi_tx_mb,
(rt_uint32_t *)&data_packet,
0);
if ((result == RT_EOK) && (data_packet != RT_NULL) && (data_packet->data_len > 0))
{
cmd.M2S_len = data_packet->data_len + member_offset(struct spi_data_packet, buffer);
//SPI_DEBUG("cmd.M2S_len = %d\n", cmd.M2S_len);
}
rt_spi_send(rt_spi_device, &cmd, sizeof(cmd));
while (spi_wifi_is_busy());
{
struct rt_spi_message message;
uint32_t max_data_len = 0;
/* setup message */
message.send_buf = RT_NULL;
message.recv_buf = &resp;
message.length = sizeof(resp);
message.cs_take = 1;
message.cs_release = 0;
rt_spi_take_bus(rt_spi_device);
/* transfer message */
rt_spi_device->bus->ops->xfer(rt_spi_device, &message);
if ((resp.magic1 != RESP_MAGIC1) || (resp.magic2 != RESP_MAGIC2))
{
SPI_DEBUG("bad resp magic, abort!\n");
goto _bad_resp_magic;
}
if (resp.flag & RESP_FLAG_SRDY)
{
SPI_DEBUG("RESP_FLAG_SRDY\n");
max_data_len = cmd.M2S_len;
}
if (resp.S2M_len)
{
SPI_DEBUG("resp.S2M_len: %d\n", resp.S2M_len);
if (resp.S2M_len > MAX_SPI_PACKET_SIZE)
{
SPI_DEBUG("resp.S2M_len %d > %d(MAX_SPI_PACKET_SIZE), drop!\n", resp.S2M_len, MAX_SPI_PACKET_SIZE);
resp.S2M_len = 0;//drop
}
if (resp.S2M_len > max_data_len)
max_data_len = resp.S2M_len;
}
if (max_data_len == 0)
{
SPI_DEBUG("no rx or tx data!\n");
}
//SPI_DEBUG("max_data_len = %d\n", max_data_len);
_bad_resp_magic:
/* setup message */
message.send_buf = data_packet;//&tx_buffer;
message.recv_buf = wifi_device->spi_hw_rx_buffer;//&rx_buffer;
message.length = max_data_len;
message.cs_take = 0;
message.cs_release = 1;
/* transfer message */
rt_spi_device->bus->ops->xfer(rt_spi_device, &message);
rt_spi_release_bus(rt_spi_device);
if (cmd.M2S_len && (resp.flag & RESP_FLAG_SRDY))
{
rt_mp_free((void *)data_packet);
}
if ((resp.S2M_len) && (resp.S2M_len <= MAX_SPI_PACKET_SIZE))
{
data_packet = (struct spi_data_packet *)wifi_device->spi_hw_rx_buffer;
if (data_packet->data_type == data_type_eth_data)
{
if (wifi_device->active)
{
p = pbuf_alloc(PBUF_LINK, data_packet->data_len, PBUF_RAM);
pbuf_take(p, (rt_uint8_t *)data_packet->buffer, data_packet->data_len);
rt_mb_send(&wifi_device->eth_rx_mb, (rt_uint32_t)p);
eth_device_ready((struct eth_device *)dev);
}
else
{
SPI_DEBUG("!active, RX drop.\n");
}
}
else if (data_packet->data_type == data_type_resp)
{
SPI_DEBUG("data_type_resp\n");
resp_handler(dev, (struct rw009_resp *)data_packet->buffer);
}
else
{
SPI_DEBUG("data_type: %d, %dbyte\n",
data_packet->data_type,
data_packet->data_len);
}
}
}
spi_wifi_int_cmd(1);
SPI_DEBUG("sequence finish!\n\n");
if ((cmd.M2S_len == 0) && (resp.S2M_len == 0))
{
return -RT_ERROR;
}
return RT_EOK;
}
#if defined(ETH_RX_DUMP) || defined(ETH_TX_DUMP)
static void packet_dump(const char *msg, const struct pbuf *p)
{
const struct pbuf* q;
rt_uint32_t i,j;
rt_uint8_t *ptr = p->payload;
rt_kprintf("%s %d byte\n", msg, p->tot_len);
i=0;
for(q=p; q != RT_NULL; q= q->next)
{
ptr = q->payload;
for(j=0; j<q->len; j++)
{
if( (i%8) == 0 )
{
rt_kprintf(" ");
}
if( (i%16) == 0 )
{
rt_kprintf("\r\n");
}
rt_kprintf("%02x ",*ptr);
i++;
ptr++;
}
}
rt_kprintf("\n\n");
}
#endif /* dump */
/********************************* RT-Thread Ethernet interface begin **************************************/
static rt_err_t rw009_wifi_init(rt_device_t dev)
{
return RT_EOK;
}
static rt_err_t rw009_wifi_open(rt_device_t dev, rt_uint16_t oflag)
{
return RT_EOK;
}
static rt_err_t rw009_wifi_close(rt_device_t dev)
{
return RT_EOK;
}
static rt_ssize_t rw009_wifi_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
rt_set_errno(-RT_ENOSYS);
return 0;
}
static rt_ssize_t rw009_wifi_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
rt_set_errno(-RT_ENOSYS);
return 0;
}
static rt_err_t rw009_wifi_control(rt_device_t dev, int cmd, void *args)
{
struct rw009_wifi *wifi_device = (struct rw009_wifi *)dev;
rt_err_t result = RT_EOK;
if (cmd == NIOCTL_GADDR)
{
rt_memcpy(args, wifi_device->dev_addr, 6);
}
else
{
result = rw009_cmd(wifi_device, cmd, args);
}
return result;
}
/* transmit packet. */
rt_err_t rw009_wifi_tx(rt_device_t dev, struct pbuf *p)
{
rt_err_t result = RT_EOK;
struct spi_data_packet *data_packet;
struct rw009_wifi *wifi_device = (struct rw009_wifi *)dev;
if (!wifi_device->active)
{
WIFI_DEBUG("!active, TX drop!\n");
return RT_EOK;
}
/* get free tx buffer */
data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER);
if (data_packet != RT_NULL)
{
data_packet->data_type = data_type_eth_data;
data_packet->data_len = p->tot_len;
pbuf_copy_partial(p, data_packet->buffer, data_packet->data_len, 0);
rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet);
rt_event_send(&spi_wifi_data_event, 1);
}
else
return -RT_ERROR;
#ifdef ETH_TX_DUMP
packet_dump("TX dump", p);
#endif /* ETH_TX_DUMP */
/* Return SUCCESS */
return result;
}
/* reception packet. */
struct pbuf *rw009_wifi_rx(rt_device_t dev)
{
struct pbuf *p = RT_NULL;
struct rw009_wifi *wifi_device = (struct rw009_wifi *)dev;
if (rt_mb_recv(&wifi_device->eth_rx_mb, (rt_uint32_t *)&p, 0) != RT_EOK)
{
return RT_NULL;
}
#ifdef ETH_RX_DUMP
if(p)
packet_dump("RX dump", p);
#endif /* ETH_RX_DUMP */
return p;
}
/********************************* RT-Thread Ethernet interface end **************************************/
static void spi_wifi_data_thread_entry(void *parameter)
{
rt_uint32_t e;
rt_err_t result;
while (1)
{
/* receive first event */
if (rt_event_recv(&spi_wifi_data_event,
1,
RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER,
&e) != RT_EOK)
{
continue;
}
result = spi_wifi_transfer(&rw009_wifi_device);
if (result == RT_EOK)
{
rt_event_send(&spi_wifi_data_event, 1);
}
}
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops rw009_ops =
{
rw009_wifi_init,
rw009_wifi_open,
rw009_wifi_close,
rw009_wifi_read,
rw009_wifi_write,
rw009_wifi_control
};
#endif
rt_err_t rt_hw_wifi_init(const char *spi_device_name, wifi_mode_t mode)
{
/* align and struct size check. */
RT_ASSERT( (SPI_MAX_DATA_LEN & 0x03) == 0);
RT_ASSERT( sizeof(struct rw009_resp) <= SPI_MAX_DATA_LEN);
rt_memset(&rw009_wifi_device, 0, sizeof(struct rw009_wifi));
rw009_wifi_device.rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
if (rw009_wifi_device.rt_spi_device == RT_NULL)
{
SPI_DEBUG("spi device %s not found!\r\n", spi_device_name);
return -RT_ENOSYS;
}
/* config spi */
{
struct rt_spi_configuration cfg;
cfg.data_width = 8;
cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0. */
cfg.max_hz = 15 * 1000000; /* 10M */
rt_spi_configure(rw009_wifi_device.rt_spi_device, &cfg);
}
#ifdef RT_USING_DEVICE_OPS
rw009_wifi_device.parent.parent.ops = &rw009_ops;
#else
rw009_wifi_device.parent.parent.init = rw009_wifi_init;
rw009_wifi_device.parent.parent.open = rw009_wifi_open;
rw009_wifi_device.parent.parent.close = rw009_wifi_close;
rw009_wifi_device.parent.parent.read = rw009_wifi_read;
rw009_wifi_device.parent.parent.write = rw009_wifi_write;
rw009_wifi_device.parent.parent.control = rw009_wifi_control;
#endif
rw009_wifi_device.parent.parent.user_data = RT_NULL;
rw009_wifi_device.parent.eth_rx = rw009_wifi_rx;
rw009_wifi_device.parent.eth_tx = rw009_wifi_tx;
rt_mp_init(&rw009_wifi_device.spi_tx_mp,
"spi_tx",
&rw009_wifi_device.spi_tx_mempool[0],
sizeof(rw009_wifi_device.spi_tx_mempool),
sizeof(struct spi_data_packet));
rt_mp_init(&rw009_wifi_device.spi_rx_mp,
"spi_rx",
&rw009_wifi_device.spi_rx_mempool[0],
sizeof(rw009_wifi_device.spi_rx_mempool),
sizeof(struct spi_data_packet));
rt_mb_init(&rw009_wifi_device.spi_tx_mb,
"spi_tx",
&rw009_wifi_device.spi_tx_mb_pool[0],
SPI_TX_POOL_SIZE,
RT_IPC_FLAG_PRIO);
rt_mb_init(&rw009_wifi_device.eth_rx_mb,
"eth_rx",
&rw009_wifi_device.eth_rx_mb_pool[0],
SPI_TX_POOL_SIZE,
RT_IPC_FLAG_PRIO);
rt_mb_init(&rw009_wifi_device.rw009_cmd_mb,
"wifi_cmd",
&rw009_wifi_device.rw009_cmd_mb_pool[0],
sizeof(rw009_wifi_device.rw009_cmd_mb_pool) / 4,
RT_IPC_FLAG_PRIO);
rt_event_init(&spi_wifi_data_event, "wifi", RT_IPC_FLAG_FIFO);
spi_wifi_hw_init();
{
rt_thread_t tid;
tid = rt_thread_create("wifi",
spi_wifi_data_thread_entry,
RT_NULL,
2048,
RT_THREAD_PRIORITY_MAX - 2,
20);
if (tid != RT_NULL)
rt_thread_startup(tid);
}
/* init: get mac address */
{
rw009_cmd_init init;
init.mode = mode;
WIFI_DEBUG("wifi_control RW009_CMD_INIT\n");
rw009_wifi_control((rt_device_t)&rw009_wifi_device,
RW009_CMD_INIT,
(void *)&init); // 0: firmware, 1: STA, 2:AP
}
/* register eth device */
eth_device_init(&(rw009_wifi_device.parent), "w0");
eth_device_linkchange(&rw009_wifi_device.parent, RT_FALSE);
return RT_EOK;
}
void spi_wifi_isr(int vector)
{
/* enter interrupt */
rt_interrupt_enter();
SPI_DEBUG("spi_wifi_isr\n");
rt_event_send(&spi_wifi_data_event, 1);
/* leave interrupt */
rt_interrupt_leave();
}
/********************************* RW009 tools **************************************/
rt_err_t rw009_join(const char * SSID, const char * passwd)
{
rt_err_t result;
rt_device_t wifi_device;
rw009_cmd_easy_join easy_join;
wifi_device = rt_device_find("w0");
if(wifi_device == RT_NULL)
return -RT_ENOSYS;
strncpy( easy_join.ssid, SSID, sizeof(easy_join.ssid) );
strncpy( easy_join.passwd, passwd, sizeof(easy_join.passwd) );
result = rt_device_control(wifi_device,
RW009_CMD_EASY_JOIN,
(void *)&easy_join);
return result;
}
rt_err_t rw009_softap(const char * SSID, const char * passwd,uint32_t security,uint32_t channel)
{
rt_err_t result;
rt_device_t wifi_device;
rw009_cmd_softap softap;
wifi_device = rt_device_find("w0");
if(wifi_device == RT_NULL)
return -RT_ENOSYS;
strncpy( softap.ssid, SSID, sizeof(softap.ssid) );
strncpy( softap.passwd, passwd, sizeof(softap.passwd) );
softap.security = security;
softap.channel = channel;
result = rt_device_control(wifi_device,
RW009_CMD_SOFTAP,
(void *)&softap);
return result;
}
int32_t rw009_rssi(void)
{
rt_err_t result;
struct rw009_wifi * wifi_device;
wifi_device = (struct rw009_wifi *)rt_device_find("w0");
if(wifi_device == RT_NULL)
return 0;
if(wifi_device->active == 0)
return 0;
// SCAN
result = rt_device_control((rt_device_t)wifi_device,
RW009_CMD_RSSI,
RT_NULL);
if(result == RT_EOK)
{
return wifi_device->ap_info.rssi;
}
return 0;
}
#ifdef RT_USING_FINSH
#include <finsh.h>
static rt_err_t rw009_scan(void)
{
rt_err_t result;
struct rw009_wifi * wifi_device;
wifi_device = (struct rw009_wifi *)rt_device_find("w0");
rt_kprintf("\nCMD RW009_CMD_SCAN \n");
result = rt_device_control((rt_device_t)wifi_device,
RW009_CMD_SCAN,
RT_NULL);
rt_kprintf("CMD RW009_CMD_SCAN result:%d\n", result);
if(result == RT_EOK)
{
uint32_t i;
rw009_ap_info *ap_info;
for(i=0; i<wifi_device->ap_scan_count; i++)
{
ap_info = &wifi_device->ap_scan[i];
rt_kprintf("AP #%02d SSID: %-32.32s\n", i, ap_info->ssid );
}
}
return result;
}
FINSH_FUNCTION_EXPORT(rw009_scan, SACN and list AP.);
FINSH_FUNCTION_EXPORT(rw009_join, RW009 join to AP.);
FINSH_FUNCTION_EXPORT(rw009_rssi, get RW009 current AP rssi.);
#endif // RT_USING_FINSH

View File

@@ -0,0 +1,212 @@
/*
* COPYRIGHT (C) 2011-2023, Real-Thread Information Technology Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2014-07-31 aozima the first version
* 2014-09-18 aozima update command & response.
*/
#ifndef SPI_WIFI_H_INCLUDED
#define SPI_WIFI_H_INCLUDED
#include <stdint.h>
// little-endian
struct spi_cmd_request
{
uint32_t flag;
uint32_t M2S_len; // master to slave data len.
uint32_t magic1;
uint32_t magic2;
};
#define CMD_MAGIC1 (0x67452301)
#define CMD_MAGIC2 (0xEFCDAB89)
#define CMD_FLAG_MRDY (0x01)
// little-endian
struct spi_response
{
uint32_t flag;
uint32_t S2M_len; // slave to master data len.
uint32_t magic1;
uint32_t magic2;
};
#define RESP_FLAG_SRDY (0x01)
#define RESP_MAGIC1 (0x98BADCFE)
#define RESP_MAGIC2 (0x10325476)
/* spi slave configure. */
#define SPI_MAX_DATA_LEN 1520
#define SPI_TX_POOL_SIZE 2
#define SPI_RX_POOL_SIZE 2
typedef enum
{
data_type_eth_data = 0,
data_type_cmd,
data_type_resp,
data_type_status,
}
app_data_type_typedef;
struct spi_data_packet
{
uint32_t data_len;
uint32_t data_type;
char buffer[SPI_MAX_DATA_LEN];
};
/********************************* RW009 **************************************/
/* option */
#define RW009_CMD_TIMEOUT (RT_TICK_PER_SECOND*3)
#define SSID_NAME_LENGTH_MAX (32)
#define PASSWORD_LENGTH_MAX (64)
typedef enum
{
MODE_STATION=0,
MODE_SOFTAP=1,
} wifi_mode_t;
typedef struct _rw009_ap_info
{
char ssid[SSID_NAME_LENGTH_MAX];
uint8_t bssid[8]; // 6byte + 2byte PAD.
int rssi; /* Receive Signal Strength Indication in dBm. */
uint32_t max_data_rate; /* Maximum data rate in kilobits/s */
uint32_t security; /* Security type */
uint32_t channel; /* Radio channel that the AP beacon was received on */
} rw009_ap_info;
typedef struct _rw009_cmd_init
{
uint32_t mode;
} rw009_cmd_init;
typedef struct _rw009_resp_init
{
uint8_t mac[8]; // 6byte + 2byte PAD.
uint8_t sn[24]; // serial.
char version[16]; // firmware version.
} rw009_resp_init;
typedef struct _rw009_cmd_easy_join
{
char ssid[SSID_NAME_LENGTH_MAX];
char passwd[PASSWORD_LENGTH_MAX];
} rw009_cmd_easy_join;
typedef struct _rw009_cmd_join
{
uint8_t bssid[8]; // 6byte + 2byte PAD.
char passwd[PASSWORD_LENGTH_MAX];
} rw009_cmd_join;
typedef struct _rw009_cmd_rssi
{
uint8_t bssid[8]; // 6byte + 2byte PAD.
} rw009_cmd_rssi;
typedef struct _rw009_cmd_softap
{
char ssid[SSID_NAME_LENGTH_MAX];
char passwd[PASSWORD_LENGTH_MAX];
uint32_t security; /* Security type. */
uint32_t channel; /* Radio channel that the AP beacon was received on */
} rw009_cmd_softap;
typedef struct _rw009_resp_join
{
rw009_ap_info ap_info;
} rw009_resp_join;
struct rw009_cmd
{
uint32_t cmd;
uint32_t len;
/** command body */
union
{
rw009_cmd_init init;
rw009_cmd_easy_join easy_join;
rw009_cmd_join join;
rw009_cmd_rssi rssi;
rw009_cmd_softap softap;
} params;
};
struct rw009_resp
{
uint32_t cmd;
uint32_t len;
int32_t result; // result for CMD.
/** resp Body */
union
{
rw009_resp_init init;
rw009_ap_info ap_info;
} resp;
};
#define RW009_CMD_INIT 128
#define RW009_CMD_SCAN 129
#define RW009_CMD_JOIN 130
#define RW009_CMD_EASY_JOIN 131
#define RW009_CMD_RSSI 132
#define RW009_CMD_SOFTAP 133
/** cond !ADDTHIS*/
#define SHARED_ENABLED 0x00008000
#define WPA_SECURITY 0x00200000
#define WPA2_SECURITY 0x00400000
#define WPS_ENABLED 0x10000000
#define WEP_ENABLED 0x0001
#define TKIP_ENABLED 0x0002
#define AES_ENABLED 0x0004
#define WSEC_SWFLAG 0x0008
/** endcond */
/**
* Enumeration of Wi-Fi security modes
*/
typedef enum
{
SECURITY_OPEN = 0, /**< Open security */
SECURITY_WEP_PSK = WEP_ENABLED, /**< WEP Security with open authentication */
SECURITY_WEP_SHARED = ( WEP_ENABLED | SHARED_ENABLED ), /**< WEP Security with shared authentication */
SECURITY_WPA_TKIP_PSK = ( WPA_SECURITY | TKIP_ENABLED ), /**< WPA Security with TKIP */
SECURITY_WPA_AES_PSK = ( WPA_SECURITY | AES_ENABLED ), /**< WPA Security with AES */
SECURITY_WPA2_AES_PSK = ( WPA2_SECURITY | AES_ENABLED ), /**< WPA2 Security with AES */
SECURITY_WPA2_TKIP_PSK = ( WPA2_SECURITY | TKIP_ENABLED ), /**< WPA2 Security with TKIP */
SECURITY_WPA2_MIXED_PSK = ( WPA2_SECURITY | AES_ENABLED | TKIP_ENABLED ), /**< WPA2 Security with AES & TKIP */
SECURITY_WPS_OPEN = WPS_ENABLED, /**< WPS with open security */
SECURITY_WPS_SECURE = (WPS_ENABLED | AES_ENABLED), /**< WPS with AES security */
SECURITY_UNKNOWN = -1, /**< May be returned by scan function if security is unknown. Do not pass this to the join function! */
SECURITY_FORCE_32_BIT = 0x7fffffff /**< Exists only to force wiced_security_t type to 32 bits */
} security_t;
/* porting */
extern void spi_wifi_hw_init(void);
extern void spi_wifi_int_cmd(rt_bool_t cmd);
extern rt_bool_t spi_wifi_is_busy(void);
/* export API. */
extern rt_err_t rt_hw_wifi_init(const char *spi_device_name,wifi_mode_t mode);
extern int32_t rw009_rssi(void);
extern rt_err_t rw009_join(const char * SSID, const char * passwd);
extern rt_err_t rw009_softap(const char * SSID, const char * passwd,uint32_t security,uint32_t channel);
#endif // SPI_WIFI_H_INCLUDED

View File

@@ -0,0 +1,253 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-05-20 tyustli the first version
*/
#include <rtdevice.h>
#include <string.h>
#define DBG_TAG "touch"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
/* ISR for touch interrupt */
void rt_hw_touch_isr(rt_touch_t touch)
{
RT_ASSERT(touch);
if (touch->parent.rx_indicate == RT_NULL)
{
return;
}
if (touch->irq_handle != RT_NULL)
{
touch->irq_handle(touch);
}
touch->parent.rx_indicate(&touch->parent, 1);
}
#ifdef RT_TOUCH_PIN_IRQ
static void touch_irq_callback(void *param)
{
rt_hw_touch_isr((rt_touch_t)param);
}
#endif
/* touch interrupt initialization function */
static rt_err_t rt_touch_irq_init(rt_touch_t touch)
{
#ifdef RT_TOUCH_PIN_IRQ
if (touch->config.irq_pin.pin == PIN_IRQ_PIN_NONE)
{
return -RT_EINVAL;
}
rt_pin_mode(touch->config.irq_pin.pin, touch->config.irq_pin.mode);
if (touch->config.irq_pin.mode == PIN_MODE_INPUT_PULLDOWN)
{
rt_pin_attach_irq(touch->config.irq_pin.pin, PIN_IRQ_MODE_RISING, touch_irq_callback, (void *)touch);
}
else if (touch->config.irq_pin.mode == PIN_MODE_INPUT_PULLUP)
{
rt_pin_attach_irq(touch->config.irq_pin.pin, PIN_IRQ_MODE_FALLING, touch_irq_callback, (void *)touch);
}
else if (touch->config.irq_pin.mode == PIN_MODE_INPUT)
{
rt_pin_attach_irq(touch->config.irq_pin.pin, PIN_IRQ_MODE_RISING_FALLING, touch_irq_callback, (void *)touch);
}
rt_pin_irq_enable(touch->config.irq_pin.pin, PIN_IRQ_ENABLE);
#endif
return RT_EOK;
}
/* touch interrupt enable */
static void rt_touch_irq_enable(rt_touch_t touch)
{
#ifdef RT_TOUCH_PIN_IRQ
if (touch->config.irq_pin.pin != PIN_IRQ_PIN_NONE)
{
rt_pin_irq_enable(touch->config.irq_pin.pin, RT_TRUE);
}
#else
touch->ops->touch_control(touch, RT_TOUCH_CTRL_ENABLE_INT, RT_NULL);
#endif
}
/* touch interrupt disable */
static void rt_touch_irq_disable(rt_touch_t touch)
{
#ifdef RT_TOUCH_PIN_IRQ
if (touch->config.irq_pin.pin != PIN_IRQ_PIN_NONE)
{
rt_pin_irq_enable(touch->config.irq_pin.pin, RT_FALSE);
}
#else
touch->ops->touch_control(touch, RT_TOUCH_CTRL_DISABLE_INT, RT_NULL);
#endif
}
static rt_err_t rt_touch_open(rt_device_t dev, rt_uint16_t oflag)
{
rt_touch_t touch;
RT_ASSERT(dev != RT_NULL);
touch = (rt_touch_t)dev;
if (oflag & RT_DEVICE_FLAG_INT_RX && dev->flag & RT_DEVICE_FLAG_INT_RX)
{
/* Initialization touch interrupt */
rt_touch_irq_init(touch);
}
return RT_EOK;
}
static rt_err_t rt_touch_close(rt_device_t dev)
{
rt_touch_t touch;
RT_ASSERT(dev != RT_NULL);
touch = (rt_touch_t)dev;
/* touch disable interrupt */
rt_touch_irq_disable(touch);
return RT_EOK;
}
static rt_ssize_t rt_touch_read(rt_device_t dev, rt_off_t pos, void *buf, rt_size_t len)
{
rt_touch_t touch;
rt_size_t result = 0;
RT_ASSERT(dev != RT_NULL);
touch = (rt_touch_t)dev;
if (buf == NULL || len == 0)
{
return 0;
}
result = touch->ops->touch_readpoint(touch, buf, len);
return result;
}
static rt_err_t rt_touch_control(rt_device_t dev, int cmd, void *args)
{
rt_touch_t touch;
rt_err_t result = RT_EOK;
RT_ASSERT(dev != RT_NULL);
touch = (rt_touch_t)dev;
switch (cmd)
{
case RT_TOUCH_CTRL_SET_MODE:
result = touch->ops->touch_control(touch, RT_TOUCH_CTRL_SET_MODE, args);
if (result == RT_EOK)
{
rt_uint16_t mode;
mode = *(rt_uint16_t*)args;
if (mode == RT_DEVICE_FLAG_INT_RX)
{
rt_touch_irq_enable(touch); /* enable interrupt */
}
}
break;
case RT_TOUCH_CTRL_SET_X_RANGE:
result = touch->ops->touch_control(touch, RT_TOUCH_CTRL_SET_X_RANGE, args);
if (result == RT_EOK)
{
touch->info.range_x = *(rt_int32_t *)args;
LOG_D("set x coordinate range :%d\n", touch->info.range_x);
}
break;
case RT_TOUCH_CTRL_SET_Y_RANGE:
result = touch->ops->touch_control(touch, RT_TOUCH_CTRL_SET_Y_RANGE, args);
if (result == RT_EOK)
{
touch->info.range_y = *(rt_uint32_t *)args;
LOG_D("set y coordinate range :%d \n", touch->info.range_x);
}
break;
case RT_TOUCH_CTRL_DISABLE_INT:
rt_touch_irq_disable(touch);
break;
case RT_TOUCH_CTRL_ENABLE_INT:
rt_touch_irq_enable(touch);
break;
case RT_TOUCH_CTRL_GET_ID:
case RT_TOUCH_CTRL_GET_INFO:
default:
return touch->ops->touch_control(touch, cmd, args);
}
return result;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops rt_touch_ops =
{
RT_NULL,
rt_touch_open,
rt_touch_close,
rt_touch_read,
RT_NULL,
rt_touch_control
};
#endif
/*
* touch register
*/
int rt_hw_touch_register(rt_touch_t touch,
const char *name,
rt_uint32_t flag,
void *data)
{
rt_err_t result;
rt_device_t device;
RT_ASSERT(touch != RT_NULL);
device = &touch->parent;
#ifdef RT_USING_DEVICE_OPS
device->ops = &rt_touch_ops;
#else
device->init = RT_NULL;
device->open = rt_touch_open;
device->close = rt_touch_close;
device->read = rt_touch_read;
device->write = RT_NULL;
device->control = rt_touch_control;
#endif
device->type = RT_Device_Class_Touch;
device->rx_indicate = RT_NULL;
device->tx_complete = RT_NULL;
device->user_data = data;
result = rt_device_register(device, name, flag | RT_DEVICE_FLAG_STANDALONE);
if (result != RT_EOK)
{
LOG_E("rt_touch register err code: %d", result);
return result;
}
LOG_I("rt_touch init success");
return RT_EOK;
}

View File

@@ -0,0 +1,312 @@
# Kconfig file for CherryUSB
menuconfig CHERRYUSB
bool "Using CherryUSB"
default n
if CHERRYUSB
menuconfig CHERRYUSB_DEVICE
bool "Enable usb device mode"
default n
if CHERRYUSB_DEVICE
choice
prompt "Select usb device speed"
default CHERRYUSB_DEVICE_SPEED_FS
config CHERRYUSB_DEVICE_SPEED_FS
bool "FS"
config CHERRYUSB_DEVICE_SPEED_HS
bool "HS"
config CHERRYUSB_DEVICE_SPEED_AUTO
bool "AUTO"
endchoice
choice
prompt "Select usb device ip, and some ip need config in usb_config.h, please check"
default CHERRYUSB_DEVICE_CUSTOM
config CHERRYUSB_DEVICE_CUSTOM
bool "CUSTOM (Implement it yourself)"
config CHERRYUSB_DEVICE_FSDEV
bool "fsdev"
config CHERRYUSB_DEVICE_DWC2_ST
bool "dwc2_st"
config CHERRYUSB_DEVICE_DWC2_ESP
bool "dwc2_esp"
config CHERRYUSB_DEVICE_DWC2_AT
bool "dwc2_at"
config CHERRYUSB_DEVICE_DWC2_GD
bool "dwc2_gd"
config CHERRYUSB_DEVICE_DWC2_HC
bool "dwc2_hc"
config CHERRYUSB_DEVICE_DWC2_CUSTOM
bool "dwc2_custom"
config CHERRYUSB_DEVICE_MUSB_ES
bool "musb_es"
config CHERRYUSB_DEVICE_MUSB_SUNXI
bool "musb_sunxi"
config CHERRYUSB_DEVICE_MUSB_BK
bool "musb_bk"
config CHERRYUSB_DEVICE_MUSB_CUSTOM
bool "musb_custom"
config CHERRYUSB_DEVICE_BL
bool "bouffalo"
config CHERRYUSB_DEVICE_HPM
bool "hpm"
config CHERRYUSB_DEVICE_AIC
bool "aic"
config CHERRYUSB_DEVICE_CH32
bool "ch32"
config CHERRYUSB_DEVICE_PUSB2
bool "pusb2"
endchoice
config CHERRYUSB_DEVICE_CDC_ACM
bool
prompt "Enable usb cdc acm device"
default n
config CHERRYUSB_DEVICE_HID
bool
prompt "Enable usb hid device"
default n
config CHERRYUSB_DEVICE_MSC
bool
prompt "Enable usb msc device"
default n
config CHERRYUSB_DEVICE_AUDIO
bool
prompt "Enable usb audio device"
default n
config CHERRYUSB_DEVICE_VIDEO
bool
prompt "Enable usb video device"
default n
config CHERRYUSB_DEVICE_CDC_RNDIS
bool
prompt "Enable usb cdc rndis device"
default n
config CHERRYUSB_DEVICE_CDC_ECM
bool
prompt "Enable usb cdc ecm device"
default n
config CHERRYUSB_DEVICE_CDC_NCM
bool
prompt "Enable usb cdc ncm device"
default n
config CHERRYUSB_DEVICE_DFU
bool
prompt "Enable usb dfu device"
default n
choice
prompt "Select usb device template"
default CHERRYUSB_DEVICE_TEMPLATE
config CHERRYUSB_DEVICE_TEMPLATE_NONE
bool "none (Implement it yourself)"
config CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM
bool "cdc_acm"
config CHERRYUSB_DEVICE_TEMPLATE_MSC
bool "msc"
config CHERRYUSB_DEVICE_TEMPLATE_HID_KEYBOARD
bool "hid_keyboard"
config CHERRYUSB_DEVICE_TEMPLATE_HID_MOUSE
bool "hid_mouse"
config CHERRYUSB_DEVICE_TEMPLATE_HID_CUSTOM
bool "hid_custom"
config CHERRYUSB_DEVICE_TEMPLATE_VIDEO
bool "video"
config CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V1_MIC_SPEAKER
bool "audio_v1_mic_speaker_multichan"
config CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V2_MIC_SPEAKER
bool "audio_v2_mic_speaker_multichan"
config CHERRYUSB_DEVICE_TEMPLATE_CDC_RNDIS
bool "cdc_rndis"
config CHERRYUSB_DEVICE_TEMPLATE_CDC_ECM
bool "cdc_ecm"
config CHERRYUSB_DEVICE_TEMPLATE_CDC_NCM
bool "cdc_ncm"
config CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC
bool "cdc_acm_msc"
config CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC_HID
bool "cdc_acm_msc_hid"
config CHERRYUSB_DEVICE_TEMPLATE_WINUSBV1
bool "winusbv1"
config CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_CDC
bool "winusbv2_cdc"
config CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_HID
bool "winusbv2_hid"
endchoice
endif
menuconfig CHERRYUSB_HOST
bool "Enable usb host mode"
default n
if CHERRYUSB_HOST
choice
prompt "Select usb host ip, and some ip need config in usb_config.h, please check"
default CHERRYUSB_HOST_CUSTOM
config CHERRYUSB_HOST_CUSTOM
bool "CUSTOM (Implement it yourself)"
config CHERRYUSB_HOST_EHCI_BL
bool "ehci_bouffalo"
config CHERRYUSB_HOST_EHCI_HPM
bool "ehci_hpm"
config CHERRYUSB_HOST_EHCI_AIC
bool "ehci_aic"
config CHERRYUSB_HOST_EHCI_NUVOTON_NUC980
bool "ehci_nuvoton_nuc980"
config CHERRYUSB_HOST_EHCI_NUVOTON_MA35D0
bool "ehci_nuvoton_ma35d0"
config CHERRYUSB_HOST_EHCI_CUSTOM
bool "ehci_custom"
config CHERRYUSB_HOST_DWC2_ST
bool "dwc2_st"
config CHERRYUSB_HOST_DWC2_ESP
bool "dwc2_esp"
config CHERRYUSB_HOST_DWC2_HC
bool "dwc2_hc"
config CHERRYUSB_HOST_DWC2_CUSTOM
bool "dwc2_custom"
config CHERRYUSB_HOST_MUSB_ES
bool "musb_es"
config CHERRYUSB_HOST_MUSB_SUNXI
bool "musb_sunxi"
config CHERRYUSB_HOST_MUSB_BK
bool "musb_bk"
config CHERRYUSB_HOST_MUSB_CUSTOM
bool "musb_custom"
config CHERRYUSB_HOST_PUSB2
bool "pusb2"
config CHERRYUSB_HOST_XHCI
bool "xhci"
endchoice
config CHERRYUSB_HOST_CDC_ACM
bool
prompt "Enable usb cdc acm driver"
default n
config CHERRYUSB_HOST_HID
bool
prompt "Enable usb hid driver"
default n
config CHERRYUSB_HOST_MSC
bool
prompt "Enable usb msc driver"
default n
config CHERRYUSB_HOST_CDC_ECM
bool
prompt "Enable usb cdc ecm driver"
select USBHOST_PLATFORM_CDC_ECM
default n
config CHERRYUSB_HOST_CDC_RNDIS
bool
prompt "Enable usb rndis driver"
select USBHOST_PLATFORM_CDC_RNDIS
default n
config CHERRYUSB_HOST_CDC_NCM
bool
prompt "Enable usb cdc ncm driver"
select USBHOST_PLATFORM_CDC_NCM
default n
config CHERRYUSB_HOST_VIDEO
bool
prompt "Enable usb video driver, it is commercial charge"
default n
config CHERRYUSB_HOST_AUDIO
bool
prompt "Enable usb audio driver, it is commercial charge"
default n
config CHERRYUSB_HOST_BLUETOOTH
bool
prompt "Enable usb bluetooth driver"
default n
config CHERRYUSB_HOST_ASIX
bool
prompt "Enable usb asix driver"
select USBHOST_PLATFORM_ASIX
default n
config CHERRYUSB_HOST_RTL8152
bool
prompt "Enable usb rtl8152 driver"
select USBHOST_PLATFORM_RTL8152
default n
config CHERRYUSB_HOST_FTDI
bool
prompt "Enable usb ftdi driver"
default n
config CHERRYUSB_HOST_CH34X
bool
prompt "Enable usb ch34x driver"
default n
config CHERRYUSB_HOST_CP210X
bool
prompt "Enable usb cp210x driver"
default n
config CHERRYUSB_HOST_PL2303
bool
prompt "Enable usb pl2303 driver"
default n
config USBHOST_PLATFORM_CDC_ECM
bool
config USBHOST_PLATFORM_CDC_RNDIS
bool
config USBHOST_PLATFORM_CDC_NCM
bool
config USBHOST_PLATFORM_ASIX
bool
config USBHOST_PLATFORM_RTL8152
bool
config CHERRYUSB_HOST_TEMPLATE
bool
prompt "Use usb host template"
default n
if CHERRYUSB_HOST_TEMPLATE
config TEST_USBH_CDC_ACM
int
prompt "demo for test cdc acm"
default 0
depends on CHERRYUSB_HOST_CDC_ACM
config TEST_USBH_HID
int
prompt "demo for test hid"
default 0
depends on CHERRYUSB_HOST_HID
config TEST_USBH_MSC
int
prompt "demo for test msc"
default 0
depends on CHERRYUSB_HOST_MSC
endif
endif
endif

View File

@@ -0,0 +1,118 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
#include "usbd_cdc.h"
const char *stop_name[] = { "1", "1.5", "2" };
const char *parity_name[] = { "N", "O", "E", "M", "S" };
static int cdc_acm_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
USB_LOG_DBG("CDC Class request: "
"bRequest 0x%02x\r\n",
setup->bRequest);
struct cdc_line_coding line_coding;
bool dtr, rts;
uint8_t intf_num = LO_BYTE(setup->wIndex);
switch (setup->bRequest) {
case CDC_REQUEST_SET_LINE_CODING:
/*******************************************************************************/
/* Line Coding Structure */
/*-----------------------------------------------------------------------------*/
/* Offset | Field | Size | Value | Description */
/* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
/* 4 | bCharFormat | 1 | Number | Stop bits */
/* 0 - 1 Stop bit */
/* 1 - 1.5 Stop bits */
/* 2 - 2 Stop bits */
/* 5 | bParityType | 1 | Number | Parity */
/* 0 - None */
/* 1 - Odd */
/* 2 - Even */
/* 3 - Mark */
/* 4 - Space */
/* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
/*******************************************************************************/
memcpy(&line_coding, *data, setup->wLength);
USB_LOG_DBG("Set intf:%d linecoding <%d %d %s %s>\r\n",
intf_num,
line_coding.dwDTERate,
line_coding.bDataBits,
parity_name[line_coding.bParityType],
stop_name[line_coding.bCharFormat]);
usbd_cdc_acm_set_line_coding(busid, intf_num, &line_coding);
break;
case CDC_REQUEST_SET_CONTROL_LINE_STATE:
dtr = (setup->wValue & 0x0001);
rts = (setup->wValue & 0x0002);
USB_LOG_DBG("Set intf:%d DTR 0x%x,RTS 0x%x\r\n",
intf_num,
dtr,
rts);
usbd_cdc_acm_set_dtr(busid, intf_num, dtr);
usbd_cdc_acm_set_rts(busid, intf_num, rts);
break;
case CDC_REQUEST_GET_LINE_CODING:
usbd_cdc_acm_get_line_coding(busid, intf_num, &line_coding);
memcpy(*data, &line_coding, 7);
*len = 7;
USB_LOG_DBG("Get intf:%d linecoding %d %d %d %d\r\n",
intf_num,
line_coding.dwDTERate,
line_coding.bCharFormat,
line_coding.bParityType,
line_coding.bDataBits);
break;
case CDC_REQUEST_SEND_BREAK:
usbd_cdc_acm_send_break(busid, intf_num);
break;
default:
USB_LOG_WRN("Unhandled CDC Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
return 0;
}
struct usbd_interface *usbd_cdc_acm_init_intf(uint8_t busid, struct usbd_interface *intf)
{
intf->class_interface_handler = cdc_acm_class_interface_request_handler;
intf->class_endpoint_handler = NULL;
intf->vendor_handler = NULL;
intf->notify_handler = NULL;
return intf;
}
__WEAK void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding)
{
}
__WEAK void usbd_cdc_acm_get_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding)
{
line_coding->dwDTERate = 2000000;
line_coding->bDataBits = 8;
line_coding->bParityType = 0;
line_coding->bCharFormat = 0;
}
__WEAK void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr)
{
}
__WEAK void usbd_cdc_acm_set_rts(uint8_t busid, uint8_t intf, bool rts)
{
}
__WEAK void usbd_cdc_acm_send_break(uint8_t busid, uint8_t intf)
{
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
#define MS_OS_20_DESCRIPTOR_LENGTH (0xB2)
#define WEBUSB_URL_STRINGS \
'd', 'e', 'v', 'a', 'n', 'l', 'a', 'i', '.', 'g', 'i', 't', 'h', 'u', 'b', '.', 'i', 'o', '/', 'w', 'e', 'b', 'd', 'f', 'u', '/', 'd', 'f', 'u', '-', 'u', 't', 'i', 'l'
#define WL_REQUEST_WEBUSB (0x22)
#define WL_REQUEST_WINUSB (0x21)
#define URL_DESCRIPTOR_LENGTH 0x2C
// 描述符集信息
const uint8_t MS_OS_20_DESCRIPTOR_SET[MS_OS_20_DESCRIPTOR_LENGTH] = {
// Microsoft OS 2.0 描述符集标头
0x0A, 0x00, // Descriptor size (10 bytes)
0x00, 0x00, // MS OS 2.0 descriptor set header
0x00, 0x00, 0x03, 0x06, // Windows version (8.1) (0x06030000)
MS_OS_20_DESCRIPTOR_LENGTH, 0x00, // Size, MS OS 2.0 descriptor set
// Microsoft OS 2.0 配置子集标头
0x08, 0x00, // wLength
0x01, 0x00, // wDescriptorType
0x00, // 适用于配置 1
0x00, // bReserved
0XA8, 0X00, // Size, MS OS 2.0 configuration subset
// Microsoft OS 2.0 功能子集头
0x08, 0x00, // Descriptor size (8 bytes)
0x02, 0x00, // MS OS 2.0 function subset header
0x01, // 第2个接口
0x00, // 必须设置为 0
0xA0, 0x00,
// Microsoft OS 2.0 兼容 ID 描述符
// 兼容 ID 描述符告诉 Windows 此设备与 WinUSB 驱动程序兼容
0x14, 0x00, // wLength 20
0x03, 0x00, // MS_OS_20_FEATURE_COMPATIBLE_ID
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Microsoft OS 2.0 注册表属性描述符
// 注册表属性分配设备接口 GUID
0x84, 0x00, //wLength: 132
0x04, 0x00, // wDescriptorType: MS_OS_20_FEATURE_REG_PROPERTY: 0x04 (Table 9)
0x07, 0x00, //wPropertyDataType: REG_MULTI_SZ (Table 15)
0x2a, 0x00, //wPropertyNameLength:
//bPropertyName: “DeviceInterfaceGUID”
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00,
'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00,
0x00, 0x00,
0x50, 0x00, // wPropertyDataLength
//bPropertyData: “{975F44D9-0D08-43FD-8B3E-127CA8AFFF9D}”.
'{', 0x00, '9', 0x00, 'd', 0x00, '7', 0x00, 'd', 0x00, 'e', 0x00, 'b', 0x00, 'b', 0x00, 'c', 0x00, '-', 0x00,
'c', 0x00, '8', 0x00, '5', 0x00, 'd', 0x00, '-', 0x00, '1', 0x00, '1', 0x00, 'd', 0x00, '1', 0x00, '-', 0x00,
'9', 0x00, 'e', 0x00, 'b', 0x00, '4', 0x00, '-', 0x00, '0', 0x00, '0', 0x00, '6', 0x00, '0', 0x00, '0', 0x00,
'8', 0x00, 'c', 0x00, '3', 0x00, 'a', 0x00, '1', 0x00, '9', 0x00, 'a', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00
};
const uint8_t USBD_WebUSBURLDescriptor[URL_DESCRIPTOR_LENGTH] = {
URL_DESCRIPTOR_LENGTH,
WEBUSB_URL_TYPE,
WEBUSB_URL_SCHEME_HTTPS,
WEBUSB_URL_STRINGS
};
struct usb_webusb_url_ex_descriptor webusb_url_desc = {
.vendor_code = WL_REQUEST_WEBUSB,
.string = MS_OS_20_DESCRIPTOR_SET,
.string_len = MS_OS_20_DESCRIPTOR_LENGTH
};

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _USB_EHCI_PRIV_H
#define _USB_EHCI_PRIV_H
#include "usbh_core.h"
#include "usbh_hub.h"
#include "usb_hc_ehci.h"
#define EHCI_HCCR ((struct ehci_hccr *)(uintptr_t)(bus->hcd.reg_base + CONFIG_USB_EHCI_HCCR_OFFSET))
#define EHCI_HCOR ((struct ehci_hcor *)(uintptr_t)(bus->hcd.reg_base + CONFIG_USB_EHCI_HCCR_OFFSET + g_ehci_hcd[bus->hcd.hcd_id].hcor_offset))
#define EHCI_PTR2ADDR(x) ((uint32_t)(uintptr_t)(x) & ~0x1F)
#define EHCI_ADDR2QH(x) ((struct ehci_qh_hw *)(uintptr_t)((uint32_t)(x) & ~0x1F))
#define EHCI_ADDR2QTD(x) ((struct ehci_qtd_hw *)(uintptr_t)((uint32_t)(x) & ~0x1F))
#define EHCI_ADDR2ITD(x) ((struct ehci_itd_hw *)(uintptr_t)((uint32_t)(x) & ~0x1F))
#ifndef CONFIG_USB_EHCI_QH_NUM
#define CONFIG_USB_EHCI_QH_NUM CONFIG_USBHOST_PIPE_NUM
#endif
#ifndef CONFIG_USB_EHCI_QTD_NUM
#define CONFIG_USB_EHCI_QTD_NUM 3
#endif
#ifndef CONFIG_USB_EHCI_ITD_NUM
#define CONFIG_USB_EHCI_ITD_NUM 5
#endif
#ifndef CONFIG_USB_EHCI_ISO_NUM
#define CONFIG_USB_EHCI_ISO_NUM 4
#endif
extern uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port);
struct ehci_qtd_hw {
struct ehci_qtd hw;
struct usbh_urb *urb;
uint32_t length;
} __attribute__((aligned(32)));
struct ehci_qh_hw {
struct ehci_qh hw;
struct ehci_qtd_hw qtd_pool[CONFIG_USB_EHCI_QTD_NUM];
uint32_t first_qtd;
struct usbh_urb *urb;
usb_osal_sem_t waitsem;
uint8_t remove_in_iaad;
} __attribute__((aligned(32)));
struct ehci_itd_hw {
struct ehci_itd hw;
struct usbh_urb *urb;
uint16_t start_frame;
uint8_t mf_unmask;
uint8_t mf_valid;
uint32_t pkt_idx[8];
} __attribute__((aligned(32)));
struct ehci_iso_hw
{
struct ehci_itd_hw itd_pool[CONFIG_USB_EHCI_ITD_NUM];
uint32_t itd_num;
};
struct ehci_hcd {
bool ehci_qh_used[CONFIG_USB_EHCI_QH_NUM];
bool ehci_iso_used[CONFIG_USB_EHCI_ISO_NUM];
bool ppc; /* Port Power Control */
bool has_tt; /* if use tt instead of Companion Controller */
uint8_t n_cc; /* Number of Companion Controller */
uint8_t n_pcc; /* Number of ports supported per companion host controller */
uint8_t n_ports;
uint8_t hcor_offset;
};
extern struct ehci_hcd g_ehci_hcd[CONFIG_USBHOST_MAX_BUS];
extern uint32_t g_framelist[CONFIG_USBHOST_MAX_BUS][USB_ALIGN_UP(CONFIG_USB_EHCI_FRAME_LIST_SIZE, 1024)];
int ehci_iso_urb_init(struct usbh_bus *bus, struct usbh_urb *urb);
void ehci_kill_iso_urb(struct usbh_bus *bus, struct usbh_urb *urb);
void ehci_scan_isochronous_list(struct usbh_bus *bus);
#endif

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _USB_OHCI_PRIV_H
#define _USB_OHCI_PRIV_H
#include "usbh_core.h"
#include "usbh_hub.h"
#include "usb_hc_ohci.h"
#define OHCI_HCOR ((struct ohci_hcor *)(uintptr_t)(bus->hcd.reg_base + CONFIG_USB_OHCI_HCOR_OFFSET))
int ohci_init(struct usbh_bus *bus);
int ohci_deinit(struct usbh_bus *bus);
uint16_t ohci_get_frame_number(struct usbh_bus *bus);
int ohci_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf);
int ohci_submit_urb(struct usbh_urb *urb);
int ohci_kill_urb(struct usbh_urb *urb);
void OHCI_IRQHandler(uint8_t busid);
#endif

View File

@@ -0,0 +1,110 @@
/*
* COPYRIGHT (C) 2011-2023, Real-Thread Information Technology Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-09-12 heyuanjie87 first version.
* 2014-03-04 Bernard code cleanup
*/
#include <drivers/watchdog.h>
/* RT-Thread Device Interface */
/*
* This function initializes watchdog
*/
static rt_err_t rt_watchdog_init(struct rt_device *dev)
{
rt_watchdog_t *wtd;
RT_ASSERT(dev != RT_NULL);
wtd = (rt_watchdog_t *)dev;
if (wtd->ops->init)
{
return (wtd->ops->init(wtd));
}
return (-RT_ENOSYS);
}
static rt_err_t rt_watchdog_open(struct rt_device *dev, rt_uint16_t oflag)
{
return (RT_EOK);
}
static rt_err_t rt_watchdog_close(struct rt_device *dev)
{
rt_watchdog_t *wtd;
RT_ASSERT(dev != RT_NULL);
wtd = (rt_watchdog_t *)dev;
if (wtd->ops->control(wtd, RT_DEVICE_CTRL_WDT_STOP, RT_NULL) != RT_EOK)
{
rt_kprintf(" This watchdog can not be stoped\n");
return (-RT_ERROR);
}
return (RT_EOK);
}
static rt_err_t rt_watchdog_control(struct rt_device *dev,
int cmd,
void *args)
{
rt_watchdog_t *wtd;
RT_ASSERT(dev != RT_NULL);
wtd = (rt_watchdog_t *)dev;
return (wtd->ops->control(wtd, cmd, args));
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops wdt_ops =
{
rt_watchdog_init,
rt_watchdog_open,
rt_watchdog_close,
RT_NULL,
RT_NULL,
rt_watchdog_control,
};
#endif
/**
* This function register a watchdog device
*/
rt_err_t rt_hw_watchdog_register(struct rt_watchdog_device *wtd,
const char *name,
rt_uint32_t flag,
void *data)
{
struct rt_device *device;
RT_ASSERT(wtd != RT_NULL);
device = &(wtd->parent);
device->type = RT_Device_Class_WDT;
device->rx_indicate = RT_NULL;
device->tx_complete = RT_NULL;
#ifdef RT_USING_DEVICE_OPS
device->ops = &wdt_ops;
#else
device->init = rt_watchdog_init;
device->open = rt_watchdog_open;
device->close = rt_watchdog_close;
device->read = RT_NULL;
device->write = RT_NULL;
device->control = rt_watchdog_control;
#endif
device->user_data = data;
/* register a character device */
return rt_device_register(device, name, flag);
}

View File

@@ -0,0 +1,468 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-08-06 tyx the first version
*/
#include <rtthread.h>
#include <wlan_cfg.h>
#define DBG_TAG "WLAN.cfg"
#ifdef RT_WLAN_CFG_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif /* RT_WLAN_CFG_DEBUG */
#include <rtdbg.h>
#ifdef RT_WLAN_CFG_ENABLE
#define WLAN_CFG_LOCK() (rt_mutex_take(&cfg_mutex, RT_WAITING_FOREVER))
#define WLAN_CFG_UNLOCK() (rt_mutex_release(&cfg_mutex))
#if RT_WLAN_CFG_INFO_MAX < 1
#error "The minimum configuration is 1"
#endif
struct cfg_save_info_head
{
rt_uint32_t magic;
rt_uint32_t len;
rt_uint32_t num;
rt_uint32_t crc;
};
struct rt_wlan_cfg_des
{
rt_uint32_t num;
struct rt_wlan_cfg_info *cfg_info;
};
static struct rt_wlan_cfg_des *cfg_cache;
static const struct rt_wlan_cfg_ops *cfg_ops;
static struct rt_mutex cfg_mutex;
/*
* CRC16_CCITT
*/
static rt_uint16_t rt_wlan_cal_crc(rt_uint8_t *buff, int len)
{
rt_uint16_t wCRCin = 0x0000;
rt_uint16_t wCPoly = 0x1021;
rt_uint8_t wChar = 0;
while (len--)
{
int i;
wChar = *(buff++);
wCRCin ^= (wChar << 8);
for (i = 0; i < 8; i++)
{
if (wCRCin & 0x8000)
wCRCin = (wCRCin << 1) ^ wCPoly;
else
wCRCin = wCRCin << 1;
}
}
return wCRCin;
}
void rt_wlan_cfg_init(void)
{
/* init cache memory */
if (cfg_cache == RT_NULL)
{
cfg_cache = rt_malloc(sizeof(struct rt_wlan_cfg_des));
if (cfg_cache != RT_NULL)
{
rt_memset(cfg_cache, 0, sizeof(struct rt_wlan_cfg_des));
}
/* init mutex lock */
rt_mutex_init(&cfg_mutex, "wlan_cfg", RT_IPC_FLAG_PRIO);
}
}
void rt_wlan_cfg_set_ops(const struct rt_wlan_cfg_ops *ops)
{
rt_wlan_cfg_init();
WLAN_CFG_LOCK();
/* save ops pointer */
cfg_ops = ops;
WLAN_CFG_UNLOCK();
}
/* save config data */
rt_err_t rt_wlan_cfg_cache_save(void)
{
rt_err_t err = RT_EOK;
struct cfg_save_info_head *info_pkg;
int len = 0;
if ((cfg_ops == RT_NULL) || (cfg_ops->write_cfg == RT_NULL))
return RT_EOK;
WLAN_CFG_LOCK();
len = sizeof(struct cfg_save_info_head) + sizeof(struct rt_wlan_cfg_info) * cfg_cache->num;
info_pkg = rt_malloc(len);
if (info_pkg == RT_NULL)
{
WLAN_CFG_UNLOCK();
return -RT_ENOMEM;
}
info_pkg->magic = RT_WLAN_CFG_MAGIC;
info_pkg->len = len;
info_pkg->num = cfg_cache->num;
/* CRC */
info_pkg->crc = rt_wlan_cal_crc((rt_uint8_t *)cfg_cache->cfg_info, sizeof(struct rt_wlan_cfg_info) * cfg_cache->num);
rt_memcpy(((rt_uint8_t *)info_pkg) + sizeof(struct cfg_save_info_head),
cfg_cache->cfg_info, sizeof(struct rt_wlan_cfg_info) * cfg_cache->num);
if (cfg_ops->write_cfg(info_pkg, len) != len)
err = -RT_ERROR;
rt_free(info_pkg);
WLAN_CFG_UNLOCK();
return err;
}
rt_err_t rt_wlan_cfg_cache_refresh(void)
{
int len = 0, i, j;
struct cfg_save_info_head *head;
void *data;
struct rt_wlan_cfg_info *t_info, *cfg_info;
rt_uint32_t crc;
rt_bool_t equal_flag;
/* cache is full! exit */
if (cfg_cache == RT_NULL || cfg_cache->num >= RT_WLAN_CFG_INFO_MAX)
return -RT_ERROR;
/* check callback */
if ((cfg_ops == RT_NULL) ||
(cfg_ops->get_len == RT_NULL) ||
(cfg_ops->read_cfg == RT_NULL))
return -RT_ERROR;
WLAN_CFG_LOCK();
/* get data len */
if ((len = cfg_ops->get_len()) <= 0)
{
WLAN_CFG_UNLOCK();
return -RT_ERROR;
}
head = rt_malloc(len);
if (head == RT_NULL)
{
WLAN_CFG_UNLOCK();
return -RT_ERROR;
}
/* get data */
if (cfg_ops->read_cfg(head, len) != len)
{
rt_free(head);
WLAN_CFG_UNLOCK();
return -RT_ERROR;
}
/* get config */
data = ((rt_uint8_t *)head) + sizeof(struct cfg_save_info_head);
crc = rt_wlan_cal_crc((rt_uint8_t *)data, len - sizeof(struct cfg_save_info_head));
LOG_D("head->magic:0x%08x RT_WLAN_CFG_MAGIC:0x%08x", head->magic, RT_WLAN_CFG_MAGIC);
LOG_D("head->len:%d len:%d", head->len, len);
LOG_D("head->num:%d num:%d", head->num, (len - sizeof(struct cfg_save_info_head)) / sizeof(struct rt_wlan_cfg_info));
LOG_D("hred->crc:0x%04x crc:0x%04x", head->crc, crc);
/* check */
if ((head->magic != RT_WLAN_CFG_MAGIC) ||
(head->len != len) ||
(head->num != (len - sizeof(struct cfg_save_info_head)) / sizeof(struct rt_wlan_cfg_info)) ||
(head->crc != crc))
{
rt_free(head);
WLAN_CFG_UNLOCK();
return -RT_ERROR;
}
/* remove duplicate config */
cfg_info = (struct rt_wlan_cfg_info *)data;
for (i = 0; i < head->num; i++)
{
equal_flag = RT_FALSE;
for (j = 0; j < cfg_cache->num; j++)
{
if ((cfg_cache->cfg_info[j].info.ssid.len == cfg_info[i].info.ssid.len) &&
(rt_memcmp(&cfg_cache->cfg_info[j].info.ssid.val[0], &cfg_info[i].info.ssid.val[0],
cfg_cache->cfg_info[j].info.ssid.len) == 0) &&
(rt_memcmp(&cfg_cache->cfg_info[j].info.bssid[0], &cfg_info[i].info.bssid[0], RT_WLAN_BSSID_MAX_LENGTH) == 0))
{
equal_flag = RT_TRUE;
break;
}
}
if (cfg_cache->num >= RT_WLAN_CFG_INFO_MAX)
{
break;
}
if (equal_flag == RT_FALSE)
{
t_info = rt_realloc(cfg_cache->cfg_info, sizeof(struct rt_wlan_cfg_info) * (cfg_cache->num + 1));
if (t_info == RT_NULL)
{
rt_free(head);
WLAN_CFG_UNLOCK();
return -RT_ERROR;
}
cfg_cache->cfg_info = t_info;
cfg_cache->cfg_info[cfg_cache->num] = cfg_info[i];
cfg_cache->num ++;
}
}
rt_free(head);
WLAN_CFG_UNLOCK();
return RT_EOK;
}
int rt_wlan_cfg_get_num(void)
{
rt_wlan_cfg_init();
return cfg_cache->num;
}
int rt_wlan_cfg_read(struct rt_wlan_cfg_info *cfg_info, int num)
{
rt_wlan_cfg_init();
if ((cfg_info == RT_NULL) || (num <= 0))
return 0;
/* copy data */
WLAN_CFG_LOCK();
num = cfg_cache->num > num ? num : cfg_cache->num;
rt_memcpy(&cfg_cache->cfg_info[0], cfg_info, sizeof(struct rt_wlan_cfg_info) * num);
WLAN_CFG_UNLOCK();
return num;
}
rt_err_t rt_wlan_cfg_save(struct rt_wlan_cfg_info *cfg_info)
{
rt_err_t err = RT_EOK;
struct rt_wlan_cfg_info *t_info;
int idx = -1, i = 0;
rt_wlan_cfg_init();
/* parameter check */
if ((cfg_info == RT_NULL) || (cfg_info->info.ssid.len == 0))
{
return -RT_EINVAL;
}
/* if (iteam == cache) exit */
WLAN_CFG_LOCK();
for (i = 0; i < cfg_cache->num; i++)
{
if ((cfg_cache->cfg_info[i].info.ssid.len == cfg_info->info.ssid.len) &&
(rt_memcmp(&cfg_cache->cfg_info[i].info.ssid.val[0], &cfg_info->info.ssid.val[0],
cfg_cache->cfg_info[i].info.ssid.len) == 0) &&
(rt_memcmp(&cfg_cache->cfg_info[i].info.bssid[0], &cfg_info->info.bssid[0], RT_WLAN_BSSID_MAX_LENGTH) == 0))
{
idx = i;
break;
}
}
if ((idx == 0) && (cfg_cache->cfg_info[i].key.len == cfg_info->key.len) &&
(rt_memcmp(&cfg_cache->cfg_info[i].key.val[0], &cfg_info->key.val[0], cfg_info->key.len) == 0))
{
WLAN_CFG_UNLOCK();
return RT_EOK;
}
/* not find iteam with cache, Add iteam to the head */
if ((idx == -1) && (cfg_cache->num < RT_WLAN_CFG_INFO_MAX))
{
t_info = rt_realloc(cfg_cache->cfg_info, sizeof(struct rt_wlan_cfg_info) * (cfg_cache->num + 1));
if (t_info == RT_NULL)
{
WLAN_CFG_UNLOCK();
return -RT_ENOMEM;
}
cfg_cache->cfg_info = t_info;
cfg_cache->num ++;
}
/* move cache info */
i = (i >= RT_WLAN_CFG_INFO_MAX ? RT_WLAN_CFG_INFO_MAX - 1 : i);
for (; i; i--)
{
cfg_cache->cfg_info[i] = cfg_cache->cfg_info[i - 1];
}
/* add iteam to head */
cfg_cache->cfg_info[i] = *cfg_info;
WLAN_CFG_UNLOCK();
/* save info to flash */
err = rt_wlan_cfg_cache_save();
return err;
}
int rt_wlan_cfg_read_index(struct rt_wlan_cfg_info *cfg_info, int index)
{
rt_wlan_cfg_init();
if ((cfg_info == RT_NULL) || (index < 0))
return 0;
WLAN_CFG_LOCK();
if (index >= cfg_cache->num)
{
WLAN_CFG_UNLOCK();
return 0;
}
/* copy data */
*cfg_info = cfg_cache->cfg_info[index];
WLAN_CFG_UNLOCK();
return 1;
}
int rt_wlan_cfg_delete_index(int index)
{
struct rt_wlan_cfg_info *cfg_info;
int i;
rt_wlan_cfg_init();
if (index < 0)
return -1;
WLAN_CFG_LOCK();
if (index >= cfg_cache->num)
{
WLAN_CFG_UNLOCK();
return -1;
}
/* malloc new mem */
cfg_info = rt_malloc(sizeof(struct rt_wlan_cfg_info) * (cfg_cache->num - 1));
if (cfg_info == RT_NULL)
{
WLAN_CFG_UNLOCK();
return -1;
}
/* copy data to new mem */
for (i = 0; i < cfg_cache->num; i++)
{
if (i < index)
{
cfg_info[i] = cfg_cache->cfg_info[i];
}
else if (i > index)
{
cfg_info[i - 1] = cfg_cache->cfg_info[i];
}
}
rt_free(cfg_cache->cfg_info);
cfg_cache->cfg_info = cfg_info;
cfg_cache->num --;
WLAN_CFG_UNLOCK();
return 0;
}
void rt_wlan_cfg_delete_all(void)
{
rt_wlan_cfg_init();
/* delete all iteam */
WLAN_CFG_LOCK();
cfg_cache->num = 0;
rt_free(cfg_cache->cfg_info);
cfg_cache->cfg_info = RT_NULL;
WLAN_CFG_UNLOCK();
}
void rt_wlan_cfg_dump(void)
{
int index = 0;
struct rt_wlan_info *info;
struct rt_wlan_key *key;
char *security;
rt_wlan_cfg_init();
rt_kprintf(" SSID PASSWORD MAC security chn\n");
rt_kprintf("------------------------------- ------------------------------- ----------------- -------------- ---\n");
for (index = 0; index < cfg_cache->num; index ++)
{
info = &cfg_cache->cfg_info[index].info;
key = &cfg_cache->cfg_info[index].key;
if (info->ssid.len)
rt_kprintf("%-32.32s", &info->ssid.val[0]);
else
rt_kprintf("%-32.32s", " ");
if (key->len)
rt_kprintf("%-32.32s", &key->val[0]);
else
rt_kprintf("%-32.32s", " ");
rt_kprintf("%02x:%02x:%02x:%02x:%02x:%02x ",
info->bssid[0],
info->bssid[1],
info->bssid[2],
info->bssid[3],
info->bssid[4],
info->bssid[5]
);
switch (info->security)
{
case SECURITY_OPEN:
security = "OPEN";
break;
case SECURITY_WEP_PSK:
security = "WEP_PSK";
break;
case SECURITY_WEP_SHARED:
security = "WEP_SHARED";
break;
case SECURITY_WPA_TKIP_PSK:
security = "WPA_TKIP_PSK";
break;
case SECURITY_WPA_AES_PSK:
security = "WPA_AES_PSK";
break;
case SECURITY_WPA2_AES_PSK:
security = "WPA2_AES_PSK";
break;
case SECURITY_WPA2_TKIP_PSK:
security = "WPA2_TKIP_PSK";
break;
case SECURITY_WPA2_MIXED_PSK:
security = "WPA2_MIXED_PSK";
break;
case SECURITY_WPS_OPEN:
security = "WPS_OPEN";
break;
case SECURITY_WPS_SECURE:
security = "WPS_SECURE";
break;
default:
security = "UNKNOWN";
break;
}
rt_kprintf("%-14.14s ", security);
rt_kprintf("%3d \n", info->channel);
}
}
#endif

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-08-06 tyx the first version
*/
#ifndef __WLAN_CFG_H__
#define __WLAN_CFG_H__
#include <wlan_dev.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef RT_WLAN_CFG_INFO_MAX
#define RT_WLAN_CFG_INFO_MAX (3) /* min is 1 */
#endif
#define RT_WLAN_CFG_MAGIC (0x426f6d62)
struct rt_wlan_cfg_info
{
struct rt_wlan_info info;
struct rt_wlan_key key;
};
typedef int (*rt_wlan_wr)(void *buff, int len);
struct rt_wlan_cfg_ops
{
int (*read_cfg)(void *buff, int len);
int (*get_len)(void);
int (*write_cfg)(void *buff, int len);
};
void rt_wlan_cfg_init(void);
void rt_wlan_cfg_set_ops(const struct rt_wlan_cfg_ops *ops);
int rt_wlan_cfg_get_num(void);
int rt_wlan_cfg_read(struct rt_wlan_cfg_info *cfg_info, int num);
int rt_wlan_cfg_read_index(struct rt_wlan_cfg_info *cfg_info, int index);
rt_err_t rt_wlan_cfg_save(struct rt_wlan_cfg_info *cfg_info);
rt_err_t rt_wlan_cfg_cache_refresh(void);
rt_err_t rt_wlan_cfg_cache_save(void);
int rt_wlan_cfg_delete_index(int index);
void rt_wlan_cfg_delete_all(void);
void rt_wlan_cfg_dump(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,827 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-08-13 tyx the first version
* 2024-03-24 Evlers fixed a duplicate issue with the wifi scan command
*/
#include <rtthread.h>
#include <rthw.h>
#include <wlan_mgnt.h>
#include <wlan_cfg.h>
#include <wlan_prot.h>
#define DBG_TAG "WLAN.cmd"
#ifdef RT_WLAN_MGNT_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif /* RT_WLAN_MGNT_DEBUG */
#include <rtdbg.h>
static struct rt_wlan_scan_result scan_result;
static struct rt_wlan_info *scan_filter = RT_NULL;
#if defined(RT_WLAN_MANAGE_ENABLE) && defined(RT_WLAN_MSH_CMD_ENABLE)
struct wifi_cmd_des
{
const char *cmd;
int (*fun)(int argc, char *argv[]);
};
static int wifi_help(int argc, char *argv[]);
static int wifi_scan(int argc, char *argv[]);
static int wifi_status(int argc, char *argv[]);
static int wifi_join(int argc, char *argv[]);
static int wifi_ap(int argc, char *argv[]);
static int wifi_list_sta(int argc, char *argv[]);
static int wifi_disconnect(int argc, char *argv[]);
static int wifi_ap_stop(int argc, char *argv[]);
#ifdef RT_WLAN_CMD_DEBUG
/* just for debug */
static int wifi_debug(int argc, char *argv[]);
static int wifi_debug_save_cfg(int argc, char *argv[]);
static int wifi_debug_dump_cfg(int argc, char *argv[]);
static int wifi_debug_clear_cfg(int argc, char *argv[]);
static int wifi_debug_dump_prot(int argc, char *argv[]);
static int wifi_debug_set_mode(int argc, char *argv[]);
static int wifi_debug_set_prot(int argc, char *argv[]);
static int wifi_debug_set_autoconnect(int argc, char *argv[]);
#endif
/* cmd table */
static const struct wifi_cmd_des cmd_tab[] =
{
{"scan", wifi_scan},
{"help", wifi_help},
{"status", wifi_status},
{"join", wifi_join},
{"ap", wifi_ap},
{"list_sta", wifi_list_sta},
{"disc", wifi_disconnect},
{"ap_stop", wifi_ap_stop},
{"smartconfig", RT_NULL},
#ifdef RT_WLAN_CMD_DEBUG
{"-d", wifi_debug},
#endif
};
#ifdef RT_WLAN_CMD_DEBUG
/* debug cmd table */
static const struct wifi_cmd_des debug_tab[] =
{
{"save_cfg", wifi_debug_save_cfg},
{"dump_cfg", wifi_debug_dump_cfg},
{"clear_cfg", wifi_debug_clear_cfg},
{"dump_prot", wifi_debug_dump_prot},
{"mode", wifi_debug_set_mode},
{"prot", wifi_debug_set_prot},
{"auto", wifi_debug_set_autoconnect},
};
#endif
static int wifi_help(int argc, char *argv[])
{
rt_kprintf("wifi\n");
rt_kprintf("wifi help\n");
rt_kprintf("wifi scan [SSID]\n");
rt_kprintf("wifi join [SSID] [PASSWORD]\n");
rt_kprintf("wifi ap SSID [PASSWORD]\n");
rt_kprintf("wifi disc\n");
rt_kprintf("wifi ap_stop\n");
rt_kprintf("wifi status\n");
rt_kprintf("wifi smartconfig\n");
#ifdef RT_WLAN_CMD_DEBUG
rt_kprintf("wifi -d debug command\n");
#endif
return 0;
}
static int wifi_status(int argc, char *argv[])
{
int rssi;
struct rt_wlan_info info;
if (argc > 2)
return -1;
if (rt_wlan_is_connected() == 1)
{
rssi = rt_wlan_get_rssi();
rt_wlan_get_info(&info);
rt_kprintf("Wi-Fi STA Info\n");
rt_kprintf("SSID : %-.32s\n", &info.ssid.val[0]);
rt_kprintf("MAC Addr: %02x:%02x:%02x:%02x:%02x:%02x\n", info.bssid[0],
info.bssid[1],
info.bssid[2],
info.bssid[3],
info.bssid[4],
info.bssid[5]);
rt_kprintf("Channel: %d\n", info.channel);
rt_kprintf("DataRate: %dMbps\n", info.datarate / 1000000);
rt_kprintf("RSSI: %d\n", rssi);
}
else
{
rt_kprintf("wifi disconnected!\n");
}
if (rt_wlan_ap_is_active() == 1)
{
rt_wlan_ap_get_info(&info);
rt_kprintf("Wi-Fi AP Info\n");
rt_kprintf("SSID : %-.32s\n", &info.ssid.val[0]);
rt_kprintf("MAC Addr: %02x:%02x:%02x:%02x:%02x:%02x\n", info.bssid[0],
info.bssid[1],
info.bssid[2],
info.bssid[3],
info.bssid[4],
info.bssid[5]);
rt_kprintf("Channel: %d\n", info.channel);
rt_kprintf("DataRate: %dMbps\n", info.datarate / 1000000);
rt_kprintf("hidden: %s\n", info.hidden ? "Enable" : "Disable");
}
else
{
rt_kprintf("wifi ap not start!\n");
}
rt_kprintf("Auto Connect status:%s!\n", (rt_wlan_get_autoreconnect_mode() ? "Enable" : "Disable"));
return 0;
}
static rt_bool_t wifi_info_isequ(struct rt_wlan_info *info1, struct rt_wlan_info *info2)
{
rt_bool_t is_equ = 1;
rt_uint8_t bssid_zero[RT_WLAN_BSSID_MAX_LENGTH] = { 0 };
if (is_equ && (info1->security != SECURITY_UNKNOWN) && (info2->security != SECURITY_UNKNOWN))
{
is_equ &= info2->security == info1->security;
}
if (is_equ && ((info1->ssid.len > 0) && (info2->ssid.len > 0)))
{
is_equ &= info1->ssid.len == info2->ssid.len;
is_equ &= rt_memcmp(&info2->ssid.val[0], &info1->ssid.val[0], info1->ssid.len) == 0;
}
if (is_equ && (rt_memcmp(&info1->bssid[0], bssid_zero, RT_WLAN_BSSID_MAX_LENGTH)) &&
(rt_memcmp(&info2->bssid[0], bssid_zero, RT_WLAN_BSSID_MAX_LENGTH)))
{
is_equ &= rt_memcmp(&info1->bssid[0], &info2->bssid[0], RT_WLAN_BSSID_MAX_LENGTH) == 0;
}
if (is_equ && info1->datarate && info2->datarate)
{
is_equ &= info1->datarate == info2->datarate;
}
if (is_equ && (info1->channel >= 0) && (info2->channel >= 0))
{
is_equ &= info1->channel == info2->channel;
}
if (is_equ && (info1->rssi < 0) && (info2->rssi < 0))
{
is_equ &= info1->rssi == info2->rssi;
}
return is_equ;
}
static rt_err_t wifi_scan_result_cache(struct rt_wlan_info *info)
{
struct rt_wlan_info *ptable;
rt_err_t err = RT_EOK;
int i, insert = -1;
rt_base_t level;
if ((info == RT_NULL) || (info->ssid.len == 0)) return -RT_EINVAL;
LOG_D("ssid:%s len:%d mac:%02x:%02x:%02x:%02x:%02x:%02x", info->ssid.val, info->ssid.len,
info->bssid[0], info->bssid[1], info->bssid[2], info->bssid[3], info->bssid[4], info->bssid[5]);
/* scanning result filtering */
level = rt_hw_interrupt_disable();
if (scan_filter)
{
struct rt_wlan_info _tmp_info = *scan_filter;
rt_hw_interrupt_enable(level);
if (wifi_info_isequ(&_tmp_info, info) != RT_TRUE)
{
return RT_EOK;
}
}
else
{
rt_hw_interrupt_enable(level);
}
/* de-duplicatio */
for (i = 0; i < scan_result.num; i++)
{
if ((info->ssid.len == scan_result.info[i].ssid.len) &&
(rt_memcmp(&info->bssid[0], &scan_result.info[i].bssid[0], RT_WLAN_BSSID_MAX_LENGTH) == 0))
{
return RT_EOK;
}
#ifdef RT_WLAN_SCAN_SORT
if (insert >= 0)
{
continue;
}
/* Signal intensity comparison */
if ((info->rssi < 0) && (scan_result.info[i].rssi < 0))
{
if (info->rssi > scan_result.info[i].rssi)
{
insert = i;
continue;
}
else if (info->rssi < scan_result.info[i].rssi)
{
continue;
}
}
/* Channel comparison */
if (info->channel < scan_result.info[i].channel)
{
insert = i;
continue;
}
else if (info->channel > scan_result.info[i].channel)
{
continue;
}
/* data rate comparison */
if ((info->datarate > scan_result.info[i].datarate))
{
insert = i;
continue;
}
else if (info->datarate < scan_result.info[i].datarate)
{
continue;
}
#endif
}
/* Insert the end */
if (insert == -1)
insert = scan_result.num;
if (scan_result.num >= RT_WLAN_SCAN_CACHE_NUM)
return RT_EOK;
/* malloc memory */
ptable = rt_malloc(sizeof(struct rt_wlan_info) * (scan_result.num + 1));
if (ptable == RT_NULL)
{
LOG_E("wlan info malloc failed!");
return -RT_ENOMEM;
}
scan_result.num ++;
/* copy info */
for (i = 0; i < scan_result.num; i++)
{
if (i < insert)
{
ptable[i] = scan_result.info[i];
}
else if (i > insert)
{
ptable[i] = scan_result.info[i - 1];
}
else if (i == insert)
{
ptable[i] = *info;
}
}
rt_free(scan_result.info);
scan_result.info = ptable;
return err;
}
static void wifi_scan_result_clean(void)
{
/* If there is data */
if (scan_result.num)
{
scan_result.num = 0;
rt_free(scan_result.info);
scan_result.info = RT_NULL;
}
}
static void print_ap_info(struct rt_wlan_info *info,int index)
{
char *security;
if(index == 0)
{
rt_kprintf(" SSID MAC security rssi chn Mbps\n");
rt_kprintf("------------------------------- ----------------- -------------- ---- --- ----\n");
}
{
rt_kprintf("%-32.32s", &(info->ssid.val[0]));
rt_kprintf("%02x:%02x:%02x:%02x:%02x:%02x ",
info->bssid[0],
info->bssid[1],
info->bssid[2],
info->bssid[3],
info->bssid[4],
info->bssid[5]
);
switch (info->security)
{
case SECURITY_OPEN:
security = "OPEN";
break;
case SECURITY_WEP_PSK:
security = "WEP_PSK";
break;
case SECURITY_WEP_SHARED:
security = "WEP_SHARED";
break;
case SECURITY_WPA_TKIP_PSK:
security = "WPA_TKIP_PSK";
break;
case SECURITY_WPA_AES_PSK:
security = "WPA_AES_PSK";
break;
case SECURITY_WPA2_AES_PSK:
security = "WPA2_AES_PSK";
break;
case SECURITY_WPA2_TKIP_PSK:
security = "WPA2_TKIP_PSK";
break;
case SECURITY_WPA2_MIXED_PSK:
security = "WPA2_MIXED_PSK";
break;
case SECURITY_WPS_OPEN:
security = "WPS_OPEN";
break;
case SECURITY_WPS_SECURE:
security = "WPS_SECURE";
break;
default:
security = "UNKNOWN";
break;
}
rt_kprintf("%-14.14s ", security);
rt_kprintf("%-4d ", info->rssi);
rt_kprintf("%3d ", info->channel);
rt_kprintf("%4d\n", info->datarate / 1000000);
}
}
static void user_ap_info_callback(int event, struct rt_wlan_buff *buff, void *parameter)
{
struct rt_wlan_info *info = RT_NULL;
int index = 0;
int ret = RT_EOK;
rt_uint32_t last_num = scan_result.num;
RT_ASSERT(event == RT_WLAN_EVT_SCAN_REPORT);
RT_ASSERT(buff != RT_NULL);
RT_ASSERT(parameter != RT_NULL);
info = (struct rt_wlan_info *)buff->data;
index = *((int *)(parameter));
ret = wifi_scan_result_cache(info);
if(ret == RT_EOK)
{
if(scan_filter == RT_NULL ||
(scan_filter != RT_NULL &&
scan_filter->ssid.len == info->ssid.len &&
rt_memcmp(&scan_filter->ssid.val[0], &info->ssid.val[0], scan_filter->ssid.len) == 0))
{
/*Check whether a new ap is added*/
if (last_num < scan_result.num)
{
/*Print the info*/
print_ap_info(info,index);
}
index++;
*((int *)(parameter)) = index;
}
}
}
static int wifi_scan(int argc, char *argv[])
{
struct rt_wlan_info *info = RT_NULL;
struct rt_wlan_info filter;
int ret = 0;
int i = 0;
if (argc > 3)
return -1;
if (argc == 3)
{
INVALID_INFO(&filter);
SSID_SET(&filter, argv[2]);
info = &filter;
}
ret = rt_wlan_register_event_handler(RT_WLAN_EVT_SCAN_REPORT,user_ap_info_callback,&i);
if(ret != RT_EOK)
{
LOG_E("Scan register user callback error:%d!\n",ret);
return 0;
}
if(info)
{
scan_filter = info;
}
/*Todo: what can i do for it return val */
ret = rt_wlan_scan_with_info(info);
if(ret != RT_EOK)
{
LOG_E("Scan with info error:%d!\n",ret);
}
/* clean scan result */
wifi_scan_result_clean();
if(info)
{
scan_filter = RT_NULL;
}
return 0;
}
static int wifi_join(int argc, char *argv[])
{
const char *ssid = RT_NULL;
const char *key = RT_NULL;
struct rt_wlan_cfg_info cfg_info;
rt_memset(&cfg_info, 0, sizeof(cfg_info));
if (argc == 2)
{
#ifdef RT_WLAN_CFG_ENABLE
/* get info to connect */
if (rt_wlan_cfg_read_index(&cfg_info, 0) == 1)
{
ssid = (char *)(&cfg_info.info.ssid.val[0]);
if (cfg_info.key.len)
key = (char *)(&cfg_info.key.val[0]);
}
else
#endif
{
rt_kprintf("not find connect info\n");
}
}
else if (argc == 3)
{
/* ssid */
ssid = argv[2];
}
else if (argc == 4)
{
ssid = argv[2];
/* password */
key = argv[3];
}
else
{
return -1;
}
rt_wlan_connect(ssid, key);
return 0;
}
static int wifi_ap(int argc, char *argv[])
{
const char *ssid = RT_NULL;
const char *key = RT_NULL;
if (argc == 3)
{
ssid = argv[2];
}
else if (argc == 4)
{
ssid = argv[2];
key = argv[3];
}
else
{
return -1;
}
rt_wlan_start_ap(ssid, key);
return 0;
}
static int wifi_list_sta(int argc, char *argv[])
{
struct rt_wlan_info *sta_info;
int num, i;
if (argc > 2)
return -1;
num = rt_wlan_ap_get_sta_num();
sta_info = rt_malloc(sizeof(struct rt_wlan_info) * num);
if (sta_info == RT_NULL)
{
rt_kprintf("num:%d\n", num);
return 0;
}
rt_wlan_ap_get_sta_info(sta_info, num);
rt_kprintf("num:%d\n", num);
for (i = 0; i < num; i++)
{
rt_kprintf("sta mac %02x:%02x:%02x:%02x:%02x:%02x\n",
sta_info[i].bssid[0], sta_info[i].bssid[1], sta_info[i].bssid[2],
sta_info[i].bssid[3], sta_info[i].bssid[4], sta_info[i].bssid[5]);
}
rt_free(sta_info);
return 0;
}
static int wifi_disconnect(int argc, char *argv[])
{
if (argc != 2)
{
return -1;
}
rt_wlan_disconnect();
return 0;
}
static int wifi_ap_stop(int argc, char *argv[])
{
if (argc != 2)
{
return -1;
}
rt_wlan_ap_stop();
return 0;
}
#ifdef RT_WLAN_CMD_DEBUG
/* just for debug */
static int wifi_debug_help(int argc, char *argv[])
{
rt_kprintf("save_cfg ssid [password]\n");
rt_kprintf("dump_cfg\n");
rt_kprintf("clear_cfg\n");
rt_kprintf("dump_prot\n");
rt_kprintf("mode sta/ap dev_name\n");
rt_kprintf("prot lwip dev_name\n");
rt_kprintf("auto enable/disable\n");
return 0;
}
static int wifi_debug_save_cfg(int argc, char *argv[])
{
struct rt_wlan_cfg_info cfg_info;
int len;
char *ssid = RT_NULL, *password = RT_NULL;
rt_memset(&cfg_info, 0, sizeof(cfg_info));
INVALID_INFO(&cfg_info.info);
if (argc == 2)
{
ssid = argv[1];
}
else if (argc == 3)
{
ssid = argv[1];
password = argv[2];
}
else
{
return -1;
}
if (ssid != RT_NULL)
{
len = rt_strlen(ssid);
if (len > RT_WLAN_SSID_MAX_LENGTH)
{
rt_kprintf("ssid is to long");
return 0;
}
rt_memcpy(&cfg_info.info.ssid.val[0], ssid, len);
cfg_info.info.ssid.len = len;
}
if (password != RT_NULL)
{
len = rt_strlen(password);
if (len > RT_WLAN_PASSWORD_MAX_LENGTH)
{
rt_kprintf("password is to long");
return 0;
}
rt_memcpy(&cfg_info.key.val[0], password, len);
cfg_info.key.len = len;
}
#ifdef RT_WLAN_CFG_ENABLE
rt_wlan_cfg_save(&cfg_info);
#endif
return 0;
}
static int wifi_debug_dump_cfg(int argc, char *argv[])
{
if (argc == 1)
{
#ifdef RT_WLAN_CFG_ENABLE
rt_wlan_cfg_dump();
#endif
}
else
{
return -1;
}
return 0;
}
static int wifi_debug_clear_cfg(int argc, char *argv[])
{
if (argc == 1)
{
#ifdef RT_WLAN_CFG_ENABLE
rt_wlan_cfg_delete_all();
rt_wlan_cfg_cache_save();
#endif
}
else
{
return -1;
}
return 0;
}
static int wifi_debug_dump_prot(int argc, char *argv[])
{
if (argc == 1)
{
rt_wlan_prot_dump();
}
else
{
return -1;
}
return 0;
}
static int wifi_debug_set_mode(int argc, char *argv[])
{
rt_wlan_mode_t mode;
if (argc != 3)
return -1;
if (rt_strcmp("sta", argv[1]) == 0)
{
mode = RT_WLAN_STATION;
}
else if (rt_strcmp("ap", argv[1]) == 0)
{
mode = RT_WLAN_AP;
}
else if (rt_strcmp("none", argv[1]) == 0)
{
mode = RT_WLAN_NONE;
}
else
return -1;
rt_wlan_set_mode(argv[2], mode);
return 0;
}
static int wifi_debug_set_prot(int argc, char *argv[])
{
if (argc != 3)
{
return -1;
}
rt_wlan_prot_attach(argv[2], argv[1]);
return 0;
}
static int wifi_debug_set_autoconnect(int argc, char *argv[])
{
if (argc == 2)
{
if (rt_strcmp(argv[1], "enable") == 0)
rt_wlan_config_autoreconnect(RT_TRUE);
else if (rt_strcmp(argv[1], "disable") == 0)
rt_wlan_config_autoreconnect(RT_FALSE);
}
else
{
return -1;
}
return 0;
}
static int wifi_debug(int argc, char *argv[])
{
int i, result = 0;
const struct wifi_cmd_des *run_cmd = RT_NULL;
if (argc < 3)
{
wifi_debug_help(0, RT_NULL);
return 0;
}
for (i = 0; i < sizeof(debug_tab) / sizeof(debug_tab[0]); i++)
{
if (rt_strcmp(debug_tab[i].cmd, argv[2]) == 0)
{
run_cmd = &debug_tab[i];
break;
}
}
if (run_cmd == RT_NULL)
{
wifi_debug_help(0, RT_NULL);
return 0;
}
if (run_cmd->fun != RT_NULL)
{
result = run_cmd->fun(argc - 2, &argv[2]);
}
if (result)
{
wifi_debug_help(argc - 2, &argv[2]);
}
return 0;
}
#endif
static int wifi_msh(int argc, char *argv[])
{
int i, result = 0;
const struct wifi_cmd_des *run_cmd = RT_NULL;
if (argc == 1)
{
wifi_help(argc, argv);
return 0;
}
/* find fun */
for (i = 0; i < sizeof(cmd_tab) / sizeof(cmd_tab[0]); i++)
{
if (rt_strcmp(cmd_tab[i].cmd, argv[1]) == 0)
{
run_cmd = &cmd_tab[i];
break;
}
}
/* not find fun, print help */
if (run_cmd == RT_NULL)
{
wifi_help(argc, argv);
return 0;
}
/* run fun */
if (run_cmd->fun != RT_NULL)
{
result = run_cmd->fun(argc, argv);
}
if (result)
{
wifi_help(argc, argv);
}
return 0;
}
#if defined(RT_USING_FINSH)
MSH_CMD_EXPORT_ALIAS(wifi_msh, wifi, wifi command);
#endif
#endif

View File

@@ -0,0 +1,974 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-08-03 tyx the first version
*/
#include <rthw.h>
#include <rtthread.h>
#include <wlan_dev.h>
#include <wlan_prot.h>
#define DBG_TAG "WLAN.dev"
#ifdef RT_WLAN_DEV_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif /* RT_WLAN_DEV_DEBUG */
#include <rtdbg.h>
#if defined(RT_USING_WIFI) || defined(RT_USING_WLAN)
#ifndef RT_DEVICE
#define RT_DEVICE(__device) ((rt_device_t)__device)
#endif
#define WLAN_DEV_LOCK(_wlan) (rt_mutex_take(&(_wlan)->lock, RT_WAITING_FOREVER))
#define WLAN_DEV_UNLOCK(_wlan) (rt_mutex_release(&(_wlan)->lock))
#if RT_WLAN_SSID_MAX_LENGTH < 1
#error "SSID length is too short"
#endif
#if RT_WLAN_BSSID_MAX_LENGTH < 1
#error "BSSID length is too short"
#endif
#if RT_WLAN_PASSWORD_MAX_LENGTH < 1
#error "password length is too short"
#endif
#if RT_WLAN_DEV_EVENT_NUM < 2
#error "dev num Too little"
#endif
rt_err_t rt_wlan_dev_init(struct rt_wlan_device *device, rt_wlan_mode_t mode)
{
rt_err_t result = RT_EOK;
/* init wlan device */
LOG_D("F:%s L:%d is run device:0x%08x mode:%d", __FUNCTION__, __LINE__, device, mode);
if ((device == RT_NULL) || (mode >= RT_WLAN_MODE_MAX))
{
LOG_E("F:%s L:%d Parameter Wrongful device:0x%08x mode:%d", __FUNCTION__, __LINE__, device, mode);
return -RT_ERROR;
}
if (mode == RT_WLAN_AP && device->flags & RT_WLAN_FLAG_STA_ONLY)
{
LOG_E("F:%s L:%d This wlan device can only be set to sta mode!", __FUNCTION__, __LINE__);
return -RT_ERROR;
}
else if (mode == RT_WLAN_STATION && device->flags & RT_WLAN_FLAG_AP_ONLY)
{
LOG_E("F:%s L:%d This wlan device can only be set to ap mode!", __FUNCTION__, __LINE__);
return -RT_ERROR;
}
result = rt_device_init(RT_DEVICE(device));
if (result != RT_EOK)
{
LOG_E("L:%d wlan init failed", __LINE__);
return -RT_ERROR;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_MODE, (void *)&mode);
if (result != RT_EOK)
{
LOG_E("L:%d wlan config mode failed", __LINE__);
return -RT_ERROR;
}
device->mode = mode;
return result;
}
rt_err_t rt_wlan_dev_connect(struct rt_wlan_device *device, struct rt_wlan_info *info, const char *password, int password_len)
{
rt_err_t result = RT_EOK;
struct rt_sta_info sta_info;
if (device == RT_NULL)
{
return -RT_EIO;
}
if (info == RT_NULL)
{
return -RT_ERROR;
}
if ((password_len > RT_WLAN_PASSWORD_MAX_LENGTH) ||
(info->ssid.len > RT_WLAN_SSID_MAX_LENGTH))
{
LOG_E("L:%d password or ssid is too long", __LINE__);
return -RT_ERROR;
}
rt_memset(&sta_info, 0, sizeof(struct rt_sta_info));
rt_memcpy(&sta_info.ssid, &info->ssid, sizeof(rt_wlan_ssid_t));
rt_memcpy(sta_info.bssid, info->bssid, RT_WLAN_BSSID_MAX_LENGTH);
if (password != RT_NULL)
{
rt_memcpy(sta_info.key.val, password, password_len);
sta_info.key.len = password_len;
}
sta_info.channel = info->channel;
sta_info.security = info->security;
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_JOIN, &sta_info);
return result;
}
rt_err_t rt_wlan_dev_fast_connect(struct rt_wlan_device *device, struct rt_wlan_info *info, const char *password, int password_len)
{
rt_err_t result = RT_EOK;
struct rt_wlan_buff buff = {0};
if (device == RT_NULL)
{
return -RT_EIO;
}
if (info == RT_NULL)
{
return -RT_ERROR;
}
if ((password_len > RT_WLAN_PASSWORD_MAX_LENGTH) ||
(info->ssid.len > RT_WLAN_SSID_MAX_LENGTH))
{
LOG_E("L:%d password or ssid is too long", __LINE__);
return -RT_ERROR;
}
buff.len = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_FAST_CONNECT_INFO, buff.data);
if(buff.len < 0)
{
LOG_D("L:%d Can't get fast connect info", __LINE__);
return buff.len;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_FAST_CONNECT, &buff);
return result;
}
rt_err_t rt_wlan_dev_disconnect(struct rt_wlan_device *device)
{
rt_err_t result = RT_EOK;
if (device == RT_NULL)
{
return -RT_EIO;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_DISCONNECT, RT_NULL);
return result;
}
rt_err_t rt_wlan_dev_ap_start(struct rt_wlan_device *device, struct rt_wlan_info *info, const char *password, int password_len)
{
rt_err_t result = RT_EOK;
struct rt_ap_info ap_info;
if (device == RT_NULL)
{
return -RT_EIO;
}
if (info == RT_NULL)
{
return -RT_ERROR;
}
if ((password_len > RT_WLAN_PASSWORD_MAX_LENGTH) ||
(info->ssid.len > RT_WLAN_SSID_MAX_LENGTH))
{
LOG_E("L:%d password or ssid is too long", __LINE__);
return -RT_ERROR;
}
rt_memset(&ap_info, 0, sizeof(struct rt_ap_info));
rt_memcpy(&ap_info.ssid, &info->ssid, sizeof(rt_wlan_ssid_t));
if (password != RT_NULL)
{
rt_memcpy(ap_info.key.val, password, password_len);
}
ap_info.key.len = password_len;
ap_info.hidden = info->hidden;
ap_info.channel = info->channel;
ap_info.security = info->security;
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_SOFTAP, &ap_info);
return result;
}
rt_err_t rt_wlan_dev_ap_stop(struct rt_wlan_device *device)
{
rt_err_t result = RT_EOK;
if (device == RT_NULL)
{
return -RT_EIO;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_AP_STOP, RT_NULL);
return result;
}
rt_err_t rt_wlan_dev_ap_deauth(struct rt_wlan_device *device, rt_uint8_t mac[6])
{
rt_err_t result = RT_EOK;
if (device == RT_NULL)
{
return -RT_EIO;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_AP_DEAUTH, mac);
return result;
}
int rt_wlan_dev_get_rssi(struct rt_wlan_device *device)
{
int rssi = 0;
rt_err_t result = RT_EOK;
if (device == RT_NULL)
{
rt_set_errno(-RT_EIO);
return 0;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_RSSI, &rssi);
if (result != RT_EOK)
{
rt_set_errno(result);
return 0;
}
return rssi;
}
rt_err_t rt_wlan_dev_get_mac(struct rt_wlan_device *device, rt_uint8_t mac[6])
{
rt_err_t result = RT_EOK;
if (device == RT_NULL)
{
return -RT_EIO;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_MAC, &mac[0]);
return result;
}
rt_err_t rt_wlan_dev_set_mac(struct rt_wlan_device *device, rt_uint8_t mac[6])
{
rt_err_t result = RT_EOK;
if (device == RT_NULL)
{
return -RT_EIO;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_SET_MAC, &mac[0]);
return result;
}
rt_err_t rt_wlan_dev_set_powersave(struct rt_wlan_device *device, int level)
{
rt_err_t result = RT_EOK;
if (device == RT_NULL)
{
return -RT_EIO;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_SET_POWERSAVE, &level);
return result;
}
int rt_wlan_dev_get_powersave(struct rt_wlan_device *device)
{
int level = -1;
rt_err_t result = RT_EOK;
if (device == RT_NULL)
{
rt_set_errno(-RT_EIO);
return -1;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_POWERSAVE, &level);
if (result != RT_EOK)
{
rt_set_errno(result);
}
return level;
}
rt_err_t rt_wlan_dev_register_event_handler(struct rt_wlan_device *device, rt_wlan_dev_event_t event, rt_wlan_dev_event_handler handler, void *parameter)
{
int i = 0;
rt_base_t level;
if (device == RT_NULL)
{
return -RT_EIO;
}
if (event >= RT_WLAN_DEV_EVT_MAX)
{
return -RT_EINVAL;
}
level = rt_hw_interrupt_disable();
for (i = 0; i < RT_WLAN_DEV_EVENT_NUM; i++)
{
if (device->handler_table[event][i].handler == RT_NULL)
{
device->handler_table[event][i].handler = handler;
device->handler_table[event][i].parameter = parameter;
rt_hw_interrupt_enable(level);
return RT_EOK;
}
}
rt_hw_interrupt_enable(level);
/* No space found */
return -RT_ERROR;
}
rt_err_t rt_wlan_dev_unregister_event_handler(struct rt_wlan_device *device, rt_wlan_dev_event_t event, rt_wlan_dev_event_handler handler)
{
int i = 0;
rt_base_t level;
if (device == RT_NULL)
{
return -RT_EIO;
}
if (event >= RT_WLAN_DEV_EVT_MAX)
{
return -RT_EINVAL;
}
level = rt_hw_interrupt_disable();
for (i = 0; i < RT_WLAN_DEV_EVENT_NUM; i++)
{
if (device->handler_table[event][i].handler == handler)
{
rt_memset(&device->handler_table[event][i], 0, sizeof(struct rt_wlan_dev_event_desc));
rt_hw_interrupt_enable(level);
return RT_EOK;
}
}
rt_hw_interrupt_enable(level);
/* not find iteam */
return -RT_ERROR;
}
void rt_wlan_dev_indicate_event_handle(struct rt_wlan_device *device, rt_wlan_dev_event_t event, struct rt_wlan_buff *buff)
{
void *parameter[RT_WLAN_DEV_EVENT_NUM] = {0};
rt_wlan_dev_event_handler handler[RT_WLAN_DEV_EVENT_NUM] = {0};
int i;
rt_base_t level;
if (device == RT_NULL)
{
return;
}
if (event >= RT_WLAN_DEV_EVT_MAX)
{
return;
}
/* get callback handle */
level = rt_hw_interrupt_disable();
for (i = 0; i < RT_WLAN_DEV_EVENT_NUM; i++)
{
handler[i] = device->handler_table[event][i].handler;
parameter[i] = device->handler_table[event][i].parameter;
}
rt_hw_interrupt_enable(level);
/* run callback */
for (i = 0; i < RT_WLAN_DEV_EVENT_NUM; i++)
{
if (handler[i] != RT_NULL)
{
handler[i](device, event, buff, parameter[i]);
}
}
}
rt_err_t rt_wlan_dev_enter_promisc(struct rt_wlan_device *device)
{
rt_err_t result = RT_EOK;
int enable = 1;
if (device == RT_NULL)
{
return -RT_EIO;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_CFG_PROMISC, &enable);
return result;
}
rt_err_t rt_wlan_dev_exit_promisc(struct rt_wlan_device *device)
{
rt_err_t result = RT_EOK;
int enable = 0;
if (device == RT_NULL)
{
return -RT_EIO;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_CFG_PROMISC, &enable);
return result;
}
rt_err_t rt_wlan_dev_set_promisc_callback(struct rt_wlan_device *device, rt_wlan_pormisc_callback_t callback)
{
if (device == RT_NULL)
{
return -RT_EIO;
}
device->pormisc_callback = callback;
return RT_EOK;
}
void rt_wlan_dev_promisc_handler(struct rt_wlan_device *device, void *data, int len)
{
rt_wlan_pormisc_callback_t callback;
if (device == RT_NULL)
{
return;
}
callback = device->pormisc_callback;
if (callback != RT_NULL)
{
callback(device, data, len);
}
}
rt_err_t rt_wlan_dev_cfg_filter(struct rt_wlan_device *device, struct rt_wlan_filter *filter)
{
rt_err_t result = RT_EOK;
if (device == RT_NULL)
{
return -RT_EIO;
}
if (filter == RT_NULL)
{
return -RT_ERROR;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_CFG_FILTER, filter);
return result;
}
rt_err_t rt_wlan_dev_set_channel(struct rt_wlan_device *device, int channel)
{
rt_err_t result = RT_EOK;
if (device == RT_NULL)
{
return -RT_EIO;
}
if (channel < 0)
{
return -RT_ERROR;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_SET_CHANNEL, &channel);
return result;
}
int rt_wlan_dev_get_channel(struct rt_wlan_device *device)
{
rt_err_t result = RT_EOK;
int channel = -1;
if (device == RT_NULL)
{
rt_set_errno(-RT_EIO);
return -1;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_CHANNEL, &channel);
if (result != RT_EOK)
{
rt_set_errno(result);
return -1;
}
return channel;
}
rt_err_t rt_wlan_dev_set_country(struct rt_wlan_device *device, rt_country_code_t country_code)
{
int result = RT_EOK;
if (device == RT_NULL)
{
return -RT_EIO;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_SET_COUNTRY, &country_code);
return result;
}
rt_country_code_t rt_wlan_dev_get_country(struct rt_wlan_device *device)
{
int result = RT_EOK;
rt_country_code_t country_code = RT_COUNTRY_UNKNOWN;
if (device == RT_NULL)
{
rt_set_errno(-RT_EIO);
return RT_COUNTRY_UNKNOWN;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_COUNTRY, &country_code);
if (result != RT_EOK)
{
rt_set_errno(result);
return RT_COUNTRY_UNKNOWN;
}
return country_code;
}
rt_err_t rt_wlan_dev_scan(struct rt_wlan_device *device, struct rt_wlan_info *info)
{
struct rt_scan_info scan_info = { 0 };
struct rt_scan_info *p_scan_info = RT_NULL;
rt_err_t result = 0;
if (device == RT_NULL)
{
return -RT_EIO;
}
if (info != RT_NULL)
{
if (info->ssid.len > RT_WLAN_SSID_MAX_LENGTH)
{
LOG_E("L:%d ssid is too long", __LINE__);
return -RT_EINVAL;
}
rt_memcpy(&scan_info.ssid, &info->ssid, sizeof(rt_wlan_ssid_t));
rt_memcpy(scan_info.bssid, info->bssid, RT_WLAN_BSSID_MAX_LENGTH);
if (info->channel > 0)
{
scan_info.channel_min = info->channel;
scan_info.channel_max = info->channel;
}
else
{
scan_info.channel_min = -1;
scan_info.channel_max = -1;
}
scan_info.passive = info->hidden ? RT_TRUE : RT_FALSE;
p_scan_info = &scan_info;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_SCAN, p_scan_info);
return result;
}
rt_err_t rt_wlan_dev_scan_stop(struct rt_wlan_device *device)
{
rt_err_t result = 0;
if (device == RT_NULL)
{
return -RT_EIO;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_SCAN_STOP, RT_NULL);
return result;
}
rt_err_t rt_wlan_dev_report_data(struct rt_wlan_device *device, void *buff, int len)
{
#ifdef RT_WLAN_PROT_ENABLE
return rt_wlan_dev_transfer_prot(device, buff, len);
#else
return -RT_ERROR;
#endif
}
rt_err_t rt_wlan_dev_enter_mgnt_filter(struct rt_wlan_device *device)
{
rt_err_t result = RT_EOK;
int enable = 1;
if (device == RT_NULL)
{
return -RT_EIO;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_CFG_MGNT_FILTER, &enable);
return result;
}
rt_err_t rt_wlan_dev_exit_mgnt_filter(struct rt_wlan_device *device)
{
rt_err_t result = RT_EOK;
int enable = 0;
if (device == RT_NULL)
{
return -RT_EIO;
}
result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_CFG_MGNT_FILTER, &enable);
return result;
}
rt_err_t rt_wlan_dev_set_mgnt_filter_callback(struct rt_wlan_device *device, rt_wlan_mgnt_filter_callback_t callback)
{
if (device == RT_NULL)
{
return -RT_EIO;
}
device->mgnt_filter_callback = callback;
return RT_EOK;
}
void rt_wlan_dev_mgnt_filter_handler(struct rt_wlan_device *device, void *data, int len)
{
rt_wlan_mgnt_filter_callback_t callback;
if (device == RT_NULL)
{
return;
}
callback = device->mgnt_filter_callback;
if (callback != RT_NULL)
{
callback(device, data, len);
}
}
int rt_wlan_dev_send_raw_frame(struct rt_wlan_device *device, void *buff, int len)
{
if (device == RT_NULL)
{
return -RT_EIO;
}
if (device->ops->wlan_send_raw_frame)
{
return device->ops->wlan_send_raw_frame(device, buff, len);
}
return -RT_ERROR;
}
static rt_err_t _rt_wlan_dev_init(rt_device_t dev)
{
struct rt_wlan_device *wlan = (struct rt_wlan_device *)dev;
rt_err_t result = RT_EOK;
rt_mutex_init(&wlan->lock, "wlan_dev", RT_IPC_FLAG_PRIO);
if (wlan->ops->wlan_init)
result = wlan->ops->wlan_init(wlan);
if (result == RT_EOK)
{
LOG_I("wlan init success");
}
else
{
LOG_I("wlan init failed");
}
return result;
}
static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args)
{
struct rt_wlan_device *wlan = (struct rt_wlan_device *)dev;
rt_err_t err = RT_EOK;
RT_ASSERT(dev != RT_NULL);
WLAN_DEV_LOCK(wlan);
switch (cmd)
{
case RT_WLAN_CMD_MODE:
{
rt_wlan_mode_t mode = *((rt_wlan_mode_t *)args);
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_MODE, "RT_WLAN_CMD_MODE");
if (wlan->ops->wlan_mode)
err = wlan->ops->wlan_mode(wlan, mode);
break;
}
case RT_WLAN_CMD_SCAN:
{
struct rt_scan_info *scan_info = args;
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SCAN, "RT_WLAN_CMD_SCAN");
if (wlan->ops->wlan_scan)
err = wlan->ops->wlan_scan(wlan, scan_info);
break;
}
case RT_WLAN_CMD_JOIN:
{
struct rt_sta_info *sta_info = args;
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_JOIN, "RT_WLAN_CMD_JOIN");
if (wlan->ops->wlan_join)
err = wlan->ops->wlan_join(wlan, sta_info);
break;
}
case RT_WLAN_CMD_SOFTAP:
{
struct rt_ap_info *ap_info = args;
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SOFTAP, "RT_WLAN_CMD_SOFTAP");
if (wlan->ops->wlan_softap)
err = wlan->ops->wlan_softap(wlan, ap_info);
break;
}
case RT_WLAN_CMD_DISCONNECT:
{
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_DISCONNECT, "RT_WLAN_CMD_DISCONNECT");
if (wlan->ops->wlan_disconnect)
err = wlan->ops->wlan_disconnect(wlan);
break;
}
case RT_WLAN_CMD_AP_STOP:
{
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_AP_STOP, "RT_WLAN_CMD_AP_STOP");
if (wlan->ops->wlan_ap_stop)
err = wlan->ops->wlan_ap_stop(wlan);
break;
}
case RT_WLAN_CMD_AP_DEAUTH:
{
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_AP_DEAUTH, "RT_WLAN_CMD_AP_DEAUTH");
if (wlan->ops->wlan_ap_deauth)
err = wlan->ops->wlan_ap_deauth(wlan, args);
break;
}
case RT_WLAN_CMD_SCAN_STOP:
{
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SCAN_STOP, "RT_WLAN_CMD_SCAN_STOP");
if (wlan->ops->wlan_scan_stop)
err = wlan->ops->wlan_scan_stop(wlan);
break;
}
case RT_WLAN_CMD_GET_RSSI:
{
int *rssi = args;
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_GET_RSSI, "RT_WLAN_CMD_GET_RSSI");
if (wlan->ops->wlan_get_rssi)
*rssi = wlan->ops->wlan_get_rssi(wlan);
break;
}
case RT_WLAN_CMD_SET_POWERSAVE:
{
int level = *((int *)args);
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_POWERSAVE, "RT_WLAN_CMD_SET_POWERSAVE");
if (wlan->ops->wlan_set_powersave)
err = wlan->ops->wlan_set_powersave(wlan, level);
break;
}
case RT_WLAN_CMD_GET_POWERSAVE:
{
int *level = args;
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_GET_POWERSAVE, "RT_WLAN_CMD_GET_POWERSAVE");
if (wlan->ops->wlan_get_powersave)
*level = wlan->ops->wlan_get_powersave(wlan);
break;
}
case RT_WLAN_CMD_CFG_PROMISC:
{
rt_bool_t start = *((rt_bool_t *)args);
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_CFG_PROMISC, "RT_WLAN_CMD_CFG_PROMISC");
if (wlan->ops->wlan_cfg_promisc)
err = wlan->ops->wlan_cfg_promisc(wlan, start);
break;
}
case RT_WLAN_CMD_CFG_FILTER:
{
struct rt_wlan_filter *filter = args;
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_CFG_FILTER, "RT_WLAN_CMD_CFG_FILTER");
if (wlan->ops->wlan_cfg_filter)
err = wlan->ops->wlan_cfg_filter(wlan, filter);
break;
}
case RT_WLAN_CMD_CFG_MGNT_FILTER:
{
rt_bool_t start = *((rt_bool_t *)args);
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_CFG_MGNT_FILTER, "RT_WLAN_CMD_CFG_MGNT_FILTER");
if (wlan->ops->wlan_cfg_mgnt_filter)
err = wlan->ops->wlan_cfg_mgnt_filter(wlan, start);
break;
}
case RT_WLAN_CMD_SET_CHANNEL:
{
int channel = *(int *)args;
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_CHANNEL, "RT_WLAN_CMD_SET_CHANNEL");
if (wlan->ops->wlan_set_channel)
err = wlan->ops->wlan_set_channel(wlan, channel);
break;
}
case RT_WLAN_CMD_GET_CHANNEL:
{
int *channel = args;
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_GET_CHANNEL, "RT_WLAN_CMD_GET_CHANNEL");
if (wlan->ops->wlan_get_channel)
*channel = wlan->ops->wlan_get_channel(wlan);
break;
}
case RT_WLAN_CMD_SET_COUNTRY:
{
rt_country_code_t country = *(rt_country_code_t *)args;
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_COUNTRY, "RT_WLAN_CMD_SET_COUNTRY");
if (wlan->ops->wlan_set_country)
err = wlan->ops->wlan_set_country(wlan, country);
break;
}
case RT_WLAN_CMD_GET_COUNTRY:
{
rt_country_code_t *country = args;
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_GET_COUNTRY, "RT_WLAN_CMD_GET_COUNTRY");
if (wlan->ops->wlan_get_country)
*country = wlan->ops->wlan_get_country(wlan);
break;
}
case RT_WLAN_CMD_SET_MAC:
{
rt_uint8_t *mac = args;
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_MAC, "RT_WLAN_CMD_SET_MAC");
if (wlan->ops->wlan_set_mac)
err = wlan->ops->wlan_set_mac(wlan, mac);
break;
}
case RT_WLAN_CMD_GET_MAC:
{
rt_uint8_t *mac = args;
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_GET_MAC, "RT_WLAN_CMD_GET_MAC");
if (wlan->ops->wlan_get_mac)
err = wlan->ops->wlan_get_mac(wlan, mac);
break;
}
case RT_WLAN_CMD_GET_FAST_CONNECT_INFO:
{
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_GET_FAST_INFO, "RT_WLAN_CMD_GET_FAST_INFO");
if (wlan->ops->wlan_get_fast_info)
{
err = wlan->ops->wlan_get_fast_info(args);
}
else
{
err = -RT_EEMPTY;
}
break;
}
case RT_WLAN_CMD_FAST_CONNECT:
{
struct rt_wlan_buff *buff = (struct rt_wlan_buff *)args;
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_FAST_CONNECT, "RT_WLAN_CMD_FAST_CONNECT");
if (wlan->ops->wlan_get_fast_info)
{
err = wlan->ops->wlan_fast_connect(buff->data,buff->len);
}
else
{
err = -RT_EEMPTY;
}
break;
}
default:
LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, -1, "UNKUOWN");
break;
}
WLAN_DEV_UNLOCK(wlan);
return err;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops wlan_ops =
{
_rt_wlan_dev_init,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
_rt_wlan_dev_control
};
#endif
rt_err_t rt_wlan_dev_register(struct rt_wlan_device *wlan, const char *name, const struct rt_wlan_dev_ops *ops, rt_uint32_t flag, void *user_data)
{
rt_err_t err = RT_EOK;
if ((wlan == RT_NULL) || (name == RT_NULL) || (ops == RT_NULL) ||
(flag & RT_WLAN_FLAG_STA_ONLY && flag & RT_WLAN_FLAG_AP_ONLY))
{
LOG_E("F:%s L:%d parameter Wrongful", __FUNCTION__, __LINE__);
return RT_NULL;
}
rt_memset(wlan, 0, sizeof(struct rt_wlan_device));
#ifdef RT_USING_DEVICE_OPS
wlan->device.ops = &wlan_ops;
#else
wlan->device.init = _rt_wlan_dev_init;
wlan->device.open = RT_NULL;
wlan->device.close = RT_NULL;
wlan->device.read = RT_NULL;
wlan->device.write = RT_NULL;
wlan->device.control = _rt_wlan_dev_control;
#endif
wlan->device.user_data = RT_NULL;
wlan->device.type = RT_Device_Class_NetIf;
wlan->ops = ops;
wlan->user_data = user_data;
wlan->flags = flag;
err = rt_device_register(&wlan->device, name, RT_DEVICE_FLAG_RDWR);
LOG_D("F:%s L:%d run", __FUNCTION__, __LINE__);
return err;
}
#endif

View File

@@ -0,0 +1,604 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-08-03 tyx the first version
*/
#ifndef __WLAN_DEVICE_H__
#define __WLAN_DEVICE_H__
#ifdef __cplusplus
extern "C" {
#endif
typedef enum
{
RT_WLAN_NONE,
RT_WLAN_STATION,
RT_WLAN_AP,
RT_WLAN_MODE_MAX
} rt_wlan_mode_t;
typedef enum
{
RT_WLAN_CMD_MODE = 0x10,
RT_WLAN_CMD_SCAN, /* trigger scanning (list cells) */
RT_WLAN_CMD_JOIN,
RT_WLAN_CMD_SOFTAP, /* start soft-AP */
RT_WLAN_CMD_DISCONNECT,
RT_WLAN_CMD_AP_STOP, /* stop soft-AP */
RT_WLAN_CMD_AP_DEAUTH,
RT_WLAN_CMD_SCAN_STOP,
RT_WLAN_CMD_GET_RSSI, /* get sensitivity (dBm) */
RT_WLAN_CMD_SET_POWERSAVE,
RT_WLAN_CMD_GET_POWERSAVE,
RT_WLAN_CMD_CFG_PROMISC, /* start/stop minitor */
RT_WLAN_CMD_CFG_FILTER, /* start/stop frame filter */
RT_WLAN_CMD_CFG_MGNT_FILTER, /* start/stop management frame filter */
RT_WLAN_CMD_SET_CHANNEL,
RT_WLAN_CMD_GET_CHANNEL,
RT_WLAN_CMD_SET_COUNTRY,
RT_WLAN_CMD_GET_COUNTRY,
RT_WLAN_CMD_SET_MAC,
RT_WLAN_CMD_GET_MAC,
RT_WLAN_CMD_GET_FAST_CONNECT_INFO,
RT_WLAN_CMD_FAST_CONNECT,
} rt_wlan_cmd_t;
typedef enum
{
RT_WLAN_DEV_EVT_INIT_DONE = 0,
RT_WLAN_DEV_EVT_CONNECT,
RT_WLAN_DEV_EVT_CONNECT_FAIL,
RT_WLAN_DEV_EVT_DISCONNECT,
RT_WLAN_DEV_EVT_AP_START,
RT_WLAN_DEV_EVT_AP_STOP,
RT_WLAN_DEV_EVT_AP_ASSOCIATED,
RT_WLAN_DEV_EVT_AP_DISASSOCIATED,
RT_WLAN_DEV_EVT_AP_ASSOCIATE_FAILED,
RT_WLAN_DEV_EVT_SCAN_REPORT,
RT_WLAN_DEV_EVT_SCAN_DONE,
RT_WLAN_DEV_EVT_MAX,
} rt_wlan_dev_event_t;
#define SHARED_ENABLED 0x00008000
#define WPA_SECURITY 0x00200000
#define WPA2_SECURITY 0x00400000
#define WPS_ENABLED 0x10000000
#define WEP_ENABLED 0x0001
#define TKIP_ENABLED 0x0002
#define AES_ENABLED 0x0004
#define WSEC_SWFLAG 0x0008
#define RT_WLAN_FLAG_STA_ONLY (0x1 << 0)
#define RT_WLAN_FLAG_AP_ONLY (0x1 << 1)
#ifndef RT_WLAN_SSID_MAX_LENGTH
#define RT_WLAN_SSID_MAX_LENGTH (32) /* SSID MAX LEN */
#endif
#ifndef RT_WLAN_BSSID_MAX_LENGTH
#define RT_WLAN_BSSID_MAX_LENGTH (6) /* BSSID MAX LEN (default is 6) */
#endif
#ifndef RT_WLAN_PASSWORD_MAX_LENGTH
#define RT_WLAN_PASSWORD_MAX_LENGTH (32) /* PASSWORD MAX LEN*/
#endif
#ifndef RT_WLAN_DEV_EVENT_NUM
#define RT_WLAN_DEV_EVENT_NUM (2) /* EVENT GROUP MAX NUM */
#endif
/**
* Enumeration of Wi-Fi security modes
*/
typedef enum
{
SECURITY_OPEN = 0, /* Open security */
SECURITY_WEP_PSK = WEP_ENABLED, /* WEP Security with open authentication */
SECURITY_WEP_SHARED = (WEP_ENABLED | SHARED_ENABLED), /* WEP Security with shared authentication */
SECURITY_WPA_TKIP_PSK = (WPA_SECURITY | TKIP_ENABLED), /* WPA Security with TKIP */
SECURITY_WPA_AES_PSK = (WPA_SECURITY | AES_ENABLED), /* WPA Security with AES */
SECURITY_WPA2_AES_PSK = (WPA2_SECURITY | AES_ENABLED), /* WPA2 Security with AES */
SECURITY_WPA2_TKIP_PSK = (WPA2_SECURITY | TKIP_ENABLED), /* WPA2 Security with TKIP */
SECURITY_WPA2_MIXED_PSK = (WPA2_SECURITY | AES_ENABLED | TKIP_ENABLED), /* WPA2 Security with AES & TKIP */
SECURITY_WPS_OPEN = WPS_ENABLED, /* WPS with open security */
SECURITY_WPS_SECURE = (WPS_ENABLED | AES_ENABLED), /* WPS with AES security */
SECURITY_UNKNOWN = -1, /* May be returned by scan function if security is unknown.
Do not pass this to the join function! */
} rt_wlan_security_t;
typedef enum
{
RT_802_11_BAND_5GHZ = 0, /* Denotes 5GHz radio band */
RT_802_11_BAND_2_4GHZ = 1, /* Denotes 2.4GHz radio band */
RT_802_11_BAND_UNKNOWN = 0x7fffffff, /* unknown */
} rt_802_11_band_t;
typedef enum
{
RT_COUNTRY_AFGHANISTAN,
RT_COUNTRY_ALBANIA,
RT_COUNTRY_ALGERIA,
RT_COUNTRY_AMERICAN_SAMOA,
RT_COUNTRY_ANGOLA,
RT_COUNTRY_ANGUILLA,
RT_COUNTRY_ANTIGUA_AND_BARBUDA,
RT_COUNTRY_ARGENTINA,
RT_COUNTRY_ARMENIA,
RT_COUNTRY_ARUBA,
RT_COUNTRY_AUSTRALIA,
RT_COUNTRY_AUSTRIA,
RT_COUNTRY_AZERBAIJAN,
RT_COUNTRY_BAHAMAS,
RT_COUNTRY_BAHRAIN,
RT_COUNTRY_BAKER_ISLAND,
RT_COUNTRY_BANGLADESH,
RT_COUNTRY_BARBADOS,
RT_COUNTRY_BELARUS,
RT_COUNTRY_BELGIUM,
RT_COUNTRY_BELIZE,
RT_COUNTRY_BENIN,
RT_COUNTRY_BERMUDA,
RT_COUNTRY_BHUTAN,
RT_COUNTRY_BOLIVIA,
RT_COUNTRY_BOSNIA_AND_HERZEGOVINA,
RT_COUNTRY_BOTSWANA,
RT_COUNTRY_BRAZIL,
RT_COUNTRY_BRITISH_INDIAN_OCEAN_TERRITORY,
RT_COUNTRY_BRUNEI_DARUSSALAM,
RT_COUNTRY_BULGARIA,
RT_COUNTRY_BURKINA_FASO,
RT_COUNTRY_BURUNDI,
RT_COUNTRY_CAMBODIA,
RT_COUNTRY_CAMEROON,
RT_COUNTRY_CANADA,
RT_COUNTRY_CAPE_VERDE,
RT_COUNTRY_CAYMAN_ISLANDS,
RT_COUNTRY_CENTRAL_AFRICAN_REPUBLIC,
RT_COUNTRY_CHAD,
RT_COUNTRY_CHILE,
RT_COUNTRY_CHINA,
RT_COUNTRY_CHRISTMAS_ISLAND,
RT_COUNTRY_COLOMBIA,
RT_COUNTRY_COMOROS,
RT_COUNTRY_CONGO,
RT_COUNTRY_CONGO_THE_DEMOCRATIC_REPUBLIC_OF_THE,
RT_COUNTRY_COSTA_RICA,
RT_COUNTRY_COTE_DIVOIRE,
RT_COUNTRY_CROATIA,
RT_COUNTRY_CUBA,
RT_COUNTRY_CYPRUS,
RT_COUNTRY_CZECH_REPUBLIC,
RT_COUNTRY_DENMARK,
RT_COUNTRY_DJIBOUTI,
RT_COUNTRY_DOMINICA,
RT_COUNTRY_DOMINICAN_REPUBLIC,
RT_COUNTRY_DOWN_UNDER,
RT_COUNTRY_ECUADOR,
RT_COUNTRY_EGYPT,
RT_COUNTRY_EL_SALVADOR,
RT_COUNTRY_EQUATORIAL_GUINEA,
RT_COUNTRY_ERITREA,
RT_COUNTRY_ESTONIA,
RT_COUNTRY_ETHIOPIA,
RT_COUNTRY_FALKLAND_ISLANDS_MALVINAS,
RT_COUNTRY_FAROE_ISLANDS,
RT_COUNTRY_FIJI,
RT_COUNTRY_FINLAND,
RT_COUNTRY_FRANCE,
RT_COUNTRY_FRENCH_GUINA,
RT_COUNTRY_FRENCH_POLYNESIA,
RT_COUNTRY_FRENCH_SOUTHERN_TERRITORIES,
RT_COUNTRY_GABON,
RT_COUNTRY_GAMBIA,
RT_COUNTRY_GEORGIA,
RT_COUNTRY_GERMANY,
RT_COUNTRY_GHANA,
RT_COUNTRY_GIBRALTAR,
RT_COUNTRY_GREECE,
RT_COUNTRY_GRENADA,
RT_COUNTRY_GUADELOUPE,
RT_COUNTRY_GUAM,
RT_COUNTRY_GUATEMALA,
RT_COUNTRY_GUERNSEY,
RT_COUNTRY_GUINEA,
RT_COUNTRY_GUINEA_BISSAU,
RT_COUNTRY_GUYANA,
RT_COUNTRY_HAITI,
RT_COUNTRY_HOLY_SEE_VATICAN_CITY_STATE,
RT_COUNTRY_HONDURAS,
RT_COUNTRY_HONG_KONG,
RT_COUNTRY_HUNGARY,
RT_COUNTRY_ICELAND,
RT_COUNTRY_INDIA,
RT_COUNTRY_INDONESIA,
RT_COUNTRY_IRAN_ISLAMIC_REPUBLIC_OF,
RT_COUNTRY_IRAQ,
RT_COUNTRY_IRELAND,
RT_COUNTRY_ISRAEL,
RT_COUNTRY_ITALY,
RT_COUNTRY_JAMAICA,
RT_COUNTRY_JAPAN,
RT_COUNTRY_JERSEY,
RT_COUNTRY_JORDAN,
RT_COUNTRY_KAZAKHSTAN,
RT_COUNTRY_KENYA,
RT_COUNTRY_KIRIBATI,
RT_COUNTRY_KOREA_REPUBLIC_OF,
RT_COUNTRY_KOSOVO,
RT_COUNTRY_KUWAIT,
RT_COUNTRY_KYRGYZSTAN,
RT_COUNTRY_LAO_PEOPLES_DEMOCRATIC_REPUBIC,
RT_COUNTRY_LATVIA,
RT_COUNTRY_LEBANON,
RT_COUNTRY_LESOTHO,
RT_COUNTRY_LIBERIA,
RT_COUNTRY_LIBYAN_ARAB_JAMAHIRIYA,
RT_COUNTRY_LIECHTENSTEIN,
RT_COUNTRY_LITHUANIA,
RT_COUNTRY_LUXEMBOURG,
RT_COUNTRY_MACAO,
RT_COUNTRY_MACEDONIA_FORMER_YUGOSLAV_REPUBLIC_OF,
RT_COUNTRY_MADAGASCAR,
RT_COUNTRY_MALAWI,
RT_COUNTRY_MALAYSIA,
RT_COUNTRY_MALDIVES,
RT_COUNTRY_MALI,
RT_COUNTRY_MALTA,
RT_COUNTRY_MAN_ISLE_OF,
RT_COUNTRY_MARTINIQUE,
RT_COUNTRY_MAURITANIA,
RT_COUNTRY_MAURITIUS,
RT_COUNTRY_MAYOTTE,
RT_COUNTRY_MEXICO,
RT_COUNTRY_MICRONESIA_FEDERATED_STATES_OF,
RT_COUNTRY_MOLDOVA_REPUBLIC_OF,
RT_COUNTRY_MONACO,
RT_COUNTRY_MONGOLIA,
RT_COUNTRY_MONTENEGRO,
RT_COUNTRY_MONTSERRAT,
RT_COUNTRY_MOROCCO,
RT_COUNTRY_MOZAMBIQUE,
RT_COUNTRY_MYANMAR,
RT_COUNTRY_NAMIBIA,
RT_COUNTRY_NAURU,
RT_COUNTRY_NEPAL,
RT_COUNTRY_NETHERLANDS,
RT_COUNTRY_NETHERLANDS_ANTILLES,
RT_COUNTRY_NEW_CALEDONIA,
RT_COUNTRY_NEW_ZEALAND,
RT_COUNTRY_NICARAGUA,
RT_COUNTRY_NIGER,
RT_COUNTRY_NIGERIA,
RT_COUNTRY_NORFOLK_ISLAND,
RT_COUNTRY_NORTHERN_MARIANA_ISLANDS,
RT_COUNTRY_NORWAY,
RT_COUNTRY_OMAN,
RT_COUNTRY_PAKISTAN,
RT_COUNTRY_PALAU,
RT_COUNTRY_PANAMA,
RT_COUNTRY_PAPUA_NEW_GUINEA,
RT_COUNTRY_PARAGUAY,
RT_COUNTRY_PERU,
RT_COUNTRY_PHILIPPINES,
RT_COUNTRY_POLAND,
RT_COUNTRY_PORTUGAL,
RT_COUNTRY_PUETO_RICO,
RT_COUNTRY_QATAR,
RT_COUNTRY_REUNION,
RT_COUNTRY_ROMANIA,
RT_COUNTRY_RUSSIAN_FEDERATION,
RT_COUNTRY_RWANDA,
RT_COUNTRY_SAINT_KITTS_AND_NEVIS,
RT_COUNTRY_SAINT_LUCIA,
RT_COUNTRY_SAINT_PIERRE_AND_MIQUELON,
RT_COUNTRY_SAINT_VINCENT_AND_THE_GRENADINES,
RT_COUNTRY_SAMOA,
RT_COUNTRY_SANIT_MARTIN_SINT_MARTEEN,
RT_COUNTRY_SAO_TOME_AND_PRINCIPE,
RT_COUNTRY_SAUDI_ARABIA,
RT_COUNTRY_SENEGAL,
RT_COUNTRY_SERBIA,
RT_COUNTRY_SEYCHELLES,
RT_COUNTRY_SIERRA_LEONE,
RT_COUNTRY_SINGAPORE,
RT_COUNTRY_SLOVAKIA,
RT_COUNTRY_SLOVENIA,
RT_COUNTRY_SOLOMON_ISLANDS,
RT_COUNTRY_SOMALIA,
RT_COUNTRY_SOUTH_AFRICA,
RT_COUNTRY_SPAIN,
RT_COUNTRY_SRI_LANKA,
RT_COUNTRY_SURINAME,
RT_COUNTRY_SWAZILAND,
RT_COUNTRY_SWEDEN,
RT_COUNTRY_SWITZERLAND,
RT_COUNTRY_SYRIAN_ARAB_REPUBLIC,
RT_COUNTRY_TAIWAN_PROVINCE_OF_CHINA,
RT_COUNTRY_TAJIKISTAN,
RT_COUNTRY_TANZANIA_UNITED_REPUBLIC_OF,
RT_COUNTRY_THAILAND,
RT_COUNTRY_TOGO,
RT_COUNTRY_TONGA,
RT_COUNTRY_TRINIDAD_AND_TOBAGO,
RT_COUNTRY_TUNISIA,
RT_COUNTRY_TURKEY,
RT_COUNTRY_TURKMENISTAN,
RT_COUNTRY_TURKS_AND_CAICOS_ISLANDS,
RT_COUNTRY_TUVALU,
RT_COUNTRY_UGANDA,
RT_COUNTRY_UKRAINE,
RT_COUNTRY_UNITED_ARAB_EMIRATES,
RT_COUNTRY_UNITED_KINGDOM,
RT_COUNTRY_UNITED_STATES,
RT_COUNTRY_UNITED_STATES_REV4,
RT_COUNTRY_UNITED_STATES_NO_DFS,
RT_COUNTRY_UNITED_STATES_MINOR_OUTLYING_ISLANDS,
RT_COUNTRY_URUGUAY,
RT_COUNTRY_UZBEKISTAN,
RT_COUNTRY_VANUATU,
RT_COUNTRY_VENEZUELA,
RT_COUNTRY_VIET_NAM,
RT_COUNTRY_VIRGIN_ISLANDS_BRITISH,
RT_COUNTRY_VIRGIN_ISLANDS_US,
RT_COUNTRY_WALLIS_AND_FUTUNA,
RT_COUNTRY_WEST_BANK,
RT_COUNTRY_WESTERN_SAHARA,
RT_COUNTRY_WORLD_WIDE_XX,
RT_COUNTRY_YEMEN,
RT_COUNTRY_ZAMBIA,
RT_COUNTRY_ZIMBABWE,
RT_COUNTRY_UNKNOWN
} rt_country_code_t;
struct rt_wlan_device;
struct rt_wlan_buff;
typedef void (*rt_wlan_dev_event_handler)(struct rt_wlan_device *device, rt_wlan_dev_event_t event, struct rt_wlan_buff *buff, void *parameter);
typedef void (*rt_wlan_pormisc_callback_t)(struct rt_wlan_device *device, void *data, int len);
typedef void (*rt_wlan_mgnt_filter_callback_t)(struct rt_wlan_device *device, void *data, int len);
struct rt_wlan_ssid
{
rt_uint8_t len;
rt_uint8_t val[RT_WLAN_SSID_MAX_LENGTH + 1];
};
typedef struct rt_wlan_ssid rt_wlan_ssid_t;
struct rt_wlan_key
{
rt_uint8_t len;
rt_uint8_t val[RT_WLAN_PASSWORD_MAX_LENGTH + 1];
};
typedef struct rt_wlan_key rt_wlan_key_t;
#define INVALID_INFO(_info) do { \
rt_memset((_info), 0, sizeof(struct rt_wlan_info)); \
(_info)->band = RT_802_11_BAND_UNKNOWN; \
(_info)->security = SECURITY_UNKNOWN; \
(_info)->channel = -1; \
} while(0)
#define SSID_SET(_info, _ssid) do { \
rt_strncpy((char *)(_info)->ssid.val, (_ssid), RT_WLAN_SSID_MAX_LENGTH); \
(_info)->ssid.len = rt_strlen((char *)(_info)->ssid.val); \
} while(0)
struct rt_wlan_info
{
/* security type */
rt_wlan_security_t security;
/* 2.4G/5G */
rt_802_11_band_t band;
/* maximal data rate */
rt_uint32_t datarate;
/* radio channel */
rt_int16_t channel;
/* signal strength */
rt_int16_t rssi;
/* ssid */
rt_wlan_ssid_t ssid;
/* hwaddr */
rt_uint8_t bssid[RT_WLAN_BSSID_MAX_LENGTH];
rt_uint8_t hidden;
};
struct rt_wlan_buff
{
void *data;
rt_int32_t len;
};
struct rt_filter_pattern
{
rt_uint16_t offset; /* Offset in bytes to start filtering (referenced to the start of the ethernet packet) */
rt_uint16_t mask_size; /* Size of the mask in bytes */
rt_uint8_t *mask; /* Pattern mask bytes to be ANDed with the pattern eg. "\xff00" (must be in network byte order) */
rt_uint8_t *pattern; /* Pattern bytes used to filter eg. "\x0800" (must be in network byte order) */
};
typedef enum
{
RT_POSITIVE_MATCHING = 0, /* Receive the data matching with this pattern and discard the other data */
RT_NEGATIVE_MATCHING = 1 /* Discard the data matching with this pattern and receive the other data */
} rt_filter_rule_t;
struct rt_wlan_filter
{
struct rt_filter_pattern patt;
rt_filter_rule_t rule;
rt_uint8_t enable;
};
struct rt_wlan_dev_event_desc
{
rt_wlan_dev_event_handler handler;
void *parameter;
};
struct rt_wlan_device
{
struct rt_device device;
rt_wlan_mode_t mode;
struct rt_mutex lock;
struct rt_wlan_dev_event_desc handler_table[RT_WLAN_DEV_EVT_MAX][RT_WLAN_DEV_EVENT_NUM];
rt_wlan_pormisc_callback_t pormisc_callback;
rt_wlan_mgnt_filter_callback_t mgnt_filter_callback;
const struct rt_wlan_dev_ops *ops;
rt_uint32_t flags;
struct netdev *netdev;
void *prot;
void *user_data;
};
struct rt_sta_info
{
rt_wlan_ssid_t ssid;
rt_wlan_key_t key;
rt_uint8_t bssid[6];
rt_uint16_t channel;
rt_wlan_security_t security;
};
struct rt_ap_info
{
rt_wlan_ssid_t ssid;
rt_wlan_key_t key;
rt_bool_t hidden;
rt_uint16_t channel;
rt_wlan_security_t security;
};
struct rt_scan_info
{
rt_wlan_ssid_t ssid;
rt_uint8_t bssid[6];
rt_int16_t channel_min;
rt_int16_t channel_max;
rt_bool_t passive;
};
struct rt_wlan_dev_ops
{
rt_err_t (*wlan_init)(struct rt_wlan_device *wlan);
rt_err_t (*wlan_mode)(struct rt_wlan_device *wlan, rt_wlan_mode_t mode);
rt_err_t (*wlan_scan)(struct rt_wlan_device *wlan, struct rt_scan_info *scan_info);
rt_err_t (*wlan_join)(struct rt_wlan_device *wlan, struct rt_sta_info *sta_info);
rt_err_t (*wlan_softap)(struct rt_wlan_device *wlan, struct rt_ap_info *ap_info);
rt_err_t (*wlan_disconnect)(struct rt_wlan_device *wlan);
rt_err_t (*wlan_ap_stop)(struct rt_wlan_device *wlan);
rt_err_t (*wlan_ap_deauth)(struct rt_wlan_device *wlan, rt_uint8_t mac[]);
rt_err_t (*wlan_scan_stop)(struct rt_wlan_device *wlan);
int (*wlan_get_rssi)(struct rt_wlan_device *wlan);
rt_err_t (*wlan_set_powersave)(struct rt_wlan_device *wlan, int level);
int (*wlan_get_powersave)(struct rt_wlan_device *wlan);
rt_err_t (*wlan_cfg_promisc)(struct rt_wlan_device *wlan, rt_bool_t start);
rt_err_t (*wlan_cfg_filter)(struct rt_wlan_device *wlan, struct rt_wlan_filter *filter);
rt_err_t (*wlan_cfg_mgnt_filter)(struct rt_wlan_device *wlan, rt_bool_t start);
rt_err_t (*wlan_set_channel)(struct rt_wlan_device *wlan, int channel);
int (*wlan_get_channel)(struct rt_wlan_device *wlan);
rt_err_t (*wlan_set_country)(struct rt_wlan_device *wlan, rt_country_code_t country_code);
rt_country_code_t (*wlan_get_country)(struct rt_wlan_device *wlan);
rt_err_t (*wlan_set_mac)(struct rt_wlan_device *wlan, rt_uint8_t mac[]);
rt_err_t (*wlan_get_mac)(struct rt_wlan_device *wlan, rt_uint8_t mac[]);
int (*wlan_recv)(struct rt_wlan_device *wlan, void *buff, int len);
int (*wlan_send)(struct rt_wlan_device *wlan, void *buff, int len);
int (*wlan_send_raw_frame)(struct rt_wlan_device *wlan, void *buff, int len);
int (*wlan_get_fast_info)(void *data);
rt_err_t (*wlan_fast_connect)(void *data,rt_int32_t len);
};
/*
* wlan device init
*/
rt_err_t rt_wlan_dev_init(struct rt_wlan_device *device, rt_wlan_mode_t mode);
/*
* wlan device station interface
*/
rt_err_t rt_wlan_dev_connect(struct rt_wlan_device *device, struct rt_wlan_info *info, const char *password, int password_len);
rt_err_t rt_wlan_dev_fast_connect(struct rt_wlan_device *device, struct rt_wlan_info *info, const char *password, int password_len);
rt_err_t rt_wlan_dev_disconnect(struct rt_wlan_device *device);
int rt_wlan_dev_get_rssi(struct rt_wlan_device *device);
/*
* wlan device ap interface
*/
rt_err_t rt_wlan_dev_ap_start(struct rt_wlan_device *device, struct rt_wlan_info *info, const char *password, int password_len);
rt_err_t rt_wlan_dev_ap_stop(struct rt_wlan_device *device);
rt_err_t rt_wlan_dev_ap_deauth(struct rt_wlan_device *device, rt_uint8_t mac[6]);
/*
* wlan device scan interface
*/
rt_err_t rt_wlan_dev_scan(struct rt_wlan_device *device, struct rt_wlan_info *info);
rt_err_t rt_wlan_dev_scan_stop(struct rt_wlan_device *device);
/*
* wlan device mac interface
*/
rt_err_t rt_wlan_dev_get_mac(struct rt_wlan_device *device, rt_uint8_t mac[6]);
rt_err_t rt_wlan_dev_set_mac(struct rt_wlan_device *device, rt_uint8_t mac[6]);
/*
* wlan device powersave interface
*/
rt_err_t rt_wlan_dev_set_powersave(struct rt_wlan_device *device, int level);
int rt_wlan_dev_get_powersave(struct rt_wlan_device *device);
/*
* wlan device event interface
*/
rt_err_t rt_wlan_dev_register_event_handler(struct rt_wlan_device *device, rt_wlan_dev_event_t event, rt_wlan_dev_event_handler handler, void *parameter);
rt_err_t rt_wlan_dev_unregister_event_handler(struct rt_wlan_device *device, rt_wlan_dev_event_t event, rt_wlan_dev_event_handler handler);
void rt_wlan_dev_indicate_event_handle(struct rt_wlan_device *device, rt_wlan_dev_event_t event, struct rt_wlan_buff *buff);
/*
* wlan device promisc interface
*/
rt_err_t rt_wlan_dev_enter_promisc(struct rt_wlan_device *device);
rt_err_t rt_wlan_dev_exit_promisc(struct rt_wlan_device *device);
rt_err_t rt_wlan_dev_set_promisc_callback(struct rt_wlan_device *device, rt_wlan_pormisc_callback_t callback);
void rt_wlan_dev_promisc_handler(struct rt_wlan_device *device, void *data, int len);
/*
* wlan device filter interface
*/
rt_err_t rt_wlan_dev_cfg_filter(struct rt_wlan_device *device, struct rt_wlan_filter *filter);
/*
* wlan device channel interface
*/
rt_err_t rt_wlan_dev_set_channel(struct rt_wlan_device *device, int channel);
int rt_wlan_dev_get_channel(struct rt_wlan_device *device);
/*
* wlan device country interface
*/
rt_err_t rt_wlan_dev_set_country(struct rt_wlan_device *device, rt_country_code_t country_code);
rt_country_code_t rt_wlan_dev_get_country(struct rt_wlan_device *device);
/*
* wlan device datat transfer interface
*/
rt_err_t rt_wlan_dev_report_data(struct rt_wlan_device *device, void *buff, int len);
// void rt_wlan_dev_data_ready(struct rt_wlan_device *device, int len);
/*
* wlan device register interface
*/
rt_err_t rt_wlan_dev_register(struct rt_wlan_device *wlan, const char *name,
const struct rt_wlan_dev_ops *ops, rt_uint32_t flag, void *user_data);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,558 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-08-14 tyx the first version
*/
#include <rthw.h>
#include <rtthread.h>
#include <wlan_dev.h>
#include <wlan_prot.h>
#include <wlan_workqueue.h>
#if defined(RT_WLAN_PROT_ENABLE) && defined(RT_WLAN_PROT_LWIP_ENABLE)
#ifdef RT_USING_LWIP
#include <netif/ethernetif.h>
#include <lwip/netifapi.h>
#ifdef LWIP_USING_DHCPD
#include <dhcp_server.h>
#endif
#ifdef RT_USING_NETDEV
#include <netdev.h>
#endif
#define DBG_TAG "WLAN.lwip"
#ifdef RT_WLAN_LWIP_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif /* RT_WLAN_LWIP_DEBUG */
#include <rtdbg.h>
#ifndef IPADDR_STRLEN_MAX
#define IPADDR_STRLEN_MAX (32)
#endif
#ifndef RT_WLAN_PROT_LWIP_NAME
#define RT_WLAN_PROT_LWIP_NAME ("lwip")
#endif
struct lwip_prot_des
{
struct rt_wlan_prot prot;
struct eth_device eth;
rt_int8_t connected_flag;
struct rt_timer timer;
struct rt_work work;
};
static void netif_is_ready(struct rt_work *work, void *parameter)
{
ip_addr_t ip_addr_zero = { 0 };
struct rt_wlan_device *wlan = parameter;
struct lwip_prot_des *lwip_prot = (struct lwip_prot_des *)wlan->prot;
struct eth_device *eth_dev;
rt_base_t level;
struct rt_wlan_buff buff;
rt_uint32_t ip_addr[4];
char str[IPADDR_STRLEN_MAX];
if (lwip_prot == RT_NULL)
return;
eth_dev = &lwip_prot->eth;
rt_timer_stop(&lwip_prot->timer);
if (ip_addr_cmp(&(eth_dev->netif->ip_addr), &ip_addr_zero) != 0)
{
rt_timer_start(&lwip_prot->timer);
goto exit;
}
rt_memset(&ip_addr, 0, sizeof(ip_addr));
#if LWIP_IPV4 && LWIP_IPV6
if (eth_dev->netif->ip_addr.type == IPADDR_TYPE_V4)
{
ip_addr[0] = ip4_addr_get_u32(&eth_dev->netif->ip_addr.u_addr.ip4);
buff.data = &ip_addr[0];
buff.len = sizeof(ip_addr[0]);
}
else if (eth_dev->netif->ip_addr.type == IPADDR_TYPE_V6)
{
*(ip6_addr_t *)(&ip_addr[0]) = eth_dev->netif->ip_addr.u_addr.ip6;
buff.data = ip_addr;
buff.len = sizeof(ip_addr);
}
else
{
LOG_W("F:%s L:%d ip addr type not support", __FUNCTION__, __LINE__);
}
#else
#if LWIP_IPV4
ip_addr[0] = ip4_addr_get_u32(&eth_dev->netif->ip_addr);
buff.data = &ip_addr[0];
buff.len = sizeof(ip_addr[0]);
#else
*(ip_addr_t *)(&ip_addr[0]) = eth_dev->netif->ip_addr;
buff.data = ip_addr;
buff.len = sizeof(ip_addr);
#endif
#endif
if (rt_wlan_prot_ready(wlan, &buff) != 0)
{
rt_timer_start(&lwip_prot->timer);
goto exit;
}
rt_memset(str, 0, IPADDR_STRLEN_MAX);
rt_enter_critical();
rt_memcpy(str, ipaddr_ntoa(&(eth_dev->netif->ip_addr)), IPADDR_STRLEN_MAX);
rt_exit_critical();
LOG_I("Got IP address : %s", str);
exit:
level = rt_hw_interrupt_disable();
if (work)
{
rt_memset(work, 0, sizeof(struct rt_work));
}
rt_hw_interrupt_enable(level);
}
static void timer_callback(void *parameter)
{
#ifdef RT_WLAN_WORK_THREAD_ENABLE
struct rt_workqueue *workqueue;
struct rt_wlan_device *wlan = parameter;
struct lwip_prot_des *lwip_prot = (struct lwip_prot_des *)wlan->prot;
struct rt_work *work;
rt_base_t level;
if (lwip_prot == RT_NULL)
return;
work = &lwip_prot->work;
workqueue = rt_wlan_get_workqueue();
if (workqueue != RT_NULL)
{
level = rt_hw_interrupt_disable();
rt_work_init(work, netif_is_ready, parameter);
rt_hw_interrupt_enable(level);
if (rt_workqueue_dowork(workqueue, work) != RT_EOK)
{
level = rt_hw_interrupt_disable();
rt_memset(work, 0, sizeof(struct rt_work));
rt_hw_interrupt_enable(level);
}
}
#else
netif_is_ready(RT_NULL, parameter);
#endif
}
static void netif_set_connected(void *parameter)
{
struct rt_wlan_device *wlan = parameter;
struct lwip_prot_des *lwip_prot = wlan->prot;
struct eth_device *eth_dev;
if (lwip_prot == RT_NULL)
return;
eth_dev = &lwip_prot->eth;
if (lwip_prot->connected_flag)
{
if (wlan->mode == RT_WLAN_STATION)
{
LOG_D("F:%s L:%d dhcp start run", __FUNCTION__, __LINE__);
netifapi_netif_common(eth_dev->netif, netif_set_link_up, NULL);
#ifdef RT_LWIP_DHCP
netifapi_dhcp_start(eth_dev->netif);
#endif
rt_timer_start(&lwip_prot->timer);
}
else if (wlan->mode == RT_WLAN_AP)
{
LOG_D("F:%s L:%d dhcpd start run", __FUNCTION__, __LINE__);
netifapi_netif_common(eth_dev->netif, netif_set_link_up, NULL);
#ifdef LWIP_USING_DHCPD
{
char netif_name[RT_NAME_MAX];
rt_memset(netif_name, 0, sizeof(netif_name));
rt_memcpy(netif_name, eth_dev->netif->name, sizeof(eth_dev->netif->name));
dhcpd_start(netif_name);
}
#endif
}
}
else
{
LOG_D("F:%s L:%d set linkdown", __FUNCTION__, __LINE__);
netifapi_netif_common(eth_dev->netif, netif_set_link_down, NULL);
rt_timer_stop(&lwip_prot->timer);
#ifdef RT_LWIP_DHCP
{
ip_addr_t ip_addr = { 0 };
netifapi_dhcp_stop(eth_dev->netif);
netif_set_addr(eth_dev->netif, &ip_addr, &ip_addr, &ip_addr);
}
#endif
#ifdef LWIP_USING_DHCPD
{
char netif_name[RT_NAME_MAX];
rt_memset(netif_name, 0, sizeof(netif_name));
rt_memcpy(netif_name, lwip_prot->eth.netif->name, sizeof(lwip_prot->eth.netif->name));
dhcpd_stop(netif_name);
}
#endif
}
}
static void rt_wlan_lwip_event_handle(struct rt_wlan_prot *port, struct rt_wlan_device *wlan, int event)
{
struct lwip_prot_des *lwip_prot = (struct lwip_prot_des *)wlan->prot;
rt_bool_t flag_old;
if (lwip_prot == RT_NULL)
return;
flag_old = lwip_prot->connected_flag;
switch (event)
{
case RT_WLAN_PROT_EVT_CONNECT:
{
LOG_D("event: CONNECT");
lwip_prot->connected_flag = RT_TRUE;
break;
}
case RT_WLAN_PROT_EVT_DISCONNECT:
{
LOG_D("event: DISCONNECT");
lwip_prot->connected_flag = RT_FALSE;
break;
}
case RT_WLAN_PROT_EVT_AP_START:
{
LOG_D("event: AP_START");
lwip_prot->connected_flag = RT_TRUE;
break;
}
case RT_WLAN_PROT_EVT_AP_STOP:
{
LOG_D("event: AP_STOP");
lwip_prot->connected_flag = RT_FALSE;
break;
}
case RT_WLAN_PROT_EVT_AP_ASSOCIATED:
{
LOG_D("event: ASSOCIATED");
break;
}
case RT_WLAN_PROT_EVT_AP_DISASSOCIATED:
{
LOG_D("event: DISASSOCIATED");
break;
}
default :
{
LOG_D("event: UNKNOWN");
break;
}
}
if (flag_old != lwip_prot->connected_flag)
{
#ifdef RT_WLAN_WORK_THREAD_ENABLE
rt_wlan_workqueue_dowork(netif_set_connected, wlan);
#else
netif_set_connected(wlan);
#endif
}
}
static rt_err_t rt_wlan_lwip_protocol_control(rt_device_t device, int cmd, void *args)
{
struct eth_device *eth_dev = (struct eth_device *)device;
struct rt_wlan_device *wlan;
rt_err_t err = RT_EOK;
RT_ASSERT(eth_dev != RT_NULL);
LOG_D("F:%s L:%d device:0x%08x user_data:0x%08x", __FUNCTION__, __LINE__, eth_dev, eth_dev->parent.user_data);
switch (cmd)
{
case NIOCTL_GADDR:
/* get MAC address */
wlan = eth_dev->parent.user_data;
err = rt_device_control((rt_device_t)wlan, RT_WLAN_CMD_GET_MAC, args);
break;
default :
break;
}
return err;
}
static rt_err_t rt_wlan_lwip_protocol_recv(struct rt_wlan_device *wlan, void *buff, int len)
{
struct eth_device *eth_dev = &((struct lwip_prot_des *)wlan->prot)->eth;
struct pbuf *p = RT_NULL;
LOG_D("F:%s L:%d run", __FUNCTION__, __LINE__);
if (eth_dev == RT_NULL)
{
return -RT_ERROR;
}
#ifdef RT_WLAN_PROT_LWIP_PBUF_FORCE
{
p = buff;
if ((eth_dev->netif->input(p, eth_dev->netif)) != ERR_OK)
{
return -RT_ERROR;
}
return RT_EOK;
}
#else
{
int count = 0;
while (p == RT_NULL)
{
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
if (p != RT_NULL)
break;
p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM);
if (p != RT_NULL)
break;
LOG_D("F:%s L:%d wait for pbuf_alloc!", __FUNCTION__, __LINE__);
rt_thread_delay(1);
count++;
//wait for 10ms or give up!!
if (count >= 10)
{
LOG_W("F:%s L:%d pbuf allocate fail!!!", __FUNCTION__, __LINE__);
return -RT_ENOMEM;
}
}
/*copy data dat -> pbuf*/
pbuf_take(p, buff, len);
if ((eth_dev->netif->input(p, eth_dev->netif)) != ERR_OK)
{
LOG_D("F:%s L:%d IP input error", __FUNCTION__, __LINE__);
pbuf_free(p);
p = RT_NULL;
}
LOG_D("F:%s L:%d netif iput success! len:%d", __FUNCTION__, __LINE__, len);
return RT_EOK;
}
#endif
}
static rt_err_t rt_wlan_lwip_protocol_send(rt_device_t device, struct pbuf *p)
{
struct rt_wlan_device *wlan = ((struct eth_device *)device)->parent.user_data;
LOG_D("F:%s L:%d run", __FUNCTION__, __LINE__);
if (wlan == RT_NULL)
{
return RT_EOK;
}
#ifdef RT_WLAN_PROT_LWIP_PBUF_FORCE
{
rt_wlan_prot_transfer_dev(wlan, p, p->tot_len);
return RT_EOK;
}
#else
{
rt_uint8_t *frame;
/* sending data directly */
if (p->len == p->tot_len)
{
frame = (rt_uint8_t *)p->payload;
rt_wlan_prot_transfer_dev(wlan, frame, p->tot_len);
LOG_D("F:%s L:%d run len:%d", __FUNCTION__, __LINE__, p->tot_len);
return RT_EOK;
}
frame = rt_malloc(p->tot_len);
if (frame == RT_NULL)
{
LOG_E("F:%s L:%d malloc out_buf fail\n", __FUNCTION__, __LINE__);
return -RT_ENOMEM;
}
/*copy pbuf -> data dat*/
pbuf_copy_partial(p, frame, p->tot_len, 0);
/* send data */
rt_wlan_prot_transfer_dev(wlan, frame, p->tot_len);
LOG_D("F:%s L:%d run len:%d", __FUNCTION__, __LINE__, p->tot_len);
rt_free(frame);
return RT_EOK;
}
#endif
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops wlan_lwip_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
rt_wlan_lwip_protocol_control
};
#endif
static struct rt_wlan_prot *rt_wlan_lwip_protocol_register(struct rt_wlan_prot *prot, struct rt_wlan_device *wlan)
{
struct eth_device *eth = RT_NULL;
rt_uint8_t id = 0;
char eth_name[4], timer_name[16];
rt_device_t device = RT_NULL;
struct lwip_prot_des *lwip_prot;
if (wlan == RT_NULL || prot == RT_NULL)
return RT_NULL;;
LOG_D("F:%s L:%d is run wlan:0x%08x", __FUNCTION__, __LINE__, wlan);
do
{
/* find ETH device name */
eth_name[0] = 'w';
eth_name[1] = '0' + id++;
eth_name[2] = '\0';
device = rt_device_find(eth_name);
}
while (device);
if (id > 9)
{
LOG_E("F:%s L:%d not find Empty name", __FUNCTION__, __LINE__, eth_name);
return RT_NULL;
}
if (rt_device_open((rt_device_t)wlan, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
{
LOG_E("F:%s L:%d open wlan failed", __FUNCTION__, __LINE__);
return RT_NULL;
}
lwip_prot = rt_malloc(sizeof(struct lwip_prot_des));
if (lwip_prot == RT_NULL)
{
LOG_E("F:%s L:%d malloc mem failed", __FUNCTION__, __LINE__);
rt_device_close((rt_device_t)wlan);
return RT_NULL;
}
rt_memset(lwip_prot, 0, sizeof(struct lwip_prot_des));
eth = &lwip_prot->eth;
#ifdef RT_USING_DEVICE_OPS
eth->parent.ops = &wlan_lwip_ops;
#else
eth->parent.init = RT_NULL;
eth->parent.open = RT_NULL;
eth->parent.close = RT_NULL;
eth->parent.read = RT_NULL;
eth->parent.write = RT_NULL;
eth->parent.control = rt_wlan_lwip_protocol_control;
#endif
eth->parent.user_data = wlan;
eth->eth_rx = RT_NULL;
eth->eth_tx = rt_wlan_lwip_protocol_send;
/* register ETH device */
if (eth_device_init(eth, eth_name) != RT_EOK)
{
LOG_E("eth device init failed");
rt_device_close((rt_device_t)wlan);
rt_free(lwip_prot);
return RT_NULL;
}
rt_memcpy(&lwip_prot->prot, prot, sizeof(struct rt_wlan_prot));
rt_sprintf(timer_name, "timer_%s", eth_name);
rt_timer_init(&lwip_prot->timer, timer_name, timer_callback, wlan, rt_tick_from_millisecond(1000),
RT_TIMER_FLAG_SOFT_TIMER | RT_TIMER_FLAG_ONE_SHOT);
netif_set_up(eth->netif);
LOG_I("eth device init ok name:%s", eth_name);
#ifdef RT_USING_NETDEV
wlan->netdev = netdev_get_by_name(eth_name);
#endif
return &lwip_prot->prot;
}
static void rt_wlan_lwip_protocol_unregister(struct rt_wlan_prot *prot, struct rt_wlan_device *wlan)
{
struct lwip_prot_des *lwip_prot = (struct lwip_prot_des *)prot;
LOG_D("F:%s L:%d is run wlan:0x%08x", __FUNCTION__, __LINE__, wlan);
#if !defined(RT_USING_LWIP141)
wlan->prot = RT_NULL;
if (lwip_prot == RT_NULL)
{
return;
}
#ifdef LWIP_USING_DHCPD
{
char netif_name[RT_NAME_MAX];
rt_memset(netif_name, 0, sizeof(netif_name));
rt_memcpy(netif_name, lwip_prot->eth.netif->name, sizeof(lwip_prot->eth.netif->name));
dhcpd_stop(netif_name);
}
#endif
eth_device_deinit(&lwip_prot->eth);
rt_device_close((rt_device_t)wlan);
rt_timer_detach(&lwip_prot->timer);
wlan->netdev = RT_NULL;
rt_free(lwip_prot);
#endif
}
static struct rt_wlan_prot_ops ops =
{
rt_wlan_lwip_protocol_recv,
rt_wlan_lwip_protocol_register,
rt_wlan_lwip_protocol_unregister
};
int rt_wlan_lwip_init(void)
{
static struct rt_wlan_prot prot;
rt_wlan_prot_event_t event;
rt_memset(&prot, 0, sizeof(prot));
rt_strncpy(&prot.name[0], RT_WLAN_PROT_LWIP_NAME, RT_WLAN_PROT_NAME_LEN);
prot.ops = &ops;
if (rt_wlan_prot_regisetr(&prot) != RT_EOK)
{
LOG_E("F:%s L:%d protocol regisetr failed", __FUNCTION__, __LINE__);
return -1;
}
for (event = RT_WLAN_PROT_EVT_INIT_DONE; event < RT_WLAN_PROT_EVT_MAX; event++)
{
rt_wlan_prot_event_register(&prot, event, rt_wlan_lwip_event_handle);
}
return 0;
}
INIT_PREV_EXPORT(rt_wlan_lwip_init);
#endif
#endif

Some files were not shown because too many files have changed in this diff Show More