sdio+fatfs创建
This commit is contained in:
commit
f762d5d7f8
2473 files changed
+1192014
No files matched your search
@@ -0,0 +1,865 @@
|
||||
menu "Device Drivers"
|
||||
|
||||
config RT_USING_DEVICE_IPC
|
||||
bool "Using device drivers IPC"
|
||||
default y
|
||||
|
||||
if RT_USING_DEVICE_IPC
|
||||
config RT_USING_SYSTEM_WORKQUEUE
|
||||
bool "Using system default workqueue"
|
||||
default n
|
||||
|
||||
if RT_USING_SYSTEM_WORKQUEUE
|
||||
config RT_SYSTEM_WORKQUEUE_STACKSIZE
|
||||
int "The stack size for system workqueue thread"
|
||||
default 2048
|
||||
|
||||
config RT_SYSTEM_WORKQUEUE_PRIORITY
|
||||
int "The priority level of system workqueue thread"
|
||||
default 23
|
||||
endif
|
||||
endif
|
||||
|
||||
menuconfig RT_USING_SERIAL
|
||||
bool "USING Serial device drivers"
|
||||
select RT_USING_DEVICE_IPC
|
||||
select RT_USING_DEVICE
|
||||
default y
|
||||
|
||||
if RT_USING_SERIAL
|
||||
choice
|
||||
prompt "Choice Serial version"
|
||||
default RT_USING_SERIAL_V1
|
||||
config RT_USING_SERIAL_V1
|
||||
bool "RT_USING_SERIAL_V1"
|
||||
config RT_USING_SERIAL_V2
|
||||
bool "RT_USING_SERIAL_V2"
|
||||
endchoice
|
||||
config RT_SERIAL_USING_DMA
|
||||
bool "Enable serial DMA mode"
|
||||
default y
|
||||
|
||||
config RT_SERIAL_RB_BUFSZ
|
||||
int "Set RX buffer size"
|
||||
depends on !RT_USING_SERIAL_V2
|
||||
default 64
|
||||
endif
|
||||
|
||||
config RT_USING_CAN
|
||||
bool "Using CAN device drivers"
|
||||
default n
|
||||
|
||||
if RT_USING_CAN
|
||||
config RT_CAN_USING_HDR
|
||||
bool "Enable CAN hardware filter"
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_USING_HWTIMER
|
||||
bool "Using hardware timer device drivers"
|
||||
default n
|
||||
|
||||
config RT_USING_CPUTIME
|
||||
bool "Enable CPU time for high resolution clock counter"
|
||||
default n
|
||||
help
|
||||
When enable this option, the BSP should provide a rt_clock_cputime_ops
|
||||
for CPU time by:
|
||||
const static struct rt_clock_cputime_ops _ops = {...};
|
||||
clock_cpu_setops(&_ops);
|
||||
|
||||
Then user can use high resolution clock counter with:
|
||||
|
||||
ts1 = clock_cpu_gettime();
|
||||
ts2 = clock_cpu_gettime();
|
||||
|
||||
/* and get the ms of delta tick with API: */
|
||||
ms_tick = clock_cpu_millisecond(t2 - t1);
|
||||
us_tick = clock_cpu_microsecond(t2 - t1);
|
||||
|
||||
if RT_USING_CPUTIME
|
||||
config RT_USING_CPUTIME_CORTEXM
|
||||
bool "Use DWT for CPU time"
|
||||
default y
|
||||
depends on ARCH_ARM_CORTEX_M3 || ARCH_ARM_CORTEX_M4 || ARCH_ARM_CORTEX_M7
|
||||
help
|
||||
Some Cortex-M3/4/7 MCU has Data Watchpoint and Trace Register, use
|
||||
the cycle counter in DWT for CPU time.
|
||||
endif
|
||||
|
||||
config RT_USING_I2C
|
||||
bool "Using I2C device drivers"
|
||||
default n
|
||||
|
||||
if RT_USING_I2C
|
||||
config RT_I2C_DEBUG
|
||||
bool "Use I2C debug message"
|
||||
default n
|
||||
|
||||
config RT_USING_I2C_BITOPS
|
||||
bool "Use GPIO to simulate I2C"
|
||||
default y
|
||||
|
||||
if RT_USING_I2C_BITOPS
|
||||
config RT_I2C_BITOPS_DEBUG
|
||||
bool "Use simulate I2C debug message"
|
||||
default n
|
||||
endif
|
||||
endif
|
||||
|
||||
config RT_USING_PHY
|
||||
bool "Using ethernet phy device drivers"
|
||||
default n
|
||||
|
||||
config RT_USING_PIN
|
||||
bool "Using generic GPIO device drivers"
|
||||
default y
|
||||
|
||||
config RT_USING_ADC
|
||||
bool "Using ADC device drivers"
|
||||
default n
|
||||
|
||||
config RT_USING_DAC
|
||||
bool "Using DAC device drivers"
|
||||
default n
|
||||
|
||||
config RT_USING_PWM
|
||||
bool "Using PWM device drivers"
|
||||
default n
|
||||
|
||||
config RT_USING_MTD_NOR
|
||||
bool "Using MTD Nor Flash device drivers"
|
||||
default n
|
||||
|
||||
config RT_USING_MTD_NAND
|
||||
bool "Using MTD Nand Flash device drivers"
|
||||
default n
|
||||
|
||||
if RT_USING_MTD_NAND
|
||||
config RT_MTD_NAND_DEBUG
|
||||
bool "Enable MTD Nand operations debug information"
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_USING_PM
|
||||
bool "Using Power Management device drivers"
|
||||
default n
|
||||
|
||||
if RT_USING_PM
|
||||
config PM_TICKLESS_THRESHOLD_TIME
|
||||
int "PM tickless threashold time"
|
||||
default 2
|
||||
|
||||
config PM_USING_CUSTOM_CONFIG
|
||||
bool "PM using custom pm config"
|
||||
default n
|
||||
|
||||
config PM_ENABLE_DEBUG
|
||||
bool "PM Enable Debug"
|
||||
default n
|
||||
|
||||
config PM_ENABLE_SUSPEND_SLEEP_MODE
|
||||
bool "PM Device suspend change sleep mode"
|
||||
default n
|
||||
|
||||
config PM_ENABLE_THRESHOLD_SLEEP_MODE
|
||||
bool "PM using threshold time change sleep mode"
|
||||
default n
|
||||
|
||||
if PM_ENABLE_THRESHOLD_SLEEP_MODE
|
||||
config PM_LIGHT_THRESHOLD_TIME
|
||||
int "PM light mode threashold time"
|
||||
default 5
|
||||
|
||||
config PM_DEEP_THRESHOLD_TIME
|
||||
int "PM deep mode threashold time"
|
||||
default 20
|
||||
|
||||
config PM_STANDBY_THRESHOLD_TIME
|
||||
int "PM standby mode threashold time"
|
||||
default 100
|
||||
endif
|
||||
endif
|
||||
|
||||
config RT_USING_RTC
|
||||
bool "Using RTC device drivers"
|
||||
default n
|
||||
|
||||
if RT_USING_RTC
|
||||
config RT_USING_ALARM
|
||||
bool "Using RTC alarm"
|
||||
default n
|
||||
|
||||
config RT_USING_SOFT_RTC
|
||||
bool "Using software simulation RTC device"
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_USING_SDIO
|
||||
bool "Using SD/MMC device drivers"
|
||||
default n
|
||||
|
||||
if RT_USING_SDIO
|
||||
config RT_SDIO_STACK_SIZE
|
||||
int "The stack size for sdio irq thread"
|
||||
default 512
|
||||
|
||||
config RT_SDIO_THREAD_PRIORITY
|
||||
int "The priority level value of sdio irq thread"
|
||||
default 15
|
||||
|
||||
config RT_MMCSD_STACK_SIZE
|
||||
int "The stack size for mmcsd thread"
|
||||
default 1024
|
||||
|
||||
config RT_MMCSD_THREAD_PREORITY
|
||||
int "The priority level value of mmcsd thread"
|
||||
default 22
|
||||
|
||||
config RT_MMCSD_MAX_PARTITION
|
||||
int "mmcsd max partition"
|
||||
default 16
|
||||
config RT_SDIO_DEBUG
|
||||
bool "Enable SDIO debug log output"
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_USING_SPI
|
||||
bool "Using SPI Bus/Device device drivers"
|
||||
default n
|
||||
|
||||
if RT_USING_SPI
|
||||
config RT_USING_SPI_BITOPS
|
||||
select RT_USING_PIN
|
||||
bool "Use GPIO to simulate SPI"
|
||||
default n
|
||||
|
||||
if RT_USING_SPI_BITOPS
|
||||
config RT_SPI_BITOPS_DEBUG
|
||||
bool "Use simulate SPI debug message"
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_USING_QSPI
|
||||
bool "Enable QSPI mode"
|
||||
default n
|
||||
|
||||
config RT_USING_SPI_MSD
|
||||
bool "Using SD/TF card driver with spi"
|
||||
select RT_USING_DFS
|
||||
default n
|
||||
|
||||
config RT_USING_SFUD
|
||||
bool "Using Serial Flash Universal Driver"
|
||||
default n
|
||||
help
|
||||
An using JEDEC's SFDP standard serial (SPI) flash universal driver library
|
||||
|
||||
if RT_USING_SFUD
|
||||
config RT_SFUD_USING_SFDP
|
||||
bool "Using auto probe flash JEDEC SFDP parameter"
|
||||
default y
|
||||
|
||||
config RT_SFUD_USING_FLASH_INFO_TABLE
|
||||
bool "Using defined supported flash chip information table"
|
||||
default y
|
||||
|
||||
config RT_SFUD_USING_QSPI
|
||||
bool "Using QSPI mode support"
|
||||
select RT_USING_QSPI
|
||||
default n
|
||||
|
||||
config RT_SFUD_SPI_MAX_HZ
|
||||
int "Default spi maximum speed(HZ)"
|
||||
range 0 50000000
|
||||
default 50000000
|
||||
help
|
||||
Read the JEDEC SFDP command must run at 50 MHz or less,and you also can use rt_spi_configure(); to config spi speed.
|
||||
|
||||
config RT_DEBUG_SFUD
|
||||
bool "Show more SFUD debug information"
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_USING_ENC28J60
|
||||
bool "Using ENC28J60 SPI Ethernet network interface"
|
||||
select RT_USING_LWIP
|
||||
default n
|
||||
|
||||
config RT_USING_SPI_WIFI
|
||||
bool "Using RW009/007 SPI Wi-Fi wireless interface"
|
||||
select RT_USING_LWIP
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_USING_WDT
|
||||
bool "Using Watch Dog device drivers"
|
||||
default n
|
||||
|
||||
config RT_USING_AUDIO
|
||||
bool "Using Audio device drivers"
|
||||
default n
|
||||
|
||||
if RT_USING_AUDIO
|
||||
config RT_AUDIO_REPLAY_MP_BLOCK_SIZE
|
||||
int "Replay memory pool block size"
|
||||
default 4096
|
||||
|
||||
config RT_AUDIO_REPLAY_MP_BLOCK_COUNT
|
||||
int "Replay memory pool block count"
|
||||
default 2
|
||||
|
||||
config RT_AUDIO_RECORD_PIPE_SIZE
|
||||
int "Record pipe size"
|
||||
default 2048
|
||||
endif
|
||||
|
||||
config RT_USING_SENSOR
|
||||
bool "Using Sensor device drivers"
|
||||
select RT_USING_PIN
|
||||
default n
|
||||
|
||||
if RT_USING_SENSOR
|
||||
config RT_USING_SENSOR_CMD
|
||||
bool "Using Sensor cmd"
|
||||
default y
|
||||
endif
|
||||
|
||||
config RT_USING_TOUCH
|
||||
bool "Using Touch device drivers"
|
||||
default n
|
||||
if RT_USING_TOUCH
|
||||
config RT_TOUCH_PIN_IRQ
|
||||
bool "touch irq use pin irq"
|
||||
default n
|
||||
endif
|
||||
|
||||
menuconfig RT_USING_HWCRYPTO
|
||||
bool "Using Hardware Crypto drivers"
|
||||
default n
|
||||
|
||||
if RT_USING_HWCRYPTO
|
||||
config RT_HWCRYPTO_DEFAULT_NAME
|
||||
string "Hardware crypto device name"
|
||||
default "hwcryto"
|
||||
|
||||
config RT_HWCRYPTO_IV_MAX_SIZE
|
||||
int "IV max size"
|
||||
default "16"
|
||||
|
||||
config RT_HWCRYPTO_KEYBIT_MAX_SIZE
|
||||
int "Key max bit length"
|
||||
default 256
|
||||
|
||||
config RT_HWCRYPTO_USING_GCM
|
||||
bool "Using Hardware GCM"
|
||||
default n
|
||||
|
||||
config RT_HWCRYPTO_USING_AES
|
||||
bool "Using Hardware AES"
|
||||
default n
|
||||
|
||||
if RT_HWCRYPTO_USING_AES
|
||||
config RT_HWCRYPTO_USING_AES_ECB
|
||||
bool "Using Hardware AES ECB mode"
|
||||
default y
|
||||
|
||||
config RT_HWCRYPTO_USING_AES_CBC
|
||||
bool "Using Hardware AES CBC mode"
|
||||
default n
|
||||
|
||||
config RT_HWCRYPTO_USING_AES_CFB
|
||||
bool "Using Hardware AES CFB mode"
|
||||
default n
|
||||
|
||||
config RT_HWCRYPTO_USING_AES_CTR
|
||||
bool "Using Hardware AES CTR mode"
|
||||
default n
|
||||
|
||||
config RT_HWCRYPTO_USING_AES_OFB
|
||||
bool "Using Hardware AES OFB mode"
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_HWCRYPTO_USING_DES
|
||||
bool "Using Hardware DES"
|
||||
default n
|
||||
|
||||
if RT_HWCRYPTO_USING_DES
|
||||
config RT_HWCRYPTO_USING_DES_ECB
|
||||
bool "Using Hardware DES ECB mode"
|
||||
default y
|
||||
|
||||
config RT_HWCRYPTO_USING_DES_CBC
|
||||
bool "Using Hardware DES CBC mode"
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_HWCRYPTO_USING_3DES
|
||||
bool "Using Hardware 3DES"
|
||||
default n
|
||||
|
||||
if RT_HWCRYPTO_USING_3DES
|
||||
config RT_HWCRYPTO_USING_3DES_ECB
|
||||
bool "Using Hardware 3DES ECB mode"
|
||||
default y
|
||||
|
||||
config RT_HWCRYPTO_USING_3DES_CBC
|
||||
bool "Using Hardware 3DES CBC mode"
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_HWCRYPTO_USING_RC4
|
||||
bool "Using Hardware RC4"
|
||||
default n
|
||||
|
||||
config RT_HWCRYPTO_USING_MD5
|
||||
bool "Using Hardware MD5"
|
||||
default n
|
||||
|
||||
config RT_HWCRYPTO_USING_SHA1
|
||||
bool "Using Hardware SHA1"
|
||||
default n
|
||||
|
||||
config RT_HWCRYPTO_USING_SHA2
|
||||
bool "Using Hardware SHA2"
|
||||
default n
|
||||
|
||||
if RT_HWCRYPTO_USING_SHA2
|
||||
config RT_HWCRYPTO_USING_SHA2_224
|
||||
bool "Using Hardware SHA2_224 mode"
|
||||
default n
|
||||
|
||||
config RT_HWCRYPTO_USING_SHA2_256
|
||||
bool "Using Hardware SHA2_256 mode"
|
||||
default y
|
||||
|
||||
config RT_HWCRYPTO_USING_SHA2_384
|
||||
bool "Using Hardware SHA2_384 mode"
|
||||
default n
|
||||
|
||||
config RT_HWCRYPTO_USING_SHA2_512
|
||||
bool "Using Hardware SHA2_512 mode"
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_HWCRYPTO_USING_RNG
|
||||
bool "Using Hardware RNG"
|
||||
default n
|
||||
|
||||
config RT_HWCRYPTO_USING_CRC
|
||||
bool "Using Hardware CRC"
|
||||
default n
|
||||
|
||||
if RT_HWCRYPTO_USING_CRC
|
||||
config RT_HWCRYPTO_USING_CRC_07
|
||||
bool "Using Hardware CRC-8 0x07 polynomial"
|
||||
default n
|
||||
|
||||
config RT_HWCRYPTO_USING_CRC_8005
|
||||
bool "Using Hardware CRC-16 0x8005 polynomial"
|
||||
default n
|
||||
|
||||
config RT_HWCRYPTO_USING_CRC_1021
|
||||
bool "Using Hardware CRC-16 0x1021 polynomial"
|
||||
default n
|
||||
|
||||
config RT_HWCRYPTO_USING_CRC_3D65
|
||||
bool "Using Hardware CRC-16 0x3D65 polynomial"
|
||||
default n
|
||||
|
||||
config RT_HWCRYPTO_USING_CRC_04C11DB7
|
||||
bool "Using Hardware CRC-32 0x04C11DB7 polynomial"
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_HWCRYPTO_USING_BIGNUM
|
||||
bool "Using Hardware bignum"
|
||||
default n
|
||||
|
||||
if RT_HWCRYPTO_USING_BIGNUM
|
||||
config RT_HWCRYPTO_USING_BIGNUM_EXPTMOD
|
||||
bool "Using Hardware bignum expt_mod operation"
|
||||
default y
|
||||
|
||||
config RT_HWCRYPTO_USING_BIGNUM_MULMOD
|
||||
bool "Using Hardware bignum mul_mod operation"
|
||||
default y
|
||||
|
||||
config RT_HWCRYPTO_USING_BIGNUM_MUL
|
||||
bool "Using Hardware bignum mul operation"
|
||||
default n
|
||||
|
||||
config RT_HWCRYPTO_USING_BIGNUM_ADD
|
||||
bool "Using Hardware bignum add operation"
|
||||
default n
|
||||
|
||||
config RT_HWCRYPTO_USING_BIGNUM_SUB
|
||||
bool "Using Hardware bignum sub operation"
|
||||
default n
|
||||
endif
|
||||
endif
|
||||
|
||||
config RT_USING_PULSE_ENCODER
|
||||
bool "Using PULSE ENCODER device drivers"
|
||||
default n
|
||||
|
||||
config RT_USING_INPUT_CAPTURE
|
||||
bool "Using INPUT CAPTURE device drivers"
|
||||
default n
|
||||
|
||||
if RT_USING_INPUT_CAPTURE
|
||||
config RT_INPUT_CAPTURE_RB_SIZE
|
||||
int "Set input capture ringbuffer size"
|
||||
default 100
|
||||
endif
|
||||
|
||||
menuconfig RT_USING_WIFI
|
||||
bool "Using Wi-Fi framework"
|
||||
default n
|
||||
|
||||
if RT_USING_WIFI
|
||||
config RT_WLAN_DEVICE_STA_NAME
|
||||
string "The device name for station"
|
||||
default "wlan0"
|
||||
|
||||
config RT_WLAN_DEVICE_AP_NAME
|
||||
string "The device name for ap"
|
||||
default "wlan1"
|
||||
|
||||
config RT_WLAN_SSID_MAX_LENGTH
|
||||
int "SSID maximum length"
|
||||
default 32
|
||||
|
||||
config RT_WLAN_PASSWORD_MAX_LENGTH
|
||||
int "Password maximum length"
|
||||
default 32
|
||||
|
||||
config RT_WLAN_DEV_EVENT_NUM
|
||||
int "Driver events maxcount"
|
||||
default 2
|
||||
|
||||
config RT_WLAN_MANAGE_ENABLE
|
||||
bool "Connection management Enable"
|
||||
default y
|
||||
|
||||
if RT_WLAN_MANAGE_ENABLE
|
||||
config RT_WLAN_SCAN_WAIT_MS
|
||||
int "Set scan timeout time(ms)"
|
||||
default 10000
|
||||
|
||||
config RT_WLAN_CONNECT_WAIT_MS
|
||||
int "Set connect timeout time(ms)"
|
||||
default 10000
|
||||
|
||||
config RT_WLAN_SCAN_SORT
|
||||
bool "Automatic sorting of scan results"
|
||||
default y
|
||||
|
||||
config RT_WLAN_MSH_CMD_ENABLE
|
||||
bool "MSH command Enable"
|
||||
default y
|
||||
|
||||
config RT_WLAN_AUTO_CONNECT_ENABLE
|
||||
bool "Auto connect Enable"
|
||||
select RT_WLAN_CFG_ENABLE
|
||||
select RT_WLAN_WORK_THREAD_ENABLE
|
||||
default y
|
||||
|
||||
if RT_WLAN_AUTO_CONNECT_ENABLE
|
||||
config AUTO_CONNECTION_PERIOD_MS
|
||||
int "Auto connect period(ms)"
|
||||
default 2000
|
||||
endif
|
||||
endif
|
||||
|
||||
config RT_WLAN_CFG_ENABLE
|
||||
bool "WiFi information automatically saved Enable"
|
||||
default y
|
||||
|
||||
if RT_WLAN_CFG_ENABLE
|
||||
config RT_WLAN_CFG_INFO_MAX
|
||||
int "Maximum number of WiFi information automatically saved"
|
||||
default 3
|
||||
endif
|
||||
|
||||
config RT_WLAN_PROT_ENABLE
|
||||
bool "Transport protocol manage Enable"
|
||||
default y
|
||||
|
||||
if RT_WLAN_PROT_ENABLE
|
||||
config RT_WLAN_PROT_NAME_LEN
|
||||
int "Transport protocol name length"
|
||||
default 8
|
||||
|
||||
config RT_WLAN_PROT_MAX
|
||||
int "Transport protocol maxcount"
|
||||
default 2
|
||||
|
||||
config RT_WLAN_DEFAULT_PROT
|
||||
string "Default transport protocol"
|
||||
default "lwip"
|
||||
|
||||
config RT_WLAN_PROT_LWIP_ENABLE
|
||||
bool "LWIP transport protocol Enable"
|
||||
select RT_USING_LWIP
|
||||
default y
|
||||
|
||||
if RT_WLAN_PROT_LWIP_ENABLE
|
||||
config RT_WLAN_PROT_LWIP_NAME
|
||||
string "LWIP transport protocol name"
|
||||
default "lwip"
|
||||
|
||||
config RT_WLAN_PROT_LWIP_PBUF_FORCE
|
||||
bool "Forced use of PBUF transmission"
|
||||
default n
|
||||
endif
|
||||
endif
|
||||
|
||||
config RT_WLAN_WORK_THREAD_ENABLE
|
||||
bool "WLAN work queue thread Enable"
|
||||
default y
|
||||
|
||||
if RT_WLAN_WORK_THREAD_ENABLE
|
||||
config RT_WLAN_WORKQUEUE_THREAD_NAME
|
||||
string "WLAN work queue thread name"
|
||||
default "wlan"
|
||||
|
||||
config RT_WLAN_WORKQUEUE_THREAD_SIZE
|
||||
int "WLAN work queue thread size"
|
||||
default 2048
|
||||
|
||||
config RT_WLAN_WORKQUEUE_THREAD_PRIO
|
||||
int "WLAN work queue thread priority"
|
||||
default 15
|
||||
endif
|
||||
|
||||
menuconfig RT_WLAN_DEBUG
|
||||
bool "Enable WLAN Debugging Options"
|
||||
default n
|
||||
|
||||
if RT_WLAN_DEBUG
|
||||
config RT_WLAN_CMD_DEBUG
|
||||
bool "Enable Debugging of wlan_cmd.c"
|
||||
default n
|
||||
|
||||
config RT_WLAN_MGNT_DEBUG
|
||||
bool "Enable Debugging of wlan_mgnt.c"
|
||||
default n
|
||||
|
||||
config RT_WLAN_DEV_DEBUG
|
||||
bool "Enable Debugging of wlan_dev.c"
|
||||
default n
|
||||
|
||||
config RT_WLAN_PROT_DEBUG
|
||||
bool "Enable Debugging of wlan_prot.c"
|
||||
default n
|
||||
|
||||
config RT_WLAN_CFG_DEBUG
|
||||
bool "Enable Debugging of wlan_cfg.c"
|
||||
default n
|
||||
|
||||
config RT_WLAN_LWIP_DEBUG
|
||||
bool "Enable Debugging of wlan_lwip.c"
|
||||
default n
|
||||
endif
|
||||
endif
|
||||
|
||||
menu "Using USB"
|
||||
config RT_USING_USB
|
||||
bool
|
||||
default n
|
||||
|
||||
config RT_USING_USB_HOST
|
||||
bool "Using USB host"
|
||||
default n
|
||||
select RT_USING_USB
|
||||
|
||||
if RT_USING_USB_HOST
|
||||
config RT_USBH_MSTORAGE
|
||||
bool "Enable Udisk Drivers"
|
||||
default n
|
||||
if RT_USBH_MSTORAGE
|
||||
config UDISK_MOUNTPOINT
|
||||
string "Udisk mount dir"
|
||||
default "/"
|
||||
endif
|
||||
config RT_USBH_HID
|
||||
bool "Enable HID Drivers"
|
||||
default n
|
||||
if RT_USBH_HID
|
||||
config RT_USBH_HID_MOUSE
|
||||
bool "Enable HID mouse protocol"
|
||||
default n
|
||||
endif
|
||||
endif
|
||||
config RT_USING_USB_DEVICE
|
||||
bool "Using USB device"
|
||||
default n
|
||||
select RT_USING_USB
|
||||
|
||||
if RT_USING_USB_DEVICE || RT_USING_USB_HOST
|
||||
config RT_USBD_THREAD_STACK_SZ
|
||||
int "usb thread stack size"
|
||||
default 4096
|
||||
endif
|
||||
if RT_USING_USB_DEVICE
|
||||
config USB_VENDOR_ID
|
||||
hex "USB Vendor ID"
|
||||
default 0x0FFE
|
||||
config USB_PRODUCT_ID
|
||||
hex "USB Product ID"
|
||||
default 0x0001
|
||||
|
||||
config RT_USB_DEVICE_COMPOSITE
|
||||
bool "Enable composite device"
|
||||
default n
|
||||
choice
|
||||
prompt "Device type"
|
||||
default _RT_USB_DEVICE_NONE
|
||||
depends on !RT_USB_DEVICE_COMPOSITE
|
||||
config _RT_USB_DEVICE_NONE
|
||||
bool "Using custom class by register interface"
|
||||
select RT_USB_DEVICE_NONE
|
||||
config _RT_USB_DEVICE_CDC
|
||||
bool "Enable to use device as CDC device"
|
||||
select RT_USB_DEVICE_CDC
|
||||
config _RT_USB_DEVICE_MSTORAGE
|
||||
bool "Enable to use device as Mass Storage device"
|
||||
select RT_USB_DEVICE_MSTORAGE
|
||||
config _RT_USB_DEVICE_HID
|
||||
bool "Enable to use device as HID device"
|
||||
select RT_USB_DEVICE_HID
|
||||
config _RT_USB_DEVICE_RNDIS
|
||||
bool "Enable to use device as rndis device"
|
||||
select RT_USB_DEVICE_RNDIS
|
||||
depends on RT_USING_LWIP
|
||||
config _RT_USB_DEVICE_ECM
|
||||
bool "Enable to use device as ecm device"
|
||||
select RT_USB_DEVICE_ECM
|
||||
depends on RT_USING_LWIP
|
||||
config _RT_USB_DEVICE_WINUSB
|
||||
bool "Enable to use device as winusb device"
|
||||
select RT_USB_DEVICE_WINUSB
|
||||
config _RT_USB_DEVICE_AUDIO
|
||||
bool "Enable to use device as audio device"
|
||||
select RT_USB_DEVICE_AUDIO
|
||||
endchoice
|
||||
if RT_USB_DEVICE_COMPOSITE
|
||||
config RT_USB_DEVICE_CDC
|
||||
bool "Enable to use device as CDC device"
|
||||
default n
|
||||
config RT_USB_DEVICE_NONE
|
||||
bool
|
||||
default y
|
||||
config RT_USB_DEVICE_MSTORAGE
|
||||
bool "Enable to use device as Mass Storage device"
|
||||
default n
|
||||
config RT_USB_DEVICE_HID
|
||||
bool "Enable to use device as HID device"
|
||||
default n
|
||||
config RT_USB_DEVICE_RNDIS
|
||||
bool "Enable to use device as rndis device"
|
||||
default n
|
||||
depends on RT_USING_LWIP
|
||||
config RT_USB_DEVICE_ECM
|
||||
bool "Enable to use device as ecm device"
|
||||
default n
|
||||
depends on RT_USING_LWIP
|
||||
config RT_USB_DEVICE_WINUSB
|
||||
bool "Enable to use device as winusb device"
|
||||
default n
|
||||
config RT_USB_DEVICE_AUDIO
|
||||
bool "Enable to use device as audio device"
|
||||
default n
|
||||
endif
|
||||
if RT_USB_DEVICE_CDC
|
||||
config RT_VCOM_TASK_STK_SIZE
|
||||
int "virtual com thread stack size"
|
||||
default 512
|
||||
config RT_CDC_RX_BUFSIZE
|
||||
int "virtual com rx buffer size"
|
||||
default 128
|
||||
config RT_VCOM_TX_USE_DMA
|
||||
bool "Enable to use dma for vcom tx"
|
||||
default n
|
||||
config RT_VCOM_SERNO
|
||||
string "serial number of virtual com"
|
||||
default "32021919830108"
|
||||
config RT_VCOM_SER_LEN
|
||||
int "serial number length of virtual com"
|
||||
default 14
|
||||
config RT_VCOM_TX_TIMEOUT
|
||||
int "tx timeout(ticks) of virtual com"
|
||||
default 1000
|
||||
endif
|
||||
if RT_USB_DEVICE_WINUSB
|
||||
config RT_WINUSB_GUID
|
||||
string "Guid for winusb"
|
||||
default "{6860DC3C-C05F-4807-8807-1CA861CC1D66}"
|
||||
endif
|
||||
if RT_USB_DEVICE_MSTORAGE
|
||||
config RT_USB_MSTORAGE_DISK_NAME
|
||||
string "msc class disk name"
|
||||
default "flash0"
|
||||
endif
|
||||
|
||||
if RT_USB_DEVICE_RNDIS
|
||||
config RNDIS_DELAY_LINK_UP
|
||||
bool "Delay linkup media connection"
|
||||
select RT_USING_TIMER_SOFT
|
||||
default n
|
||||
endif
|
||||
|
||||
if RT_USB_DEVICE_HID
|
||||
config RT_USB_DEVICE_HID_KEYBOARD
|
||||
bool "Use to HID device as Keyboard"
|
||||
default n
|
||||
if RT_USB_DEVICE_HID_KEYBOARD
|
||||
config RT_USB_DEVICE_HID_KEYBOARD_NUMBER
|
||||
int "Number of Keyboard(max 3)"
|
||||
default 1
|
||||
range 1 3
|
||||
endif
|
||||
config RT_USB_DEVICE_HID_MOUSE
|
||||
bool "Use to HID device as Mouse"
|
||||
default n
|
||||
config RT_USB_DEVICE_HID_GENERAL
|
||||
bool "Use to HID device as General HID device"
|
||||
default y
|
||||
if RT_USB_DEVICE_HID_GENERAL
|
||||
config RT_USB_DEVICE_HID_GENERAL_OUT_REPORT_LENGTH
|
||||
int "General HID device out report length"
|
||||
default 63
|
||||
range 0 63
|
||||
|
||||
config RT_USB_DEVICE_HID_GENERAL_IN_REPORT_LENGTH
|
||||
int "General HID device in report length"
|
||||
default 63
|
||||
range 0 63
|
||||
endif
|
||||
config RT_USB_DEVICE_HID_MEDIA
|
||||
bool "Use to HID device as media keyboard"
|
||||
default y
|
||||
endif
|
||||
if RT_USB_DEVICE_AUDIO
|
||||
config RT_USB_DEVICE_AUDIO_MIC
|
||||
bool "Use usb mic device as audio device"
|
||||
default n
|
||||
if RT_USB_DEVICE_AUDIO_MIC
|
||||
config RT_USBD_MIC_DEVICE_NAME
|
||||
string "audio mic device name"
|
||||
default "mic0"
|
||||
endif
|
||||
config RT_USB_DEVICE_AUDIO_SPEAKER
|
||||
bool "Use usb speaker device as audio device"
|
||||
default n
|
||||
if RT_USB_DEVICE_AUDIO_SPEAKER
|
||||
config RT_USBD_SPEAKER_DEVICE_NAME
|
||||
string "audio speaker device name"
|
||||
default "sound0"
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endmenu
|
||||
endmenu
|
||||
@@ -0,0 +1,14 @@
|
||||
# for module compiling
|
||||
import os
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
objs = []
|
||||
list = os.listdir(cwd)
|
||||
|
||||
for d in list:
|
||||
path = os.path.join(cwd, d)
|
||||
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||
objs = objs + SConscript(os.path.join(d, 'SConscript'))
|
||||
|
||||
Return('objs')
|
||||
@@ -0,0 +1,9 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_AUDIO'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,612 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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_size_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_size_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);
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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_list_entry(pipe->suspended_write_list.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
|
||||
/* resume the write thread */
|
||||
rt_thread_resume(thread);
|
||||
|
||||
rt_schedule();
|
||||
}
|
||||
}
|
||||
|
||||
static rt_size_t rt_pipe_read(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
rt_uint32_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),
|
||||
&(thread->tlist));
|
||||
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_list_entry(pipe->suspended_read_list.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
|
||||
/* resume the read thread */
|
||||
rt_thread_resume(thread);
|
||||
|
||||
rt_schedule();
|
||||
}
|
||||
}
|
||||
|
||||
static rt_size_t rt_pipe_write(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
rt_uint32_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),
|
||||
&(thread->tlist));
|
||||
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 */
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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__ */
|
||||
@@ -0,0 +1,8 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd + '/../include']
|
||||
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_CAN'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,970 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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 int _can_int_rx(struct rt_can_device *can, struct rt_can_msg *data, int msgs)
|
||||
{
|
||||
int 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)
|
||||
{
|
||||
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;
|
||||
|
||||
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_uint32_t)tx_tosnd - (rt_uint32_t)tx_fifo->buffer) / sizeof(struct rt_can_sndbxinx_list);
|
||||
tx_tosnd->result = RT_CAN_SND_RESULT_WAIT;
|
||||
if (can->ops->sendmsg(can, data, no) != RT_EOK)
|
||||
{
|
||||
/* send failed. */
|
||||
level = rt_hw_interrupt_disable();
|
||||
rt_list_insert_after(&tx_fifo->freelist, &tx_tosnd->list);
|
||||
rt_hw_interrupt_enable(level);
|
||||
rt_sem_release(&(tx_fifo->sem));
|
||||
continue;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
/* clear can rx interrupt */
|
||||
can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX);
|
||||
}
|
||||
|
||||
if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
|
||||
{
|
||||
struct rt_can_tx_fifo *tx_fifo;
|
||||
|
||||
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;
|
||||
/* clear can tx interrupt */
|
||||
can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_TX);
|
||||
}
|
||||
|
||||
can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_CAN_INT_ERR);
|
||||
|
||||
CAN_UNLOCK(can);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_size_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_size_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)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 >= can->config.maxhdr || pitem->hdr < 0)
|
||||
{
|
||||
count--;
|
||||
pitem++;
|
||||
continue;
|
||||
}
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (!can->hdr[pitem->hdr].connected)
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
rt_memcpy(&can->hdr[pitem->hdr].filter, pitem,
|
||||
sizeof(struct rt_can_filter_item));
|
||||
level = rt_hw_interrupt_disable();
|
||||
can->hdr[pitem->hdr].connected = 1;
|
||||
can->hdr[pitem->hdr].msgs = 0;
|
||||
rt_list_init(&can->hdr[pitem->hdr].list);
|
||||
}
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
count--;
|
||||
pitem++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (count)
|
||||
{
|
||||
if (pitem->hdr >= can->config.maxhdr || pitem->hdr < 0)
|
||||
{
|
||||
count--;
|
||||
pitem++;
|
||||
continue;
|
||||
}
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
if (can->hdr[pitem->hdr].connected)
|
||||
{
|
||||
can->hdr[pitem->hdr].connected = 0;
|
||||
can->hdr[pitem->hdr].msgs = 0;
|
||||
if (!rt_list_isempty(&can->hdr[pitem->hdr].list))
|
||||
{
|
||||
rt_list_remove(can->hdr[pitem->hdr].list.next);
|
||||
}
|
||||
rt_hw_interrupt_enable(level);
|
||||
rt_memset(&can->hdr[pitem->hdr].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;
|
||||
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(" Finded 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. Droped.receive.packages: %010ld.",
|
||||
status.rcvpkg, status.dropedrcvpkg);
|
||||
rt_kprintf("\n Total..send...packages: %010ld. Droped...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
|
||||
@@ -0,0 +1,132 @@
|
||||
说明:
|
||||
本驱动完成了can控制器硬件抽象
|
||||
一 CAN Driver 注册
|
||||
Can driver注册需要填充以下几个数据结构:
|
||||
1、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;
|
||||
#ifdef RT_CAN_USING_LED
|
||||
const struct rt_can_led* rcvled;
|
||||
const struct rt_can_led* sndled;
|
||||
const struct rt_can_led* errled;
|
||||
#endif /*RT_CAN_USING_LED*/
|
||||
rt_uint32_t ticks;
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
rt_uint32_t maxhdr;
|
||||
#endif
|
||||
};
|
||||
struct can_configure 为can驱动的基本配置信息:
|
||||
baud_rate :
|
||||
enum CANBAUD
|
||||
{
|
||||
CAN1MBaud=0, // 1 MBit/sec
|
||||
CAN800kBaud, // 800 kBit/sec
|
||||
CAN500kBaud, // 500 kBit/sec
|
||||
CAN250kBaud, // 250 kBit/sec
|
||||
CAN125kBaud, // 125 kBit/sec
|
||||
CAN100kBaud, // 100 kBit/sec
|
||||
CAN50kBaud, // 50 kBit/sec
|
||||
CAN20kBaud, // 20 kBit/sec
|
||||
CAN10kBaud // 10 kBit/sec
|
||||
};
|
||||
配置Can的波特率。
|
||||
msgboxsz : Can接收邮箱缓冲数量,本驱动在软件层开辟msgboxsz个接收邮箱。
|
||||
sndboxnumber : can 发送通道数量,该配置为Can控制器实际的发送通道数量。
|
||||
mode :
|
||||
#define RT_CAN_MODE_NORMAL 0 正常模式
|
||||
#define RT_CAN_MODE_LISEN 1 只听模式
|
||||
#define RT_CAN_MODE_LOOPBACK 2 自发自收模式
|
||||
#define RT_CAN_MODE_LOOPBACKANLISEN 3 自发自收只听模式
|
||||
配置Can 的工作状态。
|
||||
privmode :
|
||||
#define RT_CAN_MODE_PRIV 0x01 处于优先级模式,高优先级的消息优先发送。
|
||||
#define RT_CAN_MODE_NOPRIV 0x00
|
||||
配置Can driver的优先级模式。
|
||||
#ifdef RT_CAN_USING_LED
|
||||
const struct rt_can_led* rcvled;
|
||||
const struct rt_can_led* sndled;
|
||||
const struct rt_can_led* errled;
|
||||
#endif /*RT_CAN_USING_LED*/
|
||||
配置can led信息, 当前can驱动的led使用了 pin驱动,
|
||||
开启RT_CAN_USING_LED时要确保当前系统已实现pin驱动。
|
||||
rt_uint32_t ticks : 配置Can driver timer周期。
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
rt_uint32_t maxhdr;
|
||||
#endif
|
||||
如果使用硬件过滤,则开启RT_CAN_USING_HDR, maxhdr 为Can控制器过滤表的数量。
|
||||
2、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);
|
||||
int (*sendmsg)(struct rt_can_device *can, const void* buf, rt_uint32_t boxno);
|
||||
int (*recvmsg)(struct rt_can_device *can,void* buf, rt_uint32_t boxno);
|
||||
};
|
||||
struct rt_can_ops 为要实现的特定的can控制器操作。
|
||||
rt_err_t (*configure)(struct rt_can_device *can, struct can_configure *cfg);
|
||||
configure根据配置信息初始化Can控制器工作模式。
|
||||
rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg);
|
||||
control 当前接受以下cmd参数:
|
||||
#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
|
||||
int (*sendmsg)(struct rt_can_device *can, const void* buf, rt_uint32_t boxno);
|
||||
sendmsg向Can控制器发送数,boxno为发送通道号。
|
||||
int (*recvmsg)(struct rt_can_device *can,void* buf, rt_uint32_t boxno);
|
||||
recvmsg从Can控制器接收数据,boxno为接收通道号。
|
||||
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
|
||||
void *can_rx;
|
||||
void *can_tx;
|
||||
};
|
||||
填充完成后,便可调用rt_hw_can_register完成can驱动的注册。
|
||||
二、 CAN Driver 的添加:
|
||||
要添加一个新的Can驱动,至少要完成以下接口。
|
||||
1、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);
|
||||
int (*sendmsg)(struct rt_can_device *can, const void* buf, rt_uint32_t boxno);
|
||||
int (*recvmsg)(struct rt_can_device *can,void* buf, rt_uint32_t boxno);
|
||||
};
|
||||
2、 rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg);
|
||||
接口的
|
||||
#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
|
||||
若干命令。
|
||||
3、can口中断,要完接收,发送结束,以及错误中断。
|
||||
#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 complete */
|
||||
#define RT_CAN_EVENT_RX_TIMEOUT 0x05 /* Rx timeout */
|
||||
#define RT_CAN_EVENT_RXOF_IND 0x06 /* Rx overflow */
|
||||
中断产生后,调用rt_hw_can_isr(struct rt_can_device *can, int event)
|
||||
进入相应的操作,其中接收发送中断的event,最低8位为上面的事件,16到24位为通信通道号。
|
||||
一个作为一个例子,参见bsp/stm32f10x/driver下的bxcan.c 。
|
||||
三、CAN Driver的使用:
|
||||
一个使用的例子,参数bsp/stm32f10x/applications下的canapp.c
|
||||
四、当前Can驱动,没有实现轮模式,采用中断模式,bxcan驱动工作在loopback模式下的时候不能读数据。
|
||||
|
||||
五、当前Can驱动,在stm32f105上测试,暂无问题。
|
||||
@@ -0,0 +1,14 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd + '/../include']
|
||||
src = Split('''
|
||||
cputime.c
|
||||
''')
|
||||
|
||||
if GetDepend('RT_USING_CPUTIME_CORTEXM'):
|
||||
src += ['cputime_cortexm.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_CPUTIME'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2017-12-23 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rtdevice.h>
|
||||
#include <rtthread.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
static const struct rt_clock_cputime_ops *_cputime_ops = RT_NULL;
|
||||
|
||||
/**
|
||||
* The clock_cpu_getres() function shall return the resolution of CPU time, the
|
||||
* number of nanosecond per tick.
|
||||
*
|
||||
* @return the number of nanosecond per tick
|
||||
*/
|
||||
float clock_cpu_getres(void)
|
||||
{
|
||||
if (_cputime_ops)
|
||||
return _cputime_ops->cputime_getres();
|
||||
|
||||
rt_set_errno(ENOSYS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The clock_cpu_gettime() function shall return the current value of cpu time tick.
|
||||
*
|
||||
* @return the cpu tick
|
||||
*/
|
||||
uint64_t clock_cpu_gettime(void)
|
||||
{
|
||||
if (_cputime_ops)
|
||||
return _cputime_ops->cputime_gettime();
|
||||
|
||||
rt_set_errno(ENOSYS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The clock_cpu_microsecond() fucntion shall return the microsecond according to
|
||||
* cpu_tick parameter.
|
||||
*
|
||||
* @param cpu_tick the cpu tick
|
||||
*
|
||||
* @return the microsecond
|
||||
*/
|
||||
uint32_t clock_cpu_microsecond(uint32_t cpu_tick)
|
||||
{
|
||||
float unit = clock_cpu_getres();
|
||||
|
||||
return (uint32_t)((cpu_tick * unit) / 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* The clock_cpu_microsecond() fucntion shall return the millisecond according to
|
||||
* cpu_tick parameter.
|
||||
*
|
||||
* @param cpu_tick the cpu tick
|
||||
*
|
||||
* @return the millisecond
|
||||
*/
|
||||
uint32_t clock_cpu_millisecond(uint32_t cpu_tick)
|
||||
{
|
||||
float unit = clock_cpu_getres();
|
||||
|
||||
return (uint32_t)((cpu_tick * unit) / (1000 * 1000));
|
||||
}
|
||||
|
||||
/**
|
||||
* The clock_cpu_seops() function shall set the ops of cpu time.
|
||||
*
|
||||
* @return always return 0.
|
||||
*/
|
||||
int clock_cpu_setops(const struct rt_clock_cputime_ops *ops)
|
||||
{
|
||||
_cputime_ops = ops;
|
||||
if (ops)
|
||||
{
|
||||
RT_ASSERT(ops->cputime_getres != RT_NULL);
|
||||
RT_ASSERT(ops->cputime_gettime != RT_NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2017-12-23 Bernard first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdevice.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include <board.h>
|
||||
|
||||
/* Use Cycle counter of Data Watchpoint and Trace Register for CPU time */
|
||||
|
||||
static float cortexm_cputime_getres(void)
|
||||
{
|
||||
float ret = 1000 * 1000 * 1000;
|
||||
|
||||
ret = ret / SystemCoreClock;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint64_t cortexm_cputime_gettime(void)
|
||||
{
|
||||
return DWT->CYCCNT;
|
||||
}
|
||||
|
||||
const static struct rt_clock_cputime_ops _cortexm_ops =
|
||||
{
|
||||
cortexm_cputime_getres,
|
||||
cortexm_cputime_gettime
|
||||
};
|
||||
|
||||
int cortexm_cputime_init(void)
|
||||
{
|
||||
/* check support bit */
|
||||
if ((DWT->CTRL & (1UL << DWT_CTRL_NOCYCCNT_Pos)) == 0)
|
||||
{
|
||||
/* enable trace*/
|
||||
CoreDebug->DEMCR |= (1UL << CoreDebug_DEMCR_TRCENA_Pos);
|
||||
|
||||
/* whether cycle counter not enabled */
|
||||
if ((DWT->CTRL & (1UL << DWT_CTRL_CYCCNTENA_Pos)) == 0)
|
||||
{
|
||||
/* enable cycle counter */
|
||||
DWT->CTRL |= (1UL << DWT_CTRL_CYCCNTENA_Pos);
|
||||
}
|
||||
|
||||
clock_cpu_setops(&_cortexm_ops);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_BOARD_EXPORT(cortexm_cputime_init);
|
||||
@@ -0,0 +1,34 @@
|
||||
Import('RTT_ROOT')
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd, str(Dir('#'))]
|
||||
|
||||
src = ['hwcrypto.c']
|
||||
|
||||
if (GetDepend(['RT_HWCRYPTO_USING_AES']) or
|
||||
GetDepend(['RT_HWCRYPTO_USING_DES']) or
|
||||
GetDepend(['RT_HWCRYPTO_USING_3DES']) or
|
||||
GetDepend(['RT_HWCRYPTO_USING_RC4'])):
|
||||
src += ['hw_symmetric.c']
|
||||
if GetDepend(['RT_HWCRYPTO_USING_GCM']):
|
||||
src += ['hw_gcm.c']
|
||||
|
||||
if (GetDepend(['RT_HWCRYPTO_USING_MD5']) or
|
||||
GetDepend(['RT_HWCRYPTO_USING_SHA1']) or
|
||||
GetDepend(['RT_HWCRYPTO_USING_SHA2'])):
|
||||
src += ['hw_hash.c']
|
||||
|
||||
if GetDepend(['RT_HWCRYPTO_USING_RNG']):
|
||||
src += ['hw_rng.c']
|
||||
|
||||
if GetDepend(['RT_HWCRYPTO_USING_CRC']):
|
||||
src += ['hw_crc.c']
|
||||
|
||||
if GetDepend(['RT_HWCRYPTO_USING_BIGNUM']):
|
||||
src += ['hw_bignum.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_HWCRYPTO'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-04-25 tyx the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <hw_bignum.h>
|
||||
|
||||
static struct rt_hwcrypto_ctx *bignum_default;
|
||||
|
||||
rt_inline rt_err_t hwcrypto_bignum_dev_is_init(void)
|
||||
{
|
||||
struct rt_hwcrypto_device *dev;
|
||||
|
||||
if (bignum_default)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
dev = rt_hwcrypto_dev_default();
|
||||
if (dev == RT_NULL)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
return rt_hwcrypto_bignum_default(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Setting bignum default devices
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_bignum_default(struct rt_hwcrypto_device *device)
|
||||
{
|
||||
if (bignum_default)
|
||||
{
|
||||
rt_hwcrypto_ctx_destroy(bignum_default);
|
||||
bignum_default = RT_NULL;
|
||||
}
|
||||
if (device == RT_NULL)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
bignum_default = rt_hwcrypto_ctx_create(device, HWCRYPTO_TYPE_BIGNUM, sizeof(struct hwcrypto_bignum));
|
||||
if (bignum_default == RT_NULL)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Init bignum obj
|
||||
*
|
||||
* @param n bignum obj
|
||||
*/
|
||||
void rt_hwcrypto_bignum_init(struct hw_bignum_mpi *n)
|
||||
{
|
||||
if(n == RT_NULL)
|
||||
return;
|
||||
|
||||
n->sign = 1;
|
||||
n->total = 0;
|
||||
n->p = RT_NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief free a bignum obj
|
||||
*
|
||||
* @param Pointer to bignum obj
|
||||
*/
|
||||
void rt_hwcrypto_bignum_free(struct hw_bignum_mpi *n)
|
||||
{
|
||||
if (n)
|
||||
{
|
||||
rt_free(n->p);
|
||||
n->sign = 0;
|
||||
n->total = 0;
|
||||
n->p = RT_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get length of bignum as an unsigned binary buffer
|
||||
*
|
||||
* @param n bignum obj
|
||||
*
|
||||
* @return binary buffer length
|
||||
*/
|
||||
int rt_hwcrypto_bignum_get_len(const struct hw_bignum_mpi *n)
|
||||
{
|
||||
int tmp_len, total;
|
||||
|
||||
if (n == RT_NULL || n->p == RT_NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
tmp_len = 0;
|
||||
total = n->total;
|
||||
while ((total > 0) && (n->p[total - 1] == 0))
|
||||
{
|
||||
tmp_len++;
|
||||
total--;
|
||||
}
|
||||
return n->total - tmp_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Export n into unsigned binary data, big endian
|
||||
*
|
||||
* @param n bignum obj
|
||||
* @param buf Buffer for the binary number
|
||||
* @param len Length of the buffer
|
||||
*
|
||||
* @return export bin length
|
||||
*/
|
||||
int rt_hwcrypto_bignum_export_bin(struct hw_bignum_mpi *n, rt_uint8_t *buf, int len)
|
||||
{
|
||||
int cp_len, i, j;
|
||||
|
||||
if (n == RT_NULL || buf == RT_NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
rt_memset(buf, 0, len);
|
||||
cp_len = n->total > len ? len : n->total;
|
||||
for(i = cp_len, j = 0; i > 0; i--, j++)
|
||||
{
|
||||
buf[i - 1] = n->p[j];
|
||||
}
|
||||
|
||||
return cp_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Import n from unsigned binary data, big endian
|
||||
*
|
||||
* @param n bignum obj
|
||||
* @param buf Buffer for the binary number
|
||||
* @param len Length of the buffer
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_bignum_import_bin(struct hw_bignum_mpi *n, rt_uint8_t *buf, int len)
|
||||
{
|
||||
int cp_len, i, j;
|
||||
void *temp_p;
|
||||
|
||||
if (n == RT_NULL || buf == RT_NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (n->total < len)
|
||||
{
|
||||
temp_p = rt_malloc(len);
|
||||
if (temp_p == RT_NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
rt_memset(temp_p, 0, len);
|
||||
rt_free(n->p);
|
||||
n->p = temp_p;
|
||||
n->total = len;
|
||||
}
|
||||
cp_len = n->total > len ? len : n->total;
|
||||
|
||||
for(i = cp_len, j = 0; i > 0; i--, j++)
|
||||
{
|
||||
n->p[j] = buf[i - 1];
|
||||
}
|
||||
|
||||
return cp_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief x = a + b
|
||||
*
|
||||
* @param a bignum obj
|
||||
* @param b bignum obj
|
||||
* @param c bignum obj
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_bignum_add(struct hw_bignum_mpi *x,
|
||||
const struct hw_bignum_mpi *a,
|
||||
const struct hw_bignum_mpi *b)
|
||||
{
|
||||
struct hwcrypto_bignum *bignum_ctx;
|
||||
|
||||
if (hwcrypto_bignum_dev_is_init() != RT_EOK)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
bignum_ctx = (struct hwcrypto_bignum *)bignum_default;
|
||||
if (bignum_ctx->ops->add)
|
||||
{
|
||||
return bignum_ctx->ops->add(bignum_ctx, x, a, b);
|
||||
}
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief x = a - b
|
||||
*
|
||||
* @param a bignum obj
|
||||
* @param b bignum obj
|
||||
* @param c bignum obj
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_bignum_sub(struct hw_bignum_mpi *x,
|
||||
const struct hw_bignum_mpi *a,
|
||||
const struct hw_bignum_mpi *b)
|
||||
{
|
||||
struct hwcrypto_bignum *bignum_ctx;
|
||||
|
||||
if (hwcrypto_bignum_dev_is_init() != RT_EOK)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
bignum_ctx = (struct hwcrypto_bignum *)bignum_default;
|
||||
if (bignum_ctx->ops->sub)
|
||||
{
|
||||
return bignum_ctx->ops->sub(bignum_ctx, x, a, b);
|
||||
}
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief x = a * b
|
||||
*
|
||||
* @param a bignum obj
|
||||
* @param b bignum obj
|
||||
* @param c bignum obj
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_bignum_mul(struct hw_bignum_mpi *x,
|
||||
const struct hw_bignum_mpi *a,
|
||||
const struct hw_bignum_mpi *b)
|
||||
{
|
||||
struct hwcrypto_bignum *bignum_ctx;
|
||||
|
||||
if (hwcrypto_bignum_dev_is_init() != RT_EOK)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
bignum_ctx = (struct hwcrypto_bignum *)bignum_default;
|
||||
if (bignum_ctx->ops->mul)
|
||||
{
|
||||
return bignum_ctx->ops->mul(bignum_ctx, x, a, b);
|
||||
}
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief x = a * b (mod c)
|
||||
*
|
||||
* @param a bignum obj
|
||||
* @param b bignum obj
|
||||
* @param c bignum obj
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_bignum_mulmod(struct hw_bignum_mpi *x,
|
||||
const struct hw_bignum_mpi *a,
|
||||
const struct hw_bignum_mpi *b,
|
||||
const struct hw_bignum_mpi *c)
|
||||
{
|
||||
struct hwcrypto_bignum *bignum_ctx;
|
||||
|
||||
if (hwcrypto_bignum_dev_is_init() != RT_EOK)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
bignum_ctx = (struct hwcrypto_bignum *)bignum_default;
|
||||
if (bignum_ctx->ops->mulmod)
|
||||
{
|
||||
return bignum_ctx->ops->mulmod(bignum_ctx, x, a, b, c);
|
||||
}
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief x = a ^ b (mod c)
|
||||
*
|
||||
* @param a bignum obj
|
||||
* @param b bignum obj
|
||||
* @param c bignum obj
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_bignum_exptmod(struct hw_bignum_mpi *x,
|
||||
const struct hw_bignum_mpi *a,
|
||||
const struct hw_bignum_mpi *b,
|
||||
const struct hw_bignum_mpi *c)
|
||||
{
|
||||
struct hwcrypto_bignum *bignum_ctx;
|
||||
|
||||
if (hwcrypto_bignum_dev_is_init() != RT_EOK)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
bignum_ctx = (struct hwcrypto_bignum *)bignum_default;
|
||||
if (bignum_ctx->ops->exptmod)
|
||||
{
|
||||
return bignum_ctx->ops->exptmod(bignum_ctx, x, a, b, c);
|
||||
}
|
||||
return -RT_ERROR;
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-04-25 tyx the first version
|
||||
*/
|
||||
|
||||
#ifndef __HW_BIGNUM_H__
|
||||
#define __HW_BIGNUM_H__
|
||||
|
||||
#include <hwcrypto.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct hwcrypto_bignum;
|
||||
|
||||
/* bignum obj */
|
||||
struct hw_bignum_mpi
|
||||
{
|
||||
int sign; /**< integer sign */
|
||||
rt_size_t total; /**< total of limbs */
|
||||
rt_uint8_t *p; /**< pointer to limbs */
|
||||
};
|
||||
|
||||
struct hwcrypto_bignum_ops
|
||||
{
|
||||
rt_err_t (*add)(struct hwcrypto_bignum *bignum_ctx,
|
||||
struct hw_bignum_mpi *x,
|
||||
const struct hw_bignum_mpi *a,
|
||||
const struct hw_bignum_mpi *b); /**< x = a + b */
|
||||
rt_err_t (*sub)(struct hwcrypto_bignum *bignum_ctx,
|
||||
struct hw_bignum_mpi *x,
|
||||
const struct hw_bignum_mpi *a,
|
||||
const struct hw_bignum_mpi *b); /**< x = a - b */
|
||||
rt_err_t (*mul)(struct hwcrypto_bignum *bignum_ctx,
|
||||
struct hw_bignum_mpi *x,
|
||||
const struct hw_bignum_mpi *a,
|
||||
const struct hw_bignum_mpi *b); /**< x = a * b */
|
||||
rt_err_t (*mulmod)(struct hwcrypto_bignum *bignum_ctx,
|
||||
struct hw_bignum_mpi *x,
|
||||
const struct hw_bignum_mpi *a,
|
||||
const struct hw_bignum_mpi *b,
|
||||
const struct hw_bignum_mpi *c); /**< x = a * b (mod c) */
|
||||
rt_err_t (*exptmod)(struct hwcrypto_bignum *bignum_ctx,
|
||||
struct hw_bignum_mpi *x,
|
||||
const struct hw_bignum_mpi *a,
|
||||
const struct hw_bignum_mpi *b,
|
||||
const struct hw_bignum_mpi *c); /**< x = a ^ b (mod c) */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief bignum context. Hardware driver usage
|
||||
*/
|
||||
struct hwcrypto_bignum
|
||||
{
|
||||
struct rt_hwcrypto_ctx parent; /**< Inheritance from hardware crypto context */
|
||||
const struct hwcrypto_bignum_ops *ops; /**< !! Hardware initializes this value when creating context !! */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Setting bignum default devices
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_bignum_default(struct rt_hwcrypto_device *device);
|
||||
|
||||
/**
|
||||
* @brief Init bignum obj
|
||||
*/
|
||||
void rt_hwcrypto_bignum_init(struct hw_bignum_mpi *n);
|
||||
|
||||
/**
|
||||
* @brief free a bignum obj
|
||||
*
|
||||
* @param Pointer to bignum obj
|
||||
*/
|
||||
void rt_hwcrypto_bignum_free(struct hw_bignum_mpi *n);
|
||||
|
||||
/**
|
||||
* @brief Get length of bignum as an unsigned binary buffer
|
||||
*
|
||||
* @param n bignum obj
|
||||
*
|
||||
* @return binary buffer Length
|
||||
*/
|
||||
int rt_hwcrypto_bignum_get_len(const struct hw_bignum_mpi *n);
|
||||
|
||||
/**
|
||||
* @brief Export n into unsigned binary data, big endian
|
||||
*
|
||||
* @param n bignum obj
|
||||
* @param buf Buffer for the binary number
|
||||
* @param len Length of the buffer
|
||||
*
|
||||
* @return export bin length
|
||||
*/
|
||||
int rt_hwcrypto_bignum_export_bin(struct hw_bignum_mpi *n, rt_uint8_t *buf, int len);
|
||||
|
||||
/**
|
||||
* @brief Import n from unsigned binary data, big endian
|
||||
*
|
||||
* @param n bignum obj
|
||||
* @param buf Buffer for the binary number
|
||||
* @param len Length of the buffer
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_bignum_import_bin(struct hw_bignum_mpi *n, rt_uint8_t *buf, int len);
|
||||
|
||||
/**
|
||||
* @brief x = a + b
|
||||
*
|
||||
* @param a bignum obj
|
||||
* @param b bignum obj
|
||||
* @param c bignum obj
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_bignum_add(struct hw_bignum_mpi *x,
|
||||
const struct hw_bignum_mpi *a,
|
||||
const struct hw_bignum_mpi *b);
|
||||
|
||||
/**
|
||||
* @brief x = a - b
|
||||
*
|
||||
* @param a bignum obj
|
||||
* @param b bignum obj
|
||||
* @param c bignum obj
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_bignum_sub(struct hw_bignum_mpi *x,
|
||||
const struct hw_bignum_mpi *a,
|
||||
const struct hw_bignum_mpi *b);
|
||||
|
||||
/**
|
||||
* @brief x = a * b
|
||||
*
|
||||
* @param a bignum obj
|
||||
* @param b bignum obj
|
||||
* @param c bignum obj
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_bignum_mul(struct hw_bignum_mpi *x,
|
||||
const struct hw_bignum_mpi *a,
|
||||
const struct hw_bignum_mpi *b);
|
||||
|
||||
/**
|
||||
* @brief x = a * b (mod c)
|
||||
*
|
||||
* @param a bignum obj
|
||||
* @param b bignum obj
|
||||
* @param c bignum obj
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_bignum_mulmod(struct hw_bignum_mpi *x,
|
||||
const struct hw_bignum_mpi *a,
|
||||
const struct hw_bignum_mpi *b,
|
||||
const struct hw_bignum_mpi *c);
|
||||
|
||||
/**
|
||||
* @brief x = a ^ b (mod c)
|
||||
*
|
||||
* @param a bignum obj
|
||||
* @param b bignum obj
|
||||
* @param c bignum obj
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_bignum_exptmod(struct hw_bignum_mpi *x,
|
||||
const struct hw_bignum_mpi *a,
|
||||
const struct hw_bignum_mpi *b,
|
||||
const struct hw_bignum_mpi *c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-04-25 tyx the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <hw_crc.h>
|
||||
|
||||
/**
|
||||
* @brief Creating CRC Context
|
||||
*
|
||||
* @param device Hardware crypto device
|
||||
* @param mode Setting default mode or custom mode
|
||||
*
|
||||
* @return CRC context
|
||||
*/
|
||||
struct rt_hwcrypto_ctx *rt_hwcrypto_crc_create(struct rt_hwcrypto_device *device,
|
||||
hwcrypto_crc_mode mode)
|
||||
{
|
||||
struct hwcrypto_crc *crc_ctx;
|
||||
|
||||
crc_ctx = (struct hwcrypto_crc *)rt_hwcrypto_ctx_create(device, HWCRYPTO_TYPE_CRC, sizeof(struct hwcrypto_crc));
|
||||
if (crc_ctx == RT_NULL)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case HWCRYPTO_CRC_CRC8:
|
||||
{
|
||||
struct hwcrypto_crc_cfg temp = HWCRYPTO_CRC8_CFG;
|
||||
crc_ctx->crc_cfg = temp;
|
||||
break;
|
||||
}
|
||||
case HWCRYPTO_CRC_CRC16:
|
||||
{
|
||||
struct hwcrypto_crc_cfg temp = HWCRYPTO_CRC16_CFG;
|
||||
crc_ctx->crc_cfg = temp;
|
||||
break;
|
||||
}
|
||||
case HWCRYPTO_CRC_CRC32:
|
||||
{
|
||||
struct hwcrypto_crc_cfg temp = HWCRYPTO_CRC32_CFG;
|
||||
crc_ctx->crc_cfg = temp;
|
||||
break;
|
||||
}
|
||||
case HWCRYPTO_CRC_CCITT:
|
||||
{
|
||||
struct hwcrypto_crc_cfg temp = HWCRYPTO_CRC_CCITT_CFG;
|
||||
crc_ctx->crc_cfg = temp;
|
||||
break;
|
||||
}
|
||||
case HWCRYPTO_CRC_DNP:
|
||||
{
|
||||
struct hwcrypto_crc_cfg temp = HWCRYPTO_CRC_DNP_CFG;
|
||||
crc_ctx->crc_cfg = temp;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return &crc_ctx->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroy CRC Context
|
||||
*
|
||||
* @param ctx CRC context
|
||||
*/
|
||||
void rt_hwcrypto_crc_destroy(struct rt_hwcrypto_ctx *ctx)
|
||||
{
|
||||
rt_hwcrypto_ctx_destroy(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Processing a packet of data
|
||||
*
|
||||
* @param ctx CRC context
|
||||
* @param input Data buffer to be Processed
|
||||
* @param length Data Buffer length
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_uint32_t rt_hwcrypto_crc_update(struct rt_hwcrypto_ctx *ctx,
|
||||
const rt_uint8_t *input,
|
||||
rt_size_t length)
|
||||
{
|
||||
struct hwcrypto_crc *crc_ctx = (struct hwcrypto_crc *)ctx;
|
||||
if (ctx && crc_ctx->ops->update)
|
||||
{
|
||||
return crc_ctx->ops->update(crc_ctx, input, length);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CRC context configuration
|
||||
*
|
||||
* @param ctx CRC context
|
||||
* @param cfg CRC config
|
||||
*/
|
||||
void rt_hwcrypto_crc_cfg(struct rt_hwcrypto_ctx *ctx,
|
||||
struct hwcrypto_crc_cfg *cfg)
|
||||
{
|
||||
if (cfg)
|
||||
{
|
||||
((struct hwcrypto_crc *)ctx)->crc_cfg = *cfg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-04-25 tyx the first version
|
||||
*/
|
||||
|
||||
#ifndef __HW_CRC_H__
|
||||
#define __HW_CRC_H__
|
||||
|
||||
#include <hwcrypto.h>
|
||||
|
||||
#define CRC_FLAG_REFIN (0x1 << 0)
|
||||
#define CRC_FLAG_REFOUT (0x1 << 1)
|
||||
|
||||
#define HWCRYPTO_CRC8_CFG \
|
||||
{ \
|
||||
.last_val = 0x00, \
|
||||
.poly = 0x07, \
|
||||
.width = 8, \
|
||||
.xorout = 0x00, \
|
||||
.flags = 0, \
|
||||
}
|
||||
|
||||
#define HWCRYPTO_CRC16_CFG \
|
||||
{ \
|
||||
.last_val = 0x0000, \
|
||||
.poly = 0x8005, \
|
||||
.width = 16, \
|
||||
.xorout = 0x0000, \
|
||||
.flags = 0, \
|
||||
}
|
||||
|
||||
#define HWCRYPTO_CRC32_CFG \
|
||||
{ \
|
||||
.last_val = 0x00000000, \
|
||||
.poly = 0x04C11DB7, \
|
||||
.width = 32, \
|
||||
.xorout = 0x00000000, \
|
||||
.flags = 0, \
|
||||
}
|
||||
|
||||
#define HWCRYPTO_CRC_CCITT_CFG \
|
||||
{ \
|
||||
.last_val = 0x0000, \
|
||||
.poly = 0x1021, \
|
||||
.width = 16, \
|
||||
.xorout = 0x0000, \
|
||||
.flags = CRC_FLAG_REFIN | CRC_FLAG_REFOUT, \
|
||||
}
|
||||
|
||||
#define HWCRYPTO_CRC_DNP_CFG \
|
||||
{ \
|
||||
.last_val = 0x0000, \
|
||||
.poly = 0x3D65, \
|
||||
.width = 16, \
|
||||
.xorout = 0xffff, \
|
||||
.flags = CRC_FLAG_REFIN | CRC_FLAG_REFOUT, \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct hwcrypto_crc;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
HWCRYPTO_CRC_CUSTOM, /**< Custom CRC mode */
|
||||
HWCRYPTO_CRC_CRC8, /**< poly : 0x07 */
|
||||
HWCRYPTO_CRC_CRC16, /**< poly : 0x8005 */
|
||||
HWCRYPTO_CRC_CRC32, /**< poly : 0x04C11DB7 */
|
||||
HWCRYPTO_CRC_CCITT, /**< poly : 0x1021 */
|
||||
HWCRYPTO_CRC_DNP, /**< poly : 0x3D65 */
|
||||
} hwcrypto_crc_mode;
|
||||
|
||||
struct hwcrypto_crc_cfg
|
||||
{
|
||||
rt_uint32_t last_val; /**< Last CRC value cache */
|
||||
rt_uint32_t poly; /**< CRC polynomial */
|
||||
rt_uint16_t width; /**< CRC value width */
|
||||
rt_uint32_t xorout; /**< Result XOR Value */
|
||||
rt_uint16_t flags; /**< Input or output data reverse. CRC_FLAG_REFIN or CRC_FLAG_REFOUT */
|
||||
};
|
||||
|
||||
struct hwcrypto_crc_ops
|
||||
{
|
||||
rt_uint32_t (*update)(struct hwcrypto_crc *ctx,
|
||||
const rt_uint8_t *in, rt_size_t length); /**< Perform a CRC calculation. return CRC value */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief CRC context. Hardware driver usage
|
||||
*/
|
||||
struct hwcrypto_crc
|
||||
{
|
||||
struct rt_hwcrypto_ctx parent; /**< Inherited from the standard device */
|
||||
struct hwcrypto_crc_cfg crc_cfg; /**< CRC configure */
|
||||
const struct hwcrypto_crc_ops *ops; /**< !! Hardware initializes this value when creating context !! */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creating CRC Context
|
||||
*
|
||||
* @param device Hardware crypto device
|
||||
* @param mode Setting default mode or custom mode
|
||||
*
|
||||
* @return CRC context
|
||||
*/
|
||||
struct rt_hwcrypto_ctx *rt_hwcrypto_crc_create(struct rt_hwcrypto_device *device,
|
||||
hwcrypto_crc_mode mode);
|
||||
|
||||
/**
|
||||
* @brief Destroy CRC Context
|
||||
*
|
||||
* @param ctx CRC context
|
||||
*/
|
||||
void rt_hwcrypto_crc_destroy(struct rt_hwcrypto_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Processing a packet of data
|
||||
*
|
||||
* @param ctx CRC context
|
||||
* @param input Data buffer to be Processed
|
||||
* @param length Data Buffer length
|
||||
*
|
||||
* @return CRC value
|
||||
*/
|
||||
rt_uint32_t rt_hwcrypto_crc_update(struct rt_hwcrypto_ctx *ctx,
|
||||
const rt_uint8_t *input, rt_size_t length);
|
||||
|
||||
/**
|
||||
* @brief CRC context configuration
|
||||
*
|
||||
* @param ctx CRC context
|
||||
* @param cfg CRC config
|
||||
*/
|
||||
void rt_hwcrypto_crc_cfg(struct rt_hwcrypto_ctx *ctx,
|
||||
struct hwcrypto_crc_cfg *cfg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-05-14 tyx the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <hw_gcm.h>
|
||||
|
||||
/**
|
||||
* @brief Creating GCM Context
|
||||
*
|
||||
* @param device Hardware crypto device
|
||||
* @param type Type of symmetric crypto context
|
||||
*
|
||||
* @return GCM context
|
||||
*/
|
||||
struct rt_hwcrypto_ctx *rt_hwcrypto_gcm_create(struct rt_hwcrypto_device *device,
|
||||
hwcrypto_type crypt_type)
|
||||
{
|
||||
struct rt_hwcrypto_ctx *ctx;
|
||||
|
||||
ctx = rt_hwcrypto_ctx_create(device, HWCRYPTO_TYPE_GCM, sizeof(struct hwcrypto_gcm));
|
||||
if (ctx)
|
||||
{
|
||||
((struct hwcrypto_gcm *)ctx)->crypt_type = crypt_type;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroy GCM Context
|
||||
*
|
||||
* @param ctx GCM context
|
||||
*/
|
||||
void rt_hwcrypto_gcm_destroy(struct rt_hwcrypto_ctx *ctx)
|
||||
{
|
||||
rt_hwcrypto_ctx_destroy(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function starts a GCM encryption or decryption operation
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param add The buffer holding the additional data
|
||||
* @param add_len The length of the additional data
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_gcm_start(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *add,
|
||||
rt_size_t add_len)
|
||||
{
|
||||
struct hwcrypto_gcm *gcm_ctx = (struct hwcrypto_gcm *)ctx;
|
||||
|
||||
if (gcm_ctx && gcm_ctx->ops->start)
|
||||
{
|
||||
return gcm_ctx->ops->start(gcm_ctx, add, add_len);
|
||||
}
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function finishes the GCM operation and generates the authentication tag
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param tag The buffer for holding the tag
|
||||
* @param tag_len The length of the tag to generate
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_gcm_finish(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *tag,
|
||||
rt_size_t tag_len)
|
||||
{
|
||||
struct hwcrypto_gcm *gcm_ctx = (struct hwcrypto_gcm *)ctx;
|
||||
|
||||
if (gcm_ctx && gcm_ctx->ops->finish)
|
||||
{
|
||||
return gcm_ctx->ops->finish(gcm_ctx, tag, tag_len);
|
||||
}
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function performs a symmetric encryption or decryption operation
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param mode Operation mode. HWCRYPTO_MODE_ENCRYPT or HWCRYPTO_MODE_DECRYPT
|
||||
* @param length The length of the input data in Bytes. This must be a multiple of the block size
|
||||
* @param in The buffer holding the input data
|
||||
* @param out The buffer holding the output data
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_gcm_crypt(struct rt_hwcrypto_ctx *ctx, hwcrypto_mode mode,
|
||||
rt_size_t length, const rt_uint8_t *in, rt_uint8_t *out)
|
||||
{
|
||||
return rt_hwcrypto_symmetric_crypt(ctx, mode, length, in, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set Symmetric Encryption and Decryption Key
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param key The crypto key
|
||||
* @param bitlen The crypto key bit length
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_gcm_setkey(struct rt_hwcrypto_ctx *ctx,
|
||||
const rt_uint8_t *key, rt_uint32_t bitlen)
|
||||
{
|
||||
return rt_hwcrypto_symmetric_setkey(ctx, key, bitlen);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get Symmetric Encryption and Decryption Key
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param key The crypto key buffer
|
||||
* @param bitlen The crypto key bit length
|
||||
*
|
||||
* @return Key length of copy
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_gcm_getkey(struct rt_hwcrypto_ctx *ctx,
|
||||
rt_uint8_t *key, rt_uint32_t bitlen)
|
||||
{
|
||||
return rt_hwcrypto_symmetric_getkey(ctx, key, bitlen);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set Symmetric Encryption and Decryption initialization vector
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param iv The crypto initialization vector
|
||||
* @param len The crypto initialization vector length
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_gcm_setiv(struct rt_hwcrypto_ctx *ctx,
|
||||
const rt_uint8_t *iv, rt_size_t len)
|
||||
{
|
||||
return rt_hwcrypto_symmetric_setiv(ctx, iv, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get Symmetric Encryption and Decryption initialization vector
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param iv The crypto initialization vector buffer
|
||||
* @param len The crypto initialization vector buffer length
|
||||
*
|
||||
* @return IV length of copy
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_gcm_getiv(struct rt_hwcrypto_ctx *ctx,
|
||||
rt_uint8_t *iv, rt_size_t len)
|
||||
{
|
||||
return rt_hwcrypto_symmetric_getiv(ctx, iv, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set offset in initialization vector
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param iv_off The offset in IV
|
||||
*/
|
||||
void rt_hwcrypto_gcm_set_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t iv_off)
|
||||
{
|
||||
rt_hwcrypto_symmetric_set_ivoff(ctx, iv_off);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get offset in initialization vector
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param iv_off It must point to a valid memory
|
||||
*/
|
||||
void rt_hwcrypto_gcm_get_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t *iv_off)
|
||||
{
|
||||
rt_hwcrypto_symmetric_get_ivoff(ctx, iv_off);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function copy GCM context
|
||||
*
|
||||
* @param des The destination GCM context
|
||||
* @param src The GCM context to be copy
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_gcm_cpy(struct rt_hwcrypto_ctx *des,
|
||||
const struct rt_hwcrypto_ctx *src)
|
||||
{
|
||||
struct hwcrypto_gcm *gcm_des = (struct hwcrypto_gcm *)des;
|
||||
struct hwcrypto_gcm *gcm_src = (struct hwcrypto_gcm *)src;
|
||||
|
||||
if (des != RT_NULL && src != RT_NULL)
|
||||
{
|
||||
gcm_des->crypt_type = gcm_src->crypt_type;
|
||||
/* symmetric crypto context copy */
|
||||
return rt_hwcrypto_symmetric_cpy(des, src);
|
||||
}
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset GCM context
|
||||
*
|
||||
* @param ctx GCM context
|
||||
*/
|
||||
void rt_hwcrypto_gcm_reset(struct rt_hwcrypto_ctx *ctx)
|
||||
{
|
||||
rt_hwcrypto_symmetric_reset(ctx);
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-05-14 tyx the first version
|
||||
*/
|
||||
|
||||
#ifndef __HW_GCM_H__
|
||||
#define __HW_GCM_H__
|
||||
|
||||
#include "hw_symmetric.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct hwcrypto_gcm;
|
||||
|
||||
struct hwcrypto_gcm_ops
|
||||
{
|
||||
rt_err_t (*start)(struct hwcrypto_gcm *gcm_ctx,
|
||||
const unsigned char *add, rt_size_t add_len); /**< Set additional data. start GCM operation */
|
||||
rt_err_t (*finish)(struct hwcrypto_gcm *gcm_ctx,
|
||||
const unsigned char *tag, rt_size_t tag_len); /**< finish GCM operation. get tag */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief GCM context. Hardware driver usage
|
||||
*/
|
||||
struct hwcrypto_gcm
|
||||
{
|
||||
struct hwcrypto_symmetric parent; /**< Inheritance from hardware symmetric crypto context */
|
||||
hwcrypto_type crypt_type; /**< symmetric crypto type. eg: AES/DES */
|
||||
const struct hwcrypto_gcm_ops *ops; /**< !! Hardware initializes this value when creating context !! */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creating GCM Context
|
||||
*
|
||||
* @param device Hardware crypto device
|
||||
* @param type Type of symmetric crypto context
|
||||
*
|
||||
* @return GCM context
|
||||
*/
|
||||
struct rt_hwcrypto_ctx *rt_hwcrypto_gcm_create(struct rt_hwcrypto_device *device,
|
||||
hwcrypto_type crypt_type);
|
||||
|
||||
/**
|
||||
* @brief Destroy GCM Context
|
||||
*
|
||||
* @param ctx GCM context
|
||||
*/
|
||||
void rt_hwcrypto_gcm_destroy(struct rt_hwcrypto_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief This function starts a GCM encryption or decryption operation
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param add The buffer holding the additional data
|
||||
* @param add_len The length of the additional data
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_gcm_start(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *add,
|
||||
rt_size_t add_len);
|
||||
|
||||
/**
|
||||
* @brief This function finishes the GCM operation and generates the authentication tag
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param tag The buffer for holding the tag
|
||||
* @param tag_len The length of the tag to generate
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_gcm_finish(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *tag,
|
||||
rt_size_t tag_len);
|
||||
|
||||
/**
|
||||
* @brief This function performs a symmetric encryption or decryption operation
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param mode Operation mode. HWCRYPTO_MODE_ENCRYPT or HWCRYPTO_MODE_DECRYPT
|
||||
* @param length The length of the input data in Bytes. This must be a multiple of the block size
|
||||
* @param in The buffer holding the input data
|
||||
* @param out The buffer holding the output data
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_gcm_crypt(struct rt_hwcrypto_ctx *ctx, hwcrypto_mode mode,
|
||||
rt_size_t length, const rt_uint8_t *in, rt_uint8_t *out);
|
||||
|
||||
/**
|
||||
* @brief Set Symmetric Encryption and Decryption Key
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param key The crypto key
|
||||
* @param bitlen The crypto key bit length
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_gcm_setkey(struct rt_hwcrypto_ctx *ctx,
|
||||
const rt_uint8_t *key, rt_uint32_t bitlen);
|
||||
|
||||
/**
|
||||
* @brief Get Symmetric Encryption and Decryption Key
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param key The crypto key buffer
|
||||
* @param bitlen The crypto key bit length
|
||||
*
|
||||
* @return Key length of copy
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_gcm_getkey(struct rt_hwcrypto_ctx *ctx,
|
||||
rt_uint8_t *key, rt_uint32_t bitlen);
|
||||
|
||||
/**
|
||||
* @brief Set Symmetric Encryption and Decryption initialization vector
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param iv The crypto initialization vector
|
||||
* @param len The crypto initialization vector length
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_gcm_setiv(struct rt_hwcrypto_ctx *ctx,
|
||||
const rt_uint8_t *iv, rt_size_t len);
|
||||
|
||||
/**
|
||||
* @brief Get Symmetric Encryption and Decryption initialization vector
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param iv The crypto initialization vector buffer
|
||||
* @param len The crypto initialization vector buffer length
|
||||
*
|
||||
* @return IV length of copy
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_gcm_getiv(struct rt_hwcrypto_ctx *ctx,
|
||||
rt_uint8_t *iv, rt_size_t len);
|
||||
|
||||
/**
|
||||
* @brief Set offset in initialization vector
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param iv_off The offset in IV
|
||||
*/
|
||||
void rt_hwcrypto_gcm_set_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t iv_off);
|
||||
|
||||
/**
|
||||
* @brief Get offset in initialization vector
|
||||
*
|
||||
* @param ctx GCM context
|
||||
* @param iv_off It must point to a valid memory
|
||||
*/
|
||||
void rt_hwcrypto_gcm_get_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t *iv_off);
|
||||
|
||||
/**
|
||||
* @brief This function copy GCM context
|
||||
*
|
||||
* @param des The destination GCM context
|
||||
* @param src The GCM context to be copy
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_gcm_cpy(struct rt_hwcrypto_ctx *des,
|
||||
const struct rt_hwcrypto_ctx *src);
|
||||
|
||||
/**
|
||||
* @brief Reset GCM context
|
||||
*
|
||||
* @param ctx GCM context
|
||||
*/
|
||||
void rt_hwcrypto_gcm_reset(struct rt_hwcrypto_ctx *ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-04-23 tyx the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <hw_hash.h>
|
||||
|
||||
/**
|
||||
* @brief Creating hash Context
|
||||
*
|
||||
* @param device Hardware crypto device
|
||||
* @param type Type of hash context
|
||||
*
|
||||
* @return Hash context
|
||||
*/
|
||||
struct rt_hwcrypto_ctx *rt_hwcrypto_hash_create(struct rt_hwcrypto_device *device, hwcrypto_type type)
|
||||
{
|
||||
struct rt_hwcrypto_ctx *ctx;
|
||||
|
||||
ctx = rt_hwcrypto_ctx_create(device, type, sizeof(struct hwcrypto_hash));
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroy hash Context
|
||||
*
|
||||
* @param ctx Hash context
|
||||
*/
|
||||
void rt_hwcrypto_hash_destroy(struct rt_hwcrypto_ctx *ctx)
|
||||
{
|
||||
rt_hwcrypto_ctx_destroy(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the final hash value
|
||||
*
|
||||
* @param ctx Hash context
|
||||
* @param output Hash value buffer
|
||||
* @param length Hash value buffer length
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_hash_finish(struct rt_hwcrypto_ctx *ctx, rt_uint8_t *output, rt_size_t length)
|
||||
{
|
||||
if (ctx && ((struct hwcrypto_hash *)ctx)->ops->finish)
|
||||
{
|
||||
return ((struct hwcrypto_hash *)ctx)->ops->finish((struct hwcrypto_hash *)ctx, output, length);
|
||||
}
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Processing a packet of data
|
||||
*
|
||||
* @param ctx Hash context
|
||||
* @param input Data buffer to be Processed
|
||||
* @param length Data Buffer length
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_hash_update(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *input, rt_size_t length)
|
||||
{
|
||||
if (ctx && ((struct hwcrypto_hash *)ctx)->ops->update)
|
||||
{
|
||||
return ((struct hwcrypto_hash *)ctx)->ops->update((struct hwcrypto_hash *)ctx, input, length);
|
||||
}
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function copy hash context
|
||||
*
|
||||
* @param des The destination hash context
|
||||
* @param src The hash context to be copy
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_hash_cpy(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src)
|
||||
{
|
||||
return rt_hwcrypto_ctx_cpy(des, src);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset hash context
|
||||
*
|
||||
* @param ctx Hash context
|
||||
*/
|
||||
void rt_hwcrypto_hash_reset(struct rt_hwcrypto_ctx *ctx)
|
||||
{
|
||||
rt_hwcrypto_ctx_reset(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Setting hash context type
|
||||
*
|
||||
* @param ctx Hash context
|
||||
* @param type Types of settings
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_hash_set_type(struct rt_hwcrypto_ctx *ctx, hwcrypto_type type)
|
||||
{
|
||||
return rt_hwcrypto_set_type(ctx, type);
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-04-23 tyx the first version
|
||||
*/
|
||||
|
||||
#ifndef __HW_HASH_H__
|
||||
#define __HW_HASH_H__
|
||||
|
||||
#include <hwcrypto.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct hwcrypto_hash;
|
||||
|
||||
struct hwcrypto_hash_ops
|
||||
{
|
||||
rt_err_t (*update)(struct hwcrypto_hash *hash_ctx,
|
||||
const rt_uint8_t *in, rt_size_t length); /**< Processing a packet of data */
|
||||
rt_err_t (*finish)(struct hwcrypto_hash *hash_ctx,
|
||||
rt_uint8_t *out, rt_size_t length); /**< Get the final hash value */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief hash context. Hardware driver usage
|
||||
*/
|
||||
struct hwcrypto_hash
|
||||
{
|
||||
struct rt_hwcrypto_ctx parent; /**< Inheritance from hardware crypto context */
|
||||
const struct hwcrypto_hash_ops *ops; /**< !! Hardware initializes this value when creating context !! */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creating hash Context
|
||||
*
|
||||
* @param device Hardware crypto device
|
||||
* @param type Type of hash context
|
||||
*
|
||||
* @return Hash context
|
||||
*/
|
||||
struct rt_hwcrypto_ctx *rt_hwcrypto_hash_create(struct rt_hwcrypto_device *device,
|
||||
hwcrypto_type type);
|
||||
|
||||
/**
|
||||
* @brief Destroy hash Context
|
||||
*
|
||||
* @param ctx Hash context
|
||||
*/
|
||||
void rt_hwcrypto_hash_destroy(struct rt_hwcrypto_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Get the final hash value
|
||||
*
|
||||
* @param ctx Hash context
|
||||
* @param output Hash value buffer
|
||||
* @param length Hash value buffer length
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_hash_finish(struct rt_hwcrypto_ctx *ctx, rt_uint8_t *output, rt_size_t length);
|
||||
|
||||
/**
|
||||
* @brief Processing a packet of data
|
||||
*
|
||||
* @param ctx Hash context
|
||||
* @param input Data buffer to be Processed
|
||||
* @param length Data Buffer length
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_hash_update(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *input, rt_size_t length);
|
||||
|
||||
/**
|
||||
* @brief This function copy hash context
|
||||
*
|
||||
* @param des The destination hash context
|
||||
* @param src The hash context to be copy
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_hash_cpy(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src);
|
||||
|
||||
/**
|
||||
* @brief Reset hash context
|
||||
*
|
||||
* @param ctx Hash context
|
||||
*/
|
||||
void rt_hwcrypto_hash_reset(struct rt_hwcrypto_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Setting hash context type
|
||||
*
|
||||
* @param ctx Hash context
|
||||
* @param type Types of settings
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_hash_set_type(struct rt_hwcrypto_ctx *ctx, hwcrypto_type type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-04-25 tyx the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <hw_rng.h>
|
||||
|
||||
/* Used to save default RNG Context */
|
||||
static struct rt_hwcrypto_ctx *ctx_default;
|
||||
|
||||
/**
|
||||
* @brief Creating RNG Context
|
||||
*
|
||||
* @param device Hardware crypto device
|
||||
*
|
||||
* @return RNG context
|
||||
*/
|
||||
struct rt_hwcrypto_ctx *rt_hwcrypto_rng_create(struct rt_hwcrypto_device *device)
|
||||
{
|
||||
struct rt_hwcrypto_ctx *ctx;
|
||||
|
||||
ctx = rt_hwcrypto_ctx_create(device, HWCRYPTO_TYPE_RNG, sizeof(struct hwcrypto_rng));
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroy RNG Context
|
||||
*
|
||||
* @param ctx RNG context
|
||||
*/
|
||||
void rt_hwcrypto_rng_destroy(struct rt_hwcrypto_ctx *ctx)
|
||||
{
|
||||
/* Destroy the defaule RNG Context ? */
|
||||
if (ctx == ctx_default)
|
||||
{
|
||||
ctx_default = RT_NULL;
|
||||
}
|
||||
rt_hwcrypto_ctx_destroy(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Setting RNG default devices
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_rng_default(struct rt_hwcrypto_device *device)
|
||||
{
|
||||
struct rt_hwcrypto_ctx *tmp_ctx;
|
||||
|
||||
/* if device is null, destroy default RNG Context */
|
||||
if (device == RT_NULL)
|
||||
{
|
||||
if (ctx_default)
|
||||
{
|
||||
rt_hwcrypto_rng_destroy(ctx_default);
|
||||
ctx_default = RT_NULL;
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
/* Try create RNG Context */
|
||||
tmp_ctx = rt_hwcrypto_rng_create(device);
|
||||
if (tmp_ctx == RT_NULL)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
/* create RNG Context success, update default RNG Context */
|
||||
rt_hwcrypto_rng_destroy(ctx_default);
|
||||
ctx_default = tmp_ctx;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getting Random Numbers from RNG Context
|
||||
*
|
||||
* @param ctx RNG context
|
||||
*
|
||||
* @return Random number
|
||||
*/
|
||||
rt_uint32_t rt_hwcrypto_rng_update_ctx(struct rt_hwcrypto_ctx *ctx)
|
||||
{
|
||||
if (ctx)
|
||||
{
|
||||
return ((struct hwcrypto_rng *)ctx)->ops->update((struct hwcrypto_rng *)ctx);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return a random number
|
||||
*
|
||||
* @return Random number
|
||||
*/
|
||||
rt_uint32_t rt_hwcrypto_rng_update(void)
|
||||
{
|
||||
/* Default device does not exist ? */
|
||||
if (ctx_default == RT_NULL)
|
||||
{
|
||||
/* try create Context from default device */
|
||||
rt_hwcrypto_rng_default(rt_hwcrypto_dev_default());
|
||||
}
|
||||
return rt_hwcrypto_rng_update_ctx(ctx_default);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-04-25 tyx the first version
|
||||
*/
|
||||
|
||||
#ifndef __HW_RNG_H__
|
||||
#define __HW_RNG_H__
|
||||
|
||||
#include <hwcrypto.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct hwcrypto_rng;
|
||||
|
||||
struct hwcrypto_rng_ops
|
||||
{
|
||||
rt_uint32_t (*update)(struct hwcrypto_rng *ctx); /**< Return a random number */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief random context. Hardware driver usage
|
||||
*/
|
||||
struct hwcrypto_rng
|
||||
{
|
||||
struct rt_hwcrypto_ctx parent; /**< Inheritance from hardware crypto context */
|
||||
const struct hwcrypto_rng_ops *ops; /**< !! Hardware initializes this value when creating context !! */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creating RNG Context
|
||||
*
|
||||
* @param device Hardware crypto device
|
||||
*
|
||||
* @return RNG context
|
||||
*/
|
||||
struct rt_hwcrypto_ctx *rt_hwcrypto_rng_create(struct rt_hwcrypto_device *device);
|
||||
|
||||
/**
|
||||
* @brief Destroy RNG Context
|
||||
*
|
||||
* @param ctx RNG context
|
||||
*/
|
||||
void rt_hwcrypto_rng_destroy(struct rt_hwcrypto_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Setting RNG default devices
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_rng_default(struct rt_hwcrypto_device *device);
|
||||
|
||||
/**
|
||||
* @brief Getting Random Numbers from RNG Context
|
||||
*
|
||||
* @param ctx RNG context
|
||||
*
|
||||
* @return Random number
|
||||
*/
|
||||
rt_uint32_t rt_hwcrypto_rng_update_ctx(struct rt_hwcrypto_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Return a random number
|
||||
*
|
||||
* @return Random number
|
||||
*/
|
||||
rt_uint32_t rt_hwcrypto_rng_update(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-04-25 tyx the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <hw_symmetric.h>
|
||||
|
||||
/**
|
||||
* @brief Creating Symmetric Encryption and Decryption Context
|
||||
*
|
||||
* @param device Hardware crypto device
|
||||
* @param type Type of symmetric crypto context
|
||||
*
|
||||
* @return Symmetric crypto context
|
||||
*/
|
||||
struct rt_hwcrypto_ctx *rt_hwcrypto_symmetric_create(struct rt_hwcrypto_device *device, hwcrypto_type type)
|
||||
{
|
||||
struct rt_hwcrypto_ctx *ctx;
|
||||
|
||||
ctx = rt_hwcrypto_ctx_create(device, type, sizeof(struct hwcrypto_symmetric));
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroy Symmetric Encryption and Decryption Context
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
*/
|
||||
void rt_hwcrypto_symmetric_destroy(struct rt_hwcrypto_ctx *ctx)
|
||||
{
|
||||
rt_hwcrypto_ctx_destroy(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function performs a symmetric encryption or decryption operation
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
* @param mode Operation mode. HWCRYPTO_MODE_ENCRYPT or HWCRYPTO_MODE_DECRYPT
|
||||
* @param length The length of the input data in Bytes. This must be a multiple of the block size
|
||||
* @param in The buffer holding the input data
|
||||
* @param out The buffer holding the output data
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_symmetric_crypt(struct rt_hwcrypto_ctx *ctx, hwcrypto_mode mode, rt_size_t length, const rt_uint8_t *in, rt_uint8_t *out)
|
||||
{
|
||||
struct hwcrypto_symmetric *symmetric_ctx;
|
||||
struct hwcrypto_symmetric_info symmetric_info;
|
||||
rt_err_t err;
|
||||
|
||||
if (ctx == RT_NULL)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
symmetric_ctx = (struct hwcrypto_symmetric *)ctx;
|
||||
if (symmetric_ctx->ops->crypt == RT_NULL)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
if (mode != HWCRYPTO_MODE_ENCRYPT && mode != HWCRYPTO_MODE_DECRYPT)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
/* Input information packaging */
|
||||
symmetric_info.mode = mode;
|
||||
symmetric_info.in = in;
|
||||
symmetric_info.out = out;
|
||||
symmetric_info.length = length;
|
||||
|
||||
/* Calling Hardware Encryption and Decryption Function */
|
||||
err = symmetric_ctx->ops->crypt(symmetric_ctx, &symmetric_info);
|
||||
|
||||
/* clean up flags */
|
||||
symmetric_ctx->flags &= ~(SYMMTRIC_MODIFY_KEY | SYMMTRIC_MODIFY_IV | SYMMTRIC_MODIFY_IVOFF);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set Symmetric Encryption and Decryption Key
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
* @param key The crypto key
|
||||
* @param bitlen The crypto key bit length
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_symmetric_setkey(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *key, rt_uint32_t bitlen)
|
||||
{
|
||||
struct hwcrypto_symmetric *symmetric_ctx;
|
||||
|
||||
if (ctx && bitlen <= RT_HWCRYPTO_KEYBIT_MAX_SIZE)
|
||||
{
|
||||
symmetric_ctx = (struct hwcrypto_symmetric *)ctx;
|
||||
rt_memcpy(symmetric_ctx->key, key, bitlen >> 3);
|
||||
/* Record key length */
|
||||
symmetric_ctx->key_bitlen = bitlen;
|
||||
/* Key change flag set up */
|
||||
symmetric_ctx->flags |= SYMMTRIC_MODIFY_KEY;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get Symmetric Encryption and Decryption Key
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
* @param key The crypto key buffer
|
||||
* @param bitlen The crypto key bit length
|
||||
*
|
||||
* @return Key length of copy
|
||||
*/
|
||||
int rt_hwcrypto_symmetric_getkey(struct rt_hwcrypto_ctx *ctx, rt_uint8_t *key, rt_uint32_t bitlen)
|
||||
{
|
||||
struct hwcrypto_symmetric *symmetric_ctx = (struct hwcrypto_symmetric *)ctx;
|
||||
|
||||
if (ctx && bitlen >= symmetric_ctx->key_bitlen)
|
||||
{
|
||||
rt_memcpy(key, symmetric_ctx->key, symmetric_ctx->key_bitlen >> 3);
|
||||
return symmetric_ctx->key_bitlen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set Symmetric Encryption and Decryption initialization vector
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
* @param iv The crypto initialization vector
|
||||
* @param len The crypto initialization vector length
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_symmetric_setiv(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *iv, rt_size_t len)
|
||||
{
|
||||
struct hwcrypto_symmetric *symmetric_ctx;
|
||||
|
||||
if (ctx && len <= RT_HWCRYPTO_IV_MAX_SIZE)
|
||||
{
|
||||
symmetric_ctx = (struct hwcrypto_symmetric *)ctx;
|
||||
rt_memcpy(symmetric_ctx->iv, iv, len);
|
||||
symmetric_ctx->iv_len = len;
|
||||
/* IV change flag set up */
|
||||
symmetric_ctx->flags |= SYMMTRIC_MODIFY_IV;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get Symmetric Encryption and Decryption initialization vector
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
* @param iv The crypto initialization vector buffer
|
||||
* @param len The crypto initialization vector buffer length
|
||||
*
|
||||
* @return IV length of copy
|
||||
*/
|
||||
int rt_hwcrypto_symmetric_getiv(struct rt_hwcrypto_ctx *ctx, rt_uint8_t *iv, rt_size_t len)
|
||||
{
|
||||
struct hwcrypto_symmetric *symmetric_ctx = (struct hwcrypto_symmetric *)ctx;;
|
||||
|
||||
if (ctx && len >= symmetric_ctx->iv_len)
|
||||
{
|
||||
rt_memcpy(iv, symmetric_ctx->iv, symmetric_ctx->iv_len);
|
||||
return symmetric_ctx->iv_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set offset in initialization vector
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
* @param iv_off The offset in IV
|
||||
*/
|
||||
void rt_hwcrypto_symmetric_set_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t iv_off)
|
||||
{
|
||||
if (ctx)
|
||||
{
|
||||
((struct hwcrypto_symmetric *)ctx)->iv_off = iv_off;
|
||||
/* iv_off change flag set up */
|
||||
((struct hwcrypto_symmetric *)ctx)->flags |= SYMMTRIC_MODIFY_IVOFF;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get offset in initialization vector
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
* @param iv_off It must point to a valid memory
|
||||
*/
|
||||
void rt_hwcrypto_symmetric_get_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t *iv_off)
|
||||
{
|
||||
if (ctx && iv_off)
|
||||
{
|
||||
*iv_off = ((struct hwcrypto_symmetric *)ctx)->iv_off;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function copy symmetric crypto context
|
||||
*
|
||||
* @param des The destination symmetric crypto context
|
||||
* @param src The symmetric crypto context to be copy
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_symmetric_cpy(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src)
|
||||
{
|
||||
struct hwcrypto_symmetric *symmetric_des = (struct hwcrypto_symmetric *)des;
|
||||
struct hwcrypto_symmetric *symmetric_src = (struct hwcrypto_symmetric *)src;
|
||||
|
||||
if (des != RT_NULL && src != RT_NULL)
|
||||
{
|
||||
/* Copy Symmetric Encryption and Decryption Context Information */
|
||||
symmetric_des->flags = symmetric_src->flags ;
|
||||
symmetric_des->iv_len = symmetric_src->iv_len ;
|
||||
symmetric_des->iv_off = symmetric_src->iv_off ;
|
||||
symmetric_des->key_bitlen = symmetric_src->key_bitlen;
|
||||
rt_memcpy(symmetric_des->iv, symmetric_src->iv, symmetric_src->iv_len);
|
||||
rt_memcpy(symmetric_des->key, symmetric_src->key, symmetric_src->key_bitlen >> 3);
|
||||
|
||||
/* Hardware context copy */
|
||||
return rt_hwcrypto_ctx_cpy(des, src);
|
||||
}
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset symmetric crypto context
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
*/
|
||||
void rt_hwcrypto_symmetric_reset(struct rt_hwcrypto_ctx *ctx)
|
||||
{
|
||||
struct hwcrypto_symmetric *symmetric_ctx = (struct hwcrypto_symmetric *)ctx;
|
||||
if (ctx != RT_NULL)
|
||||
{
|
||||
/* Copy Symmetric Encryption and Decryption Context Information */
|
||||
symmetric_ctx->flags = 0x00;
|
||||
symmetric_ctx->iv_len = 0x00;
|
||||
symmetric_ctx->iv_off = 0x00;
|
||||
symmetric_ctx->key_bitlen = 0x00;
|
||||
rt_memset(symmetric_ctx->iv, 0, RT_HWCRYPTO_IV_MAX_SIZE);
|
||||
rt_memset(symmetric_ctx->key, 0, RT_HWCRYPTO_KEYBIT_MAX_SIZE >> 3);
|
||||
|
||||
/* Hardware context reset */
|
||||
rt_hwcrypto_ctx_reset(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Setting symmetric crypto context type
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
* @param type Types of settings
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_symmetric_set_type(struct rt_hwcrypto_ctx *ctx, hwcrypto_type type)
|
||||
{
|
||||
return rt_hwcrypto_set_type(ctx, type);
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-04-25 tyx the first version
|
||||
*/
|
||||
|
||||
#ifndef __HW_SYMMETRIC_H__
|
||||
#define __HW_SYMMETRIC_H__
|
||||
|
||||
#include <hwcrypto.h>
|
||||
|
||||
#ifndef RT_HWCRYPTO_IV_MAX_SIZE
|
||||
#define RT_HWCRYPTO_IV_MAX_SIZE (16)
|
||||
#endif
|
||||
#ifndef RT_HWCRYPTO_KEYBIT_MAX_SIZE
|
||||
#define RT_HWCRYPTO_KEYBIT_MAX_SIZE (256)
|
||||
#endif
|
||||
|
||||
#define SYMMTRIC_MODIFY_KEY (0x1 << 0)
|
||||
#define SYMMTRIC_MODIFY_IV (0x1 << 1)
|
||||
#define SYMMTRIC_MODIFY_IVOFF (0x1 << 2)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct hwcrypto_symmetric;
|
||||
struct hwcrypto_symmetric_info;
|
||||
|
||||
struct hwcrypto_symmetric_ops
|
||||
{
|
||||
rt_err_t (*crypt)(struct hwcrypto_symmetric *symmetric_ctx,
|
||||
struct hwcrypto_symmetric_info *symmetric_info); /**< Hardware Symmetric Encryption and Decryption Callback */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Hardware driver usage, including input and output information
|
||||
*/
|
||||
struct hwcrypto_symmetric_info
|
||||
{
|
||||
hwcrypto_mode mode; /**< crypto mode. HWCRYPTO_MODE_ENCRYPT or HWCRYPTO_MODE_DECRYPT */
|
||||
const rt_uint8_t *in; /**< Input data */
|
||||
rt_uint8_t *out; /**< Output data will be written */
|
||||
rt_size_t length; /**< The length of the input data in Bytes. It's a multiple of block size. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Symmetric crypto context. Hardware driver usage
|
||||
*/
|
||||
struct hwcrypto_symmetric
|
||||
{
|
||||
struct rt_hwcrypto_ctx parent; /**< Inheritance from hardware crypto context */
|
||||
rt_uint32_t flags; /**< key or iv or ivoff has been changed. The flag will be set up */
|
||||
rt_int32_t iv_len; /**< initialization vector effective length */
|
||||
rt_int32_t iv_off; /**< The offset in IV */
|
||||
rt_uint8_t iv[RT_HWCRYPTO_IV_MAX_SIZE]; /**< The initialization vector */
|
||||
rt_uint8_t key[RT_HWCRYPTO_KEYBIT_MAX_SIZE >> 3]; /**< The crypto key */
|
||||
rt_int32_t key_bitlen; /**< The crypto key bit length */
|
||||
const struct hwcrypto_symmetric_ops *ops; /**< !! Hardware initializes this value when creating context !! */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creating Symmetric Encryption and Decryption Context
|
||||
*
|
||||
* @param device Hardware crypto device
|
||||
* @param type Type of symmetric crypto context
|
||||
*
|
||||
* @return Symmetric crypto context
|
||||
*/
|
||||
struct rt_hwcrypto_ctx *rt_hwcrypto_symmetric_create(struct rt_hwcrypto_device *device,
|
||||
hwcrypto_type type);
|
||||
|
||||
/**
|
||||
* @brief Destroy Symmetric Encryption and Decryption Context
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
*/
|
||||
void rt_hwcrypto_symmetric_destroy(struct rt_hwcrypto_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief This function performs a symmetric encryption or decryption operation
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
* @param mode Operation mode. HWCRYPTO_MODE_ENCRYPT or HWCRYPTO_MODE_DECRYPT
|
||||
* @param length The length of the input data in Bytes. This must be a multiple of the block size
|
||||
* @param in The buffer holding the input data
|
||||
* @param out The buffer holding the output data
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_symmetric_crypt(struct rt_hwcrypto_ctx *ctx, hwcrypto_mode mode,
|
||||
rt_size_t length, const rt_uint8_t *in, rt_uint8_t *out);
|
||||
|
||||
/**
|
||||
* @brief Set Symmetric Encryption and Decryption Key
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
* @param key The crypto key
|
||||
* @param bitlen The crypto key bit length
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_symmetric_setkey(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *key, rt_uint32_t bitlen);
|
||||
|
||||
/**
|
||||
* @brief Get Symmetric Encryption and Decryption Key
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
* @param key The crypto key buffer
|
||||
* @param bitlen The crypto key bit length
|
||||
*
|
||||
* @return Key length of copy
|
||||
*/
|
||||
int rt_hwcrypto_symmetric_getkey(struct rt_hwcrypto_ctx *ctx, rt_uint8_t *key, rt_uint32_t bitlen);
|
||||
|
||||
/**
|
||||
* @brief Set Symmetric Encryption and Decryption initialization vector
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
* @param iv The crypto initialization vector
|
||||
* @param len The crypto initialization vector length
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_symmetric_setiv(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *iv, rt_size_t len);
|
||||
|
||||
/**
|
||||
* @brief Get Symmetric Encryption and Decryption initialization vector
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
* @param iv The crypto initialization vector buffer
|
||||
* @param len The crypto initialization vector buffer length
|
||||
*
|
||||
* @return IV length of copy
|
||||
*/
|
||||
int rt_hwcrypto_symmetric_getiv(struct rt_hwcrypto_ctx *ctx, rt_uint8_t *iv, rt_size_t len);
|
||||
|
||||
/**
|
||||
* @brief Set offset in initialization vector
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
* @param iv_off The offset in IV
|
||||
*/
|
||||
void rt_hwcrypto_symmetric_set_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t iv_off);
|
||||
|
||||
/**
|
||||
* @brief Get offset in initialization vector
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
* @param iv_off It must point to a valid memory
|
||||
*/
|
||||
void rt_hwcrypto_symmetric_get_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t *iv_off);
|
||||
|
||||
/**
|
||||
* @brief This function copy symmetric crypto context
|
||||
*
|
||||
* @param des The destination symmetric crypto context
|
||||
* @param src The symmetric crypto context to be copy
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_symmetric_cpy(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src);
|
||||
|
||||
/**
|
||||
* @brief Reset symmetric crypto context
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
*/
|
||||
void rt_hwcrypto_symmetric_reset(struct rt_hwcrypto_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Setting symmetric crypto context type
|
||||
*
|
||||
* @param ctx Symmetric crypto context
|
||||
* @param type Types of settings
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_symmetric_set_type(struct rt_hwcrypto_ctx *ctx, hwcrypto_type type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-04-23 tyx the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <hwcrypto.h>
|
||||
|
||||
/**
|
||||
* @brief Setting context type (Direct calls are not recommended)
|
||||
*
|
||||
* @param ctx Crypto context
|
||||
* @param type Types of settings
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_set_type(struct rt_hwcrypto_ctx *ctx, hwcrypto_type type)
|
||||
{
|
||||
if (ctx)
|
||||
{
|
||||
/* Is it the same category? */
|
||||
if ((ctx->type & HWCRYPTO_MAIN_TYPE_MASK) == (type & HWCRYPTO_MAIN_TYPE_MASK))
|
||||
{
|
||||
ctx->type = type;
|
||||
return RT_EOK;
|
||||
}
|
||||
/* Context is empty type */
|
||||
else if (ctx->type == HWCRYPTO_TYPE_NULL)
|
||||
{
|
||||
ctx->type = type;
|
||||
return RT_EOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
}
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset context type (Direct calls are not recommended)
|
||||
*
|
||||
* @param ctx Crypto context
|
||||
*
|
||||
*/
|
||||
void rt_hwcrypto_ctx_reset(struct rt_hwcrypto_ctx *ctx)
|
||||
{
|
||||
if (ctx && ctx->device->ops->reset)
|
||||
{
|
||||
ctx->device->ops->reset(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Init crypto context
|
||||
*
|
||||
* @param ctx The context to initialize
|
||||
* @param device Hardware crypto device
|
||||
* @param type Type of context
|
||||
* @param obj_size Size of context object
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_ctx_init(struct rt_hwcrypto_ctx *ctx, struct rt_hwcrypto_device *device, hwcrypto_type type)
|
||||
{
|
||||
rt_err_t err;
|
||||
|
||||
/* Setting context type */
|
||||
rt_hwcrypto_set_type(ctx, type);
|
||||
ctx->device = device;
|
||||
/* Create hardware context */
|
||||
err = ctx->device->ops->create(ctx);
|
||||
if (err != RT_EOK)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create crypto context
|
||||
*
|
||||
* @param device Hardware crypto device
|
||||
* @param type Type of context
|
||||
* @param obj_size Size of context object
|
||||
*
|
||||
* @return Crypto context
|
||||
*/
|
||||
struct rt_hwcrypto_ctx *rt_hwcrypto_ctx_create(struct rt_hwcrypto_device *device, hwcrypto_type type, rt_uint32_t obj_size)
|
||||
{
|
||||
struct rt_hwcrypto_ctx *ctx;
|
||||
rt_err_t err;
|
||||
|
||||
/* Parameter checking */
|
||||
if (device == RT_NULL || obj_size < sizeof(struct rt_hwcrypto_ctx))
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
ctx = rt_malloc(obj_size);
|
||||
if (ctx == RT_NULL)
|
||||
{
|
||||
return ctx;
|
||||
}
|
||||
rt_memset(ctx, 0, obj_size);
|
||||
/* Init context */
|
||||
err = rt_hwcrypto_ctx_init(ctx, device, type);
|
||||
if (err != RT_EOK)
|
||||
{
|
||||
rt_free(ctx);
|
||||
ctx = RT_NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroy crypto context
|
||||
*
|
||||
* @param device Crypto context
|
||||
*/
|
||||
void rt_hwcrypto_ctx_destroy(struct rt_hwcrypto_ctx *ctx)
|
||||
{
|
||||
if (ctx == RT_NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* Destroy hardware context */
|
||||
if (ctx->device->ops->destroy)
|
||||
{
|
||||
ctx->device->ops->destroy(ctx);
|
||||
}
|
||||
/* Free the resources */
|
||||
rt_free(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy crypto context
|
||||
*
|
||||
* @param des The destination context
|
||||
* @param src The context to be copy
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_ctx_cpy(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src)
|
||||
{
|
||||
if (des == RT_NULL || src == RT_NULL)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
/* The equipment is different or of different types and cannot be copied */
|
||||
if (des->device != src->device ||
|
||||
(des->type & HWCRYPTO_MAIN_TYPE_MASK) != (src->type & HWCRYPTO_MAIN_TYPE_MASK))
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
des->type = src->type;
|
||||
/* Calling Hardware Context Copy Function */
|
||||
return src->device->ops->copy(des, src);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the default hardware crypto device
|
||||
*
|
||||
* @return Hardware crypto device
|
||||
*
|
||||
*/
|
||||
struct rt_hwcrypto_device *rt_hwcrypto_dev_default(void)
|
||||
{
|
||||
static struct rt_hwcrypto_device *hwcrypto_dev;
|
||||
|
||||
/* If there is a default device, return the device */
|
||||
if (hwcrypto_dev)
|
||||
{
|
||||
return hwcrypto_dev;
|
||||
}
|
||||
/* Find by default device name */
|
||||
hwcrypto_dev = (struct rt_hwcrypto_device *)rt_device_find(RT_HWCRYPTO_DEFAULT_NAME);
|
||||
return hwcrypto_dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the unique ID of the device
|
||||
*
|
||||
* @param device Device object
|
||||
*
|
||||
* @return Device unique ID
|
||||
*/
|
||||
rt_uint64_t rt_hwcrypto_id(struct rt_hwcrypto_device *device)
|
||||
{
|
||||
if (device)
|
||||
{
|
||||
return device->id;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops hwcrypto_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Register hardware crypto device
|
||||
*
|
||||
* @param device Hardware crypto device
|
||||
* @param name Name of device
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_register(struct rt_hwcrypto_device *device, const char *name)
|
||||
{
|
||||
rt_err_t err;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(name != RT_NULL);
|
||||
RT_ASSERT(device->ops != RT_NULL);
|
||||
RT_ASSERT(device->ops->create != RT_NULL);
|
||||
RT_ASSERT(device->ops->destroy != RT_NULL);
|
||||
RT_ASSERT(device->ops->copy != RT_NULL);
|
||||
RT_ASSERT(device->ops->reset != RT_NULL);
|
||||
|
||||
rt_memset(&device->parent, 0, sizeof(struct rt_device));
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
device->parent.ops = &hwcrypto_ops;
|
||||
#else
|
||||
device->parent.init = RT_NULL;
|
||||
device->parent.open = RT_NULL;
|
||||
device->parent.close = RT_NULL;
|
||||
device->parent.read = RT_NULL;
|
||||
device->parent.write = RT_NULL;
|
||||
device->parent.control = RT_NULL;
|
||||
#endif
|
||||
|
||||
device->parent.user_data = RT_NULL;
|
||||
device->parent.type = RT_Device_Class_Miscellaneous;
|
||||
|
||||
/* Register device */
|
||||
err = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-04-23 tyx the first version
|
||||
*/
|
||||
|
||||
#ifndef __HWCRYPTO_H__
|
||||
#define __HWCRYPTO_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifndef RT_HWCRYPTO_DEFAULT_NAME
|
||||
#define RT_HWCRYPTO_DEFAULT_NAME ("hwcryto")
|
||||
#endif
|
||||
|
||||
#define HWCRYPTO_MAIN_TYPE_MASK (0xffffUL << 16)
|
||||
#define HWCRYPTO_SUB_TYPE_MASK (0xffUL << 8)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
HWCRYPTO_TYPE_NULL = 0x00000000,
|
||||
|
||||
/* Main Type */
|
||||
/* symmetric Type */
|
||||
HWCRYPTO_TYPE_HEAD = __LINE__,
|
||||
HWCRYPTO_TYPE_AES = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< AES */
|
||||
HWCRYPTO_TYPE_DES = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< DES */
|
||||
HWCRYPTO_TYPE_3DES = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< 3DES */
|
||||
HWCRYPTO_TYPE_RC4 = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< RC4 */
|
||||
HWCRYPTO_TYPE_GCM = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< GCM */
|
||||
/* HASH Type */
|
||||
HWCRYPTO_TYPE_MD5 = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< MD5 */
|
||||
HWCRYPTO_TYPE_SHA1 = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< SHA1 */
|
||||
HWCRYPTO_TYPE_SHA2 = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< SHA2 */
|
||||
/* Other Type */
|
||||
HWCRYPTO_TYPE_RNG = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< RNG */
|
||||
HWCRYPTO_TYPE_CRC = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< CRC */
|
||||
HWCRYPTO_TYPE_BIGNUM = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< BIGNUM */
|
||||
|
||||
/* AES Subtype */
|
||||
HWCRYPTO_TYPE_AES_ECB = HWCRYPTO_TYPE_AES | (0x01 << 8),
|
||||
HWCRYPTO_TYPE_AES_CBC = HWCRYPTO_TYPE_AES | (0x02 << 8),
|
||||
HWCRYPTO_TYPE_AES_CFB = HWCRYPTO_TYPE_AES | (0x03 << 8),
|
||||
HWCRYPTO_TYPE_AES_CTR = HWCRYPTO_TYPE_AES | (0x04 << 8),
|
||||
HWCRYPTO_TYPE_AES_OFB = HWCRYPTO_TYPE_AES | (0x05 << 8),
|
||||
|
||||
/* DES Subtype */
|
||||
HWCRYPTO_TYPE_DES_ECB = HWCRYPTO_TYPE_DES | (0x01 << 8),
|
||||
HWCRYPTO_TYPE_DES_CBC = HWCRYPTO_TYPE_DES | (0x02 << 8),
|
||||
|
||||
/* 3DES Subtype */
|
||||
HWCRYPTO_TYPE_3DES_ECB = HWCRYPTO_TYPE_3DES | (0x01 << 8),
|
||||
HWCRYPTO_TYPE_3DES_CBC = HWCRYPTO_TYPE_3DES | (0x02 << 8),
|
||||
|
||||
/* SHA2 Subtype */
|
||||
HWCRYPTO_TYPE_SHA224 = HWCRYPTO_TYPE_SHA2 | (0x01 << 8),
|
||||
HWCRYPTO_TYPE_SHA256 = HWCRYPTO_TYPE_SHA2 | (0x02 << 8),
|
||||
HWCRYPTO_TYPE_SHA384 = HWCRYPTO_TYPE_SHA2 | (0x03 << 8),
|
||||
HWCRYPTO_TYPE_SHA512 = HWCRYPTO_TYPE_SHA2 | (0x04 << 8),
|
||||
} hwcrypto_type;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
HWCRYPTO_MODE_ENCRYPT = 0x1, /**< Encryption operations */
|
||||
HWCRYPTO_MODE_DECRYPT = 0x2, /**< Decryption operations */
|
||||
HWCRYPTO_MODE_UNKNOWN = 0x7fffffff, /**< Unknown */
|
||||
} hwcrypto_mode;
|
||||
|
||||
struct rt_hwcrypto_ctx;
|
||||
|
||||
struct rt_hwcrypto_ops
|
||||
{
|
||||
rt_err_t (*create)(struct rt_hwcrypto_ctx *ctx); /**< Creating hardware context */
|
||||
void (*destroy)(struct rt_hwcrypto_ctx *ctx); /**< Delete hardware context */
|
||||
rt_err_t (*copy)(struct rt_hwcrypto_ctx *des,
|
||||
const struct rt_hwcrypto_ctx *src); /**< Cpoy hardware context */
|
||||
void (*reset)(struct rt_hwcrypto_ctx *ctx); /**< Reset hardware context */
|
||||
};
|
||||
|
||||
struct rt_hwcrypto_device
|
||||
{
|
||||
struct rt_device parent; /**< Inherited from the standard device */
|
||||
const struct rt_hwcrypto_ops *ops; /**< Hardware crypto ops */
|
||||
rt_uint64_t id; /**< Unique id */
|
||||
void *user_data; /**< Device user data */
|
||||
};
|
||||
|
||||
struct rt_hwcrypto_ctx
|
||||
{
|
||||
struct rt_hwcrypto_device *device; /**< Binding device */
|
||||
hwcrypto_type type; /**< Encryption and decryption types */
|
||||
void *contex; /**< Hardware context */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Setting context type (Direct calls are not recommended)
|
||||
*
|
||||
* @param ctx Crypto context
|
||||
* @param type Types of settings
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_set_type(struct rt_hwcrypto_ctx *ctx, hwcrypto_type type);
|
||||
|
||||
/**
|
||||
* @brief Reset context type (Direct calls are not recommended)
|
||||
*
|
||||
* @param ctx Crypto context
|
||||
*/
|
||||
void rt_hwcrypto_ctx_reset(struct rt_hwcrypto_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Init crypto context (Direct calls are not recommended)
|
||||
*
|
||||
* @param ctx The context to initialize
|
||||
* @param device Hardware crypto device
|
||||
* @param type Type of context
|
||||
* @param obj_size Size of context object
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_ctx_init(struct rt_hwcrypto_ctx *ctx,
|
||||
struct rt_hwcrypto_device *device, hwcrypto_type type);
|
||||
|
||||
/**
|
||||
* @brief Create crypto context (Direct calls are not recommended)
|
||||
*
|
||||
* @param device Hardware crypto device
|
||||
* @param type Type of context
|
||||
* @param obj_size Size of context object
|
||||
*
|
||||
* @return Crypto context
|
||||
*/
|
||||
struct rt_hwcrypto_ctx *rt_hwcrypto_ctx_create(struct rt_hwcrypto_device *device,
|
||||
hwcrypto_type type, rt_uint32_t obj_size);
|
||||
|
||||
/**
|
||||
* @brief Destroy crypto context (Direct calls are not recommended)
|
||||
*
|
||||
* @param device Crypto context
|
||||
*/
|
||||
void rt_hwcrypto_ctx_destroy(struct rt_hwcrypto_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Copy crypto context (Direct calls are not recommended)
|
||||
*
|
||||
* @param des The destination context
|
||||
* @param src The context to be copy
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_ctx_cpy(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src);
|
||||
|
||||
/**
|
||||
* @brief Register hardware crypto device
|
||||
*
|
||||
* @param device Hardware crypto device
|
||||
* @param name Name of device
|
||||
*
|
||||
* @return RT_EOK on success.
|
||||
*/
|
||||
rt_err_t rt_hwcrypto_register(struct rt_hwcrypto_device *device, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Get the default hardware crypto device
|
||||
*
|
||||
* @return Hardware crypto device
|
||||
*
|
||||
*/
|
||||
struct rt_hwcrypto_device *rt_hwcrypto_dev_default(void);
|
||||
|
||||
/**
|
||||
* @brief Get the unique ID of the device
|
||||
*
|
||||
* @param device Device object
|
||||
*
|
||||
* @return Device unique ID
|
||||
*/
|
||||
rt_uint64_t rt_hwcrypto_id(struct rt_hwcrypto_device *device);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,97 @@
|
||||
# 定时器设备
|
||||
|
||||
## 功能
|
||||
|
||||
* 时间测量
|
||||
* 周期或单次执行回调函数
|
||||
|
||||
## 编译
|
||||
|
||||
1. 在rtconfig.h添加 `#define RT_USING_HWTIMER`
|
||||
|
||||
## 使用流程
|
||||
|
||||
1. 以读写方式打开设备
|
||||
2. 设置超时回调函数(如果需要)
|
||||
3. 根据需要设置定时模式(单次/周期)
|
||||
4. 设置计数频率(可选)
|
||||
5. 写入超时值,定时器随即启动
|
||||
6. 停止定时器(可选)
|
||||
7. 关闭设备(如果需要)
|
||||
|
||||
应用参考 [hwtimer_test] (/examples/test/hwtimer\_test.c)
|
||||
|
||||
## 驱动编写指南
|
||||
|
||||
### 操作接口
|
||||
|
||||
```
|
||||
struct rt_hwtimer_ops
|
||||
{
|
||||
void (*init)(struct rt_hwtimer_device *timer, rt_uint32_t state);
|
||||
rt_err_t (*start)(struct rt_hwtimer_device *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode);
|
||||
void (*stop)(struct rt_hwtimer_device *timer);
|
||||
rt_uint32_t (*count_get)(struct rt_hwtimer_device *timer);
|
||||
rt_err_t (*control)(struct rt_hwtimer_device *timer, rt_uint32_t cmd, void *args);
|
||||
};
|
||||
```
|
||||
|
||||
* init - state <1 打开设备 0 关闭设备>
|
||||
* start - cnt <超时值> - mode <单次/周期>
|
||||
* stop - <停止计数>
|
||||
* count_get - <读取计数器值>
|
||||
* control - <设置计数频率 >
|
||||
|
||||
### 定时器特征信息
|
||||
|
||||
```
|
||||
struct rt_hwtimer_info
|
||||
{
|
||||
rt_int32_t maxfreq;
|
||||
rt_int32_t minfreq;
|
||||
rt_uint32_t maxcnt;
|
||||
rt_uint8_t cntmode;
|
||||
};
|
||||
```
|
||||
|
||||
* maxfreq <设备支持的最大计数频率>
|
||||
* minfreq <设备支持的最小计数频率>
|
||||
* maxcnt <计数器最大计数值>
|
||||
* cntmode <递增计数/递减计数>
|
||||
|
||||
### 注册设备
|
||||
|
||||
```
|
||||
static rt_hwtimer_t _timer0;
|
||||
int stm32_hwtimer_init(void)
|
||||
{
|
||||
_timer0.info = &_info;
|
||||
_timer0.ops = &_ops;
|
||||
|
||||
rt_device_hwtimer_register(&_timer0, "timer0", TIM2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 定时器中断
|
||||
|
||||
```
|
||||
void timer_irq_handler(void)
|
||||
{
|
||||
//其它操作
|
||||
|
||||
rt_device_hwtimer_isr(&_timer0);
|
||||
}
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
**可能出现定时误差**
|
||||
|
||||
误差原因:
|
||||
|
||||
假设计数器最大值0xFFFF,计数频率1Mhz,定时时间1秒又1微秒。
|
||||
|
||||
由于定时器一次最多只能计时到65535us,对于1000001us的定时要求。
|
||||
可以50000us定时20次完成,此时将会出现计算误差1us。
|
||||
@@ -0,0 +1,8 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd + '/../include']
|
||||
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_HWTIMER'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-08-31 heyuanjie87 first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <rthw.h>
|
||||
|
||||
rt_inline rt_uint32_t timeout_calc(rt_hwtimer_t *timer, rt_hwtimerval_t *tv)
|
||||
{
|
||||
float overflow;
|
||||
float timeout;
|
||||
rt_uint32_t counter;
|
||||
int i, index = 0;
|
||||
float tv_sec;
|
||||
float devi_min = 1;
|
||||
float devi;
|
||||
|
||||
/* changed to second */
|
||||
overflow = timer->info->maxcnt/(float)timer->freq;
|
||||
tv_sec = tv->sec + tv->usec/(float)1000000;
|
||||
|
||||
if (tv_sec < (1/(float)timer->freq))
|
||||
{
|
||||
/* little timeout */
|
||||
i = 0;
|
||||
timeout = 1/(float)timer->freq;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 1; i > 0; i ++)
|
||||
{
|
||||
timeout = tv_sec/i;
|
||||
|
||||
if (timeout <= overflow)
|
||||
{
|
||||
counter = timeout*timer->freq;
|
||||
devi = tv_sec - (counter/(float)timer->freq)*i;
|
||||
/* Minimum calculation error */
|
||||
if (devi > devi_min)
|
||||
{
|
||||
i = index;
|
||||
timeout = tv_sec/i;
|
||||
break;
|
||||
}
|
||||
else if (devi == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (devi < devi_min)
|
||||
{
|
||||
devi_min = devi;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timer->cycles = i;
|
||||
timer->reload = i;
|
||||
timer->period_sec = timeout;
|
||||
counter = timeout*timer->freq;
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
static rt_err_t rt_hwtimer_init(struct rt_device *dev)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_hwtimer_t *timer;
|
||||
|
||||
timer = (rt_hwtimer_t *)dev;
|
||||
/* try to change to 1MHz */
|
||||
if ((1000000 <= timer->info->maxfreq) && (1000000 >= timer->info->minfreq))
|
||||
{
|
||||
timer->freq = 1000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
timer->freq = timer->info->minfreq;
|
||||
}
|
||||
timer->mode = HWTIMER_MODE_ONESHOT;
|
||||
timer->cycles = 0;
|
||||
timer->overflow = 0;
|
||||
|
||||
if (timer->ops->init)
|
||||
{
|
||||
timer->ops->init(timer, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_ENOSYS;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t rt_hwtimer_open(struct rt_device *dev, rt_uint16_t oflag)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_hwtimer_t *timer;
|
||||
|
||||
timer = (rt_hwtimer_t *)dev;
|
||||
if (timer->ops->control != RT_NULL)
|
||||
{
|
||||
timer->ops->control(timer, HWTIMER_CTRL_FREQ_SET, &timer->freq);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_ENOSYS;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t rt_hwtimer_close(struct rt_device *dev)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_hwtimer_t *timer;
|
||||
|
||||
timer = (rt_hwtimer_t*)dev;
|
||||
if (timer->ops->init != RT_NULL)
|
||||
{
|
||||
timer->ops->init(timer, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_ENOSYS;
|
||||
}
|
||||
|
||||
dev->flag &= ~RT_DEVICE_FLAG_ACTIVATED;
|
||||
dev->rx_indicate = RT_NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_size_t rt_hwtimer_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size)
|
||||
{
|
||||
rt_hwtimer_t *timer;
|
||||
rt_hwtimerval_t tv;
|
||||
rt_uint32_t cnt;
|
||||
rt_base_t level;
|
||||
rt_int32_t overflow;
|
||||
float t;
|
||||
|
||||
timer = (rt_hwtimer_t *)dev;
|
||||
if (timer->ops->count_get == RT_NULL)
|
||||
return 0;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
cnt = timer->ops->count_get(timer);
|
||||
overflow = timer->overflow;
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
if (timer->info->cntmode == HWTIMER_CNTMODE_DW)
|
||||
{
|
||||
cnt = (timer->freq * timer->period_sec) - cnt;
|
||||
}
|
||||
|
||||
t = overflow * timer->period_sec + cnt/(float)timer->freq;
|
||||
tv.sec = t;
|
||||
tv.usec = (t - tv.sec) * 1000000;
|
||||
size = size > sizeof(tv)? sizeof(tv) : size;
|
||||
rt_memcpy(buffer, &tv, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static rt_size_t rt_hwtimer_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size)
|
||||
{
|
||||
rt_uint32_t t;
|
||||
rt_hwtimer_mode_t opm = HWTIMER_MODE_PERIOD;
|
||||
rt_hwtimer_t *timer;
|
||||
|
||||
timer = (rt_hwtimer_t *)dev;
|
||||
if ((timer->ops->start == RT_NULL) || (timer->ops->stop == RT_NULL))
|
||||
return 0;
|
||||
|
||||
if (size != sizeof(rt_hwtimerval_t))
|
||||
return 0;
|
||||
|
||||
timer->ops->stop(timer);
|
||||
timer->overflow = 0;
|
||||
|
||||
t = timeout_calc(timer, (rt_hwtimerval_t*)buffer);
|
||||
if ((timer->cycles <= 1) && (timer->mode == HWTIMER_MODE_ONESHOT))
|
||||
{
|
||||
opm = HWTIMER_MODE_ONESHOT;
|
||||
}
|
||||
|
||||
if (timer->ops->start(timer, t, opm) != RT_EOK)
|
||||
size = 0;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static rt_err_t rt_hwtimer_control(struct rt_device *dev, int cmd, void *args)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_hwtimer_t *timer;
|
||||
|
||||
timer = (rt_hwtimer_t *)dev;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case HWTIMER_CTRL_STOP:
|
||||
{
|
||||
if (timer->ops->stop != RT_NULL)
|
||||
{
|
||||
timer->ops->stop(timer);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_ENOSYS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HWTIMER_CTRL_FREQ_SET:
|
||||
{
|
||||
rt_uint32_t *f;
|
||||
|
||||
if (args == RT_NULL)
|
||||
{
|
||||
result = -RT_EEMPTY;
|
||||
break;
|
||||
}
|
||||
|
||||
f = (rt_uint32_t*)args;
|
||||
if ((*f > timer->info->maxfreq) || (*f < timer->info->minfreq))
|
||||
{
|
||||
result = -RT_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (timer->ops->control != RT_NULL)
|
||||
{
|
||||
result = timer->ops->control(timer, cmd, args);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
timer->freq = *f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_ENOSYS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HWTIMER_CTRL_INFO_GET:
|
||||
{
|
||||
if (args == RT_NULL)
|
||||
{
|
||||
result = -RT_EEMPTY;
|
||||
break;
|
||||
}
|
||||
|
||||
*((struct rt_hwtimer_info*)args) = *timer->info;
|
||||
}
|
||||
break;
|
||||
case HWTIMER_CTRL_MODE_SET:
|
||||
{
|
||||
rt_hwtimer_mode_t *m;
|
||||
|
||||
if (args == RT_NULL)
|
||||
{
|
||||
result = -RT_EEMPTY;
|
||||
break;
|
||||
}
|
||||
|
||||
m = (rt_hwtimer_mode_t*)args;
|
||||
|
||||
if ((*m != HWTIMER_MODE_ONESHOT) && (*m != HWTIMER_MODE_PERIOD))
|
||||
{
|
||||
result = -RT_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
timer->mode = *m;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
result = -RT_ENOSYS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void rt_device_hwtimer_isr(rt_hwtimer_t *timer)
|
||||
{
|
||||
RT_ASSERT(timer != RT_NULL);
|
||||
|
||||
timer->overflow ++;
|
||||
|
||||
if (timer->cycles != 0)
|
||||
{
|
||||
timer->cycles --;
|
||||
}
|
||||
|
||||
if (timer->cycles == 0)
|
||||
{
|
||||
timer->cycles = timer->reload;
|
||||
|
||||
if (timer->mode == HWTIMER_MODE_ONESHOT)
|
||||
{
|
||||
if (timer->ops->stop != RT_NULL)
|
||||
{
|
||||
timer->ops->stop(timer);
|
||||
}
|
||||
}
|
||||
|
||||
if (timer->parent.rx_indicate != RT_NULL)
|
||||
{
|
||||
timer->parent.rx_indicate(&timer->parent, sizeof(struct rt_hwtimerval));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops hwtimer_ops =
|
||||
{
|
||||
rt_hwtimer_init,
|
||||
rt_hwtimer_open,
|
||||
rt_hwtimer_close,
|
||||
rt_hwtimer_read,
|
||||
rt_hwtimer_write,
|
||||
rt_hwtimer_control
|
||||
};
|
||||
#endif
|
||||
|
||||
rt_err_t rt_device_hwtimer_register(rt_hwtimer_t *timer, const char *name, void *user_data)
|
||||
{
|
||||
struct rt_device *device;
|
||||
|
||||
RT_ASSERT(timer != RT_NULL);
|
||||
RT_ASSERT(timer->ops != RT_NULL);
|
||||
RT_ASSERT(timer->info != RT_NULL);
|
||||
|
||||
device = &(timer->parent);
|
||||
|
||||
device->type = RT_Device_Class_Timer;
|
||||
device->rx_indicate = RT_NULL;
|
||||
device->tx_complete = RT_NULL;
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
device->ops = &hwtimer_ops;
|
||||
#else
|
||||
device->init = rt_hwtimer_init;
|
||||
device->open = rt_hwtimer_open;
|
||||
device->close = rt_hwtimer_close;
|
||||
device->read = rt_hwtimer_read;
|
||||
device->write = rt_hwtimer_write;
|
||||
device->control = rt_hwtimer_control;
|
||||
#endif
|
||||
device->user_data = user_data;
|
||||
|
||||
return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
Import('RTT_ROOT')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Split("""
|
||||
i2c_core.c
|
||||
i2c_dev.c
|
||||
""")
|
||||
|
||||
if GetDepend('RT_USING_I2C_BITOPS'):
|
||||
src = src + ['i2c-bit-ops.c']
|
||||
|
||||
# The set of source files associated with this SConscript file.
|
||||
path = [cwd + '/../include']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_I2C'], CPPPATH = path)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,453 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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;
|
||||
rt_thread_delay((ops->timeout + 1) >> 1);
|
||||
}
|
||||
#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_size_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_size_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_size_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 i, ret;
|
||||
rt_uint16_t ignore_nack;
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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);
|
||||
|
||||
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_size_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,
|
||||
struct rt_i2c_msg msgs[],
|
||||
rt_uint32_t num)
|
||||
{
|
||||
rt_size_t ret;
|
||||
|
||||
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
|
||||
|
||||
rt_mutex_take(&bus->lock, RT_WAITING_FOREVER);
|
||||
ret = bus->ops->master_xfer(bus, msgs, num);
|
||||
rt_mutex_release(&bus->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("I2C bus operation not supported");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
rt_err_t rt_i2c_control(struct rt_i2c_bus_device *bus,
|
||||
rt_uint32_t cmd,
|
||||
rt_uint32_t arg)
|
||||
{
|
||||
rt_err_t ret;
|
||||
|
||||
if(bus->ops->i2c_bus_control)
|
||||
{
|
||||
ret = bus->ops->i2c_bus_control(bus, cmd, arg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("I2C bus operation not supported");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
rt_size_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_err_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 > 0) ? count : ret;
|
||||
}
|
||||
|
||||
rt_size_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_err_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 > 0) ? count : ret;
|
||||
}
|
||||
|
||||
int rt_i2c_core_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(rt_i2c_core_init);
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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_size_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_size_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_uint32_t bus_clock;
|
||||
|
||||
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;
|
||||
case RT_I2C_DEV_CTRL_CLK:
|
||||
bus_clock = *(rt_uint32_t *)args;
|
||||
ret = rt_i2c_control(bus, cmd, bus_clock);
|
||||
if (ret < 0)
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-05-07 aozima the first version
|
||||
* 2018-11-16 Ernest Chen add finsh command and update adc function
|
||||
*/
|
||||
|
||||
#ifndef __ADC_H__
|
||||
#define __ADC_H__
|
||||
#include <rtthread.h>
|
||||
|
||||
struct rt_adc_device;
|
||||
struct rt_adc_ops
|
||||
{
|
||||
rt_err_t (*enabled)(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled);
|
||||
rt_err_t (*convert)(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value);
|
||||
};
|
||||
|
||||
struct rt_adc_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
const struct rt_adc_ops *ops;
|
||||
};
|
||||
typedef struct rt_adc_device *rt_adc_device_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RT_ADC_CMD_ENABLE,
|
||||
RT_ADC_CMD_DISABLE,
|
||||
} rt_adc_cmd_t;
|
||||
|
||||
rt_err_t rt_hw_adc_register(rt_adc_device_t adc,const char *name, const struct rt_adc_ops *ops, const void *user_data);
|
||||
|
||||
rt_uint32_t rt_adc_read(rt_adc_device_t dev, rt_uint32_t channel);
|
||||
rt_err_t rt_adc_enable(rt_adc_device_t dev, rt_uint32_t channel);
|
||||
rt_err_t rt_adc_disable(rt_adc_device_t dev, rt_uint32_t channel);
|
||||
|
||||
#endif /* __ADC_H__ */
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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 onece */
|
||||
#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 */
|
||||
|
||||
/* 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);
|
||||
|
||||
/* used for low level RTC driver */
|
||||
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 */
|
||||
};
|
||||
|
||||
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__ */
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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) (0x10 + 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_size_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__ */
|
||||
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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.
|
||||
*/
|
||||
|
||||
#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 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_LISEN 1
|
||||
#define RT_CAN_MODE_LOOPBACK 2
|
||||
#define RT_CAN_MODE_LOOPBACKANLISEN 3
|
||||
|
||||
#define RT_CAN_MODE_PRIV 0x01
|
||||
#define RT_CAN_MODE_NOPRIV 0x00
|
||||
|
||||
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;
|
||||
#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, (ind), (args)}
|
||||
#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, }
|
||||
#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 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
|
||||
};
|
||||
|
||||
#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_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 : 8;
|
||||
rt_uint32_t reserved : 8;
|
||||
rt_uint8_t data[8];
|
||||
};
|
||||
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);
|
||||
int (*sendmsg)(struct rt_can_device *can, const void *buf, rt_uint32_t boxno);
|
||||
int (*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*/
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2017-12-23 Bernard first version
|
||||
*/
|
||||
|
||||
#ifndef CPUTIME_H__
|
||||
#define CPUTIME_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct rt_clock_cputime_ops
|
||||
{
|
||||
float (*cputime_getres) (void);
|
||||
uint64_t (*cputime_gettime)(void);
|
||||
};
|
||||
|
||||
float clock_cpu_getres(void);
|
||||
uint64_t clock_cpu_gettime(void);
|
||||
|
||||
uint32_t clock_cpu_microsecond(uint32_t cpu_tick);
|
||||
uint32_t clock_cpu_millisecond(uint32_t cpu_tick);
|
||||
|
||||
int clock_cpu_setops(const struct rt_clock_cputime_ops *ops);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-05-17 tyx the first version
|
||||
*/
|
||||
|
||||
#ifndef __CRYPTO_H__
|
||||
#define __CRYPTO_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <hwcrypto.h>
|
||||
#include <hw_symmetric.h>
|
||||
#include <hw_rng.h>
|
||||
#include <hw_hash.h>
|
||||
#include <hw_crc.h>
|
||||
#include <hw_gcm.h>
|
||||
#include <hw_bignum.h>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2020-06-19 thread-liu the first version
|
||||
*/
|
||||
|
||||
#ifndef __DAC_H__
|
||||
#define __DAC_H__
|
||||
#include <rtthread.h>
|
||||
|
||||
struct rt_dac_device;
|
||||
struct rt_dac_ops
|
||||
{
|
||||
rt_err_t (*disabled)(struct rt_dac_device *device, rt_uint32_t channel);
|
||||
rt_err_t (*enabled)(struct rt_dac_device *device, rt_uint32_t channel);
|
||||
rt_err_t (*convert)(struct rt_dac_device *device, rt_uint32_t channel, rt_uint32_t *value);
|
||||
};
|
||||
|
||||
struct rt_dac_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
const struct rt_dac_ops *ops;
|
||||
};
|
||||
typedef struct rt_dac_device *rt_dac_device_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RT_DAC_CMD_ENABLE,
|
||||
RT_DAC_CMD_DISABLE,
|
||||
} rt_dac_cmd_t;
|
||||
|
||||
rt_err_t rt_hw_dac_register(rt_dac_device_t dac,const char *name, const struct rt_dac_ops *ops, const void *user_data);
|
||||
|
||||
rt_uint32_t rt_dac_write(rt_dac_device_t dev, rt_uint32_t channel, rt_uint32_t value);
|
||||
rt_err_t rt_dac_enable(rt_dac_device_t dev, rt_uint32_t channel);
|
||||
rt_err_t rt_dac_disable(rt_dac_device_t dev, rt_uint32_t channel);
|
||||
|
||||
#endif /* __dac_H__ */
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
#ifndef __HWTIMER_H__
|
||||
#define __HWTIMER_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Timer Control Command */
|
||||
typedef enum
|
||||
{
|
||||
HWTIMER_CTRL_FREQ_SET = 0x01, /* set the count frequency */
|
||||
HWTIMER_CTRL_STOP, /* stop timer */
|
||||
HWTIMER_CTRL_INFO_GET, /* get a timer feature information */
|
||||
HWTIMER_CTRL_MODE_SET /* Setting the timing mode(oneshot/period) */
|
||||
} rt_hwtimer_ctrl_t;
|
||||
|
||||
/* Timing Mode */
|
||||
typedef enum
|
||||
{
|
||||
HWTIMER_MODE_ONESHOT = 0x01,
|
||||
HWTIMER_MODE_PERIOD
|
||||
} rt_hwtimer_mode_t;
|
||||
|
||||
/* Time Value */
|
||||
typedef struct rt_hwtimerval
|
||||
{
|
||||
rt_int32_t sec; /* second */
|
||||
rt_int32_t usec; /* microsecond */
|
||||
} rt_hwtimerval_t;
|
||||
|
||||
#define HWTIMER_CNTMODE_UP 0x01 /* increment count mode */
|
||||
#define HWTIMER_CNTMODE_DW 0x02 /* decreasing count mode */
|
||||
|
||||
struct rt_hwtimer_device;
|
||||
|
||||
struct rt_hwtimer_ops
|
||||
{
|
||||
void (*init)(struct rt_hwtimer_device *timer, rt_uint32_t state);
|
||||
rt_err_t (*start)(struct rt_hwtimer_device *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode);
|
||||
void (*stop)(struct rt_hwtimer_device *timer);
|
||||
rt_uint32_t (*count_get)(struct rt_hwtimer_device *timer);
|
||||
rt_err_t (*control)(struct rt_hwtimer_device *timer, rt_uint32_t cmd, void *args);
|
||||
};
|
||||
|
||||
/* Timer Feature Information */
|
||||
struct rt_hwtimer_info
|
||||
{
|
||||
rt_int32_t maxfreq; /* the maximum count frequency timer support */
|
||||
rt_int32_t minfreq; /* the minimum count frequency timer support */
|
||||
rt_uint32_t maxcnt; /* counter maximum value */
|
||||
rt_uint8_t cntmode; /* count mode (inc/dec) */
|
||||
};
|
||||
|
||||
typedef struct rt_hwtimer_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
const struct rt_hwtimer_ops *ops;
|
||||
const struct rt_hwtimer_info *info;
|
||||
|
||||
rt_int32_t freq; /* counting frequency set by the user */
|
||||
rt_int32_t overflow; /* timer overflows */
|
||||
float period_sec;
|
||||
rt_int32_t cycles; /* how many times will generate a timeout event after overflow */
|
||||
rt_int32_t reload; /* reload cycles(using in period mode) */
|
||||
rt_hwtimer_mode_t mode; /* timing mode(oneshot/period) */
|
||||
} rt_hwtimer_t;
|
||||
|
||||
rt_err_t rt_device_hwtimer_register(rt_hwtimer_t *timer, const char *name, void *user_data);
|
||||
void rt_device_hwtimer_isr(rt_hwtimer_t *timer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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 */
|
||||
};
|
||||
|
||||
rt_err_t rt_i2c_bit_add_bus(struct rt_i2c_bus_device *bus,
|
||||
const char *bus_name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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_size_t (*master_xfer)(struct rt_i2c_bus_device *bus,
|
||||
struct rt_i2c_msg msgs[],
|
||||
rt_uint32_t num);
|
||||
rt_size_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,
|
||||
rt_uint32_t,
|
||||
rt_uint32_t);
|
||||
};
|
||||
|
||||
/*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
|
||||
{
|
||||
struct rt_i2c_bus_device *bus;
|
||||
rt_uint16_t client_addr;
|
||||
};
|
||||
|
||||
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_size_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,
|
||||
rt_uint32_t cmd,
|
||||
rt_uint32_t arg);
|
||||
rt_size_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_size_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);
|
||||
}
|
||||
|
||||
int rt_i2c_core_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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 0x20
|
||||
#define RT_I2C_DEV_CTRL_TIMEOUT 0x22
|
||||
#define RT_I2C_DEV_CTRL_RW 0x23
|
||||
#define RT_I2C_DEV_CTRL_CLK 0x24
|
||||
|
||||
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
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-10-11 zhangsz the first version
|
||||
*/
|
||||
|
||||
#ifndef __LPTIMER_H__
|
||||
#define __LPTIMER_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
struct rt_lptimer
|
||||
{
|
||||
struct rt_timer timer;
|
||||
rt_list_t list;
|
||||
};
|
||||
typedef struct rt_lptimer *rt_lptimer_t;
|
||||
|
||||
void rt_lptimer_init(rt_lptimer_t timer,
|
||||
const char *name,
|
||||
void (*timeout)(void *parameter),
|
||||
void *parameter,
|
||||
rt_tick_t time,
|
||||
rt_uint8_t flag);
|
||||
|
||||
rt_err_t rt_lptimer_detach(rt_lptimer_t timer);
|
||||
rt_err_t rt_lptimer_start(rt_lptimer_t timer);
|
||||
rt_err_t rt_lptimer_stop(rt_lptimer_t timer);
|
||||
|
||||
rt_err_t rt_lptimer_control(rt_lptimer_t timer, int cmd, void *arg);
|
||||
|
||||
rt_tick_t rt_lptimer_next_timeout_tick(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-06-15 hichard first version
|
||||
*/
|
||||
|
||||
#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_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_TIMING_BC 0 /* Backwards compatility */
|
||||
#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
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-07-25 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __MMCSD_CARD_H__
|
||||
#define __MMCSD_CARD_H__
|
||||
|
||||
#include <drivers/mmcsd_host.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SD_SCR_BUS_WIDTH_1 (1 << 0)
|
||||
#define SD_SCR_BUS_WIDTH_4 (1 << 2)
|
||||
|
||||
struct rt_mmcsd_cid {
|
||||
rt_uint8_t mid; /* ManufacturerID */
|
||||
rt_uint8_t prv; /* Product Revision */
|
||||
rt_uint16_t oid; /* OEM/Application ID */
|
||||
rt_uint32_t psn; /* Product Serial Number */
|
||||
rt_uint8_t pnm[5]; /* Product Name */
|
||||
rt_uint8_t reserved1;/* reserved */
|
||||
rt_uint16_t mdt; /* Manufacturing Date */
|
||||
rt_uint8_t crc; /* CID CRC */
|
||||
rt_uint8_t reserved2;/* not used, always 1 */
|
||||
};
|
||||
|
||||
struct rt_mmcsd_csd {
|
||||
rt_uint8_t csd_structure; /* CSD register version */
|
||||
rt_uint8_t taac;
|
||||
rt_uint8_t nsac;
|
||||
rt_uint8_t tran_speed; /* max data transfer rate */
|
||||
rt_uint16_t card_cmd_class; /* card command classes */
|
||||
rt_uint8_t rd_blk_len; /* max read data block length */
|
||||
rt_uint8_t rd_blk_part;
|
||||
rt_uint8_t wr_blk_misalign;
|
||||
rt_uint8_t rd_blk_misalign;
|
||||
rt_uint8_t dsr_imp; /* DSR implemented */
|
||||
rt_uint8_t c_size_mult; /* CSD 1.0 , device size multiplier */
|
||||
rt_uint32_t c_size; /* device size */
|
||||
rt_uint8_t r2w_factor;
|
||||
rt_uint8_t wr_blk_len; /* max wtire data block length */
|
||||
rt_uint8_t wr_blk_partial;
|
||||
rt_uint8_t csd_crc;
|
||||
|
||||
};
|
||||
|
||||
struct rt_sd_scr {
|
||||
rt_uint8_t sd_version;
|
||||
rt_uint8_t sd_bus_widths;
|
||||
};
|
||||
|
||||
struct rt_sdio_cccr {
|
||||
rt_uint8_t sdio_version;
|
||||
rt_uint8_t sd_version;
|
||||
rt_uint8_t direct_cmd:1, /* Card Supports Direct Commands during data transfer
|
||||
only SD mode, not used for SPI mode */
|
||||
multi_block:1, /* Card Supports Multi-Block */
|
||||
read_wait:1, /* Card Supports Read Wait
|
||||
only SD mode, not used for SPI mode */
|
||||
suspend_resume:1, /* Card supports Suspend/Resume
|
||||
only SD mode, not used for SPI mode */
|
||||
s4mi:1, /* generate interrupts during a 4-bit
|
||||
multi-block data transfer */
|
||||
e4mi:1, /* Enable the multi-block IRQ during
|
||||
4-bit transfer for the SDIO card */
|
||||
low_speed:1, /* Card is a Low-Speed card */
|
||||
low_speed_4:1; /* 4-bit support for Low-Speed cards */
|
||||
|
||||
rt_uint8_t bus_width:1, /* Support SDIO bus width, 1:4bit, 0:1bit */
|
||||
cd_disable:1, /* Connect[0]/Disconnect[1] the 10K-90K ohm pull-up
|
||||
resistor on CD/DAT[3] (pin 1) of the card */
|
||||
power_ctrl:1, /* Support Master Power Control */
|
||||
high_speed:1; /* Support High-Speed */
|
||||
|
||||
|
||||
};
|
||||
|
||||
struct rt_sdio_cis {
|
||||
rt_uint16_t manufacturer;
|
||||
rt_uint16_t product;
|
||||
rt_uint16_t func0_blk_size;
|
||||
rt_uint32_t max_tran_speed;
|
||||
};
|
||||
|
||||
/*
|
||||
* SDIO function CIS tuple (unknown to the core)
|
||||
*/
|
||||
struct rt_sdio_function_tuple {
|
||||
struct rt_sdio_function_tuple *next;
|
||||
rt_uint8_t code;
|
||||
rt_uint8_t size;
|
||||
rt_uint8_t *data;
|
||||
};
|
||||
|
||||
struct rt_sdio_function;
|
||||
typedef void (rt_sdio_irq_handler_t)(struct rt_sdio_function *);
|
||||
|
||||
/*
|
||||
* SDIO function devices
|
||||
*/
|
||||
struct rt_sdio_function {
|
||||
struct rt_mmcsd_card *card; /* the card this device belongs to */
|
||||
rt_sdio_irq_handler_t *irq_handler; /* IRQ callback */
|
||||
rt_uint8_t num; /* function number */
|
||||
|
||||
rt_uint8_t func_code; /* Standard SDIO Function interface code */
|
||||
rt_uint16_t manufacturer; /* manufacturer id */
|
||||
rt_uint16_t product; /* product id */
|
||||
|
||||
rt_uint32_t max_blk_size; /* maximum block size */
|
||||
rt_uint32_t cur_blk_size; /* current block size */
|
||||
|
||||
rt_uint32_t enable_timeout_val; /* max enable timeout in msec */
|
||||
|
||||
struct rt_sdio_function_tuple *tuples;
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
#define SDIO_MAX_FUNCTIONS 7
|
||||
|
||||
|
||||
|
||||
struct rt_mmcsd_card {
|
||||
struct rt_mmcsd_host *host;
|
||||
rt_uint32_t rca; /* card addr */
|
||||
rt_uint32_t resp_cid[4]; /* card CID register */
|
||||
rt_uint32_t resp_csd[4]; /* card CSD register */
|
||||
rt_uint32_t resp_scr[2]; /* card SCR register */
|
||||
|
||||
rt_uint16_t tacc_clks; /* data access time by ns */
|
||||
rt_uint32_t tacc_ns; /* data access time by clk cycles */
|
||||
rt_uint32_t max_data_rate; /* max data transfer rate */
|
||||
rt_uint32_t card_capacity; /* card capacity, unit:KB */
|
||||
rt_uint32_t card_blksize; /* card block size */
|
||||
rt_uint32_t erase_size; /* erase size in sectors */
|
||||
rt_uint16_t card_type;
|
||||
#define CARD_TYPE_MMC 0 /* MMC card */
|
||||
#define CARD_TYPE_SD 1 /* SD card */
|
||||
#define CARD_TYPE_SDIO 2 /* SDIO card */
|
||||
#define CARD_TYPE_SDIO_COMBO 3 /* SD combo (IO+mem) card */
|
||||
|
||||
rt_uint16_t flags;
|
||||
#define CARD_FLAG_HIGHSPEED (1 << 0) /* SDIO bus speed 50MHz */
|
||||
#define CARD_FLAG_SDHC (1 << 1) /* SDHC card */
|
||||
#define CARD_FLAG_SDXC (1 << 2) /* SDXC card */
|
||||
|
||||
struct rt_sd_scr scr;
|
||||
struct rt_mmcsd_csd csd;
|
||||
rt_uint32_t hs_max_data_rate; /* max data transfer rate in high speed mode */
|
||||
|
||||
rt_uint8_t sdio_function_num; /* totol number of SDIO functions */
|
||||
struct rt_sdio_cccr cccr; /* common card info */
|
||||
struct rt_sdio_cis cis; /* common tuple info */
|
||||
struct rt_sdio_function *sdio_function[SDIO_MAX_FUNCTIONS + 1]; /* SDIO functions (devices) */
|
||||
rt_list_t blk_devices; /* for block device list */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-07-25 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __CMD_H__
|
||||
#define __CMD_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* class 1 */
|
||||
#define GO_IDLE_STATE 0 /* bc */
|
||||
#define SEND_OP_COND 1 /* bcr [31:0] OCR R3 */
|
||||
#define ALL_SEND_CID 2 /* bcr R2 */
|
||||
#define SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
|
||||
#define SET_DSR 4 /* bc [31:16] RCA */
|
||||
#define SWITCH 6 /* ac [31:0] See below R1b */
|
||||
#define SELECT_CARD 7 /* ac [31:16] RCA R1 */
|
||||
#define SEND_EXT_CSD 8 /* adtc R1 */
|
||||
#define SEND_CSD 9 /* ac [31:16] RCA R2 */
|
||||
#define SEND_CID 10 /* ac [31:16] RCA R2 */
|
||||
#define READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
|
||||
#define STOP_TRANSMISSION 12 /* ac R1b */
|
||||
#define SEND_STATUS 13 /* ac [31:16] RCA R1 */
|
||||
#define GO_INACTIVE_STATE 15 /* ac [31:16] RCA */
|
||||
#define SPI_READ_OCR 58 /* spi spi_R3 */
|
||||
#define SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */
|
||||
|
||||
/* class 2 */
|
||||
#define SET_BLOCKLEN 16 /* ac [31:0] block len R1 */
|
||||
#define READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
|
||||
#define READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
|
||||
|
||||
/* class 3 */
|
||||
#define WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
|
||||
|
||||
/* class 4 */
|
||||
#define SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */
|
||||
#define WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */
|
||||
#define WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */
|
||||
#define PROGRAM_CID 26 /* adtc R1 */
|
||||
#define PROGRAM_CSD 27 /* adtc R1 */
|
||||
|
||||
/* class 6 */
|
||||
#define SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */
|
||||
#define CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */
|
||||
#define SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */
|
||||
|
||||
/* class 5 */
|
||||
#define ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */
|
||||
#define ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */
|
||||
#define ERASE 38 /* ac R1b */
|
||||
|
||||
/* class 9 */
|
||||
#define FAST_IO 39 /* ac <Complex> R4 */
|
||||
#define GO_IRQ_STATE 40 /* bcr R5 */
|
||||
|
||||
/* class 7 */
|
||||
#define LOCK_UNLOCK 42 /* adtc R1b */
|
||||
|
||||
/* class 8 */
|
||||
#define APP_CMD 55 /* ac [31:16] RCA R1 */
|
||||
#define GEN_CMD 56 /* adtc [0] RD/WR R1 */
|
||||
|
||||
|
||||
/* SD commands type argument response */
|
||||
/* class 0 */
|
||||
/* This is basically the same command as for MMC with some quirks. */
|
||||
#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
|
||||
#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
|
||||
|
||||
/* class 10 */
|
||||
#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
|
||||
|
||||
/* Application commands */
|
||||
#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
|
||||
#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */
|
||||
#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */
|
||||
#define SD_APP_SEND_SCR 51 /* adtc R1 */
|
||||
|
||||
#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */
|
||||
#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */
|
||||
#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00 */
|
||||
|
||||
|
||||
/* SDIO commands type argument response */
|
||||
#define SD_IO_SEND_OP_COND 5 /* bcr [23:0] OCR R4 */
|
||||
#define SD_IO_RW_DIRECT 52 /* ac [31:0] See below R5 */
|
||||
#define SD_IO_RW_EXTENDED 53 /* adtc [31:0] See below R5 */
|
||||
|
||||
|
||||
/* CMD52 arguments */
|
||||
#define SDIO_ARG_CMD52_READ (0<<31)
|
||||
#define SDIO_ARG_CMD52_WRITE (1u<<31)
|
||||
#define SDIO_ARG_CMD52_FUNC_SHIFT 28
|
||||
#define SDIO_ARG_CMD52_FUNC_MASK 0x7
|
||||
#define SDIO_ARG_CMD52_RAW_FLAG (1u<<27)
|
||||
#define SDIO_ARG_CMD52_REG_SHIFT 9
|
||||
#define SDIO_ARG_CMD52_REG_MASK 0x1ffff
|
||||
#define SDIO_ARG_CMD52_DATA_SHIFT 0
|
||||
#define SDIO_ARG_CMD52_DATA_MASK 0xff
|
||||
#define SDIO_R5_DATA(resp) ((resp)[0] & 0xff)
|
||||
|
||||
/* CMD53 arguments */
|
||||
#define SDIO_ARG_CMD53_READ (0<<31)
|
||||
#define SDIO_ARG_CMD53_WRITE (1u<<31)
|
||||
#define SDIO_ARG_CMD53_FUNC_SHIFT 28
|
||||
#define SDIO_ARG_CMD53_FUNC_MASK 0x7
|
||||
#define SDIO_ARG_CMD53_BLOCK_MODE (1u<<27)
|
||||
#define SDIO_ARG_CMD53_INCREMENT (1u<<26)
|
||||
#define SDIO_ARG_CMD53_REG_SHIFT 9
|
||||
#define SDIO_ARG_CMD53_REG_MASK 0x1ffff
|
||||
#define SDIO_ARG_CMD53_LENGTH_SHIFT 0
|
||||
#define SDIO_ARG_CMD53_LENGTH_MASK 0x1ff
|
||||
#define SDIO_ARG_CMD53_LENGTH_MAX 511
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/*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
|
||||
|
||||
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_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);
|
||||
struct rt_mmcsd_host *mmcsd_alloc_host(void);
|
||||
void mmcsd_free_host(struct rt_mmcsd_host *host);
|
||||
int rt_mmcsd_core_init(void);
|
||||
|
||||
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
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-07-25 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __HOST_H__
|
||||
#define __HOST_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct rt_mmcsd_io_cfg {
|
||||
rt_uint32_t clock; /* clock rate */
|
||||
rt_uint16_t vdd;
|
||||
|
||||
/* vdd stores the bit number of the selected voltage range from below. */
|
||||
|
||||
rt_uint8_t bus_mode; /* command output mode */
|
||||
|
||||
#define MMCSD_BUSMODE_OPENDRAIN 1
|
||||
#define MMCSD_BUSMODE_PUSHPULL 2
|
||||
|
||||
rt_uint8_t chip_select; /* SPI chip select */
|
||||
|
||||
#define MMCSD_CS_IGNORE 0
|
||||
#define MMCSD_CS_HIGH 1
|
||||
#define MMCSD_CS_LOW 2
|
||||
|
||||
rt_uint8_t power_mode; /* power supply mode */
|
||||
|
||||
#define MMCSD_POWER_OFF 0
|
||||
#define MMCSD_POWER_UP 1
|
||||
#define MMCSD_POWER_ON 2
|
||||
|
||||
rt_uint8_t bus_width; /* data bus width */
|
||||
|
||||
#define MMCSD_BUS_WIDTH_1 0
|
||||
#define MMCSD_BUS_WIDTH_4 2
|
||||
#define MMCSD_BUS_WIDTH_8 3
|
||||
|
||||
};
|
||||
|
||||
struct rt_mmcsd_host;
|
||||
struct rt_mmcsd_req;
|
||||
|
||||
struct rt_mmcsd_host_ops {
|
||||
void (*request)(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req);
|
||||
void (*set_iocfg)(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg);
|
||||
rt_int32_t (*get_card_status)(struct rt_mmcsd_host *host);
|
||||
void (*enable_sdio_irq)(struct rt_mmcsd_host *host, rt_int32_t en);
|
||||
};
|
||||
|
||||
struct rt_mmcsd_host {
|
||||
struct rt_mmcsd_card *card;
|
||||
const struct rt_mmcsd_host_ops *ops;
|
||||
rt_uint32_t freq_min;
|
||||
rt_uint32_t freq_max;
|
||||
struct rt_mmcsd_io_cfg io_cfg;
|
||||
rt_uint32_t valid_ocr; /* current valid OCR */
|
||||
#define VDD_165_195 (1 << 7) /* VDD voltage 1.65 - 1.95 */
|
||||
#define VDD_20_21 (1 << 8) /* VDD voltage 2.0 ~ 2.1 */
|
||||
#define VDD_21_22 (1 << 9) /* VDD voltage 2.1 ~ 2.2 */
|
||||
#define VDD_22_23 (1 << 10) /* VDD voltage 2.2 ~ 2.3 */
|
||||
#define VDD_23_24 (1 << 11) /* VDD voltage 2.3 ~ 2.4 */
|
||||
#define VDD_24_25 (1 << 12) /* VDD voltage 2.4 ~ 2.5 */
|
||||
#define VDD_25_26 (1 << 13) /* VDD voltage 2.5 ~ 2.6 */
|
||||
#define VDD_26_27 (1 << 14) /* VDD voltage 2.6 ~ 2.7 */
|
||||
#define VDD_27_28 (1 << 15) /* VDD voltage 2.7 ~ 2.8 */
|
||||
#define VDD_28_29 (1 << 16) /* VDD voltage 2.8 ~ 2.9 */
|
||||
#define VDD_29_30 (1 << 17) /* VDD voltage 2.9 ~ 3.0 */
|
||||
#define VDD_30_31 (1 << 18) /* VDD voltage 3.0 ~ 3.1 */
|
||||
#define VDD_31_32 (1 << 19) /* VDD voltage 3.1 ~ 3.2 */
|
||||
#define VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */
|
||||
#define VDD_33_34 (1 << 21) /* VDD voltage 3.3 ~ 3.4 */
|
||||
#define VDD_34_35 (1 << 22) /* VDD voltage 3.4 ~ 3.5 */
|
||||
#define VDD_35_36 (1 << 23) /* VDD voltage 3.5 ~ 3.6 */
|
||||
rt_uint32_t flags; /* define device capabilities */
|
||||
#define MMCSD_BUSWIDTH_4 (1 << 0)
|
||||
#define MMCSD_BUSWIDTH_8 (1 << 1)
|
||||
#define MMCSD_MUTBLKWRITE (1 << 2)
|
||||
#define MMCSD_HOST_IS_SPI (1 << 3)
|
||||
#define controller_is_spi(host) (host->flags & MMCSD_HOST_IS_SPI)
|
||||
#define MMCSD_SUP_SDIO_IRQ (1 << 4) /* support signal pending SDIO IRQs */
|
||||
#define MMCSD_SUP_HIGHSPEED (1 << 5) /* support high speed */
|
||||
|
||||
rt_uint32_t max_seg_size; /* maximum size of one dma segment */
|
||||
rt_uint32_t max_dma_segs; /* maximum number of dma segments in one request */
|
||||
rt_uint32_t max_blk_size; /* maximum block size */
|
||||
rt_uint32_t max_blk_count; /* maximum block count */
|
||||
|
||||
rt_uint32_t id; /* Assigned host id */
|
||||
|
||||
rt_uint32_t spi_use_crc;
|
||||
struct rt_mutex bus_lock;
|
||||
struct rt_semaphore sem_ack;
|
||||
|
||||
rt_uint32_t sdio_irq_num;
|
||||
struct rt_semaphore *sdio_irq_sem;
|
||||
struct rt_thread *sdio_irq_thread;
|
||||
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
rt_inline void mmcsd_delay_ms(rt_uint32_t ms)
|
||||
{
|
||||
if (ms < 1000 / RT_TICK_PER_SECOND)
|
||||
{
|
||||
rt_thread_delay(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_thread_delay(ms/(1000 / RT_TICK_PER_SECOND));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-12-05 Bernard the first version
|
||||
* 2011-04-02 prife add mark_badblock and check_block
|
||||
*/
|
||||
|
||||
/*
|
||||
* COPYRIGHT (C) 2012, Shanghai Real Thread
|
||||
*/
|
||||
|
||||
#ifndef __MTD_NAND_H__
|
||||
#define __MTD_NAND_H__
|
||||
|
||||
#include <rtdevice.h>
|
||||
|
||||
struct rt_mtd_nand_driver_ops;
|
||||
#define RT_MTD_NAND_DEVICE(device) ((struct rt_mtd_nand_device*)(device))
|
||||
|
||||
#define RT_MTD_EOK 0 /* NO error */
|
||||
#define RT_MTD_EECC 101 /* ECC error */
|
||||
#define RT_MTD_EBUSY 102 /* hardware busy */
|
||||
#define RT_MTD_EIO 103 /* generic IO issue */
|
||||
#define RT_MTD_ENOMEM 104 /* out of memory */
|
||||
#define RT_MTD_ESRC 105 /* source issue */
|
||||
#define RT_MTD_EECC_CORRECT 106 /* ECC error but correct */
|
||||
|
||||
struct rt_mtd_nand_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
|
||||
rt_uint16_t page_size; /* The Page size in the flash */
|
||||
rt_uint16_t oob_size; /* Out of bank size */
|
||||
rt_uint16_t oob_free; /* the free area in oob that flash driver not use */
|
||||
rt_uint16_t plane_num; /* the number of plane in the NAND Flash */
|
||||
|
||||
rt_uint32_t pages_per_block; /* The number of page a block */
|
||||
rt_uint16_t block_total;
|
||||
|
||||
/* Only be touched by driver */
|
||||
rt_uint32_t block_start; /* The start of available block*/
|
||||
rt_uint32_t block_end; /* The end of available block */
|
||||
|
||||
/* operations interface */
|
||||
const struct rt_mtd_nand_driver_ops *ops;
|
||||
};
|
||||
|
||||
struct rt_mtd_nand_driver_ops
|
||||
{
|
||||
rt_err_t (*read_id)(struct rt_mtd_nand_device *device);
|
||||
|
||||
rt_err_t (*read_page)(struct rt_mtd_nand_device *device,
|
||||
rt_off_t page,
|
||||
rt_uint8_t *data, rt_uint32_t data_len,
|
||||
rt_uint8_t *spare, rt_uint32_t spare_len);
|
||||
|
||||
rt_err_t (*write_page)(struct rt_mtd_nand_device *device,
|
||||
rt_off_t page,
|
||||
const rt_uint8_t *data, rt_uint32_t data_len,
|
||||
const rt_uint8_t *spare, rt_uint32_t spare_len);
|
||||
rt_err_t (*move_page)(struct rt_mtd_nand_device *device, rt_off_t src_page, rt_off_t dst_page);
|
||||
|
||||
rt_err_t (*erase_block)(struct rt_mtd_nand_device *device, rt_uint32_t block);
|
||||
rt_err_t (*check_block)(struct rt_mtd_nand_device *device, rt_uint32_t block);
|
||||
rt_err_t (*mark_badblock)(struct rt_mtd_nand_device *device, rt_uint32_t block);
|
||||
};
|
||||
|
||||
rt_err_t rt_mtd_nand_register_device(const char *name, struct rt_mtd_nand_device *device);
|
||||
|
||||
rt_inline rt_uint32_t rt_mtd_nand_read_id(struct rt_mtd_nand_device *device)
|
||||
{
|
||||
RT_ASSERT(device->ops->read_id);
|
||||
return device->ops->read_id(device);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_mtd_nand_read(
|
||||
struct rt_mtd_nand_device *device,
|
||||
rt_off_t page,
|
||||
rt_uint8_t *data, rt_uint32_t data_len,
|
||||
rt_uint8_t *spare, rt_uint32_t spare_len)
|
||||
{
|
||||
RT_ASSERT(device->ops->read_page);
|
||||
return device->ops->read_page(device, page, data, data_len, spare, spare_len);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_mtd_nand_write(
|
||||
struct rt_mtd_nand_device *device,
|
||||
rt_off_t page,
|
||||
const rt_uint8_t *data, rt_uint32_t data_len,
|
||||
const rt_uint8_t *spare, rt_uint32_t spare_len)
|
||||
{
|
||||
RT_ASSERT(device->ops->write_page);
|
||||
return device->ops->write_page(device, page, data, data_len, spare, spare_len);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_mtd_nand_move_page(struct rt_mtd_nand_device *device,
|
||||
rt_off_t src_page, rt_off_t dst_page)
|
||||
{
|
||||
RT_ASSERT(device->ops->move_page);
|
||||
return device->ops->move_page(device, src_page, dst_page);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_mtd_nand_erase_block(struct rt_mtd_nand_device *device, rt_uint32_t block)
|
||||
{
|
||||
RT_ASSERT(device->ops->erase_block);
|
||||
return device->ops->erase_block(device, block);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_mtd_nand_check_block(struct rt_mtd_nand_device *device, rt_uint32_t block)
|
||||
{
|
||||
if (device->ops->check_block)
|
||||
{
|
||||
return device->ops->check_block(device, block);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_mtd_nand_mark_badblock(struct rt_mtd_nand_device *device, rt_uint32_t block)
|
||||
{
|
||||
if (device->ops->mark_badblock)
|
||||
{
|
||||
return device->ops->mark_badblock(device, block);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* MTD_NAND_H_ */
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* COPYRIGHT (C) 2011-2021, Real-Thread Information Technology Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-5-30 Bernard the first version
|
||||
*/
|
||||
|
||||
#ifndef __MTD_NOR_H__
|
||||
#define __MTD_NOR_H__
|
||||
|
||||
#include <rtdevice.h>
|
||||
|
||||
struct rt_mtd_nor_driver_ops;
|
||||
#define RT_MTD_NOR_DEVICE(device) ((struct rt_mtd_nor_device*)(device))
|
||||
|
||||
struct rt_mtd_nor_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
|
||||
rt_uint32_t block_size; /* The Block size in the flash */
|
||||
rt_uint32_t block_start; /* The start of available block*/
|
||||
rt_uint32_t block_end; /* The end of available block */
|
||||
|
||||
/* operations interface */
|
||||
const struct rt_mtd_nor_driver_ops* ops;
|
||||
};
|
||||
|
||||
struct rt_mtd_nor_driver_ops
|
||||
{
|
||||
rt_err_t (*read_id) (struct rt_mtd_nor_device* device);
|
||||
|
||||
rt_size_t (*read) (struct rt_mtd_nor_device* device, rt_off_t offset, rt_uint8_t* data, rt_uint32_t length);
|
||||
rt_size_t (*write) (struct rt_mtd_nor_device* device, rt_off_t offset, const rt_uint8_t* data, rt_uint32_t length);
|
||||
|
||||
rt_err_t (*erase_block)(struct rt_mtd_nor_device* device, rt_off_t offset, rt_uint32_t length);
|
||||
};
|
||||
|
||||
rt_err_t rt_mtd_nor_register_device(const char* name, struct rt_mtd_nor_device* device);
|
||||
|
||||
rt_inline rt_uint32_t rt_mtd_nor_read_id(struct rt_mtd_nor_device* device)
|
||||
{
|
||||
return device->ops->read_id(device);
|
||||
}
|
||||
|
||||
rt_inline rt_size_t rt_mtd_nor_read(
|
||||
struct rt_mtd_nor_device* device,
|
||||
rt_off_t offset, rt_uint8_t* data, rt_uint32_t length)
|
||||
{
|
||||
return device->ops->read(device, offset, data, length);
|
||||
}
|
||||
|
||||
rt_inline rt_size_t rt_mtd_nor_write(
|
||||
struct rt_mtd_nor_device* device,
|
||||
rt_off_t offset, const rt_uint8_t* data, rt_uint32_t length)
|
||||
{
|
||||
return device->ops->write(device, offset, data, length);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_mtd_nor_erase_block(struct rt_mtd_nor_device* device, rt_off_t offset, rt_size_t length)
|
||||
{
|
||||
return device->ops->erase_block(device, offset, length);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2020-10-14 wangqiang the first version
|
||||
*/
|
||||
|
||||
#ifndef __PHY_H__
|
||||
#define __PHY_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Defines the PHY link speed. This is align with the speed for MAC. */
|
||||
enum phy_speed
|
||||
{
|
||||
PHY_SPEED_10M = 0U, /* PHY 10M speed. */
|
||||
PHY_SPEED_100M /* PHY 100M speed. */
|
||||
};
|
||||
|
||||
/* Defines the PHY link duplex. */
|
||||
enum phy_duplex
|
||||
{
|
||||
PHY_HALF_DUPLEX = 0U, /* PHY half duplex. */
|
||||
PHY_FULL_DUPLEX /* PHY full duplex. */
|
||||
};
|
||||
|
||||
/*! @brief Defines the PHY loopback mode. */
|
||||
enum phy_loop
|
||||
{
|
||||
PHY_LOCAL_LOOP = 0U, /* PHY local loopback. */
|
||||
PHY_REMOTE_LOOP /* PHY remote loopback. */
|
||||
};
|
||||
|
||||
|
||||
struct rt_phy_msg
|
||||
{
|
||||
rt_uint32_t reg;
|
||||
rt_uint32_t value;
|
||||
};
|
||||
|
||||
typedef struct rt_phy_msg rt_phy_msg_t;
|
||||
|
||||
|
||||
struct rt_phy_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
struct rt_mdio_bus *bus;
|
||||
rt_uint32_t addr;
|
||||
struct rt_phy_ops *ops;
|
||||
};
|
||||
|
||||
typedef struct rt_phy_device rt_phy_t;
|
||||
|
||||
|
||||
enum {
|
||||
PHY_STATUS_OK = 0,
|
||||
PHY_STATUS_FAIL,
|
||||
PHY_STATUS_TIMEOUT,
|
||||
};
|
||||
|
||||
typedef rt_int32_t rt_phy_status;
|
||||
|
||||
struct rt_phy_ops
|
||||
{
|
||||
rt_phy_status (*init)(void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz);
|
||||
rt_phy_status (*read)(rt_uint32_t reg, rt_uint32_t *data);
|
||||
rt_phy_status (*write)(rt_uint32_t reg, rt_uint32_t data);
|
||||
rt_phy_status (*loopback)(rt_uint32_t mode, rt_uint32_t speed, rt_bool_t enable);
|
||||
rt_phy_status (*get_link_status)(rt_bool_t *status);
|
||||
rt_phy_status (*get_link_speed_duplex)(rt_uint32_t *speed, rt_uint32_t *duplex);
|
||||
};
|
||||
|
||||
rt_err_t rt_hw_phy_register(struct rt_phy_device *phy, const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __PHY_H__*/
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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
|
||||
|
||||
/* pin device and operations for RT-Thread */
|
||||
struct rt_device_pin
|
||||
{
|
||||
struct rt_device parent;
|
||||
const struct rt_pin_ops *ops;
|
||||
};
|
||||
|
||||
#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
|
||||
|
||||
#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 -1
|
||||
|
||||
struct rt_device_pin_mode
|
||||
{
|
||||
rt_uint16_t pin;
|
||||
rt_uint16_t mode;
|
||||
};
|
||||
struct rt_device_pin_status
|
||||
{
|
||||
rt_uint16_t pin;
|
||||
rt_uint16_t status;
|
||||
};
|
||||
struct rt_pin_irq_hdr
|
||||
{
|
||||
rt_int16_t pin;
|
||||
rt_uint16_t mode;
|
||||
void (*hdr)(void *args);
|
||||
void *args;
|
||||
};
|
||||
struct rt_pin_ops
|
||||
{
|
||||
void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_base_t mode);
|
||||
void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_base_t value);
|
||||
int (*pin_read)(struct rt_device *device, rt_base_t pin);
|
||||
rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_int32_t pin,
|
||||
rt_uint32_t mode, void (*hdr)(void *args), void *args);
|
||||
rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_int32_t pin);
|
||||
rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled);
|
||||
rt_base_t (*pin_get)(const char *name);
|
||||
};
|
||||
|
||||
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_base_t mode);
|
||||
void rt_pin_write(rt_base_t pin, rt_base_t value);
|
||||
int rt_pin_read(rt_base_t pin);
|
||||
rt_err_t rt_pin_attach_irq(rt_int32_t pin, rt_uint32_t mode,
|
||||
void (*hdr)(void *args), void *args);
|
||||
rt_err_t rt_pin_detach_irq(rt_int32_t pin);
|
||||
rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled);
|
||||
/* Get pin number by name,such as PA.0,P0.12 */
|
||||
rt_base_t rt_pin_get(const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-06-02 Bernard the first version
|
||||
* 2018-08-02 Tanek split run and sleep modes, support custom mode
|
||||
* 2019-04-28 Zero-Free improve PM mode and device ops interface
|
||||
* 2020-11-23 zhangsz update pm mode select
|
||||
* 2020-11-27 zhangsz update pm 2.0
|
||||
*/
|
||||
|
||||
#ifndef __PM_H__
|
||||
#define __PM_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <rtthread.h>
|
||||
#include <drivers/lptimer.h>
|
||||
|
||||
/* All modes used for rt_pm_request() and rt_pm_release() */
|
||||
enum
|
||||
{
|
||||
/* sleep modes */
|
||||
PM_SLEEP_MODE_NONE = 0,
|
||||
PM_SLEEP_MODE_IDLE,
|
||||
PM_SLEEP_MODE_LIGHT,
|
||||
PM_SLEEP_MODE_DEEP,
|
||||
PM_SLEEP_MODE_STANDBY,
|
||||
PM_SLEEP_MODE_SHUTDOWN,
|
||||
PM_SLEEP_MODE_MAX,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
/* run modes*/
|
||||
PM_RUN_MODE_HIGH_SPEED = 0,
|
||||
PM_RUN_MODE_NORMAL_SPEED,
|
||||
PM_RUN_MODE_MEDIUM_SPEED,
|
||||
PM_RUN_MODE_LOW_SPEED,
|
||||
PM_RUN_MODE_MAX,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
RT_PM_FREQUENCY_PENDING = 0x01,
|
||||
};
|
||||
|
||||
/* The name of all modes used in the msh command "pm_dump" */
|
||||
#define PM_SLEEP_MODE_NAMES \
|
||||
{ \
|
||||
"None Mode", \
|
||||
"Idle Mode", \
|
||||
"LightSleep Mode", \
|
||||
"DeepSleep Mode", \
|
||||
"Standby Mode", \
|
||||
"Shutdown Mode", \
|
||||
}
|
||||
|
||||
#define PM_RUN_MODE_NAMES \
|
||||
{ \
|
||||
"High Speed", \
|
||||
"Normal Speed", \
|
||||
"Medium Speed", \
|
||||
"Low Mode", \
|
||||
}
|
||||
|
||||
#ifndef PM_USING_CUSTOM_CONFIG
|
||||
/**
|
||||
* Modules used for
|
||||
* pm_module_request(PM_BOARD_ID, PM_SLEEP_MODE_IDLE)
|
||||
* pm_module_release(PM_BOARD_ID, PM_SLEEP_MODE_IDLE)
|
||||
* pm_module_release_all(PM_BOARD_ID, PM_SLEEP_MODE_IDLE)
|
||||
*/
|
||||
enum pm_module_id {
|
||||
PM_NONE_ID = 0,
|
||||
PM_POWER_ID,
|
||||
PM_BOARD_ID,
|
||||
PM_BSP_ID,
|
||||
PM_MAIN_ID,
|
||||
PM_PMS_ID,
|
||||
PM_PMC_ID,
|
||||
PM_TASK_ID,
|
||||
PM_SPI_ID,
|
||||
PM_I2C_ID,
|
||||
PM_UART_ID,
|
||||
PM_CAN_ID,
|
||||
PM_ETH_ID,
|
||||
PM_SENSOR_ID,
|
||||
PM_LCD_ID,
|
||||
PM_KEY_ID,
|
||||
PM_TP_ID,
|
||||
PM_MODULE_MAX_ID, /* enum must! */
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#include <pm_cfg.h>
|
||||
|
||||
#endif /* PM_USING_CUSTOM_CONFIG */
|
||||
|
||||
#ifndef RT_PM_DEFAULT_SLEEP_MODE
|
||||
#define RT_PM_DEFAULT_SLEEP_MODE PM_SLEEP_MODE_NONE
|
||||
#endif
|
||||
|
||||
#ifndef RT_PM_DEFAULT_DEEPSLEEP_MODE
|
||||
#define RT_PM_DEFAULT_DEEPSLEEP_MODE PM_SLEEP_MODE_DEEP
|
||||
#endif
|
||||
|
||||
#ifndef RT_PM_DEFAULT_RUN_MODE
|
||||
#define RT_PM_DEFAULT_RUN_MODE PM_RUN_MODE_NORMAL_SPEED
|
||||
#endif
|
||||
|
||||
/**
|
||||
* device control flag to request or release power
|
||||
*/
|
||||
#define RT_PM_DEVICE_CTRL_REQUEST 0x01
|
||||
#define RT_PM_DEVICE_CTRL_RELEASE 0x00
|
||||
|
||||
struct rt_pm;
|
||||
|
||||
/**
|
||||
* low power mode operations
|
||||
*/
|
||||
struct rt_pm_ops
|
||||
{
|
||||
void (*sleep)(struct rt_pm *pm, rt_uint8_t mode);
|
||||
void (*run)(struct rt_pm *pm, rt_uint8_t mode);
|
||||
void (*timer_start)(struct rt_pm *pm, rt_uint32_t timeout);
|
||||
void (*timer_stop)(struct rt_pm *pm);
|
||||
rt_tick_t (*timer_get_tick)(struct rt_pm *pm);
|
||||
};
|
||||
|
||||
struct rt_device_pm_ops
|
||||
{
|
||||
int (*suspend)(const struct rt_device *device, rt_uint8_t mode);
|
||||
void (*resume)(const struct rt_device *device, rt_uint8_t mode);
|
||||
int (*frequency_change)(const struct rt_device *device, rt_uint8_t mode);
|
||||
};
|
||||
|
||||
struct rt_device_pm
|
||||
{
|
||||
const struct rt_device *device;
|
||||
const struct rt_device_pm_ops *ops;
|
||||
};
|
||||
|
||||
struct rt_pm_module
|
||||
{
|
||||
rt_uint8_t req_status;
|
||||
rt_bool_t busy_flag;
|
||||
rt_uint32_t timeout;
|
||||
rt_uint32_t start_time;
|
||||
};
|
||||
|
||||
/**
|
||||
* power management
|
||||
*/
|
||||
struct rt_pm
|
||||
{
|
||||
struct rt_device parent;
|
||||
|
||||
/* modes */
|
||||
rt_uint8_t modes[PM_SLEEP_MODE_MAX];
|
||||
rt_uint8_t sleep_mode; /* current sleep mode */
|
||||
rt_uint8_t run_mode; /* current running mode */
|
||||
|
||||
/* modules request status*/
|
||||
struct rt_pm_module module_status[PM_MODULE_MAX_ID];
|
||||
|
||||
/* sleep request table */
|
||||
rt_uint32_t sleep_status[PM_SLEEP_MODE_MAX - 1][(PM_MODULE_MAX_ID + 31) / 32];
|
||||
|
||||
/* the list of device, which has PM feature */
|
||||
rt_uint8_t device_pm_number;
|
||||
struct rt_device_pm *device_pm;
|
||||
|
||||
/* if the mode has timer, the corresponding bit is 1*/
|
||||
rt_uint8_t timer_mask;
|
||||
rt_uint8_t flags;
|
||||
|
||||
const struct rt_pm_ops *ops;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
RT_PM_ENTER_SLEEP = 0,
|
||||
RT_PM_EXIT_SLEEP,
|
||||
};
|
||||
|
||||
struct rt_pm_notify
|
||||
{
|
||||
void (*notify)(rt_uint8_t event, rt_uint8_t mode, void *data);
|
||||
void *data;
|
||||
};
|
||||
|
||||
void rt_pm_request(rt_uint8_t sleep_mode);
|
||||
void rt_pm_release(rt_uint8_t sleep_mode);
|
||||
void rt_pm_release_all(rt_uint8_t sleep_mode);
|
||||
int rt_pm_run_enter(rt_uint8_t run_mode);
|
||||
|
||||
void rt_pm_device_register(struct rt_device *device, const struct rt_device_pm_ops *ops);
|
||||
void rt_pm_device_unregister(struct rt_device *device);
|
||||
|
||||
void rt_pm_notify_set(void (*notify)(rt_uint8_t event, rt_uint8_t mode, void *data), void *data);
|
||||
void rt_pm_default_set(rt_uint8_t sleep_mode);
|
||||
|
||||
void rt_system_pm_init(const struct rt_pm_ops *ops,
|
||||
rt_uint8_t timer_mask,
|
||||
void *user_data);
|
||||
void rt_pm_module_request(uint8_t module_id, rt_uint8_t sleep_mode);
|
||||
void rt_pm_module_release(uint8_t module_id, rt_uint8_t sleep_mode);
|
||||
void rt_pm_module_release_all(uint8_t module_id, rt_uint8_t sleep_mode);
|
||||
void rt_pm_module_delay_sleep(rt_uint8_t module_id, rt_tick_t timeout);
|
||||
rt_uint32_t rt_pm_module_get_status(void);
|
||||
rt_uint8_t rt_pm_get_sleep_mode(void);
|
||||
struct rt_pm *rt_pm_get_handle(void);
|
||||
|
||||
/* sleep : request or release */
|
||||
void rt_pm_sleep_request(rt_uint16_t module_id, rt_uint8_t mode);
|
||||
void rt_pm_sleep_release(rt_uint16_t module_id, rt_uint8_t mode);
|
||||
void rt_pm_sleep_none_request(rt_uint16_t module_id);
|
||||
void rt_pm_sleep_none_release(rt_uint16_t module_id);
|
||||
void rt_pm_sleep_idle_request(rt_uint16_t module_id);
|
||||
void rt_pm_sleep_idle_release(rt_uint16_t module_id);
|
||||
void rt_pm_sleep_light_request(rt_uint16_t module_id);
|
||||
void rt_pm_sleep_light_release(rt_uint16_t module_id);
|
||||
|
||||
#endif /* __PM_H__ */
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-08-08 balanceTWK the first version
|
||||
*/
|
||||
|
||||
#ifndef __PULSE_ENCODER_H__
|
||||
#define __PULSE_ENCODER_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* pulse_encoder control command */
|
||||
#define PULSE_ENCODER_CMD_GET_TYPE (128 + 0) /* get a pulse_encoder type information */
|
||||
#define PULSE_ENCODER_CMD_ENABLE (128 + 1) /* enable pulse_encoder */
|
||||
#define PULSE_ENCODER_CMD_DISABLE (128 + 2) /* disable pulse_encoder */
|
||||
#define PULSE_ENCODER_CMD_CLEAR_COUNT (128 + 3) /* clear pulse_encoder count */
|
||||
|
||||
/* pulse_encoder type */
|
||||
enum rt_pulse_encoder_type
|
||||
{
|
||||
UNKNOWN_PULSE_ENCODER_TYPE = 0x00, /* Unknown pulse_encoder type */
|
||||
SINGLE_PHASE_PULSE_ENCODER, /* single phase pulse_encoder */
|
||||
AB_PHASE_PULSE_ENCODER /* two phase pulse_encoder */
|
||||
};
|
||||
|
||||
struct rt_pulse_encoder_device;
|
||||
|
||||
struct rt_pulse_encoder_ops
|
||||
{
|
||||
rt_err_t (*init)(struct rt_pulse_encoder_device *pulse_encoder);
|
||||
rt_int32_t (*get_count)(struct rt_pulse_encoder_device *pulse_encoder);
|
||||
rt_err_t (*clear_count)(struct rt_pulse_encoder_device *pulse_encoder);
|
||||
rt_err_t (*control)(struct rt_pulse_encoder_device *pulse_encoder, rt_uint32_t cmd, void *args);
|
||||
};
|
||||
|
||||
struct rt_pulse_encoder_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
const struct rt_pulse_encoder_ops *ops;
|
||||
enum rt_pulse_encoder_type type;
|
||||
};
|
||||
|
||||
rt_err_t rt_device_pulse_encoder_register(struct rt_pulse_encoder_device *pulse_encoder, const char *name, void *user_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __PULSE_ENCODER_H__ */
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-05-07 aozima the first version
|
||||
*/
|
||||
|
||||
#ifndef __DRV_PWM_H_INCLUDE__
|
||||
#define __DRV_PWM_H_INCLUDE__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define PWM_CMD_ENABLE (128 + 0)
|
||||
#define PWM_CMD_DISABLE (128 + 1)
|
||||
#define PWM_CMD_SET (128 + 2)
|
||||
#define PWM_CMD_GET (128 + 3)
|
||||
#define PWMN_CMD_ENABLE (128 + 4)
|
||||
#define PWMN_CMD_DISABLE (128 + 5)
|
||||
|
||||
struct rt_pwm_configuration
|
||||
{
|
||||
rt_uint32_t channel; /* 0-n */
|
||||
rt_uint32_t period; /* unit:ns 1ns~4.29s:1Ghz~0.23hz */
|
||||
rt_uint32_t pulse; /* unit:ns (pulse<=period) */
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
#endif /* __DRV_PWM_H_INCLUDE__ */
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-08-13 balanceTWK first version.
|
||||
*/
|
||||
|
||||
#ifndef __RT_INPUT_CAPTURE_H__
|
||||
#define __RT_INPUT_CAPTURE_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* capture control command */
|
||||
#define INPUTCAPTURE_CMD_CLEAR_BUF (128 + 0) /* clear capture buf */
|
||||
#define INPUTCAPTURE_CMD_SET_WATERMARK (128 + 1) /* Set the callback threshold */
|
||||
|
||||
struct rt_inputcapture_data
|
||||
{
|
||||
rt_uint32_t pulsewidth_us;
|
||||
rt_bool_t is_high;
|
||||
};
|
||||
|
||||
struct rt_inputcapture_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
|
||||
const struct rt_inputcapture_ops *ops;
|
||||
struct rt_ringbuffer *ringbuff;
|
||||
rt_size_t watermark;
|
||||
};
|
||||
|
||||
/**
|
||||
* capture operators
|
||||
*/
|
||||
struct rt_inputcapture_ops
|
||||
{
|
||||
rt_err_t (*init)(struct rt_inputcapture_device *inputcapture);
|
||||
rt_err_t (*open)(struct rt_inputcapture_device *inputcapture);
|
||||
rt_err_t (*close)(struct rt_inputcapture_device *inputcapture);
|
||||
rt_err_t (*get_pulsewidth)(struct rt_inputcapture_device *inputcapture, rt_uint32_t *pulsewidth_us);
|
||||
};
|
||||
|
||||
void rt_hw_inputcapture_isr(struct rt_inputcapture_device *inputcapture, rt_bool_t level);
|
||||
|
||||
rt_err_t rt_device_inputcapture_register(struct rt_inputcapture_device *inputcapture,
|
||||
const char *name,
|
||||
void *data);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __RT_INPUT_CAPTURE_H__ */
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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
|
||||
*/
|
||||
|
||||
#ifndef __RTC_H__
|
||||
#define __RTC_H__
|
||||
|
||||
#include <rtdef.h>
|
||||
|
||||
#define RT_DEVICE_CTRL_RTC_GET_TIME 0x20 /**< get second time */
|
||||
#define RT_DEVICE_CTRL_RTC_SET_TIME 0x21 /**< set second time */
|
||||
#define RT_DEVICE_CTRL_RTC_GET_TIMEVAL 0x22 /**< get timeval for gettimeofday */
|
||||
#define RT_DEVICE_CTRL_RTC_SET_TIMEVAL 0x23 /**< set timeval for gettimeofday */
|
||||
#define RT_DEVICE_CTRL_RTC_GET_ALARM 0x24 /**< get alarm */
|
||||
#define RT_DEVICE_CTRL_RTC_SET_ALARM 0x25 /**< set alarm */
|
||||
|
||||
struct rt_rtc_ops
|
||||
{
|
||||
rt_err_t (*init)(void);
|
||||
rt_err_t (*get_secs)(void *arg);
|
||||
rt_err_t (*set_secs)(void *arg);
|
||||
rt_err_t (*get_alarm)(void *arg);
|
||||
rt_err_t (*set_alarm)(void *arg);
|
||||
rt_err_t (*get_timeval)(void *arg);
|
||||
rt_err_t (*set_timeval)(void *arg);
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
#endif /* __RTC_H__ */
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-07-25 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __SD_H__
|
||||
#define __SD_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <drivers/mmcsd_host.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
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
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-02-26 weety first version
|
||||
*/
|
||||
|
||||
#ifndef __SDIO_FUNC_IDS_H__
|
||||
#define __SDIO_FUNC_IDS_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Standard SDIO Function Interfaces */
|
||||
|
||||
#define SDIO_FUNC_CODE_NONE 0x00 /* Not a SDIO standard interface */
|
||||
#define SDIO_FUNC_CODE_UART 0x01 /* SDIO Standard UART */
|
||||
#define SDIO_FUNC_CODE_BT_A 0x02 /* SDIO Type-A for Bluetooth standard interface */
|
||||
#define SDIO_FUNC_CODE_BT_B 0x03 /* SDIO Type-B for Bluetooth standard interface */
|
||||
#define SDIO_FUNC_CODE_GPS 0x04 /* SDIO GPS standard interface */
|
||||
#define SDIO_FUNC_CODE_CAMERA 0x05 /* SDIO Camera standard interface */
|
||||
#define SDIO_FUNC_CODE_PHS 0x06 /* SDIO PHS standard interface */
|
||||
#define SDIO_FUNC_CODE_WLAN 0x07 /* SDIO WLAN interface */
|
||||
#define SDIO_FUNC_CODE_ATA 0x08 /* Embedded SDIO-ATA standard interface */
|
||||
|
||||
/* manufacturer id, product io */
|
||||
|
||||
#define SDIO_MANUFACTURER_ID_MARVELL 0x02df
|
||||
#define SDIO_PRODUCT_ID_MARVELL_88W8686 0x9103
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-01-31 flybreak first version
|
||||
*/
|
||||
|
||||
#ifndef __SENSOR_H__
|
||||
#define __SENSOR_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "pin.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_RTC
|
||||
#define rt_sensor_get_ts() time(RT_NULL) /* API for the sensor to get the timestamp */
|
||||
#else
|
||||
#define rt_sensor_get_ts() rt_tick_get() /* API for the sensor to get the timestamp */
|
||||
#endif
|
||||
|
||||
#define RT_PIN_NONE 0xFFFF /* RT PIN NONE */
|
||||
#define RT_DEVICE_FLAG_FIFO_RX 0x200 /* Flag to use when the sensor is open by fifo mode */
|
||||
|
||||
#define RT_SENSOR_MODULE_MAX (3) /* The maximum number of members of a sensor module */
|
||||
|
||||
/* Sensor types */
|
||||
|
||||
#define RT_SENSOR_CLASS_NONE (0)
|
||||
#define RT_SENSOR_CLASS_ACCE (1) /* Accelerometer */
|
||||
#define RT_SENSOR_CLASS_GYRO (2) /* Gyroscope */
|
||||
#define RT_SENSOR_CLASS_MAG (3) /* Magnetometer */
|
||||
#define RT_SENSOR_CLASS_TEMP (4) /* Temperature */
|
||||
#define RT_SENSOR_CLASS_HUMI (5) /* Relative Humidity */
|
||||
#define RT_SENSOR_CLASS_BARO (6) /* Barometer */
|
||||
#define RT_SENSOR_CLASS_LIGHT (7) /* Ambient light */
|
||||
#define RT_SENSOR_CLASS_PROXIMITY (8) /* Proximity */
|
||||
#define RT_SENSOR_CLASS_HR (9) /* Heart Rate */
|
||||
#define RT_SENSOR_CLASS_TVOC (10) /* TVOC Level */
|
||||
#define RT_SENSOR_CLASS_NOISE (11) /* Noise Loudness */
|
||||
#define RT_SENSOR_CLASS_STEP (12) /* Step sensor */
|
||||
#define RT_SENSOR_CLASS_FORCE (13) /* Force sensor */
|
||||
#define RT_SENSOR_CLASS_DUST (14) /* Dust sensor */
|
||||
#define RT_SENSOR_CLASS_ECO2 (15) /* eCO2 sensor */
|
||||
#define RT_SENSOR_CLASS_GNSS (16) /* GPS/GNSS sensor */
|
||||
#define RT_SENSOR_CLASS_TOF (17) /* TOF sensor */
|
||||
#define RT_SENSOR_CLASS_SPO2 (18) /* SpO2 sensor */
|
||||
#define RT_SENSOR_CLASS_IAQ (19) /* IAQ sensor. */
|
||||
#define RT_SENSOR_CLASS_ETOH (20) /* EtOH sensor. */
|
||||
|
||||
/* Sensor vendor types */
|
||||
|
||||
#define RT_SENSOR_VENDOR_UNKNOWN (0)
|
||||
#define RT_SENSOR_VENDOR_STM (1) /* STMicroelectronics */
|
||||
#define RT_SENSOR_VENDOR_BOSCH (2) /* Bosch */
|
||||
#define RT_SENSOR_VENDOR_INVENSENSE (3) /* Invensense */
|
||||
#define RT_SENSOR_VENDOR_SEMTECH (4) /* Semtech */
|
||||
#define RT_SENSOR_VENDOR_GOERTEK (5) /* Goertek */
|
||||
#define RT_SENSOR_VENDOR_MIRAMEMS (6) /* MiraMEMS */
|
||||
#define RT_SENSOR_VENDOR_DALLAS (7) /* Dallas */
|
||||
#define RT_SENSOR_VENDOR_ASAIR (8) /* Aosong */
|
||||
#define RT_SENSOR_VENDOR_SHARP (9) /* Sharp */
|
||||
#define RT_SENSOR_VENDOR_SENSIRION (10) /* Sensirion */
|
||||
#define RT_SENSOR_VENDOR_TI (11) /* Texas Instruments */
|
||||
#define RT_SENSOR_VENDOR_PLANTOWER (12) /* Plantower */
|
||||
#define RT_SENSOR_VENDOR_AMS (13) /* ams AG */
|
||||
#define RT_SENSOR_VENDOR_MAXIM (14) /* Maxim Integrated */
|
||||
|
||||
|
||||
/* Sensor unit types */
|
||||
|
||||
#define RT_SENSOR_UNIT_NONE (0)
|
||||
#define RT_SENSOR_UNIT_MG (1) /* Accelerometer unit: mG */
|
||||
#define RT_SENSOR_UNIT_MDPS (2) /* Gyroscope unit: mdps */
|
||||
#define RT_SENSOR_UNIT_MGAUSS (3) /* Magnetometer unit: mGauss */
|
||||
#define RT_SENSOR_UNIT_LUX (4) /* Ambient light unit: lux */
|
||||
#define RT_SENSOR_UNIT_CM (5) /* Distance unit: cm */
|
||||
#define RT_SENSOR_UNIT_PA (6) /* Barometer unit: pa */
|
||||
#define RT_SENSOR_UNIT_PERMILLAGE (7) /* Relative Humidity unit: permillage */
|
||||
#define RT_SENSOR_UNIT_DCELSIUS (8) /* Temperature unit: dCelsius */
|
||||
#define RT_SENSOR_UNIT_HZ (9) /* Frequency unit: HZ */
|
||||
#define RT_SENSOR_UNIT_ONE (10) /* Dimensionless quantity unit: 1 */
|
||||
#define RT_SENSOR_UNIT_BPM (11) /* Heart rate unit: bpm */
|
||||
#define RT_SENSOR_UNIT_MM (12) /* Distance unit: mm */
|
||||
#define RT_SENSOR_UNIT_MN (13) /* Force unit: mN */
|
||||
#define RT_SENSOR_UNIT_PPM (14) /* Concentration unit: ppm */
|
||||
#define RT_SENSOR_UNIT_PPB (15) /* Concentration unit: ppb */
|
||||
#define RT_SENSOR_UNIT_DMS (16) /* Coordinates unit: DMS */
|
||||
#define RT_SENSOR_UNIT_DD (17) /* Coordinates unit: DD */
|
||||
#define RT_SENSOR_UNIT_MGM3 (18) /* Concentration unit: mg/m3 */
|
||||
/* Sensor communication interface types */
|
||||
|
||||
#define RT_SENSOR_INTF_I2C (1 << 0)
|
||||
#define RT_SENSOR_INTF_SPI (1 << 1)
|
||||
#define RT_SENSOR_INTF_UART (1 << 2)
|
||||
#define RT_SENSOR_INTF_ONEWIRE (1 << 3)
|
||||
|
||||
/* Sensor power mode types */
|
||||
|
||||
#define RT_SENSOR_POWER_NONE (0)
|
||||
#define RT_SENSOR_POWER_DOWN (1) /* power down mode */
|
||||
#define RT_SENSOR_POWER_NORMAL (2) /* normal-power mode */
|
||||
#define RT_SENSOR_POWER_LOW (3) /* low-power mode */
|
||||
#define RT_SENSOR_POWER_HIGH (4) /* high-power mode */
|
||||
|
||||
/* Sensor work mode types */
|
||||
|
||||
#define RT_SENSOR_MODE_NONE (0)
|
||||
#define RT_SENSOR_MODE_POLLING (1) /* One shot only read a data */
|
||||
#define RT_SENSOR_MODE_INT (2) /* TODO: One shot interrupt only read a data */
|
||||
#define RT_SENSOR_MODE_FIFO (3) /* TODO: One shot interrupt read all fifo data */
|
||||
|
||||
/* Sensor control cmd types */
|
||||
|
||||
#define RT_SENSOR_CTRL_GET_ID (0) /* Get device id */
|
||||
#define RT_SENSOR_CTRL_GET_INFO (1) /* Get sensor info */
|
||||
#define RT_SENSOR_CTRL_SET_RANGE (2) /* Set the measure range of sensor. unit is info of sensor */
|
||||
#define RT_SENSOR_CTRL_SET_ODR (3) /* Set output date rate. unit is HZ */
|
||||
#define RT_SENSOR_CTRL_SET_MODE (4) /* Set sensor's work mode. ex. RT_SENSOR_MODE_POLLING,RT_SENSOR_MODE_INT */
|
||||
#define RT_SENSOR_CTRL_SET_POWER (5) /* Set power mode. args type of sensor power mode. ex. RT_SENSOR_POWER_DOWN,RT_SENSOR_POWER_NORMAL */
|
||||
#define RT_SENSOR_CTRL_SELF_TEST (6) /* Take a self test */
|
||||
|
||||
#define RT_SENSOR_CTRL_USER_CMD_START 0x100 /* User commands should be greater than 0x100 */
|
||||
|
||||
struct rt_sensor_info
|
||||
{
|
||||
rt_uint8_t type; /* The sensor type */
|
||||
rt_uint8_t vendor; /* Vendor of sensors */
|
||||
const char *model; /* model name of sensor */
|
||||
rt_uint8_t unit; /* unit of measurement */
|
||||
rt_uint8_t intf_type; /* Communication interface type */
|
||||
rt_int32_t range_max; /* maximum range of this sensor's value. unit is 'unit' */
|
||||
rt_int32_t range_min; /* minimum range of this sensor's value. unit is 'unit' */
|
||||
rt_uint32_t period_min; /* Minimum measurement period,unit:ms. zero = not a constant rate */
|
||||
rt_uint8_t fifo_max;
|
||||
};
|
||||
|
||||
struct rt_sensor_intf
|
||||
{
|
||||
char *dev_name; /* The name of the communication device */
|
||||
rt_uint8_t type; /* Communication interface type */
|
||||
void *user_data; /* Private data for the sensor. ex. i2c addr,spi cs,control I/O */
|
||||
};
|
||||
|
||||
struct rt_sensor_config
|
||||
{
|
||||
struct rt_sensor_intf intf; /* sensor interface config */
|
||||
struct rt_device_pin_mode irq_pin; /* Interrupt pin, The purpose of this pin is to notification read data */
|
||||
rt_uint8_t mode; /* sensor work mode */
|
||||
rt_uint8_t power; /* sensor power mode */
|
||||
rt_uint16_t odr; /* sensor out data rate */
|
||||
rt_int32_t range; /* sensor range of measurement */
|
||||
};
|
||||
|
||||
typedef struct rt_sensor_device *rt_sensor_t;
|
||||
|
||||
struct rt_sensor_device
|
||||
{
|
||||
struct rt_device parent; /* The standard device */
|
||||
|
||||
struct rt_sensor_info info; /* The sensor info data */
|
||||
struct rt_sensor_config config; /* The sensor config data */
|
||||
|
||||
void *data_buf; /* The buf of the data received */
|
||||
rt_size_t data_len; /* The size of the data received */
|
||||
|
||||
const struct rt_sensor_ops *ops; /* The sensor ops */
|
||||
|
||||
struct rt_sensor_module *module; /* The sensor module */
|
||||
|
||||
rt_err_t (*irq_handle)(rt_sensor_t sensor); /* Called when an interrupt is generated, registered by the driver */
|
||||
};
|
||||
|
||||
struct rt_sensor_module
|
||||
{
|
||||
rt_mutex_t lock; /* The module lock */
|
||||
|
||||
rt_sensor_t sen[RT_SENSOR_MODULE_MAX]; /* The module contains a list of sensors */
|
||||
rt_uint8_t sen_num; /* Number of sensors contained in the module */
|
||||
};
|
||||
|
||||
/* 3-axis Data Type */
|
||||
struct sensor_3_axis
|
||||
{
|
||||
rt_int32_t x;
|
||||
rt_int32_t y;
|
||||
rt_int32_t z;
|
||||
};
|
||||
|
||||
struct coordinates
|
||||
{
|
||||
double longitude;
|
||||
double latitude;
|
||||
};
|
||||
|
||||
struct rt_sensor_data
|
||||
{
|
||||
rt_uint32_t timestamp; /* The timestamp when the data was received */
|
||||
rt_uint8_t type; /* The sensor type of the data */
|
||||
union
|
||||
{
|
||||
struct sensor_3_axis acce; /* Accelerometer. unit: mG */
|
||||
struct sensor_3_axis gyro; /* Gyroscope. unit: mdps */
|
||||
struct sensor_3_axis mag; /* Magnetometer. unit: mGauss */
|
||||
struct coordinates coord; /* Coordinates unit: degrees */
|
||||
rt_int32_t temp; /* Temperature. unit: dCelsius */
|
||||
rt_int32_t humi; /* Relative humidity. unit: permillage */
|
||||
rt_int32_t baro; /* Pressure. unit: pascal (Pa) */
|
||||
rt_int32_t light; /* Light. unit: lux */
|
||||
rt_int32_t proximity; /* Distance. unit: centimeters */
|
||||
rt_int32_t hr; /* Heart rate. unit: bpm */
|
||||
rt_int32_t tvoc; /* TVOC. unit: permillage */
|
||||
rt_int32_t noise; /* Noise Loudness. unit: HZ */
|
||||
rt_uint32_t step; /* Step sensor. unit: 1 */
|
||||
rt_int32_t force; /* Force sensor. unit: mN */
|
||||
rt_uint32_t dust; /* Dust sensor. unit: ug/m3 */
|
||||
rt_uint32_t eco2; /* eCO2 sensor. unit: ppm */
|
||||
rt_uint32_t spo2; /* SpO2 sensor. unit: permillage */
|
||||
rt_uint32_t iaq; /* IAQ sensor. unit: 1 */
|
||||
rt_uint32_t etoh; /* EtOH sensor. unit: ppm */
|
||||
} data;
|
||||
};
|
||||
|
||||
struct rt_sensor_ops
|
||||
{
|
||||
rt_size_t (*fetch_data)(struct rt_sensor_device *sensor, void *buf, rt_size_t len);
|
||||
rt_err_t (*control)(struct rt_sensor_device *sensor, int cmd, void *arg);
|
||||
};
|
||||
|
||||
int rt_hw_sensor_register(rt_sensor_t sensor,
|
||||
const char *name,
|
||||
rt_uint32_t flag,
|
||||
void *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SENSOR_H__ */
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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_921600 921600
|
||||
#define BAUD_RATE_2000000 2000000
|
||||
#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 */
|
||||
|
||||
#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 \
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
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_size_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);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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_921600 921600
|
||||
#define BAUD_RATE_2000000 2000000
|
||||
#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
|
||||
|
||||
/* 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 */ \
|
||||
0 \
|
||||
}
|
||||
|
||||
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 reserved :6;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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_size_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);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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
|
||||
*/
|
||||
|
||||
#ifndef __SPI_H__
|
||||
#define __SPI_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <rtthread.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_uint32_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;
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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_size_t rt_spi_transfer(struct rt_spi_device *device,
|
||||
const void *send_buf,
|
||||
void *recv_buf,
|
||||
rt_size_t length);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
rt_inline rt_uint8_t rt_spi_sendrecv8(struct rt_spi_device *device,
|
||||
rt_uint8_t data)
|
||||
{
|
||||
rt_uint8_t value;
|
||||
|
||||
rt_spi_send_then_recv(device, &data, 1, &value, 1);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
rt_inline rt_uint16_t rt_spi_sendrecv16(struct rt_spi_device *device,
|
||||
rt_uint16_t data)
|
||||
{
|
||||
rt_uint16_t value;
|
||||
|
||||
rt_spi_send_then_recv(device, &data, 2, &value, 2);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -0,0 +1,578 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-10-01 Yi Qiu first version
|
||||
* 2013-04-26 aozima add DEVICEQUALIFIER support.
|
||||
* 2017-11-15 ZYH fix ep0 transform error
|
||||
*/
|
||||
|
||||
#ifndef __USB_COMMON_H__
|
||||
#define __USB_COMMON_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define RT_DEBUG_USB 0x00
|
||||
#define USB_DYNAMIC 0x00
|
||||
|
||||
#define USB_CLASS_DEVICE 0x00
|
||||
#define USB_CLASS_AUDIO 0x01
|
||||
#define USB_CLASS_CDC 0x02
|
||||
#define USB_CLASS_HID 0x03
|
||||
#define USB_CLASS_PHYSICAL 0x05
|
||||
#define USB_CLASS_IMAGE 0x06
|
||||
#define USB_CLASS_PRINTER 0x07
|
||||
#define USB_CLASS_MASS_STORAGE 0x08
|
||||
#define USB_CLASS_HUB 0x09
|
||||
#define USB_CLASS_CDC_DATA 0x0a
|
||||
#define USB_CLASS_SMART_CARD 0x0b
|
||||
#define USB_CLASS_SECURITY 0x0d
|
||||
#define USB_CLASS_VIDEO 0x0e
|
||||
#define USB_CLASS_HEALTHCARE 0x0f
|
||||
#define USB_CLASS_DIAG_DEVICE 0xdc
|
||||
#define USB_CLASS_WIRELESS 0xe0
|
||||
#define USB_CLASS_MISC 0xef
|
||||
#define USB_CLASS_APP_SPECIFIC 0xfe
|
||||
#define USB_CLASS_VEND_SPECIFIC 0xff
|
||||
|
||||
#define USB_DESC_TYPE_DEVICE 0x01
|
||||
#define USB_DESC_TYPE_CONFIGURATION 0x02
|
||||
#define USB_DESC_TYPE_STRING 0x03
|
||||
#define USB_DESC_TYPE_INTERFACE 0x04
|
||||
#define USB_DESC_TYPE_ENDPOINT 0x05
|
||||
#define USB_DESC_TYPE_DEVICEQUALIFIER 0x06
|
||||
#define USB_DESC_TYPE_OTHERSPEED 0x07
|
||||
#define USB_DESC_TYPE_IAD 0x0b
|
||||
#define USB_DESC_TYPE_HID 0x21
|
||||
#define USB_DESC_TYPE_REPORT 0x22
|
||||
#define USB_DESC_TYPE_PHYSICAL 0x23
|
||||
#define USB_DESC_TYPE_HUB 0x29
|
||||
|
||||
#define USB_DESC_LENGTH_DEVICE 0x12
|
||||
#define USB_DESC_LENGTH_CONFIG 0x9
|
||||
#define USB_DESC_LENGTH_IAD 0x8
|
||||
#define USB_DESC_LENGTH_STRING 0x4
|
||||
#define USB_DESC_LENGTH_INTERFACE 0x9
|
||||
#define USB_DESC_LENGTH_ENDPOINT 0x7
|
||||
|
||||
#define USB_REQ_TYPE_STANDARD 0x00
|
||||
#define USB_REQ_TYPE_CLASS 0x20
|
||||
#define USB_REQ_TYPE_VENDOR 0x40
|
||||
#define USB_REQ_TYPE_MASK 0x60
|
||||
|
||||
#define USB_REQ_TYPE_DIR_OUT 0x00
|
||||
#define USB_REQ_TYPE_DIR_IN 0x80
|
||||
|
||||
#define USB_REQ_TYPE_DEVICE 0x00
|
||||
#define USB_REQ_TYPE_INTERFACE 0x01
|
||||
#define USB_REQ_TYPE_ENDPOINT 0x02
|
||||
#define USB_REQ_TYPE_OTHER 0x03
|
||||
#define USB_REQ_TYPE_RECIPIENT_MASK 0x1f
|
||||
|
||||
#define USB_FEATURE_ENDPOINT_HALT 0x00
|
||||
#define USB_FEATURE_DEV_REMOTE_WAKEUP 0x01
|
||||
#define USB_FEATURE_TEST_MODE 0x02
|
||||
|
||||
#define USB_REQ_GET_STATUS 0x00
|
||||
#define USB_REQ_CLEAR_FEATURE 0x01
|
||||
#define USB_REQ_SET_FEATURE 0x03
|
||||
#define USB_REQ_SET_ADDRESS 0x05
|
||||
#define USB_REQ_GET_DESCRIPTOR 0x06
|
||||
#define USB_REQ_SET_DESCRIPTOR 0x07
|
||||
#define USB_REQ_GET_CONFIGURATION 0x08
|
||||
#define USB_REQ_SET_CONFIGURATION 0x09
|
||||
#define USB_REQ_GET_INTERFACE 0x0A
|
||||
#define USB_REQ_SET_INTERFACE 0x0B
|
||||
#define USB_REQ_SYNCH_FRAME 0x0C
|
||||
#define USB_REQ_SET_ENCRYPTION 0x0D
|
||||
#define USB_REQ_GET_ENCRYPTION 0x0E
|
||||
#define USB_REQ_RPIPE_ABORT 0x0E
|
||||
#define USB_REQ_SET_HANDSHAKE 0x0F
|
||||
#define USB_REQ_RPIPE_RESET 0x0F
|
||||
#define USB_REQ_GET_HANDSHAKE 0x10
|
||||
#define USB_REQ_SET_CONNECTION 0x11
|
||||
#define USB_REQ_SET_SECURITY_DATA 0x12
|
||||
#define USB_REQ_GET_SECURITY_DATA 0x13
|
||||
#define USB_REQ_SET_WUSB_DATA 0x14
|
||||
#define USB_REQ_LOOPBACK_DATA_WRITE 0x15
|
||||
#define USB_REQ_LOOPBACK_DATA_READ 0x16
|
||||
#define USB_REQ_SET_INTERFACE_DS 0x17
|
||||
|
||||
#define USB_STRING_LANGID_INDEX 0x00
|
||||
#define USB_STRING_MANU_INDEX 0x01
|
||||
#define USB_STRING_PRODUCT_INDEX 0x02
|
||||
#define USB_STRING_SERIAL_INDEX 0x03
|
||||
#define USB_STRING_CONFIG_INDEX 0x04
|
||||
#define USB_STRING_INTERFACE_INDEX 0x05
|
||||
#define USB_STRING_OS_INDEX 0x06
|
||||
#define USB_STRING_MAX 0xff
|
||||
|
||||
#define USB_STRING_OS "MSFT100A"
|
||||
|
||||
#define USB_PID_OUT 0x01
|
||||
#define USB_PID_ACK 0x02
|
||||
#define USB_PID_DATA0 0x03
|
||||
#define USB_PID_SOF 0x05
|
||||
#define USB_PID_IN 0x09
|
||||
#define USB_PID_NACK 0x0A
|
||||
#define USB_PID_DATA1 0x0B
|
||||
#define USB_PID_PRE 0x0C
|
||||
#define USB_PID_SETUP 0x0D
|
||||
#define USB_PID_STALL 0x0E
|
||||
|
||||
#define USB_EP_DESC_OUT 0x00
|
||||
#define USB_EP_DESC_IN 0x80
|
||||
#define USB_EP_DESC_NUM_MASK 0x0f
|
||||
|
||||
#define USB_EP_ATTR_CONTROL 0x00
|
||||
#define USB_EP_ATTR_ISOC 0x01
|
||||
#define USB_EP_ATTR_BULK 0x02
|
||||
#define USB_EP_ATTR_INT 0x03
|
||||
#define USB_EP_ATTR_TYPE_MASK 0x03
|
||||
|
||||
#define USB_EPNO_MASK 0x7f
|
||||
#define USB_DIR_OUT 0x00
|
||||
#define USB_DIR_IN 0x80
|
||||
#define USB_DIR_INOUT 0x40
|
||||
#define USB_DIR_MASK 0x80
|
||||
|
||||
#define ID_UNASSIGNED 0
|
||||
#define ID_ASSIGNED 1
|
||||
|
||||
#define RH_GET_PORT_STATUS 0
|
||||
#define RH_SET_PORT_STATUS 1
|
||||
#define RH_CLEAR_PORT_FEATURE 2
|
||||
#define RH_SET_PORT_FEATURE 3
|
||||
|
||||
#define USB_BUS_POWERED 0
|
||||
#define USB_SELF_POWERED 1
|
||||
#define USB_REMOTE_WAKEUP 1
|
||||
#define USB_EP_HALT 0
|
||||
|
||||
/*
|
||||
* Port feature numbers
|
||||
*/
|
||||
#define PORT_FEAT_CONNECTION 0
|
||||
#define PORT_FEAT_ENABLE 1
|
||||
#define PORT_FEAT_SUSPEND 2
|
||||
#define PORT_FEAT_OVER_CURRENT 3
|
||||
#define PORT_FEAT_RESET 4
|
||||
#define PORT_FEAT_POWER 8
|
||||
#define PORT_FEAT_LOWSPEED 9
|
||||
#define PORT_FEAT_HIGHSPEED 10
|
||||
#define PORT_FEAT_C_CONNECTION 16
|
||||
#define PORT_FEAT_C_ENABLE 17
|
||||
#define PORT_FEAT_C_SUSPEND 18
|
||||
#define PORT_FEAT_C_OVER_CURRENT 19
|
||||
#define PORT_FEAT_C_RESET 20
|
||||
|
||||
/*
|
||||
The HcRhPortStatus[1:NDP] register is used to control and report port events on a per-port
|
||||
basis. NumberDownstreamPorts represents the number of HcRhPortStatus registers that are
|
||||
implemented in hardware. The lower word is used to reflect the port status, whereas the upper
|
||||
word reflects the status change bits. Some status bits are implemented with special write behavior
|
||||
(see below). If a transaction (token through handshake) is in progress when a write to change
|
||||
port status occurs, the resulting port status change must be postponed until the transaction
|
||||
completes. Reserved bits should always be written '0'.
|
||||
*/
|
||||
#define PORT_CCS 0x00000001UL /* R:CurrentConnectStatus - W:ClearPortEnable */
|
||||
#define PORT_PES 0x00000002UL /* R:PortEnableStatus - W:SetPortEnable */
|
||||
#define PORT_PSS 0x00000004UL /* R:PortSuspendStatus - W:SetPortSuspend */
|
||||
#define PORT_POCI 0x00000008UL /* R:PortOverCurrentIndicator - W:ClearSuspendStatus */
|
||||
#define PORT_PRS 0x00000010UL /* R:PortResetStatus - W: SetPortReset */
|
||||
#define PORT_PPS 0x00000100UL /* R:PortPowerStatus - W: SetPortPower */
|
||||
#define PORT_LSDA 0x00000200UL /* R:LowSpeedDeviceAttached - W:ClearPortPower */
|
||||
#define PORT_CCSC 0x00010000UL
|
||||
#define PORT_PESC 0x00020000UL
|
||||
#define PORT_PSSC 0x00040000UL
|
||||
#define PORT_POCIC 0x00080000UL
|
||||
#define PORT_PRSC 0x00100000UL
|
||||
|
||||
/*
|
||||
*Hub Status & Hub Change bit masks
|
||||
*/
|
||||
#define HUB_STATUS_LOCAL_POWER 0x0001
|
||||
#define HUB_STATUS_OVERCURRENT 0x0002
|
||||
|
||||
#define HUB_CHANGE_LOCAL_POWER 0x0001
|
||||
#define HUB_CHANGE_OVERCURRENT 0x0002
|
||||
|
||||
#define USB_EP_ATTR(attr) (attr & USB_EP_ATTR_TYPE_MASK)
|
||||
#define USB_EP_DESC_NUM(addr) (addr & USB_EP_DESC_NUM_MASK)
|
||||
#define USB_EP_DIR(addr) ((addr & USB_DIR_MASK)>>7)
|
||||
|
||||
#define HID_REPORT_ID_KEYBOARD1 1
|
||||
#define HID_REPORT_ID_KEYBOARD2 2
|
||||
#define HID_REPORT_ID_KEYBOARD3 3
|
||||
#define HID_REPORT_ID_KEYBOARD4 7
|
||||
#define HID_REPORT_ID_MEDIA 4
|
||||
#define HID_REPORT_ID_GENERAL 5
|
||||
#define HID_REPORT_ID_MOUSE 6
|
||||
|
||||
/*
|
||||
* Time of usb timeout
|
||||
*/
|
||||
#ifndef USB_TIMEOUT_BASIC
|
||||
#define USB_TIMEOUT_BASIC (RT_TICK_PER_SECOND) /* 1s */
|
||||
#endif
|
||||
#ifndef USB_TIMEOUT_LONG
|
||||
#define USB_TIMEOUT_LONG (RT_TICK_PER_SECOND * 5) /* 5s */
|
||||
#endif
|
||||
#ifndef USB_DEBOUNCE_TIME
|
||||
#define USB_DEBOUNCE_TIME (RT_TICK_PER_SECOND / 5) /* 0.2s */
|
||||
#endif
|
||||
|
||||
#define uswap_32(x) \
|
||||
((((x) & 0xff000000) >> 24) | \
|
||||
(((x) & 0x00ff0000) >> 8) | \
|
||||
(((x) & 0x0000ff00) << 8) | \
|
||||
(((x) & 0x000000ff) << 24))
|
||||
|
||||
#define uswap_8(x) \
|
||||
(((rt_uint16_t)(*((rt_uint8_t *)(x)))) + \
|
||||
(((rt_uint16_t)(*(((rt_uint8_t *)(x)) + 1))) << 8))
|
||||
|
||||
typedef void (*func_callback)(void *context);
|
||||
typedef enum
|
||||
{
|
||||
USB_STATE_NOTATTACHED = 0,
|
||||
USB_STATE_ATTACHED,
|
||||
USB_STATE_POWERED,
|
||||
USB_STATE_RECONNECTING,
|
||||
USB_STATE_UNAUTHENTICATED,
|
||||
USB_STATE_DEFAULT,
|
||||
USB_STATE_ADDRESS,
|
||||
USB_STATE_CONFIGURED,
|
||||
USB_STATE_SUSPENDED
|
||||
}udevice_state_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STAGE_IDLE,
|
||||
STAGE_SETUP,
|
||||
STAGE_STATUS_IN,
|
||||
STAGE_STATUS_OUT,
|
||||
STAGE_DIN,
|
||||
STAGE_DOUT
|
||||
} uep0_stage_t;
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct usb_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t type;
|
||||
};
|
||||
typedef struct usb_descriptor* udesc_t;
|
||||
|
||||
struct udevice_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t type;
|
||||
rt_uint16_t bcdUSB;
|
||||
rt_uint8_t bDeviceClass;
|
||||
rt_uint8_t bDeviceSubClass;
|
||||
rt_uint8_t bDeviceProtocol;
|
||||
rt_uint8_t bMaxPacketSize0;
|
||||
rt_uint16_t idVendor;
|
||||
rt_uint16_t idProduct;
|
||||
rt_uint16_t bcdDevice;
|
||||
rt_uint8_t iManufacturer;
|
||||
rt_uint8_t iProduct;
|
||||
rt_uint8_t iSerialNumber;
|
||||
rt_uint8_t bNumConfigurations;
|
||||
};
|
||||
typedef struct udevice_descriptor* udev_desc_t;
|
||||
|
||||
struct uconfig_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t type;
|
||||
rt_uint16_t wTotalLength;
|
||||
rt_uint8_t bNumInterfaces;
|
||||
rt_uint8_t bConfigurationValue;
|
||||
rt_uint8_t iConfiguration;
|
||||
rt_uint8_t bmAttributes;
|
||||
rt_uint8_t MaxPower;
|
||||
rt_uint8_t data[2048];
|
||||
};
|
||||
typedef struct uconfig_descriptor* ucfg_desc_t;
|
||||
|
||||
struct uinterface_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t type;
|
||||
rt_uint8_t bInterfaceNumber;
|
||||
rt_uint8_t bAlternateSetting;
|
||||
rt_uint8_t bNumEndpoints;
|
||||
rt_uint8_t bInterfaceClass;
|
||||
rt_uint8_t bInterfaceSubClass;
|
||||
rt_uint8_t bInterfaceProtocol;
|
||||
rt_uint8_t iInterface;
|
||||
};
|
||||
typedef struct uinterface_descriptor* uintf_desc_t;
|
||||
|
||||
/* Interface Association Descriptor (IAD) */
|
||||
struct uiad_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t bDescriptorType;
|
||||
rt_uint8_t bFirstInterface;
|
||||
rt_uint8_t bInterfaceCount;
|
||||
rt_uint8_t bFunctionClass;
|
||||
rt_uint8_t bFunctionSubClass;
|
||||
rt_uint8_t bFunctionProtocol;
|
||||
rt_uint8_t iFunction;
|
||||
};
|
||||
typedef struct uiad_descriptor* uiad_desc_t;
|
||||
|
||||
struct uendpoint_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t type;
|
||||
rt_uint8_t bEndpointAddress;
|
||||
rt_uint8_t bmAttributes;
|
||||
rt_uint16_t wMaxPacketSize;
|
||||
rt_uint8_t bInterval;
|
||||
};
|
||||
typedef struct uendpoint_descriptor* uep_desc_t;
|
||||
|
||||
struct ustring_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t type;
|
||||
rt_uint8_t String[64];
|
||||
};
|
||||
typedef struct ustring_descriptor* ustr_desc_t;
|
||||
|
||||
struct uhub_descriptor
|
||||
{
|
||||
rt_uint8_t length;
|
||||
rt_uint8_t type;
|
||||
rt_uint8_t num_ports;
|
||||
rt_uint16_t characteristics;
|
||||
rt_uint8_t pwron_to_good; /* power on to power good */
|
||||
rt_uint8_t current;
|
||||
rt_uint8_t removable[8];
|
||||
rt_uint8_t pwr_ctl[8];
|
||||
};
|
||||
typedef struct uhub_descriptor* uhub_desc_t;
|
||||
|
||||
/* USB_DESC_TYPE_DEVICEQUALIFIER: Device Qualifier descriptor */
|
||||
struct usb_qualifier_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t bDescriptorType;
|
||||
|
||||
rt_uint16_t bcdUSB; // TODO: big-endian.
|
||||
rt_uint8_t bDeviceClass;
|
||||
rt_uint8_t bDeviceSubClass;
|
||||
rt_uint8_t bDeviceProtocol;
|
||||
rt_uint8_t bMaxPacketSize0;
|
||||
rt_uint8_t bNumConfigurations;
|
||||
rt_uint8_t bRESERVED;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct usb_os_header_comp_id_descriptor
|
||||
{
|
||||
rt_uint32_t dwLength;
|
||||
rt_uint16_t bcdVersion;
|
||||
rt_uint16_t wIndex;
|
||||
rt_uint8_t bCount;
|
||||
rt_uint8_t reserved[7];
|
||||
};
|
||||
typedef struct usb_os_header_comp_id_descriptor * usb_os_header_desc_t;
|
||||
|
||||
struct usb_os_function_comp_id_descriptor
|
||||
{
|
||||
rt_list_t list;
|
||||
rt_uint8_t bFirstInterfaceNumber;
|
||||
rt_uint8_t reserved1;
|
||||
rt_uint8_t compatibleID[8];
|
||||
rt_uint8_t subCompatibleID[8];
|
||||
rt_uint8_t reserved2[6];
|
||||
};
|
||||
typedef struct usb_os_function_comp_id_descriptor * usb_os_func_comp_id_desc_t;
|
||||
|
||||
struct usb_os_comp_id_descriptor
|
||||
{
|
||||
struct usb_os_header_comp_id_descriptor head_desc;
|
||||
rt_list_t func_desc;
|
||||
};
|
||||
typedef struct usb_os_comp_id_descriptor * usb_os_comp_id_desc_t;
|
||||
|
||||
struct usb_os_property_header
|
||||
{
|
||||
rt_uint32_t dwLength;
|
||||
rt_uint16_t bcdVersion;
|
||||
rt_uint16_t wIndex;
|
||||
rt_uint16_t wCount;
|
||||
};
|
||||
typedef struct usb_os_property_header * usb_os_property_header_t;
|
||||
struct usb_os_proerty
|
||||
{
|
||||
rt_uint32_t dwSize;
|
||||
rt_uint32_t dwPropertyDataType;
|
||||
rt_uint16_t wPropertyNameLength;
|
||||
const char * bPropertyName;
|
||||
rt_uint32_t dwPropertyDataLength;
|
||||
const char * bPropertyData;
|
||||
};
|
||||
typedef struct usb_os_proerty * usb_os_proerty_t;
|
||||
|
||||
// Value Description
|
||||
// 1 A NULL-terminated Unicode String (REG_SZ)
|
||||
// 2 A NULL-terminated Unicode String that includes environment variables (REG_EXPAND_SZ)
|
||||
// 3 Free-form binary (REG_BINARY)
|
||||
// 4 A little-endian 32-bit integer (REG_DWORD_LITTLE_ENDIAN)
|
||||
// 5 A big-endian 32-bit integer (REG_DWORD_BIG_ENDIAN)
|
||||
// 6 A NULL-terminated Unicode string that contains a symbolic link (REG_LINK)
|
||||
// 7 Multiple NULL-terminated Unicode strings (REG_MULTI_SZ)
|
||||
#define USB_OS_PROPERTY_TYPE_REG_SZ 0x01UL
|
||||
#define USB_OS_PROPERTY_TYPE_REG_EXPAND_SZ 0x02UL
|
||||
#define USB_OS_PROPERTY_TYPE_REG_BINARY 0x03UL
|
||||
#define USB_OS_PROPERTY_TYPE_REG_DWORD_LITTLE_ENDIAN 0x04UL
|
||||
#define USB_OS_PROPERTY_TYPE_REG_DWORD_BIG_ENDIAN 0x05UL
|
||||
#define USB_OS_PROPERTY_TYPE_REG_LINK 0x06UL
|
||||
#define USB_OS_PROPERTY_TYPE_REG_MULTI_SZ 0x07UL
|
||||
|
||||
#define USB_OS_PROPERTY_DESC(PropertyDataType,PropertyName,PropertyData) \
|
||||
{\
|
||||
.dwSize = sizeof(struct usb_os_proerty)-sizeof(const char *)*2\
|
||||
+sizeof(PropertyName)*2+sizeof(PropertyData)*2,\
|
||||
.dwPropertyDataType = PropertyDataType,\
|
||||
.wPropertyNameLength = sizeof(PropertyName)*2,\
|
||||
.bPropertyName = PropertyName,\
|
||||
.dwPropertyDataLength = sizeof(PropertyData)*2,\
|
||||
.bPropertyData = PropertyData\
|
||||
}
|
||||
|
||||
|
||||
#ifndef HID_SUB_DESCRIPTOR_MAX
|
||||
#define HID_SUB_DESCRIPTOR_MAX 1
|
||||
#endif
|
||||
|
||||
struct uhid_descriptor
|
||||
{
|
||||
rt_uint8_t bLength;
|
||||
rt_uint8_t type;
|
||||
rt_uint16_t bcdHID;
|
||||
rt_uint8_t bCountryCode;
|
||||
rt_uint8_t bNumDescriptors;
|
||||
struct hid_descriptor_list
|
||||
{
|
||||
rt_uint8_t type;
|
||||
rt_uint16_t wLength;
|
||||
}Descriptor[HID_SUB_DESCRIPTOR_MAX];
|
||||
};
|
||||
typedef struct uhid_descriptor* uhid_desc_t;
|
||||
|
||||
struct hid_report
|
||||
{
|
||||
rt_uint8_t report_id;
|
||||
rt_uint8_t report[63];
|
||||
rt_uint8_t size;
|
||||
};
|
||||
typedef struct hid_report* hid_report_t;
|
||||
extern void HID_Report_Received(hid_report_t report);
|
||||
|
||||
struct urequest
|
||||
{
|
||||
rt_uint8_t request_type;
|
||||
rt_uint8_t bRequest;
|
||||
rt_uint16_t wValue;
|
||||
rt_uint16_t wIndex;
|
||||
rt_uint16_t wLength;
|
||||
};
|
||||
typedef struct urequest* ureq_t;
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (a < b ? a : b)
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) (a > b ? a : b)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* the define related to mass storage
|
||||
*/
|
||||
#define USBREQ_GET_MAX_LUN 0xfe
|
||||
#define USBREQ_MASS_STORAGE_RESET 0xff
|
||||
|
||||
#define SIZEOF_CSW 0x0d
|
||||
#define SIZEOF_CBW 0x1f
|
||||
#define SIZEOF_INQUIRY_CMD 0x24
|
||||
#define SIZEOF_MODE_SENSE_6 0x4
|
||||
#define SIZEOF_READ_CAPACITIES 0xc
|
||||
#define SIZEOF_READ_CAPACITY 0x8
|
||||
#define SIZEOF_REQUEST_SENSE 0x12
|
||||
|
||||
#define CBWFLAGS_DIR_M 0x80
|
||||
#define CBWFLAGS_DIR_IN 0x80
|
||||
#define CBWFLAGS_DIR_OUT 0x00
|
||||
|
||||
#define SCSI_TEST_UNIT_READY 0x00
|
||||
#define SCSI_REQUEST_SENSE 0x03
|
||||
#define SCSI_INQUIRY_CMD 0x12
|
||||
#define SCSI_ALLOW_REMOVAL 0x1e
|
||||
#define SCSI_MODE_SENSE_6 0x1a
|
||||
#define SCSI_START_STOP 0x1b
|
||||
#define SCSI_READ_CAPACITIES 0x23
|
||||
#define SCSI_READ_CAPACITY 0x25
|
||||
#define SCSI_READ_10 0x28
|
||||
#define SCSI_WRITE_10 0x2a
|
||||
#define SCSI_VERIFY_10 0x2f
|
||||
|
||||
#define CBW_SIGNATURE 0x43425355
|
||||
#define CSW_SIGNATURE 0x53425355
|
||||
#define CBW_TAG_VALUE 0x12345678
|
||||
|
||||
struct ustorage_cbw
|
||||
{
|
||||
rt_uint32_t signature;
|
||||
rt_uint32_t tag;
|
||||
rt_uint32_t xfer_len;
|
||||
rt_uint8_t dflags;
|
||||
rt_uint8_t lun;
|
||||
rt_uint8_t cb_len;
|
||||
rt_uint8_t cb[16];
|
||||
};
|
||||
typedef struct ustorage_cbw* ustorage_cbw_t;
|
||||
|
||||
struct ustorage_csw
|
||||
{
|
||||
rt_uint32_t signature;
|
||||
rt_uint32_t tag;
|
||||
rt_int32_t data_reside;
|
||||
rt_uint8_t status;
|
||||
};
|
||||
typedef struct ustorage_csw* ustorage_csw_t;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
/*
|
||||
* USB device event loop thread configurations
|
||||
*/
|
||||
/* the stack size of USB thread */
|
||||
#ifndef RT_USBD_THREAD_STACK_SZ
|
||||
#define RT_USBD_THREAD_STACK_SZ 512
|
||||
#endif
|
||||
|
||||
/* the priority of USB thread */
|
||||
#ifndef RT_USBD_THREAD_PRIO
|
||||
#define RT_USBD_THREAD_PRIO 8
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,470 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-10-01 Yi Qiu first version
|
||||
* 2012-12-12 heyuanjie87 change endpoint and function handler
|
||||
* 2013-04-26 aozima add DEVICEQUALIFIER support.
|
||||
* 2017-11-15 ZYH fix ep0 transform error
|
||||
*/
|
||||
|
||||
#ifndef __USB_DEVICE_H__
|
||||
#define __USB_DEVICE_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "drivers/usb_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Vendor ID */
|
||||
#ifdef USB_VENDOR_ID
|
||||
#define _VENDOR_ID USB_VENDOR_ID
|
||||
#else
|
||||
#define _VENDOR_ID 0x0EFF
|
||||
#endif
|
||||
/* Product ID */
|
||||
#ifdef USB_PRODUCT_ID
|
||||
#define _PRODUCT_ID USB_PRODUCT_ID
|
||||
#else
|
||||
#define _PRODUCT_ID 0x0001
|
||||
#endif
|
||||
|
||||
#ifndef MAX_INTF_STR
|
||||
#define MAX_INTF_STR 20
|
||||
#endif
|
||||
|
||||
#define USB_BCD_DEVICE 0x0200 /* USB Specification Release Number in Binary-Coded Decimal */
|
||||
#define USB_BCD_VERSION 0x0200 /* USB 2.0 */
|
||||
#define EP0_IN_ADDR 0x80
|
||||
#define EP0_OUT_ADDR 0x00
|
||||
#define EP_HANDLER(ep, func, size) RT_ASSERT(ep != RT_NULL); ep->handler(func, size)
|
||||
#define EP_ADDRESS(ep) ep->ep_desc->bEndpointAddress
|
||||
#define EP_MAXPACKET(ep) ep->ep_desc->wMaxPacketSize
|
||||
#define FUNC_ENABLE(func) do{ \
|
||||
if(func->ops->enable != RT_NULL && \
|
||||
func->enabled == RT_FALSE) \
|
||||
{ \
|
||||
if(func->ops->enable(func) == RT_EOK) \
|
||||
func->enabled = RT_TRUE; \
|
||||
} \
|
||||
}while(0)
|
||||
#define FUNC_DISABLE(func) do{ \
|
||||
if(func->ops->disable != RT_NULL && \
|
||||
func->enabled == RT_TRUE) \
|
||||
{ \
|
||||
func->enabled = RT_FALSE; \
|
||||
func->ops->disable(func); \
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
struct ufunction;
|
||||
struct udevice;
|
||||
struct uendpoint;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
/* request to read full count */
|
||||
UIO_REQUEST_READ_FULL,
|
||||
/* request to read any count */
|
||||
UIO_REQUEST_READ_BEST,
|
||||
/* request to write full count */
|
||||
UIO_REQUEST_WRITE,
|
||||
}UIO_REQUEST_TYPE;
|
||||
|
||||
struct udcd_ops
|
||||
{
|
||||
rt_err_t (*set_address)(rt_uint8_t address);
|
||||
rt_err_t (*set_config)(rt_uint8_t address);
|
||||
rt_err_t (*ep_set_stall)(rt_uint8_t address);
|
||||
rt_err_t (*ep_clear_stall)(rt_uint8_t address);
|
||||
rt_err_t (*ep_enable)(struct uendpoint* ep);
|
||||
rt_err_t (*ep_disable)(struct uendpoint* ep);
|
||||
rt_size_t (*ep_read_prepare)(rt_uint8_t address, void *buffer, rt_size_t size);
|
||||
rt_size_t (*ep_read)(rt_uint8_t address, void *buffer);
|
||||
rt_size_t (*ep_write)(rt_uint8_t address, void *buffer, rt_size_t size);
|
||||
rt_err_t (*ep0_send_status)(void);
|
||||
rt_err_t (*suspend)(void);
|
||||
rt_err_t (*wakeup)(void);
|
||||
};
|
||||
|
||||
struct ep_id
|
||||
{
|
||||
rt_uint8_t addr;
|
||||
rt_uint8_t type;
|
||||
rt_uint8_t dir;
|
||||
rt_uint16_t maxpacket;
|
||||
rt_uint8_t status;
|
||||
};
|
||||
|
||||
typedef rt_err_t (*udep_handler_t)(struct ufunction* func, rt_size_t size);
|
||||
|
||||
struct uio_request
|
||||
{
|
||||
rt_list_t list;
|
||||
UIO_REQUEST_TYPE req_type;
|
||||
rt_uint8_t* buffer;
|
||||
rt_size_t size;
|
||||
rt_size_t remain_size;
|
||||
};
|
||||
typedef struct uio_request* uio_request_t;
|
||||
|
||||
struct uendpoint
|
||||
{
|
||||
rt_list_t list;
|
||||
uep_desc_t ep_desc;
|
||||
rt_list_t request_list;
|
||||
struct uio_request request;
|
||||
rt_uint8_t* buffer;
|
||||
rt_bool_t stalled;
|
||||
struct ep_id* id;
|
||||
udep_handler_t handler;
|
||||
rt_err_t (*rx_indicate)(struct udevice* dev, rt_size_t size);
|
||||
};
|
||||
typedef struct uendpoint* uep_t;
|
||||
|
||||
struct udcd
|
||||
{
|
||||
struct rt_device parent;
|
||||
const struct udcd_ops* ops;
|
||||
struct uendpoint ep0;
|
||||
uep0_stage_t stage;
|
||||
struct ep_id* ep_pool;
|
||||
rt_uint8_t device_is_hs;
|
||||
};
|
||||
typedef struct udcd* udcd_t;
|
||||
|
||||
struct ualtsetting
|
||||
{
|
||||
rt_list_t list;
|
||||
uintf_desc_t intf_desc;
|
||||
void* desc;
|
||||
rt_size_t desc_size;
|
||||
rt_list_t ep_list;
|
||||
};
|
||||
typedef struct ualtsetting* ualtsetting_t;
|
||||
|
||||
typedef rt_err_t (*uintf_handler_t)(struct ufunction* func, ureq_t setup);
|
||||
|
||||
struct uinterface
|
||||
{
|
||||
rt_list_t list;
|
||||
rt_uint8_t intf_num;
|
||||
ualtsetting_t curr_setting;
|
||||
rt_list_t setting_list;
|
||||
uintf_handler_t handler;
|
||||
};
|
||||
typedef struct uinterface* uintf_t;
|
||||
|
||||
struct ufunction_ops
|
||||
{
|
||||
rt_err_t (*enable)(struct ufunction* func);
|
||||
rt_err_t (*disable)(struct ufunction* func);
|
||||
rt_err_t (*sof_handler)(struct ufunction* func);
|
||||
};
|
||||
typedef struct ufunction_ops* ufunction_ops_t;
|
||||
|
||||
struct ufunction
|
||||
{
|
||||
rt_list_t list;
|
||||
ufunction_ops_t ops;
|
||||
struct udevice* device;
|
||||
udev_desc_t dev_desc;
|
||||
void* user_data;
|
||||
rt_bool_t enabled;
|
||||
|
||||
rt_list_t intf_list;
|
||||
};
|
||||
typedef struct ufunction* ufunction_t;
|
||||
|
||||
struct uconfig
|
||||
{
|
||||
rt_list_t list;
|
||||
struct uconfig_descriptor cfg_desc;
|
||||
rt_list_t func_list;
|
||||
};
|
||||
typedef struct uconfig* uconfig_t;
|
||||
|
||||
struct udevice
|
||||
{
|
||||
rt_list_t list;
|
||||
struct udevice_descriptor dev_desc;
|
||||
|
||||
struct usb_qualifier_descriptor * dev_qualifier;
|
||||
usb_os_comp_id_desc_t os_comp_id_desc;
|
||||
const char** str;
|
||||
const char *str_intf[MAX_INTF_STR];
|
||||
udevice_state_t state;
|
||||
rt_list_t cfg_list;
|
||||
uconfig_t curr_cfg;
|
||||
rt_uint8_t nr_intf;
|
||||
|
||||
udcd_t dcd;
|
||||
};
|
||||
typedef struct udevice* udevice_t;
|
||||
|
||||
struct udclass
|
||||
{
|
||||
rt_list_t list;
|
||||
ufunction_t (*rt_usbd_function_create)(udevice_t device);
|
||||
};
|
||||
typedef struct udclass* udclass_t;
|
||||
|
||||
enum udev_msg_type
|
||||
{
|
||||
USB_MSG_SETUP_NOTIFY,
|
||||
USB_MSG_DATA_NOTIFY,
|
||||
USB_MSG_EP0_OUT,
|
||||
USB_MSG_EP_CLEAR_FEATURE,
|
||||
USB_MSG_SOF,
|
||||
USB_MSG_RESET,
|
||||
USB_MSG_PLUG_IN,
|
||||
/* we don't need to add a "PLUG_IN" event because after the cable is
|
||||
* plugged in(before any SETUP) the classed have nothing to do. If the host
|
||||
* is ready, it will send RESET and we will have USB_MSG_RESET. So, a RESET
|
||||
* should reset and run the class while plug_in is not. */
|
||||
USB_MSG_PLUG_OUT,
|
||||
};
|
||||
typedef enum udev_msg_type udev_msg_type;
|
||||
|
||||
struct ep_msg
|
||||
{
|
||||
rt_size_t size;
|
||||
rt_uint8_t ep_addr;
|
||||
};
|
||||
|
||||
struct udev_msg
|
||||
{
|
||||
udev_msg_type type;
|
||||
udcd_t dcd;
|
||||
union
|
||||
{
|
||||
struct ep_msg ep_msg;
|
||||
struct urequest setup;
|
||||
} content;
|
||||
};
|
||||
typedef struct udev_msg* udev_msg_t;
|
||||
|
||||
int rt_usbd_class_list_init(void);
|
||||
udevice_t rt_usbd_device_new(void);
|
||||
uconfig_t rt_usbd_config_new(void);
|
||||
ufunction_t rt_usbd_function_new(udevice_t device, udev_desc_t dev_desc,
|
||||
ufunction_ops_t ops);
|
||||
uintf_t rt_usbd_interface_new(udevice_t device, uintf_handler_t handler);
|
||||
uep_t rt_usbd_endpoint_new(uep_desc_t ep_desc, udep_handler_t handler);
|
||||
ualtsetting_t rt_usbd_altsetting_new(rt_size_t desc_size);
|
||||
|
||||
rt_err_t rt_usbd_core_init(void);
|
||||
rt_err_t rt_usb_device_init(void);
|
||||
rt_err_t rt_usbd_event_signal(struct udev_msg* msg);
|
||||
rt_err_t rt_usbd_device_set_controller(udevice_t device, udcd_t dcd);
|
||||
rt_err_t rt_usbd_device_set_descriptor(udevice_t device, udev_desc_t dev_desc);
|
||||
rt_err_t rt_usbd_device_set_string(udevice_t device, const char** ustring);
|
||||
rt_err_t rt_usbd_device_set_interface_string(udevice_t device, int index, const char* string);
|
||||
rt_err_t rt_usbd_device_set_qualifier(udevice_t device, struct usb_qualifier_descriptor* qualifier);
|
||||
rt_err_t rt_usbd_device_set_os_comp_id_desc(udevice_t device, usb_os_comp_id_desc_t os_comp_id_desc);
|
||||
rt_err_t rt_usbd_device_add_config(udevice_t device, uconfig_t cfg);
|
||||
rt_err_t rt_usbd_config_add_function(uconfig_t cfg, ufunction_t func);
|
||||
rt_err_t rt_usbd_class_register(udclass_t udclass);
|
||||
rt_err_t rt_usbd_function_add_interface(ufunction_t func, uintf_t intf);
|
||||
rt_err_t rt_usbd_interface_add_altsetting(uintf_t intf, ualtsetting_t setting);
|
||||
rt_err_t rt_usbd_altsetting_add_endpoint(ualtsetting_t setting, uep_t ep);
|
||||
rt_err_t rt_usbd_os_comp_id_desc_add_os_func_comp_id_desc(usb_os_comp_id_desc_t os_comp_id_desc, usb_os_func_comp_id_desc_t os_func_comp_id_desc);
|
||||
rt_err_t rt_usbd_altsetting_config_descriptor(ualtsetting_t setting, const void* desc, rt_off_t intf_pos);
|
||||
rt_err_t rt_usbd_set_config(udevice_t device, rt_uint8_t value);
|
||||
rt_err_t rt_usbd_set_altsetting(uintf_t intf, rt_uint8_t value);
|
||||
|
||||
udevice_t rt_usbd_find_device(udcd_t dcd);
|
||||
uconfig_t rt_usbd_find_config(udevice_t device, rt_uint8_t value);
|
||||
uintf_t rt_usbd_find_interface(udevice_t device, rt_uint8_t value, ufunction_t *pfunc);
|
||||
uep_t rt_usbd_find_endpoint(udevice_t device, ufunction_t* pfunc, rt_uint8_t ep_addr);
|
||||
rt_size_t rt_usbd_io_request(udevice_t device, uep_t ep, uio_request_t req);
|
||||
rt_size_t rt_usbd_ep0_write(udevice_t device, void *buffer, rt_size_t size);
|
||||
rt_size_t rt_usbd_ep0_read(udevice_t device, void *buffer, rt_size_t size,
|
||||
rt_err_t (*rx_ind)(udevice_t device, rt_size_t size));
|
||||
|
||||
int rt_usbd_vcom_class_register(void);
|
||||
int rt_usbd_ecm_class_register(void);
|
||||
int rt_usbd_hid_class_register(void);
|
||||
int rt_usbd_msc_class_register(void);
|
||||
int rt_usbd_rndis_class_register(void);
|
||||
int rt_usbd_winusb_class_register(void);
|
||||
|
||||
#ifdef RT_USB_DEVICE_COMPOSITE
|
||||
rt_err_t rt_usbd_function_set_iad(ufunction_t func, uiad_desc_t iad_desc);
|
||||
#endif
|
||||
|
||||
rt_err_t rt_usbd_set_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index);
|
||||
rt_err_t rt_usbd_clear_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index);
|
||||
rt_err_t rt_usbd_ep_set_stall(udevice_t device, uep_t ep);
|
||||
rt_err_t rt_usbd_ep_clear_stall(udevice_t device, uep_t ep);
|
||||
rt_err_t rt_usbd_ep0_set_stall(udevice_t device);
|
||||
rt_err_t rt_usbd_ep0_clear_stall(udevice_t device);
|
||||
rt_err_t rt_usbd_ep0_setup_handler(udcd_t dcd, struct urequest* setup);
|
||||
rt_err_t rt_usbd_ep0_in_handler(udcd_t dcd);
|
||||
rt_err_t rt_usbd_ep0_out_handler(udcd_t dcd, rt_size_t size);
|
||||
rt_err_t rt_usbd_ep_in_handler(udcd_t dcd, rt_uint8_t address, rt_size_t size);
|
||||
rt_err_t rt_usbd_ep_out_handler(udcd_t dcd, rt_uint8_t address, rt_size_t size);
|
||||
rt_err_t rt_usbd_reset_handler(udcd_t dcd);
|
||||
rt_err_t rt_usbd_connect_handler(udcd_t dcd);
|
||||
rt_err_t rt_usbd_disconnect_handler(udcd_t dcd);
|
||||
rt_err_t rt_usbd_sof_handler(udcd_t dcd);
|
||||
|
||||
rt_inline rt_err_t dcd_set_address(udcd_t dcd, rt_uint8_t address)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
RT_ASSERT(dcd->ops != RT_NULL);
|
||||
RT_ASSERT(dcd->ops->set_address != RT_NULL);
|
||||
|
||||
return dcd->ops->set_address(address);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t dcd_set_config(udcd_t dcd, rt_uint8_t address)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
RT_ASSERT(dcd->ops != RT_NULL);
|
||||
RT_ASSERT(dcd->ops->set_config != RT_NULL);
|
||||
|
||||
return dcd->ops->set_config(address);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t dcd_ep_enable(udcd_t dcd, uep_t ep)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
RT_ASSERT(dcd->ops != RT_NULL);
|
||||
RT_ASSERT(dcd->ops->ep_enable != RT_NULL);
|
||||
|
||||
return dcd->ops->ep_enable(ep);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t dcd_ep_disable(udcd_t dcd, uep_t ep)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
RT_ASSERT(dcd->ops != RT_NULL);
|
||||
RT_ASSERT(dcd->ops->ep_disable != RT_NULL);
|
||||
|
||||
return dcd->ops->ep_disable(ep);
|
||||
}
|
||||
|
||||
rt_inline rt_size_t dcd_ep_read_prepare(udcd_t dcd, rt_uint8_t address, void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
RT_ASSERT(dcd->ops != RT_NULL);
|
||||
|
||||
if(dcd->ops->ep_read_prepare != RT_NULL)
|
||||
{
|
||||
return dcd->ops->ep_read_prepare(address, buffer, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
rt_inline rt_size_t dcd_ep_read(udcd_t dcd, rt_uint8_t address, void *buffer)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
RT_ASSERT(dcd->ops != RT_NULL);
|
||||
|
||||
if(dcd->ops->ep_read != RT_NULL)
|
||||
{
|
||||
return dcd->ops->ep_read(address, buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
rt_inline rt_size_t dcd_ep_write(udcd_t dcd, rt_uint8_t address, void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
RT_ASSERT(dcd->ops != RT_NULL);
|
||||
RT_ASSERT(dcd->ops->ep_write != RT_NULL);
|
||||
|
||||
return dcd->ops->ep_write(address, buffer, size);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t dcd_ep0_send_status(udcd_t dcd)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
RT_ASSERT(dcd->ops != RT_NULL);
|
||||
RT_ASSERT(dcd->ops->ep0_send_status != RT_NULL);
|
||||
|
||||
return dcd->ops->ep0_send_status();
|
||||
}
|
||||
|
||||
rt_inline rt_err_t dcd_ep_set_stall(udcd_t dcd, rt_uint8_t address)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
RT_ASSERT(dcd->ops != RT_NULL);
|
||||
RT_ASSERT(dcd->ops->ep_set_stall != RT_NULL);
|
||||
|
||||
return dcd->ops->ep_set_stall(address);
|
||||
}
|
||||
|
||||
rt_inline rt_err_t dcd_ep_clear_stall(udcd_t dcd, rt_uint8_t address)
|
||||
{
|
||||
RT_ASSERT(dcd != RT_NULL);
|
||||
RT_ASSERT(dcd->ops != RT_NULL);
|
||||
RT_ASSERT(dcd->ops->ep_clear_stall != RT_NULL);
|
||||
|
||||
return dcd->ops->ep_clear_stall(address);
|
||||
}
|
||||
rt_inline void usbd_os_proerty_descriptor_send(ufunction_t func, ureq_t setup, usb_os_proerty_t usb_os_proerty, rt_uint8_t number_of_proerty)
|
||||
{
|
||||
struct usb_os_property_header header;
|
||||
static rt_uint8_t * data;
|
||||
rt_uint8_t * pdata;
|
||||
rt_uint8_t index,i;
|
||||
if(data == RT_NULL)
|
||||
{
|
||||
header.dwLength = sizeof(struct usb_os_property_header);
|
||||
header.bcdVersion = 0x0100;
|
||||
header.wIndex = 0x05;
|
||||
header.wCount = number_of_proerty;
|
||||
for(index = 0;index < number_of_proerty;index++)
|
||||
{
|
||||
header.dwLength += usb_os_proerty[index].dwSize;
|
||||
}
|
||||
data = (rt_uint8_t *)rt_malloc(header.dwLength);
|
||||
RT_ASSERT(data != RT_NULL);
|
||||
pdata = data;
|
||||
rt_memcpy((void *)pdata,(void *)&header,sizeof(struct usb_os_property_header));
|
||||
pdata += sizeof(struct usb_os_property_header);
|
||||
for(index = 0;index < number_of_proerty;index++)
|
||||
{
|
||||
rt_memcpy((void *)pdata,(void *)&usb_os_proerty[index],10);
|
||||
pdata += 10;
|
||||
for(i = 0;i < usb_os_proerty[index].wPropertyNameLength/2;i++)
|
||||
{
|
||||
*pdata = usb_os_proerty[index].bPropertyName[i];
|
||||
pdata++;
|
||||
*pdata = 0;
|
||||
pdata++;
|
||||
}
|
||||
*((rt_uint32_t *)pdata) = usb_os_proerty[index].dwPropertyDataLength;
|
||||
pdata += 4;
|
||||
for(i = 0;i < usb_os_proerty[index].dwPropertyDataLength/2;i++)
|
||||
{
|
||||
*pdata = usb_os_proerty[index].bPropertyData[i];
|
||||
pdata++;
|
||||
*pdata = 0;
|
||||
pdata++;
|
||||
}
|
||||
}
|
||||
}
|
||||
rt_usbd_ep0_write(func->device, data, setup->wLength);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-3-12 Yi Qiu first version
|
||||
* 2021-02-23 Leslie Lee provide possibility for multi usb host
|
||||
*/
|
||||
|
||||
#ifndef __RT_USB_HOST_H__
|
||||
#define __RT_USB_HOST_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "usb_common.h"
|
||||
|
||||
#define USB_MAX_DEVICE 0x20
|
||||
#define USB_MAX_INTERFACE 0x08
|
||||
#define USB_HUB_PORT_NUM 0x04
|
||||
#define SIZEOF_USB_REQUEST 0x08
|
||||
|
||||
#define DEV_STATUS_IDLE 0x00
|
||||
#define DEV_STATUS_BUSY 0x01
|
||||
#define DEV_STATUS_ERROR 0x02
|
||||
|
||||
#define UPIPE_STATUS_OK 0x00
|
||||
#define UPIPE_STATUS_STALL 0x01
|
||||
#define UPIPE_STATUS_ERROR 0x02
|
||||
|
||||
#define USBH_PID_SETUP 0x00
|
||||
#define USBH_PID_DATA 0x01
|
||||
|
||||
struct uhcd;
|
||||
struct uhintf;
|
||||
struct uhub;
|
||||
struct upipe;
|
||||
|
||||
struct uclass_driver
|
||||
{
|
||||
rt_list_t list;
|
||||
int class_code;
|
||||
int subclass_code;
|
||||
|
||||
rt_err_t (*enable)(void* arg);
|
||||
rt_err_t (*disable)(void* arg);
|
||||
|
||||
void* user_data;
|
||||
};
|
||||
typedef struct uclass_driver* ucd_t;
|
||||
|
||||
struct uprotocal
|
||||
{
|
||||
rt_list_t list;
|
||||
int pro_id;
|
||||
|
||||
rt_err_t (*init)(void* arg);
|
||||
rt_err_t (*callback)(void* arg);
|
||||
};
|
||||
typedef struct uprotocal* uprotocal_t;
|
||||
|
||||
struct uinstance
|
||||
{
|
||||
struct rt_device parent;
|
||||
|
||||
struct udevice_descriptor dev_desc;
|
||||
ucfg_desc_t cfg_desc;
|
||||
struct uhcd *hcd;
|
||||
|
||||
struct upipe * pipe_ep0_out;
|
||||
struct upipe * pipe_ep0_in;
|
||||
rt_list_t pipe;
|
||||
|
||||
rt_uint8_t status;
|
||||
rt_uint8_t type;
|
||||
rt_uint8_t index;
|
||||
rt_uint8_t address;
|
||||
rt_uint8_t speed;
|
||||
rt_uint8_t max_packet_size;
|
||||
rt_uint8_t port;
|
||||
|
||||
struct uhub* parent_hub;
|
||||
struct uhintf* intf[USB_MAX_INTERFACE];
|
||||
};
|
||||
typedef struct uinstance* uinst_t;
|
||||
|
||||
struct uhintf
|
||||
{
|
||||
struct uinstance* device;
|
||||
uintf_desc_t intf_desc;
|
||||
|
||||
ucd_t drv;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct upipe
|
||||
{
|
||||
rt_list_t list;
|
||||
rt_uint8_t pipe_index;
|
||||
rt_uint32_t status;
|
||||
struct uendpoint_descriptor ep;
|
||||
uinst_t inst;
|
||||
func_callback callback;
|
||||
void* user_data;
|
||||
};
|
||||
typedef struct upipe* upipe_t;
|
||||
|
||||
struct uhub
|
||||
{
|
||||
struct uhub_descriptor hub_desc;
|
||||
rt_uint8_t num_ports;
|
||||
rt_uint32_t port_status[USB_HUB_PORT_NUM];
|
||||
struct uinstance* child[USB_HUB_PORT_NUM];
|
||||
|
||||
rt_bool_t is_roothub;
|
||||
|
||||
rt_uint8_t buffer[8];
|
||||
struct uinstance* self;
|
||||
struct uhcd *hcd;
|
||||
};
|
||||
typedef struct uhub* uhub_t;
|
||||
|
||||
struct uhcd_ops
|
||||
{
|
||||
rt_err_t (*reset_port) (rt_uint8_t port);
|
||||
int (*pipe_xfer) (upipe_t pipe, rt_uint8_t token, void* buffer, int nbytes, int timeout);
|
||||
rt_err_t (*open_pipe) (upipe_t pipe);
|
||||
rt_err_t (*close_pipe) (upipe_t pipe);
|
||||
};
|
||||
typedef struct uhcd_ops* uhcd_ops_t;
|
||||
struct uhcd
|
||||
{
|
||||
struct rt_device parent;
|
||||
uhcd_ops_t ops;
|
||||
rt_uint8_t num_ports;
|
||||
uhub_t roothub;
|
||||
struct rt_messagequeue *usb_mq;
|
||||
};
|
||||
typedef struct uhcd* uhcd_t;
|
||||
|
||||
enum uhost_msg_type
|
||||
{
|
||||
USB_MSG_CONNECT_CHANGE,
|
||||
USB_MSG_CALLBACK,
|
||||
};
|
||||
typedef enum uhost_msg_type uhost_msg_type;
|
||||
|
||||
struct uhost_msg
|
||||
{
|
||||
uhost_msg_type type;
|
||||
union
|
||||
{
|
||||
struct uhub* hub;
|
||||
struct
|
||||
{
|
||||
func_callback function;
|
||||
void *context;
|
||||
}cb;
|
||||
}content;
|
||||
};
|
||||
typedef struct uhost_msg* uhost_msg_t;
|
||||
|
||||
/* usb host system interface */
|
||||
rt_err_t rt_usb_host_init(const char *name);
|
||||
void rt_usbh_hub_init(struct uhcd *hcd);
|
||||
|
||||
/* usb host core interface */
|
||||
struct uinstance* rt_usbh_alloc_instance(uhcd_t uhcd);
|
||||
rt_err_t rt_usbh_attatch_instance(struct uinstance* device);
|
||||
rt_err_t rt_usbh_detach_instance(struct uinstance* device);
|
||||
rt_err_t rt_usbh_get_descriptor(struct uinstance* device, rt_uint8_t type, void* buffer, int nbytes);
|
||||
rt_err_t rt_usbh_set_configure(struct uinstance* device, int config);
|
||||
rt_err_t rt_usbh_set_address(struct uinstance* device);
|
||||
rt_err_t rt_usbh_set_interface(struct uinstance* device, int intf);
|
||||
rt_err_t rt_usbh_clear_feature(struct uinstance* device, int endpoint, int feature);
|
||||
rt_err_t rt_usbh_get_interface_descriptor(ucfg_desc_t cfg_desc, int num, uintf_desc_t* intf_desc);
|
||||
rt_err_t rt_usbh_get_endpoint_descriptor(uintf_desc_t intf_desc, int num, uep_desc_t* ep_desc);
|
||||
|
||||
/* usb class driver interface */
|
||||
rt_err_t rt_usbh_class_driver_init(void);
|
||||
rt_err_t rt_usbh_class_driver_register(ucd_t drv);
|
||||
rt_err_t rt_usbh_class_driver_unregister(ucd_t drv);
|
||||
rt_err_t rt_usbh_class_driver_enable(ucd_t drv, void* args);
|
||||
rt_err_t rt_usbh_class_driver_disable(ucd_t drv, void* args);
|
||||
ucd_t rt_usbh_class_driver_find(int class_code, int subclass_code);
|
||||
|
||||
/* usb class driver implement */
|
||||
ucd_t rt_usbh_class_driver_hub(void);
|
||||
ucd_t rt_usbh_class_driver_storage(void);
|
||||
|
||||
|
||||
|
||||
/* usb hub interface */
|
||||
rt_err_t rt_usbh_hub_get_descriptor(struct uinstance* device, rt_uint8_t *buffer,
|
||||
rt_size_t size);
|
||||
rt_err_t rt_usbh_hub_get_status(struct uinstance* device, rt_uint32_t* buffer);
|
||||
rt_err_t rt_usbh_hub_get_port_status(uhub_t uhub, rt_uint16_t port,
|
||||
rt_uint32_t* buffer);
|
||||
rt_err_t rt_usbh_hub_clear_port_feature(uhub_t uhub, rt_uint16_t port,
|
||||
rt_uint16_t feature);
|
||||
rt_err_t rt_usbh_hub_set_port_feature(uhub_t uhub, rt_uint16_t port,
|
||||
rt_uint16_t feature);
|
||||
rt_err_t rt_usbh_hub_reset_port(uhub_t uhub, rt_uint16_t port);
|
||||
rt_err_t rt_usbh_event_signal(uhcd_t uhcd, struct uhost_msg* msg);
|
||||
|
||||
|
||||
void rt_usbh_root_hub_connect_handler(struct uhcd *hcd, rt_uint8_t port, rt_bool_t isHS);
|
||||
void rt_usbh_root_hub_disconnect_handler(struct uhcd *hcd, rt_uint8_t port);
|
||||
|
||||
/* usb host controller driver interface */
|
||||
rt_inline rt_err_t rt_usb_instance_add_pipe(uinst_t inst, upipe_t pipe)
|
||||
{
|
||||
RT_ASSERT(inst != RT_NULL);
|
||||
RT_ASSERT(pipe != RT_NULL);
|
||||
rt_list_insert_before(&inst->pipe, &pipe->list);
|
||||
return RT_EOK;
|
||||
}
|
||||
rt_inline upipe_t rt_usb_instance_find_pipe(uinst_t inst,rt_uint8_t ep_address)
|
||||
{
|
||||
rt_list_t * l;
|
||||
for(l = inst->pipe.next;l != &inst->pipe;l = l->next)
|
||||
{
|
||||
if(rt_list_entry(l,struct upipe,list)->ep.bEndpointAddress == ep_address)
|
||||
{
|
||||
return rt_list_entry(l,struct upipe,list);
|
||||
}
|
||||
}
|
||||
return RT_NULL;
|
||||
}
|
||||
rt_inline rt_err_t rt_usb_hcd_alloc_pipe(uhcd_t hcd, upipe_t* pipe, uinst_t inst, uep_desc_t ep)
|
||||
{
|
||||
*pipe = (upipe_t)rt_malloc(sizeof(struct upipe));
|
||||
if(*pipe == RT_NULL)
|
||||
{
|
||||
return RT_ERROR;
|
||||
}
|
||||
rt_memset(*pipe,0,sizeof(struct upipe));
|
||||
(*pipe)->inst = inst;
|
||||
rt_memcpy(&(*pipe)->ep,ep,sizeof(struct uendpoint_descriptor));
|
||||
return hcd->ops->open_pipe(*pipe);
|
||||
}
|
||||
rt_inline void rt_usb_pipe_add_callback(upipe_t pipe, func_callback callback)
|
||||
{
|
||||
pipe->callback = callback;
|
||||
}
|
||||
|
||||
rt_inline rt_err_t rt_usb_hcd_free_pipe(uhcd_t hcd, upipe_t pipe)
|
||||
{
|
||||
RT_ASSERT(pipe != RT_NULL);
|
||||
hcd->ops->close_pipe(pipe);
|
||||
rt_free(pipe);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int rt_usb_hcd_pipe_xfer(uhcd_t hcd, upipe_t pipe, void* buffer, int nbytes, int timeout);
|
||||
rt_inline int rt_usb_hcd_setup_xfer(uhcd_t hcd, upipe_t pipe, ureq_t setup, int timeout)
|
||||
{
|
||||
return hcd->ops->pipe_xfer(pipe, USBH_PID_SETUP, (void *)setup, 8, timeout);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* COPYRIGHT (C) 2011-2021, 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 (1) /* get timeout(in seconds) */
|
||||
#define RT_DEVICE_CTRL_WDT_SET_TIMEOUT (2) /* set timeout(in seconds) */
|
||||
#define RT_DEVICE_CTRL_WDT_GET_TIMELEFT (3) /* get the left time before reboot(in seconds) */
|
||||
#define RT_DEVICE_CTRL_WDT_KEEPALIVE (4) /* refresh watchdog */
|
||||
#define RT_DEVICE_CTRL_WDT_START (5) /* start watchdog */
|
||||
#define RT_DEVICE_CTRL_WDT_STOP (6) /* stop watchdog */
|
||||
|
||||
struct rt_watchdog_ops;
|
||||
struct rt_watchdog_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
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__ */
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-09-15 tyx the first version
|
||||
*/
|
||||
|
||||
#ifndef __WLAN_H__
|
||||
#define __WLAN_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <wlan_dev.h>
|
||||
#include <wlan_cfg.h>
|
||||
#include <wlan_mgnt.h>
|
||||
#include <wlan_prot.h>
|
||||
#include <wlan_workqueue.h>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
#ifndef COMPLETION_H_
|
||||
#define COMPLETION_H_
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
/**
|
||||
* Completion
|
||||
*/
|
||||
|
||||
struct rt_completion
|
||||
{
|
||||
rt_uint32_t flag;
|
||||
|
||||
/* suspended list */
|
||||
rt_list_t suspended_list;
|
||||
};
|
||||
|
||||
void rt_completion_init(struct rt_completion *completion);
|
||||
rt_err_t rt_completion_wait(struct rt_completion *completion,
|
||||
rt_int32_t timeout);
|
||||
void rt_completion_done(struct rt_completion *completion);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
#ifndef DATAQUEUE_H__
|
||||
#define DATAQUEUE_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define RT_DATAQUEUE_EVENT_UNKNOWN 0x00
|
||||
#define RT_DATAQUEUE_EVENT_POP 0x01
|
||||
#define RT_DATAQUEUE_EVENT_PUSH 0x02
|
||||
#define RT_DATAQUEUE_EVENT_LWM 0x03
|
||||
|
||||
struct rt_data_item;
|
||||
|
||||
/* data queue implementation */
|
||||
struct rt_data_queue
|
||||
{
|
||||
rt_uint32_t magic;
|
||||
|
||||
rt_uint16_t size;
|
||||
rt_uint16_t lwm;
|
||||
|
||||
rt_uint16_t get_index : 15;
|
||||
rt_uint16_t is_empty : 1;
|
||||
rt_uint16_t put_index : 15;
|
||||
rt_uint16_t is_full : 1;
|
||||
|
||||
struct rt_data_item *queue;
|
||||
|
||||
rt_list_t suspended_push_list;
|
||||
rt_list_t suspended_pop_list;
|
||||
|
||||
/* event notify */
|
||||
void (*evt_notify)(struct rt_data_queue *queue, rt_uint32_t event);
|
||||
};
|
||||
|
||||
/**
|
||||
* DataQueue for DeviceDriver
|
||||
*/
|
||||
rt_err_t rt_data_queue_init(struct rt_data_queue *queue,
|
||||
rt_uint16_t size,
|
||||
rt_uint16_t lwm,
|
||||
void (*evt_notify)(struct rt_data_queue *queue, rt_uint32_t event));
|
||||
rt_err_t rt_data_queue_push(struct rt_data_queue *queue,
|
||||
const void *data_ptr,
|
||||
rt_size_t data_size,
|
||||
rt_int32_t timeout);
|
||||
rt_err_t rt_data_queue_pop(struct rt_data_queue *queue,
|
||||
const void **data_ptr,
|
||||
rt_size_t *size,
|
||||
rt_int32_t timeout);
|
||||
rt_err_t rt_data_queue_peek(struct rt_data_queue *queue,
|
||||
const void **data_ptr,
|
||||
rt_size_t *size);
|
||||
void rt_data_queue_reset(struct rt_data_queue *queue);
|
||||
rt_err_t rt_data_queue_deinit(struct rt_data_queue *queue);
|
||||
rt_uint16_t rt_data_queue_len(struct rt_data_queue *queue);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#ifndef PIPE_H__
|
||||
#define PIPE_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
/**
|
||||
* Pipe Device
|
||||
*/
|
||||
|
||||
struct rt_pipe_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
rt_bool_t is_named;
|
||||
|
||||
/* ring buffer in pipe device */
|
||||
struct rt_ringbuffer *fifo;
|
||||
rt_uint16_t bufsz;
|
||||
|
||||
rt_uint8_t readers;
|
||||
rt_uint8_t writers;
|
||||
|
||||
rt_wqueue_t reader_queue;
|
||||
rt_wqueue_t writer_queue;
|
||||
|
||||
struct rt_mutex lock;
|
||||
};
|
||||
typedef struct rt_pipe_device rt_pipe_t;
|
||||
|
||||
rt_pipe_t *rt_pipe_create(const char *name, int bufsz);
|
||||
int rt_pipe_delete(const char *name);
|
||||
|
||||
#endif /* PIPE_H__ */
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2016-09-19 Heyuanjie The first version.
|
||||
* 2016-12-26 Bernard Update poll interface
|
||||
*/
|
||||
#ifndef IPC_POLL_H__
|
||||
#define IPC_POLL_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct rt_pollreq;
|
||||
typedef void (*poll_queue_proc)(rt_wqueue_t *, struct rt_pollreq *);
|
||||
|
||||
typedef struct rt_pollreq
|
||||
{
|
||||
poll_queue_proc _proc;
|
||||
short _key;
|
||||
} rt_pollreq_t;
|
||||
|
||||
rt_inline void rt_poll_add(rt_wqueue_t *wq, rt_pollreq_t *req)
|
||||
{
|
||||
if (req && req->_proc && wq)
|
||||
{
|
||||
req->_proc(wq, req);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-08-25 armink the first version
|
||||
*/
|
||||
|
||||
#ifndef _RINGBLK_BUF_H_
|
||||
#define _RINGBLK_BUF_H_
|
||||
|
||||
/*
|
||||
* Introduction:
|
||||
* The rbb is the ring buffer which is composed with many blocks. It is different from the ring buffer.
|
||||
* The ring buffer is only composed with chars. The rbb put and get supported zero copies. So the rbb
|
||||
* is very suitable for put block and get block by a certain order. Such as DMA block transmit,
|
||||
* communicate frame send/recv, and so on.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum rt_rbb_status
|
||||
{
|
||||
/* unused status when first initialize or after blk_free() */
|
||||
RT_RBB_BLK_UNUSED,
|
||||
/* initialized status after blk_alloc() */
|
||||
RT_RBB_BLK_INITED,
|
||||
/* put status after blk_put() */
|
||||
RT_RBB_BLK_PUT,
|
||||
/* get status after blk_get() */
|
||||
RT_RBB_BLK_GET,
|
||||
};
|
||||
typedef enum rt_rbb_status rt_rbb_status_t;
|
||||
|
||||
/**
|
||||
* the block of rbb
|
||||
*/
|
||||
struct rt_rbb_blk
|
||||
{
|
||||
rt_rbb_status_t status :8;
|
||||
/* less then 2^24 */
|
||||
rt_size_t size :24;
|
||||
rt_uint8_t *buf;
|
||||
rt_slist_t list;
|
||||
};
|
||||
typedef struct rt_rbb_blk *rt_rbb_blk_t;
|
||||
|
||||
/**
|
||||
* Rbb block queue: the blocks (from block1->buf to blockn->buf) memory which on this queue is continuous.
|
||||
*/
|
||||
struct rt_rbb_blk_queue
|
||||
{
|
||||
rt_rbb_blk_t blocks;
|
||||
rt_size_t blk_num;
|
||||
};
|
||||
typedef struct rt_rbb_blk_queue *rt_rbb_blk_queue_t;
|
||||
|
||||
/**
|
||||
* ring block buffer
|
||||
*/
|
||||
struct rt_rbb
|
||||
{
|
||||
rt_uint8_t *buf;
|
||||
rt_size_t buf_size;
|
||||
/* all of blocks */
|
||||
rt_rbb_blk_t blk_set;
|
||||
rt_size_t blk_max_num;
|
||||
/* saved the initialized and put status blocks */
|
||||
rt_slist_t blk_list;
|
||||
/* point to tail node */
|
||||
rt_slist_t *tail;
|
||||
/* free node list */
|
||||
rt_slist_t free_list;
|
||||
};
|
||||
typedef struct rt_rbb *rt_rbb_t;
|
||||
|
||||
/* rbb (ring block buffer) API */
|
||||
void rt_rbb_init(rt_rbb_t rbb, rt_uint8_t *buf, rt_size_t buf_size, rt_rbb_blk_t block_set, rt_size_t blk_max_num);
|
||||
rt_size_t rt_rbb_get_buf_size(rt_rbb_t rbb);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
rt_rbb_t rt_rbb_create(rt_size_t buf_size, rt_size_t blk_max_num);
|
||||
void rt_rbb_destroy(rt_rbb_t rbb);
|
||||
#endif
|
||||
|
||||
/* rbb block API */
|
||||
rt_rbb_blk_t rt_rbb_blk_alloc(rt_rbb_t rbb, rt_size_t blk_size);
|
||||
void rt_rbb_blk_put(rt_rbb_blk_t block);
|
||||
rt_rbb_blk_t rt_rbb_blk_get(rt_rbb_t rbb);
|
||||
rt_size_t rt_rbb_blk_size(rt_rbb_blk_t block);
|
||||
rt_uint8_t *rt_rbb_blk_buf(rt_rbb_blk_t block);
|
||||
void rt_rbb_blk_free(rt_rbb_t rbb, rt_rbb_blk_t block);
|
||||
|
||||
/* rbb block queue API */
|
||||
rt_size_t rt_rbb_blk_queue_get(rt_rbb_t rbb, rt_size_t queue_data_len, rt_rbb_blk_queue_t blk_queue);
|
||||
rt_size_t rt_rbb_blk_queue_len(rt_rbb_blk_queue_t blk_queue);
|
||||
rt_uint8_t *rt_rbb_blk_queue_buf(rt_rbb_blk_queue_t blk_queue);
|
||||
void rt_rbb_blk_queue_free(rt_rbb_t rbb, rt_rbb_blk_queue_t blk_queue);
|
||||
rt_size_t rt_rbb_next_blk_queue_len(rt_rbb_t rbb);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _RINGBLK_BUF_H_ */
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-08-14 Jackistang add comments for function interface.
|
||||
*/
|
||||
#ifndef RINGBUFFER_H__
|
||||
#define RINGBUFFER_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
/* ring buffer */
|
||||
struct rt_ringbuffer
|
||||
{
|
||||
rt_uint8_t *buffer_ptr;
|
||||
/* use the msb of the {read,write}_index as mirror bit. You can see this as
|
||||
* if the buffer adds a virtual mirror and the pointers point either to the
|
||||
* normal or to the mirrored buffer. If the write_index has the same value
|
||||
* with the read_index, but in a different mirror, the buffer is full.
|
||||
* While if the write_index and the read_index are the same and within the
|
||||
* same mirror, the buffer is empty. The ASCII art of the ringbuffer is:
|
||||
*
|
||||
* mirror = 0 mirror = 1
|
||||
* +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
|
||||
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 ||| 0 | 1 | 2 | 3 | 4 | 5 | 6 | Full
|
||||
* +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
|
||||
* read_idx-^ write_idx-^
|
||||
*
|
||||
* +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
|
||||
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 ||| 0 | 1 | 2 | 3 | 4 | 5 | 6 | Empty
|
||||
* +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
|
||||
* read_idx-^ ^-write_idx
|
||||
*
|
||||
* The tradeoff is we could only use 32KiB of buffer for 16 bit of index.
|
||||
* But it should be enough for most of the cases.
|
||||
*
|
||||
* Ref: http://en.wikipedia.org/wiki/Circular_buffer#Mirroring */
|
||||
rt_uint16_t read_mirror : 1;
|
||||
rt_uint16_t read_index : 15;
|
||||
rt_uint16_t write_mirror : 1;
|
||||
rt_uint16_t write_index : 15;
|
||||
/* as we use msb of index as mirror bit, the size should be signed and
|
||||
* could only be positive. */
|
||||
rt_int16_t buffer_size;
|
||||
};
|
||||
|
||||
enum rt_ringbuffer_state
|
||||
{
|
||||
RT_RINGBUFFER_EMPTY,
|
||||
RT_RINGBUFFER_FULL,
|
||||
/* half full is neither full nor empty */
|
||||
RT_RINGBUFFER_HALFFULL,
|
||||
};
|
||||
|
||||
/**
|
||||
* RingBuffer for DeviceDriver
|
||||
*
|
||||
* Please note that the ring buffer implementation of RT-Thread
|
||||
* has no thread wait or resume feature.
|
||||
*/
|
||||
void rt_ringbuffer_init(struct rt_ringbuffer *rb, rt_uint8_t *pool, rt_int16_t size);
|
||||
void rt_ringbuffer_reset(struct rt_ringbuffer *rb);
|
||||
rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length);
|
||||
rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length);
|
||||
rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch);
|
||||
rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const rt_uint8_t ch);
|
||||
rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb, rt_uint8_t *ptr, rt_uint16_t length);
|
||||
rt_size_t rt_ringbuffer_peak(struct rt_ringbuffer *rb, rt_uint8_t **ptr);
|
||||
rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch);
|
||||
rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
struct rt_ringbuffer* rt_ringbuffer_create(rt_uint16_t length);
|
||||
void rt_ringbuffer_destroy(struct rt_ringbuffer *rb);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get the buffer size of the ring buffer object.
|
||||
*
|
||||
* @param rb A pointer to the ring buffer object.
|
||||
*
|
||||
* @return Buffer size.
|
||||
*/
|
||||
rt_inline rt_uint16_t rt_ringbuffer_get_size(struct rt_ringbuffer *rb)
|
||||
{
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
return rb->buffer_size;
|
||||
}
|
||||
|
||||
/** return the size of empty space in rb */
|
||||
#define rt_ringbuffer_space_len(rb) ((rb)->buffer_size - rt_ringbuffer_data_len(rb))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018/06/26 Bernard Fix the wait queue issue when wakeup a soon
|
||||
* to blocked thread.
|
||||
*/
|
||||
|
||||
#ifndef WAITQUEUE_H__
|
||||
#define WAITQUEUE_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define RT_WQ_FLAG_CLEAN 0x00
|
||||
#define RT_WQ_FLAG_WAKEUP 0x01
|
||||
|
||||
struct rt_wqueue_node;
|
||||
typedef int (*rt_wqueue_func_t)(struct rt_wqueue_node *wait, void *key);
|
||||
|
||||
struct rt_wqueue_node
|
||||
{
|
||||
rt_thread_t polling_thread;
|
||||
rt_list_t list;
|
||||
|
||||
rt_wqueue_func_t wakeup;
|
||||
rt_uint32_t key;
|
||||
};
|
||||
typedef struct rt_wqueue_node rt_wqueue_node_t;
|
||||
|
||||
int __wqueue_default_wake(struct rt_wqueue_node *wait, void *key);
|
||||
|
||||
rt_inline void rt_wqueue_init(rt_wqueue_t *queue)
|
||||
{
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
|
||||
queue->flag = RT_WQ_FLAG_CLEAN;
|
||||
rt_list_init(&(queue->waiting_list));
|
||||
}
|
||||
|
||||
void rt_wqueue_add(rt_wqueue_t *queue, struct rt_wqueue_node *node);
|
||||
void rt_wqueue_remove(struct rt_wqueue_node *node);
|
||||
int rt_wqueue_wait(rt_wqueue_t *queue, int condition, int timeout);
|
||||
void rt_wqueue_wakeup(rt_wqueue_t *queue, void *key);
|
||||
|
||||
#define DEFINE_WAIT_FUNC(name, function) \
|
||||
struct rt_wqueue_node name = { \
|
||||
rt_current_thread, \
|
||||
RT_LIST_OBJECT_INIT(((name).list)), \
|
||||
\
|
||||
function, \
|
||||
0 \
|
||||
}
|
||||
|
||||
#define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, __wqueue_default_wake)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-08-01 Meco Man remove rt_delayed_work_init() and rt_delayed_work structure
|
||||
* 2021-08-14 Jackistang add comments for rt_work_init()
|
||||
*/
|
||||
#ifndef WORKQUEUE_H__
|
||||
#define WORKQUEUE_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
enum
|
||||
{
|
||||
RT_WORK_STATE_PENDING = 0x0001, /* Work item pending state */
|
||||
RT_WORK_STATE_SUBMITTING = 0x0002, /* Work item submitting state */
|
||||
};
|
||||
|
||||
/**
|
||||
* work type definitions
|
||||
*/
|
||||
enum
|
||||
{
|
||||
RT_WORK_TYPE_DELAYED = 0x0001,
|
||||
};
|
||||
|
||||
/* workqueue implementation */
|
||||
struct rt_workqueue
|
||||
{
|
||||
rt_list_t work_list;
|
||||
rt_list_t delayed_list;
|
||||
struct rt_work *work_current; /* current work */
|
||||
|
||||
struct rt_semaphore sem;
|
||||
rt_thread_t work_thread;
|
||||
};
|
||||
|
||||
struct rt_work
|
||||
{
|
||||
rt_list_t list;
|
||||
|
||||
void (*work_func)(struct rt_work *work, void *work_data);
|
||||
void *work_data;
|
||||
rt_uint16_t flags;
|
||||
rt_uint16_t type;
|
||||
struct rt_timer timer;
|
||||
struct rt_workqueue *workqueue;
|
||||
};
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
/**
|
||||
* WorkQueue for DeviceDriver
|
||||
*/
|
||||
void rt_work_init(struct rt_work *work, void (*work_func)(struct rt_work *work, void *work_data), void *work_data);
|
||||
struct rt_workqueue *rt_workqueue_create(const char *name, rt_uint16_t stack_size, rt_uint8_t priority);
|
||||
rt_err_t rt_workqueue_destroy(struct rt_workqueue *queue);
|
||||
rt_err_t rt_workqueue_dowork(struct rt_workqueue *queue, struct rt_work *work);
|
||||
rt_err_t rt_workqueue_submit_work(struct rt_workqueue *queue, struct rt_work *work, rt_tick_t ticks);
|
||||
rt_err_t rt_workqueue_cancel_work(struct rt_workqueue *queue, struct rt_work *work);
|
||||
rt_err_t rt_workqueue_cancel_work_sync(struct rt_workqueue *queue, struct rt_work *work);
|
||||
rt_err_t rt_workqueue_cancel_all_work(struct rt_workqueue *queue);
|
||||
rt_err_t rt_workqueue_urgent_work(struct rt_workqueue *queue, struct rt_work *work);
|
||||
|
||||
#ifdef RT_USING_SYSTEM_WORKQUEUE
|
||||
rt_err_t rt_work_submit(struct rt_work *work, rt_tick_t ticks);
|
||||
rt_err_t rt_work_urgent(struct rt_work *work);
|
||||
rt_err_t rt_work_cancel(struct rt_work *work);
|
||||
#endif /* RT_USING_SYSTEM_WORKQUEUE */
|
||||
|
||||
|
||||
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-01-08 bernard first version.
|
||||
* 2014-07-12 bernard Add workqueue implementation.
|
||||
*/
|
||||
|
||||
#ifndef __RT_DEVICE_H__
|
||||
#define __RT_DEVICE_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "ipc/ringbuffer.h"
|
||||
#include "ipc/completion.h"
|
||||
#include "ipc/dataqueue.h"
|
||||
#include "ipc/workqueue.h"
|
||||
#include "ipc/waitqueue.h"
|
||||
#include "ipc/pipe.h"
|
||||
#include "ipc/poll.h"
|
||||
#include "ipc/ringblk_buf.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RT_DEVICE(device) ((rt_device_t)device)
|
||||
|
||||
#ifdef RT_USING_RTC
|
||||
#include "drivers/rtc.h"
|
||||
#ifdef RT_USING_ALARM
|
||||
#include "drivers/alarm.h"
|
||||
#endif
|
||||
#endif /* RT_USING_RTC */
|
||||
|
||||
#ifdef RT_USING_SPI
|
||||
#include "drivers/spi.h"
|
||||
#endif /* RT_USING_SPI */
|
||||
|
||||
#ifdef RT_USING_MTD_NOR
|
||||
#include "drivers/mtd_nor.h"
|
||||
#endif /* RT_USING_MTD_NOR */
|
||||
|
||||
#ifdef RT_USING_MTD_NAND
|
||||
#include "drivers/mtd_nand.h"
|
||||
#endif /* RT_USING_MTD_NAND */
|
||||
|
||||
#ifdef RT_USING_USB_DEVICE
|
||||
#include "drivers/usb_device.h"
|
||||
#endif /* RT_USING_USB_DEVICE */
|
||||
|
||||
#ifdef RT_USING_USB_HOST
|
||||
#include "drivers/usb_host.h"
|
||||
#endif /* RT_USING_USB_HOST */
|
||||
|
||||
#ifdef RT_USING_SERIAL
|
||||
#ifdef RT_USING_SERIAL_V2
|
||||
#include "drivers/serial_v2.h"
|
||||
#else
|
||||
#include "drivers/serial.h"
|
||||
#endif
|
||||
#endif /* RT_USING_SERIAL */
|
||||
|
||||
#ifdef RT_USING_I2C
|
||||
#include "drivers/i2c.h"
|
||||
#include "drivers/i2c_dev.h"
|
||||
|
||||
#ifdef RT_USING_I2C_BITOPS
|
||||
#include "drivers/i2c-bit-ops.h"
|
||||
#endif /* RT_USING_I2C_BITOPS */
|
||||
#endif /* RT_USING_I2C */
|
||||
|
||||
#ifdef RT_USING_PHY
|
||||
#include "drivers/phy.h"
|
||||
#include "drivers/phy_mdio.h"
|
||||
#endif /* RT_USING_PHY */
|
||||
|
||||
#ifdef RT_USING_SDIO
|
||||
#include "drivers/mmcsd_core.h"
|
||||
#include "drivers/sd.h"
|
||||
#include "drivers/sdio.h"
|
||||
#endif /* RT_USING_SDIO */
|
||||
|
||||
|
||||
#ifdef RT_USING_WDT
|
||||
#include "drivers/watchdog.h"
|
||||
#endif /* RT_USING_WDT */
|
||||
|
||||
#ifdef RT_USING_PIN
|
||||
#include "drivers/pin.h"
|
||||
#endif /* RT_USING_PIN */
|
||||
|
||||
#ifdef RT_USING_SENSOR
|
||||
#include "drivers/sensor.h"
|
||||
#endif /* RT_USING_SENSOR */
|
||||
|
||||
#ifdef RT_USING_CAN
|
||||
#include "drivers/can.h"
|
||||
#endif /* RT_USING_CAN */
|
||||
|
||||
#ifdef RT_USING_HWTIMER
|
||||
#include "drivers/hwtimer.h"
|
||||
#endif /* RT_USING_HWTIMER */
|
||||
|
||||
#ifdef RT_USING_AUDIO
|
||||
#include "drivers/audio.h"
|
||||
#endif /* RT_USING_AUDIO */
|
||||
|
||||
#ifdef RT_USING_CPUTIME
|
||||
#include "drivers/cputime.h"
|
||||
#endif /* RT_USING_CPUTIME */
|
||||
|
||||
#ifdef RT_USING_ADC
|
||||
#include "drivers/adc.h"
|
||||
#endif /* RT_USING_ADC */
|
||||
|
||||
#ifdef RT_USING_DAC
|
||||
#include "drivers/dac.h"
|
||||
#endif /* RT_USING_DAC */
|
||||
|
||||
#ifdef RT_USING_PWM
|
||||
#include "drivers/rt_drv_pwm.h"
|
||||
#endif /* RT_USING_PWM */
|
||||
|
||||
#ifdef RT_USING_PM
|
||||
#include "drivers/pm.h"
|
||||
#endif /* RT_USING_PM */
|
||||
|
||||
#ifdef RT_USING_WIFI
|
||||
#include "drivers/wlan.h"
|
||||
#endif /* RT_USING_WIFI */
|
||||
|
||||
#ifdef MTD_USING_NOR
|
||||
#include "drivers/mtdnor.h"
|
||||
#endif /* MTD_USING_NOR */
|
||||
|
||||
#ifdef MTD_USING_NAND
|
||||
#include "drivers/mtdnand.h"
|
||||
#endif /* MTD_USING_NAND */
|
||||
|
||||
#ifdef RT_USING_HWCRYPTO
|
||||
#include "drivers/crypto.h"
|
||||
#endif /* RT_USING_HWCRYPTO */
|
||||
|
||||
#ifdef RT_USING_PULSE_ENCODER
|
||||
#include "drivers/pulse_encoder.h"
|
||||
#endif /* RT_USING_PULSE_ENCODER */
|
||||
|
||||
#ifdef RT_USING_INPUT_CAPTURE
|
||||
#include "drivers/rt_inputcapture.h"
|
||||
#endif /* RT_USING_INPUT_CAPTURE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __RT_DEVICE_H__ */
|
||||
@@ -0,0 +1,13 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd + '/../include']
|
||||
|
||||
if not GetDepend('RT_USING_HEAP'):
|
||||
SrcRemove(src, 'dataqueue.c')
|
||||
SrcRemove(src, 'pipe.c')
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_DEVICE_IPC'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-09-30 Bernard first version.
|
||||
* 2021-08-18 chenyingchun add comments
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define RT_COMPLETED 1
|
||||
#define RT_UNCOMPLETED 0
|
||||
|
||||
/**
|
||||
* @brief This function will initialize a completion object.
|
||||
*
|
||||
* @param completion is a pointer to a completion object.
|
||||
*/
|
||||
void rt_completion_init(struct rt_completion *completion)
|
||||
{
|
||||
rt_base_t level;
|
||||
RT_ASSERT(completion != RT_NULL);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
completion->flag = RT_UNCOMPLETED;
|
||||
rt_list_init(&completion->suspended_list);
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
RTM_EXPORT(rt_completion_init);
|
||||
|
||||
/**
|
||||
* @brief This function will wait for a completion, if the completion is unavailable, the thread shall wait for
|
||||
* the completion up to a specified time.
|
||||
*
|
||||
* @param completion is a pointer to a completion object.
|
||||
*
|
||||
* @param timeout is a timeout period (unit: OS ticks). If the completion is unavailable, the thread will wait for
|
||||
* the completion done up to the amount of time specified by the argument.
|
||||
* NOTE: Generally, we use the macro RT_WAITING_FOREVER to set this parameter, which means that when the
|
||||
* completion is unavailable, the thread will be waitting forever.
|
||||
*
|
||||
* @return Return the operation status. ONLY when the return value is RT_EOK, the operation is successful.
|
||||
* If the return value is any other values, it means that the completion wait failed.
|
||||
*
|
||||
* @warning This function can ONLY be called in the thread context. It MUST NOT be called in interrupt context.
|
||||
*/
|
||||
rt_err_t rt_completion_wait(struct rt_completion *completion,
|
||||
rt_int32_t timeout)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_base_t level;
|
||||
rt_thread_t thread;
|
||||
RT_ASSERT(completion != RT_NULL);
|
||||
|
||||
/* current context checking */
|
||||
RT_DEBUG_SCHEDULER_AVAILABLE(timeout != 0);
|
||||
|
||||
result = RT_EOK;
|
||||
thread = rt_thread_self();
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (completion->flag != RT_COMPLETED)
|
||||
{
|
||||
/* only one thread can suspend on complete */
|
||||
RT_ASSERT(rt_list_isempty(&(completion->suspended_list)));
|
||||
|
||||
if (timeout == 0)
|
||||
{
|
||||
result = -RT_ETIMEOUT;
|
||||
goto __exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* reset thread error number */
|
||||
thread->error = RT_EOK;
|
||||
|
||||
/* suspend thread */
|
||||
rt_thread_suspend(thread);
|
||||
/* add to suspended list */
|
||||
rt_list_insert_before(&(completion->suspended_list),
|
||||
&(thread->tlist));
|
||||
|
||||
/* start timer */
|
||||
if (timeout > 0)
|
||||
{
|
||||
/* reset the timeout of thread timer and start it */
|
||||
rt_timer_control(&(thread->thread_timer),
|
||||
RT_TIMER_CTRL_SET_TIME,
|
||||
&timeout);
|
||||
rt_timer_start(&(thread->thread_timer));
|
||||
}
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* do schedule */
|
||||
rt_schedule();
|
||||
|
||||
/* thread is waked up */
|
||||
result = thread->error;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
}
|
||||
}
|
||||
/* clean completed flag */
|
||||
completion->flag = RT_UNCOMPLETED;
|
||||
|
||||
__exit:
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return result;
|
||||
}
|
||||
RTM_EXPORT(rt_completion_wait);
|
||||
|
||||
/**
|
||||
* @brief This function indicates a completion has done.
|
||||
*
|
||||
* @param completion is a pointer to a completion object.
|
||||
*/
|
||||
void rt_completion_done(struct rt_completion *completion)
|
||||
{
|
||||
rt_base_t level;
|
||||
RT_ASSERT(completion != RT_NULL);
|
||||
|
||||
if (completion->flag == RT_COMPLETED)
|
||||
return;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
completion->flag = RT_COMPLETED;
|
||||
|
||||
if (!rt_list_isempty(&(completion->suspended_list)))
|
||||
{
|
||||
/* there is one thread in suspended list */
|
||||
struct rt_thread *thread;
|
||||
|
||||
/* get thread entry */
|
||||
thread = rt_list_entry(completion->suspended_list.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
|
||||
/* resume it */
|
||||
rt_thread_resume(thread);
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* perform a schedule */
|
||||
rt_schedule();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
}
|
||||
RTM_EXPORT(rt_completion_done);
|
||||
|
||||
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-09-30 Bernard first version.
|
||||
* 2016-10-31 armink fix some resume push and pop thread bugs
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <rthw.h>
|
||||
|
||||
#define DATAQUEUE_MAGIC 0xbead0e0e
|
||||
|
||||
struct rt_data_item
|
||||
{
|
||||
const void *data_ptr;
|
||||
rt_size_t data_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This function will initialize the data queue. Calling this function will
|
||||
* initialize the data queue control block and set the notification callback function.
|
||||
*
|
||||
* @param queue is a pointer to the data queue object.
|
||||
*
|
||||
* @param size is the maximum number of data in the data queue.
|
||||
*
|
||||
* @param lwm is low water mark.
|
||||
* When the number of data in the data queue is less than this value, this function will
|
||||
* wake up the thread waiting for write data.
|
||||
*
|
||||
* @param evt_notify is the notification callback function.
|
||||
*
|
||||
* @return Return the operation status. When the return value is RT_EOK, the initialization is successful.
|
||||
* When the return value is RT_ENOMEM, it means insufficient memory allocation failed.
|
||||
*/
|
||||
rt_err_t
|
||||
rt_data_queue_init(struct rt_data_queue *queue,
|
||||
rt_uint16_t size,
|
||||
rt_uint16_t lwm,
|
||||
void (*evt_notify)(struct rt_data_queue *queue, rt_uint32_t event))
|
||||
{
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
RT_ASSERT(size > 0);
|
||||
|
||||
queue->evt_notify = evt_notify;
|
||||
|
||||
queue->magic = DATAQUEUE_MAGIC;
|
||||
queue->size = size;
|
||||
queue->lwm = lwm;
|
||||
|
||||
queue->get_index = 0;
|
||||
queue->put_index = 0;
|
||||
queue->is_empty = 1;
|
||||
queue->is_full = 0;
|
||||
|
||||
rt_list_init(&(queue->suspended_push_list));
|
||||
rt_list_init(&(queue->suspended_pop_list));
|
||||
|
||||
queue->queue = (struct rt_data_item *)rt_malloc(sizeof(struct rt_data_item) * size);
|
||||
if (queue->queue == RT_NULL)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_data_queue_init);
|
||||
|
||||
/**
|
||||
* @brief This function will write data to the data queue. If the data queue is full,
|
||||
* the thread will suspend for the specified amount of time.
|
||||
*
|
||||
* @param queue is a pointer to the data queue object.
|
||||
* .
|
||||
* @param data_ptr is the buffer pointer of the data to be written.
|
||||
*
|
||||
* @param size is the size in bytes of the data to be written.
|
||||
*
|
||||
* @param timeout is the waiting time.
|
||||
*
|
||||
* @return Return the operation status. When the return value is RT_EOK, the operation is successful.
|
||||
* When the return value is RT_ETIMEOUT, it means the specified time out.
|
||||
*/
|
||||
rt_err_t rt_data_queue_push(struct rt_data_queue *queue,
|
||||
const void *data_ptr,
|
||||
rt_size_t data_size,
|
||||
rt_int32_t timeout)
|
||||
{
|
||||
rt_ubase_t level;
|
||||
rt_thread_t thread;
|
||||
rt_err_t result;
|
||||
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
RT_ASSERT(queue->magic == DATAQUEUE_MAGIC);
|
||||
|
||||
/* current context checking */
|
||||
RT_DEBUG_SCHEDULER_AVAILABLE(timeout != 0);
|
||||
|
||||
result = RT_EOK;
|
||||
thread = rt_thread_self();
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
while (queue->is_full)
|
||||
{
|
||||
/* queue is full */
|
||||
if (timeout == 0)
|
||||
{
|
||||
result = -RT_ETIMEOUT;
|
||||
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
/* reset thread error number */
|
||||
thread->error = RT_EOK;
|
||||
|
||||
/* suspend thread on the push list */
|
||||
rt_thread_suspend(thread);
|
||||
rt_list_insert_before(&(queue->suspended_push_list), &(thread->tlist));
|
||||
/* start timer */
|
||||
if (timeout > 0)
|
||||
{
|
||||
/* reset the timeout of thread timer and start it */
|
||||
rt_timer_control(&(thread->thread_timer),
|
||||
RT_TIMER_CTRL_SET_TIME,
|
||||
&timeout);
|
||||
rt_timer_start(&(thread->thread_timer));
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* do schedule */
|
||||
rt_schedule();
|
||||
|
||||
/* thread is waked up */
|
||||
result = thread->error;
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (result != RT_EOK) goto __exit;
|
||||
}
|
||||
|
||||
queue->queue[queue->put_index].data_ptr = data_ptr;
|
||||
queue->queue[queue->put_index].data_size = data_size;
|
||||
queue->put_index += 1;
|
||||
if (queue->put_index == queue->size)
|
||||
{
|
||||
queue->put_index = 0;
|
||||
}
|
||||
queue->is_empty = 0;
|
||||
if (queue->put_index == queue->get_index)
|
||||
{
|
||||
queue->is_full = 1;
|
||||
}
|
||||
|
||||
/* there is at least one thread in suspended list */
|
||||
if (!rt_list_isempty(&(queue->suspended_pop_list)))
|
||||
{
|
||||
/* get thread entry */
|
||||
thread = rt_list_entry(queue->suspended_pop_list.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
|
||||
/* resume it */
|
||||
rt_thread_resume(thread);
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* perform a schedule */
|
||||
rt_schedule();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
__exit:
|
||||
rt_hw_interrupt_enable(level);
|
||||
if ((result == RT_EOK) && queue->evt_notify != RT_NULL)
|
||||
{
|
||||
queue->evt_notify(queue, RT_DATAQUEUE_EVENT_PUSH);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
RTM_EXPORT(rt_data_queue_push);
|
||||
|
||||
/**
|
||||
* @brief This function will pop data from the data queue. If the data queue is empty,the thread
|
||||
* will suspend for the specified amount of time.
|
||||
*
|
||||
* @note When the number of data in the data queue is less than lwm(low water mark), will
|
||||
* wake up the thread waiting for write data.
|
||||
*
|
||||
* @param queue is a pointer to the data queue object.
|
||||
*
|
||||
* @param data_ptr is the buffer pointer of the data to be fetched.
|
||||
*
|
||||
* @param size is the size in bytes of the data to be fetched.
|
||||
*
|
||||
* @param timeout is the waiting time.
|
||||
*
|
||||
* @return Return the operation status. When the return value is RT_EOK, the operation is successful.
|
||||
* When the return value is RT_ETIMEOUT, it means the specified time out.
|
||||
*/
|
||||
rt_err_t rt_data_queue_pop(struct rt_data_queue *queue,
|
||||
const void** data_ptr,
|
||||
rt_size_t *size,
|
||||
rt_int32_t timeout)
|
||||
{
|
||||
rt_ubase_t level;
|
||||
rt_thread_t thread;
|
||||
rt_err_t result;
|
||||
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
RT_ASSERT(queue->magic == DATAQUEUE_MAGIC);
|
||||
RT_ASSERT(data_ptr != RT_NULL);
|
||||
RT_ASSERT(size != RT_NULL);
|
||||
|
||||
/* current context checking */
|
||||
RT_DEBUG_SCHEDULER_AVAILABLE(timeout != 0);
|
||||
|
||||
result = RT_EOK;
|
||||
thread = rt_thread_self();
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
while (queue->is_empty)
|
||||
{
|
||||
/* queue is empty */
|
||||
if (timeout == 0)
|
||||
{
|
||||
result = -RT_ETIMEOUT;
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
/* reset thread error number */
|
||||
thread->error = RT_EOK;
|
||||
|
||||
/* suspend thread on the pop list */
|
||||
rt_thread_suspend(thread);
|
||||
rt_list_insert_before(&(queue->suspended_pop_list), &(thread->tlist));
|
||||
/* start timer */
|
||||
if (timeout > 0)
|
||||
{
|
||||
/* reset the timeout of thread timer and start it */
|
||||
rt_timer_control(&(thread->thread_timer),
|
||||
RT_TIMER_CTRL_SET_TIME,
|
||||
&timeout);
|
||||
rt_timer_start(&(thread->thread_timer));
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* do schedule */
|
||||
rt_schedule();
|
||||
|
||||
/* thread is waked up */
|
||||
result = thread->error;
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (result != RT_EOK)
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
*data_ptr = queue->queue[queue->get_index].data_ptr;
|
||||
*size = queue->queue[queue->get_index].data_size;
|
||||
queue->get_index += 1;
|
||||
if (queue->get_index == queue->size)
|
||||
{
|
||||
queue->get_index = 0;
|
||||
}
|
||||
queue->is_full = 0;
|
||||
if (queue->put_index == queue->get_index)
|
||||
{
|
||||
queue->is_empty = 1;
|
||||
}
|
||||
|
||||
if (rt_data_queue_len(queue) <= queue->lwm)
|
||||
{
|
||||
/* there is at least one thread in suspended list */
|
||||
if (!rt_list_isempty(&(queue->suspended_push_list)))
|
||||
{
|
||||
/* get thread entry */
|
||||
thread = rt_list_entry(queue->suspended_push_list.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
|
||||
/* resume it */
|
||||
rt_thread_resume(thread);
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* perform a schedule */
|
||||
rt_schedule();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
|
||||
if (queue->evt_notify != RT_NULL)
|
||||
queue->evt_notify(queue, RT_DATAQUEUE_EVENT_LWM);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
__exit:
|
||||
rt_hw_interrupt_enable(level);
|
||||
if ((result == RT_EOK) && (queue->evt_notify != RT_NULL))
|
||||
{
|
||||
queue->evt_notify(queue, RT_DATAQUEUE_EVENT_POP);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
RTM_EXPORT(rt_data_queue_pop);
|
||||
|
||||
/**
|
||||
* @brief This function will fetch but retaining data in the data queue.
|
||||
*
|
||||
* @param queue is a pointer to the data queue object.
|
||||
*
|
||||
* @param data_ptr is the buffer pointer of the data to be fetched.
|
||||
*
|
||||
* @param size is the size in bytes of the data to be fetched.
|
||||
*
|
||||
* @return Return the operation status. When the return value is RT_EOK, the operation is successful.
|
||||
* When the return value is -RT_EEMPTY, it means the data queue is empty.
|
||||
*/
|
||||
rt_err_t rt_data_queue_peek(struct rt_data_queue *queue,
|
||||
const void** data_ptr,
|
||||
rt_size_t *size)
|
||||
{
|
||||
rt_ubase_t level;
|
||||
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
RT_ASSERT(queue->magic == DATAQUEUE_MAGIC);
|
||||
|
||||
if (queue->is_empty)
|
||||
{
|
||||
return -RT_EEMPTY;
|
||||
}
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
*data_ptr = queue->queue[queue->get_index].data_ptr;
|
||||
*size = queue->queue[queue->get_index].data_size;
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_data_queue_peek);
|
||||
|
||||
/**
|
||||
* @brief This function will reset the data queue.
|
||||
*
|
||||
* @note Calling this function will wake up all threads on the data queue
|
||||
* that are hanging and waiting.
|
||||
*
|
||||
* @param queue is a pointer to the data queue object.
|
||||
*/
|
||||
void rt_data_queue_reset(struct rt_data_queue *queue)
|
||||
{
|
||||
rt_ubase_t level;
|
||||
struct rt_thread *thread;
|
||||
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
RT_ASSERT(queue->magic == DATAQUEUE_MAGIC);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
queue->get_index = 0;
|
||||
queue->put_index = 0;
|
||||
queue->is_empty = 1;
|
||||
queue->is_full = 0;
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_enter_critical();
|
||||
/* wakeup all suspend threads */
|
||||
|
||||
/* resume on pop list */
|
||||
while (!rt_list_isempty(&(queue->suspended_pop_list)))
|
||||
{
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
/* get next suspend thread */
|
||||
thread = rt_list_entry(queue->suspended_pop_list.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
/* set error code to RT_ERROR */
|
||||
thread->error = -RT_ERROR;
|
||||
|
||||
/*
|
||||
* resume thread
|
||||
* In rt_thread_resume function, it will remove current thread from
|
||||
* suspend list
|
||||
*/
|
||||
rt_thread_resume(thread);
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
|
||||
/* resume on push list */
|
||||
while (!rt_list_isempty(&(queue->suspended_push_list)))
|
||||
{
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
/* get next suspend thread */
|
||||
thread = rt_list_entry(queue->suspended_push_list.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
/* set error code to RT_ERROR */
|
||||
thread->error = -RT_ERROR;
|
||||
|
||||
/*
|
||||
* resume thread
|
||||
* In rt_thread_resume function, it will remove current thread from
|
||||
* suspend list
|
||||
*/
|
||||
rt_thread_resume(thread);
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
rt_exit_critical();
|
||||
|
||||
rt_schedule();
|
||||
}
|
||||
RTM_EXPORT(rt_data_queue_reset);
|
||||
|
||||
/**
|
||||
* @brief This function will deinit the data queue.
|
||||
*
|
||||
* @param queue is a pointer to the data queue object.
|
||||
*
|
||||
* @return Return the operation status. When the return value is RT_EOK, the operation is successful.
|
||||
*/
|
||||
rt_err_t rt_data_queue_deinit(struct rt_data_queue *queue)
|
||||
{
|
||||
rt_ubase_t level;
|
||||
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
RT_ASSERT(queue->magic == DATAQUEUE_MAGIC);
|
||||
|
||||
/* wakeup all suspend threads */
|
||||
rt_data_queue_reset(queue);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
queue->magic = 0;
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_free(queue->queue);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_data_queue_deinit);
|
||||
|
||||
/**
|
||||
* @brief This function will get the number of data in the data queue.
|
||||
*
|
||||
* @param queue is a pointer to the data queue object.
|
||||
*
|
||||
* @return Return the number of data in the data queue.
|
||||
*/
|
||||
rt_uint16_t rt_data_queue_len(struct rt_data_queue *queue)
|
||||
{
|
||||
rt_ubase_t level;
|
||||
rt_int16_t len;
|
||||
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
RT_ASSERT(queue->magic == DATAQUEUE_MAGIC);
|
||||
|
||||
if (queue->is_empty)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
if (queue->put_index > queue->get_index)
|
||||
{
|
||||
len = queue->put_index - queue->get_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = queue->size + queue->put_index - queue->get_index;
|
||||
}
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return len;
|
||||
}
|
||||
RTM_EXPORT(rt_data_queue_len);
|
||||
|
||||
@@ -0,0 +1,758 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-09-30 Bernard first version.
|
||||
* 2017-11-08 JasonJiaJie fix memory leak issue when close a pipe.
|
||||
*/
|
||||
#include <rthw.h>
|
||||
#include <rtdevice.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#if defined(RT_USING_POSIX_DEVIO) && defined(RT_USING_POSIX_PIPE)
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <dfs_file.h>
|
||||
|
||||
/**
|
||||
* @brief This function will open a pipe.
|
||||
*
|
||||
* @param fd is the file descriptor.
|
||||
*
|
||||
* @return Return the operation status.
|
||||
* When the return value is 0, it means the operation is successful.
|
||||
* When the return value is -1, it means the file descriptor is invalid.
|
||||
* When the return value is -RT_ENOMEM, it means insufficient memory allocation failed.
|
||||
*/
|
||||
static int pipe_fops_open(struct dfs_fd *fd)
|
||||
{
|
||||
int rc = 0;
|
||||
rt_device_t device;
|
||||
rt_pipe_t *pipe;
|
||||
|
||||
pipe = (rt_pipe_t *)fd->data;
|
||||
if (!pipe) return -1;
|
||||
|
||||
device = &(pipe->parent);
|
||||
rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
|
||||
|
||||
if (device->ref_count == 0)
|
||||
{
|
||||
pipe->fifo = rt_ringbuffer_create(pipe->bufsz);
|
||||
if (pipe->fifo == RT_NULL)
|
||||
{
|
||||
rc = -RT_ENOMEM;
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
|
||||
switch (fd->flags & O_ACCMODE)
|
||||
{
|
||||
case O_RDONLY:
|
||||
pipe->readers ++;
|
||||
break;
|
||||
case O_WRONLY:
|
||||
pipe->writers ++;
|
||||
break;
|
||||
case O_RDWR:
|
||||
pipe->readers ++;
|
||||
pipe->writers ++;
|
||||
break;
|
||||
}
|
||||
device->ref_count ++;
|
||||
|
||||
__exit:
|
||||
rt_mutex_release(&(pipe->lock));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will close a pipe.
|
||||
*
|
||||
* @param fd is the file descriptor.
|
||||
*
|
||||
* @return Return the operation status.
|
||||
* When the return value is 0, it means the operation is successful.
|
||||
* When the return value is -1, it means the file descriptor is invalid.
|
||||
*/
|
||||
static int pipe_fops_close(struct dfs_fd *fd)
|
||||
{
|
||||
rt_device_t device;
|
||||
rt_pipe_t *pipe;
|
||||
|
||||
pipe = (rt_pipe_t *)fd->data;
|
||||
if (!pipe) return -1;
|
||||
|
||||
device = &(pipe->parent);
|
||||
rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
|
||||
|
||||
switch (fd->flags & O_ACCMODE)
|
||||
{
|
||||
case O_RDONLY:
|
||||
pipe->readers --;
|
||||
break;
|
||||
case O_WRONLY:
|
||||
pipe->writers --;
|
||||
break;
|
||||
case O_RDWR:
|
||||
pipe->readers --;
|
||||
pipe->writers --;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pipe->writers == 0)
|
||||
{
|
||||
rt_wqueue_wakeup(&(pipe->reader_queue), (void*)(POLLIN | POLLERR | POLLHUP));
|
||||
}
|
||||
|
||||
if (pipe->readers == 0)
|
||||
{
|
||||
rt_wqueue_wakeup(&(pipe->writer_queue), (void*)(POLLOUT | POLLERR | POLLHUP));
|
||||
}
|
||||
|
||||
if (device->ref_count == 1)
|
||||
{
|
||||
if (pipe->fifo != RT_NULL)
|
||||
rt_ringbuffer_destroy(pipe->fifo);
|
||||
pipe->fifo = RT_NULL;
|
||||
}
|
||||
device->ref_count --;
|
||||
|
||||
rt_mutex_release(&(pipe->lock));
|
||||
|
||||
if (device->ref_count == 0 && pipe->is_named == RT_FALSE)
|
||||
{
|
||||
/* delete the unamed pipe */
|
||||
rt_pipe_delete(device->parent.name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will get the pipe space size depends on the command.
|
||||
*
|
||||
* @param fd is the file descriptor.
|
||||
*
|
||||
* @param cmd is the command. It determines what data will get.
|
||||
*
|
||||
* FIONREAD The command to get the number of bytes in the pipe.
|
||||
*
|
||||
* FIONWRITE The command to get the number of bytes can be written to the pipe.
|
||||
*
|
||||
* @param args is the pointer to the data to store the read data.
|
||||
*
|
||||
* @return Return the operation status.
|
||||
* When the return value is 0, it means the operation is successful.
|
||||
* When the return value is -EINVAL, it means the command is invalid.
|
||||
*/
|
||||
static int pipe_fops_ioctl(struct dfs_fd *fd, int cmd, void *args)
|
||||
{
|
||||
rt_pipe_t *pipe;
|
||||
int ret = 0;
|
||||
|
||||
pipe = (rt_pipe_t *)fd->data;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case FIONREAD:
|
||||
*((int*)args) = rt_ringbuffer_data_len(pipe->fifo);
|
||||
break;
|
||||
case FIONWRITE:
|
||||
*((int*)args) = rt_ringbuffer_space_len(pipe->fifo);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will read data from pipe.
|
||||
*
|
||||
* @param fd is the file descriptor.
|
||||
*
|
||||
* @param buf is the buffer to store the read data.
|
||||
*
|
||||
* @param count is the length of data to be read.
|
||||
*
|
||||
* @return Return the length of data read.
|
||||
* When the return value is 0, it means O_NONBLOCK is enabled and there is no thread that has the pipe open for writing.
|
||||
* When the return value is -EAGAIN, it means there are no data to be read.
|
||||
*/
|
||||
static int pipe_fops_read(struct dfs_fd *fd, void *buf, size_t count)
|
||||
{
|
||||
int len = 0;
|
||||
rt_pipe_t *pipe;
|
||||
|
||||
pipe = (rt_pipe_t *)fd->data;
|
||||
|
||||
/* no process has the pipe open for writing, return end-of-file */
|
||||
if (pipe->writers == 0)
|
||||
return 0;
|
||||
|
||||
rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (pipe->writers == 0)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = rt_ringbuffer_get(pipe->fifo, buf, count);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fd->flags & O_NONBLOCK)
|
||||
{
|
||||
len = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rt_mutex_release(&pipe->lock);
|
||||
rt_wqueue_wakeup(&(pipe->writer_queue), (void*)POLLOUT);
|
||||
rt_wqueue_wait(&(pipe->reader_queue), 0, -1);
|
||||
rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
|
||||
}
|
||||
}
|
||||
|
||||
/* wakeup writer */
|
||||
rt_wqueue_wakeup(&(pipe->writer_queue), (void*)POLLOUT);
|
||||
|
||||
out:
|
||||
rt_mutex_release(&pipe->lock);
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will write data to pipe.
|
||||
*
|
||||
* @param fd is the file descriptor.
|
||||
*
|
||||
* @param buf is a pointer to the data buffer to be written.
|
||||
*
|
||||
* @param count is the length of data to be write.
|
||||
*
|
||||
* @return Return the length of data written.
|
||||
* When the return value is -EAGAIN, it means O_NONBLOCK is enabled and there are no space to be written.
|
||||
* When the return value is -EPIPE, it means there is no thread that has the pipe open for reading.
|
||||
*/
|
||||
static int pipe_fops_write(struct dfs_fd *fd, const void *buf, size_t count)
|
||||
{
|
||||
int len;
|
||||
rt_pipe_t *pipe;
|
||||
int wakeup = 0;
|
||||
int ret = 0;
|
||||
uint8_t *pbuf;
|
||||
|
||||
pipe = (rt_pipe_t *)fd->data;
|
||||
|
||||
if (pipe->readers == 0)
|
||||
{
|
||||
ret = -EPIPE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
pbuf = (uint8_t*)buf;
|
||||
rt_mutex_take(&pipe->lock, -1);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (pipe->readers == 0)
|
||||
{
|
||||
if (ret == 0)
|
||||
ret = -EPIPE;
|
||||
break;
|
||||
}
|
||||
|
||||
len = rt_ringbuffer_put(pipe->fifo, pbuf, count - ret);
|
||||
ret += len;
|
||||
pbuf += len;
|
||||
wakeup = 1;
|
||||
|
||||
if (ret == count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fd->flags & O_NONBLOCK)
|
||||
{
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rt_mutex_release(&pipe->lock);
|
||||
rt_wqueue_wakeup(&(pipe->reader_queue), (void*)POLLIN);
|
||||
/* pipe full, waiting on suspended write list */
|
||||
rt_wqueue_wait(&(pipe->writer_queue), 0, -1);
|
||||
rt_mutex_take(&pipe->lock, -1);
|
||||
}
|
||||
rt_mutex_release(&pipe->lock);
|
||||
|
||||
if (wakeup)
|
||||
{
|
||||
rt_wqueue_wakeup(&(pipe->reader_queue), (void*)POLLIN);
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will get the pipe status.
|
||||
*
|
||||
* @param fd is the file descriptor.
|
||||
*
|
||||
* @param req is the request type.
|
||||
*
|
||||
* @return mask of the pipe status.
|
||||
* POLLIN means there is data to be read.
|
||||
* POLLHUP means there is no thread that occupied the pipe to open for writing.
|
||||
* POLLOUT means there is space to be written.
|
||||
* POLLERR means there is no thread that occupied the pipe to open for reading.
|
||||
*/
|
||||
static int pipe_fops_poll(struct dfs_fd *fd, rt_pollreq_t *req)
|
||||
{
|
||||
int mask = 0;
|
||||
rt_pipe_t *pipe;
|
||||
int mode = 0;
|
||||
pipe = (rt_pipe_t *)fd->data;
|
||||
|
||||
rt_poll_add(&(pipe->reader_queue), req);
|
||||
rt_poll_add(&(pipe->writer_queue), req);
|
||||
|
||||
switch (fd->flags & O_ACCMODE)
|
||||
{
|
||||
case O_RDONLY:
|
||||
mode = 1;
|
||||
break;
|
||||
case O_WRONLY:
|
||||
mode = 2;
|
||||
break;
|
||||
case O_RDWR:
|
||||
mode = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mode & 1)
|
||||
{
|
||||
if (rt_ringbuffer_data_len(pipe->fifo) != 0)
|
||||
{
|
||||
mask |= POLLIN;
|
||||
}
|
||||
if (pipe->writers == 0)
|
||||
{
|
||||
mask |= POLLHUP;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode & 2)
|
||||
{
|
||||
if (rt_ringbuffer_space_len(pipe->fifo) != 0)
|
||||
{
|
||||
mask |= POLLOUT;
|
||||
}
|
||||
if (pipe->readers == 0)
|
||||
{
|
||||
mask |= POLLERR;
|
||||
}
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static const struct dfs_file_ops pipe_fops =
|
||||
{
|
||||
pipe_fops_open,
|
||||
pipe_fops_close,
|
||||
pipe_fops_ioctl,
|
||||
pipe_fops_read,
|
||||
pipe_fops_write,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
pipe_fops_poll,
|
||||
};
|
||||
#endif /* defined(RT_USING_POSIX_DEVIO) && defined(RT_USING_POSIX_PIPE) */
|
||||
|
||||
/**
|
||||
* @brief This function will open the pipe and actually creates the pipe buffer.
|
||||
*
|
||||
* @param device is a pointer to the pipe device descriptor.
|
||||
*
|
||||
* @param oflag is the open method, but it is not used yet.
|
||||
*
|
||||
* @return Return the operation status.
|
||||
* When the return value is RT_EOK, the operation is successful.
|
||||
* When the return value is -RT_EINVAL, it means the device handle is empty.
|
||||
* When the return value is -RT_ENOMEM, it means insufficient memory allocation failed.
|
||||
*/
|
||||
static rt_err_t rt_pipe_open(rt_device_t device, rt_uint16_t oflag)
|
||||
{
|
||||
rt_pipe_t *pipe = (rt_pipe_t *)device;
|
||||
rt_err_t ret = RT_EOK;
|
||||
|
||||
if (device == RT_NULL)
|
||||
{
|
||||
ret = -RT_EINVAL;
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
|
||||
|
||||
if (pipe->fifo == RT_NULL)
|
||||
{
|
||||
pipe->fifo = rt_ringbuffer_create(pipe->bufsz);
|
||||
if (pipe->fifo == RT_NULL)
|
||||
{
|
||||
ret = -RT_ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
rt_mutex_release(&(pipe->lock));
|
||||
|
||||
__exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will close the pipe and release the pipe buffer.
|
||||
*
|
||||
* @param device is a pointer to the pipe device descriptor.
|
||||
*
|
||||
* @return Return the operation status.
|
||||
* When the return value is RT_EOK, the operation is successful.
|
||||
* When the return value is -RT_EINVAL, it means the device handle is empty.
|
||||
*/
|
||||
static rt_err_t rt_pipe_close(rt_device_t device)
|
||||
{
|
||||
rt_pipe_t *pipe = (rt_pipe_t *)device;
|
||||
|
||||
if (device == RT_NULL) return -RT_EINVAL;
|
||||
rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
|
||||
|
||||
if (device->ref_count == 1)
|
||||
{
|
||||
rt_ringbuffer_destroy(pipe->fifo);
|
||||
pipe->fifo = RT_NULL;
|
||||
}
|
||||
|
||||
rt_mutex_release(&(pipe->lock));
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will read the specified length of data from the pipe.
|
||||
*
|
||||
* @param device is a pointer to the pipe device descriptor.
|
||||
*
|
||||
* @param pos is a parameter compatible with POSIX standard interface (currently meaningless, just pass in 0).
|
||||
*
|
||||
* @param buffer is a pointer to the buffer to store the read data.
|
||||
*
|
||||
* @param count is the length of data to be read.
|
||||
*
|
||||
* @return Return the length of data read.
|
||||
* When the return value is 0, it means the pipe device handle is empty or the count is 0.
|
||||
*/
|
||||
static rt_size_t rt_pipe_read(rt_device_t device, rt_off_t pos, void *buffer, rt_size_t count)
|
||||
{
|
||||
uint8_t *pbuf;
|
||||
rt_size_t read_bytes = 0;
|
||||
rt_pipe_t *pipe = (rt_pipe_t *)device;
|
||||
|
||||
if (device == RT_NULL)
|
||||
{
|
||||
rt_set_errno(EINVAL);
|
||||
return 0;
|
||||
}
|
||||
if (count == 0) return 0;
|
||||
|
||||
pbuf = (uint8_t*)buffer;
|
||||
rt_mutex_take(&(pipe->lock), RT_WAITING_FOREVER);
|
||||
|
||||
while (read_bytes < count)
|
||||
{
|
||||
int len = rt_ringbuffer_get(pipe->fifo, &pbuf[read_bytes], count - read_bytes);
|
||||
if (len <= 0) break;
|
||||
|
||||
read_bytes += len;
|
||||
}
|
||||
rt_mutex_release(&pipe->lock);
|
||||
|
||||
return read_bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will write the specified length of data to the pipe.
|
||||
*
|
||||
* @param device is a pointer to the pipe device descriptor.
|
||||
*
|
||||
* @param pos is a parameter compatible with POSIX standard interface (currently meaningless, just pass in 0).
|
||||
*
|
||||
* @param buffer is a pointer to the data buffer to be written.
|
||||
*
|
||||
* @param count is the length of data to be written.
|
||||
*
|
||||
* @return Return the length of data written.
|
||||
* When the return value is 0, it means the pipe device handle is empty or the count is 0.
|
||||
*/
|
||||
static rt_size_t rt_pipe_write(rt_device_t device, rt_off_t pos, const void *buffer, rt_size_t count)
|
||||
{
|
||||
uint8_t *pbuf;
|
||||
rt_size_t write_bytes = 0;
|
||||
rt_pipe_t *pipe = (rt_pipe_t *)device;
|
||||
|
||||
if (device == RT_NULL)
|
||||
{
|
||||
rt_set_errno(EINVAL);
|
||||
return 0;
|
||||
}
|
||||
if (count == 0) return 0;
|
||||
|
||||
pbuf = (uint8_t*)buffer;
|
||||
rt_mutex_take(&pipe->lock, -1);
|
||||
|
||||
while (write_bytes < count)
|
||||
{
|
||||
int len = rt_ringbuffer_put(pipe->fifo, &pbuf[write_bytes], count - write_bytes);
|
||||
if (len <= 0) break;
|
||||
|
||||
write_bytes += len;
|
||||
}
|
||||
rt_mutex_release(&pipe->lock);
|
||||
|
||||
return write_bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function is not used yet.
|
||||
*
|
||||
* @param dev is not used yet.
|
||||
*
|
||||
* @param cmd is not used yet.
|
||||
*
|
||||
* @param args is not used yet.
|
||||
*
|
||||
* @return Always return RT_EOK.
|
||||
*/
|
||||
static rt_err_t rt_pipe_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops pipe_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
rt_pipe_open,
|
||||
rt_pipe_close,
|
||||
rt_pipe_read,
|
||||
rt_pipe_write,
|
||||
rt_pipe_control,
|
||||
};
|
||||
#endif /* RT_USING_DEVICE_OPS */
|
||||
|
||||
/**
|
||||
* @brief This function will initialize a pipe device.
|
||||
* The system allocates a pipe handle from dynamic heap memory, initializes the pipe handle
|
||||
* with the specified value, and registers the pipe device with the system.
|
||||
*
|
||||
* @param name is the name of pipe device.
|
||||
*
|
||||
* @param bufsz is the size of pipe buffer.
|
||||
*
|
||||
* @return Return the pointer to the pipe device.
|
||||
* When the return value is RT_NULL, it means the initialization failed.
|
||||
*/
|
||||
rt_pipe_t *rt_pipe_create(const char *name, int bufsz)
|
||||
{
|
||||
rt_pipe_t *pipe;
|
||||
rt_device_t dev;
|
||||
|
||||
pipe = (rt_pipe_t *)rt_malloc(sizeof(rt_pipe_t));
|
||||
if (pipe == RT_NULL) return RT_NULL;
|
||||
|
||||
rt_memset(pipe, 0, sizeof(rt_pipe_t));
|
||||
pipe->is_named = RT_TRUE; /* initialize as a named pipe */
|
||||
rt_mutex_init(&(pipe->lock), name, RT_IPC_FLAG_PRIO);
|
||||
rt_wqueue_init(&(pipe->reader_queue));
|
||||
rt_wqueue_init(&(pipe->writer_queue));
|
||||
|
||||
RT_ASSERT(bufsz < 0xFFFF);
|
||||
pipe->bufsz = bufsz;
|
||||
|
||||
dev = &(pipe->parent);
|
||||
dev->type = RT_Device_Class_Pipe;
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
dev->ops = &pipe_ops;
|
||||
#else
|
||||
dev->init = RT_NULL;
|
||||
dev->open = rt_pipe_open;
|
||||
dev->read = rt_pipe_read;
|
||||
dev->write = rt_pipe_write;
|
||||
dev->close = rt_pipe_close;
|
||||
dev->control = rt_pipe_control;
|
||||
#endif
|
||||
|
||||
dev->rx_indicate = RT_NULL;
|
||||
dev->tx_complete = RT_NULL;
|
||||
|
||||
if (rt_device_register(&(pipe->parent), name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE) != 0)
|
||||
{
|
||||
rt_free(pipe);
|
||||
return RT_NULL;
|
||||
}
|
||||
#if defined(RT_USING_POSIX_DEVIO) && defined(RT_USING_POSIX_PIPE)
|
||||
dev->fops = (void*)&pipe_fops;
|
||||
#endif
|
||||
|
||||
return pipe;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will delete a pipe device.
|
||||
* The system will release the pipe handle and unregister the pipe device from the system.
|
||||
*
|
||||
* @param pipe is the pointer to the pipe device.
|
||||
*
|
||||
* @return Return the operation status.
|
||||
* When the return value is 0, it means the operation is successful.
|
||||
* When the return value is -RT_EINVAL, it means the pipe device is not found or the device isn't a pipe.
|
||||
* When the return value is -RT_EBUSY, it means the pipe device is busy.
|
||||
*/
|
||||
int rt_pipe_delete(const char *name)
|
||||
{
|
||||
int result = 0;
|
||||
rt_device_t device;
|
||||
|
||||
device = rt_device_find(name);
|
||||
if (device)
|
||||
{
|
||||
if (device->type == RT_Device_Class_Pipe)
|
||||
{
|
||||
rt_pipe_t *pipe;
|
||||
|
||||
if (device->ref_count != 0)
|
||||
{
|
||||
return -RT_EBUSY;
|
||||
}
|
||||
|
||||
pipe = (rt_pipe_t *)device;
|
||||
|
||||
rt_mutex_detach(&(pipe->lock));
|
||||
rt_device_unregister(device);
|
||||
|
||||
/* close fifo ringbuffer */
|
||||
if (pipe->fifo)
|
||||
{
|
||||
rt_ringbuffer_destroy(pipe->fifo);
|
||||
pipe->fifo = RT_NULL;
|
||||
}
|
||||
rt_free(pipe);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_EINVAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(RT_USING_POSIX_DEVIO) && defined(RT_USING_POSIX_PIPE)
|
||||
/**
|
||||
* @brief This function will creat a anonymous pipe.
|
||||
*
|
||||
* @param fildes[0] is the read handle.
|
||||
* fildes[1] is the write handle.
|
||||
*
|
||||
* @return Return the operation status.
|
||||
* When the return value is 0, it means the operation is successful.
|
||||
* When the return value is -1, it means the operation is failed.
|
||||
*/
|
||||
int pipe(int fildes[2])
|
||||
{
|
||||
rt_pipe_t *pipe;
|
||||
char dname[RT_NAME_MAX];
|
||||
char dev_name[RT_NAME_MAX * 4];
|
||||
static int pipeno = 0;
|
||||
|
||||
rt_snprintf(dname, sizeof(dname), "pipe%d", pipeno++);
|
||||
|
||||
pipe = rt_pipe_create(dname, RT_USING_POSIX_PIPE_SIZE);
|
||||
if (pipe == RT_NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
pipe->is_named = RT_FALSE; /* unamed pipe */
|
||||
rt_snprintf(dev_name, sizeof(dev_name), "/dev/%s", dname);
|
||||
fildes[0] = open(dev_name, O_RDONLY, 0);
|
||||
if (fildes[0] < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
fildes[1] = open(dev_name, O_WRONLY, 0);
|
||||
if (fildes[1] < 0)
|
||||
{
|
||||
close(fildes[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will create a named pipe.
|
||||
*
|
||||
* @param path is the name of pipe device.
|
||||
*
|
||||
* @param mode is not used yet.
|
||||
*
|
||||
* @return Return the operation status.
|
||||
* When the return value is 0, it means the operation is successful.
|
||||
* When the return value is -1, it means the operation is failed.
|
||||
*/
|
||||
int mkfifo(const char *path, mode_t mode)
|
||||
{
|
||||
rt_pipe_t *pipe;
|
||||
|
||||
pipe = rt_pipe_create(path, RT_USING_POSIX_PIPE_SIZE);
|
||||
if (pipe == RT_NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* defined(RT_USING_POSIX_DEVIO) && defined(RT_USING_POSIX_PIPE) */
|
||||
@@ -0,0 +1,596 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-08-25 armink the first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
/**
|
||||
* ring block buffer object initialization
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
* @param buf buffer
|
||||
* @param buf_size buffer size
|
||||
* @param block_set block set
|
||||
* @param blk_max_num max block number
|
||||
*
|
||||
* @note When your application need align access, please make the buffer address is aligned.
|
||||
*/
|
||||
void rt_rbb_init(rt_rbb_t rbb, rt_uint8_t *buf, rt_size_t buf_size, rt_rbb_blk_t block_set, rt_size_t blk_max_num)
|
||||
{
|
||||
rt_size_t i;
|
||||
|
||||
RT_ASSERT(rbb);
|
||||
RT_ASSERT(buf);
|
||||
RT_ASSERT(block_set);
|
||||
|
||||
rbb->buf = buf;
|
||||
rbb->buf_size = buf_size;
|
||||
rbb->blk_set = block_set;
|
||||
rbb->blk_max_num = blk_max_num;
|
||||
rbb->tail = &rbb->blk_list;
|
||||
rt_slist_init(&rbb->blk_list);
|
||||
rt_slist_init(&rbb->free_list);
|
||||
/* initialize block status */
|
||||
for (i = 0; i < blk_max_num; i++)
|
||||
{
|
||||
block_set[i].status = RT_RBB_BLK_UNUSED;
|
||||
rt_slist_init(&block_set[i].list);
|
||||
rt_slist_insert(&rbb->free_list, &block_set[i].list);
|
||||
}
|
||||
}
|
||||
RTM_EXPORT(rt_rbb_init);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
|
||||
/**
|
||||
* ring block buffer object create
|
||||
*
|
||||
* @param buf_size buffer size
|
||||
* @param blk_max_num max block number
|
||||
*
|
||||
* @return != RT_NULL: ring block buffer object
|
||||
* RT_NULL: create failed
|
||||
*/
|
||||
rt_rbb_t rt_rbb_create(rt_size_t buf_size, rt_size_t blk_max_num)
|
||||
{
|
||||
rt_rbb_t rbb = RT_NULL;
|
||||
rt_uint8_t *buf;
|
||||
rt_rbb_blk_t blk_set;
|
||||
|
||||
rbb = (rt_rbb_t)rt_malloc(sizeof(struct rt_rbb));
|
||||
if (!rbb)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
buf = (rt_uint8_t *)rt_malloc(buf_size);
|
||||
if (!buf)
|
||||
{
|
||||
rt_free(rbb);
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
blk_set = (rt_rbb_blk_t)rt_malloc(sizeof(struct rt_rbb_blk) * blk_max_num);
|
||||
if (!blk_set)
|
||||
{
|
||||
rt_free(buf);
|
||||
rt_free(rbb);
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
rt_rbb_init(rbb, buf, buf_size, blk_set, blk_max_num);
|
||||
|
||||
return rbb;
|
||||
}
|
||||
RTM_EXPORT(rt_rbb_create);
|
||||
|
||||
/**
|
||||
* ring block buffer object destroy
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
*/
|
||||
void rt_rbb_destroy(rt_rbb_t rbb)
|
||||
{
|
||||
RT_ASSERT(rbb);
|
||||
|
||||
rt_free(rbb->buf);
|
||||
rt_free(rbb->blk_set);
|
||||
rt_free(rbb);
|
||||
|
||||
}
|
||||
RTM_EXPORT(rt_rbb_destroy);
|
||||
|
||||
#endif
|
||||
|
||||
static rt_rbb_blk_t find_empty_blk_in_set(rt_rbb_t rbb)
|
||||
{
|
||||
struct rt_rbb_blk *blk;
|
||||
|
||||
RT_ASSERT(rbb);
|
||||
|
||||
if (rt_slist_isempty(&rbb->free_list))
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
blk = rt_slist_first_entry(&rbb->free_list, struct rt_rbb_blk, list);
|
||||
rt_slist_remove(&rbb->free_list, &blk->list);
|
||||
RT_ASSERT(blk->status == RT_RBB_BLK_UNUSED);
|
||||
return blk;
|
||||
}
|
||||
|
||||
rt_inline void list_append(rt_rbb_t rbb, rt_slist_t* n)
|
||||
{
|
||||
/* append the node to the tail */
|
||||
rbb->tail->next = n;
|
||||
n->next = RT_NULL;
|
||||
/* save tail node */
|
||||
rbb->tail = n;
|
||||
}
|
||||
|
||||
rt_inline rt_slist_t *list_remove(rt_rbb_t rbb, rt_slist_t* n)
|
||||
{
|
||||
rt_slist_t* l = &rbb->blk_list;
|
||||
struct rt_slist_node* node = l;
|
||||
|
||||
/* remove slist head */
|
||||
while (node->next && node->next != n) node = node->next;
|
||||
/* remove node */
|
||||
if (node->next != (rt_slist_t*)0)
|
||||
{
|
||||
node->next = node->next->next;
|
||||
n->next = RT_NULL;
|
||||
/* update tail node */
|
||||
if (rbb->tail == n)
|
||||
rbb->tail = node;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a block by given size. The block will add to blk_list when allocate success.
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
* @param blk_size block size
|
||||
*
|
||||
* @note When your application need align access, please make the blk_szie is aligned.
|
||||
*
|
||||
* @return != RT_NULL: allocated block
|
||||
* RT_NULL: allocate failed
|
||||
*/
|
||||
rt_rbb_blk_t rt_rbb_blk_alloc(rt_rbb_t rbb, rt_size_t blk_size)
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_size_t empty1 = 0, empty2 = 0;
|
||||
rt_rbb_blk_t head, tail, new_rbb = RT_NULL;
|
||||
|
||||
RT_ASSERT(rbb);
|
||||
RT_ASSERT(blk_size < (1L << 24));
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
new_rbb = find_empty_blk_in_set(rbb);
|
||||
|
||||
if (new_rbb)
|
||||
{
|
||||
if (rt_slist_isempty(&rbb->blk_list) == 0)
|
||||
{
|
||||
head = rt_slist_first_entry(&rbb->blk_list, struct rt_rbb_blk, list);
|
||||
/* get tail rbb blk object */
|
||||
tail = rt_slist_entry(rbb->tail, struct rt_rbb_blk, list);
|
||||
if (head->buf <= tail->buf)
|
||||
{
|
||||
/**
|
||||
* head tail
|
||||
* +--------------------------------------+-----------------+------------------+
|
||||
* | empty2 | block1 | block2 | block3 | empty1 |
|
||||
* +--------------------------------------+-----------------+------------------+
|
||||
* rbb->buf
|
||||
*/
|
||||
empty1 = (rbb->buf + rbb->buf_size) - (tail->buf + tail->size);
|
||||
empty2 = head->buf - rbb->buf;
|
||||
|
||||
if (empty1 >= blk_size)
|
||||
{
|
||||
list_append(rbb, &new_rbb->list);
|
||||
new_rbb->status = RT_RBB_BLK_INITED;
|
||||
new_rbb->buf = tail->buf + tail->size;
|
||||
new_rbb->size = blk_size;
|
||||
}
|
||||
else if (empty2 >= blk_size)
|
||||
{
|
||||
list_append(rbb, &new_rbb->list);
|
||||
new_rbb->status = RT_RBB_BLK_INITED;
|
||||
new_rbb->buf = rbb->buf;
|
||||
new_rbb->size = blk_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no space */
|
||||
new_rbb = RT_NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
* tail head
|
||||
* +----------------+-------------------------------------+--------+-----------+
|
||||
* | block3 | empty1 | block1 | block2 |
|
||||
* +----------------+-------------------------------------+--------+-----------+
|
||||
* rbb->buf
|
||||
*/
|
||||
empty1 = head->buf - (tail->buf + tail->size);
|
||||
|
||||
if (empty1 >= blk_size)
|
||||
{
|
||||
list_append(rbb, &new_rbb->list);
|
||||
new_rbb->status = RT_RBB_BLK_INITED;
|
||||
new_rbb->buf = tail->buf + tail->size;
|
||||
new_rbb->size = blk_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no space */
|
||||
new_rbb = RT_NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* the list is empty */
|
||||
list_append(rbb, &new_rbb->list);
|
||||
new_rbb->status = RT_RBB_BLK_INITED;
|
||||
new_rbb->buf = rbb->buf;
|
||||
new_rbb->size = blk_size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_rbb = RT_NULL;
|
||||
}
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return new_rbb;
|
||||
}
|
||||
RTM_EXPORT(rt_rbb_blk_alloc);
|
||||
|
||||
/**
|
||||
* put a block to ring block buffer object
|
||||
*
|
||||
* @param block the block
|
||||
*/
|
||||
void rt_rbb_blk_put(rt_rbb_blk_t block)
|
||||
{
|
||||
RT_ASSERT(block);
|
||||
RT_ASSERT(block->status == RT_RBB_BLK_INITED);
|
||||
|
||||
block->status = RT_RBB_BLK_PUT;
|
||||
}
|
||||
RTM_EXPORT(rt_rbb_blk_put);
|
||||
|
||||
/**
|
||||
* get a block from the ring block buffer object
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
*
|
||||
* @return != RT_NULL: block
|
||||
* RT_NULL: get failed
|
||||
*/
|
||||
rt_rbb_blk_t rt_rbb_blk_get(rt_rbb_t rbb)
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_rbb_blk_t block = RT_NULL;
|
||||
rt_slist_t *node;
|
||||
|
||||
RT_ASSERT(rbb);
|
||||
|
||||
if (rt_slist_isempty(&rbb->blk_list))
|
||||
return 0;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
for (node = rt_slist_first(&rbb->blk_list); node; node = rt_slist_next(node))
|
||||
{
|
||||
block = rt_slist_entry(node, struct rt_rbb_blk, list);
|
||||
if (block->status == RT_RBB_BLK_PUT)
|
||||
{
|
||||
block->status = RT_RBB_BLK_GET;
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
/* not found */
|
||||
block = RT_NULL;
|
||||
|
||||
__exit:
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return block;
|
||||
}
|
||||
RTM_EXPORT(rt_rbb_blk_get);
|
||||
|
||||
/**
|
||||
* return the block size
|
||||
*
|
||||
* @param block the block
|
||||
*
|
||||
* @return block size
|
||||
*/
|
||||
rt_size_t rt_rbb_blk_size(rt_rbb_blk_t block)
|
||||
{
|
||||
RT_ASSERT(block);
|
||||
|
||||
return block->size;
|
||||
}
|
||||
RTM_EXPORT(rt_rbb_blk_size);
|
||||
|
||||
/**
|
||||
* return the block buffer
|
||||
*
|
||||
* @param block the block
|
||||
*
|
||||
* @return block buffer
|
||||
*/
|
||||
rt_uint8_t *rt_rbb_blk_buf(rt_rbb_blk_t block)
|
||||
{
|
||||
RT_ASSERT(block);
|
||||
|
||||
return block->buf;
|
||||
}
|
||||
RTM_EXPORT(rt_rbb_blk_buf);
|
||||
|
||||
/**
|
||||
* free the block
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
* @param block the block
|
||||
*/
|
||||
void rt_rbb_blk_free(rt_rbb_t rbb, rt_rbb_blk_t block)
|
||||
{
|
||||
rt_base_t level;
|
||||
|
||||
RT_ASSERT(rbb);
|
||||
RT_ASSERT(block);
|
||||
RT_ASSERT(block->status != RT_RBB_BLK_UNUSED);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
/* remove it on rbb block list */
|
||||
list_remove(rbb, &block->list);
|
||||
block->status = RT_RBB_BLK_UNUSED;
|
||||
rt_slist_insert(&rbb->free_list, &block->list);
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
RTM_EXPORT(rt_rbb_blk_free);
|
||||
|
||||
/**
|
||||
* get a continuous block to queue by given size
|
||||
*
|
||||
* tail head
|
||||
* +------------------+---------------+--------+----------+--------+
|
||||
* | block3 | empty1 | block1 | block2 |fragment|
|
||||
* +------------------+------------------------+----------+--------+
|
||||
* |<-- return_size -->| |
|
||||
* |<--- queue_data_len --->|
|
||||
*
|
||||
* tail head
|
||||
* +------------------+---------------+--------+----------+--------+
|
||||
* | block3 | empty1 | block1 | block2 |fragment|
|
||||
* +------------------+------------------------+----------+--------+
|
||||
* |<-- return_size -->| out of len(b1+b2+b3) |
|
||||
* |<-------------------- queue_data_len -------------------->|
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
* @param queue_data_len The max queue data size, and the return size must less then it.
|
||||
* @param queue continuous block queue
|
||||
*
|
||||
* @return the block queue data total size
|
||||
*/
|
||||
rt_size_t rt_rbb_blk_queue_get(rt_rbb_t rbb, rt_size_t queue_data_len, rt_rbb_blk_queue_t blk_queue)
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_size_t data_total_size = 0;
|
||||
rt_slist_t *node, *tmp = RT_NULL;
|
||||
rt_rbb_blk_t last_block = RT_NULL, block;
|
||||
|
||||
RT_ASSERT(rbb);
|
||||
RT_ASSERT(blk_queue);
|
||||
|
||||
if (rt_slist_isempty(&rbb->blk_list))
|
||||
return 0;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
node = rt_slist_first(&rbb->blk_list);
|
||||
if (node != RT_NULL)
|
||||
{
|
||||
tmp = rt_slist_next(node);
|
||||
}
|
||||
for (; node; node = tmp, tmp = rt_slist_next(node))
|
||||
{
|
||||
if (!last_block)
|
||||
{
|
||||
last_block = rt_slist_entry(node, struct rt_rbb_blk, list);
|
||||
if (last_block->status == RT_RBB_BLK_PUT)
|
||||
{
|
||||
/* save the first put status block to queue */
|
||||
blk_queue->blocks = last_block;
|
||||
blk_queue->blk_num = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* the first block must be put status */
|
||||
last_block = RT_NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
block = rt_slist_entry(node, struct rt_rbb_blk, list);
|
||||
/*
|
||||
* these following conditions will break the loop:
|
||||
* 1. the current block is not put status
|
||||
* 2. the last block and current block is not continuous
|
||||
* 3. the data_total_size will out of range
|
||||
*/
|
||||
if (block->status != RT_RBB_BLK_PUT ||
|
||||
last_block->buf > block->buf ||
|
||||
data_total_size + block->size > queue_data_len)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* backup last block */
|
||||
last_block = block;
|
||||
}
|
||||
/* remove current block */
|
||||
data_total_size += last_block->size;
|
||||
last_block->status = RT_RBB_BLK_GET;
|
||||
blk_queue->blk_num++;
|
||||
}
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return data_total_size;
|
||||
}
|
||||
RTM_EXPORT(rt_rbb_blk_queue_get);
|
||||
|
||||
/**
|
||||
* get all block length on block queue
|
||||
*
|
||||
* @param blk_queue the block queue
|
||||
*
|
||||
* @return total length
|
||||
*/
|
||||
rt_size_t rt_rbb_blk_queue_len(rt_rbb_blk_queue_t blk_queue)
|
||||
{
|
||||
rt_size_t i = 0, data_total_size = 0;
|
||||
rt_rbb_blk_t blk;
|
||||
|
||||
RT_ASSERT(blk_queue);
|
||||
|
||||
for (blk = blk_queue->blocks; i < blk_queue->blk_num; i++)
|
||||
{
|
||||
data_total_size += blk->size;
|
||||
blk = rt_slist_entry(blk->list.next, struct rt_rbb_blk, list);
|
||||
}
|
||||
return data_total_size;
|
||||
}
|
||||
RTM_EXPORT(rt_rbb_blk_queue_len);
|
||||
|
||||
/**
|
||||
* return the block queue buffer
|
||||
*
|
||||
* @param blk_queue the block queue
|
||||
*
|
||||
* @return block queue buffer
|
||||
*/
|
||||
rt_uint8_t *rt_rbb_blk_queue_buf(rt_rbb_blk_queue_t blk_queue)
|
||||
{
|
||||
RT_ASSERT(blk_queue);
|
||||
|
||||
return blk_queue->blocks[0].buf;
|
||||
}
|
||||
RTM_EXPORT(rt_rbb_blk_queue_buf);
|
||||
|
||||
/**
|
||||
* free the block queue
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
* @param blk_queue the block queue
|
||||
*/
|
||||
void rt_rbb_blk_queue_free(rt_rbb_t rbb, rt_rbb_blk_queue_t blk_queue)
|
||||
{
|
||||
rt_size_t i = 0;
|
||||
rt_rbb_blk_t blk, next_blk;
|
||||
|
||||
RT_ASSERT(rbb);
|
||||
RT_ASSERT(blk_queue);
|
||||
|
||||
for (blk = blk_queue->blocks; i < blk_queue->blk_num; i++)
|
||||
{
|
||||
next_blk = rt_slist_entry(blk->list.next, struct rt_rbb_blk, list);
|
||||
rt_rbb_blk_free(rbb, blk);
|
||||
blk = next_blk;
|
||||
}
|
||||
}
|
||||
RTM_EXPORT(rt_rbb_blk_queue_free);
|
||||
|
||||
/**
|
||||
* The put status and buffer continuous blocks can be make a block queue.
|
||||
* This function will return the length which from next can be make block queue.
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
*
|
||||
* @return the next can be make block queue's length
|
||||
*/
|
||||
rt_size_t rt_rbb_next_blk_queue_len(rt_rbb_t rbb)
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_size_t data_len = 0;
|
||||
rt_slist_t *node;
|
||||
rt_rbb_blk_t last_block = RT_NULL, block;
|
||||
|
||||
RT_ASSERT(rbb);
|
||||
|
||||
if (rt_slist_isempty(&rbb->blk_list))
|
||||
return 0;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
for (node = rt_slist_first(&rbb->blk_list); node; node = rt_slist_next(node))
|
||||
{
|
||||
if (!last_block)
|
||||
{
|
||||
last_block = rt_slist_entry(node, struct rt_rbb_blk, list);
|
||||
if (last_block->status != RT_RBB_BLK_PUT)
|
||||
{
|
||||
/* the first block must be put status */
|
||||
last_block = RT_NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
block = rt_slist_entry(node, struct rt_rbb_blk, list);
|
||||
/*
|
||||
* these following conditions will break the loop:
|
||||
* 1. the current block is not put status
|
||||
* 2. the last block and current block is not continuous
|
||||
*/
|
||||
if (block->status != RT_RBB_BLK_PUT || last_block->buf > block->buf)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* backup last block */
|
||||
last_block = block;
|
||||
}
|
||||
data_len += last_block->size;
|
||||
}
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return data_len;
|
||||
}
|
||||
RTM_EXPORT(rt_rbb_next_blk_queue_len);
|
||||
|
||||
/**
|
||||
* get the ring block buffer object buffer size
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
*
|
||||
* @return buffer size
|
||||
*/
|
||||
rt_size_t rt_rbb_get_buf_size(rt_rbb_t rbb)
|
||||
{
|
||||
RT_ASSERT(rbb);
|
||||
|
||||
return rbb->buf_size;
|
||||
}
|
||||
RTM_EXPORT(rt_rbb_get_buf_size);
|
||||
@@ -0,0 +1,467 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-09-30 Bernard first version.
|
||||
* 2013-05-08 Grissiom reimplement
|
||||
* 2016-08-18 heyuanjie add interface
|
||||
* 2021-07-20 arminker fix write_index bug in function rt_ringbuffer_put_force
|
||||
* 2021-08-14 Jackistang add comments for function interface.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <string.h>
|
||||
|
||||
rt_inline enum rt_ringbuffer_state rt_ringbuffer_status(struct rt_ringbuffer *rb)
|
||||
{
|
||||
if (rb->read_index == rb->write_index)
|
||||
{
|
||||
if (rb->read_mirror == rb->write_mirror)
|
||||
return RT_RINGBUFFER_EMPTY;
|
||||
else
|
||||
return RT_RINGBUFFER_FULL;
|
||||
}
|
||||
return RT_RINGBUFFER_HALFFULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the ring buffer object.
|
||||
*
|
||||
* @param rb A pointer to the ring buffer object.
|
||||
* @param pool A pointer to the buffer.
|
||||
* @param size The size of the buffer in bytes.
|
||||
*/
|
||||
void rt_ringbuffer_init(struct rt_ringbuffer *rb,
|
||||
rt_uint8_t *pool,
|
||||
rt_int16_t size)
|
||||
{
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
RT_ASSERT(size > 0);
|
||||
|
||||
/* initialize read and write index */
|
||||
rb->read_mirror = rb->read_index = 0;
|
||||
rb->write_mirror = rb->write_index = 0;
|
||||
|
||||
/* set buffer pool and size */
|
||||
rb->buffer_ptr = pool;
|
||||
rb->buffer_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_init);
|
||||
|
||||
/**
|
||||
* @brief Put a block of data into the ring buffer. If the capacity of ring buffer is insufficient, it will discard out-of-range data.
|
||||
*
|
||||
* @param rb A pointer to the ring buffer object.
|
||||
* @param ptr A pointer to the data buffer.
|
||||
* @param length The size of data in bytes.
|
||||
*
|
||||
* @return Return the data size we put into the ring buffer.
|
||||
*/
|
||||
rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb,
|
||||
const rt_uint8_t *ptr,
|
||||
rt_uint16_t length)
|
||||
{
|
||||
rt_uint16_t size;
|
||||
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
|
||||
/* whether has enough space */
|
||||
size = rt_ringbuffer_space_len(rb);
|
||||
|
||||
/* no space */
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
/* drop some data */
|
||||
if (size < length)
|
||||
length = size;
|
||||
|
||||
if (rb->buffer_size - rb->write_index > length)
|
||||
{
|
||||
/* read_index - write_index = empty space */
|
||||
rt_memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
|
||||
/* this should not cause overflow because there is enough space for
|
||||
* length of data in current mirror */
|
||||
rb->write_index += length;
|
||||
return length;
|
||||
}
|
||||
|
||||
rt_memcpy(&rb->buffer_ptr[rb->write_index],
|
||||
&ptr[0],
|
||||
rb->buffer_size - rb->write_index);
|
||||
rt_memcpy(&rb->buffer_ptr[0],
|
||||
&ptr[rb->buffer_size - rb->write_index],
|
||||
length - (rb->buffer_size - rb->write_index));
|
||||
|
||||
/* we are going into the other side of the mirror */
|
||||
rb->write_mirror = ~rb->write_mirror;
|
||||
rb->write_index = length - (rb->buffer_size - rb->write_index);
|
||||
|
||||
return length;
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_put);
|
||||
|
||||
/**
|
||||
* @brief Put a block of data into the ring buffer. If the capacity of ring buffer is insufficient, it will overwrite the existing data in the ring buffer.
|
||||
*
|
||||
* @param rb A pointer to the ring buffer object.
|
||||
* @param ptr A pointer to the data buffer.
|
||||
* @param length The size of data in bytes.
|
||||
*
|
||||
* @return Return the data size we put into the ring buffer.
|
||||
*/
|
||||
rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb,
|
||||
const rt_uint8_t *ptr,
|
||||
rt_uint16_t length)
|
||||
{
|
||||
rt_uint16_t space_length;
|
||||
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
|
||||
space_length = rt_ringbuffer_space_len(rb);
|
||||
|
||||
if (length > rb->buffer_size)
|
||||
{
|
||||
ptr = &ptr[length - rb->buffer_size];
|
||||
length = rb->buffer_size;
|
||||
}
|
||||
|
||||
if (rb->buffer_size - rb->write_index > length)
|
||||
{
|
||||
/* read_index - write_index = empty space */
|
||||
rt_memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
|
||||
/* this should not cause overflow because there is enough space for
|
||||
* length of data in current mirror */
|
||||
rb->write_index += length;
|
||||
|
||||
if (length > space_length)
|
||||
rb->read_index = rb->write_index;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
rt_memcpy(&rb->buffer_ptr[rb->write_index],
|
||||
&ptr[0],
|
||||
rb->buffer_size - rb->write_index);
|
||||
rt_memcpy(&rb->buffer_ptr[0],
|
||||
&ptr[rb->buffer_size - rb->write_index],
|
||||
length - (rb->buffer_size - rb->write_index));
|
||||
|
||||
/* we are going into the other side of the mirror */
|
||||
rb->write_mirror = ~rb->write_mirror;
|
||||
rb->write_index = length - (rb->buffer_size - rb->write_index);
|
||||
|
||||
if (length > space_length)
|
||||
{
|
||||
if (rb->write_index <= rb->read_index)
|
||||
rb->read_mirror = ~rb->read_mirror;
|
||||
rb->read_index = rb->write_index;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_put_force);
|
||||
|
||||
/**
|
||||
* @brief Get data from the ring buffer.
|
||||
*
|
||||
* @param rb A pointer to the ring buffer.
|
||||
* @param ptr A pointer to the data buffer.
|
||||
* @param length The size of the data we want to read from the ring buffer.
|
||||
*
|
||||
* @return Return the data size we read from the ring buffer.
|
||||
*/
|
||||
rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb,
|
||||
rt_uint8_t *ptr,
|
||||
rt_uint16_t length)
|
||||
{
|
||||
rt_size_t size;
|
||||
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
|
||||
/* whether has enough data */
|
||||
size = rt_ringbuffer_data_len(rb);
|
||||
|
||||
/* no data */
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
/* less data */
|
||||
if (size < length)
|
||||
length = size;
|
||||
|
||||
if (rb->buffer_size - rb->read_index > length)
|
||||
{
|
||||
/* copy all of data */
|
||||
rt_memcpy(ptr, &rb->buffer_ptr[rb->read_index], length);
|
||||
/* this should not cause overflow because there is enough space for
|
||||
* length of data in current mirror */
|
||||
rb->read_index += length;
|
||||
return length;
|
||||
}
|
||||
|
||||
rt_memcpy(&ptr[0],
|
||||
&rb->buffer_ptr[rb->read_index],
|
||||
rb->buffer_size - rb->read_index);
|
||||
rt_memcpy(&ptr[rb->buffer_size - rb->read_index],
|
||||
&rb->buffer_ptr[0],
|
||||
length - (rb->buffer_size - rb->read_index));
|
||||
|
||||
/* we are going into the other side of the mirror */
|
||||
rb->read_mirror = ~rb->read_mirror;
|
||||
rb->read_index = length - (rb->buffer_size - rb->read_index);
|
||||
|
||||
return length;
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_get);
|
||||
|
||||
/**
|
||||
* @brief Get the first readable byte of the ring buffer.
|
||||
*
|
||||
* @param rb A pointer to the ringbuffer.
|
||||
* @param ptr When this function return, *ptr is a pointer to the first readable byte of the ring buffer.
|
||||
*
|
||||
* @note It is recommended to read only one byte, otherwise it may cause buffer overflow.
|
||||
*
|
||||
* @return Return the size of the ring buffer.
|
||||
*/
|
||||
rt_size_t rt_ringbuffer_peak(struct rt_ringbuffer *rb, rt_uint8_t **ptr)
|
||||
{
|
||||
rt_size_t size;
|
||||
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
|
||||
*ptr = RT_NULL;
|
||||
|
||||
/* whether has enough data */
|
||||
size = rt_ringbuffer_data_len(rb);
|
||||
|
||||
/* no data */
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
*ptr = &rb->buffer_ptr[rb->read_index];
|
||||
|
||||
if((rt_size_t)(rb->buffer_size - rb->read_index) > size)
|
||||
{
|
||||
rb->read_index += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
size = rb->buffer_size - rb->read_index;
|
||||
|
||||
/* we are going into the other side of the mirror */
|
||||
rb->read_mirror = ~rb->read_mirror;
|
||||
rb->read_index = 0;
|
||||
|
||||
return size;
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_peak);
|
||||
|
||||
/**
|
||||
* @brief Put a byte into the ring buffer. If ring buffer is full, this operation will fail.
|
||||
*
|
||||
* @param rb A pointer to the ring buffer object.
|
||||
* @param ch A byte put into the ring buffer.
|
||||
*
|
||||
* @return Return the data size we put into the ring buffer. The ring buffer is full if returns 0. Otherwise, it will return 1.
|
||||
*/
|
||||
rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch)
|
||||
{
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
|
||||
/* whether has enough space */
|
||||
if (!rt_ringbuffer_space_len(rb))
|
||||
return 0;
|
||||
|
||||
rb->buffer_ptr[rb->write_index] = ch;
|
||||
|
||||
/* flip mirror */
|
||||
if (rb->write_index == rb->buffer_size-1)
|
||||
{
|
||||
rb->write_mirror = ~rb->write_mirror;
|
||||
rb->write_index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rb->write_index++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_putchar);
|
||||
|
||||
/**
|
||||
* @brief Put a byte into the ring buffer. If ring buffer is full, it will discard an old data and put into a new data.
|
||||
*
|
||||
* @param rb A pointer to the ring buffer object.
|
||||
* @param ch A byte put into the ring buffer.
|
||||
*
|
||||
* @return Return the data size we put into the ring buffer. Always return 1.
|
||||
*/
|
||||
rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const rt_uint8_t ch)
|
||||
{
|
||||
enum rt_ringbuffer_state old_state;
|
||||
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
|
||||
old_state = rt_ringbuffer_status(rb);
|
||||
|
||||
rb->buffer_ptr[rb->write_index] = ch;
|
||||
|
||||
/* flip mirror */
|
||||
if (rb->write_index == rb->buffer_size-1)
|
||||
{
|
||||
rb->write_mirror = ~rb->write_mirror;
|
||||
rb->write_index = 0;
|
||||
if (old_state == RT_RINGBUFFER_FULL)
|
||||
{
|
||||
rb->read_mirror = ~rb->read_mirror;
|
||||
rb->read_index = rb->write_index;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rb->write_index++;
|
||||
if (old_state == RT_RINGBUFFER_FULL)
|
||||
rb->read_index = rb->write_index;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_putchar_force);
|
||||
|
||||
/**
|
||||
* @brief Get a byte from the ring buffer.
|
||||
*
|
||||
* @param rb The pointer to the ring buffer object.
|
||||
* @param ch A pointer to the buffer, used to store one byte.
|
||||
*
|
||||
* @return 0 The ring buffer is empty.
|
||||
* @return 1 Success
|
||||
*/
|
||||
rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch)
|
||||
{
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
|
||||
/* ringbuffer is empty */
|
||||
if (!rt_ringbuffer_data_len(rb))
|
||||
return 0;
|
||||
|
||||
/* put byte */
|
||||
*ch = rb->buffer_ptr[rb->read_index];
|
||||
|
||||
if (rb->read_index == rb->buffer_size-1)
|
||||
{
|
||||
rb->read_mirror = ~rb->read_mirror;
|
||||
rb->read_index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rb->read_index++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_getchar);
|
||||
|
||||
/**
|
||||
* @brief Get the size of data in the ring buffer in bytes.
|
||||
*
|
||||
* @param rb The pointer to the ring buffer object.
|
||||
*
|
||||
* @return Return the size of data in the ring buffer in bytes.
|
||||
*/
|
||||
rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb)
|
||||
{
|
||||
switch (rt_ringbuffer_status(rb))
|
||||
{
|
||||
case RT_RINGBUFFER_EMPTY:
|
||||
return 0;
|
||||
case RT_RINGBUFFER_FULL:
|
||||
return rb->buffer_size;
|
||||
case RT_RINGBUFFER_HALFFULL:
|
||||
default:
|
||||
{
|
||||
rt_size_t wi = rb->write_index, ri = rb->read_index;
|
||||
|
||||
if (wi > ri)
|
||||
return wi - ri;
|
||||
else
|
||||
return rb->buffer_size - (ri - wi);
|
||||
}
|
||||
}
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_data_len);
|
||||
|
||||
/**
|
||||
* @brief Reset the ring buffer object, and clear all contents in the buffer.
|
||||
*
|
||||
* @param rb A pointer to the ring buffer object.
|
||||
*/
|
||||
void rt_ringbuffer_reset(struct rt_ringbuffer *rb)
|
||||
{
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
|
||||
rb->read_mirror = 0;
|
||||
rb->read_index = 0;
|
||||
rb->write_mirror = 0;
|
||||
rb->write_index = 0;
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_reset);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
|
||||
/**
|
||||
* @brief Create a ring buffer object with a given size.
|
||||
*
|
||||
* @param size The size of the buffer in bytes.
|
||||
*
|
||||
* @return Return a pointer to ring buffer object. When the return value is RT_NULL, it means this creation failed.
|
||||
*/
|
||||
struct rt_ringbuffer *rt_ringbuffer_create(rt_uint16_t size)
|
||||
{
|
||||
struct rt_ringbuffer *rb;
|
||||
rt_uint8_t *pool;
|
||||
|
||||
RT_ASSERT(size > 0);
|
||||
|
||||
size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
|
||||
|
||||
rb = (struct rt_ringbuffer *)rt_malloc(sizeof(struct rt_ringbuffer));
|
||||
if (rb == RT_NULL)
|
||||
goto exit;
|
||||
|
||||
pool = (rt_uint8_t *)rt_malloc(size);
|
||||
if (pool == RT_NULL)
|
||||
{
|
||||
rt_free(rb);
|
||||
rb = RT_NULL;
|
||||
goto exit;
|
||||
}
|
||||
rt_ringbuffer_init(rb, pool, size);
|
||||
|
||||
exit:
|
||||
return rb;
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_create);
|
||||
|
||||
/**
|
||||
* @brief Destroy the ring buffer object, which is created by rt_ringbuffer_create() .
|
||||
*
|
||||
* @param rb A pointer to the ring buffer object.
|
||||
*/
|
||||
void rt_ringbuffer_destroy(struct rt_ringbuffer *rb)
|
||||
{
|
||||
RT_ASSERT(rb != RT_NULL);
|
||||
|
||||
rt_free(rb->buffer_ptr);
|
||||
rt_free(rb);
|
||||
}
|
||||
RTM_EXPORT(rt_ringbuffer_destroy);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018/06/26 Bernard Fix the wait queue issue when wakeup a soon
|
||||
* to blocked thread.
|
||||
* 2022-01-24 THEWON let rt_wqueue_wait return thread->error when using signal
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdevice.h>
|
||||
#include <rtservice.h>
|
||||
|
||||
/**
|
||||
* @brief This function will insert a node to the wait queue.
|
||||
*
|
||||
* @param queue is a pointer to the wait queue.
|
||||
*
|
||||
* @param node is a pointer to the node to be inserted.
|
||||
*/
|
||||
void rt_wqueue_add(rt_wqueue_t *queue, struct rt_wqueue_node *node)
|
||||
{
|
||||
rt_base_t level;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
rt_list_insert_before(&(queue->waiting_list), &(node->list));
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will remove a node from the wait queue.
|
||||
*
|
||||
* @param queue is a pointer to the wait queue.
|
||||
*
|
||||
* @param node is a pointer to the node to be removed.
|
||||
*/
|
||||
void rt_wqueue_remove(struct rt_wqueue_node *node)
|
||||
{
|
||||
rt_base_t level;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
rt_list_remove(&(node->list));
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function is the default wakeup function, but it doesn't do anything in actual.
|
||||
* It always return 0, user should define their own wakeup function.
|
||||
*
|
||||
* @param queue is a pointer to the wait queue.
|
||||
*
|
||||
* @param key is the wakeup condition.
|
||||
*
|
||||
* @return always return 0.
|
||||
*/
|
||||
int __wqueue_default_wake(struct rt_wqueue_node *wait, void *key)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will wake up a pending thread on the specified waiting queue that meets the conditions.
|
||||
*
|
||||
* @param queue is a pointer to the wait queue.
|
||||
*
|
||||
* @param key is the wakeup conditions, but it is not effective now, because
|
||||
* default wakeup function always return 0.
|
||||
* If user wants to use it, user should define their own wakeup function.
|
||||
*/
|
||||
void rt_wqueue_wakeup(rt_wqueue_t *queue, void *key)
|
||||
{
|
||||
rt_base_t level;
|
||||
register int need_schedule = 0;
|
||||
|
||||
rt_list_t *queue_list;
|
||||
struct rt_list_node *node;
|
||||
struct rt_wqueue_node *entry;
|
||||
|
||||
queue_list = &(queue->waiting_list);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
/* set wakeup flag in the queue */
|
||||
queue->flag = RT_WQ_FLAG_WAKEUP;
|
||||
|
||||
if (!(rt_list_isempty(queue_list)))
|
||||
{
|
||||
for (node = queue_list->next; node != queue_list; node = node->next)
|
||||
{
|
||||
entry = rt_list_entry(node, struct rt_wqueue_node, list);
|
||||
if (entry->wakeup(entry, key) == 0)
|
||||
{
|
||||
rt_thread_resume(entry->polling_thread);
|
||||
need_schedule = 1;
|
||||
|
||||
rt_wqueue_remove(entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
if (need_schedule)
|
||||
rt_schedule();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will join a thread to the specified waiting queue, the thread will holds a wait or
|
||||
* timeout return on the specified wait queue.
|
||||
*
|
||||
* @param queue is a pointer to the wait queue.
|
||||
*
|
||||
* @param condition is parameters compatible with POSIX standard interface (currently meaningless, just pass in 0).
|
||||
*
|
||||
* @param msec is the timeout value, unit is millisecond.
|
||||
*
|
||||
* @return Return 0 if the thread is woken up.
|
||||
*/
|
||||
int rt_wqueue_wait(rt_wqueue_t *queue, int condition, int msec)
|
||||
{
|
||||
int tick;
|
||||
rt_thread_t tid = rt_thread_self();
|
||||
rt_timer_t tmr = &(tid->thread_timer);
|
||||
struct rt_wqueue_node __wait;
|
||||
rt_base_t level;
|
||||
|
||||
/* current context checking */
|
||||
RT_DEBUG_SCHEDULER_AVAILABLE(RT_TRUE);
|
||||
|
||||
tick = rt_tick_from_millisecond(msec);
|
||||
|
||||
if ((condition) || (tick == 0))
|
||||
return 0;
|
||||
|
||||
__wait.polling_thread = rt_thread_self();
|
||||
__wait.key = 0;
|
||||
__wait.wakeup = __wqueue_default_wake;
|
||||
rt_list_init(&__wait.list);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
/* reset thread error */
|
||||
tid->error = RT_EOK;
|
||||
|
||||
if (queue->flag == RT_WQ_FLAG_WAKEUP)
|
||||
{
|
||||
/* already wakeup */
|
||||
goto __exit_wakeup;
|
||||
}
|
||||
|
||||
rt_wqueue_add(queue, &__wait);
|
||||
rt_thread_suspend(tid);
|
||||
|
||||
/* start timer */
|
||||
if (tick != RT_WAITING_FOREVER)
|
||||
{
|
||||
rt_timer_control(tmr,
|
||||
RT_TIMER_CTRL_SET_TIME,
|
||||
&tick);
|
||||
|
||||
rt_timer_start(tmr);
|
||||
}
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_schedule();
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
__exit_wakeup:
|
||||
queue->flag = RT_WQ_FLAG_CLEAN;
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_wqueue_remove(&__wait);
|
||||
|
||||
return tid->error;
|
||||
}
|
||||
@@ -0,0 +1,510 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2017-02-27 Bernard fix the re-work issue.
|
||||
* 2021-08-01 Meco Man remove rt_delayed_work_init()
|
||||
* 2021-08-14 Jackistang add comments for function interface
|
||||
* 2022-01-16 Meco Man add rt_work_urgent()
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
|
||||
static void _delayed_work_timeout_handler(void *parameter);
|
||||
|
||||
rt_inline rt_err_t _workqueue_work_completion(struct rt_workqueue *queue)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
rt_enter_critical();
|
||||
while (1)
|
||||
{
|
||||
/* try to take condition semaphore */
|
||||
result = rt_sem_trytake(&(queue->sem));
|
||||
if (result == -RT_ETIMEOUT)
|
||||
{
|
||||
/* it's timeout, release this semaphore */
|
||||
rt_sem_release(&(queue->sem));
|
||||
}
|
||||
else if (result == RT_EOK)
|
||||
{
|
||||
/* keep the sem value = 0 */
|
||||
result = RT_EOK;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rt_exit_critical();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void _workqueue_thread_entry(void *parameter)
|
||||
{
|
||||
rt_base_t level;
|
||||
struct rt_work *work;
|
||||
struct rt_workqueue *queue;
|
||||
|
||||
queue = (struct rt_workqueue *) parameter;
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
|
||||
while (1)
|
||||
{
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (rt_list_isempty(&(queue->work_list)))
|
||||
{
|
||||
/* no software timer exist, suspend self. */
|
||||
rt_thread_suspend(rt_thread_self());
|
||||
rt_hw_interrupt_enable(level);
|
||||
rt_schedule();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* we have work to do with. */
|
||||
work = rt_list_entry(queue->work_list.next, struct rt_work, list);
|
||||
rt_list_remove(&(work->list));
|
||||
queue->work_current = work;
|
||||
work->flags &= ~RT_WORK_STATE_PENDING;
|
||||
work->workqueue = RT_NULL;
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
/* do work */
|
||||
work->work_func(work, work->work_data);
|
||||
/* clean current work */
|
||||
queue->work_current = RT_NULL;
|
||||
|
||||
/* ack work completion */
|
||||
_workqueue_work_completion(queue);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t _workqueue_submit_work(struct rt_workqueue *queue,
|
||||
struct rt_work *work, rt_tick_t ticks)
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_err_t err;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
/* remove list */
|
||||
rt_list_remove(&(work->list));
|
||||
work->flags &= ~RT_WORK_STATE_PENDING;
|
||||
|
||||
if (ticks == 0)
|
||||
{
|
||||
if (queue->work_current != work)
|
||||
{
|
||||
rt_list_insert_after(queue->work_list.prev, &(work->list));
|
||||
work->flags |= RT_WORK_STATE_PENDING;
|
||||
work->workqueue = queue;
|
||||
err = RT_EOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EBUSY;
|
||||
}
|
||||
|
||||
/* whether the workqueue is doing work */
|
||||
if (queue->work_current == RT_NULL &&
|
||||
((queue->work_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND))
|
||||
{
|
||||
/* resume work thread */
|
||||
rt_thread_resume(queue->work_thread);
|
||||
rt_hw_interrupt_enable(level);
|
||||
rt_schedule();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
else if (ticks < RT_TICK_MAX / 2)
|
||||
{
|
||||
/* Timer started */
|
||||
if (work->flags & RT_WORK_STATE_SUBMITTING)
|
||||
{
|
||||
rt_timer_stop(&work->timer);
|
||||
rt_timer_control(&work->timer, RT_TIMER_CTRL_SET_TIME, &ticks);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_timer_init(&(work->timer), "work", _delayed_work_timeout_handler,
|
||||
work, ticks, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER);
|
||||
work->flags |= RT_WORK_STATE_SUBMITTING;
|
||||
}
|
||||
work->workqueue = queue;
|
||||
/* insert delay work list */
|
||||
rt_list_insert_after(queue->delayed_list.prev, &(work->list));
|
||||
rt_hw_interrupt_enable(level);
|
||||
rt_timer_start(&(work->timer));
|
||||
return RT_EOK;
|
||||
}
|
||||
rt_hw_interrupt_enable(level);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
static rt_err_t _workqueue_cancel_work(struct rt_workqueue *queue, struct rt_work *work)
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_err_t err;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
rt_list_remove(&(work->list));
|
||||
work->flags &= ~RT_WORK_STATE_PENDING;
|
||||
/* Timer started */
|
||||
if (work->flags & RT_WORK_STATE_SUBMITTING)
|
||||
{
|
||||
rt_timer_stop(&(work->timer));
|
||||
rt_timer_detach(&(work->timer));
|
||||
work->flags &= ~RT_WORK_STATE_SUBMITTING;
|
||||
}
|
||||
err = queue->work_current != work ? RT_EOK : -RT_EBUSY;
|
||||
work->workqueue = RT_NULL;
|
||||
rt_hw_interrupt_enable(level);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void _delayed_work_timeout_handler(void *parameter)
|
||||
{
|
||||
struct rt_work *work;
|
||||
struct rt_workqueue *queue;
|
||||
rt_base_t level;
|
||||
|
||||
work = (struct rt_work *)parameter;
|
||||
queue = work->workqueue;
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
rt_timer_detach(&(work->timer));
|
||||
work->flags &= ~RT_WORK_STATE_SUBMITTING;
|
||||
/* remove delay list */
|
||||
rt_list_remove(&(work->list));
|
||||
/* insert work queue */
|
||||
if (queue->work_current != work)
|
||||
{
|
||||
rt_list_insert_after(queue->work_list.prev, &(work->list));
|
||||
work->flags |= RT_WORK_STATE_PENDING;
|
||||
}
|
||||
/* whether the workqueue is doing work */
|
||||
if (queue->work_current == RT_NULL &&
|
||||
((queue->work_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND))
|
||||
{
|
||||
/* resume work thread */
|
||||
rt_thread_resume(queue->work_thread);
|
||||
rt_hw_interrupt_enable(level);
|
||||
rt_schedule();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize a work item, binding with a callback function.
|
||||
*
|
||||
* @param work is a pointer to the work item object.
|
||||
*
|
||||
* @param work_func is a callback function that will be called when this work item is executed.
|
||||
*
|
||||
* @param work_data is a user data passed to the callback function as the second parameter.
|
||||
*/
|
||||
void rt_work_init(struct rt_work *work,
|
||||
void (*work_func)(struct rt_work *work, void *work_data),
|
||||
void *work_data)
|
||||
{
|
||||
RT_ASSERT(work != RT_NULL);
|
||||
RT_ASSERT(work_func != RT_NULL);
|
||||
|
||||
rt_list_init(&(work->list));
|
||||
work->work_func = work_func;
|
||||
work->work_data = work_data;
|
||||
work->workqueue = RT_NULL;
|
||||
work->flags = 0;
|
||||
work->type = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a work queue with a thread inside.
|
||||
*
|
||||
* @param name is a name of the work queue thread.
|
||||
*
|
||||
* @param stack_size is stack size of the work queue thread.
|
||||
*
|
||||
* @param priority is a priority of the work queue thread.
|
||||
*
|
||||
* @return Return a pointer to the workqueue object. It will return RT_NULL if failed.
|
||||
*/
|
||||
struct rt_workqueue *rt_workqueue_create(const char *name, rt_uint16_t stack_size, rt_uint8_t priority)
|
||||
{
|
||||
struct rt_workqueue *queue = RT_NULL;
|
||||
|
||||
queue = (struct rt_workqueue *)RT_KERNEL_MALLOC(sizeof(struct rt_workqueue));
|
||||
if (queue != RT_NULL)
|
||||
{
|
||||
/* initialize work list */
|
||||
rt_list_init(&(queue->work_list));
|
||||
rt_list_init(&(queue->delayed_list));
|
||||
queue->work_current = RT_NULL;
|
||||
rt_sem_init(&(queue->sem), "wqueue", 0, RT_IPC_FLAG_FIFO);
|
||||
|
||||
/* create the work thread */
|
||||
queue->work_thread = rt_thread_create(name, _workqueue_thread_entry, queue, stack_size, priority, 10);
|
||||
if (queue->work_thread == RT_NULL)
|
||||
{
|
||||
RT_KERNEL_FREE(queue);
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
rt_thread_startup(queue->work_thread);
|
||||
}
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroy a work queue.
|
||||
*
|
||||
* @param queue is a pointer to the workqueue object.
|
||||
*
|
||||
* @return RT_EOK Success.
|
||||
*/
|
||||
rt_err_t rt_workqueue_destroy(struct rt_workqueue *queue)
|
||||
{
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
|
||||
rt_workqueue_cancel_all_work(queue);
|
||||
rt_thread_delete(queue->work_thread);
|
||||
rt_sem_detach(&(queue->sem));
|
||||
RT_KERNEL_FREE(queue);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Submit a work item to the work queue without delay.
|
||||
*
|
||||
* @param queue is a pointer to the workqueue object.
|
||||
*
|
||||
* @param work is a pointer to the work item object.
|
||||
*
|
||||
* @return RT_EOK Success.
|
||||
* -RT_EBUSY This work item is executing.
|
||||
*/
|
||||
rt_err_t rt_workqueue_dowork(struct rt_workqueue *queue, struct rt_work *work)
|
||||
{
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
RT_ASSERT(work != RT_NULL);
|
||||
|
||||
return _workqueue_submit_work(queue, work, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Submit a work item to the work queue with a delay.
|
||||
*
|
||||
* @param queue is a pointer to the workqueue object.
|
||||
*
|
||||
* @param work is a pointer to the work item object.
|
||||
*
|
||||
* @param ticks is the delay ticks for the work item to be submitted to the work queue.
|
||||
*
|
||||
* NOTE: The max timeout tick should be no more than (RT_TICK_MAX/2 - 1)
|
||||
*
|
||||
* @return RT_EOK Success.
|
||||
* -RT_EBUSY This work item is executing.
|
||||
* -RT_ERROR The ticks parameter is invalid.
|
||||
*/
|
||||
rt_err_t rt_workqueue_submit_work(struct rt_workqueue *queue, struct rt_work *work, rt_tick_t ticks)
|
||||
{
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
RT_ASSERT(work != RT_NULL);
|
||||
RT_ASSERT(ticks < RT_TICK_MAX / 2);
|
||||
|
||||
return _workqueue_submit_work(queue, work, ticks);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Submit a work item to the work queue without delay. This work item will be executed after the current work item.
|
||||
*
|
||||
* @param queue is a pointer to the workqueue object.
|
||||
*
|
||||
* @param work is a pointer to the work item object.
|
||||
*
|
||||
* @return RT_EOK Success.
|
||||
*/
|
||||
rt_err_t rt_workqueue_urgent_work(struct rt_workqueue *queue, struct rt_work *work)
|
||||
{
|
||||
rt_base_t level;
|
||||
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
RT_ASSERT(work != RT_NULL);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
/* NOTE: the work MUST be initialized firstly */
|
||||
rt_list_remove(&(work->list));
|
||||
rt_list_insert_after(&queue->work_list, &(work->list));
|
||||
/* whether the workqueue is doing work */
|
||||
if (queue->work_current == RT_NULL &&
|
||||
((queue->work_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND))
|
||||
{
|
||||
/* resume work thread */
|
||||
rt_thread_resume(queue->work_thread);
|
||||
rt_hw_interrupt_enable(level);
|
||||
rt_schedule();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cancel a work item in the work queue.
|
||||
*
|
||||
* @param queue is a pointer to the workqueue object.
|
||||
*
|
||||
* @param work is a pointer to the work item object.
|
||||
*
|
||||
* @return RT_EOK Success.
|
||||
* -RT_EBUSY This work item is executing.
|
||||
*/
|
||||
rt_err_t rt_workqueue_cancel_work(struct rt_workqueue *queue, struct rt_work *work)
|
||||
{
|
||||
RT_ASSERT(work != RT_NULL);
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
|
||||
return _workqueue_cancel_work(queue, work);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cancel a work item in the work queue. If the work item is executing, this function will block until it is done.
|
||||
*
|
||||
* @param queue is a pointer to the workqueue object.
|
||||
*
|
||||
* @param work is a pointer to the work item object.
|
||||
*
|
||||
* @return RT_EOK Success.
|
||||
*/
|
||||
rt_err_t rt_workqueue_cancel_work_sync(struct rt_workqueue *queue, struct rt_work *work)
|
||||
{
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
RT_ASSERT(work != RT_NULL);
|
||||
|
||||
if (queue->work_current == work) /* it's current work in the queue */
|
||||
{
|
||||
/* wait for work completion */
|
||||
rt_sem_take(&(queue->sem), RT_WAITING_FOREVER);
|
||||
}
|
||||
else
|
||||
{
|
||||
_workqueue_cancel_work(queue, work);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will cancel all work items in work queue.
|
||||
*
|
||||
* @param queue is a pointer to the workqueue object.
|
||||
*
|
||||
* @return RT_EOK Success.
|
||||
*/
|
||||
rt_err_t rt_workqueue_cancel_all_work(struct rt_workqueue *queue)
|
||||
{
|
||||
struct rt_work *work;
|
||||
|
||||
RT_ASSERT(queue != RT_NULL);
|
||||
|
||||
/* cancel work */
|
||||
rt_enter_critical();
|
||||
while (rt_list_isempty(&queue->work_list) == RT_FALSE)
|
||||
{
|
||||
work = rt_list_first_entry(&queue->work_list, struct rt_work, list);
|
||||
_workqueue_cancel_work(queue, work);
|
||||
}
|
||||
/* cancel delay work */
|
||||
while (rt_list_isempty(&queue->delayed_list) == RT_FALSE)
|
||||
{
|
||||
work = rt_list_first_entry(&queue->delayed_list, struct rt_work, list);
|
||||
_workqueue_cancel_work(queue, work);
|
||||
}
|
||||
rt_exit_critical();
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_SYSTEM_WORKQUEUE
|
||||
|
||||
static struct rt_workqueue *sys_workq; /* system work queue */
|
||||
|
||||
/**
|
||||
* @brief Submit a work item to the system work queue with a delay.
|
||||
*
|
||||
* @param work is a pointer to the work item object.
|
||||
*
|
||||
* @param ticks is the delay OS ticks for the work item to be submitted to the work queue.
|
||||
*
|
||||
* NOTE: The max timeout tick should be no more than (RT_TICK_MAX/2 - 1)
|
||||
*
|
||||
* @return RT_EOK Success.
|
||||
* -RT_EBUSY This work item is executing.
|
||||
* -RT_ERROR The ticks parameter is invalid.
|
||||
*/
|
||||
rt_err_t rt_work_submit(struct rt_work *work, rt_tick_t ticks)
|
||||
{
|
||||
return rt_workqueue_submit_work(sys_workq, work, ticks);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Submit a work item to the system work queue without delay. This work item will be executed after the current work item.
|
||||
*
|
||||
* @param work is a pointer to the work item object.
|
||||
*
|
||||
* @return RT_EOK Success.
|
||||
*/
|
||||
rt_err_t rt_work_urgent(struct rt_work *work)
|
||||
{
|
||||
return rt_workqueue_urgent_work(sys_workq, work);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cancel a work item in the system work queue.
|
||||
*
|
||||
* @param work is a pointer to the work item object.
|
||||
*
|
||||
* @return RT_EOK Success.
|
||||
* -RT_EBUSY This work item is executing.
|
||||
*/
|
||||
rt_err_t rt_work_cancel(struct rt_work *work)
|
||||
{
|
||||
return rt_workqueue_cancel_work(sys_workq, work);
|
||||
}
|
||||
|
||||
static int rt_work_sys_workqueue_init(void)
|
||||
{
|
||||
if (sys_workq != RT_NULL)
|
||||
return RT_EOK;
|
||||
|
||||
sys_workq = rt_workqueue_create("sys workq", RT_SYSTEM_WORKQUEUE_STACKSIZE,
|
||||
RT_SYSTEM_WORKQUEUE_PRIORITY);
|
||||
RT_ASSERT(sys_workq != RT_NULL);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
INIT_PREV_EXPORT(rt_work_sys_workqueue_init);
|
||||
#endif /* RT_USING_SYSTEM_WORKQUEUE */
|
||||
#endif /* RT_USING_HEAP */
|
||||
@@ -0,0 +1,29 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = []
|
||||
CPPPATH = [cwd + '/../include']
|
||||
group = []
|
||||
|
||||
if GetDepend(['RT_USING_PIN']):
|
||||
src = src + ['pin.c']
|
||||
|
||||
if GetDepend(['RT_USING_ADC']):
|
||||
src = src + ['adc.c']
|
||||
|
||||
if GetDepend(['RT_USING_DAC']):
|
||||
src = src + ['dac.c']
|
||||
|
||||
if GetDepend(['RT_USING_PWM']):
|
||||
src = src + ['rt_drv_pwm.c']
|
||||
|
||||
if GetDepend(['RT_USING_PULSE_ENCODER']):
|
||||
src = src + ['pulse_encoder.c']
|
||||
|
||||
if GetDepend(['RT_USING_INPUT_CAPTURE']):
|
||||
src = src + ['rt_inputcapture.c']
|
||||
|
||||
if len(src):
|
||||
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-05-07 aozima the first version
|
||||
* 2018-11-16 Ernest Chen add finsh command and update adc function
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DBG_TAG "adc"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
static rt_size_t _adc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_size_t i;
|
||||
struct rt_adc_device *adc = (struct rt_adc_device *)dev;
|
||||
rt_uint32_t *value = (rt_uint32_t *)buffer;
|
||||
|
||||
for (i = 0; i < size; i += sizeof(int))
|
||||
{
|
||||
result = adc->ops->convert(adc, pos + i, value);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
value++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static rt_err_t _adc_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_adc_device_t adc = (struct rt_adc_device *)dev;
|
||||
|
||||
if (adc->ops->enabled == RT_NULL)
|
||||
{
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
if (cmd == RT_ADC_CMD_ENABLE)
|
||||
{
|
||||
result = adc->ops->enabled(adc, (rt_uint32_t)args, RT_TRUE);
|
||||
}
|
||||
else if (cmd == RT_ADC_CMD_DISABLE)
|
||||
{
|
||||
result = adc->ops->enabled(adc, (rt_uint32_t)args, RT_FALSE);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops adc_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
_adc_read,
|
||||
RT_NULL,
|
||||
_adc_control,
|
||||
};
|
||||
#endif
|
||||
|
||||
rt_err_t rt_hw_adc_register(rt_adc_device_t device, const char *name, const struct rt_adc_ops *ops, const void *user_data)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
RT_ASSERT(ops != RT_NULL && ops->convert != RT_NULL);
|
||||
|
||||
device->parent.type = RT_Device_Class_Miscellaneous;
|
||||
device->parent.rx_indicate = RT_NULL;
|
||||
device->parent.tx_complete = RT_NULL;
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
device->parent.ops = &adc_ops;
|
||||
#else
|
||||
device->parent.init = RT_NULL;
|
||||
device->parent.open = RT_NULL;
|
||||
device->parent.close = RT_NULL;
|
||||
device->parent.read = _adc_read;
|
||||
device->parent.write = RT_NULL;
|
||||
device->parent.control = _adc_control;
|
||||
#endif
|
||||
device->ops = ops;
|
||||
device->parent.user_data = (void *)user_data;
|
||||
|
||||
result = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_uint32_t rt_adc_read(rt_adc_device_t dev, rt_uint32_t channel)
|
||||
{
|
||||
rt_uint32_t value;
|
||||
|
||||
RT_ASSERT(dev);
|
||||
|
||||
dev->ops->convert(dev, channel, &value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
rt_err_t rt_adc_enable(rt_adc_device_t dev, rt_uint32_t channel)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
RT_ASSERT(dev);
|
||||
if (dev->ops->enabled != RT_NULL)
|
||||
{
|
||||
result = dev->ops->enabled(dev, channel, RT_TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_ENOSYS;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_err_t rt_adc_disable(rt_adc_device_t dev, rt_uint32_t channel)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
RT_ASSERT(dev);
|
||||
if (dev->ops->enabled != RT_NULL)
|
||||
{
|
||||
result = dev->ops->enabled(dev, channel, RT_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_ENOSYS;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
|
||||
static int adc(int argc, char **argv)
|
||||
{
|
||||
int value = 0;
|
||||
int result = RT_EOK;
|
||||
static rt_adc_device_t adc_device = RT_NULL;
|
||||
char *result_str;
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
if (!strcmp(argv[1], "probe"))
|
||||
{
|
||||
if (argc == 3)
|
||||
{
|
||||
adc_device = (rt_adc_device_t)rt_device_find(argv[2]);
|
||||
result_str = (adc_device == RT_NULL) ? "failure" : "success";
|
||||
rt_kprintf("probe %s %s \n", argv[2], result_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("adc probe <adc_name> - probe adc by name\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (adc_device == RT_NULL)
|
||||
{
|
||||
rt_kprintf("Please using 'adc probe <adc_name>' first\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
if (!strcmp(argv[1], "enable"))
|
||||
{
|
||||
if (argc == 3)
|
||||
{
|
||||
result = rt_adc_enable(adc_device, atoi(argv[2]));
|
||||
result_str = (result == RT_EOK) ? "success" : "failure";
|
||||
rt_kprintf("%s channel %d enables %s \n", adc_device->parent.parent.name, atoi(argv[2]), result_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("adc enable <channel> - enable adc channel\n");
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[1], "read"))
|
||||
{
|
||||
if (argc == 3)
|
||||
{
|
||||
value = rt_adc_read(adc_device, atoi(argv[2]));
|
||||
rt_kprintf("%s channel %d read value is 0x%08X \n", adc_device->parent.parent.name, atoi(argv[2]), value);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("adc read <channel> - read adc value on the channel\n");
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[1], "disable"))
|
||||
{
|
||||
if (argc == 3)
|
||||
{
|
||||
result = rt_adc_disable(adc_device, atoi(argv[2]));
|
||||
result_str = (result == RT_EOK) ? "success" : "failure";
|
||||
rt_kprintf("%s channel %d disable %s \n", adc_device->parent.parent.name, atoi(argv[2]), result_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("adc disable <channel> - disable adc channel\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Unknown command. Please enter 'adc' for help\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Usage: \n");
|
||||
rt_kprintf("adc probe <adc_name> - probe adc by name\n");
|
||||
rt_kprintf("adc read <channel> - read adc value on the channel\n");
|
||||
rt_kprintf("adc disable <channel> - disable adc channel\n");
|
||||
rt_kprintf("adc enable <channel> - enable adc channel\n");
|
||||
result = -RT_ERROR;
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
MSH_CMD_EXPORT(adc, adc function);
|
||||
|
||||
#endif /* RT_USING_FINSH */
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2020-06-19 thread-liu the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DBG_TAG "dac"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
static rt_size_t _dac_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_size_t i;
|
||||
struct rt_dac_device *dac = (struct rt_dac_device *)dev;
|
||||
rt_uint32_t *value = (rt_uint32_t *)buffer;
|
||||
|
||||
for (i = 0; i < size; i += sizeof(int))
|
||||
{
|
||||
result = dac->ops->convert(dac, pos + i, value);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
value++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static rt_err_t _dac_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_dac_device_t dac = (struct rt_dac_device *)dev;
|
||||
|
||||
if (dac->ops->enabled == RT_NULL)
|
||||
{
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
if (cmd == RT_DAC_CMD_ENABLE)
|
||||
{
|
||||
result = dac->ops->enabled(dac, (rt_uint32_t)args);
|
||||
}
|
||||
else if (cmd == RT_DAC_CMD_DISABLE)
|
||||
{
|
||||
result = dac->ops->disabled(dac, (rt_uint32_t)args);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops dac_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
_dac_write,
|
||||
_dac_control,
|
||||
};
|
||||
#endif
|
||||
|
||||
rt_err_t rt_hw_dac_register(rt_dac_device_t device, const char *name, const struct rt_dac_ops *ops, const void *user_data)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
RT_ASSERT(ops != RT_NULL && ops->convert != RT_NULL);
|
||||
|
||||
device->parent.type = RT_Device_Class_Miscellaneous;
|
||||
device->parent.rx_indicate = RT_NULL;
|
||||
device->parent.tx_complete = RT_NULL;
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
device->parent.ops = &dac_ops;
|
||||
#else
|
||||
device->parent.init = RT_NULL;
|
||||
device->parent.open = RT_NULL;
|
||||
device->parent.close = RT_NULL;
|
||||
device->parent.read = RT_NULL;
|
||||
device->parent.write = _dac_write;
|
||||
device->parent.control = _dac_control;
|
||||
#endif
|
||||
device->ops = ops;
|
||||
device->parent.user_data = (void *)user_data;
|
||||
|
||||
result = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_uint32_t rt_dac_write(rt_dac_device_t dev, rt_uint32_t channel, rt_uint32_t value)
|
||||
{
|
||||
RT_ASSERT(dev);
|
||||
|
||||
dev->ops->convert(dev, channel, &value);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t rt_dac_enable(rt_dac_device_t dev, rt_uint32_t channel)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
RT_ASSERT(dev);
|
||||
if (dev->ops->enabled != RT_NULL)
|
||||
{
|
||||
result = dev->ops->enabled(dev, channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_ENOSYS;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_err_t rt_dac_disable(rt_dac_device_t dev, rt_uint32_t channel)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
RT_ASSERT(dev);
|
||||
if (dev->ops->disabled != RT_NULL)
|
||||
{
|
||||
result = dev->ops->disabled(dev, channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_ENOSYS;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
|
||||
static int dac(int argc, char **argv)
|
||||
{
|
||||
int result = RT_EOK;
|
||||
static rt_dac_device_t dac_device = RT_NULL;
|
||||
char *result_str;
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
if (!strcmp(argv[1], "probe"))
|
||||
{
|
||||
if (argc == 3)
|
||||
{
|
||||
dac_device = (rt_dac_device_t)rt_device_find(argv[2]);
|
||||
result_str = (dac_device == RT_NULL) ? "failure" : "success";
|
||||
rt_kprintf("probe %s %s \n", argv[2], result_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("dac probe <dac_name> - probe dac by name\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dac_device == RT_NULL)
|
||||
{
|
||||
rt_kprintf("Please using 'dac probe <dac_name>' first\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
if (!strcmp(argv[1], "enable"))
|
||||
{
|
||||
if (argc == 3)
|
||||
{
|
||||
result = rt_dac_enable(dac_device, atoi(argv[2]));
|
||||
result_str = (result == RT_EOK) ? "success" : "failure";
|
||||
rt_kprintf("%s channel %d enables %s \n", dac_device->parent.parent.name, atoi(argv[2]), result_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("dac enable <channel> - enable dac channel\n");
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[1], "write"))
|
||||
{
|
||||
if (argc == 4)
|
||||
{
|
||||
rt_dac_write(dac_device, atoi(argv[2]), atoi(argv[3]));
|
||||
rt_kprintf("%s channel %d write value is %d \n", dac_device->parent.parent.name, atoi(argv[2]), atoi(argv[3]));
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("dac write <channel> <value> - write dac value on the channel\n");
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[1], "disable"))
|
||||
{
|
||||
if (argc == 3)
|
||||
{
|
||||
result = rt_dac_disable(dac_device, atoi(argv[2]));
|
||||
result_str = (result == RT_EOK) ? "success" : "failure";
|
||||
rt_kprintf("%s channel %d disable %s \n", dac_device->parent.parent.name, atoi(argv[2]), result_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("dac disable <channel> - disable dac channel\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Unknown command. Please enter 'dac' for help\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Usage: \n");
|
||||
rt_kprintf("dac probe <dac_name> - probe dac by name\n");
|
||||
rt_kprintf("dac write <channel> <value> - write dac value on the channel\n");
|
||||
rt_kprintf("dac disable <channel> - disable dac channel\n");
|
||||
rt_kprintf("dac enable <channel> - enable dac channel\n");
|
||||
result = -RT_ERROR;
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
MSH_CMD_EXPORT(dac, dac function);
|
||||
|
||||
#endif /* RT_USING_FINSH */
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, 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
|
||||
*/
|
||||
|
||||
#include <drivers/pin.h>
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
#include <finsh.h>
|
||||
#endif
|
||||
|
||||
static struct rt_device_pin _hw_pin;
|
||||
static rt_size_t _pin_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
|
||||
{
|
||||
struct rt_device_pin_status *status;
|
||||
struct rt_device_pin *pin = (struct rt_device_pin *)dev;
|
||||
|
||||
/* check parameters */
|
||||
RT_ASSERT(pin != RT_NULL);
|
||||
|
||||
status = (struct rt_device_pin_status *) buffer;
|
||||
if (status == RT_NULL || size != sizeof(*status)) return 0;
|
||||
|
||||
status->status = pin->ops->pin_read(dev, status->pin);
|
||||
return size;
|
||||
}
|
||||
|
||||
static rt_size_t _pin_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
|
||||
{
|
||||
struct rt_device_pin_status *status;
|
||||
struct rt_device_pin *pin = (struct rt_device_pin *)dev;
|
||||
|
||||
/* check parameters */
|
||||
RT_ASSERT(pin != RT_NULL);
|
||||
|
||||
status = (struct rt_device_pin_status *) buffer;
|
||||
if (status == RT_NULL || size != sizeof(*status)) return 0;
|
||||
|
||||
pin->ops->pin_write(dev, (rt_base_t)status->pin, (rt_base_t)status->status);
|
||||
|
||||
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_Miscellaneous;
|
||||
_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_int32_t pin, rt_uint32_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_int32_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_uint32_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_base_t mode)
|
||||
{
|
||||
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
||||
_hw_pin.ops->pin_mode(&_hw_pin.parent, pin, mode);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(rt_pin_mode, pinMode, set hardware pin mode);
|
||||
|
||||
void rt_pin_write(rt_base_t pin, rt_base_t value)
|
||||
{
|
||||
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
||||
_hw_pin.ops->pin_write(&_hw_pin.parent, pin, value);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(rt_pin_write, pinWrite, write value to hardware pin);
|
||||
|
||||
int rt_pin_read(rt_base_t pin)
|
||||
{
|
||||
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
||||
return _hw_pin.ops->pin_read(&_hw_pin.parent, pin);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(rt_pin_read, pinRead, read status from hardware pin);
|
||||
|
||||
rt_base_t rt_pin_get(const char *name)
|
||||
{
|
||||
RT_ASSERT(_hw_pin.ops != RT_NULL);
|
||||
RT_ASSERT(name[0] == 'P');
|
||||
|
||||
if(_hw_pin.ops->pin_get == RT_NULL)
|
||||
{
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
return _hw_pin.ops->pin_get(name);
|
||||
}
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(rt_pin_get, pinGet, get pin number from hardware pin);
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-08-08 balanceTWK the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
static rt_err_t rt_pulse_encoder_init(struct rt_device *dev)
|
||||
{
|
||||
struct rt_pulse_encoder_device *pulse_encoder;
|
||||
|
||||
pulse_encoder = (struct rt_pulse_encoder_device *)dev;
|
||||
if (pulse_encoder->ops->init)
|
||||
{
|
||||
return pulse_encoder->ops->init(pulse_encoder);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t rt_pulse_encoder_open(struct rt_device *dev, rt_uint16_t oflag)
|
||||
{
|
||||
struct rt_pulse_encoder_device *pulse_encoder;
|
||||
|
||||
pulse_encoder = (struct rt_pulse_encoder_device *)dev;
|
||||
if (pulse_encoder->ops->control)
|
||||
{
|
||||
return pulse_encoder->ops->control(pulse_encoder, PULSE_ENCODER_CMD_ENABLE, RT_NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t rt_pulse_encoder_close(struct rt_device *dev)
|
||||
{
|
||||
struct rt_pulse_encoder_device *pulse_encoder;
|
||||
|
||||
pulse_encoder = (struct rt_pulse_encoder_device *)dev;
|
||||
if (pulse_encoder->ops->control)
|
||||
{
|
||||
return pulse_encoder->ops->control(pulse_encoder, PULSE_ENCODER_CMD_DISABLE, RT_NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
static rt_size_t rt_pulse_encoder_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size)
|
||||
{
|
||||
struct rt_pulse_encoder_device *pulse_encoder;
|
||||
|
||||
pulse_encoder = (struct rt_pulse_encoder_device *)dev;
|
||||
if (pulse_encoder->ops->get_count)
|
||||
{
|
||||
*(rt_int32_t *)buffer = pulse_encoder->ops->get_count(pulse_encoder);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static rt_err_t rt_pulse_encoder_control(struct rt_device *dev, int cmd, void *args)
|
||||
{
|
||||
rt_err_t result;
|
||||
struct rt_pulse_encoder_device *pulse_encoder;
|
||||
|
||||
result = RT_EOK;
|
||||
pulse_encoder = (struct rt_pulse_encoder_device *)dev;
|
||||
switch (cmd)
|
||||
{
|
||||
case PULSE_ENCODER_CMD_CLEAR_COUNT:
|
||||
result = pulse_encoder->ops->clear_count(pulse_encoder);
|
||||
break;
|
||||
case PULSE_ENCODER_CMD_GET_TYPE:
|
||||
*(enum rt_pulse_encoder_type *)args = pulse_encoder->type;
|
||||
break;
|
||||
case PULSE_ENCODER_CMD_ENABLE:
|
||||
case PULSE_ENCODER_CMD_DISABLE:
|
||||
result = pulse_encoder->ops->control(pulse_encoder, cmd, args);
|
||||
break;
|
||||
default:
|
||||
result = -RT_ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops pulse_encoder_ops =
|
||||
{
|
||||
rt_pulse_encoder_init,
|
||||
rt_pulse_encoder_open,
|
||||
rt_pulse_encoder_close,
|
||||
rt_pulse_encoder_read,
|
||||
RT_NULL,
|
||||
rt_pulse_encoder_control
|
||||
};
|
||||
#endif
|
||||
|
||||
rt_err_t rt_device_pulse_encoder_register(struct rt_pulse_encoder_device *pulse_encoder, const char *name, void *user_data)
|
||||
{
|
||||
struct rt_device *device;
|
||||
|
||||
RT_ASSERT(pulse_encoder != RT_NULL);
|
||||
RT_ASSERT(pulse_encoder->ops != RT_NULL);
|
||||
|
||||
device = &(pulse_encoder->parent);
|
||||
|
||||
device->type = RT_Device_Class_Miscellaneous;
|
||||
device->rx_indicate = RT_NULL;
|
||||
device->tx_complete = RT_NULL;
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
device->ops = &pulse_encoder_ops;
|
||||
#else
|
||||
device->init = rt_pulse_encoder_init;
|
||||
device->open = rt_pulse_encoder_open;
|
||||
device->close = rt_pulse_encoder_close;
|
||||
device->read = rt_pulse_encoder_read;
|
||||
device->write = RT_NULL;
|
||||
device->control = rt_pulse_encoder_control;
|
||||
#endif
|
||||
device->user_data = user_data;
|
||||
|
||||
return rt_device_register(device, name, RT_DEVICE_FLAG_RDONLY | RT_DEVICE_FLAG_STANDALONE);
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-05-07 aozima the first version
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <drivers/rt_drv_pwm.h>
|
||||
|
||||
static rt_err_t _pwm_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct rt_device_pwm *pwm = (struct rt_device_pwm *)dev;
|
||||
|
||||
if (pwm->ops->control)
|
||||
{
|
||||
result = pwm->ops->control(pwm, cmd, args);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
pos: channel
|
||||
void *buffer: rt_uint32_t pulse[size]
|
||||
size : number of pulse, only set to sizeof(rt_uint32_t).
|
||||
*/
|
||||
static rt_size_t _pwm_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct rt_device_pwm *pwm = (struct rt_device_pwm *)dev;
|
||||
rt_uint32_t *pulse = (rt_uint32_t *)buffer;
|
||||
struct rt_pwm_configuration configuration = {0};
|
||||
|
||||
configuration.channel = pos;
|
||||
|
||||
if (pwm->ops->control)
|
||||
{
|
||||
result = pwm->ops->control(pwm, PWM_CMD_GET, &configuration);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
*pulse = configuration.pulse;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
pos: channel
|
||||
void *buffer: rt_uint32_t pulse[size]
|
||||
size : number of pulse, only set to sizeof(rt_uint32_t).
|
||||
*/
|
||||
static rt_size_t _pwm_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct rt_device_pwm *pwm = (struct rt_device_pwm *)dev;
|
||||
rt_uint32_t *pulse = (rt_uint32_t *)buffer;
|
||||
struct rt_pwm_configuration configuration = {0};
|
||||
|
||||
configuration.channel = pos;
|
||||
|
||||
if (pwm->ops->control)
|
||||
{
|
||||
result = pwm->ops->control(pwm, PWM_CMD_GET, &configuration);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
configuration.pulse = *pulse;
|
||||
|
||||
result = pwm->ops->control(pwm, PWM_CMD_SET, &configuration);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
static const struct rt_device_ops pwm_device_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
_pwm_read,
|
||||
_pwm_write,
|
||||
_pwm_control
|
||||
};
|
||||
#endif /* RT_USING_DEVICE_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 result = RT_EOK;
|
||||
|
||||
rt_memset(device, 0, sizeof(struct rt_device_pwm));
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
device->parent.ops = &pwm_device_ops;
|
||||
#else
|
||||
device->parent.init = RT_NULL;
|
||||
device->parent.open = RT_NULL;
|
||||
device->parent.close = RT_NULL;
|
||||
device->parent.read = _pwm_read;
|
||||
device->parent.write = _pwm_write;
|
||||
device->parent.control = _pwm_control;
|
||||
#endif /* RT_USING_DEVICE_OPS */
|
||||
|
||||
device->parent.type = RT_Device_Class_Miscellaneous;
|
||||
device->ops = ops;
|
||||
device->parent.user_data = (void *)user_data;
|
||||
|
||||
result = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_err_t rt_pwm_enable(struct rt_device_pwm *device, int channel)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct rt_pwm_configuration configuration = {0};
|
||||
|
||||
if (!device)
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
|
||||
configuration.channel = (channel > 0) ? (channel) : (-channel); /* Make it is positive num forever */
|
||||
configuration.complementary = (channel > 0) ? (RT_FALSE) : (RT_TRUE); /* If nagetive, it's complementary */
|
||||
result = rt_device_control(&device->parent, PWM_CMD_ENABLE, &configuration);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_err_t rt_pwm_disable(struct rt_device_pwm *device, int channel)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct rt_pwm_configuration configuration = {0};
|
||||
|
||||
if (!device)
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
|
||||
configuration.channel = (channel > 0) ? (channel) : (-channel); /* Make it is positive num forever */
|
||||
configuration.complementary = (channel > 0) ? (RT_FALSE) : (RT_TRUE); /* If nagetive, it's complementary */
|
||||
result = rt_device_control(&device->parent, PWM_CMD_DISABLE, &configuration);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_err_t rt_pwm_set(struct rt_device_pwm *device, int channel, rt_uint32_t period, rt_uint32_t pulse)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct rt_pwm_configuration configuration = {0};
|
||||
|
||||
if (!device)
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
|
||||
configuration.channel = channel;
|
||||
configuration.period = period;
|
||||
configuration.pulse = pulse;
|
||||
result = rt_device_control(&device->parent, PWM_CMD_SET, &configuration);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
rt_err_t rt_pwm_get(struct rt_device_pwm *device, struct rt_pwm_configuration *cfg)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
if (!device)
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
|
||||
result = rt_device_control(&device->parent, PWM_CMD_GET, cfg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
#include <finsh.h>
|
||||
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(rt_pwm_enable, pwm_enable, enable pwm by channel.);
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(rt_pwm_set, pwm_set, set pwm.);
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
static int pwm_enable(int argc, char **argv)
|
||||
{
|
||||
int result = 0;
|
||||
struct rt_device_pwm *device = RT_NULL;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
rt_kprintf("Usage: pwm_enable pwm1 1\n");
|
||||
rt_kprintf(" pwm_enable <pwm_dev> <channel/-channel>\n");
|
||||
result = -RT_ERROR;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
device = (struct rt_device_pwm *)rt_device_find(argv[1]);
|
||||
if (!device)
|
||||
{
|
||||
result = -RT_EIO;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
/* If channel is complementary(1), make the channel number to nagetive */
|
||||
result = rt_pwm_enable(device, atoi(argv[2]));
|
||||
|
||||
_exit:
|
||||
return result;
|
||||
}
|
||||
MSH_CMD_EXPORT(pwm_enable, pwm_enable <pwm_dev> <channel/-channel>);
|
||||
|
||||
static int pwm_disable(int argc, char **argv)
|
||||
{
|
||||
int result = 0;
|
||||
struct rt_device_pwm *device = RT_NULL;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
rt_kprintf("Usage: pwm_disable pwm1 1\n");
|
||||
rt_kprintf(" pwm_disable <pwm_dev> <channel/-channel> \n");
|
||||
result = -RT_ERROR;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
device = (struct rt_device_pwm *)rt_device_find(argv[1]);
|
||||
if (!device)
|
||||
{
|
||||
result = -RT_EIO;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
/* If channel is complementary(1), make the channel number to nagetive */
|
||||
result = rt_pwm_disable(device, atoi(argv[2]));
|
||||
|
||||
_exit:
|
||||
return result;
|
||||
}
|
||||
MSH_CMD_EXPORT(pwm_disable, pwm_disable <pwm_dev> <channel/-channel>);
|
||||
|
||||
static int pwm_set(int argc, char **argv)
|
||||
{
|
||||
int result = 0;
|
||||
struct rt_device_pwm *device = RT_NULL;
|
||||
|
||||
if (argc != 5)
|
||||
{
|
||||
rt_kprintf("Usage: pwm_set pwm1 1 100 50\n");
|
||||
rt_kprintf("Usage: pwm_set <pwm_dev> <channel> <period> <pulse>\n");
|
||||
result = -RT_ERROR;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
device = (struct rt_device_pwm *)rt_device_find(argv[1]);
|
||||
if (!device)
|
||||
{
|
||||
result = -RT_EIO;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
result = rt_pwm_set(device, atoi(argv[2]), atoi(argv[3]), atoi(argv[4]));
|
||||
|
||||
_exit:
|
||||
return result;
|
||||
}
|
||||
MSH_CMD_EXPORT(pwm_set, pwm_set <pwm_dev> <channel> <period> <pulse>);
|
||||
|
||||
|
||||
static int pwm_get(int argc, char **argv)
|
||||
{
|
||||
int result = 0;
|
||||
struct rt_device_pwm *device = RT_NULL;
|
||||
struct rt_pwm_configuration cfg = {0};
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
rt_kprintf("Usage: pwm_get pwm1 1\n");
|
||||
rt_kprintf(" pwm_get <pwm_dev> <channel>\n");
|
||||
result = -RT_ERROR;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
device = (struct rt_device_pwm *)rt_device_find(argv[1]);
|
||||
if (!device)
|
||||
{
|
||||
result = -RT_EIO;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
cfg.channel = atoi(argv[2]);
|
||||
result = rt_pwm_get(device, &cfg);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
rt_kprintf("Get info of device: [%s] error.\n", argv[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Get info of device: [%s]:\n", argv[1]);
|
||||
rt_kprintf("period : %d\n", cfg.period);
|
||||
rt_kprintf("pulse : %d\n", cfg.pulse);
|
||||
rt_kprintf("Duty cycle : %d%%\n", (int)(((double)(cfg.pulse)/(cfg.period)) * 100));
|
||||
}
|
||||
|
||||
_exit:
|
||||
return result;
|
||||
}
|
||||
MSH_CMD_EXPORT(pwm_get, pwm_get <pwm_dev> <channel>);
|
||||
|
||||
#endif /* RT_USING_FINSH */
|
||||
#endif /* RT_USING_FINSH */
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-08-13 balanceTWK the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
static rt_err_t rt_inputcapture_init(struct rt_device *dev)
|
||||
{
|
||||
rt_err_t ret;
|
||||
struct rt_inputcapture_device *inputcapture;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
ret = RT_EOK;
|
||||
inputcapture = (struct rt_inputcapture_device *)dev;
|
||||
inputcapture->watermark = RT_INPUT_CAPTURE_RB_SIZE / 2;
|
||||
if (inputcapture->ops->init)
|
||||
{
|
||||
ret = inputcapture->ops->init(inputcapture);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static rt_err_t rt_inputcapture_open(struct rt_device *dev, rt_uint16_t oflag)
|
||||
{
|
||||
rt_err_t ret;
|
||||
struct rt_inputcapture_device *inputcapture;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
ret = RT_EOK;
|
||||
inputcapture = (struct rt_inputcapture_device *)dev;
|
||||
if (inputcapture->ringbuff == RT_NULL)
|
||||
{
|
||||
inputcapture->ringbuff = rt_ringbuffer_create(sizeof(struct rt_inputcapture_data) * RT_INPUT_CAPTURE_RB_SIZE);
|
||||
}
|
||||
if (inputcapture->ops->open)
|
||||
{
|
||||
ret = inputcapture->ops->open(inputcapture);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static rt_err_t rt_inputcapture_close(struct rt_device *dev)
|
||||
{
|
||||
rt_err_t ret;
|
||||
struct rt_inputcapture_device *inputcapture;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
ret = -RT_ERROR;
|
||||
inputcapture = (struct rt_inputcapture_device *)dev;
|
||||
|
||||
if (inputcapture->ops->close)
|
||||
{
|
||||
ret = inputcapture->ops->close(inputcapture);
|
||||
}
|
||||
|
||||
if (ret != RT_EOK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (inputcapture->ringbuff)
|
||||
{
|
||||
rt_ringbuffer_destroy(inputcapture->ringbuff);
|
||||
inputcapture->ringbuff = RT_NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static rt_size_t rt_inputcapture_read(struct rt_device *dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
rt_size_t receive_size;
|
||||
struct rt_inputcapture_device *inputcapture;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
inputcapture = (struct rt_inputcapture_device *)dev;
|
||||
receive_size = rt_ringbuffer_get(inputcapture->ringbuff, (rt_uint8_t *)buffer, sizeof(struct rt_inputcapture_data) * size);
|
||||
|
||||
return receive_size / sizeof(struct rt_inputcapture_data);
|
||||
}
|
||||
|
||||
static rt_err_t rt_inputcapture_control(struct rt_device *dev, int cmd, void *args)
|
||||
{
|
||||
rt_err_t result;
|
||||
struct rt_inputcapture_device *inputcapture;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
result = RT_EOK;
|
||||
inputcapture = (struct rt_inputcapture_device *)dev;
|
||||
switch (cmd)
|
||||
{
|
||||
case INPUTCAPTURE_CMD_CLEAR_BUF:
|
||||
if (inputcapture->ringbuff)
|
||||
{
|
||||
rt_ringbuffer_reset(inputcapture->ringbuff);
|
||||
}
|
||||
break;
|
||||
case INPUTCAPTURE_CMD_SET_WATERMARK:
|
||||
inputcapture->watermark = *(rt_size_t *)args;
|
||||
break;
|
||||
default:
|
||||
result = -RT_ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops inputcapture_ops =
|
||||
{
|
||||
rt_inputcapture_init,
|
||||
rt_inputcapture_open,
|
||||
rt_inputcapture_close,
|
||||
rt_inputcapture_read,
|
||||
RT_NULL,
|
||||
rt_inputcapture_control
|
||||
};
|
||||
#endif
|
||||
|
||||
rt_err_t rt_device_inputcapture_register(struct rt_inputcapture_device *inputcapture, const char *name, void *user_data)
|
||||
{
|
||||
struct rt_device *device;
|
||||
|
||||
RT_ASSERT(inputcapture != RT_NULL);
|
||||
RT_ASSERT(inputcapture->ops != RT_NULL);
|
||||
RT_ASSERT(inputcapture->ops->get_pulsewidth != RT_NULL);
|
||||
|
||||
device = &(inputcapture->parent);
|
||||
|
||||
device->type = RT_Device_Class_Miscellaneous;
|
||||
device->rx_indicate = RT_NULL;
|
||||
device->tx_complete = RT_NULL;
|
||||
inputcapture->ringbuff = RT_NULL;
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
device->ops = &inputcapture_ops;
|
||||
#else
|
||||
device->init = rt_inputcapture_init;
|
||||
device->open = rt_inputcapture_open;
|
||||
device->close = rt_inputcapture_close;
|
||||
device->read = rt_inputcapture_read;
|
||||
device->write = RT_NULL;
|
||||
device->control = rt_inputcapture_control;
|
||||
#endif
|
||||
device->user_data = user_data;
|
||||
|
||||
return rt_device_register(device, name, RT_DEVICE_FLAG_RDONLY | RT_DEVICE_FLAG_STANDALONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is ISR for inputcapture interrupt.
|
||||
* level: RT_TRUE denotes high level pulse, and RT_FALSE denotes low level pulse.
|
||||
*/
|
||||
void rt_hw_inputcapture_isr(struct rt_inputcapture_device *inputcapture, rt_bool_t level)
|
||||
{
|
||||
struct rt_inputcapture_data data;
|
||||
rt_size_t receive_size;
|
||||
if (inputcapture->ops->get_pulsewidth(inputcapture, &data.pulsewidth_us) != RT_EOK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
data.is_high = level;
|
||||
if (rt_ringbuffer_put(inputcapture->ringbuff, (rt_uint8_t *)&data, sizeof(struct rt_inputcapture_data)) == 0)
|
||||
{
|
||||
LOG_W("inputcapture ringbuffer doesn't have enough space.");
|
||||
}
|
||||
|
||||
receive_size = rt_ringbuffer_data_len(inputcapture->ringbuff) / sizeof(struct rt_inputcapture_data);
|
||||
|
||||
if (receive_size >= inputcapture->watermark)
|
||||
{
|
||||
/* indicate to upper layer application */
|
||||
if (inputcapture->parent.rx_indicate != RT_NULL)
|
||||
inputcapture->parent.rx_indicate(&inputcapture->parent, receive_size);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = []
|
||||
depend = ['']
|
||||
|
||||
CPPPATH = [cwd + '/../include']
|
||||
group = []
|
||||
|
||||
if GetDepend(['RT_USING_MTD_NOR']):
|
||||
src += ['mtd_nor.c']
|
||||
depend += ['RT_USING_MTD_NOR']
|
||||
|
||||
if GetDepend(['RT_USING_MTD_NAND']):
|
||||
src += ['mtd_nand.c']
|
||||
depend += ['RT_USING_MTD_NAND']
|
||||
|
||||
if src:
|
||||
group = DefineGroup('DeviceDrivers', src, depend = depend, CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-12-05 Bernard the first version
|
||||
*/
|
||||
|
||||
/*
|
||||
* COPYRIGHT (C) 2012, Shanghai Real Thread
|
||||
*/
|
||||
|
||||
#include <drivers/mtd_nand.h>
|
||||
|
||||
#ifdef RT_USING_MTD_NAND
|
||||
|
||||
/**
|
||||
* RT-Thread Generic Device Interface
|
||||
*/
|
||||
static rt_err_t _mtd_init(rt_device_t dev)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t _mtd_open(rt_device_t dev, rt_uint16_t oflag)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t _mtd_close(rt_device_t dev)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_size_t _mtd_read(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
static rt_size_t _mtd_write(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
static rt_err_t _mtd_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops mtd_nand_ops =
|
||||
{
|
||||
_mtd_init,
|
||||
_mtd_open,
|
||||
_mtd_close,
|
||||
_mtd_read,
|
||||
_mtd_write,
|
||||
_mtd_control
|
||||
};
|
||||
#endif
|
||||
|
||||
rt_err_t rt_mtd_nand_register_device(const char *name,
|
||||
struct rt_mtd_nand_device *device)
|
||||
{
|
||||
rt_device_t dev;
|
||||
|
||||
dev = RT_DEVICE(device);
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
/* set device class and generic device interface */
|
||||
dev->type = RT_Device_Class_MTD;
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
dev->ops = &mtd_nand_ops;
|
||||
#else
|
||||
dev->init = _mtd_init;
|
||||
dev->open = _mtd_open;
|
||||
dev->read = _mtd_read;
|
||||
dev->write = _mtd_write;
|
||||
dev->close = _mtd_close;
|
||||
dev->control = _mtd_control;
|
||||
#endif
|
||||
|
||||
dev->rx_indicate = RT_NULL;
|
||||
dev->tx_complete = RT_NULL;
|
||||
|
||||
/* register to RT-Thread device system */
|
||||
return rt_device_register(dev, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
|
||||
}
|
||||
|
||||
#if defined(RT_MTD_NAND_DEBUG) && defined(RT_USING_FINSH)
|
||||
#include <finsh.h>
|
||||
#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
|
||||
|
||||
static void mtd_dump_hex(const rt_uint8_t *ptr, rt_size_t buflen)
|
||||
{
|
||||
unsigned char *buf = (unsigned char *)ptr;
|
||||
int i, j;
|
||||
for (i = 0; i < buflen; i += 16)
|
||||
{
|
||||
rt_kprintf("%06x: ", i);
|
||||
for (j = 0; j < 16; j++)
|
||||
if (i + j < buflen)
|
||||
rt_kprintf("%02x ", buf[i + j]);
|
||||
else
|
||||
rt_kprintf(" ");
|
||||
rt_kprintf(" ");
|
||||
for (j = 0; j < 16; j++)
|
||||
if (i + j < buflen)
|
||||
rt_kprintf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int mtd_nandid(const char *name)
|
||||
{
|
||||
struct rt_mtd_nand_device *nand;
|
||||
nand = RT_MTD_NAND_DEVICE(rt_device_find(name));
|
||||
if (nand == RT_NULL)
|
||||
{
|
||||
rt_kprintf("no nand device found!\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
return rt_mtd_nand_read_id(nand);
|
||||
}
|
||||
|
||||
int mtd_nand_read(const char *name, int block, int page)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_uint8_t *page_ptr;
|
||||
rt_uint8_t *oob_ptr;
|
||||
struct rt_mtd_nand_device *nand;
|
||||
|
||||
nand = RT_MTD_NAND_DEVICE(rt_device_find(name));
|
||||
if (nand == RT_NULL)
|
||||
{
|
||||
rt_kprintf("no nand device found!\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
page_ptr = rt_malloc(nand->page_size + nand->oob_size);
|
||||
if (page_ptr == RT_NULL)
|
||||
{
|
||||
rt_kprintf("out of memory!\n");
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
oob_ptr = page_ptr + nand->page_size;
|
||||
rt_memset(page_ptr, 0xff, nand->page_size + nand->oob_size);
|
||||
|
||||
/* calculate the page number */
|
||||
page = block * nand->pages_per_block + page;
|
||||
result = rt_mtd_nand_read(nand, page, page_ptr, nand->page_size,
|
||||
oob_ptr, nand->oob_size);
|
||||
|
||||
rt_kprintf("read page, rc=%d\n", result);
|
||||
mtd_dump_hex(page_ptr, nand->page_size);
|
||||
mtd_dump_hex(oob_ptr, nand->oob_size);
|
||||
|
||||
rt_free(page_ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mtd_nand_readoob(const char *name, int block, int page)
|
||||
{
|
||||
struct rt_mtd_nand_device *nand;
|
||||
rt_uint8_t *oob_ptr;
|
||||
|
||||
nand = RT_MTD_NAND_DEVICE(rt_device_find(name));
|
||||
if (nand == RT_NULL)
|
||||
{
|
||||
rt_kprintf("no nand device found!\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
oob_ptr = rt_malloc(nand->oob_size);
|
||||
if (oob_ptr == RT_NULL)
|
||||
{
|
||||
rt_kprintf("out of memory!\n");
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
/* calculate the page number */
|
||||
page = block * nand->pages_per_block + page;
|
||||
rt_mtd_nand_read(nand, page, RT_NULL, nand->page_size,
|
||||
oob_ptr, nand->oob_size);
|
||||
mtd_dump_hex(oob_ptr, nand->oob_size);
|
||||
|
||||
rt_free(oob_ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mtd_nand_write(const char *name, int block, int page)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_uint8_t *page_ptr;
|
||||
rt_uint8_t *oob_ptr;
|
||||
rt_uint32_t index;
|
||||
struct rt_mtd_nand_device *nand;
|
||||
|
||||
nand = RT_MTD_NAND_DEVICE(rt_device_find(name));
|
||||
if (nand == RT_NULL)
|
||||
{
|
||||
rt_kprintf("no nand device found!\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
page_ptr = rt_malloc(nand->page_size + nand->oob_size);
|
||||
if (page_ptr == RT_NULL)
|
||||
{
|
||||
rt_kprintf("out of memory!\n");
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
oob_ptr = page_ptr + nand->page_size;
|
||||
/* prepare page data */
|
||||
for (index = 0; index < nand->page_size; index ++)
|
||||
{
|
||||
page_ptr[index] = index & 0xff;
|
||||
}
|
||||
/* prepare oob data */
|
||||
for (index = 0; index < nand->oob_size; index ++)
|
||||
{
|
||||
oob_ptr[index] = index & 0xff;
|
||||
}
|
||||
|
||||
/* calculate the page number */
|
||||
page = block * nand->pages_per_block + page;
|
||||
result = rt_mtd_nand_write(nand, page, page_ptr, nand->page_size,
|
||||
oob_ptr, nand->oob_size);
|
||||
if (result != RT_MTD_EOK)
|
||||
{
|
||||
rt_kprintf("write page failed!, rc=%d\n", result);
|
||||
}
|
||||
|
||||
rt_free(page_ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mtd_nand_erase(const char *name, int block)
|
||||
{
|
||||
struct rt_mtd_nand_device *nand;
|
||||
nand = RT_MTD_NAND_DEVICE(rt_device_find(name));
|
||||
if (nand == RT_NULL)
|
||||
{
|
||||
rt_kprintf("no nand device found!\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
return rt_mtd_nand_erase_block(nand, block);
|
||||
}
|
||||
|
||||
int mtd_nand_erase_all(const char *name)
|
||||
{
|
||||
rt_uint32_t index = 0;
|
||||
struct rt_mtd_nand_device *nand;
|
||||
|
||||
nand = RT_MTD_NAND_DEVICE(rt_device_find(name));
|
||||
if (nand == RT_NULL)
|
||||
{
|
||||
rt_kprintf("no nand device found!\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
for (index = 0; index < (nand->block_end - nand->block_start); index ++)
|
||||
{
|
||||
rt_mtd_nand_erase_block(nand, index);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
static void mtd_nand(int argc, char **argv)
|
||||
{
|
||||
/* If the number of arguments less than 2 */
|
||||
if (argc < 3)
|
||||
{
|
||||
help:
|
||||
rt_kprintf("\n");
|
||||
rt_kprintf("mtd_nand [OPTION] [PARAM ...]\n");
|
||||
rt_kprintf(" id <name> Get nandid by given name\n");
|
||||
rt_kprintf(" read <name> <bn> <pn> Read data on page <pn> of block <bn> of device <name>\n");
|
||||
rt_kprintf(" readoob <name> <bn> <pn> Read oob on page <pn> of block <bn> of device <name>\n");
|
||||
rt_kprintf(" write <name> <bn> <pn> Run write test on page <pn> of block <bn> of device <name>\n");
|
||||
rt_kprintf(" erase <name> <bn> Erase on block <bn> of device <name>\n");
|
||||
rt_kprintf(" eraseall <name> Erase all block on device <name>\n");
|
||||
return ;
|
||||
}
|
||||
else if (!rt_strcmp(argv[1], "id"))
|
||||
{
|
||||
mtd_nandid(argv[2]);
|
||||
}
|
||||
else if (!rt_strcmp(argv[1], "read"))
|
||||
{
|
||||
if (argc < 5)
|
||||
{
|
||||
rt_kprintf("The input parameters are too few!\n");
|
||||
goto help;
|
||||
}
|
||||
mtd_nand_read(argv[2], atoi(argv[3]), atoi(argv[4]));
|
||||
}
|
||||
else if (!rt_strcmp(argv[1], "readoob"))
|
||||
{
|
||||
if (argc < 5)
|
||||
{
|
||||
rt_kprintf("The input parameters are too few!\n");
|
||||
goto help;
|
||||
}
|
||||
mtd_nand_readoob(argv[2], atoi(argv[3]), atoi(argv[4]));
|
||||
}
|
||||
else if (!rt_strcmp(argv[1], "write"))
|
||||
{
|
||||
if (argc < 5)
|
||||
{
|
||||
rt_kprintf("The input parameters are too few!\n");
|
||||
goto help;
|
||||
}
|
||||
mtd_nand_write(argv[2], atoi(argv[3]), atoi(argv[4]));
|
||||
}
|
||||
else if (!rt_strcmp(argv[1], "erase"))
|
||||
{
|
||||
if (argc < 4)
|
||||
{
|
||||
rt_kprintf("The input parameters are too few!\n");
|
||||
goto help;
|
||||
}
|
||||
mtd_nand_erase(argv[2], atoi(argv[3]));
|
||||
}
|
||||
else if (!rt_strcmp(argv[1], "eraseall"))
|
||||
{
|
||||
mtd_nand_erase_all(argv[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Input parameters are not supported!\n");
|
||||
goto help;
|
||||
}
|
||||
}
|
||||
MSH_CMD_EXPORT(mtd_nand, MTD nand device test function);
|
||||
#endif /* RT_USING_FINSH */
|
||||
|
||||
#ifndef RT_USING_FINSH_ONLY
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(mtd_nandid, nand_id, read ID - nandid(name));
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(mtd_nand_read, nand_read, read page in nand - nand_read(name, block, page));
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(mtd_nand_readoob, nand_readoob, read spare data in nand - nand_readoob(name, block, page));
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(mtd_nand_write, nand_write, write dump data to nand - nand_write(name, block, page));
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(mtd_nand_erase, nand_erase, nand_erase(name, block));
|
||||
FINSH_FUNCTION_EXPORT_ALIAS(mtd_nand_erase_all, nand_erase_all, erase all of nand device - nand_erase_all(name, block));
|
||||
#endif /* RT_USING_FINSH_ONLY */
|
||||
|
||||
#endif /* defined(RT_MTD_NAND_DEBUG) && defined(RT_USING_FINSH) */
|
||||
|
||||
#endif /* RT_USING_MTD_NAND */
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* COPYRIGHT (C) 2011-2021, Real-Thread Information Technology Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-5-30 Bernard the first version
|
||||
*/
|
||||
|
||||
#include <drivers/mtd_nor.h>
|
||||
|
||||
#ifdef RT_USING_MTD_NOR
|
||||
|
||||
/**
|
||||
* RT-Thread Generic Device Interface
|
||||
*/
|
||||
static rt_err_t _mtd_init(rt_device_t dev)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t _mtd_open(rt_device_t dev, rt_uint16_t oflag)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t _mtd_close(rt_device_t dev)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_size_t _mtd_read(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
static rt_size_t _mtd_write(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
static rt_err_t _mtd_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops mtd_nor_ops =
|
||||
{
|
||||
_mtd_init,
|
||||
_mtd_open,
|
||||
_mtd_close,
|
||||
_mtd_read,
|
||||
_mtd_write,
|
||||
_mtd_control
|
||||
};
|
||||
#endif
|
||||
|
||||
rt_err_t rt_mtd_nor_register_device(const char *name,
|
||||
struct rt_mtd_nor_device *device)
|
||||
{
|
||||
rt_device_t dev;
|
||||
|
||||
dev = RT_DEVICE(device);
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
/* set device class and generic device interface */
|
||||
dev->type = RT_Device_Class_MTD;
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
dev->ops = &mtd_nor_ops;
|
||||
#else
|
||||
dev->init = _mtd_init;
|
||||
dev->open = _mtd_open;
|
||||
dev->read = _mtd_read;
|
||||
dev->write = _mtd_write;
|
||||
dev->close = _mtd_close;
|
||||
dev->control = _mtd_control;
|
||||
#endif
|
||||
|
||||
dev->rx_indicate = RT_NULL;
|
||||
dev->tx_complete = RT_NULL;
|
||||
|
||||
/* register to RT-Thread device system */
|
||||
return rt_device_register(dev, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
|
||||
}
|
||||
|
||||
#endif
|
||||
Loaded 100 of 2473 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user