init commit
This commit is contained in:
+32
@@ -0,0 +1,32 @@
|
|||||||
|
# Buid folder
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Xilinx tools generated files
|
||||||
|
.metadata/
|
||||||
|
.settings/
|
||||||
|
.wsdata/
|
||||||
|
.Xil/
|
||||||
|
logs/
|
||||||
|
Packages/
|
||||||
|
*.log*
|
||||||
|
|
||||||
|
# System generated files
|
||||||
|
# -- macOS
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
._*
|
||||||
|
|
||||||
|
# -- Windows
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
# -- Linux
|
||||||
|
*~
|
||||||
|
|
||||||
|
# IDEs and editors' files
|
||||||
|
*.idea
|
||||||
|
*.vscode
|
||||||
|
*.sublime-workspace
|
||||||
|
*.sublime-project
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
include scripts/generic_variables.mk
|
||||||
|
|
||||||
|
PLATFORM := xilinx
|
||||||
|
TARGET_PROJ ?= node
|
||||||
|
BUILD_DIR := $(PROJECT)/build
|
||||||
|
CONFIG_FILE := $(PROJECT)/config.json
|
||||||
|
|
||||||
|
include scripts/generic.mk
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# KY-XTZ
|
||||||
|
|
||||||
|
该项目为跨于新体制链路层程序。
|
||||||
|
|
||||||
|
> **注意**:本项目基于 **Vivado 2019.1** 套件构建。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 在 Linux 上构建
|
||||||
|
|
||||||
|
1. 初始化工具链环境:
|
||||||
|
```shell
|
||||||
|
source /tools/Xilinx/SDK/2019.1/settings64.sh
|
||||||
|
```
|
||||||
|
2. 运行以下命令完成构建:
|
||||||
|
```shell
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
### 在 Windows 上构建
|
||||||
|
|
||||||
|
1. 双击运行 `build.bat` 文件。
|
||||||
|
2. 根据提示输入正确的 Xilinx 工具安装路径以完成构建。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 待办事项
|
||||||
|
|
||||||
|
1. **协议完善:**
|
||||||
|
- 《网控模块 GLINK 协议》中部分描述存在模糊之处,需进一步确认。
|
||||||
|
- 实现未定义的协议内容,以确保完整的协议交互。
|
||||||
|
|
||||||
|
2. **链路层更新:**
|
||||||
|
- 当前 GLINK 总线协议显示,对飞与跨域的链路层逻辑存在显著不一致性。
|
||||||
|
- 制定并完善跨域链路层协议内容(目前协议文档尚为空)。
|
||||||
|
|
||||||
|
3. **相控阵逻辑调整:**
|
||||||
|
- 跨域与对飞所使用的相控阵控制逻辑不一致。
|
||||||
|
- 修改并优化相控阵控制逻辑以适配跨域需求(当前缺少相关技术资料)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 更新日志
|
||||||
|
|
||||||
|
### 2024/11/29
|
||||||
|
|
||||||
|
完成从 [对飞程序](https://git.gatsby.icu/gatsby/df_datalink.git) 的基础移植工作:
|
||||||
|
|
||||||
|
- 重写总线驱动程序,采用 **PS UART 控制器**完成总线信息的收发。
|
||||||
|
- 更新总线控制协议,基于《网控模块 GLINK 协议》实现核心交互逻辑。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
如需帮助或报告问题,请联系项目维护者。
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
@echo off
|
||||||
|
set "platform=xilinx"
|
||||||
|
set "tools_dir=%~dp0scripts\platform\%platform%"
|
||||||
|
set "platform_ver=2019.1"
|
||||||
|
set "work_dir=%~dp0build"
|
||||||
|
set "config=%~dp0config.json"
|
||||||
|
|
||||||
|
REM Change working dir to the dir where this script is located
|
||||||
|
cd /d "%~dp0"
|
||||||
|
|
||||||
|
REM Set up environment
|
||||||
|
call "%tools_dir%\setenv.bat" "%platform_ver%"
|
||||||
|
if "%ERRORLEVEL%" neq "0" (
|
||||||
|
echo Error: Failed to initialize environment.
|
||||||
|
pause >nul
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Build project
|
||||||
|
call "%tools_dir%\build.bat" "%config%" "%work_dir%"
|
||||||
|
if "%ERRORLEVEL%" neq "0" (
|
||||||
|
echo Error: Failed to build project.
|
||||||
|
pause >nul
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Launch SDK
|
||||||
|
call "%tools_dir%\launch.bat" "%platform_ver%" "%work_dir%"
|
||||||
|
if "%ERRORLEVEL%" neq "0" (
|
||||||
|
echo Error: Failed to launch SDK.
|
||||||
|
pause >nul
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
exit /b 0
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"project_name": "ky-xtz",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"hw_design": "hw/hsjl_node_v0.0.0.hdf",
|
||||||
|
"apps": {
|
||||||
|
"xtz_app": {
|
||||||
|
"sources": ["src/*"],
|
||||||
|
"target_cpu": "ps7_cortexa9_0",
|
||||||
|
"os": "standalone",
|
||||||
|
"language": "C",
|
||||||
|
"mem_layout" : {
|
||||||
|
"heap_size": "0x800000",
|
||||||
|
"stack_size": "0x20000"
|
||||||
|
},
|
||||||
|
"build_config": {
|
||||||
|
"debug": {
|
||||||
|
"include-path": ["src/include"],
|
||||||
|
"libraries": ["m"]
|
||||||
|
},
|
||||||
|
"release": {
|
||||||
|
"include-path": ["src/include"],
|
||||||
|
"libraries": ["m"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,193 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* Description: Global configurations.
|
||||||
|
*
|
||||||
|
* Date: 2021-04-28 13:19
|
||||||
|
* Last Editors: Fan Hao
|
||||||
|
* Last Edit Time: [2022-05-23 20:32]
|
||||||
|
*
|
||||||
|
* Revisions: Rev 0.0
|
||||||
|
* History:
|
||||||
|
* [2021-04-28]: Initial edition.
|
||||||
|
*
|
||||||
|
* Copyright(c) 2024 Beijing Institute of Technology.
|
||||||
|
* Lab of Communication and Networking
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __APP_CONFIG_H_
|
||||||
|
#define __APP_CONFIG_H_
|
||||||
|
|
||||||
|
#define XILINX_PLATFORM
|
||||||
|
|
||||||
|
#include "xparameters.h"
|
||||||
|
|
||||||
|
/******** Software Version ********/
|
||||||
|
#define _APP_VER 0x00010008
|
||||||
|
|
||||||
|
#define _APP_VER_MAIN ((_APP_VER & 0xFF000000) >> 24)
|
||||||
|
#define _APP_VER_MINOR ((_APP_VER & 0x00FF0000) >> 16)
|
||||||
|
#define _APP_VER_PATCH (_APP_VER & 0x0000FFFF)
|
||||||
|
|
||||||
|
/*********** Debug Info Level ************/
|
||||||
|
// #define _DEBUG_LEVEL 1
|
||||||
|
// 3 - print all debug info
|
||||||
|
// 2 - print warnings and errors
|
||||||
|
// 1 - print only errors
|
||||||
|
// other - print nothing
|
||||||
|
|
||||||
|
#define DATALINK_ENABLE_AUTORECONNECT
|
||||||
|
#define DATALINK_ENABLE_AUTOTIMESYNC
|
||||||
|
// #define DATALINK_ENABLE_BERTEST
|
||||||
|
|
||||||
|
/************ Hardware Configs ************/
|
||||||
|
#define CPU_CLK_HZ XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ
|
||||||
|
#define GLOBAL_TIMER_CLK_HZ (CPU_CLK_HZ / 2)
|
||||||
|
#define SCU_TIMER_CLK_HZ (CPU_CLK_HZ / 2)
|
||||||
|
#define FCLK_CLK0_HZ 100000000
|
||||||
|
|
||||||
|
/********* Zynq Platform Configs **********/
|
||||||
|
// SCU Timer (for logging)
|
||||||
|
#define SCUTIMER_DEVICE_ID XPAR_PS7_SCUTIMER_0_DEVICE_ID
|
||||||
|
#define SCUTIMER_INTR_ID XPAR_SCUTIMER_INTR
|
||||||
|
|
||||||
|
// Physical Layer Configs
|
||||||
|
#define PHY_DEVICE_ID 0X00
|
||||||
|
#define PHY_BASEADDR XPAR_PHYC_BASEADDR
|
||||||
|
#define PHY_BEAM_FORMING_ENABLE
|
||||||
|
// -- Antenna Bram Configs
|
||||||
|
#define PHY_ANTCONFIG_BRAM_DEVICE_ID XPAR_PHY_DATA_INTERFACE_ANT_CONFIG_BRAM_CTRL_DEVICE_ID
|
||||||
|
#define PHY_ANTINFO_BRAM_DEVICE_ID XPAR_PHY_DATA_INTERFACE_ANT_BEAM_BRAM_CTRL_DEVICE_ID
|
||||||
|
// -- Buffers
|
||||||
|
#define PHY_TXBUFF_BRAM_DEVICE_ID XPAR_PHY_DATA_INTERFACE_TX_FRAME_BRAM_CTRL_DEVICE_ID
|
||||||
|
#define PHY_RXBUFF_BRAM_DEVICE_ID XPAR_PHY_DATA_INTERFACE_RX_FRAME_BRAM_CTRL_DEVICE_ID
|
||||||
|
// -- Xadc
|
||||||
|
#define PHY_HW_XADC_DEVICE_ID XPAR_PS7_XADC_0_DEVICE_ID
|
||||||
|
// -- Interrupt id
|
||||||
|
#define PHY_INTR_ID XPAR_FABRIC_PHY_IRQ_INTR
|
||||||
|
#define PERIODIC_5MS_INTR_ID XPAR_FABRIC_PHY_5MS_DELAY_2MS_INTR
|
||||||
|
|
||||||
|
// Time Controller Configs
|
||||||
|
#define TIME_CONTROLLER_BASEADDR XPAR_TMC_BASEADDR
|
||||||
|
|
||||||
|
// System Bus Configs
|
||||||
|
#define SYSBUS_DEV_ID XPAR_XUARTPS_0_DEVICE_ID
|
||||||
|
#define SYSBUS_INTR_ID XPAR_XUARTPS_0_INTR
|
||||||
|
|
||||||
|
// Global Timer config
|
||||||
|
#define GLOBAL_TIMER_DEVICE_ID XPAR_GLOBAL_TMR_DEVICE_ID
|
||||||
|
#define GLOBAL_TIMER_BASEADDR XPAR_GLOBAL_TMR_BASEADDR
|
||||||
|
#define GLOBAL_TIMER_INTR_ID XPAR_GLOBAL_TMR_INTR
|
||||||
|
|
||||||
|
// INTC configis
|
||||||
|
#define INTC_DEVICE_ID XPAR_SCUGIC_0_DEVICE_ID
|
||||||
|
|
||||||
|
// AD9361 Configuration
|
||||||
|
#define SPI_INTERFACE_SPI_ENGINE
|
||||||
|
#define HAVE_SPLIT_GAIN_TABLE 1 /* only set to 0 in case split_gain_table_mode_enable = 0*/
|
||||||
|
#define HAVE_TDD_SYNTH_TABLE 1 /* only set to 0 in case split_gain_table_mode_enable = 0*/
|
||||||
|
#define AD9361_DEVICE 1 /* set it 1 if AD9361 device is used, 0 otherwise */
|
||||||
|
#define AD9364_DEVICE 0 /* set it 1 if AD9364 device is used, 0 otherwise */
|
||||||
|
#define AD9363A_DEVICE 0 /* set it 1 if AD9363A device is used, 0 otherwise */
|
||||||
|
#define HAVE_VERBOSE_MESSAGES /* Recommended during development prints errors and warnings */
|
||||||
|
// #define HAVE_DEBUG_MESSAGES /* For Debug purposes only */
|
||||||
|
// -- AD9361 SPI Engine Configuration
|
||||||
|
#define AD9361_SPI_DEVICE_ID 0
|
||||||
|
#define AD9361_SPI_ENGINE_REF_CLK FCLK_CLK0_HZ
|
||||||
|
#define AD9361_SPI_ENGINE_MAX_SPEED 5000000
|
||||||
|
#define AD9361_SPI_ENGINE_BASEADDR XPAR_AXI_SPI_ENGINE_AXI_SPI_ENGINE_BASEADDR
|
||||||
|
#define AD9361_SPI_ENGINE_DATA_WIDTH 8
|
||||||
|
#define AD9361_SPI_ENGINE_CS_DELAY 3
|
||||||
|
#define AD9361_SPI_CS_AD9361_1 0x01
|
||||||
|
#define AD9361_SPI_CS_AD9361_2 0x02
|
||||||
|
#define AD9361_TIMEOUT_TH 2000
|
||||||
|
// AD9361 GPIO Configurations
|
||||||
|
#define AD9361_GPIO_DEVICE_ID 0
|
||||||
|
#define AD9361_GPIO_OFFSET 54
|
||||||
|
#define AD9361_GPIO_INPUT 0
|
||||||
|
#define AD9361_GPIO_OUTPUT 1
|
||||||
|
#define AD9361_GPIO_DISABLE 0
|
||||||
|
#define AD9361_GPIO_ENABLE 1
|
||||||
|
// -- AD9361-1
|
||||||
|
#define AD9361_1_TXNRX (AD9361_GPIO_OFFSET + 6)
|
||||||
|
#define AD9361_1_ENABLE (AD9361_GPIO_OFFSET + 7)
|
||||||
|
#define AD9361_1_EN_AGC (AD9361_GPIO_OFFSET + 8)
|
||||||
|
#define AD9361_1_RESET_B (AD9361_GPIO_OFFSET + 9)
|
||||||
|
#define AD9361_1_CTRL_OUT0 (AD9361_GPIO_OFFSET + 10)
|
||||||
|
#define AD9361_1_CTRL_OUT1 (AD9361_GPIO_OFFSET + 11)
|
||||||
|
#define AD9361_1_CTRL_OUT2 (AD9361_GPIO_OFFSET + 12)
|
||||||
|
#define AD9361_1_CTRL_OUT3 (AD9361_GPIO_OFFSET + 13)
|
||||||
|
#define AD9361_1_CTRL_OUT4 (AD9361_GPIO_OFFSET + 14)
|
||||||
|
#define AD9361_1_CTRL_OUT5 (AD9361_GPIO_OFFSET + 15)
|
||||||
|
#define AD9361_1_CTRL_OUT6 (AD9361_GPIO_OFFSET + 16)
|
||||||
|
#define AD9361_1_CTRL_OUT7 (AD9361_GPIO_OFFSET + 17)
|
||||||
|
#define AD9361_1_CTRL_IN0 (AD9361_GPIO_OFFSET + 18)
|
||||||
|
#define AD9361_1_CTRL_IN1 (AD9361_GPIO_OFFSET + 19)
|
||||||
|
#define AD9361_1_CTRL_IN2 (AD9361_GPIO_OFFSET + 20)
|
||||||
|
#define AD9361_1_CTRL_IN3 (AD9361_GPIO_OFFSET + 21)
|
||||||
|
// AD9361-2
|
||||||
|
#define AD9361_2_TXNRX (AD9361_GPIO_OFFSET + 22)
|
||||||
|
#define AD9361_2_ENABLE (AD9361_GPIO_OFFSET + 23)
|
||||||
|
#define AD9361_2_EN_AGC (AD9361_GPIO_OFFSET + 24)
|
||||||
|
#define AD9361_2_RESET_B (AD9361_GPIO_OFFSET + 25)
|
||||||
|
#define AD9361_2_CTRL_OUT0 (AD9361_GPIO_OFFSET + 26)
|
||||||
|
#define AD9361_2_CTRL_OUT1 (AD9361_GPIO_OFFSET + 27)
|
||||||
|
#define AD9361_2_CTRL_OUT2 (AD9361_GPIO_OFFSET + 28)
|
||||||
|
#define AD9361_2_CTRL_OUT3 (AD9361_GPIO_OFFSET + 29)
|
||||||
|
#define AD9361_2_CTRL_OUT4 (AD9361_GPIO_OFFSET + 30)
|
||||||
|
#define AD9361_2_CTRL_OUT5 (AD9361_GPIO_OFFSET + 31)
|
||||||
|
#define AD9361_2_CTRL_OUT6 (AD9361_GPIO_OFFSET + 32)
|
||||||
|
#define AD9361_2_CTRL_OUT7 (AD9361_GPIO_OFFSET + 33)
|
||||||
|
#define AD9361_2_CTRL_IN0 (AD9361_GPIO_OFFSET + 34)
|
||||||
|
#define AD9361_2_CTRL_IN1 (AD9361_GPIO_OFFSET + 35)
|
||||||
|
#define AD9361_2_CTRL_IN2 (AD9361_GPIO_OFFSET + 36)
|
||||||
|
#define AD9361_2_CTRL_IN3 (AD9361_GPIO_OFFSET + 37)
|
||||||
|
// AD9361-Status Code
|
||||||
|
#define AD9361_SYNC (AD9361_GPIO_OFFSET + 38)
|
||||||
|
#define AD9361_RX_FIFO_RST (AD9361_GPIO_OFFSET + 39)
|
||||||
|
#define AD9361_1_CAL_START (AD9361_GPIO_OFFSET + 40)
|
||||||
|
#define AD9361_2_CAL_START (AD9361_GPIO_OFFSET + 41)
|
||||||
|
#define AD9361_RECAL (AD9361_GPIO_OFFSET + 42)
|
||||||
|
#define AD9361_TX_SWITCH (AD9361_GPIO_OFFSET + 43)
|
||||||
|
#define AD9361_1_CAL_DONE (AD9361_GPIO_OFFSET + 44)
|
||||||
|
#define AD9361_2_CAL_DONE (AD9361_GPIO_OFFSET + 45)
|
||||||
|
#define AD9361_CAL_RESULT (AD9361_GPIO_OFFSET + 46)
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
TX_FREQ_125,
|
||||||
|
TX_FREQ_126,
|
||||||
|
TX_FREQ_4125
|
||||||
|
} ad9361TxFreq;
|
||||||
|
|
||||||
|
// HMC7044 Configurations
|
||||||
|
#define HMC7044_GPIO_DEVICE_ID 0
|
||||||
|
#define HMC7044_GPIO_OFFSET 54
|
||||||
|
#define HMC7044_RESET (HMC7044_GPIO_OFFSET + 0)
|
||||||
|
#define HMC7044_SYNC (HMC7044_GPIO_OFFSET + 1)
|
||||||
|
#define HMC7044_GPIO_0 (HMC7044_GPIO_OFFSET + 2)
|
||||||
|
#define HMC7044_GPIO_1 (HMC7044_GPIO_OFFSET + 3)
|
||||||
|
#define HMC7044_GPIO_2 (HMC7044_GPIO_OFFSET + 4)
|
||||||
|
#define HMC7044_GPIO_3 (HMC7044_GPIO_OFFSET + 5)
|
||||||
|
// -- HMC7044 SPI Engine Configuration
|
||||||
|
#define HMC7044_SPI_DEVICE_ID 0
|
||||||
|
#define HMC7044_SPI_ENGINE_REF_CLK FCLK_CLK0_HZ
|
||||||
|
#define HMC7044_SPI_ENGINE_MAX_SPEED 5000000
|
||||||
|
#define HMC7044_SPI_ENGINE_BASEADDR XPAR_AXI_SPI_ENGINE_AXI_SPI_ENGINE_BASEADDR
|
||||||
|
#define HMC7044_SPI_ENGINE_DATA_WIDTH 8
|
||||||
|
#define HMC7044_SPI_ENGINE_CS_DELAY 3
|
||||||
|
#define HMC7044_SPI_CS_HMC7044 0x00
|
||||||
|
|
||||||
|
// Configuration Check
|
||||||
|
#if defined(PHY_BEAM_SET_PRESET) && !defined(PHY_BEAM_FORMING_ENABLE)
|
||||||
|
#define PHY_BEAM_FORMING_ENABLE
|
||||||
|
#warning To impliment beam scan must enable beam forming...
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(DATALINK_ENABLE_BERTEST)
|
||||||
|
#if !defined(DATALINK_ENABLE_AUTOTIMESYNC)
|
||||||
|
#warning To enbale bit error rate test, auto time-sync should be enabled...
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //__APP_CONFIG_H_
|
||||||
@@ -0,0 +1,340 @@
|
|||||||
|
#include "dev_profile.h"
|
||||||
|
#include "../config/app_config.h"
|
||||||
|
#include "../drivers/rf-transceiver/ad9361/ad9361_api.h"
|
||||||
|
#include "../drivers/axi_core/spi_engine/spi_engine.h"
|
||||||
|
#include "../drivers/platform/xilinx_gpio.h"
|
||||||
|
|
||||||
|
struct spi_engine_init_param spi_engine_param = {
|
||||||
|
.ref_clk_hz = AD9361_SPI_ENGINE_REF_CLK,
|
||||||
|
.type = SPI_ENGINE,
|
||||||
|
.spi_engine_baseaddr = AD9361_SPI_ENGINE_BASEADDR,
|
||||||
|
.cs_delay = AD9361_SPI_ENGINE_CS_DELAY,
|
||||||
|
.data_width = AD9361_SPI_ENGINE_DATA_WIDTH
|
||||||
|
};
|
||||||
|
|
||||||
|
struct xil_gpio_init_param xil_gpio_param = {
|
||||||
|
.type = GPIO_PS,
|
||||||
|
.device_id = AD9361_GPIO_DEVICE_ID
|
||||||
|
};
|
||||||
|
|
||||||
|
AD9361_InitParam ad9361_default_init_param = {
|
||||||
|
/* Device selection */
|
||||||
|
ID_AD9361, // dev_sel
|
||||||
|
/* Reference Clock */
|
||||||
|
48000000UL, //reference_clk_rate
|
||||||
|
/* Base Configuration */
|
||||||
|
1, //two_rx_two_tx_mode_enable *** adi,2rx-2tx-mode-enable
|
||||||
|
1, //one_rx_one_tx_mode_use_rx_num *** adi,1rx-1tx-mode-use-rx-num
|
||||||
|
1, //one_rx_one_tx_mode_use_tx_num *** adi,1rx-1tx-mode-use-tx-num
|
||||||
|
1, //frequency_division_duplex_mode_enable *** adi,frequency-division-duplex-mode-enable
|
||||||
|
0, //frequency_division_duplex_independent_mode_enable *** adi,frequency-division-duplex-independent-mode-enable
|
||||||
|
0, //tdd_use_dual_synth_mode_enable *** adi,tdd-use-dual-synth-mode-enable
|
||||||
|
0, //tdd_skip_vco_cal_enable *** adi,tdd-skip-vco-cal-enable
|
||||||
|
0, //tx_fastlock_delay_ns *** adi,tx-fastlock-delay-ns
|
||||||
|
0, //rx_fastlock_delay_ns *** adi,rx-fastlock-delay-ns
|
||||||
|
0, //rx_fastlock_pincontrol_enable *** adi,rx-fastlock-pincontrol-enable
|
||||||
|
0, //tx_fastlock_pincontrol_enable *** adi,tx-fastlock-pincontrol-enable
|
||||||
|
0, //external_rx_lo_enable *** adi,external-rx-lo-enable
|
||||||
|
0, //external_tx_lo_enable *** adi,external-tx-lo-enable
|
||||||
|
5, //dc_offset_tracking_update_event_mask *** adi,dc-offset-tracking-update-event-mask
|
||||||
|
6, //dc_offset_attenuation_high_range *** adi,dc-offset-attenuation-high-range
|
||||||
|
5, //dc_offset_attenuation_low_range *** adi,dc-offset-attenuation-low-range
|
||||||
|
0x28, //dc_offset_count_high_range *** adi,dc-offset-count-high-range
|
||||||
|
0x32, //dc_offset_count_low_range *** adi,dc-offset-count-low-range
|
||||||
|
0, //split_gain_table_mode_enable *** adi,split-gain-table-mode-enable
|
||||||
|
MAX_SYNTH_FREF, //trx_synthesizer_target_fref_overwrite_hz *** adi,trx-synthesizer-target-fref-overwrite-hz
|
||||||
|
0, // qec_tracking_slow_mode_enable *** adi,qec-tracking-slow-mode-enable
|
||||||
|
/* ENSM Control */
|
||||||
|
0, //ensm_enable_pin_pulse_mode_enable *** adi,ensm-enable-pin-pulse-mode-enable
|
||||||
|
0, //ensm_enable_txnrx_control_enable *** adi,ensm-enable-txnrx-control-enable
|
||||||
|
/* LO Control */
|
||||||
|
4125000000UL, //rx_synthesizer_frequency_hz *** adi,rx-synthesizer-frequency-hz
|
||||||
|
4126000000UL, //tx_synthesizer_frequency_hz *** adi,tx-synthesizer-frequency-hz
|
||||||
|
1, //tx_lo_powerdown_managed_enable *** adi,tx-lo-powerdown-managed-enable
|
||||||
|
/* Rate & BW Control */
|
||||||
|
{768000000, 192000000, 96000000, 48000000, 24000000, 24000000},// rx_path_clock_frequencies[6] *** adi,rx-path-clock-frequencies
|
||||||
|
{768000000, 192000000, 96000000, 48000000, 24000000, 24000000},// tx_path_clock_frequencies[6] *** adi,tx-path-clock-frequencies
|
||||||
|
18000000,//rf_rx_bandwidth_hz *** adi,rf-rx-bandwidth-hz
|
||||||
|
18000000,//rf_tx_bandwidth_hz *** adi,rf-tx-bandwidth-hz
|
||||||
|
/* RF Port Control */
|
||||||
|
0, //rx_rf_port_input_select *** adi,rx-rf-port-input-select
|
||||||
|
0, //tx_rf_port_input_select *** adi,tx-rf-port-input-select
|
||||||
|
/* TX Attenuation Control */
|
||||||
|
10000, //tx_attenuation_mdB *** adi,tx-attenuation-mdB
|
||||||
|
0, //update_tx_gain_in_alert_enable *** adi,update-tx-gain-in-alert-enable
|
||||||
|
/* Reference Clock Control */
|
||||||
|
0, //xo_disable_use_ext_refclk_enable *** adi,xo-disable-use-ext-refclk-enable
|
||||||
|
{8, 5920}, //dcxo_coarse_and_fine_tune[2] *** adi,dcxo-coarse-and-fine-tune
|
||||||
|
CLKOUT_DISABLE, //clk_output_mode_select *** adi,clk-output-mode-select
|
||||||
|
/* Gain Control */
|
||||||
|
2, //gc_rx1_mode *** adi,gc-rx1-mode
|
||||||
|
2, //gc_rx2_mode *** adi,gc-rx2-mode
|
||||||
|
58, //gc_adc_large_overload_thresh *** adi,gc-adc-large-overload-thresh
|
||||||
|
4, //gc_adc_ovr_sample_size *** adi,gc-adc-ovr-sample-size
|
||||||
|
47, //gc_adc_small_overload_thresh *** adi,gc-adc-small-overload-thresh
|
||||||
|
8192, //gc_dec_pow_measurement_duration *** adi,gc-dec-pow-measurement-duration
|
||||||
|
0, //gc_dig_gain_enable *** adi,gc-dig-gain-enable
|
||||||
|
800, //gc_lmt_overload_high_thresh *** adi,gc-lmt-overload-high-thresh
|
||||||
|
704, //gc_lmt_overload_low_thresh *** adi,gc-lmt-overload-low-thresh
|
||||||
|
24, //gc_low_power_thresh *** adi,gc-low-power-thresh
|
||||||
|
15, //gc_max_dig_gain *** adi,gc-max-dig-gain
|
||||||
|
0, //gc_use_rx_fir_out_for_dec_pwr_meas_enable *** adi,gc-use-rx-fir-out-for-dec-pwr-meas-enable
|
||||||
|
/* Gain MGC Control */
|
||||||
|
2, //mgc_dec_gain_step *** adi,mgc-dec-gain-step
|
||||||
|
2, //mgc_inc_gain_step *** adi,mgc-inc-gain-step
|
||||||
|
0, //mgc_rx1_ctrl_inp_enable *** adi,mgc-rx1-ctrl-inp-enable
|
||||||
|
0, //mgc_rx2_ctrl_inp_enable *** adi,mgc-rx2-ctrl-inp-enable
|
||||||
|
0, //mgc_split_table_ctrl_inp_gain_mode *** adi,mgc-split-table-ctrl-inp-gain-mode
|
||||||
|
/* Gain AGC Control */
|
||||||
|
10, //agc_adc_large_overload_exceed_counter *** adi,agc-adc-large-overload-exceed-counter
|
||||||
|
2, //agc_adc_large_overload_inc_steps *** adi,agc-adc-large-overload-inc-steps
|
||||||
|
0, //agc_adc_lmt_small_overload_prevent_gain_inc_enable *** adi,agc-adc-lmt-small-overload-prevent-gain-inc-enable
|
||||||
|
10, //agc_adc_small_overload_exceed_counter *** adi,agc-adc-small-overload-exceed-counter
|
||||||
|
4, //agc_dig_gain_step_size *** adi,agc-dig-gain-step-size
|
||||||
|
3, //agc_dig_saturation_exceed_counter *** adi,agc-dig-saturation-exceed-counter
|
||||||
|
1000, // agc_gain_update_interval_us *** adi,agc-gain-update-interval-us
|
||||||
|
0, //agc_immed_gain_change_if_large_adc_overload_enable *** adi,agc-immed-gain-change-if-large-adc-overload-enable
|
||||||
|
0, //agc_immed_gain_change_if_large_lmt_overload_enable *** adi,agc-immed-gain-change-if-large-lmt-overload-enable
|
||||||
|
10, //agc_inner_thresh_high *** adi,agc-inner-thresh-high
|
||||||
|
1, //agc_inner_thresh_high_dec_steps *** adi,agc-inner-thresh-high-dec-steps
|
||||||
|
12, //agc_inner_thresh_low *** adi,agc-inner-thresh-low
|
||||||
|
1, //agc_inner_thresh_low_inc_steps *** adi,agc-inner-thresh-low-inc-steps
|
||||||
|
10, //agc_lmt_overload_large_exceed_counter *** adi,agc-lmt-overload-large-exceed-counter
|
||||||
|
2, //agc_lmt_overload_large_inc_steps *** adi,agc-lmt-overload-large-inc-steps
|
||||||
|
10, //agc_lmt_overload_small_exceed_counter *** adi,agc-lmt-overload-small-exceed-counter
|
||||||
|
5, //agc_outer_thresh_high *** adi,agc-outer-thresh-high
|
||||||
|
2, //agc_outer_thresh_high_dec_steps *** adi,agc-outer-thresh-high-dec-steps
|
||||||
|
18, //agc_outer_thresh_low *** adi,agc-outer-thresh-low
|
||||||
|
2, //agc_outer_thresh_low_inc_steps *** adi,agc-outer-thresh-low-inc-steps
|
||||||
|
1, //agc_attack_delay_extra_margin_us; *** adi,agc-attack-delay-extra-margin-us
|
||||||
|
0, //agc_sync_for_gain_counter_enable *** adi,agc-sync-for-gain-counter-enable
|
||||||
|
/* Fast AGC */
|
||||||
|
64, //fagc_dec_pow_measuremnt_duration *** adi,fagc-dec-pow-measurement-duration
|
||||||
|
260, //fagc_state_wait_time_ns *** adi,fagc-state-wait-time-ns
|
||||||
|
/* Fast AGC - Low Power */
|
||||||
|
0, //fagc_allow_agc_gain_increase *** adi,fagc-allow-agc-gain-increase-enable
|
||||||
|
5, //fagc_lp_thresh_increment_time *** adi,fagc-lp-thresh-increment-time
|
||||||
|
1, //fagc_lp_thresh_increment_steps *** adi,fagc-lp-thresh-increment-steps
|
||||||
|
/* Fast AGC - Lock Level (Lock Level is set via slow AGC inner high threshold) */
|
||||||
|
1, //fagc_lock_level_lmt_gain_increase_en *** adi,fagc-lock-level-lmt-gain-increase-enable
|
||||||
|
5, //fagc_lock_level_gain_increase_upper_limit *** adi,fagc-lock-level-gain-increase-upper-limit
|
||||||
|
/* Fast AGC - Peak Detectors and Final Settling */
|
||||||
|
1, //fagc_lpf_final_settling_steps *** adi,fagc-lpf-final-settling-steps
|
||||||
|
1, //fagc_lmt_final_settling_steps *** adi,fagc-lmt-final-settling-steps
|
||||||
|
3, //fagc_final_overrange_count *** adi,fagc-final-overrange-count
|
||||||
|
/* Fast AGC - Final Power Test */
|
||||||
|
0, //fagc_gain_increase_after_gain_lock_en *** adi,fagc-gain-increase-after-gain-lock-enable
|
||||||
|
/* Fast AGC - Unlocking the Gain */
|
||||||
|
0, //fagc_gain_index_type_after_exit_rx_mode *** adi,fagc-gain-index-type-after-exit-rx-mode
|
||||||
|
1, //fagc_use_last_lock_level_for_set_gain_en *** adi,fagc-use-last-lock-level-for-set-gain-enable
|
||||||
|
1, //fagc_rst_gla_stronger_sig_thresh_exceeded_en *** adi,fagc-rst-gla-stronger-sig-thresh-exceeded-enable
|
||||||
|
5, //fagc_optimized_gain_offset *** adi,fagc-optimized-gain-offset
|
||||||
|
10, //fagc_rst_gla_stronger_sig_thresh_above_ll *** adi,fagc-rst-gla-stronger-sig-thresh-above-ll
|
||||||
|
1, //fagc_rst_gla_engergy_lost_sig_thresh_exceeded_en *** adi,fagc-rst-gla-engergy-lost-sig-thresh-exceeded-enable
|
||||||
|
1, //fagc_rst_gla_engergy_lost_goto_optim_gain_en *** adi,fagc-rst-gla-engergy-lost-goto-optim-gain-enable
|
||||||
|
10, //fagc_rst_gla_engergy_lost_sig_thresh_below_ll *** adi,fagc-rst-gla-engergy-lost-sig-thresh-below-ll
|
||||||
|
8, //fagc_energy_lost_stronger_sig_gain_lock_exit_cnt *** adi,fagc-energy-lost-stronger-sig-gain-lock-exit-cnt
|
||||||
|
1, //fagc_rst_gla_large_adc_overload_en *** adi,fagc-rst-gla-large-adc-overload-enable
|
||||||
|
1, //fagc_rst_gla_large_lmt_overload_en *** adi,fagc-rst-gla-large-lmt-overload-enable
|
||||||
|
0, //fagc_rst_gla_en_agc_pulled_high_en *** adi,fagc-rst-gla-en-agc-pulled-high-enable
|
||||||
|
0, //fagc_rst_gla_if_en_agc_pulled_high_mode *** adi,fagc-rst-gla-if-en-agc-pulled-high-mode
|
||||||
|
64, //fagc_power_measurement_duration_in_state5 *** adi,fagc-power-measurement-duration-in-state5
|
||||||
|
2, //fagc_large_overload_inc_steps *** adi,fagc-adc-large-overload-inc-steps
|
||||||
|
/* RSSI Control */
|
||||||
|
1, //rssi_delay *** adi,rssi-delay
|
||||||
|
1000, //rssi_duration *** adi,rssi-duration
|
||||||
|
3, //rssi_restart_mode *** adi,rssi-restart-mode
|
||||||
|
0, //rssi_unit_is_rx_samples_enable *** adi,rssi-unit-is-rx-samples-enable
|
||||||
|
1, //rssi_wait *** adi,rssi-wait
|
||||||
|
/* Aux ADC Control */
|
||||||
|
256, //aux_adc_decimation *** adi,aux-adc-decimation
|
||||||
|
48000000UL, //aux_adc_rate *** adi,aux-adc-rate
|
||||||
|
/* AuxDAC Control */
|
||||||
|
1, //aux_dac_manual_mode_enable *** adi,aux-dac-manual-mode-enable
|
||||||
|
0, //aux_dac1_default_value_mV *** adi,aux-dac1-default-value-mV
|
||||||
|
0, //aux_dac1_active_in_rx_enable *** adi,aux-dac1-active-in-rx-enable
|
||||||
|
0, //aux_dac1_active_in_tx_enable *** adi,aux-dac1-active-in-tx-enable
|
||||||
|
0, //aux_dac1_active_in_alert_enable *** adi,aux-dac1-active-in-alert-enable
|
||||||
|
0, //aux_dac1_rx_delay_us *** adi,aux-dac1-rx-delay-us
|
||||||
|
0, //aux_dac1_tx_delay_us *** adi,aux-dac1-tx-delay-us
|
||||||
|
0, //aux_dac2_default_value_mV *** adi,aux-dac2-default-value-mV
|
||||||
|
0, //aux_dac2_active_in_rx_enable *** adi,aux-dac2-active-in-rx-enable
|
||||||
|
0, //aux_dac2_active_in_tx_enable *** adi,aux-dac2-active-in-tx-enable
|
||||||
|
0, //aux_dac2_active_in_alert_enable *** adi,aux-dac2-active-in-alert-enable
|
||||||
|
0, //aux_dac2_rx_delay_us *** adi,aux-dac2-rx-delay-us
|
||||||
|
0, //aux_dac2_tx_delay_us *** adi,aux-dac2-tx-delay-us
|
||||||
|
/* Temperature Sensor Control */
|
||||||
|
256, //temp_sense_decimation *** adi,temp-sense-decimation
|
||||||
|
1000, //temp_sense_measurement_interval_ms *** adi,temp-sense-measurement-interval-ms
|
||||||
|
0xCE, //temp_sense_offset_signed *** adi,temp-sense-offset-signed
|
||||||
|
1, //temp_sense_periodic_measurement_enable *** adi,temp-sense-periodic-measurement-enable
|
||||||
|
/* Control Out Setup */
|
||||||
|
0xFF, //ctrl_outs_enable_mask *** adi,ctrl-outs-enable-mask
|
||||||
|
0, //ctrl_outs_index *** adi,ctrl-outs-index
|
||||||
|
/* External LNA Control */
|
||||||
|
0, //elna_settling_delay_ns *** adi,elna-settling-delay-ns
|
||||||
|
0, //elna_gain_mdB *** adi,elna-gain-mdB
|
||||||
|
0, //elna_bypass_loss_mdB *** adi,elna-bypass-loss-mdB
|
||||||
|
0, //elna_rx1_gpo0_control_enable *** adi,elna-rx1-gpo0-control-enable
|
||||||
|
0, //elna_rx2_gpo1_control_enable *** adi,elna-rx2-gpo1-control-enable
|
||||||
|
0, //elna_gaintable_all_index_enable *** adi,elna-gaintable-all-index-enable
|
||||||
|
/* Digital Interface Control */
|
||||||
|
0, //digital_interface_tune_skip_mode *** adi,digital-interface-tune-skip-mode
|
||||||
|
0, //digital_interface_tune_fir_disable *** adi,digital-interface-tune-fir-disable
|
||||||
|
1, //pp_tx_swap_enable *** adi,pp-tx-swap-enable
|
||||||
|
1, //pp_rx_swap_enable *** adi,pp-rx-swap-enable
|
||||||
|
0, //tx_channel_swap_enable *** adi,tx-channel-swap-enable
|
||||||
|
0, //rx_channel_swap_enable *** adi,rx-channel-swap-enable
|
||||||
|
1, //rx_frame_pulse_mode_enable *** adi,rx-frame-pulse-mode-enable
|
||||||
|
0, //two_t_two_r_timing_enable *** adi,2t2r-timing-enable
|
||||||
|
0, //invert_data_bus_enable *** adi,invert-data-bus-enable
|
||||||
|
0, //invert_data_clk_enable *** adi,invert-data-clk-enable
|
||||||
|
0, //fdd_alt_word_order_enable *** adi,fdd-alt-word-order-enable
|
||||||
|
0, //invert_rx_frame_enable *** adi,invert-rx-frame-enable
|
||||||
|
0, //fdd_rx_rate_2tx_enable *** adi,fdd-rx-rate-2tx-enable
|
||||||
|
0, //swap_ports_enable *** adi,swap-ports-enable
|
||||||
|
0, //single_data_rate_enable *** adi,single-data-rate-enable
|
||||||
|
1, //lvds_mode_enable *** adi,lvds-mode-enable
|
||||||
|
0, //half_duplex_mode_enable *** adi,half-duplex-mode-enable
|
||||||
|
0, //single_port_mode_enable *** adi,single-port-mode-enable
|
||||||
|
0, //full_port_enable *** adi,full-port-enable
|
||||||
|
0, //full_duplex_swap_bits_enable *** adi,full-duplex-swap-bits-enable
|
||||||
|
0, //delay_rx_data *** adi,delay-rx-data
|
||||||
|
0, //rx_data_clock_delay *** adi,rx-data-clock-delay
|
||||||
|
4, //rx_data_delay *** adi,rx-data-delay
|
||||||
|
7, //tx_fb_clock_delay *** adi,tx-fb-clock-delay
|
||||||
|
0, //tx_data_delay *** adi,tx-data-delay
|
||||||
|
150, //lvds_bias_mV *** adi,lvds-bias-mV
|
||||||
|
1, //lvds_rx_onchip_termination_enable *** adi,lvds-rx-onchip-termination-enable
|
||||||
|
0, //rx1rx2_phase_inversion_en *** adi,rx1-rx2-phase-inversion-enable
|
||||||
|
0xFF, //lvds_invert1_control *** adi,lvds-invert1-control
|
||||||
|
0x0F, //lvds_invert2_control *** adi,lvds-invert2-control
|
||||||
|
/* GPO Control */
|
||||||
|
0, //gpo_manual_mode_enable *** adi,gpo-manual-mode-enable
|
||||||
|
0, //gpo_manual_mode_enable_mask *** adi,gpo-manual-mode-enable-mask
|
||||||
|
0, //gpo0_inactive_state_high_enable *** adi,gpo0-inactive-state-high-enable
|
||||||
|
0, //gpo1_inactive_state_high_enable *** adi,gpo1-inactive-state-high-enable
|
||||||
|
0, //gpo2_inactive_state_high_enable *** adi,gpo2-inactive-state-high-enable
|
||||||
|
0, //gpo3_inactive_state_high_enable *** adi,gpo3-inactive-state-high-enable
|
||||||
|
0, //gpo0_slave_rx_enable *** adi,gpo0-slave-rx-enable
|
||||||
|
0, //gpo0_slave_tx_enable *** adi,gpo0-slave-tx-enable
|
||||||
|
0, //gpo1_slave_rx_enable *** adi,gpo1-slave-rx-enable
|
||||||
|
0, //gpo1_slave_tx_enable *** adi,gpo1-slave-tx-enable
|
||||||
|
0, //gpo2_slave_rx_enable *** adi,gpo2-slave-rx-enable
|
||||||
|
0, //gpo2_slave_tx_enable *** adi,gpo2-slave-tx-enable
|
||||||
|
0, //gpo3_slave_rx_enable *** adi,gpo3-slave-rx-enable
|
||||||
|
0, //gpo3_slave_tx_enable *** adi,gpo3-slave-tx-enable
|
||||||
|
0, //gpo0_rx_delay_us *** adi,gpo0-rx-delay-us
|
||||||
|
0, //gpo0_tx_delay_us *** adi,gpo0-tx-delay-us
|
||||||
|
0, //gpo1_rx_delay_us *** adi,gpo1-rx-delay-us
|
||||||
|
0, //gpo1_tx_delay_us *** adi,gpo1-tx-delay-us
|
||||||
|
0, //gpo2_rx_delay_us *** adi,gpo2-rx-delay-us
|
||||||
|
0, //gpo2_tx_delay_us *** adi,gpo2-tx-delay-us
|
||||||
|
0, //gpo3_rx_delay_us *** adi,gpo3-rx-delay-us
|
||||||
|
0, //gpo3_tx_delay_us *** adi,gpo3-tx-delay-us
|
||||||
|
/* Tx Monitor Control */
|
||||||
|
37000, //low_high_gain_threshold_mdB *** adi,txmon-low-high-thresh
|
||||||
|
0, //low_gain_dB *** adi,txmon-low-gain
|
||||||
|
24, //high_gain_dB *** adi,txmon-high-gain
|
||||||
|
0, //tx_mon_track_en *** adi,txmon-dc-tracking-enable
|
||||||
|
0, //one_shot_mode_en *** adi,txmon-one-shot-mode-enable
|
||||||
|
511, //tx_mon_delay *** adi,txmon-delay
|
||||||
|
8192, //tx_mon_duration *** adi,txmon-duration
|
||||||
|
2, //tx1_mon_front_end_gain *** adi,txmon-1-front-end-gain
|
||||||
|
2, //tx2_mon_front_end_gain *** adi,txmon-2-front-end-gain
|
||||||
|
48, //tx1_mon_lo_cm *** adi,txmon-1-lo-cm
|
||||||
|
48, //tx2_mon_lo_cm *** adi,txmon-2-lo-cm
|
||||||
|
/* GPIO definitions */
|
||||||
|
/* Reset_b */
|
||||||
|
{
|
||||||
|
.number = AD9361_1_RESET_B,
|
||||||
|
.platform_ops = &xil_gpio_ops,
|
||||||
|
.extra = &xil_gpio_param
|
||||||
|
}, //gpio_resetb *** reset-gpios
|
||||||
|
/* MCS Sync */
|
||||||
|
{
|
||||||
|
.number = -1,
|
||||||
|
.platform_ops = &xil_gpio_ops,
|
||||||
|
.extra = &xil_gpio_param
|
||||||
|
}, //gpio_sync *** sync-gpios
|
||||||
|
/* Cal-SW1 */
|
||||||
|
{
|
||||||
|
.number = -1,
|
||||||
|
.platform_ops = &xil_gpio_ops,
|
||||||
|
.extra = &xil_gpio_param
|
||||||
|
}, //gpio_cal_sw1 *** cal-sw1-gpios
|
||||||
|
/* Cal-SW2 */
|
||||||
|
{
|
||||||
|
.number = -1,
|
||||||
|
.platform_ops = &xil_gpio_ops,
|
||||||
|
.extra = &xil_gpio_param
|
||||||
|
}, //gpio_cal_sw2 *** cal-sw2-gpios
|
||||||
|
|
||||||
|
{
|
||||||
|
.device_id = AD9361_SPI_DEVICE_ID,
|
||||||
|
.mode = SPI_MODE_1,
|
||||||
|
.chip_select = AD9361_SPI_CS_AD9361_1,
|
||||||
|
.platform_ops = &spi_eng_platform_ops,
|
||||||
|
.extra = &spi_engine_param
|
||||||
|
},
|
||||||
|
|
||||||
|
/* External LO clocks */
|
||||||
|
NULL, //(*ad9361_rfpll_ext_recalc_rate)()
|
||||||
|
NULL, //(*ad9361_rfpll_ext_round_rate)()
|
||||||
|
NULL, //(*ad9361_rfpll_ext_set_rate)()
|
||||||
|
};
|
||||||
|
|
||||||
|
AD9361_RXFIRConfig rx_fir_config = { // BPF PASSBAND 3/20 fs to 1/4 fs
|
||||||
|
3, // rx
|
||||||
|
0, // rx_gain
|
||||||
|
1, // rx_dec
|
||||||
|
{
|
||||||
|
-4, -6, -37, 35, 186, 86, -284, -315,
|
||||||
|
107, 219, -4, 271, 558, -307, -1182, -356,
|
||||||
|
658, 157, 207, 1648, 790, -2525, -2553, 748,
|
||||||
|
865, -476, 3737, 6560, -3583, -14731, -5278, 14819,
|
||||||
|
14819, -5278, -14731, -3583, 6560, 3737, -476, 865,
|
||||||
|
748, -2553, -2525, 790, 1648, 207, 157, 658,
|
||||||
|
-356, -1182, -307, 558, 271, -4, 219, 107,
|
||||||
|
-315, -284, 86, 186, 35, -37, -6, -4,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
}, // rx_coef[128]
|
||||||
|
64, // rx_coef_size
|
||||||
|
{0, 0, 0, 0, 0, 0}, //rx_path_clks[6]
|
||||||
|
0 // rx_bandwidth
|
||||||
|
};
|
||||||
|
|
||||||
|
AD9361_TXFIRConfig tx_fir_config = { // BPF PASSBAND 3/20 fs to 1/4 fs
|
||||||
|
3, // tx
|
||||||
|
-6, // tx_gain
|
||||||
|
1, // tx_int
|
||||||
|
{
|
||||||
|
-4, -6, -37, 35, 186, 86, -284, -315,
|
||||||
|
107, 219, -4, 271, 558, -307, -1182, -356,
|
||||||
|
658, 157, 207, 1648, 790, -2525, -2553, 748,
|
||||||
|
865, -476, 3737, 6560, -3583, -14731, -5278, 14819,
|
||||||
|
14819, -5278, -14731, -3583, 6560, 3737, -476, 865,
|
||||||
|
748, -2553, -2525, 790, 1648, 207, 157, 658,
|
||||||
|
-356, -1182, -307, 558, 271, -4, 219, 107,
|
||||||
|
-315, -284, 86, 186, 35, -37, -6, -4,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
}, // tx_coef[128]
|
||||||
|
64, // tx_coef_size
|
||||||
|
{0, 0, 0, 0, 0, 0}, // tx_path_clks[6]
|
||||||
|
0 // tx_bandwidth
|
||||||
|
};
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
/home/gatsby/Workspace/GitRepo/KY-XTZ/src/config
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef _DEV_PROFILE_H_
|
||||||
|
#define _DEV_PROFILE_H_
|
||||||
|
|
||||||
|
#include "irq.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "../drivers/rf-transceiver/ad9361/ad9361_api.h"
|
||||||
|
#include "../drivers/rf-transceiver/ad9361_reg/ad9361_reg.h"
|
||||||
|
#include "../drivers/frequency/hmc7044/hmc7044.h"
|
||||||
|
#include "../drivers/adc/ad9694/ad9694.h"
|
||||||
|
#include "../config/app_config.h"
|
||||||
|
|
||||||
|
// device parameters
|
||||||
|
extern struct irq_init_param intc_init_param;
|
||||||
|
extern struct timer_init_param scutimer_init_param;
|
||||||
|
extern struct global_timer_init_param globaltimer_init_param;
|
||||||
|
|
||||||
|
// HMC7044
|
||||||
|
extern struct hmc7044_init_param hmc7044_default_init_param;
|
||||||
|
|
||||||
|
// AD9361
|
||||||
|
extern AD9361_InitParam ad9361_default_init_param;
|
||||||
|
extern AD9361_RXFIRConfig rx_fir_config;
|
||||||
|
extern AD9361_TXFIRConfig tx_fir_config;
|
||||||
|
extern struct ad9361_reg_init_param ad9361_1_reg_default_init_param;
|
||||||
|
extern struct ad9361_reg_init_param ad9361_2_reg_default_init_param;
|
||||||
|
uint32_t ad9361_reg_config(struct ad9361_reg_dev *dev);
|
||||||
|
#endif /* SRC_DEV_PROFILE_H_ */
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#include "dev_profile.h"
|
||||||
|
#include "global_timer.h"
|
||||||
|
#include "../config/app_config.h"
|
||||||
|
|
||||||
|
struct global_timer_init_param globaltimer_init_param = {
|
||||||
|
.base_addr = GLOBAL_TIMER_BASEADDR,
|
||||||
|
.id = GLOBAL_TIMER_DEVICE_ID,
|
||||||
|
.freq_hz = GLOBAL_TIMER_CLK_HZ,
|
||||||
|
.load_value = 0x0000000000000000
|
||||||
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
#include "dev_profile.h"
|
||||||
|
#include "../config/app_config.h"
|
||||||
|
#include "../drivers/platform/xilinx_gpio.h"
|
||||||
|
#include "../drivers/axi_core/spi_engine/spi_engine.h"
|
||||||
|
#include "../drivers/frequency/hmc7044/hmc7044.h"
|
||||||
|
|
||||||
|
|
||||||
|
static struct spi_engine_init_param spi_engine_param = {
|
||||||
|
.ref_clk_hz = HMC7044_SPI_ENGINE_REF_CLK,
|
||||||
|
.type = SPI_ENGINE,
|
||||||
|
.spi_engine_baseaddr = HMC7044_SPI_ENGINE_BASEADDR,
|
||||||
|
.cs_delay = HMC7044_SPI_ENGINE_CS_DELAY,
|
||||||
|
.data_width = HMC7044_SPI_ENGINE_DATA_WIDTH
|
||||||
|
};
|
||||||
|
|
||||||
|
//static struct xil_gpio_init_param xil_gpio_param = {
|
||||||
|
// .type = GPIO_PS,
|
||||||
|
// .device_id = AD9361_GPIO_DEVICE_ID
|
||||||
|
//};
|
||||||
|
|
||||||
|
// hmc7044 spi settings
|
||||||
|
static struct spi_init_param hmc7044_spi_init_param = {
|
||||||
|
.device_id = HMC7044_SPI_DEVICE_ID,
|
||||||
|
.max_speed_hz = HMC7044_SPI_ENGINE_MAX_SPEED,
|
||||||
|
.mode = SPI_MODE_4,
|
||||||
|
.chip_select = HMC7044_SPI_CS_HMC7044,
|
||||||
|
.platform_ops = &spi_eng_platform_ops,
|
||||||
|
.extra = &spi_engine_param
|
||||||
|
};
|
||||||
|
|
||||||
|
// hmc7044 channel specifications
|
||||||
|
struct hmc7044_chan_spec hmc7044_chan_spec[4] = {
|
||||||
|
/* AD9361_XTAL */
|
||||||
|
{
|
||||||
|
.disable = 0,
|
||||||
|
.num = 3,
|
||||||
|
.divider = 100,
|
||||||
|
.coarse_delay = 0,
|
||||||
|
.fine_delay = 0,
|
||||||
|
.high_performance_mode_dis = true,
|
||||||
|
.start_up_mode_dynamic_enable = false,
|
||||||
|
.dynamic_driver_enable = false,
|
||||||
|
.output_control0_rb4_enable = true,
|
||||||
|
.force_mute_enable = false,
|
||||||
|
.driver_mode = CML,
|
||||||
|
.driver_impedance = INTERNAL_100OHM_PER_PIN,
|
||||||
|
.out_mux_mode = CHANNEL_DIV
|
||||||
|
},
|
||||||
|
/* FPGA_DAC_LOGIC_CLK */
|
||||||
|
{
|
||||||
|
.disable = 0,
|
||||||
|
.num = 4,
|
||||||
|
.divider = 10,
|
||||||
|
.coarse_delay = 0,
|
||||||
|
.fine_delay = 0,
|
||||||
|
.high_performance_mode_dis = true,
|
||||||
|
.start_up_mode_dynamic_enable = false,
|
||||||
|
.dynamic_driver_enable = false,
|
||||||
|
.output_control0_rb4_enable = true,
|
||||||
|
.force_mute_enable = false,
|
||||||
|
.driver_mode = CML,
|
||||||
|
.driver_impedance = INTERNAL_100OHM_PER_PIN,
|
||||||
|
.out_mux_mode = CHANNEL_DIV
|
||||||
|
},
|
||||||
|
/* B_AD9361_XTAL */
|
||||||
|
{
|
||||||
|
.disable = 0,
|
||||||
|
.num = 12,
|
||||||
|
.divider = 100,
|
||||||
|
.coarse_delay = 0,
|
||||||
|
.fine_delay = 0,
|
||||||
|
.high_performance_mode_dis = false,
|
||||||
|
.start_up_mode_dynamic_enable = false,
|
||||||
|
.dynamic_driver_enable = false,
|
||||||
|
.output_control0_rb4_enable = true,
|
||||||
|
.force_mute_enable = false,
|
||||||
|
.driver_mode = CML,
|
||||||
|
.driver_impedance = INTERNAL_100OHM_PER_PIN,
|
||||||
|
.out_mux_mode = CHANNEL_DIV
|
||||||
|
},
|
||||||
|
/* AD9361_RX_EXT_LO */
|
||||||
|
{
|
||||||
|
.disable = 0,
|
||||||
|
.num = 13,
|
||||||
|
.divider = 10,
|
||||||
|
.coarse_delay = 0,
|
||||||
|
.fine_delay = 0,
|
||||||
|
.high_performance_mode_dis = false,
|
||||||
|
.start_up_mode_dynamic_enable = false,
|
||||||
|
.dynamic_driver_enable = false,
|
||||||
|
.output_control0_rb4_enable = true,
|
||||||
|
.force_mute_enable = false,
|
||||||
|
.driver_mode = CML,
|
||||||
|
.driver_impedance = INTERNAL_100OHM_PER_PIN,
|
||||||
|
.out_mux_mode = CHANNEL_DIV
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// hmc7044 default configurations
|
||||||
|
struct hmc7044_init_param hmc7044_default_init_param = {
|
||||||
|
.spi_init = &hmc7044_spi_init_param,
|
||||||
|
.clkin_freq = {0, 100000000, 0, 0},
|
||||||
|
.vcxo_freq = 100000000,
|
||||||
|
.pll2_freq = 2500000000,
|
||||||
|
.pll1_loop_bw = 200,
|
||||||
|
.sysref_timer_div = 1536,
|
||||||
|
.in_buf_mode = {
|
||||||
|
BUFFER_DISABLE,
|
||||||
|
ENABLE_AC_COUPLE | ENABLE_INTERNAL_TERM | BUFFER_ENABLE,
|
||||||
|
BUFFER_DISABLE,
|
||||||
|
BUFFER_DISABLE,
|
||||||
|
ENABLE_AC_COUPLE | ENABLE_INTERNAL_TERM | BUFFER_ENABLE
|
||||||
|
},
|
||||||
|
.gpi_ctrl = {
|
||||||
|
GPI_DISABLE,
|
||||||
|
GPI_DISABLE,
|
||||||
|
CHIP_SLEEP_MODE,
|
||||||
|
PULSE_GEN_REQUSET
|
||||||
|
},
|
||||||
|
.gpo_ctrl = {
|
||||||
|
PLL1_LOCK_DETECT | GPO_CMOS_MODE,
|
||||||
|
PLL2_LOCK_DETECT | GPO_CMOS_MODE,
|
||||||
|
GPO_DISABLE,
|
||||||
|
GPO_DISABLE
|
||||||
|
},
|
||||||
|
.num_channels = 4,
|
||||||
|
.pll1_ref_prio_ctrl = 0xE4,
|
||||||
|
.sync_pin_mode = SYNC_MULTICHIP,
|
||||||
|
.high_performance_mode_clock_dist_en = false,
|
||||||
|
.pulse_gen_mode = PULSE_ONE,
|
||||||
|
.channels = hmc7044_chan_spec
|
||||||
|
};
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#include "dev_profile.h"
|
||||||
|
#include "irq.h"
|
||||||
|
#include "../config/app_config.h"
|
||||||
|
#include "../drivers/platform/xilinx_irq.h"
|
||||||
|
|
||||||
|
struct xil_irq_init_param xil_intc_init_param = {
|
||||||
|
.type = IRQ_PS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct irq_init_param intc_init_param = {
|
||||||
|
.irq_ctrl_id = INTC_DEVICE_ID,
|
||||||
|
.platform_ops = &xil_irq_ops,
|
||||||
|
.extra = &xil_intc_init_param
|
||||||
|
};
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#include "dev_profile.h"
|
||||||
|
#include "timer.h"
|
||||||
|
#include "../config/app_config.h"
|
||||||
|
#include "../drivers/platform/xilinx_timer.h"
|
||||||
|
|
||||||
|
struct xil_timer_init_param xil_scutimer_init_param = {
|
||||||
|
.active_tmr = 0,
|
||||||
|
.type = TIMER_PS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct timer_init_param scutimer_init_param = {
|
||||||
|
.id = SCUTIMER_DEVICE_ID,
|
||||||
|
.freq_hz = SCU_TIMER_CLK_HZ,
|
||||||
|
.ticks_count = (SCU_TIMER_CLK_HZ/5), //update log every 200ms
|
||||||
|
.platform_ops = &xil_timer_ops,
|
||||||
|
.extra = &xil_scutimer_init_param
|
||||||
|
};
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file ad9694.c
|
||||||
|
* @brief Implementation of AD9680 Driver.
|
||||||
|
* @author DBogdan ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2014-2016(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "ad9694.h"
|
||||||
|
#include "../../../include/error.h"
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief ad9694_read
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t ad9694_read(struct ad9694_dev *dev,
|
||||||
|
uint16_t reg_addr,
|
||||||
|
uint8_t *reg_data)
|
||||||
|
{
|
||||||
|
uint8_t tx_buf[2];
|
||||||
|
uint8_t rx_buf[1];
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
tx_buf[0] = 0x80 | (reg_addr >> 8);
|
||||||
|
tx_buf[1] = reg_addr & 0xFF;
|
||||||
|
|
||||||
|
|
||||||
|
ret = spi_write_and_read_3wire(dev->spi_desc,
|
||||||
|
tx_buf, rx_buf, 2, 1);
|
||||||
|
|
||||||
|
*reg_data = rx_buf[0];
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief ad9694_write
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t ad9694_write(struct ad9694_dev *dev,
|
||||||
|
uint16_t reg_addr,
|
||||||
|
uint8_t reg_data)
|
||||||
|
{
|
||||||
|
uint8_t buf[3];
|
||||||
|
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
buf[0] = reg_addr >> 8;
|
||||||
|
buf[1] = reg_addr & 0xFF;
|
||||||
|
buf[2] = reg_data;
|
||||||
|
|
||||||
|
ret = spi_write_and_read_3wire(dev->spi_desc,
|
||||||
|
buf, NULL, 3, 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief ad9694_init
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t ad9694_init(struct ad9694_dev **device,
|
||||||
|
const struct ad9694_init_param *init_param)
|
||||||
|
{
|
||||||
|
int ret = SUCCESS;
|
||||||
|
struct ad9694_dev *dev;
|
||||||
|
|
||||||
|
dev = (struct ad9694_dev *)malloc(sizeof(*dev));
|
||||||
|
if (!dev)
|
||||||
|
return FAILURE;
|
||||||
|
|
||||||
|
/* SPI */
|
||||||
|
ret = spi_init(&dev->spi_desc, init_param->spi_init);
|
||||||
|
|
||||||
|
*device = dev;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief Free the resources allocated by ad9694_setup().
|
||||||
|
*
|
||||||
|
* @param dev - The device structure.
|
||||||
|
*
|
||||||
|
* @return SUCCESS in case of success, negative error code otherwise.
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t ad9694_remove(struct ad9694_dev *dev)
|
||||||
|
{
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
ret = spi_remove(dev->spi_desc);
|
||||||
|
|
||||||
|
free(dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,231 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file ad9694.h
|
||||||
|
* @brief Header file of AD9694 Driver.
|
||||||
|
* @author DBogdan ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2014-2016(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef AD9694_H_
|
||||||
|
#define AD9694_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "delay.h"
|
||||||
|
#include "spi.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/********************** Macros and Constants Definitions **********************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#define AD9694_REG_GLOBAL_MAP_SPI_CONF_A 0x0000
|
||||||
|
#define AD9694_REG_GLOBAL_MAP_SPI_CONF_B 0x0001
|
||||||
|
#define AD9694_REG_CH_MAP_CHIP_CONF 0x0002
|
||||||
|
#define AD9694_REG_PAIR_MAP_CHIP_TYPE 0x0003
|
||||||
|
#define AD9694_REG_PAIR_MAP_CHIP_ID_LSB 0x0004
|
||||||
|
#define AD9694_REG_PAIR_MAP_CHIP_GRADE 0x0006
|
||||||
|
#define AD9694_REG_PAIR_MAP_DEV_INDEX 0x0008
|
||||||
|
#define AD9694_REG_GLOBAL_MAP_PAIR_INDEX 0x0009
|
||||||
|
#define AD9694_REG_PAIR_MAP_SCRATCH_PAD 0x000A
|
||||||
|
#define AD9694_REG_PAIR_MAP_SPI_REVISION 0x000B
|
||||||
|
#define AD9694_REG_PAIR_MAP_VENDOR_ID_LSB 0x000C
|
||||||
|
#define AD9694_REG_PAIR_MAP_VENDOR_ID_MSB 0x000D
|
||||||
|
#define AD9694_REG_CH_MAP_CHIP_PD_PIN 0x003F
|
||||||
|
#define AD9694_REG_PAIR_MAP_CHIP_PIN_CTRL_1 0x0040
|
||||||
|
#define AD9694_REG_PAIR_MAP_CLK_DIV_CTRL 0x0108
|
||||||
|
#define AD9694_REG_CH_MAP_CLK_DIV_PHASE 0x0109
|
||||||
|
#define AD9694_REG_PAIR_MAP_CLK_DIV_SYSREF_CTRL 0x010A
|
||||||
|
#define AD9694_REG_PAIR_MAP_CLK_DELAY_CTRL 0x0110
|
||||||
|
#define AD9694_REG_CH_MAP_CLK_SUPER_FINE_DELAY 0x0111
|
||||||
|
#define AD9694_REG_CH_MAP_CLK_FINE_DELAY 0x0112
|
||||||
|
#define AD9694_REG_CLK_DETN_CTRL 0x011A
|
||||||
|
#define AD9694_REG_PAIR_MAP_CLK_STAT 0x011B
|
||||||
|
#define AD9694_REG_CLK_DCS_CTRL_1 0x011C
|
||||||
|
#define AD9694_REG_CLK_DCS_CTRL_2 0x011E
|
||||||
|
#define AD9694_REG_CLK_DCS_CTRL_3 0x011F
|
||||||
|
#define AD9694_REG_PAIR_MAP_SYSREF_CTRL_1 0x0120
|
||||||
|
#define AD9694_REG_PAIR_MAP_SYSREF_CTRL_2 0x0121
|
||||||
|
#define AD9694_REG_PAIR_MAP_SYSREF_CTRL_4 0x0123
|
||||||
|
#define AD9694_REG_PAIR_MAP_SYSREF_STAT_1 0x0128
|
||||||
|
#define AD9694_REG_PAIR_MAP_SYSREF_STAT_2 0x0129
|
||||||
|
#define AD9694_REG_PAIR_MAP_SYSREF_STAT_3 0x012A
|
||||||
|
#define AD9694_REG_PAIR_MAP_CHIP_SYNC 0x01FF
|
||||||
|
#define AD9694_REG_PAIR_MAP_CHIP_MODE 0x0200
|
||||||
|
#define AD9694_REG_PAIR_MAP_CHIP_DEC_RATIO 0x0201
|
||||||
|
#define AD9694_REG_CH_MAP_CUSTOM_OFFSET 0x0228
|
||||||
|
#define AD9694_REG_CH_MAP_FD_CTRL 0x0245
|
||||||
|
#define AD9694_REG_CH_MAP_FD_UT_LSB 0x0247
|
||||||
|
#define AD9694_REG_CH_MAP_FD_UT_MSB 0x0248
|
||||||
|
#define AD9694_REG_CH_MAP_FD_LT_LSB 0x0249
|
||||||
|
#define AD9694_REG_CH_MAP_FD_LT_MSB 0x024A
|
||||||
|
#define AD9694_REG_CH_MAP_FD_DWELL_TIME_LSB 0x024B
|
||||||
|
#define AD9694_REG_CH_MAP_FD_DWELL_TIME_MSB 0x024C
|
||||||
|
#define AD9694_REG_PAIR_MAP_SIG_MON_SYNC_CTRL 0x026F
|
||||||
|
#define AD9694_REG_CH_MAP_SIG_MON_CTRL 0x0270
|
||||||
|
#define AD9694_REG_CH_MAP_SIG_MON_PERIOD_0 0x0271
|
||||||
|
#define AD9694_REG_CH_MAP_SIG_MON_PERIOD_1 0x0272
|
||||||
|
#define AD9694_REG_CH_MAP_SIG_MON_PERIOD_2 0x0273
|
||||||
|
#define AD9694_REG_CH_MAP_SIG_MON_STAT_CTRL 0x0274
|
||||||
|
#define AD9694_REG_CH_MAP_SIG_MON_STAT_0 0x0275
|
||||||
|
#define AD9694_REG_CH_MAP_SIG_MON_STAT_1 0x0276
|
||||||
|
#define AD9694_REG_CH_MAP_SIG_MON_STAT_2 0x0277
|
||||||
|
#define AD9694_REG_CH_MAP_SIG_MON_STAT_FRAME_CNT 0x0278
|
||||||
|
#define AD9694_REG_CH_MAP_SIG_MON_SERIAL_FRAMER_CTRL 0x0279
|
||||||
|
#define AD9694_REG_SPORT_OVER_JESD204B_INPUT_SEL 0x027A
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_SYNC_CTRL 0x0300
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_0_CTRL 0x0310
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_0_INPUT_SEL 0x0311
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_0 0x0314
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_1 0x0315
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_2 0x0316
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_3 0x0317
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_4 0x0318
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_INC_5 0x031A
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_0 0x031D
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_1 0x031E
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_2 0x031F
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_3 0x0320
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_4 0x0321
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_0_PHASE_OFFSET_5 0x0322
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_0_TEST_ENABLE 0x0327
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_1_CTRL 0x0330
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_1_INPUT_SEL 0x0331
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_0 0x0334
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_1 0x0335
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_2 0x0336
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_3 0x0337
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_4 0x0338
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_INC_5 0x033A
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_0 0x033D
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_1 0x033E
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_2 0x033F
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_3 0x0340
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_4 0x0341
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_1_PHASE_OFFSET_5 0x0342
|
||||||
|
#define AD9694_REG_PAIR_MAP_DDC_1_TEST_ENABLE 0x0347
|
||||||
|
#define AD9694_REG_CH_MAP_TEST_MODE_CTRL 0x0550
|
||||||
|
#define AD9694_REG_PAIR_MAP_USER_PATTERN_1_LSB 0x0551
|
||||||
|
#define AD9694_REG_PAIR_MAP_USER_PATTERN_1_MSB 0x0552
|
||||||
|
#define AD9694_REG_PAIR_MAP_USER_PATTERN_2_LSB 0x0553
|
||||||
|
#define AD9694_REG_PAIR_MAP_USER_PATTERN_2_MSB 0x0554
|
||||||
|
#define AD9694_REG_PAIR_MAP_USER_PATTERN_3_LSB 0x0555
|
||||||
|
#define AD9694_REG_PAIR_MAP_USER_PATTERN_3_MSB 0x0556
|
||||||
|
#define AD9694_REG_PAIR_MAP_USER_PATTERN_4_LSB 0x0557
|
||||||
|
#define AD9694_REG_PAIR_MAP_USER_PATTERN_4_MSB 0x0558
|
||||||
|
#define AD9694_REG_PAIR_MAP_OUTPUT_CTRL_MODE_0 0x0559
|
||||||
|
#define AD9694_REG_PAIR_MAP_OUTPUT_CTRL_MODE_1 0x055A
|
||||||
|
#define AD9694_REG_PAIR_MAP_OUTPUT_SAMPLE_MODE 0x0561
|
||||||
|
#define AD9694_REG_PAIR_MAP_OUTPUT_CH_SEL 0x0564
|
||||||
|
#define AD9694_REG_JESD204B_MAP_PLL_CTRL 0x056E
|
||||||
|
#define AD9694_REG_JESD204B_MAP_PLL_STAT 0x056F
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_QUICK_CONF 0x0570
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_LINK_CTRL_1 0x0571
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_LINK_CTRL_2 0x0572
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_LINK_CTRL_3 0x0573
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_LINK_CTRL_4 0x0574
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_LMFC_OFFSET 0x0578
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_DID_CONF 0x0580
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_BID_CONF 0x0581
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_LID_0_CONF 0x0583
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_LID_1_CONF 0x0585
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_SCR_L_CONF 0x058B
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_F_CONF 0x058C
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_K_CONF 0x058D
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_M_CONF 0x058E
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_CS_N_CONF 0x058F
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_SUBCLASS_CONF 0x0590
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_S_CONF 0x0591
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_HD_CF_CONF 0x0592
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_CHECKSUM_0_CONF 0x05A0
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_CHECKSUM_1_CONF 0x05A1
|
||||||
|
#define AD9694_REG_SERDOUTX0_SERDOUTX1_LANE_PD 0x05B0
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_LANE_ASSIGN_1 0x05B2
|
||||||
|
#define AD9694_REG_JESD204B_MAP_JTX_LANE_ASSIGN_2 0x05B3
|
||||||
|
#define AD9694_REG_JESD204B_MAP_SERD_ADJUST_0 0x05C0
|
||||||
|
#define AD9694_REG_JESD204B_MAP_SERD_ADJUST_1 0x05C1
|
||||||
|
#define AD9694_REG_JESD204B_SER_PE_SEL_LANE_0 0x05C4
|
||||||
|
#define AD9694_REG_JESD204B_SER_PE_SEL_LANE_1 0x05C6
|
||||||
|
#define AD9694_REG_LARGE_DITHER_CTRL 0x0922
|
||||||
|
#define AD9694_REG_PLL_CAL 0x1222
|
||||||
|
#define AD9694_REG_JESD204B_STARTUP_CIRCUIT_RST 0x1228
|
||||||
|
#define AD9694_REG_PLL_LOSS_OF_LOCK_CTRL 0x1262
|
||||||
|
#define AD9694_REG_DC_OFFSET_CAL_CTRL 0x0701
|
||||||
|
#define AD9694_REG_DC_OFFSET_CAL_CTRL_2 0x073B
|
||||||
|
#define AD9694_REG_PAIR_MAP_VREF_CTRL 0x18A6
|
||||||
|
#define AD9694_REG_EXT_VCM_BUF_CTRL_1 0x18E0
|
||||||
|
#define AD9694_REG_EXT_VCM_BUF_CTRL_2 0x18E1
|
||||||
|
#define AD9694_REG_EXT_VCM_BUF_CTRL_3 0x18E2
|
||||||
|
#define AD9694_REG_EXT_VCM_BUF_CTRL 0x18E3
|
||||||
|
#define AD9694_REG_TEMP_DIODE_EXPORT 0x18E6
|
||||||
|
#define AD9694_REG_CH_MAP_ANALOG_INPUT_CTRL 0x1908
|
||||||
|
#define AD9694_REG_CH_MAP_INPUT_FULLSCALE_RANGE 0x1910
|
||||||
|
#define AD9694_REG_CH_MAP_BUF_CTRL_1 0x1A4C
|
||||||
|
#define AD9694_REG_CH_MAP_BUF_CTRL_2 0x1A4D
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
struct ad9694_dev {
|
||||||
|
/* SPI */
|
||||||
|
struct spi_desc *spi_desc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ad9694_init_param {
|
||||||
|
/* SPI */
|
||||||
|
struct spi_init_param *spi_init;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ad9694_config {
|
||||||
|
uint16_t addr;
|
||||||
|
uint8_t value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
int32_t ad9694_read(struct ad9694_dev *dev,
|
||||||
|
uint16_t reg_addr,
|
||||||
|
uint8_t *reg_data);
|
||||||
|
|
||||||
|
int32_t ad9694_write(struct ad9694_dev *dev,
|
||||||
|
uint16_t reg_addr,
|
||||||
|
uint8_t reg_data);
|
||||||
|
|
||||||
|
int32_t ad9694_init(struct ad9694_dev **device,
|
||||||
|
const struct ad9694_init_param *init_param);
|
||||||
|
|
||||||
|
int32_t ad9694_remove(struct ad9694_dev *dev);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file gpio.c
|
||||||
|
* @brief Implementation of the GPIO Interface
|
||||||
|
* @author Antoniu Miclaus ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2020(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "gpio.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Definitions *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Obtain the GPIO decriptor.
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @param param - GPIO Initialization parameters.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t gpio_get(struct gpio_desc **desc,
|
||||||
|
const struct gpio_init_param *param)
|
||||||
|
{
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
if (!param || !param->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!param->platform_ops->gpio_ops_get)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
ret = param->platform_ops->gpio_ops_get(desc, param);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
(*desc)->platform_ops = param->platform_ops;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the value of an optional GPIO.
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @param param - GPIO Initialization parameters.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t gpio_get_optional(struct gpio_desc **desc,
|
||||||
|
const struct gpio_init_param *param)
|
||||||
|
{
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
if (!param || (param->number == -1)) {
|
||||||
|
*desc = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!param->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!param->platform_ops->gpio_ops_get_optional)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
ret = param->platform_ops->gpio_ops_get_optional(desc, param);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
(*desc)->platform_ops = param->platform_ops;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Free the resources allocated by gpio_get().
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t gpio_remove(struct gpio_desc *desc)
|
||||||
|
{
|
||||||
|
if (desc) {
|
||||||
|
if (!desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->gpio_ops_remove)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->gpio_ops_remove(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable the input direction of the specified GPIO.
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t gpio_direction_input(struct gpio_desc *desc)
|
||||||
|
{
|
||||||
|
if (desc) {
|
||||||
|
if (!desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->gpio_ops_direction_input)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->gpio_ops_direction_input(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable the output direction of the specified GPIO.
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @param value - The value.
|
||||||
|
* Example: GPIO_HIGH
|
||||||
|
* GPIO_LOW
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t gpio_direction_output(struct gpio_desc *desc,
|
||||||
|
uint8_t value)
|
||||||
|
{
|
||||||
|
if (desc) {
|
||||||
|
if (!desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->gpio_ops_direction_output)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->
|
||||||
|
gpio_ops_direction_output(desc, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the direction of the specified GPIO.
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @param direction - The direction.
|
||||||
|
* Example: GPIO_OUT
|
||||||
|
* GPIO_IN
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t gpio_get_direction(struct gpio_desc *desc,
|
||||||
|
uint8_t *direction)
|
||||||
|
{
|
||||||
|
if (desc) {
|
||||||
|
if (!desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->gpio_ops_get_direction)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->
|
||||||
|
gpio_ops_get_direction(desc, direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the value of the specified GPIO.
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @param value - The value.
|
||||||
|
* Example: GPIO_HIGH
|
||||||
|
* GPIO_LOW
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t gpio_set_value(struct gpio_desc *desc,
|
||||||
|
uint8_t value)
|
||||||
|
{
|
||||||
|
if (desc) {
|
||||||
|
if (!desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->gpio_ops_set_value)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->gpio_ops_set_value(desc, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the value of the specified GPIO.
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @param value - The value.
|
||||||
|
* Example: GPIO_HIGH
|
||||||
|
* GPIO_LOW
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t gpio_get_value(struct gpio_desc *desc,
|
||||||
|
uint8_t *value)
|
||||||
|
{
|
||||||
|
if (desc) {
|
||||||
|
if (!desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->gpio_ops_set_value)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->gpio_ops_get_value(desc, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file i2c.c
|
||||||
|
* @brief Implementation of the I2C Interface
|
||||||
|
* @author Antoniu Miclaus ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2020(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "i2c.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the I2C communication peripheral.
|
||||||
|
* @param desc - The I2C descriptor.
|
||||||
|
* @param param - The structure that contains the I2C parameters.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t i2c_init(struct i2c_desc **desc,
|
||||||
|
const struct i2c_init_param *param)
|
||||||
|
{
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
if (!param || !param->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!param->platform_ops->i2c_ops_init)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
ret = param->platform_ops->i2c_ops_init(desc, param);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
(*desc)->platform_ops = param->platform_ops;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free the resources allocated by i2c_init().
|
||||||
|
* @param desc - The I2C descriptor.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t i2c_remove(struct i2c_desc *desc)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->i2c_ops_remove)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->i2c_ops_remove(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief I2C Write data to slave device.
|
||||||
|
* @param desc - The I2C descriptor.
|
||||||
|
* @param data - The buffer with the transmitted/received data.
|
||||||
|
* @param bytes_number - Number of bytes to write.
|
||||||
|
* @param stop_bit - Stop conditional control.
|
||||||
|
* Example: 0 - A stop condition will not be generated.
|
||||||
|
* 1 - A stop condition will be generated.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t i2c_write(struct i2c_desc *desc,
|
||||||
|
uint8_t *data,
|
||||||
|
uint8_t bytes_number,
|
||||||
|
uint8_t stop_bit)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->i2c_ops_write)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->i2c_ops_write(desc, data, bytes_number,
|
||||||
|
stop_bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief I2C Read data from slave device.
|
||||||
|
* @param desc - The i2c descriptor.
|
||||||
|
* @param data - The buffer with the transmitted/received data.
|
||||||
|
* @param bytes_number - Number of bytes to read.
|
||||||
|
* @param stop_bit - Stop conditional control.
|
||||||
|
* Example: 0 - A stop condition will not be generated.
|
||||||
|
* 1 - A stop condition will be generated.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t i2c_read(struct i2c_desc *desc,
|
||||||
|
uint8_t *data,
|
||||||
|
uint8_t bytes_number,
|
||||||
|
uint8_t stop_bit)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->i2c_ops_read)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->i2c_ops_read(desc, data, bytes_number,
|
||||||
|
stop_bit);
|
||||||
|
}
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file irq.c
|
||||||
|
* @brief Implementation of the IRQ Interface
|
||||||
|
* @author Andrei Porumb ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2021(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "irq.h"
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the IRQ interrupts.
|
||||||
|
* @param desc - The IRQ descriptor.
|
||||||
|
* @param param - The structure that contains the IRQ parameters.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t irq_ctrl_init(struct irq_ctrl_desc **desc,
|
||||||
|
const struct irq_init_param *param)
|
||||||
|
{
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
if (!param || !param->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!param->platform_ops->init)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
ret = param->platform_ops->init(desc, param);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
(*desc)->platform_ops = param->platform_ops;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free the resources allocated by irq_ctrl_init().
|
||||||
|
* @param desc - The SPI descriptor.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t irq_ctrl_remove(struct irq_ctrl_desc *desc)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->remove)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->remove(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register a callback to handle the irq events.
|
||||||
|
* @param desc - The IRQ controller descriptor.
|
||||||
|
* @param irq_id - Interrupt identifier.
|
||||||
|
* @param callback - Callback descriptor - platform specific type.
|
||||||
|
* @return SUCCESS in case of success, FAILURE otherwise.
|
||||||
|
*/
|
||||||
|
int32_t irq_register_callback(struct irq_ctrl_desc *desc,
|
||||||
|
uint32_t irq_id,
|
||||||
|
struct callback_desc *callback)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->register_callback)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->register_callback(desc, irq_id, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unregisters a generic IRQ handling function.
|
||||||
|
* @param desc - The IRQ controller descriptor.
|
||||||
|
* @param irq_id - Interrupt identifier.
|
||||||
|
* @param callback - Callback descriptor - platform specific type.
|
||||||
|
* @return SUCCESS in case of success, FAILURE otherwise.
|
||||||
|
*/
|
||||||
|
int32_t irq_unregister_callback(struct irq_ctrl_desc *desc,
|
||||||
|
uint32_t irq_id,
|
||||||
|
struct callback_desc *callback)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->unregister_callback)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->unregister_callback(desc, irq_id, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable global interrupts.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t irq_global_enable(struct irq_ctrl_desc *desc)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->global_enable)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->global_enable(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable global interrupts.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t irq_global_disable(struct irq_ctrl_desc *desc)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->global_disable)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->global_disable(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set interrupt trigger level.
|
||||||
|
* @param desc - The IRQ controller descriptor.
|
||||||
|
* @param irq_id - Interrupt identifier.
|
||||||
|
* @param trig - New trigger level for the interrupt.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t irq_trigger_level_set(struct irq_ctrl_desc *desc,
|
||||||
|
uint32_t irq_id,
|
||||||
|
enum irq_trig_level trig)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if(!desc->platform_ops->trigger_level_set)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->trigger_level_set(desc, irq_id, trig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable specific interrupt.
|
||||||
|
* @param desc - The IRQ controller descriptor.
|
||||||
|
* @param irq_id - Interrupt identifier.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t irq_enable(struct irq_ctrl_desc *desc, uint32_t irq_id)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->enable)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->enable(desc, irq_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable specific interrupt.
|
||||||
|
* @param desc - The IRQ controller descriptor.
|
||||||
|
* @param irq_id - Interrupt identifier.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t irq_disable(struct irq_ctrl_desc *desc, uint32_t irq_id)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->disable)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->disable(desc, irq_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the priority for an interrupt.
|
||||||
|
* @param desc - The IRQ controller descriptor.
|
||||||
|
* @param irq_id - Interrupt identifier.
|
||||||
|
* @param priority_level - The priority level of the interrupt.
|
||||||
|
* @return 0 in case of success, negative errno error codes.
|
||||||
|
*/
|
||||||
|
int32_t irq_set_priority(struct irq_ctrl_desc *desc,
|
||||||
|
uint32_t irq_id,
|
||||||
|
uint32_t priority_level)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->set_priority)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->set_priority(desc, irq_id, priority_level);
|
||||||
|
}
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file spi.c
|
||||||
|
* @brief Implementation of the SPI Interface
|
||||||
|
* @author Antoniu Miclaus ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2020(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "spi.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the SPI communication peripheral.
|
||||||
|
* @param desc - The SPI descriptor.
|
||||||
|
* @param param - The structure that contains the SPI parameters.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t spi_init(struct spi_desc **desc,
|
||||||
|
const struct spi_init_param *param)
|
||||||
|
{
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
if (!param || !param->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!param->platform_ops->init)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
ret = param->platform_ops->init(desc, param);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
(*desc)->platform_ops = param->platform_ops;
|
||||||
|
(*desc)->parent = param->parent;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free the resources allocated by spi_init().
|
||||||
|
* @param desc - The SPI descriptor.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t spi_remove(struct spi_desc *desc)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->remove)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->remove(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write and read data to/from SPI.
|
||||||
|
* @param desc - The SPI descriptor.
|
||||||
|
* @param data - The buffer with the transmitted/received data.
|
||||||
|
* @param bytes_number - Number of bytes to write/read.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t spi_write_and_read(struct spi_desc *desc,
|
||||||
|
uint8_t *data,
|
||||||
|
uint16_t bytes_number)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->write_and_read)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->write_and_read(desc, data, bytes_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write and read data to/from SPI in 3 wire mode.
|
||||||
|
* @param desc - The SPI descriptor.
|
||||||
|
* @param write_data - The buffer with the transmitted data.
|
||||||
|
* @param read_data - The buffer with the received data.
|
||||||
|
* @param write_bytes_number - Number of bytes to write.
|
||||||
|
* @param read_bytes_number - Number of bytes to read.
|
||||||
|
* @return SUCCESS in case of success, FAILURE otherwise.
|
||||||
|
*/
|
||||||
|
int32_t spi_write_and_read_3wire(struct spi_desc *desc,
|
||||||
|
uint8_t *write_data,
|
||||||
|
uint8_t *read_data,
|
||||||
|
uint16_t write_bytes_number,
|
||||||
|
uint16_t read_bytes_number)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->write_and_read_3wire)
|
||||||
|
return -ENOSYS;
|
||||||
|
return desc->platform_ops->write_and_read_3wire(desc, write_data, read_data,
|
||||||
|
write_bytes_number, read_bytes_number);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Iterate over head list and send all spi messages
|
||||||
|
* @param desc - The SPI descriptor.
|
||||||
|
* @param msgs - Array of messages.
|
||||||
|
* @param len - Number of messages in the array.
|
||||||
|
* @return 0 in case of success, negativ error code otherwise.
|
||||||
|
*/
|
||||||
|
int32_t spi_transfer(struct spi_desc *desc,
|
||||||
|
struct spi_msg *msgs,
|
||||||
|
uint32_t len)
|
||||||
|
{
|
||||||
|
int32_t ret;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (desc->platform_ops->transfer)
|
||||||
|
return desc->platform_ops->transfer(desc, msgs, len);
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (msgs[i].rx_buff != msgs[i].tx_buff || !msgs[i].tx_buff)
|
||||||
|
return -EINVAL;
|
||||||
|
ret = spi_write_and_read(desc, msgs[i].rx_buff,
|
||||||
|
msgs[i].bytes_number);
|
||||||
|
if (IS_ERR_VALUE(ret))
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file timer.c
|
||||||
|
* @brief Implementation of the timer Interface
|
||||||
|
* @author RBolboac ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2022(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY
|
||||||
|
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#include "error.h"
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Definitions *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Initialize hardware timer and the handler structure associated with
|
||||||
|
* it.
|
||||||
|
* @param [out] desc - Pointer to the reference of the device handler.
|
||||||
|
* @param [in] param - Initialization structure.
|
||||||
|
* @return 0 in case of success, negative error code otherwise
|
||||||
|
*/
|
||||||
|
int32_t timer_init(struct timer_desc **desc,
|
||||||
|
struct timer_init_param *param)
|
||||||
|
{
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
if (!param || !param->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!param->platform_ops->init)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
ret = param->platform_ops->init(desc, param);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
(*desc)->platform_ops = param->platform_ops;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free the memory allocated by timer_init().
|
||||||
|
* @param [in] desc - Pointer to the device handler.
|
||||||
|
* @return 0 in case of success, negative error code otherwise
|
||||||
|
*/
|
||||||
|
int32_t timer_remove(struct timer_desc *desc)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->remove)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->remove(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start a timer.
|
||||||
|
* @param [in] desc - Pointer to the device handler.
|
||||||
|
* @return 0 in case of success, negative error code otherwise
|
||||||
|
*/
|
||||||
|
int32_t timer_start(struct timer_desc *desc)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->start)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->start(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stop a timer from counting.
|
||||||
|
* @param [in] desc - Pointer to the device handler.
|
||||||
|
* @return 0 in case of success, negative error code otherwise
|
||||||
|
*/
|
||||||
|
int32_t timer_stop(struct timer_desc *desc)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->stop)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->stop(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the value of the counter register for the timer.
|
||||||
|
* @param [in] desc - Pointer to the device handler.
|
||||||
|
* @param [out] counter - Pointer to the counter value.
|
||||||
|
* @return 0 in case of success, error code otherwise.
|
||||||
|
*/
|
||||||
|
int32_t timer_counter_get(struct timer_desc *desc,
|
||||||
|
uint32_t *counter)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops || !counter)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->counter_get)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->counter_get(desc, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the timer counter register value.
|
||||||
|
* @param [in] desc - Pointer to the device handler.
|
||||||
|
* @param [in] new_val - The new value of the counter register.
|
||||||
|
* @return 0 in case of success, error code otherwise.
|
||||||
|
*/
|
||||||
|
int32_t timer_counter_set(struct timer_desc *desc, uint32_t new_val)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->counter_set)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->counter_set(desc, new_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the timer clock frequency.
|
||||||
|
* @param [in] desc - Pointer to the device handler.
|
||||||
|
* @param [out] freq_hz - The value in Hz of the timer clock.
|
||||||
|
* @return 0 in case of success, error code otherwise.
|
||||||
|
*/
|
||||||
|
int32_t timer_count_clk_get(struct timer_desc *desc,
|
||||||
|
uint32_t *freq_hz)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops || !freq_hz)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->count_clk_get)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->count_clk_get(desc, freq_hz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the timer clock frequency.
|
||||||
|
* @param [in] desc - Pointer to the device handler.
|
||||||
|
* @param [in] freq_hz - The value in Hz of the new timer clock.
|
||||||
|
* @return 0 in case of success, error code otherwise.
|
||||||
|
*/
|
||||||
|
int32_t timer_count_clk_set(struct timer_desc *desc,
|
||||||
|
uint32_t freq_hz)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->count_clk_set)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->count_clk_set(desc, freq_hz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the elapsed time in nsec for the timer.
|
||||||
|
* @param [in] desc - Pointer to the device handler.
|
||||||
|
* @param [in] elapsed_time - The elapsed time in nsec.
|
||||||
|
* @return 0 in case of success, error code otherwise.
|
||||||
|
*/
|
||||||
|
int32_t timer_get_elapsed_time_nsec(struct timer_desc *desc,
|
||||||
|
uint64_t *elapsed_time)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->get_elapsed_time_nsec)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->get_elapsed_time_nsec(desc, elapsed_time);
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file trng.c
|
||||||
|
* @brief Implementation of the TRNG Interface
|
||||||
|
* @author Antoniu Miclaus ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2023(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "trng.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Definitions *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the TRNG.
|
||||||
|
* @param desc - The TRNG descriptor.
|
||||||
|
* @param param - The structure that contains the TRNG parameters.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int trng_init(struct trng_desc **desc,
|
||||||
|
const struct trng_init_param *param)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!param || !param->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!param->platform_ops->init)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
ret = param->platform_ops->init(desc, param);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
(*desc)->platform_ops = param->platform_ops;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free the resources allocated by trng_init().
|
||||||
|
* @param desc - The TRNG descriptor.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int trng_remove(struct trng_desc *desc)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->remove)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->remove(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fill buffer with rng data.
|
||||||
|
* @param desc - The TRNG descriptor.
|
||||||
|
* @param buff - Buffer to be filled
|
||||||
|
* @param len - Size of the buffer
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int trng_fill_buffer(struct trng_desc *desc, uint8_t *buff,
|
||||||
|
uint32_t len)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->platform_ops)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!desc->platform_ops->fill_buffer)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
return desc->platform_ops->fill_buffer(desc, buff, len);
|
||||||
|
}
|
||||||
@@ -0,0 +1,547 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* @file axi_dmac.c
|
||||||
|
* @brief Driver for the Analog Devices AXI-DMAC core.
|
||||||
|
* @author DBogdan ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2018(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "axi_io.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "delay.h"
|
||||||
|
#include "axi_dmac.h"
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief ISR for dev to mem DMA transfer. It computes the next transfer params,
|
||||||
|
* if any, and sets the transfer structure fields accordingly.
|
||||||
|
*
|
||||||
|
* @param instance - the instance that triggered the ISR.
|
||||||
|
*
|
||||||
|
* @return None.
|
||||||
|
*******************************************************************************/
|
||||||
|
void axi_dmac_dev_to_mem_isr(void *instance)
|
||||||
|
{
|
||||||
|
struct axi_dmac *dmac = (struct axi_dmac *)instance;
|
||||||
|
uint32_t burst_size;
|
||||||
|
uint32_t reg_val;
|
||||||
|
|
||||||
|
/* Get interrupt sources and clear interrupts. */
|
||||||
|
axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING, ®_val);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_PENDING, reg_val);
|
||||||
|
|
||||||
|
if (reg_val & AXI_DMAC_IRQ_SOT) {
|
||||||
|
if (dmac->remaining_size) {
|
||||||
|
/* See if remaining size is bigger than max transfer size and
|
||||||
|
* set burst size. */
|
||||||
|
if (dmac->remaining_size > dmac->max_length) {
|
||||||
|
burst_size = dmac->max_length;
|
||||||
|
} else {
|
||||||
|
burst_size = dmac->remaining_size - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The current transfer was started; set up the new one. */
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, dmac->next_dest_addr);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, 0x0);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, burst_size);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, 0x0);
|
||||||
|
|
||||||
|
/* Compute size of the next transfer. */
|
||||||
|
dmac->remaining_size = dmac->remaining_size - (burst_size + 1);
|
||||||
|
/* Address must advance with +1 since the DMAC writes X_LENGTH+1. */
|
||||||
|
dmac->next_dest_addr = dmac->next_dest_addr + (burst_size + 1);
|
||||||
|
|
||||||
|
/* Trigger the next transfer. */
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_TRANSFER_SUBMIT, AXI_DMAC_TRANSFER_SUBMIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (reg_val & AXI_DMAC_IRQ_EOT) {
|
||||||
|
if (!dmac->remaining_size) {
|
||||||
|
dmac->transfer.transfer_done = true;
|
||||||
|
dmac->next_dest_addr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief ISR for mem DMA to dev transfer. It computes the next transfer params,
|
||||||
|
* if any, and sets the transfer structure fields accordingly.
|
||||||
|
*
|
||||||
|
* @param instance - the instance that triggered the ISR.
|
||||||
|
*
|
||||||
|
* @return None.
|
||||||
|
*******************************************************************************/
|
||||||
|
void axi_dmac_mem_to_dev_isr(void *instance)
|
||||||
|
{
|
||||||
|
struct axi_dmac *dmac = (struct axi_dmac *)instance;
|
||||||
|
uint32_t burst_size;
|
||||||
|
uint32_t reg_val;
|
||||||
|
|
||||||
|
/* Get interrupt sources and clear interrupts. */
|
||||||
|
axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING, ®_val);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_PENDING, reg_val);
|
||||||
|
|
||||||
|
if (reg_val & AXI_DMAC_IRQ_SOT) {
|
||||||
|
if ((dmac->transfer.cyclic == CYCLIC) &&
|
||||||
|
(dmac->next_src_addr >= (dmac->init_addr + dmac->transfer.size - 1))) {
|
||||||
|
dmac->remaining_size = dmac->transfer.size;
|
||||||
|
dmac->next_src_addr = dmac->init_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dmac->remaining_size) {
|
||||||
|
/** See if remaining size is bigger than max transfer size and
|
||||||
|
* set burst size. */
|
||||||
|
if (dmac->remaining_size > dmac->max_length) {
|
||||||
|
burst_size = dmac->max_length;
|
||||||
|
} else {
|
||||||
|
burst_size = dmac->remaining_size - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The current transfer was started; set up the new one. */
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, dmac->next_src_addr);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, 0x0);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, burst_size);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, 0x0);
|
||||||
|
|
||||||
|
/* Compute parameters for the next transfer. */
|
||||||
|
dmac->remaining_size = dmac->remaining_size - (burst_size + 1);
|
||||||
|
/* Address must advance with +1 since the DMAC writes X_LENGTH+1. */
|
||||||
|
dmac->next_src_addr = dmac->next_src_addr + (burst_size + 1);
|
||||||
|
|
||||||
|
/* Trigger the current transfer */
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_TRANSFER_SUBMIT, AXI_DMAC_TRANSFER_SUBMIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (reg_val & AXI_DMAC_IRQ_EOT) {
|
||||||
|
if ((!dmac->remaining_size) && (dmac->transfer.cyclic != CYCLIC)) {
|
||||||
|
dmac->transfer.transfer_done = true;
|
||||||
|
dmac->next_src_addr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief ISR for mem DMA to mem DMA transfer. It computes the next transfer
|
||||||
|
* params, if any, and sets the transfer structure fields accordingly.
|
||||||
|
*
|
||||||
|
* @param instance - the instance that triggered the ISR.
|
||||||
|
*
|
||||||
|
* @return None.
|
||||||
|
*******************************************************************************/
|
||||||
|
void axi_dmac_mem_to_mem_isr(void *instance)
|
||||||
|
{
|
||||||
|
struct axi_dmac *dmac = (struct axi_dmac *)instance;
|
||||||
|
uint32_t burst_size;
|
||||||
|
uint32_t reg_val;
|
||||||
|
|
||||||
|
/* Get interrupt sources and clear interrupts. */
|
||||||
|
axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING, ®_val);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_PENDING, reg_val);
|
||||||
|
|
||||||
|
if (reg_val & AXI_DMAC_IRQ_SOT) {
|
||||||
|
if (dmac->remaining_size) {
|
||||||
|
/** See if remaining size is bigger than max transfer size and
|
||||||
|
* set burst size. */
|
||||||
|
if (dmac->remaining_size > dmac->max_length) {
|
||||||
|
burst_size = dmac->max_length;
|
||||||
|
} else {
|
||||||
|
burst_size = dmac->remaining_size - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The current transfer was started; set up the new one. */
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, dmac->next_src_addr);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, 0x0);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, dmac->next_dest_addr);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, 0x0);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, burst_size);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, 0x0);
|
||||||
|
|
||||||
|
/* Compute parameters for the next transfer. */
|
||||||
|
dmac->remaining_size = dmac->remaining_size - (burst_size + 1);
|
||||||
|
/* Address must advance with +1 since the DMAC writes X_LENGTH+1. */
|
||||||
|
dmac->next_src_addr = dmac->next_src_addr + (burst_size + 1);
|
||||||
|
dmac->next_dest_addr = dmac->next_dest_addr + (burst_size + 1);
|
||||||
|
|
||||||
|
/* If transfer finished advance src address so that transfer_done can be set*/
|
||||||
|
if (!dmac->remaining_size) {
|
||||||
|
dmac->next_src_addr = dmac->next_src_addr + (burst_size + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Trigger the current transfer */
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_TRANSFER_SUBMIT, AXI_DMAC_TRANSFER_SUBMIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (reg_val & AXI_DMAC_IRQ_EOT) {
|
||||||
|
if (!dmac->remaining_size) {
|
||||||
|
if(dmac->next_src_addr > (dmac->init_addr + dmac->transfer.size)) {
|
||||||
|
dmac->transfer.transfer_done = true;
|
||||||
|
dmac->next_src_addr = 0;
|
||||||
|
dmac->next_dest_addr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief Wrapper for AXI IO through UIO/devmem read function.
|
||||||
|
*
|
||||||
|
* @param dmac - DMAC istance containing UIO index (/dev/uioX)/base address.
|
||||||
|
* @param reg_addr - Address to read from.
|
||||||
|
* @param reg_data - Location where read data will be stored.
|
||||||
|
*
|
||||||
|
* @return 0 - success.
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t axi_dmac_read(struct axi_dmac *dmac,
|
||||||
|
uint32_t reg_addr,
|
||||||
|
uint32_t *reg_data)
|
||||||
|
{
|
||||||
|
axi_io_read(dmac->base, reg_addr, reg_data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief Wrapper for AXI IO through UIO/devmem wrrite function.
|
||||||
|
*
|
||||||
|
* @param dmac - DMAC istance containing UIO index (/dev/uioX)/base address.
|
||||||
|
* @param reg_addr - Address to write to.
|
||||||
|
* @param reg_data - Data to be written.
|
||||||
|
*
|
||||||
|
* @return 0 - success.
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t axi_dmac_write(struct axi_dmac *dmac,
|
||||||
|
uint32_t reg_addr,
|
||||||
|
uint32_t reg_data)
|
||||||
|
{
|
||||||
|
axi_io_write(dmac->base, reg_addr, reg_data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief Get transfer status (value of dmac->transfer.transfer_done flag).
|
||||||
|
*
|
||||||
|
* @note This function should not be used if DMA IRQ is not used.
|
||||||
|
*
|
||||||
|
* @param dmac - DMAC istance.
|
||||||
|
* @param rdy - Transfer status (0 - not ready, 1 - ready).
|
||||||
|
*
|
||||||
|
* @return 0 - success.
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t axi_dmac_is_transfer_ready(struct axi_dmac *dmac, bool *rdy)
|
||||||
|
{
|
||||||
|
*rdy = dmac->transfer.transfer_done;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief Get DMAC capabilities.
|
||||||
|
*
|
||||||
|
* @param dmac - DMAC istance.
|
||||||
|
*
|
||||||
|
* @return 0 for success, -1 in case of failure.
|
||||||
|
*******************************************************************************/
|
||||||
|
static int32_t axi_dmac_detect_caps(struct axi_dmac *dmac)
|
||||||
|
{
|
||||||
|
uint32_t reg_val, initial_reg_val = 0;
|
||||||
|
uint32_t src_mem_mapped = 0;
|
||||||
|
uint32_t dest_mem_mapped = 0;
|
||||||
|
|
||||||
|
dmac->max_length = -1;
|
||||||
|
dmac->direction = INVALID_DIR;
|
||||||
|
|
||||||
|
/* Check if HW cyclic possible */
|
||||||
|
axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS, &initial_reg_val);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, DMA_CYCLIC);
|
||||||
|
axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS, ®_val);
|
||||||
|
if (reg_val == DMA_CYCLIC)
|
||||||
|
dmac->hw_cyclic = true;
|
||||||
|
/* Restore initial value for AXI_DMAC_REG_FLAGS register */
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, initial_reg_val);
|
||||||
|
|
||||||
|
/* Get maximum burst size and set value. */
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, dmac->max_length);
|
||||||
|
axi_dmac_read(dmac, AXI_DMAC_REG_X_LENGTH, &dmac->max_length);
|
||||||
|
|
||||||
|
/* Get transfer direction and set value. */
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, 0xffffffff);
|
||||||
|
axi_dmac_read(dmac, AXI_DMAC_REG_DEST_ADDRESS, &dest_mem_mapped);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, 0xffffffff);
|
||||||
|
axi_dmac_read(dmac, AXI_DMAC_REG_SRC_ADDRESS, &src_mem_mapped);
|
||||||
|
|
||||||
|
if (dest_mem_mapped && !src_mem_mapped) {
|
||||||
|
dmac->direction = DMA_DEV_TO_MEM;
|
||||||
|
} else if (!dest_mem_mapped && src_mem_mapped) {
|
||||||
|
dmac->direction = DMA_MEM_TO_DEV;
|
||||||
|
} else if (dest_mem_mapped && src_mem_mapped) {
|
||||||
|
dmac->direction = DMA_MEM_TO_MEM;
|
||||||
|
} else {
|
||||||
|
printf("Destination and source memory-mapped interfaces not supported.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief Get transfer status (value of dmac->transfer.transfer_done flag).
|
||||||
|
*
|
||||||
|
* @param dmac_core - DMAC istance.
|
||||||
|
* @param init - Structure containing initializing data.
|
||||||
|
*
|
||||||
|
* @return 0 for success, -1 in case of failure.
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t axi_dmac_init(struct axi_dmac **dmac_core,
|
||||||
|
const struct axi_dmac_init *init)
|
||||||
|
{
|
||||||
|
struct axi_dmac *dmac;
|
||||||
|
|
||||||
|
dmac = (struct axi_dmac *)calloc(1, sizeof(*dmac));
|
||||||
|
if (!dmac)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
dmac->name = init->name;
|
||||||
|
dmac->base = init->base;
|
||||||
|
dmac->irq_option = init->irq_option;
|
||||||
|
|
||||||
|
*dmac_core = dmac;
|
||||||
|
|
||||||
|
int32_t status = axi_dmac_detect_caps(*dmac_core);
|
||||||
|
if (status < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief Remove the DMAC instance.
|
||||||
|
*
|
||||||
|
* @param dmac - DMAC istance.
|
||||||
|
*
|
||||||
|
* @return 0 for success, -1 in case of failure.
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t axi_dmac_remove(struct axi_dmac *dmac)
|
||||||
|
{
|
||||||
|
if (!dmac)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
free(dmac);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief Start a DMA transfer.
|
||||||
|
*
|
||||||
|
* @param dmac - DMAC istance.
|
||||||
|
* @param dma_transfer - Structure containing transfer details.
|
||||||
|
*
|
||||||
|
* @return 0 for success, -1 in case of failure.
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t axi_dmac_transfer_start(struct axi_dmac *dmac,
|
||||||
|
struct axi_dma_transfer *dma_transfer)
|
||||||
|
{
|
||||||
|
uint32_t reg_val, burst_size;
|
||||||
|
|
||||||
|
if (dma_transfer->size == 0)
|
||||||
|
return 0; /* Nothing to do. */
|
||||||
|
|
||||||
|
/* Set current transfer parameters. */
|
||||||
|
dmac->transfer.size = dma_transfer->size;
|
||||||
|
dmac->transfer.cyclic = dma_transfer->cyclic;
|
||||||
|
dmac->transfer.dest_addr = dma_transfer->dest_addr;
|
||||||
|
dmac->transfer.src_addr = dma_transfer->src_addr;
|
||||||
|
|
||||||
|
dmac->remaining_size = dma_transfer->size;
|
||||||
|
dmac->next_dest_addr = dma_transfer->dest_addr;
|
||||||
|
dmac->next_src_addr = dma_transfer->src_addr;
|
||||||
|
|
||||||
|
/* If HW cyclic transfer selected and not available, show error */
|
||||||
|
/* HW cyclic transfer available only for MEM to DEV transfers. */
|
||||||
|
if ((!dmac->hw_cyclic) && (dma_transfer->cyclic == CYCLIC)) {
|
||||||
|
printf("Transfer mode not supported!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cyclic transfers not possible for DEV_TO_MEM and MEM_TO_MEM transmissions. */
|
||||||
|
if ((dmac->direction == DMA_DEV_TO_MEM)
|
||||||
|
|| (dmac->direction == DMA_MEM_TO_MEM)) {
|
||||||
|
if (dma_transfer->cyclic == CYCLIC) {
|
||||||
|
printf("Transfer mode not supported!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cyclic transfers set to HW or SW depending on size for MEM to DEV. */
|
||||||
|
if ((dmac->direction == DMA_MEM_TO_DEV) && (dmac->transfer.cyclic == CYCLIC)) {
|
||||||
|
if ((dmac->remaining_size - 1) <= dmac->max_length) {
|
||||||
|
if (dmac->hw_cyclic) {
|
||||||
|
axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS, ®_val);
|
||||||
|
reg_val = reg_val | DMA_CYCLIC;
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, reg_val);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS, ®_val);
|
||||||
|
reg_val = reg_val & ~DMA_CYCLIC;
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, reg_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable DMA if not already enabled. */
|
||||||
|
axi_dmac_read(dmac, AXI_DMAC_REG_CTRL, ®_val);
|
||||||
|
if (!(reg_val & AXI_DMAC_CTRL_ENABLE)) {
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_CTRL, 0x0);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_CTRL, AXI_DMAC_CTRL_ENABLE);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_MASK, 0x0);
|
||||||
|
}
|
||||||
|
|
||||||
|
axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_SUBMIT, ®_val);
|
||||||
|
/* If we don't have a start of transfer then start compute
|
||||||
|
* values and trigger next transfer. */
|
||||||
|
if (!(reg_val & AXI_DMAC_QUEUE_FULL)) {
|
||||||
|
switch (dmac->direction) {
|
||||||
|
case DMA_DEV_TO_MEM:
|
||||||
|
dmac->init_addr = dmac->next_dest_addr;
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, dmac->next_dest_addr);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, 0x0);
|
||||||
|
break;
|
||||||
|
case DMA_MEM_TO_DEV:
|
||||||
|
dmac->init_addr = dmac->next_src_addr;
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, dmac->next_src_addr);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, 0x0);
|
||||||
|
break;
|
||||||
|
case DMA_MEM_TO_MEM:
|
||||||
|
dmac->init_addr = dmac->next_src_addr;
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, dmac->next_dest_addr);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, 0x0);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, dmac->next_src_addr);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, 0x0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1; /* Other directions are not supported yet. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute the burst size. */
|
||||||
|
if (dmac->remaining_size > dmac->max_length) {
|
||||||
|
burst_size = dmac->max_length;
|
||||||
|
} else {
|
||||||
|
burst_size = dmac->remaining_size - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute next address (src or dest, or both, depending on type of transfer). */
|
||||||
|
switch (dmac->direction) {
|
||||||
|
case DMA_DEV_TO_MEM:
|
||||||
|
dmac->next_dest_addr = dmac->next_dest_addr + (burst_size + 1);
|
||||||
|
break;
|
||||||
|
case DMA_MEM_TO_DEV:
|
||||||
|
dmac->next_src_addr = dmac->next_src_addr + (burst_size + 1);
|
||||||
|
break;
|
||||||
|
case DMA_MEM_TO_MEM:
|
||||||
|
dmac->next_dest_addr = dmac->next_dest_addr + (burst_size + 1);
|
||||||
|
dmac->next_src_addr = dmac->next_src_addr + (burst_size + 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute remaining size. */
|
||||||
|
dmac->remaining_size = dmac->remaining_size - (burst_size + 1);
|
||||||
|
|
||||||
|
/* Specify the length of the transfer and trigger transfer. */
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, burst_size);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, 0x0);
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_TRANSFER_SUBMIT, AXI_DMAC_TRANSFER_SUBMIT);
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief Wait for DMA transfer to be completed.
|
||||||
|
*
|
||||||
|
* @param dmac - DMAC istance.
|
||||||
|
* @param timeout_ms - Number of ms to wait for completion of transfer.
|
||||||
|
*
|
||||||
|
* @return 0 for success, -1 in case trasnfer not completed in specified time.
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t axi_dmac_transfer_wait_completion(struct axi_dmac *dmac,
|
||||||
|
uint32_t timeout_ms)
|
||||||
|
{
|
||||||
|
uint32_t timeout = 0;
|
||||||
|
uint32_t reg_val = 0;
|
||||||
|
|
||||||
|
if (dmac->irq_option == IRQ_ENABLED) {
|
||||||
|
while (!dmac->transfer.transfer_done) {
|
||||||
|
timeout++;
|
||||||
|
mdelay(1);
|
||||||
|
if (timeout == timeout_ms) {
|
||||||
|
printf("Error transferring data using DMA.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (dmac->irq_option == IRQ_DISABLED) {
|
||||||
|
axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING, ®_val);
|
||||||
|
while (reg_val != (AXI_DMAC_IRQ_SOT | AXI_DMAC_IRQ_EOT)) {
|
||||||
|
timeout++;
|
||||||
|
mdelay(1);
|
||||||
|
if (timeout == timeout_ms) {
|
||||||
|
printf("Error transferring data using DMA.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING, ®_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief Stop a DMA transfer.
|
||||||
|
*
|
||||||
|
* @param dmac - DMAC istance.
|
||||||
|
*
|
||||||
|
* @return None
|
||||||
|
*******************************************************************************/
|
||||||
|
void axi_dmac_transfer_stop(struct axi_dmac *dmac)
|
||||||
|
{
|
||||||
|
axi_dmac_write(dmac, AXI_DMAC_REG_CTRL, AXI_DMAC_CTRL_DISABLE);
|
||||||
|
}
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file axi_dmac.h
|
||||||
|
* @brief Driver for the Analog Devices AXI-DMAC core.
|
||||||
|
* @author DBogdan ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2018(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef AXI_DMAC_H_
|
||||||
|
#define AXI_DMAC_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/********************** Macros and Constants Definitions **********************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#define AXI_DMAC_REG_IRQ_MASK 0x80
|
||||||
|
#define AXI_DMAC_REG_IRQ_PENDING 0x84
|
||||||
|
#define AXI_DMAC_IRQ_SOT BIT(0)
|
||||||
|
#define AXI_DMAC_IRQ_EOT BIT(1)
|
||||||
|
|
||||||
|
#define AXI_DMAC_REG_INTF_DESC 0x010
|
||||||
|
#define AXI_DMAC_DMA_TYPE_DEST GENMASK(5,4)
|
||||||
|
#define AXI_DMAC_DMA_TYPE_SRC GENMASK(13,12)
|
||||||
|
//Define macro for src and dest
|
||||||
|
|
||||||
|
#define AXI_DMAC_REG_CTRL 0x400
|
||||||
|
#define AXI_DMAC_CTRL_ENABLE BIT(0)
|
||||||
|
#define AXI_DMAC_CTRL_DISABLE 0u
|
||||||
|
#define AXI_DMAC_CTRL_PAUSE BIT(1)
|
||||||
|
|
||||||
|
#define AXI_DMAC_REG_TRANSFER_ID 0x404
|
||||||
|
#define AXI_DMAC_REG_TRANSFER_SUBMIT 0x408
|
||||||
|
#define AXI_DMAC_TRANSFER_SUBMIT BIT(0)
|
||||||
|
#define AXI_DMAC_QUEUE_FULL BIT(0)
|
||||||
|
#define AXI_DMAC_REG_FLAGS 0x40c
|
||||||
|
#define AXI_DMAC_REG_DEST_ADDRESS 0x410
|
||||||
|
#define AXI_DMAC_REG_SRC_ADDRESS 0x414
|
||||||
|
#define AXI_DMAC_REG_X_LENGTH 0x418
|
||||||
|
#define AXI_DMAC_REG_Y_LENGTH 0x41c
|
||||||
|
#define AXI_DMAC_REG_DEST_STRIDE 0x420
|
||||||
|
#define AXI_DMAC_REG_SRC_STRIDE 0x424
|
||||||
|
#define AXI_DMAC_REG_TRANSFER_DONE 0x428
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
enum use_irq {
|
||||||
|
IRQ_DISABLED = 0,
|
||||||
|
IRQ_ENABLED = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum dma_direction {
|
||||||
|
INVALID_DIR = 0,
|
||||||
|
DMA_DEV_TO_MEM = 1,
|
||||||
|
DMA_MEM_TO_DEV = 2,
|
||||||
|
DMA_MEM_TO_MEM = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum dma_flags {
|
||||||
|
DMA_CYCLIC = 1,
|
||||||
|
DMA_LAST = 2,
|
||||||
|
DMA_PARTIAL_REPORTING_EN = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
// Could be transformed to a bool
|
||||||
|
enum cyclic_transfer {
|
||||||
|
NO = 0,
|
||||||
|
CYCLIC = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
struct axi_dma_transfer {
|
||||||
|
uint32_t size;
|
||||||
|
volatile bool transfer_done;
|
||||||
|
enum cyclic_transfer cyclic;
|
||||||
|
uint32_t src_addr;
|
||||||
|
uint32_t dest_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct axi_dmac {
|
||||||
|
const char *name;
|
||||||
|
uint32_t base;
|
||||||
|
enum use_irq irq_option;
|
||||||
|
enum dma_direction direction;
|
||||||
|
bool hw_cyclic;
|
||||||
|
uint32_t max_length;
|
||||||
|
volatile struct axi_dma_transfer transfer;
|
||||||
|
//Current sub-transfer properties
|
||||||
|
uint32_t init_addr;
|
||||||
|
uint32_t remaining_size;
|
||||||
|
uint32_t next_src_addr;
|
||||||
|
uint32_t next_dest_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct axi_dmac_init {
|
||||||
|
const char *name;
|
||||||
|
uint32_t base;
|
||||||
|
enum use_irq irq_option;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
void axi_dmac_dev_to_mem_isr(void *instance);
|
||||||
|
void axi_dmac_mem_to_dev_isr(void *instance);
|
||||||
|
void axi_dmac_mem_to_mem_isr(void *instance);
|
||||||
|
void axi_dmac_write_isr(void *instance);
|
||||||
|
int32_t axi_dmac_read(struct axi_dmac *dmac, uint32_t reg_addr,
|
||||||
|
uint32_t *reg_data);
|
||||||
|
int32_t axi_dmac_write(struct axi_dmac *dmac, uint32_t reg_addr,
|
||||||
|
uint32_t reg_data);
|
||||||
|
int32_t axi_dmac_is_transfer_ready(struct axi_dmac *dmac, bool *rdy);
|
||||||
|
int32_t axi_dmac_init(struct axi_dmac **adc_core,
|
||||||
|
const struct axi_dmac_init *init);
|
||||||
|
int32_t axi_dmac_remove(struct axi_dmac *dmac);
|
||||||
|
int32_t axi_dmac_transfer_start(struct axi_dmac *dmac,
|
||||||
|
struct axi_dma_transfer *dma_transfer);
|
||||||
|
int32_t axi_dmac_transfer_wait_completion(struct axi_dmac *dmac,
|
||||||
|
uint32_t timeout_ms);
|
||||||
|
void axi_dmac_transfer_stop(struct axi_dmac *dmac);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,996 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* @file spi_engine.c
|
||||||
|
* @brief Core implementation of the SPI Engine Driver.
|
||||||
|
* @author Sergiu Cuciurean ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/* In debug mode the printf function used in displaying the messages is causing
|
||||||
|
significant delays */
|
||||||
|
//#define DEBUG_LEVEL 2
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sleep.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include "axi_io.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "spi_engine.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Spi engine platform specific SPI platform ops structure
|
||||||
|
*/
|
||||||
|
const struct spi_platform_ops spi_eng_platform_ops = {
|
||||||
|
.init = &spi_engine_init,
|
||||||
|
.write_and_read = &spi_engine_write_and_read,
|
||||||
|
.write_and_read_3wire = &spi_engine_write_and_read_3wire,
|
||||||
|
.remove = &spi_engine_remove
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Static variables *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Static variable used to sync transfers
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static uint8_t _sync_id = 0x01;
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************** Functions Implementation **************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write SPI Engine's axi registers
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI Engine's parameters
|
||||||
|
* @param reg_addr The address of the SPI Engine's axi register where the data
|
||||||
|
* will be written
|
||||||
|
* @param reg_data Data that will be written
|
||||||
|
* @return int32_t This function allways returns SUCCESS
|
||||||
|
*/
|
||||||
|
int32_t spi_engine_write(struct spi_engine_desc *desc,
|
||||||
|
uint32_t reg_addr,
|
||||||
|
uint32_t reg_data)
|
||||||
|
{
|
||||||
|
axi_io_write(desc->spi_engine_baseaddr, reg_addr, reg_data);
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read SPI Engine's axi registers
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI Engine's parameters
|
||||||
|
* @param reg_addr The address of the SPI Engine's axi register from where the
|
||||||
|
* data where the data will be read
|
||||||
|
* @param reg_data Pointer where the read that will be stored
|
||||||
|
* @return int32_t This function allways returns SUCCESS
|
||||||
|
*/
|
||||||
|
int32_t spi_engine_read(struct spi_engine_desc *desc,
|
||||||
|
uint32_t reg_addr,
|
||||||
|
uint32_t *reg_data)
|
||||||
|
{
|
||||||
|
axi_io_read(desc->spi_engine_baseaddr, reg_addr, reg_data);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set width of the transferred word over SPI
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI interface parameters
|
||||||
|
* @param data_width The desired data width
|
||||||
|
* The supported values are:
|
||||||
|
* - 8
|
||||||
|
* - 16
|
||||||
|
* - 24
|
||||||
|
* - 32
|
||||||
|
*/
|
||||||
|
int32_t spi_engine_set_transfer_width(struct spi_desc *desc,
|
||||||
|
uint8_t data_width)
|
||||||
|
{
|
||||||
|
struct spi_engine_desc *desc_extra;
|
||||||
|
|
||||||
|
desc_extra = desc->extra;
|
||||||
|
|
||||||
|
if (data_width > desc_extra->max_data_width)
|
||||||
|
desc_extra->data_width = desc_extra->max_data_width;
|
||||||
|
else
|
||||||
|
desc_extra->data_width = data_width;
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set SPI engine clock frequency
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI Engine's parameters
|
||||||
|
* @param speed_hz SPI engine transfer speed
|
||||||
|
*/
|
||||||
|
void spi_engine_set_speed(struct spi_desc *desc,
|
||||||
|
uint32_t speed_hz)
|
||||||
|
{
|
||||||
|
struct spi_engine_desc *desc_extra;
|
||||||
|
|
||||||
|
desc_extra = desc->extra;
|
||||||
|
|
||||||
|
desc_extra->clk_div = desc_extra->ref_clk_hz /
|
||||||
|
(2 * speed_hz) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the number of words transferred in a single transaction
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI Engine's parameters
|
||||||
|
* @param bytes_number The number of bytes to be converted
|
||||||
|
* @return uint8_t A number of words in which bytes_number can be grouped
|
||||||
|
*/
|
||||||
|
static uint8_t spi_get_words_number(struct spi_engine_desc *desc,
|
||||||
|
uint8_t bytes_number)
|
||||||
|
{
|
||||||
|
uint8_t xfer_word_len;
|
||||||
|
uint8_t words_number;
|
||||||
|
|
||||||
|
xfer_word_len = desc->data_width / 8;
|
||||||
|
words_number = bytes_number / xfer_word_len;
|
||||||
|
|
||||||
|
if ((bytes_number % xfer_word_len) != 0)
|
||||||
|
words_number++;
|
||||||
|
|
||||||
|
return words_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the word length in bytes
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI Engine's parameters
|
||||||
|
* @return uint8_t Number of bytes that fit in one word
|
||||||
|
*/
|
||||||
|
static uint8_t spi_get_word_length(struct spi_engine_desc *desc)
|
||||||
|
{
|
||||||
|
uint8_t word_length;
|
||||||
|
|
||||||
|
word_length = desc->data_width / 8;
|
||||||
|
|
||||||
|
return word_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compute the prescaler used to set the sleep period.
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI interface parameters
|
||||||
|
* @param sleep_time_ns The amount of time where the transfer hangs
|
||||||
|
* @param sleep_div Clock prescaler
|
||||||
|
* @return int32_t This function allways returns SUCCESS
|
||||||
|
*/
|
||||||
|
static int32_t spi_get_sleep_div(struct spi_desc *desc,
|
||||||
|
uint32_t sleep_time_ns,
|
||||||
|
uint32_t *sleep_div)
|
||||||
|
{
|
||||||
|
struct spi_engine_desc *eng_desc;
|
||||||
|
|
||||||
|
eng_desc = desc->extra;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Engine Wiki:
|
||||||
|
*
|
||||||
|
* The frequency of the SCLK signal is derived from the
|
||||||
|
* module clock frequency using the following formula:
|
||||||
|
* f_sclk = f_clk / ((div + 1) * 2)
|
||||||
|
*/
|
||||||
|
|
||||||
|
*sleep_div = (desc->max_speed_hz / 1000000 * sleep_time_ns / 1000) /
|
||||||
|
((eng_desc->clk_div + 1) * 2) - 1;
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a new commands queue used in a spi transfer
|
||||||
|
*
|
||||||
|
* @param fifo Command buffer, usually used in fifo mode
|
||||||
|
* @param cmd Command with which the buffer will be initiated
|
||||||
|
* @return int32_t Failure if the memory allocation failed
|
||||||
|
*/
|
||||||
|
static int32_t spi_engine_queue_new_cmd(struct spi_engine_cmd_queue **fifo,
|
||||||
|
uint32_t cmd)
|
||||||
|
{
|
||||||
|
struct spi_engine_cmd_queue *local_fifo;
|
||||||
|
|
||||||
|
local_fifo = (spi_engine_cmd_queue*)malloc(sizeof(*local_fifo));
|
||||||
|
|
||||||
|
if(!local_fifo)
|
||||||
|
return FAILURE;
|
||||||
|
|
||||||
|
local_fifo->cmd = cmd;
|
||||||
|
local_fifo->next = NULL;
|
||||||
|
*fifo = local_fifo;
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add a command at the end of an existing queue
|
||||||
|
*
|
||||||
|
* @param fifo Command buffer, usually used in fifo mode
|
||||||
|
* @param cmd Command to be added
|
||||||
|
*/
|
||||||
|
static void spi_engine_queue_add_cmd(struct spi_engine_cmd_queue **fifo,
|
||||||
|
uint32_t cmd)
|
||||||
|
{
|
||||||
|
struct spi_engine_cmd_queue *to_add = NULL;
|
||||||
|
struct spi_engine_cmd_queue *local_fifo;
|
||||||
|
|
||||||
|
local_fifo = *fifo;
|
||||||
|
while (local_fifo->next != NULL) {
|
||||||
|
// Get the last element
|
||||||
|
local_fifo = local_fifo->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new element
|
||||||
|
spi_engine_queue_new_cmd(&to_add, cmd);
|
||||||
|
// Add as the next element
|
||||||
|
local_fifo->next = to_add;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add a command at the beginning of an existing queue
|
||||||
|
*
|
||||||
|
* @param fifo Command buffer, usually used in fifo mode
|
||||||
|
* @param cmd Command to be added
|
||||||
|
*/
|
||||||
|
static void spi_engine_queue_append_cmd(struct spi_engine_cmd_queue **fifo,
|
||||||
|
uint32_t cmd)
|
||||||
|
{
|
||||||
|
struct spi_engine_cmd_queue *to_add = NULL;
|
||||||
|
|
||||||
|
// Create a new element
|
||||||
|
spi_engine_queue_new_cmd(&to_add, cmd);
|
||||||
|
// Interchange the addresses
|
||||||
|
to_add->next = *fifo;
|
||||||
|
*fifo = to_add;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the command from the beginning of the queue
|
||||||
|
*
|
||||||
|
* @param fifo Command buffer, usually used in fifo mode
|
||||||
|
* @param cmd Value of the command that was extracted
|
||||||
|
* @return int32_t Return FAILURE if the queue is empty
|
||||||
|
*/
|
||||||
|
static int32_t spi_engine_queue_get_cmd(struct spi_engine_cmd_queue **fifo,
|
||||||
|
uint32_t *cmd)
|
||||||
|
{
|
||||||
|
struct spi_engine_cmd_queue *local_fifo;
|
||||||
|
|
||||||
|
if (!*fifo)
|
||||||
|
return FAILURE;
|
||||||
|
|
||||||
|
local_fifo = *fifo;
|
||||||
|
*cmd = local_fifo->cmd;
|
||||||
|
if ((*fifo)->next) {
|
||||||
|
*fifo = local_fifo->next;
|
||||||
|
free(local_fifo);
|
||||||
|
} else {
|
||||||
|
free(*fifo);
|
||||||
|
*fifo = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free the memory allocated by a queue
|
||||||
|
*
|
||||||
|
* @param fifo The queue that needs it's memory freed
|
||||||
|
* @return int32_t This function always returns SUCCESS
|
||||||
|
*/
|
||||||
|
static int32_t spi_engine_queue_free(struct spi_engine_cmd_queue **fifo)
|
||||||
|
{
|
||||||
|
if(*fifo && (*fifo)->next)
|
||||||
|
spi_engine_queue_free(&(*fifo)->next);
|
||||||
|
if((*fifo) != NULL) {
|
||||||
|
free(*fifo);
|
||||||
|
*fifo = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write the SPI engine's command fifo
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI Engine's parameters
|
||||||
|
* @param cmd The command that will be written
|
||||||
|
* @return int32_t Returns FAILURE if the the axi transfer failed
|
||||||
|
*/
|
||||||
|
static int32_t spi_engine_write_cmd_reg(struct spi_engine_desc *desc,
|
||||||
|
uint32_t cmd)
|
||||||
|
{
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
/* Check if offload is enabled */
|
||||||
|
if(desc->offload_config & (OFFLOAD_TX_EN | OFFLOAD_RX_EN)) {
|
||||||
|
ret = spi_engine_write(desc,
|
||||||
|
SPI_ENGINE_REG_OFFLOAD_CMD_MEM(0),
|
||||||
|
cmd);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ret = spi_engine_write(desc,
|
||||||
|
SPI_ENGINE_REG_CMD_FIFO,
|
||||||
|
cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write a transfer command to the SPI engine's command fifo
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI Engine's parameters
|
||||||
|
* @param read_write Read/Write operation flag
|
||||||
|
* @param bytes_number Number of bytes to transfer
|
||||||
|
* @return int32_t This function always returns SUCCESS
|
||||||
|
*/
|
||||||
|
static int32_t spi_engine_transfer(struct spi_engine_desc *desc,
|
||||||
|
uint8_t read_write,
|
||||||
|
uint8_t bytes_number)
|
||||||
|
{
|
||||||
|
uint8_t words_number;
|
||||||
|
|
||||||
|
words_number = spi_get_words_number(desc, bytes_number);
|
||||||
|
|
||||||
|
desc->offload_tx_len += words_number;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Engine Wiki:
|
||||||
|
*
|
||||||
|
* https://wiki.analog.com/resources/fpga/peripherals/spi_engine
|
||||||
|
*
|
||||||
|
* The words number is zero based
|
||||||
|
*/
|
||||||
|
|
||||||
|
spi_engine_write_cmd_reg(desc,
|
||||||
|
SPI_ENGINE_CMD_TRANSFER(read_write,
|
||||||
|
words_number - 1));
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Change the state of the chip select port
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI interface parameters
|
||||||
|
* @param assert Chip select state.
|
||||||
|
* The supported values are :
|
||||||
|
* -true (HIGH)
|
||||||
|
* -false (LOW)
|
||||||
|
*/
|
||||||
|
static void spi_engine_set_cs(struct spi_desc *desc,
|
||||||
|
bool assert)
|
||||||
|
{
|
||||||
|
uint8_t mask;
|
||||||
|
struct spi_engine_desc *eng_desc;
|
||||||
|
|
||||||
|
eng_desc = desc->extra;
|
||||||
|
|
||||||
|
mask = 0xFF;
|
||||||
|
/* Switch the state only of the selected chip select */
|
||||||
|
if (!assert)
|
||||||
|
mask ^= BIT(desc->chip_select);
|
||||||
|
|
||||||
|
spi_engine_write_cmd_reg(eng_desc,
|
||||||
|
SPI_ENGINE_CMD_ASSERT(eng_desc->cs_delay,
|
||||||
|
mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add a delay between the engine commands
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI interface parameters
|
||||||
|
* @param sleep_time_ns Number of nanoseconds to sleep between commands
|
||||||
|
*/
|
||||||
|
static void spi_gen_sleep_ns(struct spi_desc *desc,
|
||||||
|
uint32_t sleep_time_ns)
|
||||||
|
{
|
||||||
|
uint32_t sleep_div;
|
||||||
|
struct spi_engine_desc *eng_desc;
|
||||||
|
|
||||||
|
eng_desc = desc->extra;
|
||||||
|
|
||||||
|
spi_get_sleep_div(desc, sleep_time_ns, &sleep_div);
|
||||||
|
|
||||||
|
spi_engine_write_cmd_reg(eng_desc, SPI_ENGINE_CMD_SLEEP(sleep_div));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Spi engine command interpreter
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI interface parameters
|
||||||
|
* @param cmd Command to send to the engine
|
||||||
|
* @return int32_t - SUCCESS if the command is transferred
|
||||||
|
* - FAILURE if the command format is invalid
|
||||||
|
*/
|
||||||
|
static int32_t spi_engine_write_cmd(struct spi_desc *desc,
|
||||||
|
uint32_t cmd)
|
||||||
|
{
|
||||||
|
uint8_t engine_command;
|
||||||
|
uint8_t parameter;
|
||||||
|
uint8_t modifier;
|
||||||
|
struct spi_engine_desc *desc_extra;
|
||||||
|
|
||||||
|
desc_extra = desc->extra;
|
||||||
|
|
||||||
|
engine_command = (cmd >> 12) & 0x0F;
|
||||||
|
modifier = (cmd >> 8) & 0x0F;
|
||||||
|
parameter = cmd & 0xFF;
|
||||||
|
|
||||||
|
switch(engine_command) {
|
||||||
|
case SPI_ENGINE_INST_TRANSFER:
|
||||||
|
spi_engine_transfer(desc_extra, modifier, parameter);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPI_ENGINE_INST_ASSERT:
|
||||||
|
if(parameter == 0xFF) {
|
||||||
|
/* Set the CS HIGH */
|
||||||
|
spi_engine_set_cs(desc, true);
|
||||||
|
} else if(parameter == 0x00) {
|
||||||
|
/* Set the CS LOW */
|
||||||
|
spi_engine_set_cs(desc, false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* The SYNC and SLEEP commands got the same value but different
|
||||||
|
modifier */
|
||||||
|
case SPI_ENGINE_INST_SYNC_SLEEP:
|
||||||
|
/* SYNC instruction */
|
||||||
|
if(modifier == 0x00) {
|
||||||
|
spi_engine_write_cmd_reg(desc_extra, cmd);
|
||||||
|
} else if(modifier == 0x01) {
|
||||||
|
spi_gen_sleep_ns(desc, parameter);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SPI_ENGINE_INST_CONFIG:
|
||||||
|
spi_engine_write_cmd_reg(desc_extra, cmd);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prepare the command queue before sending it to the engine
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI interface parameters
|
||||||
|
* @param msg Structure used to store the transfer messages
|
||||||
|
* @return int32_t This function always returns SUCCESS
|
||||||
|
*/
|
||||||
|
static int32_t spi_engine_compile_message(struct spi_desc *desc,
|
||||||
|
struct spi_engine_msg *msg)
|
||||||
|
{
|
||||||
|
struct spi_engine_desc *desc_extra;
|
||||||
|
|
||||||
|
desc_extra = desc->extra;
|
||||||
|
|
||||||
|
/* Configure the prescaler */
|
||||||
|
spi_engine_queue_append_cmd(&msg->cmds,
|
||||||
|
SPI_ENGINE_CMD_CONFIG(
|
||||||
|
SPI_ENGINE_CMD_REG_CLK_DIV,
|
||||||
|
desc_extra->clk_div));
|
||||||
|
|
||||||
|
/* Set the data transfer length */
|
||||||
|
spi_engine_queue_append_cmd(&msg->cmds,
|
||||||
|
SPI_ENGINE_CMD_CONFIG(
|
||||||
|
SPI_ENGINE_CMD_DATA_TRANSFER_LEN,
|
||||||
|
desc_extra->data_width));
|
||||||
|
/*
|
||||||
|
* Configure the spi mode :
|
||||||
|
* - 3 wire
|
||||||
|
* - CPOL
|
||||||
|
* - CPHA
|
||||||
|
*/
|
||||||
|
spi_engine_queue_append_cmd(&msg->cmds,
|
||||||
|
SPI_ENGINE_CMD_CONFIG(
|
||||||
|
SPI_ENGINE_CMD_REG_CONFIG,
|
||||||
|
desc->mode));
|
||||||
|
|
||||||
|
/* Add a sync command to signal that the transfer has finished */
|
||||||
|
spi_engine_queue_add_cmd(&msg->cmds, SPI_ENGINE_CMD_SYNC(_sync_id));
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initiate a spi transfer (Blocking)
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI interface parameters
|
||||||
|
* @param msg Structure used to store the transfer messages
|
||||||
|
* @return int32_t - SUCCESS if the transfer finished
|
||||||
|
* - FAILURE if the memory allocation failed
|
||||||
|
*/
|
||||||
|
static int32_t spi_engine_transfer_message(struct spi_desc *desc,
|
||||||
|
struct spi_engine_msg *msg)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t data;
|
||||||
|
uint32_t sync_id;
|
||||||
|
bool offload_en;
|
||||||
|
struct spi_engine_desc *desc_extra;
|
||||||
|
|
||||||
|
desc_extra = desc->extra;
|
||||||
|
|
||||||
|
spi_engine_compile_message(desc, msg);
|
||||||
|
|
||||||
|
offload_en = (desc_extra->offload_config & OFFLOAD_TX_EN) |
|
||||||
|
(desc_extra->offload_config & OFFLOAD_RX_EN);
|
||||||
|
|
||||||
|
/* Write the command fifo buffer */
|
||||||
|
while(msg->cmds != NULL) {
|
||||||
|
spi_engine_queue_get_cmd(&msg->cmds, &data);
|
||||||
|
spi_engine_write_cmd(desc, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write a number of tx_length WORDS on the SDO line */
|
||||||
|
if(offload_en) {
|
||||||
|
for(i = 0; i < desc_extra->offload_tx_len; i++)
|
||||||
|
spi_engine_write(desc_extra,
|
||||||
|
SPI_ENGINE_REG_OFFLOAD_SDO_MEM(0),
|
||||||
|
msg->tx_buf[i]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if(msg->tx_buf != NULL){
|
||||||
|
for(i = 0; i < msg->tx_length; i++)
|
||||||
|
spi_engine_write(desc_extra,
|
||||||
|
SPI_ENGINE_REG_SDO_DATA_FIFO,
|
||||||
|
msg->tx_buf[i]);
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
spi_engine_read(desc_extra,
|
||||||
|
SPI_ENGINE_REG_SYNC_ID,
|
||||||
|
&sync_id);
|
||||||
|
}
|
||||||
|
/* Wait for the end sync signal */
|
||||||
|
while(sync_id != _sync_id);
|
||||||
|
_sync_id++;
|
||||||
|
|
||||||
|
/* Read a number of rx_length WORDS from the SDI line and store
|
||||||
|
them */
|
||||||
|
for(i = 0; i < msg->rx_length; i++) {
|
||||||
|
spi_engine_read(desc_extra,
|
||||||
|
SPI_ENGINE_REG_SDI_DATA_FIFO,
|
||||||
|
&data);
|
||||||
|
/* Store the rx data if rx buffer valid, flush sdi_fifo if
|
||||||
|
rx buffer is invalid.*/
|
||||||
|
if(msg->rx_buf != NULL){
|
||||||
|
msg->rx_buf[i] = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the spi engine
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI interface parameters
|
||||||
|
* @param param Structure containing the spi init parameters
|
||||||
|
* @return int32_t - SUCCESS if the transfer finished
|
||||||
|
* - FAILURE if the memory allocation failed
|
||||||
|
*/
|
||||||
|
int32_t spi_engine_init(struct spi_desc **desc,
|
||||||
|
const struct spi_init_param *param)
|
||||||
|
{
|
||||||
|
uint32_t data_width;
|
||||||
|
uint32_t spi_engine_version;
|
||||||
|
struct spi_engine_desc *eng_desc;
|
||||||
|
struct spi_engine_init_param *spi_engine_init;
|
||||||
|
|
||||||
|
if (!param) {
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*desc = malloc(sizeof(**desc));
|
||||||
|
if(! *desc) {
|
||||||
|
free(*desc);
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
eng_desc = (struct spi_engine_desc*)malloc(sizeof(*eng_desc));
|
||||||
|
|
||||||
|
if (!eng_desc)
|
||||||
|
return FAILURE;
|
||||||
|
|
||||||
|
spi_engine_init = param->extra;
|
||||||
|
|
||||||
|
(*desc)->max_speed_hz = param->max_speed_hz;
|
||||||
|
(*desc)->chip_select = param->chip_select;
|
||||||
|
(*desc)->mode = param->mode;
|
||||||
|
(*desc)->extra = eng_desc;
|
||||||
|
|
||||||
|
eng_desc->offload_config = OFFLOAD_DISABLED;
|
||||||
|
eng_desc->spi_engine_baseaddr = spi_engine_init->spi_engine_baseaddr;
|
||||||
|
eng_desc->type = spi_engine_init->type;
|
||||||
|
eng_desc->cs_delay = spi_engine_init->cs_delay;
|
||||||
|
eng_desc->ref_clk_hz = spi_engine_init->ref_clk_hz;
|
||||||
|
eng_desc->clk_div = eng_desc->ref_clk_hz /
|
||||||
|
(2 * param->max_speed_hz) - 1;
|
||||||
|
|
||||||
|
/* Perform a reset */
|
||||||
|
spi_engine_write(eng_desc, SPI_ENGINE_REG_RESET, 0x01);
|
||||||
|
usleep(1000);
|
||||||
|
spi_engine_write(eng_desc, SPI_ENGINE_REG_RESET, 0x00);
|
||||||
|
|
||||||
|
/* Get current data width */
|
||||||
|
spi_engine_read(eng_desc, SPI_ENGINE_REG_DATA_WIDTH, &data_width);
|
||||||
|
eng_desc->max_data_width = data_width;
|
||||||
|
|
||||||
|
spi_engine_set_transfer_width(*desc, spi_engine_init->data_width);
|
||||||
|
|
||||||
|
/* Get spi engine version */
|
||||||
|
spi_engine_read(eng_desc, SPI_ENGINE_REG_VERSION, &spi_engine_version);
|
||||||
|
|
||||||
|
printf("Spi engine v%"PRIu32".%"PRIu32".%"PRIu32" successfully initialized.\n",
|
||||||
|
(spi_engine_version >> 16),
|
||||||
|
((spi_engine_version >> 8) & 0xFF),
|
||||||
|
(spi_engine_version & 0xFF));
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write/read on the spi interface in 4-wire mode (full-duplex)
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI interface parameters
|
||||||
|
* @param data Pointer to data buffer
|
||||||
|
* @param bytes_number Number of bytes to transfer
|
||||||
|
* @return int32_t - SUCCESS if the transfer finished
|
||||||
|
* - FAILURE if the memory allocation or transfer failed
|
||||||
|
*/
|
||||||
|
int32_t spi_engine_write_and_read(struct spi_desc *desc,
|
||||||
|
uint8_t *data,
|
||||||
|
uint16_t bytes_number)
|
||||||
|
{
|
||||||
|
uint8_t word_len;
|
||||||
|
uint8_t words_number;
|
||||||
|
int32_t ret;
|
||||||
|
struct spi_engine_msg msg;
|
||||||
|
struct spi_engine_desc *desc_extra;
|
||||||
|
|
||||||
|
desc_extra = desc->extra;
|
||||||
|
|
||||||
|
/* If we want to access SPI interface and SPI engine offload module was
|
||||||
|
* activated, we need to disable it
|
||||||
|
* This is set in spi_engine_offload_init() */
|
||||||
|
desc_extra->offload_config = OFFLOAD_DISABLED;
|
||||||
|
/* This is set in spi_engine_offload_transfer() */
|
||||||
|
spi_engine_write(desc_extra, SPI_ENGINE_REG_OFFLOAD_CTRL(0), 0);
|
||||||
|
|
||||||
|
words_number = spi_get_words_number(desc_extra, bytes_number);
|
||||||
|
|
||||||
|
msg.cmds = (spi_engine_cmd_queue*)malloc(sizeof(*msg.cmds));
|
||||||
|
if (!msg.cmds)
|
||||||
|
return FAILURE;
|
||||||
|
|
||||||
|
msg.tx_buf =(uint32_t*)calloc(words_number, sizeof(msg.tx_buf[0]));
|
||||||
|
msg.rx_buf =(uint32_t*)calloc(words_number, sizeof(msg.rx_buf[0]));
|
||||||
|
msg.tx_length = words_number;
|
||||||
|
msg.rx_length = words_number;
|
||||||
|
|
||||||
|
/* Get the length of transferred word */
|
||||||
|
word_len = spi_get_word_length(desc_extra);
|
||||||
|
|
||||||
|
/* Make sure the CS is HIGH before starting a transaction */
|
||||||
|
msg.cmds->next = NULL;
|
||||||
|
msg.cmds->cmd = CS_HIGH;
|
||||||
|
// Assert select.
|
||||||
|
spi_engine_queue_add_cmd(&msg.cmds, CS_LOW);
|
||||||
|
// add read/write command
|
||||||
|
spi_engine_queue_add_cmd(&msg.cmds, WRITE_READ(bytes_number));
|
||||||
|
// Disable select.
|
||||||
|
spi_engine_queue_add_cmd(&msg.cmds, CS_HIGH);
|
||||||
|
|
||||||
|
/* Pack the bytes into engine WORDS */
|
||||||
|
for (int i = 0; i < bytes_number; i++)
|
||||||
|
msg.tx_buf[i / word_len] |= data[i] << (desc_extra->data_width-
|
||||||
|
(i % word_len + 1) * 8);
|
||||||
|
|
||||||
|
ret = spi_engine_transfer_message(desc, &msg);
|
||||||
|
|
||||||
|
for (int i = 0; i < bytes_number; i++)
|
||||||
|
data[i] = msg.rx_buf[(i) / word_len] >>
|
||||||
|
(desc_extra->data_width -
|
||||||
|
((i) % word_len + 1) * 8);
|
||||||
|
|
||||||
|
spi_engine_queue_free(&msg.cmds);
|
||||||
|
free(msg.tx_buf);
|
||||||
|
free(msg.rx_buf);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write and read on the spi interface in 3-wire mode (half-duplex)
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI interface parameters
|
||||||
|
* @param data Pointer to data buffer
|
||||||
|
* @param bytes_number Number of bytes to transfer
|
||||||
|
* @return int32_t - SUCCESS if the transfer finished
|
||||||
|
* - FAILURE if the memory allocation or transfer failed
|
||||||
|
*/
|
||||||
|
int32_t spi_engine_write_and_read_3wire(struct spi_desc *desc,
|
||||||
|
uint8_t *write_data,
|
||||||
|
uint8_t *read_data,
|
||||||
|
uint16_t write_bytes_number,
|
||||||
|
uint16_t read_bytes_number)
|
||||||
|
{
|
||||||
|
uint8_t word_len;
|
||||||
|
uint8_t wr_words_number;
|
||||||
|
uint8_t rd_words_number;
|
||||||
|
int32_t ret;
|
||||||
|
struct spi_engine_msg msg;
|
||||||
|
struct spi_engine_desc *desc_extra;
|
||||||
|
|
||||||
|
desc_extra = desc->extra;
|
||||||
|
|
||||||
|
/* If we want to access SPI interface and SPI engine offload module was
|
||||||
|
* activated, we need to disable it
|
||||||
|
* This is set in spi_engine_offload_init() */
|
||||||
|
desc_extra->offload_config = OFFLOAD_DISABLED;
|
||||||
|
/* This is set in spi_engine_offload_transfer() */
|
||||||
|
spi_engine_write(desc_extra, SPI_ENGINE_REG_OFFLOAD_CTRL(0), 0);
|
||||||
|
|
||||||
|
wr_words_number = spi_get_words_number(desc_extra, write_bytes_number);
|
||||||
|
rd_words_number = spi_get_words_number(desc_extra, read_bytes_number);
|
||||||
|
|
||||||
|
msg.cmds = (spi_engine_cmd_queue*)malloc(sizeof(*msg.cmds));
|
||||||
|
if (!msg.cmds)
|
||||||
|
return FAILURE;
|
||||||
|
|
||||||
|
msg.tx_buf =(wr_words_number>0)?(uint32_t*)calloc(wr_words_number, sizeof(msg.tx_buf[0])):NULL;
|
||||||
|
msg.rx_buf =(rd_words_number>0)?(uint32_t*)calloc(rd_words_number, sizeof(msg.rx_buf[0])):NULL;
|
||||||
|
msg.tx_length = wr_words_number;
|
||||||
|
msg.rx_length = rd_words_number;
|
||||||
|
|
||||||
|
/* Get the length of transferred word */
|
||||||
|
word_len = spi_get_word_length(desc_extra);
|
||||||
|
|
||||||
|
/* Make sure the CS is HIGH before starting a transaction */
|
||||||
|
msg.cmds->next = NULL;
|
||||||
|
msg.cmds->cmd = CS_HIGH;
|
||||||
|
|
||||||
|
// Assert select.
|
||||||
|
spi_engine_queue_add_cmd(&msg.cmds, CS_LOW);
|
||||||
|
|
||||||
|
// add read/write command
|
||||||
|
if(write_bytes_number > 0)
|
||||||
|
spi_engine_queue_add_cmd(&msg.cmds, WRITE(write_bytes_number));
|
||||||
|
if(read_bytes_number > 0)
|
||||||
|
spi_engine_queue_add_cmd(&msg.cmds, READ(read_bytes_number));
|
||||||
|
|
||||||
|
// Disable select.
|
||||||
|
spi_engine_queue_add_cmd(&msg.cmds, CS_HIGH);
|
||||||
|
|
||||||
|
/* Pack the bytes into engine WORDS */
|
||||||
|
for (int i = 0; i < write_bytes_number; i++)
|
||||||
|
msg.tx_buf[i / word_len] |= write_data[i] << (desc_extra->data_width-
|
||||||
|
(i % word_len + 1) * 8);
|
||||||
|
|
||||||
|
ret = spi_engine_transfer_message(desc, &msg);
|
||||||
|
|
||||||
|
for (int i = 0; i < read_bytes_number; i++)
|
||||||
|
read_data[i] = msg.rx_buf[(i) / word_len] >>
|
||||||
|
(desc_extra->data_width -
|
||||||
|
((i) % word_len + 1) * 8);
|
||||||
|
|
||||||
|
spi_engine_queue_free(&msg.cmds);
|
||||||
|
free(msg.tx_buf);
|
||||||
|
free(msg.rx_buf);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the SPI engine's offload module
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI interface parameters
|
||||||
|
* @param param Structure containing the offload init parameters
|
||||||
|
* @return int32_t This function always returns SUCCESS
|
||||||
|
*/
|
||||||
|
int32_t spi_engine_offload_init(struct spi_desc *desc,
|
||||||
|
const struct spi_engine_offload_init_param *param)
|
||||||
|
{
|
||||||
|
struct spi_engine_desc *eng_desc;
|
||||||
|
struct axi_dmac_init dmac_init;
|
||||||
|
|
||||||
|
eng_desc = desc->extra;
|
||||||
|
|
||||||
|
eng_desc->offload_config = param->offload_config;
|
||||||
|
|
||||||
|
if(!(param->dma_flags)) {
|
||||||
|
eng_desc->cyclic = CYCLIC;
|
||||||
|
} else {
|
||||||
|
if((*(param->dma_flags)) & DMA_CYCLIC)
|
||||||
|
eng_desc->cyclic = CYCLIC;
|
||||||
|
else
|
||||||
|
eng_desc->cyclic = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(param->offload_config & OFFLOAD_TX_EN) {
|
||||||
|
dmac_init.name = "DAC DMAC";
|
||||||
|
dmac_init.base = param->tx_dma_baseaddr;
|
||||||
|
axi_dmac_init(&eng_desc->offload_tx_dma, &dmac_init);
|
||||||
|
if(!eng_desc->offload_tx_dma)
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
if(param->offload_config & OFFLOAD_RX_EN) {
|
||||||
|
dmac_init.name = "ADC DMAC";
|
||||||
|
dmac_init.base = param->rx_dma_baseaddr;
|
||||||
|
axi_dmac_init(&eng_desc->offload_rx_dma, &dmac_init);
|
||||||
|
if(!eng_desc->offload_rx_dma)
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initiate a SPI transfer in offload mode
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI interface parameters
|
||||||
|
* @param msg Offload message that get's to be transferred
|
||||||
|
* @param no_samples Number of time the messages will be transferred
|
||||||
|
* @return int32_t This function always returns SUCCESS
|
||||||
|
*/
|
||||||
|
int32_t spi_engine_offload_transfer(struct spi_desc *desc,
|
||||||
|
struct spi_engine_offload_message msg,
|
||||||
|
uint32_t no_samples)
|
||||||
|
{
|
||||||
|
struct spi_engine_msg transfer;
|
||||||
|
struct spi_engine_desc *eng_desc;
|
||||||
|
uint32_t i;
|
||||||
|
uint8_t word_length;
|
||||||
|
|
||||||
|
eng_desc = desc->extra;
|
||||||
|
|
||||||
|
/* Check if offload is disabled */
|
||||||
|
if(!((eng_desc->offload_config & OFFLOAD_TX_EN) |
|
||||||
|
(eng_desc->offload_config & OFFLOAD_RX_EN)))
|
||||||
|
return FAILURE;
|
||||||
|
|
||||||
|
spi_engine_write(eng_desc, SPI_ENGINE_REG_OFFLOAD_RESET(0), 1);
|
||||||
|
spi_engine_write(eng_desc, SPI_ENGINE_REG_OFFLOAD_RESET(0), 0);
|
||||||
|
|
||||||
|
eng_desc->offload_tx_len = 0;
|
||||||
|
eng_desc->offload_rx_len = 0;
|
||||||
|
|
||||||
|
transfer.cmds = (spi_engine_cmd_queue*)malloc(sizeof(*transfer.cmds));
|
||||||
|
|
||||||
|
if (!transfer.cmds)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
transfer.tx_buf = msg.commands_data;
|
||||||
|
|
||||||
|
/* Load the commands into the message */
|
||||||
|
transfer.cmds->next = NULL;
|
||||||
|
transfer.cmds->cmd = msg.commands[0];
|
||||||
|
i = 1;
|
||||||
|
while(i < msg.no_commands) {
|
||||||
|
spi_engine_queue_add_cmd(&transfer.cmds, msg.commands[i++]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_engine_transfer_message(desc, &transfer);
|
||||||
|
|
||||||
|
/* Start transfer */
|
||||||
|
spi_engine_write(eng_desc, SPI_ENGINE_REG_OFFLOAD_CTRL(0), 0x0001);
|
||||||
|
|
||||||
|
word_length = spi_get_word_length(eng_desc);
|
||||||
|
if(eng_desc->offload_config & OFFLOAD_TX_EN) {
|
||||||
|
struct axi_dma_transfer tx_transfer = {
|
||||||
|
// Number of bytes to write/read
|
||||||
|
.size = word_length * eng_desc->offload_tx_len * no_samples,
|
||||||
|
// Transfer done flag
|
||||||
|
.transfer_done = 0,
|
||||||
|
// Signal transfer mode
|
||||||
|
.cyclic = eng_desc->cyclic,
|
||||||
|
// Address of data source
|
||||||
|
.src_addr = (uintptr_t)msg.tx_addr,
|
||||||
|
// Address of data destination
|
||||||
|
.dest_addr = 0
|
||||||
|
};
|
||||||
|
axi_dmac_transfer_start(eng_desc->offload_tx_dma, &tx_transfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(eng_desc->offload_config & OFFLOAD_RX_EN) {
|
||||||
|
struct axi_dma_transfer rx_transfer = {
|
||||||
|
// Number of bytes to write/read
|
||||||
|
.size = word_length * eng_desc->offload_tx_len * no_samples,
|
||||||
|
// Transfer done flag
|
||||||
|
.transfer_done = 0,
|
||||||
|
// Signal transfer mode
|
||||||
|
.cyclic = NO,
|
||||||
|
// Address of data source
|
||||||
|
.src_addr = 0,
|
||||||
|
// Address of data destination
|
||||||
|
.dest_addr = (uintptr_t)msg.rx_addr
|
||||||
|
};
|
||||||
|
axi_dmac_transfer_start(eng_desc->offload_rx_dma, &rx_transfer);
|
||||||
|
axi_dmac_transfer_wait_completion(eng_desc->offload_rx_dma, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(1000);
|
||||||
|
|
||||||
|
spi_engine_queue_free(&transfer.cmds);
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free the resources allocated by spi_init().
|
||||||
|
*
|
||||||
|
* @param desc Decriptor containing SPI interface parameters
|
||||||
|
* @return int32_t This function allways returns SUCCESS
|
||||||
|
*/
|
||||||
|
int32_t spi_engine_remove(struct spi_desc *desc)
|
||||||
|
{
|
||||||
|
struct spi_engine_desc *eng_desc;
|
||||||
|
|
||||||
|
eng_desc = desc->extra;
|
||||||
|
|
||||||
|
if(eng_desc->offload_config & OFFLOAD_TX_EN)
|
||||||
|
axi_dmac_remove(eng_desc->offload_tx_dma);
|
||||||
|
if(eng_desc->offload_config & OFFLOAD_RX_EN)
|
||||||
|
axi_dmac_remove(eng_desc->offload_rx_dma);
|
||||||
|
free(desc->extra);
|
||||||
|
free(desc);
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* @file spi_engine.h
|
||||||
|
* @brief Header file of SPI Engine core features.
|
||||||
|
* @author Sergiu Cuciurean ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef SPI_ENGINE_H
|
||||||
|
#define SPI_ENGINE_H
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "spi_engine_private.h"
|
||||||
|
#include "../axi_dmac/axi_dmac.h"
|
||||||
|
#include "../../platform/xilinx_spi.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/********************** Macros and Constants Definitions **********************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#define OFFLOAD_DISABLED 0x00
|
||||||
|
#define OFFLOAD_TX_EN BIT(0)
|
||||||
|
#define OFFLOAD_RX_EN BIT(1)
|
||||||
|
#define OFFLOAD_TX_RX_EN OFFLOAD_TX_EN | OFFLOAD_RX_EN
|
||||||
|
|
||||||
|
#define SPI_ENGINE_MSG_QUEUE_END 0xFFFFFFFF
|
||||||
|
|
||||||
|
/* Spi engine commands */
|
||||||
|
#define WRITE(no_bytes) ((SPI_ENGINE_INST_TRANSFER << 12) |\
|
||||||
|
(SPI_ENGINE_INSTRUCTION_TRANSFER_W << 8) | no_bytes)
|
||||||
|
|
||||||
|
#define READ(no_bytes) ((SPI_ENGINE_INST_TRANSFER << 12) |\
|
||||||
|
(SPI_ENGINE_INSTRUCTION_TRANSFER_R << 8) | no_bytes)
|
||||||
|
|
||||||
|
#define WRITE_READ(no_bytes) ((SPI_ENGINE_INST_TRANSFER << 12) |\
|
||||||
|
(SPI_ENGINE_INSTRUCTION_TRANSFER_RW << 8) | no_bytes)
|
||||||
|
|
||||||
|
#define SLEEP(time) SPI_ENGINE_CMD_SLEEP(time & 0xF)
|
||||||
|
|
||||||
|
/* The delay and chip select parmeters are passed over the engine descriptor
|
||||||
|
and will be used inside the function call */
|
||||||
|
#define CS_HIGH SPI_ENGINE_CMD_ASSERT(0x01, 0xFF)
|
||||||
|
#define CS_LOW SPI_ENGINE_CMD_ASSERT(0x01, 0x00)
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct spi_engine_init_param
|
||||||
|
* @brief Structure containing the init parameters needed by the SPI engine
|
||||||
|
*/
|
||||||
|
struct spi_engine_init_param {
|
||||||
|
/** SPI engine reference clock */
|
||||||
|
uint32_t ref_clk_hz;
|
||||||
|
/** Type of implementation */
|
||||||
|
enum xil_spi_type type;
|
||||||
|
/** Base address where the HDL core is situated */
|
||||||
|
uint32_t spi_engine_baseaddr;
|
||||||
|
/** Delay between the CS toggle and the start of SCLK */
|
||||||
|
uint32_t cs_delay;
|
||||||
|
/** Data with of one SPI transfer ( in bits ) */
|
||||||
|
uint8_t data_width;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct spi_engine_desc
|
||||||
|
* @brief Structure representing an SPI engine device
|
||||||
|
*/
|
||||||
|
struct spi_engine_desc {
|
||||||
|
/** SPI engine reference clock */
|
||||||
|
uint32_t ref_clk_hz;
|
||||||
|
/** Type of implementation */
|
||||||
|
enum xil_spi_type type;
|
||||||
|
/** Pointer to a DMAC used in transmission */
|
||||||
|
struct axi_dmac *offload_tx_dma;
|
||||||
|
/** Pointer to a DMAC used in reception */
|
||||||
|
struct axi_dmac *offload_rx_dma;
|
||||||
|
/** Transfer mode for Tx DMAC */
|
||||||
|
enum cyclic_transfer cyclic;
|
||||||
|
/** Offload's module transfer direction : TX, RX or both */
|
||||||
|
uint8_t offload_config;
|
||||||
|
/** Number of words that the module has to send */
|
||||||
|
uint8_t offload_tx_len;
|
||||||
|
/** Number of words that the module has to receive */
|
||||||
|
uint8_t offload_rx_len;
|
||||||
|
/** Base address where the HDL core is situated */
|
||||||
|
uint32_t spi_engine_baseaddr;
|
||||||
|
/** Base address where the RX DMAC core is situated */
|
||||||
|
uint32_t rx_dma_baseaddr;
|
||||||
|
/** Base address where the TX DMAC core is situated */
|
||||||
|
uint32_t tx_dma_baseaddr;
|
||||||
|
/** Delay between the CS toggle and the start of SCLK */
|
||||||
|
uint8_t cs_delay;
|
||||||
|
/** Clock divider used in transmission delays */
|
||||||
|
uint32_t clk_div;
|
||||||
|
/** Data with of one SPI transfer ( in bits ) */
|
||||||
|
uint8_t data_width;
|
||||||
|
/** The maximum data width supported by the engine */
|
||||||
|
uint8_t max_data_width;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct spi_engine_offload_init_param
|
||||||
|
* @brief Structure containing the init parameters needed by the offload module
|
||||||
|
*/
|
||||||
|
struct spi_engine_offload_init_param {
|
||||||
|
/** Base address where the RX DMAC core is situated */
|
||||||
|
uint32_t rx_dma_baseaddr;
|
||||||
|
/** Base address where the TX DMAC core is situated */
|
||||||
|
uint32_t tx_dma_baseaddr;
|
||||||
|
/** DMAC flags - if not initialized, the default value is DMA_CYCLIC */
|
||||||
|
uint32_t *dma_flags;
|
||||||
|
/** Offload's module transfer direction : TX, RX or both */
|
||||||
|
uint8_t offload_config;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct spi_engine_offload_message
|
||||||
|
* @brief Structure representing an offload message
|
||||||
|
*/
|
||||||
|
struct spi_engine_offload_message {
|
||||||
|
/** Pointer to the SPI engine commands buffer that will be sent.
|
||||||
|
* The available commands can be found at:
|
||||||
|
* https://wiki.analog.com/resources/fpga/peripherals/spi_engine/
|
||||||
|
*/
|
||||||
|
uint32_t *commands;
|
||||||
|
/** Length of the SPI engine commands buffer */
|
||||||
|
uint32_t no_commands;
|
||||||
|
/** Pointer of the data that will be sent over spi */
|
||||||
|
uint32_t *commands_data;
|
||||||
|
/** The address where the data that will be transmitted is situated */
|
||||||
|
uint32_t tx_addr;
|
||||||
|
/** The address where the data that will be received is situated */
|
||||||
|
uint32_t rx_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Spi engine platform specific SPI platform ops structure
|
||||||
|
*/
|
||||||
|
extern const struct spi_platform_ops xil_spi_ops;
|
||||||
|
|
||||||
|
/* Write SPI Engine's axi registers */
|
||||||
|
int32_t spi_engine_write(struct spi_engine_desc *desc,
|
||||||
|
uint32_t reg_addr,
|
||||||
|
uint32_t reg_data);
|
||||||
|
|
||||||
|
/* Read SPI Engine's axi registers */
|
||||||
|
int32_t spi_engine_read(struct spi_engine_desc *desc,
|
||||||
|
uint32_t reg_addr,
|
||||||
|
uint32_t *reg_data);
|
||||||
|
/* Initialize the SPI engine device */
|
||||||
|
int32_t spi_engine_init(struct spi_desc **desc,
|
||||||
|
const struct spi_init_param *param);
|
||||||
|
|
||||||
|
/* Write and read data over SPI using the SPI engine */
|
||||||
|
int32_t spi_engine_write_and_read(struct spi_desc *desc,
|
||||||
|
uint8_t *data,
|
||||||
|
uint16_t bytes_number);
|
||||||
|
|
||||||
|
/* Write and read data over SPI using the SPI engine in 3-wire mode */
|
||||||
|
int32_t spi_engine_write_and_read_3wire(struct spi_desc *desc,
|
||||||
|
uint8_t *write_data,
|
||||||
|
uint8_t *read_data,
|
||||||
|
uint16_t write_bytes_number,
|
||||||
|
uint16_t read_bytes_number);
|
||||||
|
/* Free the resources used by the SPI engine device */
|
||||||
|
int32_t spi_engine_remove(struct spi_desc *desc);
|
||||||
|
|
||||||
|
/* Initialize the SPI engine offload module */
|
||||||
|
int32_t spi_engine_offload_init(struct spi_desc *desc,
|
||||||
|
const struct spi_engine_offload_init_param *param);
|
||||||
|
|
||||||
|
/* Write and read data over SPI using the offload module */
|
||||||
|
int32_t spi_engine_offload_transfer(struct spi_desc *desc,
|
||||||
|
struct spi_engine_offload_message msg,
|
||||||
|
uint32_t no_samples);
|
||||||
|
|
||||||
|
/* Set SPI transfer width */
|
||||||
|
int32_t spi_engine_set_transfer_width(struct spi_desc *desc,
|
||||||
|
uint8_t data_wdith);
|
||||||
|
|
||||||
|
/* Set SPI transfer speed */
|
||||||
|
void spi_engine_set_speed(struct spi_desc *desc,
|
||||||
|
uint32_t speed_hz);
|
||||||
|
|
||||||
|
#endif // SPI_ENGINE_H
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* @file spi_engine_private.h
|
||||||
|
* @brief Private definitions of the SPI Engine
|
||||||
|
* @author Sergiu Cuciurean ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef SPI_ENGINE_PRIVATE_H
|
||||||
|
#define SPI_ENGINE_PRIVATE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "spi.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Spi Engine registers *****************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#define SPI_ENGINE_REG_VERSION 0x00
|
||||||
|
#define SPI_ENGINE_REG_DATA_WIDTH 0x0C
|
||||||
|
#define SPI_ENGINE_REG_RESET 0x40
|
||||||
|
#define SPI_ENGINE_REG_INT_ENABLE 0x80
|
||||||
|
#define SPI_ENGINE_REG_INT_PENDING 0x84
|
||||||
|
#define SPI_ENGINE_REG_INT_SOURCE 0x88
|
||||||
|
#define SPI_ENGINE_REG_SYNC_ID 0xC0
|
||||||
|
#define SPI_ENGINE_REG_CMD_FIFO_ROOM 0xD0
|
||||||
|
#define SPI_ENGINE_REG_SDO_FIFO_ROOM 0xD4
|
||||||
|
#define SPI_ENGINE_REG_SDI_FIFO_LEVEL 0xD8
|
||||||
|
#define SPI_ENGINE_REG_CMD_FIFO 0xE0
|
||||||
|
#define SPI_ENGINE_REG_SDO_DATA_FIFO 0xE4
|
||||||
|
#define SPI_ENGINE_REG_SDI_DATA_FIFO 0xE8
|
||||||
|
#define SPI_ENGINE_REG_SDI_DATA_FIFO_PEEK 0xEC
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Spi Engine register parameters **********************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#define SPI_ENGINE_INST_TRANSFER 0x00
|
||||||
|
#define SPI_ENGINE_INST_ASSERT 0x01
|
||||||
|
#define SPI_ENGINE_INST_CONFIG 0x02
|
||||||
|
#define SPI_ENGINE_INST_SYNC_SLEEP 0x03
|
||||||
|
#define SPI_ENGINE_INST_MISC 0x03
|
||||||
|
#define SPI_ENGINE_CMD_REG_CLK_DIV 0x00
|
||||||
|
#define SPI_ENGINE_CMD_REG_CONFIG 0x01
|
||||||
|
#define SPI_ENGINE_CMD_DATA_TRANSFER_LEN 0x02
|
||||||
|
#define SPI_ENGINE_MISC_SYNC 0x00
|
||||||
|
#define SPI_ENGINE_MISC_SLEEP 0x01
|
||||||
|
#define SPI_ENGINE_SYNC_TRANSFER_BEGIN BIT(1)
|
||||||
|
#define SPI_ENGINE_SYNC_TRANSFER_END BIT(2)
|
||||||
|
#define SPI_ENGINE_INT_CMD_ALMOST_EMPTY BIT(0)
|
||||||
|
#define SPI_ENGINE_INT_SDO_ALMOST_EMPTY BIT(1)
|
||||||
|
#define SPI_ENGINE_INT_SDI_ALMOST_FULL BIT(2)
|
||||||
|
#define SPI_ENGINE_INT_SYNC BIT(3)
|
||||||
|
#define SPI_ENGINE_OFFLOAD_CTRL_ENABLE BIT(0)
|
||||||
|
#define SPI_ENGINE_OFFLOAD_STATUS_ENABLED BIT(0)
|
||||||
|
#define SPI_ENGINE_CONFIG_CPHA BIT(0)
|
||||||
|
#define SPI_ENGINE_CONFIG_CPOL BIT(1)
|
||||||
|
#define SPI_ENGINE_CONFIG_3WIRE BIT(2)
|
||||||
|
#define SPI_ENGINE_VERSION_MAJOR(x) ((x >> 16) & 0xff)
|
||||||
|
#define SPI_ENGINE_VERSION_MINOR(x) ((x >> 8) & 0xff)
|
||||||
|
#define SPI_ENGINE_VERSION_PATCH(x) (x & 0xff)
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/**************************** Spi Engine commands *****************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#define SPI_ENGINE_INSTRUCTION_TRANSFER_W 0x01
|
||||||
|
#define SPI_ENGINE_INSTRUCTION_TRANSFER_R 0x02
|
||||||
|
#define SPI_ENGINE_INSTRUCTION_TRANSFER_RW 0x03
|
||||||
|
|
||||||
|
#define SPI_ENGINE_REG_OFFLOAD_CTRL(x) (0x100 + (0x20 * x))
|
||||||
|
#define SPI_ENGINE_REG_OFFLOAD_STATUS(x) (0x104 + (0x20 * x))
|
||||||
|
#define SPI_ENGINE_REG_OFFLOAD_RESET(x) (0x108 + (0x20 * x))
|
||||||
|
#define SPI_ENGINE_REG_OFFLOAD_CMD_MEM(x) (0x110 + (0x20 * x))
|
||||||
|
#define SPI_ENGINE_REG_OFFLOAD_SDO_MEM(x) (0x114 + (0x20 * x))
|
||||||
|
|
||||||
|
#define SPI_ENGINE_CMD(inst, arg1, arg2) \
|
||||||
|
(((inst & 0x03) << 12) | \
|
||||||
|
((arg1 & 0x03) << 8) | arg2 )
|
||||||
|
|
||||||
|
#define SPI_ENGINE_CMD_TRANSFER(readwrite, n) \
|
||||||
|
SPI_ENGINE_CMD(SPI_ENGINE_INST_TRANSFER, \
|
||||||
|
(readwrite), (n))
|
||||||
|
|
||||||
|
#define SPI_ENGINE_CMD_ASSERT(delay, cs) \
|
||||||
|
SPI_ENGINE_CMD(SPI_ENGINE_INST_ASSERT, \
|
||||||
|
(delay), (cs))
|
||||||
|
|
||||||
|
#define SPI_ENGINE_CMD_CONFIG(reg, val) \
|
||||||
|
SPI_ENGINE_CMD(SPI_ENGINE_INST_CONFIG, \
|
||||||
|
(reg), (val))
|
||||||
|
|
||||||
|
#define SPI_ENGINE_CMD_SLEEP(delay) \
|
||||||
|
SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, \
|
||||||
|
SPI_ENGINE_MISC_SLEEP, \
|
||||||
|
(delay))
|
||||||
|
|
||||||
|
#define SPI_ENGINE_CMD_SYNC(id) \
|
||||||
|
SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, \
|
||||||
|
SPI_ENGINE_MISC_SYNC, \
|
||||||
|
(id))
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
typedef struct spi_engine_cmd_queue {
|
||||||
|
uint32_t cmd;
|
||||||
|
struct spi_engine_cmd_queue *next;
|
||||||
|
} spi_engine_cmd_queue;
|
||||||
|
|
||||||
|
typedef struct spi_engine_msg {
|
||||||
|
uint32_t *tx_buf;
|
||||||
|
uint32_t *rx_buf;
|
||||||
|
uint32_t tx_length;
|
||||||
|
uint32_t rx_length;
|
||||||
|
struct spi_engine_cmd_queue *cmds;
|
||||||
|
} spi_engine_msg;
|
||||||
|
|
||||||
|
#endif // SPI_ENGINE_PRIVATE_H
|
||||||
@@ -0,0 +1,927 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file hmc7044.c
|
||||||
|
* @brief Implementation of HMC7044, HMC7043 Driver.
|
||||||
|
* @author DBogdan ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2018-2020(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "hmc7044.h"
|
||||||
|
#include "../../../include/error.h"
|
||||||
|
#include "../../../include/util.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/********************** Macros and Constants Definitions **********************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#define HMC7044_WRITE (0 << 15)
|
||||||
|
#define HMC7044_READ (1 << 15)
|
||||||
|
#define HMC7044_CNT(x) (((x) - 1) << 13)
|
||||||
|
#define HMC7044_ADDR(x) ((x) & 0xFFF)
|
||||||
|
|
||||||
|
/* Global Control */
|
||||||
|
#define HMC7044_REG_SOFT_RESET 0x0000
|
||||||
|
#define HMC7044_SOFT_RESET BIT(0)
|
||||||
|
|
||||||
|
#define HMC7044_REG_REQ_MODE_0 0x0001
|
||||||
|
#define HMC7044_RESEED_REQ BIT(7)
|
||||||
|
#define HMC7044_HIGH_PERF_DISTRIB_PATH BIT(6)
|
||||||
|
#define HMC7044_HIGH_PERF_PLL_VCO BIT(5)
|
||||||
|
#define HMC7044_FORCE_HOLDOVER BIT(4)
|
||||||
|
#define HMC7044_MUTE_OUT_DIV BIT(3)
|
||||||
|
#define HMC7044_PULSE_GEN_REQ BIT(2)
|
||||||
|
#define HMC7044_RESTART_DIV_FSM BIT(1)
|
||||||
|
#define HMC7044_SLEEP_MODE BIT(0)
|
||||||
|
|
||||||
|
#define HMC7044_REG_REQ_MODE_1 0x0002
|
||||||
|
#define HMC7044_PLL2_AUTOTUNE_TRIG BIT(2)
|
||||||
|
#define HMC7044_SLIP_REQ BIT(1)
|
||||||
|
|
||||||
|
#define HMC7044_REG_EN_CTRL_0 0x0003
|
||||||
|
#define HMC7044_RF_RESEEDER_EN BIT(5)
|
||||||
|
#define HMC7044_VCO_SEL(x) (((x) & 0x3) << 3)
|
||||||
|
#define HMC7044_VCO_EXT 0
|
||||||
|
#define HMC7044_VCO_HIGH 1
|
||||||
|
#define HMC7044_VCO_LOW 2
|
||||||
|
#define HMC7044_SYSREF_TIMER_EN BIT(2)
|
||||||
|
#define HMC7044_PLL2_EN BIT(1)
|
||||||
|
#define HMC7044_PLL1_EN BIT(0)
|
||||||
|
|
||||||
|
#define HMC7044_REG_EN_CTRL_1 0x0004
|
||||||
|
#define HMC7044_SEVEN_PAIRS(x) ((x) & 0x7f)
|
||||||
|
|
||||||
|
#define HMC7044_REG_GLOB_MODE 0x0005
|
||||||
|
#define HMC7044_REF_PATH_EN(x) ((x) & 0xf)
|
||||||
|
#define HMC7044_RFSYNC_EN BIT(4)
|
||||||
|
#define HMC7044_VCOIN_MODE_EN BIT(5)
|
||||||
|
#define HMC7044_SYNC_PIN_MODE(x) (((x) & 0x3) << 6)
|
||||||
|
|
||||||
|
/* PLL1 */
|
||||||
|
#define HMC7044_REG_CLKIN0_BUF_CTRL 0x000A
|
||||||
|
#define HMC7044_REG_CLKIN1_BUF_CTRL 0x000B
|
||||||
|
#define HMC7044_REG_CLKIN2_BUF_CTRL 0x000C
|
||||||
|
#define HMC7044_REG_CLKIN3_BUF_CTRL 0x000D
|
||||||
|
#define HMC7044_REG_OSCIN_BUF_CTRL 0x000E
|
||||||
|
|
||||||
|
#define HMC7044_REG_PLL1_REF_PRIO_CTRL 0x0014
|
||||||
|
|
||||||
|
#define HMC7044_HIGH_Z_EN BIT(4)
|
||||||
|
#define HMC7044_LVPECL_EN BIT(3)
|
||||||
|
#define HMC7044_AC_COUPLING_EN BIT(2)
|
||||||
|
#define HMC7044_100_OHM_EN BIT(1)
|
||||||
|
#define HMC7044_BUF_EN BIT(0)
|
||||||
|
|
||||||
|
#define HMC7044_REG_CLKIN_PRESCALER(x) (0x001C + (x))
|
||||||
|
#define HMC7044_REG_OSCIN_PRESCALER 0x0020
|
||||||
|
|
||||||
|
#define HMC7044_REG_PLL1_R_LSB 0x0021
|
||||||
|
#define HMC7044_R1_LSB(x) ((x) & 0xff)
|
||||||
|
|
||||||
|
#define HMC7044_REG_PLL1_R_MSB 0x0022
|
||||||
|
#define HMC7044_R1_MSB(x) (((x) & 0xff00) >> 8)
|
||||||
|
|
||||||
|
#define HMC7044_REG_PLL1_N_LSB 0x0026
|
||||||
|
#define HMC7044_N1_LSB(x) ((x) & 0xff)
|
||||||
|
|
||||||
|
#define HMC7044_REG_PLL1_N_MSB 0x0027
|
||||||
|
#define HMC7044_N1_MSB(x) (((x) & 0xff00) >> 8)
|
||||||
|
|
||||||
|
#define HMC7044_REG_PLL1_LOCK_DETECT 0x0028
|
||||||
|
#define HMC7044_LOCK_DETECT_SLIP BIT(5)
|
||||||
|
#define HMC7044_LOCK_DETECT_TIMER(x) ((x) & 0x1f)
|
||||||
|
|
||||||
|
/* PLL2 */
|
||||||
|
#define HMC7044_REG_PLL2_FREQ_DOUBLER 0x0032
|
||||||
|
#define HMC7044_PLL2_FREQ_DOUBLER_DIS BIT(0)
|
||||||
|
|
||||||
|
#define HMC7044_REG_PLL2_R_LSB 0x0033
|
||||||
|
#define HMC7044_R2_LSB(x) ((x) & 0xff)
|
||||||
|
|
||||||
|
#define HMC7044_REG_PLL2_R_MSB 0x0034
|
||||||
|
#define HMC7044_R2_MSB(x) (((x) & 0xf00) >> 8)
|
||||||
|
|
||||||
|
#define HMC7044_REG_PLL2_N_LSB 0x0035
|
||||||
|
#define HMC7044_N2_LSB(x) ((x) & 0xff)
|
||||||
|
|
||||||
|
#define HMC7044_REG_PLL2_N_MSB 0x0036
|
||||||
|
#define HMC7044_N2_MSB(x) (((x) & 0xff00) >> 8)
|
||||||
|
|
||||||
|
#define HMC7044_REG_OSCOUT_PATH 0x0039
|
||||||
|
#define HMC7044_REG_OSCOUT_DRIVER_0 0x003A
|
||||||
|
#define HMC7044_REG_OSCOUT_DRIVER_1 0x003B
|
||||||
|
|
||||||
|
/* GPIO/SDATA Control */
|
||||||
|
#define HMC7044_REG_GPI_CTRL(x) (0x0046 + (x))
|
||||||
|
#define HMC7044_REG_GPI_SEL(x) ((x) & 0xf)
|
||||||
|
|
||||||
|
#define HMC7044_REG_GPO_CTRL(x) (0x0050 + (x))
|
||||||
|
#define HMC7044_GPO_SEL(x) (((x) & 0x3f) << 2)
|
||||||
|
#define HMC7044_GPO_MODE BIT(1)
|
||||||
|
#define HMC7044_GPO_EN BIT(0)
|
||||||
|
|
||||||
|
/* SYSREF/SYNC Control */
|
||||||
|
#define HMC7044_REG_PULSE_GEN 0x005A
|
||||||
|
#define HMC7044_PULSE_GEN_MODE(x) ((x) & 0x7)
|
||||||
|
|
||||||
|
#define HMC7044_REG_SYNC 0x005B
|
||||||
|
#define HMC7044_SYNC_RETIME BIT(2)
|
||||||
|
#define HMC7044_SYNC_THROUGH_PLL2 BIT(1)
|
||||||
|
#define HMC7044_SYNC_POLARITY BIT(0)
|
||||||
|
|
||||||
|
#define HMC7044_REG_SYSREF_TIMER_LSB 0x005C
|
||||||
|
#define HMC7044_SYSREF_TIMER_LSB(x) ((x) & 0xff)
|
||||||
|
|
||||||
|
#define HMC7044_REG_SYSREF_TIMER_MSB 0x005D
|
||||||
|
#define HMC7044_SYSREF_TIMER_MSB(x) (((x) & 0xf00) >> 8)
|
||||||
|
|
||||||
|
#define HMC7044_CLK_INPUT_CTRL 0x0064
|
||||||
|
#define HMC7044_LOW_FREQ_INPUT_MODE BIT(0)
|
||||||
|
#define HMC7044_DIV_2_INPUT_MODE BIT(1)
|
||||||
|
|
||||||
|
/* Status and Alarm readback */
|
||||||
|
#define HMC7044_REG_ALARM_READBACK 0x007D
|
||||||
|
#define HMC7044_REG_PLL1_STATUS 0x0082
|
||||||
|
|
||||||
|
#define HMC7044_PLL1_FSM_STATE(x) ((x) & 0x7)
|
||||||
|
#define HMC7044_PLL1_ACTIVE_CLKIN(x) (((x) >> 3) & 0x3)
|
||||||
|
|
||||||
|
#define HMC7044_PLL2_LOCK_DETECT(x) ((x) & 0x1)
|
||||||
|
#define HMC7044_SYSREF_SYNC_STAT(x) ((x) & 0x2)
|
||||||
|
#define HMC7044_CLK_OUT_PH_STATUS(x) ((x) & 0x4)
|
||||||
|
#define HMC7044_PLL1_PLL2_LOCK_STAT(x) ((x) & 0x8)
|
||||||
|
#define HMC7044_SYNC_REQ_STATUS(x) ((x) & 0x10)
|
||||||
|
|
||||||
|
/* Other Controls */
|
||||||
|
#define HMC7044_REG_CLK_OUT_DRV_LOW_PW 0x009F
|
||||||
|
#define HMC7044_REG_CLK_OUT_DRV_HIGH_PW 0x00A0
|
||||||
|
#define HMC7044_REG_PLL1_DELAY 0x00A5
|
||||||
|
#define HMC7044_REG_PLL1_HOLDOVER 0x00A8
|
||||||
|
#define HMC7044_REG_VTUNE_PRESET 0x00B0
|
||||||
|
|
||||||
|
/* Clock Distribution */
|
||||||
|
#define HMC7044_REG_CH_OUT_CRTL_0(ch) (0x00C8 + 0xA * (ch))
|
||||||
|
#define HMC7044_HI_PERF_MODE BIT(7)
|
||||||
|
#define HMC7044_SYNC_EN BIT(6)
|
||||||
|
#define HMC7044_CH_EN BIT(0)
|
||||||
|
#define HMC7044_START_UP_MODE_DYN_EN (BIT(3) | BIT(2))
|
||||||
|
|
||||||
|
#define HMC7044_REG_CH_OUT_CRTL_1(ch) (0x00C9 + 0xA * (ch))
|
||||||
|
#define HMC7044_DIV_LSB(x) ((x) & 0xFF)
|
||||||
|
|
||||||
|
#define HMC7044_REG_CH_OUT_CRTL_2(ch) (0x00CA + 0xA * (ch))
|
||||||
|
#define HMC7044_DIV_MSB(x) (((x) >> 8) & 0xFF)
|
||||||
|
|
||||||
|
#define HMC7044_REG_CH_OUT_CRTL_3(ch) (0x00CB + 0xA * (ch))
|
||||||
|
#define HMC7044_REG_CH_OUT_CRTL_4(ch) (0x00CC + 0xA * (ch))
|
||||||
|
#define HMC7044_REG_CH_OUT_CRTL_5(ch) (0x00CD + 0xA * (ch))
|
||||||
|
#define HMC7044_REG_CH_OUT_CRTL_6(ch) (0x00CE + 0xA * (ch))
|
||||||
|
#define HMC7044_REG_CH_OUT_CRTL_7(ch) (0x00CF + 0xA * (ch))
|
||||||
|
|
||||||
|
#define HMC7044_REG_CH_OUT_CRTL_8(ch) (0x00D0 + 0xA * (ch))
|
||||||
|
#define HMC7044_DRIVER_MODE(x) (((x) & 0x3) << 3)
|
||||||
|
#define HMC7044_DRIVER_Z_MODE(x) (((x) & 0x3) << 0)
|
||||||
|
#define HMC7044_DYN_DRIVER_EN BIT(5)
|
||||||
|
#define HMC7044_FORCE_MUTE_EN BIT(7)
|
||||||
|
|
||||||
|
#define HMC7044_NUM_CHAN 14
|
||||||
|
|
||||||
|
#define HMC7044_LOW_VCO_MIN 2150000
|
||||||
|
#define HMC7044_LOW_VCO_MAX 2880000
|
||||||
|
#define HMC7044_HIGH_VCO_MIN 2650000
|
||||||
|
#define HMC7044_HIGH_VCO_MAX 3200000
|
||||||
|
|
||||||
|
#define HMC7044_RECOMM_LCM_MIN 30000
|
||||||
|
#define HMC7044_RECOMM_LCM_MAX 70000
|
||||||
|
#define HMC7044_RECOMM_FPD1 10000
|
||||||
|
|
||||||
|
#define HMC7044_R1_MAX 65535
|
||||||
|
#define HMC7044_N1_MAX 65535
|
||||||
|
|
||||||
|
#define HMC7044_R2_MIN 1
|
||||||
|
#define HMC7044_R2_MAX 4095
|
||||||
|
#define HMC7044_N2_MIN 8
|
||||||
|
#define HMC7044_N2_MAX 65535
|
||||||
|
|
||||||
|
#define HMC7044_OUT_DIV_MIN 1
|
||||||
|
#define HMC7044_OUT_DIV_MAX 4094
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************** Functions Implementation **************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SPI register write to device.
|
||||||
|
* @param dev - The device structure.
|
||||||
|
* @param reg - The register address.
|
||||||
|
* @param val - The register data.
|
||||||
|
* @return SUCCESS in case of success, negative error code otherwise.
|
||||||
|
*/
|
||||||
|
int32_t hmc7044_write(struct hmc7044_dev *dev,
|
||||||
|
uint16_t reg,
|
||||||
|
uint8_t val)
|
||||||
|
{
|
||||||
|
uint8_t buf[3];
|
||||||
|
uint16_t cmd;
|
||||||
|
|
||||||
|
cmd = HMC7044_WRITE | HMC7044_CNT(1) | HMC7044_ADDR(reg);
|
||||||
|
buf[0] = cmd >> 8;
|
||||||
|
buf[1] = cmd & 0xFF;
|
||||||
|
buf[2] = val;
|
||||||
|
return spi_write_and_read_3wire(dev->spi_desc, buf, NULL,
|
||||||
|
ARRAY_SIZE(buf), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SPI register read from device.
|
||||||
|
* @param dev - The device structure.
|
||||||
|
* @param reg - The register address.
|
||||||
|
* @param val - The register data.
|
||||||
|
* @return SUCCESS in case of success, negative error code otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int32_t hmc7044_read(struct hmc7044_dev *dev, uint16_t reg, uint8_t *val)
|
||||||
|
{
|
||||||
|
uint8_t wr_buf[2];
|
||||||
|
uint8_t rd_data[1];
|
||||||
|
uint16_t cmd;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
cmd = HMC7044_READ | HMC7044_CNT(1) | HMC7044_ADDR(reg);
|
||||||
|
wr_buf[0] = cmd >> 8;
|
||||||
|
wr_buf[1] = cmd & 0xFF;
|
||||||
|
|
||||||
|
ret = spi_write_and_read_3wire(dev->spi_desc, wr_buf, rd_data,
|
||||||
|
ARRAY_SIZE(wr_buf), ARRAY_SIZE(rd_data));
|
||||||
|
if (ret != SUCCESS)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*val = rd_data[0];
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the output channel divider.
|
||||||
|
* @param rate - The desired rate.
|
||||||
|
* @param parent_rate - The parent rate.
|
||||||
|
* @return The output divider.
|
||||||
|
*/
|
||||||
|
uint32_t hmc7044_calc_out_div(uint32_t rate,
|
||||||
|
uint32_t parent_rate)
|
||||||
|
{
|
||||||
|
uint32_t div;
|
||||||
|
|
||||||
|
div = DIV_ROUND_CLOSEST(parent_rate, rate);
|
||||||
|
|
||||||
|
/* Supported odd divide ratios are 1, 3, and 5 */
|
||||||
|
if ((div != 1) && (div != 3) && (div != 5) && (div % 2))
|
||||||
|
div = DIV_ROUND_CLOSEST(parent_rate, rate * 2) * 2;
|
||||||
|
|
||||||
|
div = clamp_t(unsigned int,
|
||||||
|
div,
|
||||||
|
HMC7044_OUT_DIV_MIN,
|
||||||
|
HMC7044_OUT_DIV_MAX);
|
||||||
|
|
||||||
|
return div;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recalculate rate corresponding to a channel.
|
||||||
|
* @param dev - The device structure.
|
||||||
|
* @param chan_num - Channel number.
|
||||||
|
* @param rate - Channel rate.
|
||||||
|
* @return SUCCESS in case of success, negative error code otherwise.
|
||||||
|
*/
|
||||||
|
int32_t hmc7044_clk_recalc_rate(struct hmc7044_dev *dev, uint32_t chan_num,
|
||||||
|
uint64_t *rate)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct hmc7044_chan_spec *chan = NULL;
|
||||||
|
|
||||||
|
/* Find the reqested channel number */
|
||||||
|
for (i = 0; i < dev->num_channels; i++) {
|
||||||
|
if (dev->channels[i].num == chan_num) {
|
||||||
|
chan = &dev->channels[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan == NULL )
|
||||||
|
return FAILURE;
|
||||||
|
|
||||||
|
*rate = dev->pll2_freq / chan->divider;
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate closest possible rate
|
||||||
|
* @param dev - The device structure
|
||||||
|
* @param rate - The desired rate.
|
||||||
|
* @param rounded_rate - The closest possible rate of desired rate.
|
||||||
|
* @return SUCCESS in case of success, negative error code otherwise.
|
||||||
|
*/
|
||||||
|
int32_t hmc7044_clk_round_rate(struct hmc7044_dev *dev, uint32_t rate,
|
||||||
|
uint64_t *rounded_rate)
|
||||||
|
{
|
||||||
|
uint32_t div = hmc7044_calc_out_div(rate, dev->pll2_freq);
|
||||||
|
|
||||||
|
*rounded_rate = DIV_ROUND_CLOSEST(dev->pll2_freq, div);
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set channel rate.
|
||||||
|
* @param dev - The device structure.
|
||||||
|
* @param chan_num - Channel number.
|
||||||
|
* @param rate - Channel rate.
|
||||||
|
* @return SUCCESS in case of success, negative error code otherwise.
|
||||||
|
*/
|
||||||
|
int32_t hmc7044_clk_set_rate(struct hmc7044_dev *dev, uint32_t chan_num,
|
||||||
|
uint64_t rate)
|
||||||
|
{
|
||||||
|
uint32_t div;
|
||||||
|
int32_t ret;
|
||||||
|
int i;
|
||||||
|
struct hmc7044_chan_spec *chan = NULL;
|
||||||
|
|
||||||
|
/* Find the reqested channel number */
|
||||||
|
for (i = 0; i < dev->num_channels; i++) {
|
||||||
|
if (dev->channels[i].num == chan_num) {
|
||||||
|
chan = &dev->channels[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan == NULL )
|
||||||
|
return FAILURE;
|
||||||
|
|
||||||
|
div = hmc7044_calc_out_div(rate, dev->pll2_freq);
|
||||||
|
chan->divider = div;
|
||||||
|
|
||||||
|
ret = hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_1(chan->num),
|
||||||
|
HMC7044_DIV_LSB(div));
|
||||||
|
if(ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_2(chan->num),
|
||||||
|
HMC7044_DIV_MSB(div));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the device.
|
||||||
|
* @param dev - The device structure.
|
||||||
|
* @return SUCCESS in case of success, negative error code otherwise.
|
||||||
|
*/
|
||||||
|
static int32_t hmc7044_setup(struct hmc7044_dev *dev)
|
||||||
|
{
|
||||||
|
struct hmc7044_chan_spec *chan;
|
||||||
|
bool high_vco_en;
|
||||||
|
bool pll2_freq_doubler_en;
|
||||||
|
uint32_t vcxo_freq, pll2_freq;
|
||||||
|
uint32_t clkin_freq[4];
|
||||||
|
uint32_t lcm_freq;
|
||||||
|
uint32_t in_prescaler[5];
|
||||||
|
uint32_t pll1_lock_detect;
|
||||||
|
uint32_t n1, r1;
|
||||||
|
uint32_t pfd1_freq;
|
||||||
|
uint32_t vco_limit;
|
||||||
|
uint32_t n2[2], r2[2];
|
||||||
|
uint32_t i, ref_en = 0;
|
||||||
|
|
||||||
|
vcxo_freq = dev->vcxo_freq / 1000;
|
||||||
|
pll2_freq = dev->pll2_freq / 1000;
|
||||||
|
|
||||||
|
lcm_freq = vcxo_freq;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(clkin_freq); i++) {
|
||||||
|
if (dev->clkin_freq_ccf[i])
|
||||||
|
clkin_freq[i] = dev->clkin_freq_ccf[i] / 1000;
|
||||||
|
else
|
||||||
|
clkin_freq[i] = dev->clkin_freq[i] / 1000;
|
||||||
|
|
||||||
|
if (clkin_freq[i]) {
|
||||||
|
lcm_freq = greatest_common_divisor(clkin_freq[i], lcm_freq);
|
||||||
|
ref_en |= BIT(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (lcm_freq > HMC7044_RECOMM_LCM_MAX)
|
||||||
|
lcm_freq /= 2;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(clkin_freq); i++) {
|
||||||
|
if (clkin_freq[i])
|
||||||
|
in_prescaler[i] = clkin_freq[i] / lcm_freq;
|
||||||
|
else
|
||||||
|
in_prescaler[i] = 1;
|
||||||
|
}
|
||||||
|
in_prescaler[4] = vcxo_freq / lcm_freq;
|
||||||
|
|
||||||
|
pll1_lock_detect = log_base_2((lcm_freq * 4000) / dev->pll1_loop_bw);
|
||||||
|
|
||||||
|
/* fVCXO / N1 = fLCM / R1 */
|
||||||
|
rational_best_approximation(vcxo_freq, lcm_freq,
|
||||||
|
HMC7044_N1_MAX, HMC7044_R1_MAX,
|
||||||
|
&n1, &r1);
|
||||||
|
|
||||||
|
pfd1_freq = vcxo_freq / n1;
|
||||||
|
while ((pfd1_freq > HMC7044_RECOMM_FPD1) &&
|
||||||
|
(n1 <= HMC7044_N1_MAX / 2) &&
|
||||||
|
(r1 <= HMC7044_R1_MAX / 2)) {
|
||||||
|
pfd1_freq /= 2;
|
||||||
|
n1 *= 2;
|
||||||
|
r1 *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->pll1_pfd = pfd1_freq;
|
||||||
|
|
||||||
|
if (pll2_freq < HMC7044_LOW_VCO_MIN ||
|
||||||
|
pll2_freq > HMC7044_HIGH_VCO_MAX)
|
||||||
|
return FAILURE;
|
||||||
|
|
||||||
|
vco_limit = (HMC7044_LOW_VCO_MAX + HMC7044_HIGH_VCO_MIN) / 2;
|
||||||
|
if (pll2_freq >= vco_limit)
|
||||||
|
high_vco_en = true;
|
||||||
|
else
|
||||||
|
high_vco_en = false;
|
||||||
|
|
||||||
|
/* fVCO / N2 = fVCXO * doubler / R2 */
|
||||||
|
pll2_freq_doubler_en = true;
|
||||||
|
rational_best_approximation(pll2_freq, vcxo_freq * 2,
|
||||||
|
HMC7044_N2_MAX, HMC7044_R2_MAX,
|
||||||
|
&n2[0], &r2[0]);
|
||||||
|
|
||||||
|
if (pll2_freq != vcxo_freq * n2[0] / r2[0]) {
|
||||||
|
rational_best_approximation(pll2_freq, vcxo_freq,
|
||||||
|
HMC7044_N2_MAX, HMC7044_R2_MAX,
|
||||||
|
&n2[1], &r2[1]);
|
||||||
|
|
||||||
|
if (abs((int)pll2_freq - (int)(vcxo_freq * 2 * n2[0] / r2[0])) >
|
||||||
|
abs((int)pll2_freq - (int)(vcxo_freq * n2[1] / r2[1]))) {
|
||||||
|
n2[0] = n2[1];
|
||||||
|
r2[0] = r2[1];
|
||||||
|
pll2_freq_doubler_en = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((n2[0] < HMC7044_N2_MIN) && (r2[0] <= HMC7044_R2_MAX / 2)) {
|
||||||
|
n2[0] *= 2;
|
||||||
|
r2[0] *= 2;
|
||||||
|
}
|
||||||
|
if (n2[0] < HMC7044_N2_MIN)
|
||||||
|
return -FAILURE;
|
||||||
|
|
||||||
|
/* Resets all registers to default values */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_SOFT_RESET, HMC7044_SOFT_RESET);
|
||||||
|
mdelay(10);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_SOFT_RESET, 0);
|
||||||
|
mdelay(10);
|
||||||
|
|
||||||
|
/* Disable all channels */
|
||||||
|
for (i = 0; i < HMC7044_NUM_CHAN; i++)
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_0(i), 0);
|
||||||
|
|
||||||
|
/* Load the configuration updates (provided by Analog Devices) */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CLK_OUT_DRV_LOW_PW, 0x4d);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CLK_OUT_DRV_HIGH_PW, 0xdf);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_PLL1_DELAY, 0x06);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_PLL1_HOLDOVER, 0x06);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_VTUNE_PRESET, 0x04);
|
||||||
|
|
||||||
|
uint8_t rd_back;
|
||||||
|
hmc7044_read(dev, HMC7044_REG_CLK_OUT_DRV_LOW_PW, &rd_back);
|
||||||
|
hmc7044_read(dev, HMC7044_REG_CLK_OUT_DRV_HIGH_PW, &rd_back);
|
||||||
|
hmc7044_read(dev, HMC7044_REG_PLL1_DELAY, &rd_back);
|
||||||
|
hmc7044_read(dev, HMC7044_REG_PLL1_HOLDOVER, &rd_back);
|
||||||
|
hmc7044_read(dev, HMC7044_REG_VTUNE_PRESET, &rd_back);
|
||||||
|
|
||||||
|
hmc7044_write(dev, HMC7044_REG_GLOB_MODE,
|
||||||
|
HMC7044_SYNC_PIN_MODE(dev->sync_pin_mode) |
|
||||||
|
(dev->clkin0_rfsync_en ? HMC7044_RFSYNC_EN : 0) |
|
||||||
|
(dev->clkin1_vcoin_en ? HMC7044_VCOIN_MODE_EN : 0) |
|
||||||
|
HMC7044_REF_PATH_EN(ref_en));
|
||||||
|
|
||||||
|
/* Program PLL2 */
|
||||||
|
|
||||||
|
/* Select the VCO range */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_EN_CTRL_0,
|
||||||
|
(dev->rf_reseeder_en ? HMC7044_RF_RESEEDER_EN : 0) |
|
||||||
|
HMC7044_VCO_SEL(high_vco_en ?
|
||||||
|
HMC7044_VCO_HIGH :
|
||||||
|
HMC7044_VCO_LOW) |
|
||||||
|
HMC7044_SYSREF_TIMER_EN | HMC7044_PLL2_EN |
|
||||||
|
HMC7044_PLL1_EN);
|
||||||
|
|
||||||
|
/* Program the dividers */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_PLL2_R_LSB,
|
||||||
|
HMC7044_R2_LSB(r2[0]));
|
||||||
|
hmc7044_write(dev, HMC7044_REG_PLL2_R_MSB,
|
||||||
|
HMC7044_R2_MSB(r2[0]));
|
||||||
|
hmc7044_write(dev, HMC7044_REG_PLL2_N_LSB,
|
||||||
|
HMC7044_N2_LSB(n2[0]));
|
||||||
|
hmc7044_write(dev, HMC7044_REG_PLL2_N_MSB,
|
||||||
|
HMC7044_N2_MSB(n2[0]));
|
||||||
|
|
||||||
|
/* Program the reference doubler */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_PLL2_FREQ_DOUBLER,
|
||||||
|
pll2_freq_doubler_en ? 0 : HMC7044_PLL2_FREQ_DOUBLER_DIS);
|
||||||
|
|
||||||
|
/* Program PLL1 */
|
||||||
|
|
||||||
|
/* Set the lock detect timer threshold */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_PLL1_LOCK_DETECT,
|
||||||
|
HMC7044_LOCK_DETECT_TIMER(pll1_lock_detect));
|
||||||
|
|
||||||
|
/* Set the LCM */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(clkin_freq); i++) {
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CLKIN_PRESCALER(i),
|
||||||
|
in_prescaler[i]);
|
||||||
|
}
|
||||||
|
hmc7044_write(dev, HMC7044_REG_OSCIN_PRESCALER,
|
||||||
|
in_prescaler[4]);
|
||||||
|
|
||||||
|
/* Program the dividers */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_PLL1_R_LSB,
|
||||||
|
HMC7044_R2_LSB(r1));
|
||||||
|
hmc7044_write(dev, HMC7044_REG_PLL1_R_MSB,
|
||||||
|
HMC7044_R2_MSB(r1));
|
||||||
|
hmc7044_write(dev, HMC7044_REG_PLL1_N_LSB,
|
||||||
|
HMC7044_N2_LSB(n1));
|
||||||
|
hmc7044_write(dev, HMC7044_REG_PLL1_N_MSB,
|
||||||
|
HMC7044_N2_MSB(n1));
|
||||||
|
|
||||||
|
hmc7044_write(dev, HMC7044_REG_PLL1_REF_PRIO_CTRL,
|
||||||
|
dev->pll1_ref_prio_ctrl);
|
||||||
|
|
||||||
|
/* Program the SYSREF timer */
|
||||||
|
|
||||||
|
/* Set the divide ratio */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_SYSREF_TIMER_LSB,
|
||||||
|
HMC7044_SYSREF_TIMER_LSB(dev->sysref_timer_div));
|
||||||
|
hmc7044_write(dev, HMC7044_REG_SYSREF_TIMER_MSB,
|
||||||
|
HMC7044_SYSREF_TIMER_MSB(dev->sysref_timer_div));
|
||||||
|
|
||||||
|
/* Set the pulse generator mode configuration */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_PULSE_GEN,
|
||||||
|
HMC7044_PULSE_GEN_MODE(dev->pulse_gen_mode));
|
||||||
|
|
||||||
|
/* Enable the input buffers */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CLKIN0_BUF_CTRL,
|
||||||
|
dev->in_buf_mode[0]);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CLKIN1_BUF_CTRL,
|
||||||
|
dev->in_buf_mode[1]);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CLKIN2_BUF_CTRL,
|
||||||
|
dev->in_buf_mode[2]);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CLKIN3_BUF_CTRL,
|
||||||
|
dev->in_buf_mode[3]);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_OSCIN_BUF_CTRL,
|
||||||
|
dev->in_buf_mode[4]);
|
||||||
|
|
||||||
|
/* Set GPIOs */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(dev->gpi_ctrl); i++) {
|
||||||
|
hmc7044_write(dev, HMC7044_REG_GPI_CTRL(i),
|
||||||
|
dev->gpi_ctrl[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(dev->gpo_ctrl); i++) {
|
||||||
|
hmc7044_write(dev, HMC7044_REG_GPO_CTRL(i),
|
||||||
|
dev->gpo_ctrl[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mdelay(10);
|
||||||
|
|
||||||
|
/* Program the output channels */
|
||||||
|
for (i = 0; i < dev->num_channels; i++) {
|
||||||
|
chan = &dev->channels[i];
|
||||||
|
if (chan->num >= HMC7044_NUM_CHAN || chan->disable)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_1(chan->num),
|
||||||
|
HMC7044_DIV_LSB(chan->divider));
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_2(chan->num),
|
||||||
|
HMC7044_DIV_MSB(chan->divider));
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_8(chan->num),
|
||||||
|
HMC7044_DRIVER_MODE(chan->driver_mode) |
|
||||||
|
HMC7044_DRIVER_Z_MODE(chan->driver_impedance) |
|
||||||
|
(chan->dynamic_driver_enable ?
|
||||||
|
HMC7044_DYN_DRIVER_EN : 0) |
|
||||||
|
(chan->force_mute_enable ?
|
||||||
|
HMC7044_FORCE_MUTE_EN : 0));
|
||||||
|
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_3(chan->num),
|
||||||
|
chan->fine_delay & 0x1F);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_4(chan->num),
|
||||||
|
chan->coarse_delay & 0x1F);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_7(chan->num),
|
||||||
|
chan->out_mux_mode & 0x3);
|
||||||
|
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_0(chan->num),
|
||||||
|
(chan->start_up_mode_dynamic_enable ?
|
||||||
|
HMC7044_START_UP_MODE_DYN_EN : 0) |
|
||||||
|
(chan->output_control0_rb4_enable ? BIT(4) : 0) |
|
||||||
|
(chan->high_performance_mode_dis ?
|
||||||
|
0 : HMC7044_HI_PERF_MODE) | HMC7044_SYNC_EN |
|
||||||
|
HMC7044_CH_EN);
|
||||||
|
}
|
||||||
|
mdelay(10);
|
||||||
|
|
||||||
|
/* Do a restart to reset the system and initiate calibration */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_REQ_MODE_0,
|
||||||
|
HMC7044_RESTART_DIV_FSM);
|
||||||
|
mdelay(1);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_REQ_MODE_0,
|
||||||
|
(dev->high_performance_mode_clock_dist_en ?
|
||||||
|
HMC7044_HIGH_PERF_DISTRIB_PATH : 0));
|
||||||
|
mdelay(1);
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the device.
|
||||||
|
* @param dev - The device structure.
|
||||||
|
* @return SUCCESS in case of success, negative error code otherwise.
|
||||||
|
*/
|
||||||
|
static int32_t hmc7043_setup(struct hmc7044_dev *dev)
|
||||||
|
{
|
||||||
|
struct hmc7044_chan_spec *chan;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
if (dev->clkin_freq_ccf[0])
|
||||||
|
dev->pll2_freq = dev->clkin_freq_ccf[0];
|
||||||
|
else
|
||||||
|
dev->pll2_freq = dev->clkin_freq[0];
|
||||||
|
|
||||||
|
if (!dev->pll2_freq) {
|
||||||
|
printf("%s: Failed to get valid parent rate\n", __func__);
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resets all registers to default values */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_SOFT_RESET, HMC7044_SOFT_RESET);
|
||||||
|
mdelay(10);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_SOFT_RESET, 0);
|
||||||
|
mdelay(10);
|
||||||
|
|
||||||
|
/* Load the configuration updates (provided by Analog Devices) */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CLK_OUT_DRV_LOW_PW, 0x4d);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CLK_OUT_DRV_HIGH_PW, 0xdf);
|
||||||
|
|
||||||
|
/* Disable all channels */
|
||||||
|
for (i = 0; i < HMC7044_NUM_CHAN; i++)
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_0(i), 0);
|
||||||
|
|
||||||
|
if (dev->pll2_freq < 1000000000U)
|
||||||
|
hmc7044_write(dev, HMC7044_CLK_INPUT_CTRL,
|
||||||
|
HMC7044_LOW_FREQ_INPUT_MODE);
|
||||||
|
|
||||||
|
hmc7044_write(dev, HMC7044_REG_EN_CTRL_0,
|
||||||
|
(dev->rf_reseeder_en ? HMC7044_RF_RESEEDER_EN : 0) |
|
||||||
|
HMC7044_SYSREF_TIMER_EN);
|
||||||
|
|
||||||
|
/* Program the SYSREF timer */
|
||||||
|
|
||||||
|
/* Set the divide ratio */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_SYSREF_TIMER_LSB,
|
||||||
|
HMC7044_SYSREF_TIMER_LSB(dev->sysref_timer_div));
|
||||||
|
hmc7044_write(dev, HMC7044_REG_SYSREF_TIMER_MSB,
|
||||||
|
HMC7044_SYSREF_TIMER_MSB(dev->sysref_timer_div));
|
||||||
|
|
||||||
|
/* Set the pulse generator mode configuration */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_PULSE_GEN,
|
||||||
|
HMC7044_PULSE_GEN_MODE(dev->pulse_gen_mode));
|
||||||
|
|
||||||
|
/* Enable the input buffers */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CLKIN0_BUF_CTRL,
|
||||||
|
dev->in_buf_mode[0]);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CLKIN1_BUF_CTRL,
|
||||||
|
dev->in_buf_mode[1]);
|
||||||
|
|
||||||
|
/* Set GPIOs */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_GPI_CTRL(0),
|
||||||
|
dev->gpi_ctrl[0]);
|
||||||
|
|
||||||
|
hmc7044_write(dev, HMC7044_REG_GPO_CTRL(0),
|
||||||
|
dev->gpo_ctrl[0]);
|
||||||
|
|
||||||
|
/* Program the output channels */
|
||||||
|
for (i = 0; i < dev->num_channels; i++) {
|
||||||
|
chan = &dev->channels[i];
|
||||||
|
|
||||||
|
if (chan->num >= HMC7044_NUM_CHAN || chan->disable)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_1(chan->num),
|
||||||
|
HMC7044_DIV_LSB(chan->divider));
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_2(chan->num),
|
||||||
|
HMC7044_DIV_MSB(chan->divider));
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_8(chan->num),
|
||||||
|
HMC7044_DRIVER_MODE(chan->driver_mode) |
|
||||||
|
HMC7044_DRIVER_Z_MODE(chan->driver_impedance) |
|
||||||
|
(chan->dynamic_driver_enable ?
|
||||||
|
HMC7044_DYN_DRIVER_EN : 0) |
|
||||||
|
(chan->force_mute_enable ?
|
||||||
|
HMC7044_FORCE_MUTE_EN : 0));
|
||||||
|
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_3(chan->num),
|
||||||
|
chan->fine_delay & 0x1F);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_4(chan->num),
|
||||||
|
chan->coarse_delay & 0x1F);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_7(chan->num),
|
||||||
|
chan->out_mux_mode & 0x3);
|
||||||
|
|
||||||
|
hmc7044_write(dev, HMC7044_REG_CH_OUT_CRTL_0(chan->num),
|
||||||
|
(chan->start_up_mode_dynamic_enable ?
|
||||||
|
HMC7044_START_UP_MODE_DYN_EN : 0) |
|
||||||
|
(chan->output_control0_rb4_enable ? BIT(4) : 0) |
|
||||||
|
(chan->high_performance_mode_dis ?
|
||||||
|
0 : HMC7044_HI_PERF_MODE) | HMC7044_SYNC_EN |
|
||||||
|
HMC7044_CH_EN);
|
||||||
|
}
|
||||||
|
mdelay(10);
|
||||||
|
|
||||||
|
|
||||||
|
/* Do a restart to reset the system and initiate calibration */
|
||||||
|
hmc7044_write(dev, HMC7044_REG_REQ_MODE_0,
|
||||||
|
HMC7044_RESTART_DIV_FSM);
|
||||||
|
mdelay(1);
|
||||||
|
hmc7044_write(dev, HMC7044_REG_REQ_MODE_0,
|
||||||
|
(dev->high_performance_mode_clock_dist_en ?
|
||||||
|
HMC7044_HIGH_PERF_DISTRIB_PATH : 0));
|
||||||
|
mdelay(1);
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief hmc7044_reg_init
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t hmc7044_reg_init(struct hmc7044_dev **device,
|
||||||
|
const struct hmc7044_init_param *init_param)
|
||||||
|
{
|
||||||
|
int ret = SUCCESS;
|
||||||
|
struct hmc7044_dev *dev;
|
||||||
|
|
||||||
|
dev = (struct hmc7044_dev *)malloc(sizeof(*dev));
|
||||||
|
if (!dev)
|
||||||
|
return FAILURE;
|
||||||
|
|
||||||
|
/* SPI */
|
||||||
|
ret = spi_init(&dev->spi_desc, init_param->spi_init);
|
||||||
|
|
||||||
|
*device = dev;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the device.
|
||||||
|
* @param device - The device structure.
|
||||||
|
* @param init_param - The structure that contains the device initial
|
||||||
|
* parameters.
|
||||||
|
* @return SUCCESS in case of success, negative error code otherwise.
|
||||||
|
*/
|
||||||
|
int32_t hmc7044_init(struct hmc7044_dev **device,
|
||||||
|
const struct hmc7044_init_param *init_param)
|
||||||
|
{
|
||||||
|
struct hmc7044_dev *dev;
|
||||||
|
int32_t ret;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
dev = (struct hmc7044_dev *)malloc(sizeof(*dev));
|
||||||
|
if (!dev)
|
||||||
|
return FAILURE;
|
||||||
|
|
||||||
|
ret = spi_init(&dev->spi_desc, init_param->spi_init);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
dev->is_hmc7043 = init_param->is_hmc7043;
|
||||||
|
|
||||||
|
dev->clkin_freq[0] = init_param->clkin_freq[0];
|
||||||
|
dev->clkin_freq[1] = init_param->clkin_freq[1];
|
||||||
|
dev->clkin_freq[2] = init_param->clkin_freq[2];
|
||||||
|
dev->clkin_freq[3] = init_param->clkin_freq[3];
|
||||||
|
|
||||||
|
dev->clkin_freq_ccf[0] = init_param->clkin_freq_ccf[0];
|
||||||
|
dev->clkin_freq_ccf[1] = init_param->clkin_freq_ccf[1];
|
||||||
|
dev->clkin_freq_ccf[2] = init_param->clkin_freq_ccf[2];
|
||||||
|
dev->clkin_freq_ccf[3] = init_param->clkin_freq_ccf[3];
|
||||||
|
|
||||||
|
dev->vcxo_freq = init_param->vcxo_freq;
|
||||||
|
dev->pll1_pfd = init_param->pll1_pfd;
|
||||||
|
dev->pll2_freq = init_param->pll2_freq;
|
||||||
|
dev->pll1_loop_bw = init_param->pll1_loop_bw;
|
||||||
|
|
||||||
|
dev->sysref_timer_div = init_param->sysref_timer_div;
|
||||||
|
dev->pll1_ref_prio_ctrl = init_param->pll1_ref_prio_ctrl;
|
||||||
|
dev->clkin0_rfsync_en = init_param->clkin0_rfsync_en;
|
||||||
|
dev->clkin1_vcoin_en = init_param->clkin1_vcoin_en;
|
||||||
|
dev->high_performance_mode_clock_dist_en =
|
||||||
|
init_param->high_performance_mode_clock_dist_en;
|
||||||
|
dev->rf_reseeder_en = !init_param->rf_reseeder_disable;
|
||||||
|
dev->sync_pin_mode = init_param->sync_pin_mode;
|
||||||
|
dev->pulse_gen_mode = init_param->pulse_gen_mode;
|
||||||
|
|
||||||
|
dev->in_buf_mode[0] = init_param->in_buf_mode[0];
|
||||||
|
dev->in_buf_mode[1] = init_param->in_buf_mode[1];
|
||||||
|
dev->in_buf_mode[2] = init_param->in_buf_mode[2];
|
||||||
|
dev->in_buf_mode[3] = init_param->in_buf_mode[3];
|
||||||
|
dev->in_buf_mode[4] = init_param->in_buf_mode[4];
|
||||||
|
|
||||||
|
dev->gpi_ctrl[0] = init_param->gpi_ctrl[0];
|
||||||
|
dev->gpi_ctrl[1] = init_param->gpi_ctrl[1];
|
||||||
|
dev->gpi_ctrl[2] = init_param->gpi_ctrl[2];
|
||||||
|
dev->gpi_ctrl[3] = init_param->gpi_ctrl[3];
|
||||||
|
|
||||||
|
dev->gpo_ctrl[0] = init_param->gpo_ctrl[0];
|
||||||
|
dev->gpo_ctrl[1] = init_param->gpo_ctrl[1];
|
||||||
|
dev->gpo_ctrl[2] = init_param->gpo_ctrl[2];
|
||||||
|
dev->gpo_ctrl[3] = init_param->gpo_ctrl[3];
|
||||||
|
|
||||||
|
dev->num_channels = init_param->num_channels;
|
||||||
|
dev->channels = (struct hmc7044_chan_spec *)
|
||||||
|
malloc(sizeof(*dev->channels) * dev->num_channels);
|
||||||
|
|
||||||
|
for (i = 0; i < dev->num_channels; i++) {
|
||||||
|
dev->channels[i].num = init_param->channels[i].num;
|
||||||
|
dev->channels[i].disable = init_param->channels[i].disable;
|
||||||
|
dev->channels[i].divider = init_param->channels[i].divider;
|
||||||
|
dev->channels[i].driver_mode =
|
||||||
|
init_param->channels[i].driver_mode;
|
||||||
|
dev->channels[i].high_performance_mode_dis =
|
||||||
|
init_param->channels[i].high_performance_mode_dis;
|
||||||
|
dev->channels[i].start_up_mode_dynamic_enable =
|
||||||
|
init_param->channels[i].start_up_mode_dynamic_enable;
|
||||||
|
dev->channels[i].dynamic_driver_enable =
|
||||||
|
init_param->channels[i].dynamic_driver_enable;
|
||||||
|
dev->channels[i].output_control0_rb4_enable =
|
||||||
|
init_param->channels[i].output_control0_rb4_enable;
|
||||||
|
dev->channels[i].force_mute_enable =
|
||||||
|
init_param->channels[i].force_mute_enable;
|
||||||
|
dev->channels[i].driver_impedance =
|
||||||
|
init_param->channels[i].driver_impedance;
|
||||||
|
dev->channels[i].coarse_delay =
|
||||||
|
init_param->channels[i].coarse_delay;
|
||||||
|
dev->channels[i].fine_delay =
|
||||||
|
init_param->channels[i].fine_delay;
|
||||||
|
dev->channels[i].out_mux_mode =
|
||||||
|
init_param->channels[i].out_mux_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
*device = dev;
|
||||||
|
|
||||||
|
if (!dev->is_hmc7043)
|
||||||
|
return hmc7044_setup(dev);
|
||||||
|
else
|
||||||
|
return hmc7043_setup(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the device - release resources.
|
||||||
|
* @param device - The device structure.
|
||||||
|
* @return SUCCESS in case of success, negative error code otherwise.
|
||||||
|
*/
|
||||||
|
int32_t hmc7044_remove(struct hmc7044_dev *device)
|
||||||
|
{
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
ret = spi_remove(device->spi_desc);
|
||||||
|
free(device->channels);
|
||||||
|
free(device);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,276 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file hmc7044.h
|
||||||
|
* @brief Header file of HMC7044, HMC7043 Driver.
|
||||||
|
* @author DBogdan ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2018-2020(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef HMC7044_H_
|
||||||
|
#define HMC7044_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "delay.h"
|
||||||
|
#include "spi.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
// Enum to select SYNC pin configuration with respect to PLL2 (0x0005)
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SYNC_DISABLED = 0,
|
||||||
|
SYNC_MULTICHIP = 1,
|
||||||
|
SYNC_PULSE_GEN = 2,
|
||||||
|
SYNC_ALARM = 3
|
||||||
|
} hmc7044SyncPinModeSelect_t;
|
||||||
|
|
||||||
|
// Enum to select input buffer mode (0x000A, 0x000B, 0x000C, 0x000D, 0x000E)
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
BUFFER_ENABLE = (1) << 0,
|
||||||
|
BUFFER_DISABLE = (0) << 0,
|
||||||
|
ENABLE_INTERNAL_TERM = (1) << 1,
|
||||||
|
ENABLE_AC_COUPLE = (1) << 2,
|
||||||
|
ENABLE_LVPECL = (1) << 3,
|
||||||
|
ENABLE_HIGH_Z = (1) << 4
|
||||||
|
} hmc7044InputBufferMode_t;
|
||||||
|
|
||||||
|
// Enum to select output driver mode (0x003A, 0x003B, 0x00D0, 0x00DA, 0x00E4,
|
||||||
|
// 0x00EE, 0x00F8, 0x0102, 0x010C, 0x0116, 0x0120, 0x012A, 0x0134, 0x013E,
|
||||||
|
// 0x0148, 0x0152)
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
CML = 0,
|
||||||
|
LVPECL = 1,
|
||||||
|
LVDS = 2,
|
||||||
|
CMOS = 3
|
||||||
|
} hmc7044DriverMode_t;
|
||||||
|
|
||||||
|
// Enum to select the GPIx functionality. (0x0046, 0x0047, 0x0048, 0x0049)
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
GPI_ENABLE = (1) << 0,
|
||||||
|
GPI_DISABLE = (0) << 0,
|
||||||
|
FORCE_PLL1_HOLDOVER = (0x01) << 1 | GPI_ENABLE,
|
||||||
|
SELECT_PLL1_REF_BIT1 = (0x02) << 1 | GPI_ENABLE,
|
||||||
|
SELECT_PLL1_REF_BIT2 = (0x03) << 1 | GPI_ENABLE,
|
||||||
|
CHIP_SLEEP_MODE = (0x04) << 1 | GPI_ENABLE,
|
||||||
|
MUTE_REQUSET = (0x05) << 1 | GPI_ENABLE,
|
||||||
|
SELECT_INTERNAL_VCO_TYPE = (0x06) << 1 | GPI_ENABLE,
|
||||||
|
SELECT_HI_PERF_MODE = (0x07) << 1 | GPI_ENABLE,
|
||||||
|
PULSE_GEN_REQUSET = (0x08) << 1 | GPI_ENABLE,
|
||||||
|
RESEED_REQUEST = (0x09) << 1 | GPI_ENABLE,
|
||||||
|
RESTART_REQUSET = (0x0A) << 1 | GPI_ENABLE,
|
||||||
|
FORCE_FANOUT_MODE = (0x0B) << 1 | GPI_ENABLE,
|
||||||
|
SLIP_REQUEST = (0x0D) << 1 | GPI_ENABLE,
|
||||||
|
} hmc7044GPIControl_t;
|
||||||
|
|
||||||
|
// Enum to select the GPOx functionality. (0x0050, 0x0051, 0x0052, 0x0053)
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
GPO_ENABLE = (1) << 0,
|
||||||
|
GPO_DISABLE = (0) << 0,
|
||||||
|
GPO_CMOS_MODE = (1) << 1,
|
||||||
|
GPO_OPEN_DRAIN_MODE = (0) << 1,
|
||||||
|
ALARM_SIGNAL = (0x00) << 3 | GPO_ENABLE,
|
||||||
|
SPI_SDATA = (0x01) << 3 | GPO_ENABLE,
|
||||||
|
CLKIN3_SIGNAL_LOSS = (0x02) << 3 | GPO_ENABLE,
|
||||||
|
CLKIN2_SIGNAL_LOSS = (0x03) << 3 | GPO_ENABLE,
|
||||||
|
CLKIN1_SIGNAL_LOSS = (0x04) << 3 | GPO_ENABLE,
|
||||||
|
CLKIN0_SIGNAL_LOSS = (0x05) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_HOLDOVER_ENABLE = (0x06) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_LOCK_DETECT = (0x07) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_ACQUIRING_LOCK = (0x08) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_NEAR_CLOCK_ACQ_STAT = (0x09) << 3 | GPO_ENABLE,
|
||||||
|
PLL2_LOCK_DETECT = (0x0A) << 3 | GPO_ENABLE,
|
||||||
|
PLL2_SYSREF_SYNC = (0x0B) << 3 | GPO_ENABLE,
|
||||||
|
CLOCK_OUTPUT_PHASE_STAT = (0x0C) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_PLL2_LOCKED = (0x0D) << 3 | GPO_ENABLE,
|
||||||
|
SYNC_REQUSRT_STAT = (0x0E) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_ACTIVE_CLKIN0 = (0x0F) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_ACTIVE_CLKIN1 = (0x10) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_HOLDOVER_IN_RANGE_STAT = (0x11) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_HOLDOVER_IN_STAT = (0x12) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_VCXO_STAT = (0x13) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_ACTIVE_CLKINx_STAT = (0x14) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_FSM_BIT0 = (0x15) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_FSM_BIT1 = (0x16) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_FSM_BIT2 = (0x17) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_HOLDOVER_EXIT_PHASE_BIT0 = (0x18) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_HOLDOVER_EXIT_PHASE_BIT1 = (0x19) << 3 | GPO_ENABLE,
|
||||||
|
CHANNEL_OUTPUT_FSM_BUSY = (0x1A) << 3 | GPO_ENABLE,
|
||||||
|
SYSREF_FSM_STAT_BIT0 = (0x1B) << 3 | GPO_ENABLE,
|
||||||
|
SYSREF_FSM_STAT_BIT1 = (0x1C) << 3 | GPO_ENABLE,
|
||||||
|
SYSREF_FSM_STAT_BIT2 = (0x1D) << 3 | GPO_ENABLE,
|
||||||
|
SYSREF_FSM_STAT_BIT3 = (0x1E) << 3 | GPO_ENABLE,
|
||||||
|
FORCE_LOGIC_1 = (0x1F) << 3 | GPO_ENABLE,
|
||||||
|
FORCE_LOGIC_0 = (0x20) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_HOLDOVER_AVG_VALUE_BIT0 = (0x27) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_HOLDOVER_AVG_VALUE_BIT1 = (0x28) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_HOLDOVER_AVG_VALUE_BIT2 = (0x29) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_HOLDOVER_AVG_VALUE_BIT3 = (0x2A) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_HOLDOVER_CURR_VALUE_BIT0 = (0x2B) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_HOLDOVER_CURR_VALUE_BIT1 = (0x2C) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_HOLDOVER_CURR_VALUE_BIT2 = (0x2D) << 3 | GPO_ENABLE,
|
||||||
|
PLL1_HOLDOVER_CURR_VALUE_BIT3 = (0x2E) << 3 | GPO_ENABLE
|
||||||
|
} hmc7044GPOControl_t;
|
||||||
|
|
||||||
|
// Enum to select output channel (0x00CF, 0x00D9, 0x00E3, 0x00ED, 0x00F7,
|
||||||
|
// 0x0101, 0x010B, 0x0115, 0x011F, 0x0129, 0x0133, 0x013D, 0x0147, 0x0151
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
CHANNEL_DIV = 0,
|
||||||
|
ANALOG_DELAY = 1,
|
||||||
|
OTHER_CHANNEL = 2,
|
||||||
|
VCO_CLOCK = 3
|
||||||
|
} hmc7044OutputMuxSelect_t;
|
||||||
|
|
||||||
|
// Enum to select output driver impedance selection for CML mode (0x00D0,
|
||||||
|
// 0x00DA, 0x00E4, 0x00EE, 0x00F8, 0x0102, 0x010C, 0x0116, 0x0120, 0x012A,
|
||||||
|
// 0x0134, 0x013E, 0x0148, 0x0152)
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
INTERNAL_RES_DISABLE = 0,
|
||||||
|
INTERNAL_100OHM_PER_PIN = 1,
|
||||||
|
// INTERNAL_RES_RESERVED = 2,
|
||||||
|
INTERNAL_50OHM_PER_PIN = 3
|
||||||
|
} hmc7044DriverImpedance_t;
|
||||||
|
|
||||||
|
// Enum to select pulse generator mode (0x005A)
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PULSE_LEVEL_SENSITIVE = 0,
|
||||||
|
PULSE_ONE = 1,
|
||||||
|
PULSE_TWO = 2,
|
||||||
|
PULSE_FOUR = 3,
|
||||||
|
PULSE_EIGHT = 4,
|
||||||
|
PULSE_SIXTEEN = 5,
|
||||||
|
// PULSE_SIXTEEN = 6,
|
||||||
|
PULSE_CONTINOUS = 7
|
||||||
|
} hmc7044SyncPulseGenControl_t;
|
||||||
|
|
||||||
|
struct hmc7044_chan_spec {
|
||||||
|
unsigned int num;
|
||||||
|
bool disable;
|
||||||
|
bool high_performance_mode_dis;
|
||||||
|
bool start_up_mode_dynamic_enable;
|
||||||
|
bool dynamic_driver_enable;
|
||||||
|
bool output_control0_rb4_enable;
|
||||||
|
bool force_mute_enable;
|
||||||
|
unsigned int divider;
|
||||||
|
unsigned int coarse_delay;
|
||||||
|
unsigned int fine_delay;
|
||||||
|
hmc7044DriverMode_t driver_mode;
|
||||||
|
hmc7044DriverImpedance_t driver_impedance;
|
||||||
|
hmc7044OutputMuxSelect_t out_mux_mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hmc7044_config {
|
||||||
|
uint16_t addr;
|
||||||
|
uint8_t value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hmc7044_dev {
|
||||||
|
struct spi_desc *spi_desc;
|
||||||
|
bool is_hmc7043;
|
||||||
|
uint32_t clkin_freq[4];
|
||||||
|
uint32_t clkin_freq_ccf[4];
|
||||||
|
uint32_t vcxo_freq;
|
||||||
|
uint32_t pll1_pfd;
|
||||||
|
uint32_t pll2_freq;
|
||||||
|
uint32_t pll1_loop_bw;
|
||||||
|
uint32_t sysref_timer_div;
|
||||||
|
unsigned int pll1_ref_prio_ctrl;
|
||||||
|
bool clkin0_rfsync_en;
|
||||||
|
bool clkin1_vcoin_en;
|
||||||
|
bool high_performance_mode_clock_dist_en;
|
||||||
|
bool rf_reseeder_en;
|
||||||
|
hmc7044SyncPinModeSelect_t sync_pin_mode;
|
||||||
|
hmc7044SyncPulseGenControl_t pulse_gen_mode;
|
||||||
|
uint32_t in_buf_mode[5];
|
||||||
|
uint32_t gpi_ctrl[4];
|
||||||
|
uint32_t gpo_ctrl[4];
|
||||||
|
uint32_t num_channels;
|
||||||
|
struct hmc7044_chan_spec *channels;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hmc7044_init_param {
|
||||||
|
struct spi_init_param *spi_init;
|
||||||
|
bool is_hmc7043;
|
||||||
|
uint32_t clkin_freq[4];
|
||||||
|
uint32_t clkin_freq_ccf[4];
|
||||||
|
uint32_t vcxo_freq;
|
||||||
|
uint32_t pll1_pfd;
|
||||||
|
uint32_t pll2_freq;
|
||||||
|
uint32_t pll1_loop_bw;
|
||||||
|
uint32_t sysref_timer_div;
|
||||||
|
unsigned int pll1_ref_prio_ctrl;
|
||||||
|
bool clkin0_rfsync_en;
|
||||||
|
bool clkin1_vcoin_en;
|
||||||
|
bool high_performance_mode_clock_dist_en;
|
||||||
|
bool rf_reseeder_disable;
|
||||||
|
hmc7044SyncPinModeSelect_t sync_pin_mode;
|
||||||
|
hmc7044SyncPulseGenControl_t pulse_gen_mode;
|
||||||
|
uint32_t in_buf_mode[5];
|
||||||
|
uint32_t gpi_ctrl[4];
|
||||||
|
uint32_t gpo_ctrl[4];
|
||||||
|
uint32_t num_channels;
|
||||||
|
struct hmc7044_chan_spec *channels;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
/* Initialize the device. */
|
||||||
|
int32_t hmc7044_reg_init(struct hmc7044_dev **device,
|
||||||
|
const struct hmc7044_init_param *init_param);
|
||||||
|
int32_t hmc7044_init(struct hmc7044_dev **device,
|
||||||
|
const struct hmc7044_init_param *init_param);
|
||||||
|
/* Remove the device. */
|
||||||
|
int32_t hmc7044_remove(struct hmc7044_dev *device);
|
||||||
|
int32_t hmc7044_write(struct hmc7044_dev *dev,
|
||||||
|
uint16_t reg, uint8_t val);
|
||||||
|
int32_t hmc7044_read(struct hmc7044_dev *dev, uint16_t reg, uint8_t *val);
|
||||||
|
int32_t hmc7044_clk_recalc_rate(struct hmc7044_dev *dev, uint32_t chan_num,
|
||||||
|
uint64_t *rate);
|
||||||
|
int32_t hmc7044_clk_round_rate(struct hmc7044_dev *dev, uint32_t rate,
|
||||||
|
uint64_t *rounded_rate);
|
||||||
|
int32_t hmc7044_clk_set_rate(struct hmc7044_dev *dev, uint32_t chan_num,
|
||||||
|
uint64_t rate);
|
||||||
|
|
||||||
|
#endif // HMC7044_H_
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file xilinx/xilinx_axi_io.c
|
||||||
|
* @brief Implementation of Xilinx AXI IO.
|
||||||
|
* @author Antoniu Miclaus ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <xil_io.h>
|
||||||
|
#include "error.h"
|
||||||
|
#include "axi_io.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Definitions *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief AXI IO Xilinx specific read function.
|
||||||
|
* @param base - Base address
|
||||||
|
* @param offset - Address offset
|
||||||
|
* @param data - variable where returned data is stored
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t axi_io_read(uint32_t base, uint32_t offset, uint32_t *data)
|
||||||
|
{
|
||||||
|
*data = Xil_In32(base + offset);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief AXI IO Xilinx specific write function.
|
||||||
|
* @param base - Base address
|
||||||
|
* @param offset - Address offset
|
||||||
|
* @param data - data to be written.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t axi_io_write(uint32_t base, uint32_t offset, uint32_t data)
|
||||||
|
{
|
||||||
|
Xil_Out32(base + offset, data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file xilinx/xilinx_delay.c
|
||||||
|
* @brief Implementation of Xilinx Delay Functions.
|
||||||
|
* @author Antoniu Miclaus ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include "delay.h"
|
||||||
|
#include <sleep.h>
|
||||||
|
#ifdef _XPARAMETERS_PS_H_
|
||||||
|
#include "util.h"
|
||||||
|
#include "xtime_l.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Definitions *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate microseconds delay.
|
||||||
|
* @param usecs - Delay in microseconds.
|
||||||
|
* @return None.
|
||||||
|
*/
|
||||||
|
void udelay(uint32_t usecs)
|
||||||
|
{
|
||||||
|
#ifdef _XPARAMETERS_PS_H_
|
||||||
|
usleep(usecs);
|
||||||
|
#else
|
||||||
|
usleep_MB(usecs);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate miliseconds delay.
|
||||||
|
* @param msecs - Delay in miliseconds.
|
||||||
|
* @return None.
|
||||||
|
*/
|
||||||
|
void mdelay(uint32_t msecs)
|
||||||
|
{
|
||||||
|
#ifdef _XPARAMETERS_PS_H_
|
||||||
|
usleep(msecs * 1000);
|
||||||
|
#else
|
||||||
|
usleep_MB(msecs * 1000);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get current time.
|
||||||
|
* @return Current time structure from system start (seconds, microseconds).
|
||||||
|
*/
|
||||||
|
struct time get_time(void)
|
||||||
|
{
|
||||||
|
struct time t = {0, 0};
|
||||||
|
#ifdef _XPARAMETERS_PS_H_
|
||||||
|
unsigned long long Xtime_Global;
|
||||||
|
uint32_t rem;
|
||||||
|
|
||||||
|
XTime_GetTime(&Xtime_Global);
|
||||||
|
t.s = div_u64_rem(Xtime_Global, COUNTS_PER_SECOND, &rem);
|
||||||
|
t.us = div_u64((uint64_t)rem * 1000000, COUNTS_PER_SECOND);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
@@ -0,0 +1,464 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file xilinx/xilinx_gpio.c
|
||||||
|
* @brief Implementation of Xilinx GPIO Generic Driver.
|
||||||
|
* @author Antoniu Miclaus ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <xparameters.h>
|
||||||
|
#ifdef XPAR_XGPIO_NUM_INSTANCES
|
||||||
|
#include <xgpio.h>
|
||||||
|
#endif
|
||||||
|
#ifdef XPAR_XGPIOPS_NUM_INSTANCES
|
||||||
|
#include <xgpiops.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "error.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "xilinx_gpio.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Definitions *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prepare the GPIO decriptor.
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @param param - The structure that contains the GPIO parameters.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t _gpio_init(struct gpio_desc *desc,
|
||||||
|
const struct gpio_init_param *param)
|
||||||
|
{
|
||||||
|
int32_t ret;
|
||||||
|
struct xil_gpio_desc *xdesc;
|
||||||
|
struct xil_gpio_init_param *xinit;
|
||||||
|
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
|
xdesc = desc->extra;
|
||||||
|
xinit = param->extra;
|
||||||
|
|
||||||
|
xdesc->type = xinit->type;
|
||||||
|
desc->number = param->number;
|
||||||
|
|
||||||
|
switch (xinit->type) {
|
||||||
|
case GPIO_PL:
|
||||||
|
#ifdef XGPIO_H
|
||||||
|
xdesc->instance = (XGpio *)malloc(sizeof(XGpio));
|
||||||
|
if(!xdesc->instance)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
xdesc->config = XGpio_LookupConfig(xinit->device_id);
|
||||||
|
if(xdesc->config == NULL)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
ret = XGpio_CfgInitialize(xdesc->instance,
|
||||||
|
xdesc->config,
|
||||||
|
((XGpio_Config*)xdesc->config)
|
||||||
|
->BaseAddress);
|
||||||
|
if(ret < 0)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
break;
|
||||||
|
pl_error:
|
||||||
|
free(xdesc->instance);
|
||||||
|
#endif
|
||||||
|
goto error;
|
||||||
|
case GPIO_PS:
|
||||||
|
#ifdef XGPIOPS_H
|
||||||
|
xdesc->instance = (XGpioPs *)malloc(sizeof(XGpioPs));
|
||||||
|
if(!xdesc->instance)
|
||||||
|
goto ps_error;
|
||||||
|
|
||||||
|
xdesc->config = XGpioPs_LookupConfig(xinit->device_id);
|
||||||
|
if(xdesc->config == NULL)
|
||||||
|
goto ps_error;
|
||||||
|
|
||||||
|
ret = XGpioPs_CfgInitialize(xdesc->instance,
|
||||||
|
xdesc->config,
|
||||||
|
((XGpioPs_Config*)xdesc->config)->BaseAddr);
|
||||||
|
if(ret < 0)
|
||||||
|
goto ps_error;
|
||||||
|
break;
|
||||||
|
ps_error:
|
||||||
|
free(xdesc->instance);
|
||||||
|
#endif
|
||||||
|
goto error;
|
||||||
|
error:
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Obtain the GPIO decriptor.
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @param param - GPIO initialization parameters
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_gpio_get(struct gpio_desc **desc,
|
||||||
|
const struct gpio_init_param *param)
|
||||||
|
{
|
||||||
|
struct gpio_desc *descriptor;
|
||||||
|
struct xil_gpio_desc *extra;
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
descriptor = (struct gpio_desc *)malloc(sizeof(*descriptor));
|
||||||
|
extra = (struct xil_gpio_desc*)malloc(sizeof(*extra));
|
||||||
|
|
||||||
|
if (!descriptor || !extra)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
descriptor->extra = extra;
|
||||||
|
ret = _gpio_init(descriptor, param);
|
||||||
|
|
||||||
|
if(ret != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
*desc = descriptor;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
free(extra);
|
||||||
|
free(descriptor);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the value of an optional GPIO.
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @param param - GPIO Initialization parameters.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_gpio_get_optional(struct gpio_desc **desc,
|
||||||
|
const struct gpio_init_param *param)
|
||||||
|
{
|
||||||
|
if(param == NULL) {
|
||||||
|
*desc = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xil_gpio_get(desc, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free the resources allocated by gpio_get().
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_gpio_remove(struct gpio_desc *desc)
|
||||||
|
{
|
||||||
|
if (desc != NULL) {
|
||||||
|
free(((struct xil_gpio_desc *)(desc->extra))->instance);
|
||||||
|
free(desc->extra);
|
||||||
|
free(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable the input direction of the specified GPIO.
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_gpio_direction_input(struct gpio_desc *desc)
|
||||||
|
{
|
||||||
|
struct xil_gpio_desc *extra;
|
||||||
|
#ifdef XGPIO_H
|
||||||
|
uint8_t pin = desc->number;
|
||||||
|
uint32_t channel = 1;
|
||||||
|
uint32_t config = 0;
|
||||||
|
#endif
|
||||||
|
extra = desc->extra;
|
||||||
|
|
||||||
|
switch (extra->type) {
|
||||||
|
case GPIO_PL:
|
||||||
|
#ifdef XGPIO_H
|
||||||
|
/* We assume that pin 32 is the first pin from channel 2 */
|
||||||
|
if (pin >= 32) {
|
||||||
|
channel = 2;
|
||||||
|
pin -= 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
config = XGpio_GetDataDirection((XGpio *)extra->instance,
|
||||||
|
channel);
|
||||||
|
config |= (1 << pin);
|
||||||
|
XGpio_SetDataDirection((XGpio *)extra->instance,
|
||||||
|
channel,
|
||||||
|
config);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case GPIO_PS:
|
||||||
|
#ifdef XGPIOPS_H
|
||||||
|
XGpioPs_SetDirectionPin(extra->instance,
|
||||||
|
desc->number,
|
||||||
|
GPIO_IN);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable the output direction of the specified GPIO.
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @param value - The value.
|
||||||
|
* Example: GPIO_HIGH
|
||||||
|
* GPIO_LOW
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_gpio_direction_output(struct gpio_desc *desc,
|
||||||
|
uint8_t value)
|
||||||
|
{
|
||||||
|
struct xil_gpio_desc *extra;
|
||||||
|
#ifdef XGPIO_H
|
||||||
|
uint8_t pin = desc->number;
|
||||||
|
uint8_t channel;
|
||||||
|
uint32_t reg_val;
|
||||||
|
#endif
|
||||||
|
extra = desc->extra;
|
||||||
|
|
||||||
|
switch (extra->type) {
|
||||||
|
case GPIO_PL:
|
||||||
|
#ifdef XGPIO_H
|
||||||
|
if (pin >= 32) {
|
||||||
|
channel = 2;
|
||||||
|
pin -= 32;
|
||||||
|
} else
|
||||||
|
channel = 1;
|
||||||
|
|
||||||
|
reg_val = XGpio_GetDataDirection(extra->instance,
|
||||||
|
channel);
|
||||||
|
reg_val &= ~(1 << pin);
|
||||||
|
XGpio_SetDataDirection(extra->instance,
|
||||||
|
channel,
|
||||||
|
reg_val);
|
||||||
|
reg_val = XGpio_DiscreteRead(extra->instance,
|
||||||
|
channel);
|
||||||
|
if(value)
|
||||||
|
reg_val |= (1 << pin);
|
||||||
|
else
|
||||||
|
reg_val &= ~(1 << pin);
|
||||||
|
XGpio_DiscreteWrite(extra->instance,
|
||||||
|
channel,
|
||||||
|
reg_val);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case GPIO_PS:
|
||||||
|
#ifdef XGPIOPS_H
|
||||||
|
XGpioPs_SetDirectionPin(extra->instance,
|
||||||
|
desc->number,
|
||||||
|
GPIO_OUT);
|
||||||
|
XGpioPs_SetOutputEnablePin(extra->instance,
|
||||||
|
desc->number,
|
||||||
|
GPIO_OUT);
|
||||||
|
XGpioPs_WritePin(extra->instance,
|
||||||
|
desc->number,
|
||||||
|
value);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the direction of the specified GPIO.
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @param direction - The direction.
|
||||||
|
* Example: GPIO_OUT
|
||||||
|
* GPIO_IN
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_gpio_get_direction(struct gpio_desc *desc,
|
||||||
|
uint8_t *direction)
|
||||||
|
{
|
||||||
|
if (!desc)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
struct xil_gpio_desc *extra;
|
||||||
|
uint8_t pin = desc->number;
|
||||||
|
|
||||||
|
#ifdef XGPIO_H
|
||||||
|
uint8_t channel;
|
||||||
|
#endif
|
||||||
|
extra = desc->extra;
|
||||||
|
|
||||||
|
switch (extra->type) {
|
||||||
|
case GPIO_PL:
|
||||||
|
#ifdef XGPIO_H
|
||||||
|
if (pin >= 32) {
|
||||||
|
channel = 2;
|
||||||
|
pin -= 32;
|
||||||
|
} else
|
||||||
|
channel = 1;
|
||||||
|
*direction = ((XGpio_GetDataDirection(extra->instance,
|
||||||
|
channel) >> pin) & 0x1) ^ 0x1;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case GPIO_PS:
|
||||||
|
#ifdef XGPIOPS_H
|
||||||
|
*direction = XGpioPs_GetDirectionPin(extra->instance, pin);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the value of the specified GPIO.
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @param value - The value.
|
||||||
|
* Example: GPIO_HIGH
|
||||||
|
* GPIO_LOW
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_gpio_set_value(struct gpio_desc *desc,
|
||||||
|
uint8_t value)
|
||||||
|
{
|
||||||
|
struct xil_gpio_desc *extra;
|
||||||
|
#ifdef XGPIO_H
|
||||||
|
uint8_t pin = desc->number;
|
||||||
|
uint8_t channel;
|
||||||
|
uint32_t reg_val;
|
||||||
|
#endif
|
||||||
|
extra = desc->extra;
|
||||||
|
|
||||||
|
switch (extra->type) {
|
||||||
|
case GPIO_PL:
|
||||||
|
#ifdef XGPIO_H
|
||||||
|
if (pin >= 32) {
|
||||||
|
channel = 2;
|
||||||
|
pin -= 32;
|
||||||
|
} else
|
||||||
|
channel = 1;
|
||||||
|
|
||||||
|
reg_val = XGpio_DiscreteRead(extra->instance, channel);
|
||||||
|
if(value)
|
||||||
|
reg_val |= (1 << pin);
|
||||||
|
else
|
||||||
|
reg_val &= ~(1 << pin);
|
||||||
|
XGpio_DiscreteWrite(extra->instance, channel, reg_val);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case GPIO_PS:
|
||||||
|
#ifdef XGPIOPS_H
|
||||||
|
XGpioPs_WritePin(extra->instance, desc->number, value);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the value of the specified GPIO.
|
||||||
|
* @param desc - The GPIO descriptor.
|
||||||
|
* @param value - The value.
|
||||||
|
* Example: GPIO_HIGH
|
||||||
|
* GPIO_LOW
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_gpio_get_value(struct gpio_desc *desc,
|
||||||
|
uint8_t *value)
|
||||||
|
{
|
||||||
|
if (!desc)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
struct xil_gpio_desc *extra;
|
||||||
|
uint8_t pin = desc->number;
|
||||||
|
|
||||||
|
#ifdef XGPIO_H
|
||||||
|
uint8_t channel;
|
||||||
|
#endif
|
||||||
|
extra = desc->extra;
|
||||||
|
|
||||||
|
switch (extra->type) {
|
||||||
|
case GPIO_PL:
|
||||||
|
#ifdef XGPIO_H
|
||||||
|
if (pin >= 32) {
|
||||||
|
channel = 2;
|
||||||
|
pin -= 32;
|
||||||
|
} else
|
||||||
|
channel = 1;
|
||||||
|
*value = (XGpio_DiscreteRead(extra->instance, channel) >> pin) & 0x01;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case GPIO_PS:
|
||||||
|
#ifdef XGPIOPS_H
|
||||||
|
*value = XGpioPs_ReadPin(extra->instance, pin);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Xilinx platform specific GPIO platform ops structure
|
||||||
|
*/
|
||||||
|
const struct gpio_platform_ops xil_gpio_ops = {
|
||||||
|
.gpio_ops_get = &xil_gpio_get,
|
||||||
|
.gpio_ops_get_optional = &xil_gpio_get_optional,
|
||||||
|
.gpio_ops_remove = &xil_gpio_remove,
|
||||||
|
.gpio_ops_direction_input = &xil_gpio_direction_input,
|
||||||
|
.gpio_ops_direction_output = &xil_gpio_direction_output,
|
||||||
|
.gpio_ops_get_direction = &xil_gpio_get_direction,
|
||||||
|
.gpio_ops_set_value = &xil_gpio_set_value,
|
||||||
|
.gpio_ops_get_value = &xil_gpio_get_value,
|
||||||
|
};
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* @file xilinx/xilinx_gpio.h
|
||||||
|
* @brief Header containing extra types used in the gpio driver
|
||||||
|
* @author scuciurean ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef XILINX_GPIO_H_
|
||||||
|
#define XILINX_GPIO_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum xil_gpio_type
|
||||||
|
* @brief Xilinx platform architecture sections
|
||||||
|
*/
|
||||||
|
enum xil_gpio_type {
|
||||||
|
/** Programmable Logic */
|
||||||
|
GPIO_PL,
|
||||||
|
/** Processing System */
|
||||||
|
GPIO_PS
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct xil_gpio_init_param
|
||||||
|
* @brief Structure holding the initialization parameters for Xilinx platform
|
||||||
|
* specific GPIO parameters.
|
||||||
|
*/
|
||||||
|
struct xil_gpio_init_param {
|
||||||
|
/** Xilinx architecture */
|
||||||
|
enum xil_gpio_type type;
|
||||||
|
/** Device ID */
|
||||||
|
uint32_t device_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct xil_gpio_desc
|
||||||
|
* @brief Xilinx platform specific GPIO descriptor
|
||||||
|
*/
|
||||||
|
struct xil_gpio_desc {
|
||||||
|
/** Xilinx architecture */
|
||||||
|
enum xil_gpio_type type;
|
||||||
|
/** Xilinx GPIO configuration */
|
||||||
|
void *config;
|
||||||
|
/** Xilinx GPIO Instance */
|
||||||
|
void *instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Xilinx platform specific gpio platform ops structure
|
||||||
|
*/
|
||||||
|
extern const struct gpio_platform_ops xil_gpio_ops;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,360 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file xilinx/xilinx_gpio_irq.c
|
||||||
|
* @brief Implementation of Xilinx GPIO IRQ Generic Driver.
|
||||||
|
* @author Porumb Andrei ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2021(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "xparameters.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "xilinx_gpio_irq.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "list.h"
|
||||||
|
#include "irq.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Definitions *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Comparing function used by list.
|
||||||
|
* @param desc_a - Compared item
|
||||||
|
* @param desc_b - Reference item
|
||||||
|
* @return - 0 if items match
|
||||||
|
*/
|
||||||
|
static int32_t call_cmp(struct xil_callback_desc *desc_a,
|
||||||
|
struct xil_callback_desc *desc_b)
|
||||||
|
{
|
||||||
|
return desc_a->pin_nb - desc_b->pin_nb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function called when GPIO IRQ occurs.
|
||||||
|
* @param param - GPIO IRQ desc's extra field
|
||||||
|
* @return - None.
|
||||||
|
*/
|
||||||
|
static void xil_gpio_irq_handler(struct xil_gpio_irq_desc *param)
|
||||||
|
{
|
||||||
|
int32_t status = 0;
|
||||||
|
int32_t pin_nb;
|
||||||
|
struct xil_callback_desc *callback_desc;
|
||||||
|
|
||||||
|
status = iterator_move_to_idx(param->it, 0);
|
||||||
|
while(!status) {
|
||||||
|
iterator_read(param->it, &callback_desc);
|
||||||
|
status = iterator_move(param->it, 1);
|
||||||
|
if(XGpioPs_IntrGetStatusPin(¶m->my_Gpio, callback_desc->pin_nb))
|
||||||
|
callback_desc->triggered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = iterator_move_to_idx(param->it, 0);
|
||||||
|
while(!status) {
|
||||||
|
iterator_read(param->it, &callback_desc);
|
||||||
|
status = iterator_move(param->it, 1);
|
||||||
|
if(callback_desc->triggered == true) {
|
||||||
|
callback_desc->triggered = false;
|
||||||
|
XGpioPs_IntrDisablePin(¶m->my_Gpio, callback_desc->pin_nb);
|
||||||
|
XGpioPs_IntrClearPin(¶m->my_Gpio, callback_desc->pin_nb);
|
||||||
|
callback_desc->callback.legacy_callback(callback_desc->callback.ctx, 0U, NULL);
|
||||||
|
if(callback_desc->enabled)
|
||||||
|
XGpioPs_IntrEnablePin(¶m->my_Gpio, callback_desc->pin_nb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable specific GPIO IRQ pin.
|
||||||
|
* @param desc - The GPIO IRQ controller descriptor.
|
||||||
|
* @param irq_id - Pin number.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_gpio_irq_disable(struct irq_ctrl_desc *desc, uint32_t irq_id)
|
||||||
|
{
|
||||||
|
int32_t status;
|
||||||
|
struct xil_gpio_irq_desc *extra;
|
||||||
|
struct xil_callback_desc *callback_desc;
|
||||||
|
|
||||||
|
extra = desc->extra;
|
||||||
|
|
||||||
|
status = iterator_move_to_idx(extra->it, 0);
|
||||||
|
while(!status) {
|
||||||
|
iterator_read(extra->it, &callback_desc);
|
||||||
|
status = iterator_move(extra->it, 1);
|
||||||
|
if(callback_desc->pin_nb == irq_id) {
|
||||||
|
callback_desc->enabled = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XGpioPs_IntrDisablePin(&extra->my_Gpio, irq_id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the GPIO IRQ controller.
|
||||||
|
* @param desc - The GPIO IRQ controller descriptor.
|
||||||
|
* @param param - The GPIO IRQ controller initial parameters.
|
||||||
|
* irq_ctrl_id from irq_init_param is the interrupt id for the parent controller
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_gpio_irq_ctrl_init(struct irq_ctrl_desc **desc,
|
||||||
|
const struct irq_init_param *param)
|
||||||
|
{
|
||||||
|
int32_t i;
|
||||||
|
int32_t status;
|
||||||
|
struct irq_ctrl_desc *ldesc;
|
||||||
|
static XGpioPs_Config *GPIO_Config;
|
||||||
|
struct xil_gpio_irq_desc *xil_desc;
|
||||||
|
struct xil_gpio_irq_init_param *xil_ip;
|
||||||
|
struct callback_desc callback;
|
||||||
|
|
||||||
|
xil_desc = (struct xil_gpio_irq_desc *)calloc(1, sizeof(*xil_desc));
|
||||||
|
if(!xil_desc)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ldesc = (struct irq_ctrl_desc *)calloc(1, sizeof(*ldesc));
|
||||||
|
if(!ldesc) {
|
||||||
|
free(xil_desc);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
xil_ip = param->extra;
|
||||||
|
GPIO_Config = XGpioPs_LookupConfig(xil_ip->gpio_device_id);
|
||||||
|
status = XGpioPs_CfgInitialize(&xil_desc->my_Gpio, GPIO_Config,
|
||||||
|
GPIO_Config->BaseAddr);
|
||||||
|
if(status)
|
||||||
|
goto error_desc;
|
||||||
|
|
||||||
|
ldesc->extra = xil_desc;
|
||||||
|
xil_desc->parent_desc = xil_ip->parent_desc;
|
||||||
|
|
||||||
|
status = list_init(&xil_desc->callback_list, LIST_DEFAULT,
|
||||||
|
call_cmp);
|
||||||
|
if(status)
|
||||||
|
goto error_list;
|
||||||
|
|
||||||
|
status = iterator_init(&xil_desc->it, xil_desc->callback_list, 0);
|
||||||
|
if(status) {
|
||||||
|
iterator_remove(xil_desc->it);
|
||||||
|
goto error_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
ldesc->irq_ctrl_id = param->irq_ctrl_id;
|
||||||
|
status = irq_trigger_level_set(xil_desc->parent_desc, ldesc->irq_ctrl_id,
|
||||||
|
IRQ_EDGE_RISING);
|
||||||
|
if(status)
|
||||||
|
goto error_op;
|
||||||
|
|
||||||
|
status = irq_enable(xil_desc->parent_desc, ldesc->irq_ctrl_id);
|
||||||
|
if(status)
|
||||||
|
goto error_op;
|
||||||
|
|
||||||
|
callback.legacy_callback = &xil_gpio_irq_handler;
|
||||||
|
callback.ctx = ldesc->extra;
|
||||||
|
status = irq_register_callback(xil_desc->parent_desc, ldesc->irq_ctrl_id,
|
||||||
|
&callback);
|
||||||
|
if(status)
|
||||||
|
goto error_op;
|
||||||
|
|
||||||
|
*desc = ldesc;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_op:
|
||||||
|
iterator_remove(xil_desc->it);
|
||||||
|
error_list:
|
||||||
|
list_remove(xil_desc->callback_list);
|
||||||
|
error_desc:
|
||||||
|
free(xil_desc);
|
||||||
|
free(ldesc);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set GPIO interrupt trigger level.
|
||||||
|
* @param desc - The GPIO IRQ controller descriptor.
|
||||||
|
* @param irq_id - Pin number.
|
||||||
|
* @param trig - New trigger level for the GPIO interrupt.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_gpio_irq_trigger_level_set(struct irq_ctrl_desc *desc,
|
||||||
|
uint32_t irq_id,
|
||||||
|
enum irq_trig_level trig)
|
||||||
|
{
|
||||||
|
static const int32_t trig_level[5] = {XGPIOPS_IRQ_TYPE_LEVEL_LOW,
|
||||||
|
XGPIOPS_IRQ_TYPE_LEVEL_HIGH,
|
||||||
|
XGPIOPS_IRQ_TYPE_EDGE_FALLING,
|
||||||
|
XGPIOPS_IRQ_TYPE_EDGE_RISING,
|
||||||
|
XGPIOPS_IRQ_TYPE_EDGE_BOTH
|
||||||
|
};
|
||||||
|
struct xil_gpio_irq_desc *extra;
|
||||||
|
|
||||||
|
extra = desc->extra;
|
||||||
|
XGpioPs_SetIntrTypePin(&extra->my_Gpio, irq_id, trig_level[trig]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register pin specific GPIO interrupt.
|
||||||
|
* @param desc - The GPIO IRQ controller descriptor.
|
||||||
|
* @param irq_id - Pin number.
|
||||||
|
* @param callback_desc - Callback.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_gpio_irq_register_callback(struct irq_ctrl_desc *desc,
|
||||||
|
uint32_t irq_id,
|
||||||
|
struct callback_desc *callback_desc)
|
||||||
|
{
|
||||||
|
struct xil_callback_desc *dev_callback;
|
||||||
|
struct xil_gpio_irq_desc *extra;
|
||||||
|
|
||||||
|
dev_callback = (struct xil_callback_desc *)calloc(1,
|
||||||
|
sizeof(*dev_callback));
|
||||||
|
if(!dev_callback)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
dev_callback->pin_nb = irq_id;
|
||||||
|
dev_callback->callback.legacy_callback = callback_desc->legacy_callback;
|
||||||
|
dev_callback->callback.ctx = callback_desc->ctx;
|
||||||
|
dev_callback->triggered = false;
|
||||||
|
|
||||||
|
extra = desc->extra;
|
||||||
|
XGpioPs_SetDirectionPin(&extra->my_Gpio, irq_id, 0);
|
||||||
|
list_add_last(extra->callback_list, dev_callback);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unregister pin specific GPIO interrupt.
|
||||||
|
* @param desc - The GPIO IRQ controller descriptor.
|
||||||
|
* @param irq_id - Pin number.
|
||||||
|
* @param cb - Callback descriptor.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_gpio_irq_unregister_callback(struct irq_ctrl_desc *desc,
|
||||||
|
uint32_t irq_id, struct callback_desc *cb)
|
||||||
|
{
|
||||||
|
int32_t status;
|
||||||
|
struct xil_gpio_irq_desc *extra;
|
||||||
|
struct xil_callback_desc *dev_callback;
|
||||||
|
struct xil_callback_desc search_callback;
|
||||||
|
|
||||||
|
extra = desc->extra;
|
||||||
|
search_callback.pin_nb = irq_id;
|
||||||
|
status = list_get_find(extra->callback_list, &dev_callback,
|
||||||
|
&search_callback);
|
||||||
|
if(status)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
free(dev_callback);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable specific GPIO IRQ pin.
|
||||||
|
* @param desc - The GPIO IRQ controller descriptor.
|
||||||
|
* @param irq_id - Pin number.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_gpio_irq_enable(struct irq_ctrl_desc *desc, uint32_t irq_id)
|
||||||
|
{
|
||||||
|
int32_t status;
|
||||||
|
struct xil_gpio_irq_desc *extra;
|
||||||
|
struct xil_callback_desc *callback_desc;
|
||||||
|
|
||||||
|
extra = desc->extra;
|
||||||
|
|
||||||
|
status = iterator_move_to_idx(extra->it, 0);
|
||||||
|
while(!status) {
|
||||||
|
iterator_read(extra->it, &callback_desc);
|
||||||
|
status = iterator_move(extra->it, 1);
|
||||||
|
if(callback_desc->pin_nb == irq_id) {
|
||||||
|
callback_desc->enabled = true;
|
||||||
|
XGpioPs_IntrClearPin(&extra->my_Gpio, irq_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XGpioPs_IntrEnablePin(&extra->my_Gpio, irq_id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove the GPIO IRQ controller.
|
||||||
|
* @param desc - The GPIO IRQ controller descriptor.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_gpio_irq_ctrl_remove(struct irq_ctrl_desc *desc)
|
||||||
|
{
|
||||||
|
struct xil_gpio_irq_desc *extra;
|
||||||
|
struct xil_callback_desc *callback_desc;
|
||||||
|
|
||||||
|
if (!desc)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
extra = desc->extra;
|
||||||
|
while (0 == list_get_first(extra->callback_list, &callback_desc))
|
||||||
|
free(callback_desc);
|
||||||
|
|
||||||
|
iterator_remove(extra->it);
|
||||||
|
list_remove(extra->callback_list);
|
||||||
|
free(extra);
|
||||||
|
free(desc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Xilinx platform specific GPIO IRQ platform ops structure
|
||||||
|
*/
|
||||||
|
const struct irq_platform_ops xil_gpio_irq_ops = {
|
||||||
|
.init = &xil_gpio_irq_ctrl_init,
|
||||||
|
.enable = &xil_gpio_irq_enable,
|
||||||
|
.disable = &xil_gpio_irq_disable,
|
||||||
|
.trigger_level_set = &xil_gpio_irq_trigger_level_set,
|
||||||
|
.register_callback = &xil_gpio_irq_register_callback,
|
||||||
|
.unregister_callback = xil_gpio_irq_unregister_callback,
|
||||||
|
.remove = &xil_gpio_irq_ctrl_remove
|
||||||
|
};
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file xilinx_gpio_irq.h
|
||||||
|
* @brief Implementation of Xilinx GPIO IRQ Generic Driver.
|
||||||
|
* @author Porumb Andrei ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2021(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef XILINX_GPIO_IRQ_H_
|
||||||
|
#define XILINX_GPIO_IRQ_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include "stdbool.h"
|
||||||
|
#include "list.h"
|
||||||
|
#include "xgpiops.h"
|
||||||
|
#include "irq.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
/**
|
||||||
|
* @struct xil_callback_desc
|
||||||
|
* @brief Structure holding callback parameters for each pin
|
||||||
|
*/
|
||||||
|
struct xil_callback_desc {
|
||||||
|
int32_t pin_nb;
|
||||||
|
struct callback_desc callback;
|
||||||
|
bool triggered;
|
||||||
|
bool enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct xil_gpio_irq_init_param
|
||||||
|
* @brief Structure holding the initialization parameters for Xilinx platform
|
||||||
|
* specific GPIO IRQ parameters.
|
||||||
|
*/
|
||||||
|
struct xil_gpio_irq_init_param {
|
||||||
|
struct irq_ctrl_desc *parent_desc;
|
||||||
|
int32_t gpio_device_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct xil_gpio_irq_desc
|
||||||
|
* @brief Xilinx platform specific GPIO IRQ descriptor
|
||||||
|
*/
|
||||||
|
struct xil_gpio_irq_desc {
|
||||||
|
struct irq_ctrl_desc *parent_desc;
|
||||||
|
XGpioPs my_Gpio;
|
||||||
|
struct list_desc *callback_list;
|
||||||
|
struct iterator *it;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Xilinx specific GPIO IRQ platform ops structure
|
||||||
|
*/
|
||||||
|
extern const struct irq_platform_ops xil_gpio_irq_ops;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,514 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file xilinx/xilinx_i2c.c
|
||||||
|
* @brief Implementation of Xilinx I2C Generic Driver.
|
||||||
|
* @author Antoniu Miclaus ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <xparameters.h>
|
||||||
|
#ifdef XPAR_XIIC_NUM_INSTANCES
|
||||||
|
#include <xiic.h>
|
||||||
|
#endif
|
||||||
|
#ifdef XPAR_XIICPS_NUM_INSTANCES
|
||||||
|
#include <xiicps.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "error.h"
|
||||||
|
#include "i2c.h"
|
||||||
|
#include "xilinx_i2c.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
static struct list_desc *pl_list = NULL;
|
||||||
|
static struct iterator *pl_it = NULL;
|
||||||
|
|
||||||
|
#ifdef XIICPS_H
|
||||||
|
static struct list_desc *ps_list = NULL;
|
||||||
|
static struct iterator *ps_it = NULL;
|
||||||
|
#endif /* XIICPS_H */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct inst_table_item
|
||||||
|
* @brief Table item for I2C cores already started.
|
||||||
|
*/
|
||||||
|
struct inst_table_item {
|
||||||
|
/** Instance the BSP driver uses for this core. */
|
||||||
|
void *instance;
|
||||||
|
/** Core ID in BSP. */
|
||||||
|
uint32_t device_id;
|
||||||
|
/** Number of ADI driver instances running on this core. */
|
||||||
|
uint32_t inst_no;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef XPAR_XIICPS_NUM_INSTANCES
|
||||||
|
/** Save the current state of the bitrate to not change it each time */
|
||||||
|
static uint32_t ps_last_bitrate = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Xilinx platform specific I2C platform ops structure
|
||||||
|
*/
|
||||||
|
const struct i2c_platform_ops xil_i2c_ops = {
|
||||||
|
.i2c_ops_init = &xil_i2c_init,
|
||||||
|
.i2c_ops_write = &xil_i2c_write,
|
||||||
|
.i2c_ops_read = &xil_i2c_read,
|
||||||
|
.i2c_ops_remove = &xil_i2c_remove
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Definitions *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compare two I2C cores by ID.
|
||||||
|
* @param el1 - First I2C core to compare.
|
||||||
|
* @param el2 - Second I2C core to compare.
|
||||||
|
* @return \ref 0 if the two cores have the same ID,
|
||||||
|
* \ref difference between the first and the second IDs otherwise.
|
||||||
|
*/
|
||||||
|
static int32_t xil_i2c_cmp(void *el1, void *el2)
|
||||||
|
{
|
||||||
|
struct inst_table_item *sel1 = el1, *sel2 = el2;
|
||||||
|
|
||||||
|
return (sel1->device_id - sel2->device_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure slave address and bitrate if needed
|
||||||
|
* @param desc - Descriptor of the I2C device
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
static int32_t xil_i2c_set_transmission_config(struct i2c_desc *desc)
|
||||||
|
{
|
||||||
|
struct xil_i2c_desc *xil_i2c_desc = desc->extra;
|
||||||
|
#ifdef XIICPS_H
|
||||||
|
int32_t ret;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (xil_i2c_desc->type) {
|
||||||
|
case IIC_PL:
|
||||||
|
#ifdef XIIC_H
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
case IIC_PS:
|
||||||
|
#ifdef XIICPS_H
|
||||||
|
if (desc->max_speed_hz != ps_last_bitrate) {
|
||||||
|
ret = XIicPs_SetSClk(xil_i2c_desc->instance, desc->max_speed_hz);
|
||||||
|
if (ret != XST_SUCCESS)
|
||||||
|
return -1;
|
||||||
|
ps_last_bitrate = desc->max_speed_hz;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the I2C communication peripheral.
|
||||||
|
* @param desc - The I2C descriptor.
|
||||||
|
* @param param - The structure that contains the I2C parameters.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_i2c_init(struct i2c_desc **desc,
|
||||||
|
const struct i2c_init_param *param)
|
||||||
|
{
|
||||||
|
int32_t ret;
|
||||||
|
struct i2c_desc *idesc;
|
||||||
|
struct xil_i2c_desc *xdesc;
|
||||||
|
struct xil_i2c_init_param *xinit;
|
||||||
|
|
||||||
|
idesc = (struct i2c_desc *)malloc(sizeof(*idesc));
|
||||||
|
xdesc = (struct xil_i2c_desc *)malloc(sizeof(*xdesc));
|
||||||
|
|
||||||
|
if(!idesc || !xdesc)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
idesc->max_speed_hz = param->max_speed_hz;
|
||||||
|
idesc->slave_address = param->slave_address;
|
||||||
|
xinit = param->extra;
|
||||||
|
|
||||||
|
idesc->extra = xdesc;
|
||||||
|
xdesc->type = xinit->type;
|
||||||
|
xdesc->device_id = xinit->device_id;
|
||||||
|
switch (xinit->type) {
|
||||||
|
case IIC_PL:
|
||||||
|
#ifdef XIIC_H
|
||||||
|
; /** Intentional empty statement */
|
||||||
|
struct inst_table_item tab_check_pl;
|
||||||
|
struct inst_table_item *temp_el_pl;
|
||||||
|
|
||||||
|
if (!pl_list)
|
||||||
|
list_init(&pl_list, LIST_DEFAULT, xil_i2c_cmp);
|
||||||
|
if (!pl_it)
|
||||||
|
iterator_init(&pl_it, pl_list, true);
|
||||||
|
|
||||||
|
tab_check_pl.device_id = xdesc->device_id;
|
||||||
|
|
||||||
|
if (!IS_ERR_VALUE(list_read_find(pl_list, (void **)&temp_el_pl,
|
||||||
|
&tab_check_pl))) {
|
||||||
|
xdesc->instance = temp_el_pl->instance;
|
||||||
|
temp_el_pl->inst_no++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
xdesc->instance = (XIic *)malloc(sizeof(XIic));
|
||||||
|
if(!xdesc->instance)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
xdesc->config = XIic_LookupConfig(xinit->device_id);
|
||||||
|
if(xdesc->config == NULL)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
ret = XIic_CfgInitialize(xdesc->instance,
|
||||||
|
xdesc->config,
|
||||||
|
((XIic_Config*)xdesc->config)
|
||||||
|
->BaseAddress);
|
||||||
|
if(ret != 0)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
ret = XIic_Start(xdesc->instance);
|
||||||
|
if(ret != 0)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
ret = XIic_SetAddress(xdesc->instance,
|
||||||
|
XII_ADDR_TO_SEND_TYPE,
|
||||||
|
param->slave_address);
|
||||||
|
if(ret != 0)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
ret = XIic_SelfTest(xdesc->instance);
|
||||||
|
if(ret < 0)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
ret = XIic_SetGpOutput(xdesc->instance, 1);
|
||||||
|
if(ret < 0)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
temp_el_pl = (struct inst_table_item*)calloc(1, sizeof(*temp_el_pl));
|
||||||
|
temp_el_pl->device_id = xinit->device_id;
|
||||||
|
temp_el_pl->inst_no = 1;
|
||||||
|
temp_el_pl->instance = xdesc->instance;
|
||||||
|
pl_list->push(pl_list, temp_el_pl);
|
||||||
|
|
||||||
|
break;
|
||||||
|
pl_error:
|
||||||
|
free(xdesc->instance);
|
||||||
|
#endif
|
||||||
|
goto error;
|
||||||
|
case IIC_PS:
|
||||||
|
#ifdef XIICPS_H
|
||||||
|
; /** Intentional empty statement */
|
||||||
|
struct inst_table_item tab_check_ps;
|
||||||
|
struct inst_table_item *temp_el_ps;
|
||||||
|
|
||||||
|
if (!pl_list)
|
||||||
|
list_init(&ps_list, LIST_DEFAULT, xil_i2c_cmp);
|
||||||
|
if (!pl_it)
|
||||||
|
iterator_init(&ps_it, ps_list, true);
|
||||||
|
|
||||||
|
tab_check_ps.device_id = xdesc->device_id;
|
||||||
|
|
||||||
|
if (!IS_ERR_VALUE(list_read_find(ps_list,
|
||||||
|
(void **)&temp_el_ps,
|
||||||
|
&tab_check_ps))) {
|
||||||
|
xdesc->instance = temp_el_ps->instance;
|
||||||
|
temp_el_ps->inst_no++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
xdesc->instance = (XIicPs *)malloc(sizeof(XIicPs));
|
||||||
|
if(!xdesc->instance)
|
||||||
|
goto ps_error;
|
||||||
|
|
||||||
|
xdesc->config = XIicPs_LookupConfig(xinit->device_id);
|
||||||
|
if(xdesc->config == NULL)
|
||||||
|
goto ps_error;
|
||||||
|
|
||||||
|
ret = XIicPs_CfgInitialize(xdesc->instance,
|
||||||
|
xdesc->config,
|
||||||
|
((XIicPs_Config*)xdesc->config)
|
||||||
|
->BaseAddress);
|
||||||
|
if(ret != 0)
|
||||||
|
goto ps_error;
|
||||||
|
|
||||||
|
XIicPs_SetSClk(xdesc->instance, param->max_speed_hz);
|
||||||
|
|
||||||
|
temp_el_ps = (struct inst_table_item*)calloc(1, sizeof(*temp_el_ps));
|
||||||
|
temp_el_ps->device_id = xinit->device_id;
|
||||||
|
temp_el_ps->inst_no = 1;
|
||||||
|
temp_el_ps->instance = xdesc->instance;
|
||||||
|
ps_list->push(ps_list, temp_el_ps);
|
||||||
|
|
||||||
|
break;
|
||||||
|
ps_error:
|
||||||
|
free(xdesc->instance);
|
||||||
|
#endif
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto error;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*desc = idesc;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
free(idesc);
|
||||||
|
free(xdesc);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free the resources allocated by i2c_init().
|
||||||
|
* @param desc - The I2C descriptor.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_i2c_remove(struct i2c_desc *desc)
|
||||||
|
{
|
||||||
|
struct xil_i2c_desc *xdesc;
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
xdesc = desc->extra;
|
||||||
|
|
||||||
|
switch (xdesc->type) {
|
||||||
|
case IIC_PL:
|
||||||
|
#ifdef XIIC_H
|
||||||
|
; /** Intentional empty statement */
|
||||||
|
struct inst_table_item tab_check_pl;
|
||||||
|
struct inst_table_item *temp_el_pl;
|
||||||
|
tab_check_pl.device_id = xdesc->device_id;
|
||||||
|
ret = iterator_find(pl_it, &tab_check_pl);
|
||||||
|
if (ret != 0)
|
||||||
|
goto error;
|
||||||
|
iterator_read(pl_it, (void **)&temp_el_pl);
|
||||||
|
temp_el_pl->inst_no--;
|
||||||
|
if (temp_el_pl->inst_no != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ret = XIic_Stop(((XIic *)xdesc->instance));
|
||||||
|
|
||||||
|
if(ret != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/** Remove list element */
|
||||||
|
iterator_get(pl_it, (void **)&temp_el_pl);
|
||||||
|
free(temp_el_pl);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
goto error;
|
||||||
|
case IIC_PS:
|
||||||
|
#ifdef XIICPS_H
|
||||||
|
; /** Intentional empty statement */
|
||||||
|
struct inst_table_item tab_check_ps;
|
||||||
|
struct inst_table_item *temp_el_ps;
|
||||||
|
tab_check_ps.device_id = xdesc->device_id;
|
||||||
|
ret = iterator_find(ps_it, &tab_check_ps);
|
||||||
|
if (ret != 0)
|
||||||
|
goto error;
|
||||||
|
iterator_read(ps_it, (void **)&temp_el_ps);
|
||||||
|
temp_el_ps->inst_no--;
|
||||||
|
if (temp_el_ps->inst_no != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/** Remove list element */
|
||||||
|
iterator_get(ps_it, (void **)&temp_el_ps);
|
||||||
|
free(temp_el_ps);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
/* Intended fallthrough */
|
||||||
|
error:
|
||||||
|
default:
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(desc->extra);
|
||||||
|
free(desc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write data to a slave device.
|
||||||
|
* @param desc - The I2C descriptor.
|
||||||
|
* @param data - Buffer that stores the transmission data.
|
||||||
|
* @param bytes_number - Number of bytes to write.
|
||||||
|
* @param stop_bit - Stop condition control.
|
||||||
|
* Example: 0 - A stop condition will not be generated;
|
||||||
|
* 1 - A stop condition will be generated.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_i2c_write(struct i2c_desc *desc,
|
||||||
|
uint8_t *data,
|
||||||
|
uint8_t bytes_number,
|
||||||
|
uint8_t stop_bit)
|
||||||
|
{
|
||||||
|
struct xil_i2c_desc *xdesc;
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
xdesc = desc->extra;
|
||||||
|
|
||||||
|
switch (xdesc->type) {
|
||||||
|
case IIC_PL:
|
||||||
|
#ifdef XIIC_H
|
||||||
|
ret = xil_i2c_set_transmission_config(desc);
|
||||||
|
if (ret != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
XIic_Send(((XIic*)xdesc->instance)->BaseAddress,
|
||||||
|
desc->slave_address,
|
||||||
|
data,
|
||||||
|
bytes_number,
|
||||||
|
stop_bit ? XIIC_STOP : XIIC_REPEATED_START);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
goto error;
|
||||||
|
case IIC_PS:
|
||||||
|
#ifdef XIICPS_H
|
||||||
|
ret = xil_i2c_set_transmission_config(desc);
|
||||||
|
if (ret != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ret = XIicPs_SetOptions(xdesc->instance,
|
||||||
|
stop_bit ? 0 : XIICPS_REP_START_OPTION);
|
||||||
|
if(ret != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
XIicPs_MasterSend(xdesc->instance,
|
||||||
|
data,
|
||||||
|
bytes_number,
|
||||||
|
desc->slave_address);
|
||||||
|
if(ret != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
/* Intended fallthrough */
|
||||||
|
error:
|
||||||
|
default:
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read data from a slave device.
|
||||||
|
* @param desc - The I2C descriptor.
|
||||||
|
* @param data - Buffer that will store the received data.
|
||||||
|
* @param bytes_number - Number of bytes to read.
|
||||||
|
* @param stop_bit - Stop condition control.
|
||||||
|
* Example: 0 - A stop condition will not be generated;
|
||||||
|
* 1 - A stop condition will be generated.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_i2c_read(struct i2c_desc *desc,
|
||||||
|
uint8_t *data,
|
||||||
|
uint8_t bytes_number,
|
||||||
|
uint8_t stop_bit)
|
||||||
|
{
|
||||||
|
struct xil_i2c_desc *xdesc;
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
xdesc = desc->extra;
|
||||||
|
|
||||||
|
switch (xdesc->type) {
|
||||||
|
case IIC_PL:
|
||||||
|
#ifdef XIIC_H
|
||||||
|
ret = xil_i2c_set_transmission_config(desc);
|
||||||
|
if (ret != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ret = XIic_Recv(((XIic*)xdesc->instance)->BaseAddress,
|
||||||
|
desc->slave_address,
|
||||||
|
data,
|
||||||
|
bytes_number,
|
||||||
|
stop_bit ? XIIC_STOP : XIIC_REPEATED_START);
|
||||||
|
if(ret != bytes_number)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
goto error;
|
||||||
|
case IIC_PS:
|
||||||
|
#ifdef XIICPS_H
|
||||||
|
ret = xil_i2c_set_transmission_config(desc);
|
||||||
|
if (ret != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ret = XIicPs_SetOptions(xdesc->instance,
|
||||||
|
stop_bit ? 0 : XIICPS_REP_START_OPTION);
|
||||||
|
if(ret != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
XIicPs_MasterRecv(xdesc->instance,
|
||||||
|
data,
|
||||||
|
bytes_number,
|
||||||
|
desc->slave_address);
|
||||||
|
if(ret != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
/* Intended fallthrough */
|
||||||
|
error:
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* @file xilinx/xilinx_i2c.h
|
||||||
|
* @brief Header containing types used in the i2c driver.
|
||||||
|
* @author scuciurean ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef XILINX_I2C_H_
|
||||||
|
#define XILINX_I2C_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum xil_i2c_type
|
||||||
|
* @brief Xilinx platform architecture sections
|
||||||
|
*/
|
||||||
|
enum xil_i2c_type {
|
||||||
|
/** Programmable Logic */
|
||||||
|
IIC_PL,
|
||||||
|
/** Processing System */
|
||||||
|
IIC_PS
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct xil_i2c_init
|
||||||
|
* @brief Structure holding the initialization parameters for Xilinx platform
|
||||||
|
* specific I2C parameters.
|
||||||
|
*/
|
||||||
|
struct xil_i2c_init_param {
|
||||||
|
/** Xilinx architecture */
|
||||||
|
enum xil_i2c_type type;
|
||||||
|
/** Device ID */
|
||||||
|
uint32_t device_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct xil_i2c_desc
|
||||||
|
* @brief Xilinx platform specific I2C descriptor
|
||||||
|
*/
|
||||||
|
struct xil_i2c_desc {
|
||||||
|
/** Xilinx architecture */
|
||||||
|
enum xil_i2c_type type;
|
||||||
|
/** Device ID */
|
||||||
|
uint32_t device_id;
|
||||||
|
/** Xilinx I2C configuration */
|
||||||
|
void *config;
|
||||||
|
/** Xilinx I2C Instance */
|
||||||
|
void *instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Xilinx platform specific i2c platform ops structure
|
||||||
|
*/
|
||||||
|
extern const struct i2c_platform_ops xil_i2c_ops;
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/* Initialize the I2C communication peripheral. */
|
||||||
|
int32_t xil_i2c_init(struct i2c_desc **desc,
|
||||||
|
const struct i2c_init_param *param);
|
||||||
|
|
||||||
|
/* Free the resources allocated by i2c_init(). */
|
||||||
|
int32_t xil_i2c_remove(struct i2c_desc *desc);
|
||||||
|
|
||||||
|
/* I2C Write data */
|
||||||
|
int32_t xil_i2c_write(struct i2c_desc *desc, uint8_t *data,
|
||||||
|
uint8_t bytes_number, uint8_t stop_bit);
|
||||||
|
|
||||||
|
/* I2C Read data. */
|
||||||
|
int32_t xil_i2c_read(struct i2c_desc *desc, uint8_t *data,
|
||||||
|
uint8_t bytes_number, uint8_t stop_bit);
|
||||||
|
|
||||||
|
#endif // XILINX_I2C_H_
|
||||||
@@ -0,0 +1,433 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file xilinx/xilinx_irq.c
|
||||||
|
* @brief Implementation of Xilinx IRQ Generic Driver.
|
||||||
|
* @author Cristian Pop ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <xparameters.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "error.h"
|
||||||
|
#include "irq.h"
|
||||||
|
#include "xilinx_irq.h"
|
||||||
|
#ifdef XPAR_XSCUGIC_NUM_INSTANCES
|
||||||
|
#include <xscugic.h>
|
||||||
|
#endif
|
||||||
|
#ifdef XPAR_XINTC_NUM_INSTANCES
|
||||||
|
#include <xintc.h>
|
||||||
|
#endif
|
||||||
|
#ifdef XPAR_XTMRCTR_NUM_INSTANCES
|
||||||
|
#include <xtmrctr.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Definitions *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the IRQ interrupts.
|
||||||
|
* @param desc - The IRQ controller descriptor.
|
||||||
|
* @param param - The structure that contains the IRQ parameters.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_irq_ctrl_init(struct irq_ctrl_desc **desc,
|
||||||
|
const struct irq_init_param *param)
|
||||||
|
{
|
||||||
|
int32_t status;
|
||||||
|
struct irq_ctrl_desc *descriptor;
|
||||||
|
struct xil_irq_desc *xil_dev;
|
||||||
|
#ifdef XSCUGIC_H
|
||||||
|
void *config;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
descriptor = (struct irq_ctrl_desc *)calloc(1, sizeof *descriptor);
|
||||||
|
if(!descriptor)
|
||||||
|
return -1;
|
||||||
|
xil_dev = (struct xil_irq_desc *)calloc(1, sizeof *xil_dev);
|
||||||
|
if(!xil_dev) {
|
||||||
|
free(descriptor);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Xil_ExceptionInit();
|
||||||
|
|
||||||
|
descriptor->irq_ctrl_id = param->irq_ctrl_id;
|
||||||
|
descriptor->extra = xil_dev;
|
||||||
|
xil_dev->type = ((struct xil_irq_init_param *)param->extra)->type;
|
||||||
|
|
||||||
|
switch(xil_dev->type) {
|
||||||
|
case IRQ_PS:
|
||||||
|
#ifdef XSCUGIC_H
|
||||||
|
xil_dev->instance = calloc(1, sizeof(XScuGic));
|
||||||
|
if(!xil_dev->instance)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
config = XScuGic_LookupConfig(descriptor->irq_ctrl_id);
|
||||||
|
if(!config)
|
||||||
|
goto ps_error;
|
||||||
|
|
||||||
|
status = XScuGic_CfgInitialize(xil_dev->instance, config,
|
||||||
|
((XScuGic_Config *)config)->CpuBaseAddress);
|
||||||
|
if (status != 0)
|
||||||
|
goto ps_error;
|
||||||
|
|
||||||
|
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
|
||||||
|
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
|
||||||
|
xil_dev->instance);
|
||||||
|
|
||||||
|
break;
|
||||||
|
ps_error:
|
||||||
|
free(xil_dev->instance);
|
||||||
|
#endif
|
||||||
|
goto error;
|
||||||
|
case IRQ_PL:
|
||||||
|
#ifdef XINTC_H
|
||||||
|
xil_dev->instance = calloc(1, sizeof(XIntc));
|
||||||
|
if(!xil_dev->instance)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
status = XIntc_Initialize(xil_dev->instance, descriptor->irq_ctrl_id);
|
||||||
|
if(status != 0)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
status = XIntc_Start(xil_dev->instance, XIN_REAL_MODE);
|
||||||
|
if(status != 0)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
break;
|
||||||
|
pl_error:
|
||||||
|
free(xil_dev->instance);
|
||||||
|
#endif
|
||||||
|
goto error;
|
||||||
|
default:
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*desc = descriptor;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
free(xil_dev);
|
||||||
|
free(descriptor);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable global interrupts.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_irq_global_enable(struct irq_ctrl_desc *desc)
|
||||||
|
{
|
||||||
|
/* Enable interrupts */
|
||||||
|
Xil_ExceptionEnable();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable global interrupts.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_irq_global_disable(struct irq_ctrl_desc *desc)
|
||||||
|
{
|
||||||
|
/* Disable interrupts */
|
||||||
|
Xil_ExceptionDisable();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable specific interrupt.
|
||||||
|
* @param desc - The IRQ controller descriptor.
|
||||||
|
* @param irq_id - Interrupt identifier.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_irq_enable(struct irq_ctrl_desc *desc, uint32_t irq_id)
|
||||||
|
{
|
||||||
|
struct xil_irq_desc *xil_dev = desc->extra;
|
||||||
|
|
||||||
|
switch(xil_dev->type) {
|
||||||
|
case IRQ_PS:
|
||||||
|
#ifdef XSCUGIC_H
|
||||||
|
XScuGic_Enable(xil_dev->instance, irq_id);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case IRQ_PL:
|
||||||
|
#ifdef XINTC_H
|
||||||
|
XIntc_Enable(xil_dev->instance, irq_id);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable specific interrupt.
|
||||||
|
* @param desc - The IRQ controller descriptor.
|
||||||
|
* @param irq_id - Interrupt identifier.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_irq_disable(struct irq_ctrl_desc *desc, uint32_t irq_id)
|
||||||
|
{
|
||||||
|
struct xil_irq_desc *xil_dev = desc->extra;
|
||||||
|
|
||||||
|
switch(xil_dev->type) {
|
||||||
|
case IRQ_PS:
|
||||||
|
#ifdef XSCUGIC_H
|
||||||
|
XScuGic_Disable(xil_dev->instance, irq_id);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case IRQ_PL:
|
||||||
|
#ifdef XINTC_H
|
||||||
|
XIntc_Disable(xil_dev->instance, irq_id);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register a callback to handle the irq events.
|
||||||
|
* @param desc - The IRQ controller descriptor.
|
||||||
|
* @param irq_id - Interrupt identifier.
|
||||||
|
* @param callback_desc - Callback descriptor
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_irq_register_callback(struct irq_ctrl_desc *desc,
|
||||||
|
uint32_t irq_id,
|
||||||
|
struct callback_desc *callback_desc)
|
||||||
|
{
|
||||||
|
struct xil_irq_desc *xil_dev = desc->extra;
|
||||||
|
|
||||||
|
switch(xil_dev->type) {
|
||||||
|
case IRQ_PS:
|
||||||
|
#ifdef XSCUGIC_H
|
||||||
|
return XScuGic_Connect(xil_dev->instance, irq_id,
|
||||||
|
(Xil_InterruptHandler) callback_desc->callback,
|
||||||
|
callback_desc->ctx);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case IRQ_PL:
|
||||||
|
#ifdef XINTC_H
|
||||||
|
if (irq_id == XPAR_AXI_INTC_AXI_TIMER_INTERRUPT_INTR) {
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
ret = XIntc_Connect(xil_dev->instance, irq_id,
|
||||||
|
XTmrCtr_InterruptHandler, callback_desc->legacy_config);
|
||||||
|
if (IS_ERR_VALUE(ret))
|
||||||
|
return -1;
|
||||||
|
XTmrCtr_SetHandler(callback_desc->legacy_config,
|
||||||
|
(XTmrCtr_Handler)callback_desc->callback,
|
||||||
|
callback_desc->ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return XIntc_Connect(xil_dev->instance, irq_id,
|
||||||
|
(XInterruptHandler) callback_desc->callback,
|
||||||
|
callback_desc->ctx);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set interrupt trigger level.
|
||||||
|
* @param desc - The IRQ controller descriptor.
|
||||||
|
* @param irq_id - Interrupt identifier.
|
||||||
|
* @param trig - New trigger level for the interrupt.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_irq_trigger_level_set(struct irq_ctrl_desc *desc,
|
||||||
|
uint32_t irq_id,
|
||||||
|
enum irq_trig_level trig)
|
||||||
|
{
|
||||||
|
struct xil_irq_desc *xil_dev = desc->extra;
|
||||||
|
|
||||||
|
if(trig == IRQ_EDGE_BOTH)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch(xil_dev->type) {
|
||||||
|
case IRQ_PS:
|
||||||
|
#ifdef XSCUGIC_H
|
||||||
|
;
|
||||||
|
uint8_t priority, trigger;
|
||||||
|
|
||||||
|
XScuGic_GetPriorityTriggerType(xil_dev->instance, irq_id, &priority,
|
||||||
|
&trigger);
|
||||||
|
trigger = trig;
|
||||||
|
XScuGic_SetPriorityTriggerType(xil_dev->instance, irq_id, priority,
|
||||||
|
trigger);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case IRQ_PL:
|
||||||
|
#ifdef XINTC_H
|
||||||
|
/* Interrupt trigger determined in hardware. TODO: verify */
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set interrupt trigger level.
|
||||||
|
* @param desc - The IRQ controller descriptor.
|
||||||
|
* @param irq_id - Interrupt identifier.
|
||||||
|
* @param priority_level - New priority level for the interrupt.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_irq_set_priority(struct irq_ctrl_desc *desc,
|
||||||
|
uint32_t irq_id,
|
||||||
|
uint32_t priority_level)
|
||||||
|
{
|
||||||
|
struct xil_irq_desc *xil_dev = desc->extra;
|
||||||
|
|
||||||
|
if(priority_level % 8 != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch(xil_dev->type) {
|
||||||
|
case IRQ_PS:
|
||||||
|
#ifdef XSCUGIC_H
|
||||||
|
;
|
||||||
|
uint8_t priority, trigger;
|
||||||
|
|
||||||
|
XScuGic_GetPriorityTriggerType(xil_dev->instance, irq_id, &priority,
|
||||||
|
&trigger);
|
||||||
|
priority = priority_level;
|
||||||
|
XScuGic_SetPriorityTriggerType(xil_dev->instance, irq_id, priority,
|
||||||
|
trigger);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case IRQ_PL:
|
||||||
|
#ifdef XINTC_H
|
||||||
|
/* Interrupt priority level determined in hardware. TODO: verify */
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unregisters a generic IRQ handling function.
|
||||||
|
* @param desc - The IRQ controller descriptor.
|
||||||
|
* @param irq_id - Interrupt identifier.
|
||||||
|
* @param cb - Callback descriptor.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_irq_unregister_callback(struct irq_ctrl_desc *desc,
|
||||||
|
uint32_t irq_id, struct callback_desc *cb)
|
||||||
|
{
|
||||||
|
struct xil_irq_desc *xil_dev = desc->extra;
|
||||||
|
|
||||||
|
switch(xil_dev->type) {
|
||||||
|
case IRQ_PS:
|
||||||
|
#ifdef XSCUGIC_H
|
||||||
|
XScuGic_Disconnect(xil_dev->instance, irq_id);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case IRQ_PL:
|
||||||
|
#ifdef XINTC_H
|
||||||
|
XIntc_Disconnect(xil_dev->instance, irq_id);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free the resources allocated by irq_ctrl_init().
|
||||||
|
* @param desc - The IRQ control descriptor.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_irq_ctrl_remove(struct irq_ctrl_desc *desc)
|
||||||
|
{
|
||||||
|
struct xil_irq_desc *xil_dev = desc->extra;
|
||||||
|
free(xil_dev->instance);
|
||||||
|
free(desc->extra);
|
||||||
|
free(desc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Xilinx platform specific IRQ platform ops structure
|
||||||
|
*/
|
||||||
|
const struct irq_platform_ops xil_irq_ops = {
|
||||||
|
.init = &xil_irq_ctrl_init,
|
||||||
|
.register_callback = &xil_irq_register_callback,
|
||||||
|
.unregister_callback = &xil_irq_unregister_callback,
|
||||||
|
.global_enable = &xil_irq_global_enable,
|
||||||
|
.global_disable = &xil_irq_global_disable,
|
||||||
|
.trigger_level_set = &xil_irq_trigger_level_set,
|
||||||
|
.set_priority = &xil_irq_set_priority,
|
||||||
|
.enable = &xil_irq_enable,
|
||||||
|
.disable = &xil_irq_disable,
|
||||||
|
.remove = &xil_irq_ctrl_remove
|
||||||
|
};
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* @file xilinx_irq.h
|
||||||
|
* @brief Header containing types used in the irq driver.
|
||||||
|
* @author Cristian Pop ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef XILINX_IRQ_H_
|
||||||
|
#define XILINX_IRQ_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "irq.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum xil_irq_type
|
||||||
|
* @brief Xilinx platform architecture sections
|
||||||
|
*/
|
||||||
|
enum xil_irq_type {
|
||||||
|
/** Programmable Logic */
|
||||||
|
IRQ_PL,
|
||||||
|
/** Processing System */
|
||||||
|
IRQ_PS
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct xil_irq_init_param
|
||||||
|
* @brief Structure holding the initialization parameters for Xilinx platform
|
||||||
|
* specific IRQ parameters.
|
||||||
|
*/
|
||||||
|
struct xil_irq_init_param {
|
||||||
|
/** Xilinx architecture */
|
||||||
|
enum xil_irq_type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct xil_irq_desc
|
||||||
|
* @brief Xilinx platform specific IRQ descriptor
|
||||||
|
*/
|
||||||
|
struct xil_irq_desc {
|
||||||
|
/** Xilinx architecture */
|
||||||
|
enum xil_irq_type type;
|
||||||
|
/** Xilinx IRQ Instance */
|
||||||
|
void *instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Xilinx specific IRQ platform ops structure
|
||||||
|
*/
|
||||||
|
extern const struct irq_platform_ops xil_irq_ops;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,462 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file xilinx/xilinx_spi.c
|
||||||
|
* @brief Implementation of Xilinx SPI Generic Driver.
|
||||||
|
* @author Antoniu Miclaus ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <xparameters.h>
|
||||||
|
#ifdef XPAR_XSPI_NUM_INSTANCES
|
||||||
|
#include <xspi.h>
|
||||||
|
#endif
|
||||||
|
#ifdef XPAR_XSPIPS_NUM_INSTANCES
|
||||||
|
#include <xspips.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "error.h"
|
||||||
|
#include "spi.h"
|
||||||
|
#include "xilinx_spi.h"
|
||||||
|
|
||||||
|
#if defined(PLATFORM_ZYNQ)
|
||||||
|
#define SPI_CLK_FREQ_HZ(dev) (XPAR_PS7_SPI_ ## dev ## _SPI_CLK_FREQ_HZ)
|
||||||
|
#define SPI_NUM_INSTANCES XPAR_XSPIPS_NUM_INSTANCES
|
||||||
|
#elif defined(PLATFORM_ZYNQMP)
|
||||||
|
#define SPI_CLK_FREQ_HZ(dev) (XPAR_PSU_SPI_ ## dev ## _SPI_CLK_FREQ_HZ)
|
||||||
|
#define SPI_NUM_INSTANCES XPAR_XSPIPS_NUM_INSTANCES
|
||||||
|
#else
|
||||||
|
#define SPI_NUM_INSTANCES 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#warning SPI delays are not supported on the xilinx platform
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Definitions *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the hardware SPI peripherial
|
||||||
|
*
|
||||||
|
* @param xdesc Platform specific SPI descriptor
|
||||||
|
* @param xinit Platform specific SPI init param
|
||||||
|
* @return int32_t -1 if the device couldn't be found or configured
|
||||||
|
*/
|
||||||
|
static int32_t spi_init_pl(struct spi_desc *desc,
|
||||||
|
const struct spi_init_param *param)
|
||||||
|
{
|
||||||
|
#ifdef XSPI_H
|
||||||
|
int32_t ret;
|
||||||
|
struct xil_spi_desc *xdesc;
|
||||||
|
struct xil_spi_init_param *xinit;
|
||||||
|
|
||||||
|
xdesc = (struct xil_spi_desc*)malloc(sizeof(struct xil_spi_desc));
|
||||||
|
if(!xdesc) {
|
||||||
|
free(xdesc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc->extra = xdesc;
|
||||||
|
xinit = param->extra;
|
||||||
|
xdesc->type = xinit->type;
|
||||||
|
xdesc->flags = xinit->flags;
|
||||||
|
|
||||||
|
xdesc->instance = (XSpi*)calloc(1, sizeof(XSpi));
|
||||||
|
if(!xdesc->instance)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
xdesc->config = XSpi_LookupConfig(param->device_id);
|
||||||
|
if(xdesc->config == NULL)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
ret = XSpi_CfgInitialize(xdesc->instance,
|
||||||
|
xdesc->config,
|
||||||
|
((XSpi_Config*)xdesc->config)
|
||||||
|
->BaseAddress);
|
||||||
|
if(ret != 0)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
ret = XSpi_Initialize(xdesc->instance, param->device_id);
|
||||||
|
if (ret != 0)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
ret = XSpi_SetOptions(xdesc->instance,
|
||||||
|
XSP_MASTER_OPTION |
|
||||||
|
((desc->mode & SPI_CPOL) ?
|
||||||
|
XSP_CLK_ACTIVE_LOW_OPTION : 0) |
|
||||||
|
((desc->mode & SPI_CPHA) ?
|
||||||
|
XSP_CLK_PHASE_1_OPTION : 0));
|
||||||
|
if (ret != 0)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
ret = XSpi_Start(xdesc->instance);
|
||||||
|
if (ret != 0)
|
||||||
|
goto pl_error;
|
||||||
|
|
||||||
|
XSpi_IntrGlobalDisable((XSpi *)(xdesc->instance));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
pl_error:
|
||||||
|
free(xdesc->instance);
|
||||||
|
free(xdesc);
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the hardware SPI peripherial
|
||||||
|
*
|
||||||
|
* @param xdesc Platform specific SPI descriptor
|
||||||
|
* @param xinit Platform specific SPI init param
|
||||||
|
* @return int32_t -1 if the device couldn't be found or configured
|
||||||
|
*/
|
||||||
|
static int32_t spi_init_ps(struct spi_desc *desc,
|
||||||
|
const struct spi_init_param *param)
|
||||||
|
{
|
||||||
|
#ifdef XSPIPS_H
|
||||||
|
int32_t ret;
|
||||||
|
struct xil_spi_desc *xdesc;
|
||||||
|
struct xil_spi_init_param *xinit;
|
||||||
|
const uint32_t prescaler_default = XSPIPS_CLK_PRESCALE_64;
|
||||||
|
const uint32_t prescaler_min = XSPIPS_CLK_PRESCALE_4;
|
||||||
|
const uint32_t prescaler_max = XSPIPS_CLK_PRESCALE_256;
|
||||||
|
uint32_t prescaler = 0u;
|
||||||
|
uint32_t input_clock = 0u;
|
||||||
|
|
||||||
|
xdesc = (struct xil_spi_desc*)malloc(sizeof(struct xil_spi_desc));
|
||||||
|
if(!xdesc) {
|
||||||
|
free(xdesc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc->extra = xdesc;
|
||||||
|
xinit = param->extra;
|
||||||
|
xdesc->type = xinit->type;
|
||||||
|
xdesc->flags = xinit->flags;
|
||||||
|
|
||||||
|
xdesc->instance = (XSpiPs*)malloc(sizeof(XSpiPs));
|
||||||
|
if(!xdesc->instance)
|
||||||
|
goto ps_error;
|
||||||
|
|
||||||
|
xdesc->config = XSpiPs_LookupConfig(param->device_id);
|
||||||
|
if(xdesc->config == NULL)
|
||||||
|
goto ps_error;
|
||||||
|
|
||||||
|
ret = XSpiPs_CfgInitialize(xdesc->instance,
|
||||||
|
xdesc->config,
|
||||||
|
((XSpiPs_Config*)xdesc->config)
|
||||||
|
->BaseAddress);
|
||||||
|
if(ret != 0)
|
||||||
|
goto ps_error;
|
||||||
|
|
||||||
|
switch (param->device_id) {
|
||||||
|
#if (SPI_NUM_INSTANCES >= 1)
|
||||||
|
case 0:
|
||||||
|
input_clock = SPI_CLK_FREQ_HZ(0);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if (SPI_NUM_INSTANCES >= 2)
|
||||||
|
case 1:
|
||||||
|
input_clock = SPI_CLK_FREQ_HZ(1);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
goto ps_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (desc->max_speed_hz != 0u) {
|
||||||
|
uint32_t div = input_clock / desc->max_speed_hz;
|
||||||
|
uint32_t rem = input_clock % desc->max_speed_hz;
|
||||||
|
uint32_t po2 = !(div & (div - 1)) && !rem;
|
||||||
|
|
||||||
|
// find the power of two just higher than div and
|
||||||
|
// store the exponent in prescaler
|
||||||
|
while(div) {
|
||||||
|
prescaler += 1;
|
||||||
|
div >>= 1u;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this exponent - 1 is needed because of the way
|
||||||
|
// xilinx stores it into registers
|
||||||
|
if (prescaler)
|
||||||
|
prescaler -= 1;
|
||||||
|
|
||||||
|
// this exponent - 1 is needed when initial div was
|
||||||
|
// precisely a power of two
|
||||||
|
if (prescaler && po2)
|
||||||
|
prescaler -= 1;
|
||||||
|
|
||||||
|
if (prescaler < prescaler_min)
|
||||||
|
prescaler = prescaler_min;
|
||||||
|
|
||||||
|
if (prescaler > prescaler_max)
|
||||||
|
prescaler = prescaler_max;
|
||||||
|
} else
|
||||||
|
prescaler = prescaler_default;
|
||||||
|
|
||||||
|
ret = XSpiPs_SetClkPrescaler(xdesc->instance, prescaler);
|
||||||
|
|
||||||
|
if(ret != 0)
|
||||||
|
goto ps_error;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ps_error:
|
||||||
|
free(xdesc->instance);
|
||||||
|
free(xdesc);
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the SPI communication peripheral.
|
||||||
|
* @param desc - The SPI descriptor.
|
||||||
|
* @param param - The structure that contains the SPI parameters.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_spi_init(struct spi_desc **desc,
|
||||||
|
const struct spi_init_param *param)
|
||||||
|
{
|
||||||
|
int32_t ret;
|
||||||
|
enum xil_spi_type *spi_type;
|
||||||
|
|
||||||
|
if (!param) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*desc = malloc(sizeof(**desc));
|
||||||
|
if(! *desc) {
|
||||||
|
free(*desc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_type = param->extra;
|
||||||
|
|
||||||
|
if(!spi_type)
|
||||||
|
goto init_error;
|
||||||
|
|
||||||
|
(*desc)->max_speed_hz = param->max_speed_hz;
|
||||||
|
(*desc)->mode = param->mode;
|
||||||
|
(*desc)->bit_order = param->bit_order;
|
||||||
|
(*desc)->chip_select = param->chip_select;
|
||||||
|
|
||||||
|
switch (*spi_type) {
|
||||||
|
case SPI_PL:
|
||||||
|
ret = spi_init_pl(*desc, param);
|
||||||
|
break;
|
||||||
|
case SPI_PS:
|
||||||
|
ret = spi_init_ps(*desc, param);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto init_error;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
init_error:
|
||||||
|
free(*desc);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free the resources allocated by spi_init().
|
||||||
|
* @param desc - The SPI descriptor.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_spi_remove(struct spi_desc *desc)
|
||||||
|
{
|
||||||
|
#ifdef XSPI_H
|
||||||
|
int32_t ret;
|
||||||
|
#endif
|
||||||
|
struct xil_spi_desc *xdesc = NULL;
|
||||||
|
enum xil_spi_type *spi_type;
|
||||||
|
|
||||||
|
spi_type = desc->extra;
|
||||||
|
|
||||||
|
if(!spi_type)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
switch (*spi_type ) {
|
||||||
|
case SPI_PL:
|
||||||
|
#ifdef XSPI_H
|
||||||
|
xdesc = desc->extra;
|
||||||
|
|
||||||
|
if(!xdesc)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ret = XSpi_Stop((XSpi *)(xdesc->instance));
|
||||||
|
if(ret != 0)
|
||||||
|
goto error;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case SPI_PS:
|
||||||
|
#ifdef XSPIPS_H
|
||||||
|
xdesc = desc->extra;
|
||||||
|
|
||||||
|
if(!xdesc)
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Intended fallthrough */
|
||||||
|
#ifdef XSPI_H
|
||||||
|
error:
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(xdesc)
|
||||||
|
free(xdesc->instance);
|
||||||
|
free(desc->extra);
|
||||||
|
free(desc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write and read data to/from SPI.
|
||||||
|
* @param desc - The SPI descriptor.
|
||||||
|
* @param data - The buffer with the transmitted/received data.
|
||||||
|
* @param bytes_number - Number of bytes to write/read.
|
||||||
|
* @return 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int32_t xil_spi_write_and_read(struct spi_desc *desc,
|
||||||
|
uint8_t *data,
|
||||||
|
uint16_t bytes_number)
|
||||||
|
{
|
||||||
|
int32_t ret;
|
||||||
|
#ifdef XSPI_H
|
||||||
|
uint32_t ctrl_reg;
|
||||||
|
#endif
|
||||||
|
struct xil_spi_desc *xdesc;
|
||||||
|
enum xil_spi_type *spi_type;
|
||||||
|
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
|
spi_type = desc->extra;
|
||||||
|
|
||||||
|
if(!spi_type)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
xdesc = desc->extra;
|
||||||
|
|
||||||
|
switch (*spi_type) {
|
||||||
|
case SPI_PL:
|
||||||
|
#ifdef XSPI_H
|
||||||
|
ret = XSpi_SetOptions(xdesc->instance,
|
||||||
|
XSP_MASTER_OPTION |
|
||||||
|
((desc->mode & SPI_CPOL) ?
|
||||||
|
XSP_CLK_ACTIVE_LOW_OPTION : 0) |
|
||||||
|
((desc->mode & SPI_CPHA) ?
|
||||||
|
XSP_CLK_PHASE_1_OPTION : 0));
|
||||||
|
if (ret != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
ctrl_reg = XSpi_GetControlReg(((XSpi*)xdesc->instance));
|
||||||
|
if (desc->bit_order == SPI_BIT_ORDER_LSB_FIRST)
|
||||||
|
ctrl_reg |= XSP_CR_LSB_MSB_FIRST_MASK;
|
||||||
|
else
|
||||||
|
ctrl_reg &= ~ XSP_CR_LSB_MSB_FIRST_MASK;
|
||||||
|
XSpi_SetControlReg(((XSpi*)xdesc->instance), ctrl_reg);
|
||||||
|
|
||||||
|
ret = XSpi_SetSlaveSelect(xdesc->instance,
|
||||||
|
0x01 << desc->chip_select);
|
||||||
|
if (ret != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
ret = XSpi_Transfer(xdesc->instance,
|
||||||
|
data,
|
||||||
|
data,
|
||||||
|
bytes_number);
|
||||||
|
if (ret != 0)
|
||||||
|
goto error;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case SPI_PS:
|
||||||
|
#ifdef XSPIPS_H
|
||||||
|
ret = XSpiPs_SetOptions(xdesc->instance,
|
||||||
|
XSPIPS_MASTER_OPTION |
|
||||||
|
((xdesc->flags & SPI_CS_DECODE) ?
|
||||||
|
XSPIPS_DECODE_SSELECT_OPTION : 0) |
|
||||||
|
XSPIPS_FORCE_SSELECT_OPTION |
|
||||||
|
((desc->mode & SPI_CPOL) ?
|
||||||
|
XSPIPS_CLK_ACTIVE_LOW_OPTION : 0) |
|
||||||
|
((desc->mode & SPI_CPHA) ?
|
||||||
|
XSPIPS_CLK_PHASE_1_OPTION : 0));
|
||||||
|
if (ret != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
ret = XSpiPs_SetSlaveSelect(xdesc->instance,
|
||||||
|
desc->chip_select);
|
||||||
|
if (ret != 0)
|
||||||
|
goto error;
|
||||||
|
ret = XSpiPs_PolledTransfer(xdesc->instance,
|
||||||
|
data,
|
||||||
|
data,
|
||||||
|
bytes_number);
|
||||||
|
if (ret != 0)
|
||||||
|
goto error;
|
||||||
|
ret = XSpiPs_SetSlaveSelect(xdesc->instance, SPI_DEASSERT_CURRENT_SS);
|
||||||
|
if (ret != 0)
|
||||||
|
goto error;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
error:
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Xilinx platform specific SPI platform ops structure
|
||||||
|
*/
|
||||||
|
const struct spi_platform_ops xil_spi_ops = {
|
||||||
|
.init = &xil_spi_init,
|
||||||
|
.write_and_read = &xil_spi_write_and_read,
|
||||||
|
.remove = &xil_spi_remove
|
||||||
|
};
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* @file xilinx/xilinx_spi.h
|
||||||
|
* @brief Header containing extra types used in the spi driver.
|
||||||
|
* @author scuciurean ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef XILINX_SPI_H_
|
||||||
|
#define XILINX_SPI_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "spi.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/********************** Macros and Constants Definitions **********************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#define SPI_CS_DECODE 0x01
|
||||||
|
#define SPI_DEASSERT_CURRENT_SS 0x0F
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum xil_spi_type
|
||||||
|
* @brief Xilinx platform architecture sections
|
||||||
|
*/
|
||||||
|
enum xil_spi_type {
|
||||||
|
/** Programmable Logic */
|
||||||
|
SPI_PL,
|
||||||
|
/** Processing System */
|
||||||
|
SPI_PS,
|
||||||
|
/** SPI Engine */
|
||||||
|
SPI_ENGINE
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct xil_spi_init_param
|
||||||
|
* @brief Structure holding the initialization parameters for Xilinx platform
|
||||||
|
* specific SPI parameters when using xil_spi_ops.
|
||||||
|
*/
|
||||||
|
struct xil_spi_init_param {
|
||||||
|
/** Xilinx architecture */
|
||||||
|
enum xil_spi_type type;
|
||||||
|
/** SPI flags */
|
||||||
|
uint32_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct xil_spi_desc
|
||||||
|
* @brief Xilinx platform specific SPI descriptor
|
||||||
|
*/
|
||||||
|
struct xil_spi_desc {
|
||||||
|
/** Xilinx architecture */
|
||||||
|
enum xil_spi_type type;
|
||||||
|
/** SPI flags */
|
||||||
|
uint32_t flags;
|
||||||
|
/** SPI configuration */
|
||||||
|
void *config;
|
||||||
|
/** SPI instance */
|
||||||
|
void *instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SPI engine platform ops structure
|
||||||
|
*/
|
||||||
|
extern const struct spi_platform_ops spi_eng_platform_ops;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Xilinx specific SPI platform ops structure
|
||||||
|
*/
|
||||||
|
extern const struct spi_platform_ops xil_spi_ops;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Xilinx SPI PS register functions. No extra param needed
|
||||||
|
*/
|
||||||
|
extern const struct spi_platform_ops xil_spi_pl_ops;
|
||||||
|
|
||||||
|
#endif // XILINX_SPI_H_
|
||||||
@@ -0,0 +1,533 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* @file xilinx/xilinx_spi_pl.c
|
||||||
|
* @brief Driver for spi pl device using registers
|
||||||
|
* @author Mihail Chindris ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2021(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <xparameters.h>
|
||||||
|
|
||||||
|
#ifdef XPAR_XSPI_NUM_INSTANCES
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <xspi.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "spi.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "delay.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "alloc.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/********************** Macros and Constants Definitions **********************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#define XPS_TYPE_WRITE 0x1
|
||||||
|
#define XPS_TYPE_READ 0x2
|
||||||
|
#define XSP_DEFAULT_SR_VALUE 0x25
|
||||||
|
#define XSP_DUMMY_DATA 0xFF
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used to store current spi device configuration in order to not update it for
|
||||||
|
* each spi transaction if not needed.
|
||||||
|
*/
|
||||||
|
static struct spi_desc g_spi_desc[XPAR_XSPI_NUM_INSTANCES];
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/* Xilinx PL spi specific data */
|
||||||
|
struct xspi_desc {
|
||||||
|
uint32_t base_addr;
|
||||||
|
uint32_t disable_slaves_mask;
|
||||||
|
uint32_t fifo_depth;
|
||||||
|
uint8_t cs_asserted;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Structure used to iterate over SPI messages */
|
||||||
|
struct msg_iter {
|
||||||
|
struct spi_msg *msgs;
|
||||||
|
uint32_t len;
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t buff_i;
|
||||||
|
uint8_t is_wr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Definitions *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/* Read device register */
|
||||||
|
static inline uint32_t _read(struct xspi_desc *xdesc, uint32_t reg)
|
||||||
|
{
|
||||||
|
return Xil_In32(xdesc->base_addr + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write device register */
|
||||||
|
static inline void _write(struct xspi_desc *xdesc, uint32_t reg, uint32_t val)
|
||||||
|
{
|
||||||
|
Xil_Out32(xdesc->base_addr + reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update device register. Only bits set to 1 in mask will be modified */
|
||||||
|
static inline void _wr_mask(struct xspi_desc *xdesc, uint32_t reg,
|
||||||
|
uint32_t val, uint32_t mask)
|
||||||
|
{
|
||||||
|
uint32_t tmp;
|
||||||
|
|
||||||
|
tmp = _read(xdesc, reg);
|
||||||
|
tmp &= ~mask;
|
||||||
|
tmp |= val & mask;
|
||||||
|
_write(xdesc, reg, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update spi device configuration if needed */
|
||||||
|
static void _update_mode(struct spi_desc *desc)
|
||||||
|
{
|
||||||
|
uint32_t val;
|
||||||
|
uint32_t mask;
|
||||||
|
|
||||||
|
if (desc->mode == g_spi_desc[desc->device_id].mode &&
|
||||||
|
desc->bit_order == g_spi_desc[desc->device_id].bit_order)
|
||||||
|
return ;
|
||||||
|
|
||||||
|
/* Update mode */
|
||||||
|
val = desc->mode | SPI_CPOL ? XSP_CR_CLK_POLARITY_MASK : 0;
|
||||||
|
val |= desc->mode | SPI_CPHA ? XSP_CR_CLK_PHASE_MASK : 0;
|
||||||
|
mask = XSP_CR_CLK_POLARITY_MASK | XSP_CR_CLK_PHASE_MASK;
|
||||||
|
|
||||||
|
val |= desc->bit_order == SPI_BIT_ORDER_LSB_FIRST ?
|
||||||
|
XSP_CR_LSB_MSB_FIRST_MASK : 0;
|
||||||
|
mask |= XSP_CR_LSB_MSB_FIRST_MASK;
|
||||||
|
|
||||||
|
_wr_mask(desc->extra, XSP_CR_OFFSET, val, mask);
|
||||||
|
g_spi_desc[desc->device_id] = *desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure SPI PL device */
|
||||||
|
static int32_t _xil_spi_init_dev(struct xspi_desc *xdesc)
|
||||||
|
{
|
||||||
|
uint32_t val;
|
||||||
|
|
||||||
|
/* Software reset */
|
||||||
|
_write(xdesc, XSP_SRR_OFFSET, XSP_SRR_RESET_MASK);
|
||||||
|
mdelay(1);
|
||||||
|
|
||||||
|
/* Check if success reset */
|
||||||
|
val = _read(xdesc, XSP_SR_OFFSET);
|
||||||
|
if (val != XSP_DEFAULT_SR_VALUE)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
/* Disable interrupts. Drivers only works with pooled mode */
|
||||||
|
_write(xdesc, XSP_IIER_OFFSET, 0);
|
||||||
|
|
||||||
|
/* Deasert chip selects */
|
||||||
|
_write(xdesc, XSP_SSR_OFFSET, 0xFFFFFFFF);
|
||||||
|
|
||||||
|
/* Get fifo depth */
|
||||||
|
while (!(_read(xdesc, XSP_SR_OFFSET) & XSP_SR_TX_FULL_MASK))
|
||||||
|
_write(xdesc, XSP_DTR_OFFSET, XSP_DUMMY_DATA);
|
||||||
|
xdesc->fifo_depth = _read(xdesc, XSP_TFO_OFFSET) + 1;
|
||||||
|
|
||||||
|
/* Configure spi device */
|
||||||
|
val = XSP_CR_ENABLE_MASK |
|
||||||
|
XSP_CR_MANUAL_SS_MASK |
|
||||||
|
XSP_CR_TXFIFO_RESET_MASK |
|
||||||
|
XSP_CR_RXFIFO_RESET_MASK |
|
||||||
|
XSP_CR_MASTER_MODE_MASK |
|
||||||
|
XSP_CR_TRANS_INHIBIT_MASK;
|
||||||
|
|
||||||
|
_write(xdesc, XSP_CR_OFFSET, val);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize spi_desc structure and device */
|
||||||
|
static int32_t xil_spi_init_pl(struct spi_desc **desc,
|
||||||
|
const struct spi_init_param *param)
|
||||||
|
{
|
||||||
|
struct spi_desc *ldesc;
|
||||||
|
struct xspi_desc *xdesc;
|
||||||
|
int32_t err;
|
||||||
|
XSpi_Config *cfg;
|
||||||
|
|
||||||
|
if (!desc || !param || param->device_id >= XPAR_XSPI_NUM_INSTANCES)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
cfg = XSpi_LookupConfig(param->device_id);
|
||||||
|
if (!cfg)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (param->chip_select > cfg->NumSlaveBits)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ldesc = (struct spi_desc *)calloc(1, sizeof(*ldesc));
|
||||||
|
if (!ldesc)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
xdesc = (struct xspi_desc *)calloc(1, sizeof(*xdesc));
|
||||||
|
if (!xdesc) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ldesc->bit_order = param->bit_order;
|
||||||
|
ldesc->chip_select = param->chip_select;
|
||||||
|
ldesc->mode = param->mode;
|
||||||
|
xdesc->base_addr = cfg->BaseAddress;
|
||||||
|
xdesc->disable_slaves_mask = (1 << cfg->NumSlaveBits) - 1;
|
||||||
|
xdesc->cs_asserted = 0;
|
||||||
|
|
||||||
|
err = _xil_spi_init_dev(xdesc);
|
||||||
|
if (IS_ERR_VALUE(err))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
ldesc->extra = xdesc;
|
||||||
|
*desc = ldesc;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
free(xdesc);
|
||||||
|
free(ldesc);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove allocated resources */
|
||||||
|
static int32_t xil_spi_remove_pl(struct spi_desc *desc)
|
||||||
|
{
|
||||||
|
if (!desc)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
free(desc->extra);
|
||||||
|
free(desc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fill fifo until fifo is full or no more data available.
|
||||||
|
* Return the number of written bytes.
|
||||||
|
*/
|
||||||
|
static uint32_t _wr_fifo(struct xspi_desc *xdesc, uint8_t *data,
|
||||||
|
uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t to_write;
|
||||||
|
uint32_t tx_available;
|
||||||
|
|
||||||
|
tx_available = xdesc->fifo_depth - _read(xdesc, XSP_TFO_OFFSET);
|
||||||
|
to_write = min(tx_available, len);
|
||||||
|
for (i = 0; i < to_write; ++i)
|
||||||
|
if (data)
|
||||||
|
_write(xdesc, XSP_DTR_OFFSET, data[i]);
|
||||||
|
else
|
||||||
|
_write(xdesc, XSP_DTR_OFFSET, XSP_DUMMY_DATA);
|
||||||
|
|
||||||
|
return to_write;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read fifo until fifo is empty or no more buffer available to read into
|
||||||
|
* Returns the number of read bytes
|
||||||
|
*/
|
||||||
|
static uint32_t _rd_fifo(struct xspi_desc *xdesc, uint8_t *data,
|
||||||
|
uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t rx_available;
|
||||||
|
uint32_t to_read;
|
||||||
|
uint32_t tmp;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
tmp = _read(xdesc, XSP_SR_OFFSET);
|
||||||
|
if (tmp & XSP_SR_RX_EMPTY_MASK)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rx_available = _read(xdesc, XSP_RFO_OFFSET) + 1;
|
||||||
|
to_read = min(rx_available, len);
|
||||||
|
for (i = 0; i < to_read; ++i) {
|
||||||
|
tmp = _read(xdesc, XSP_DRR_OFFSET);
|
||||||
|
if (data)
|
||||||
|
data[i] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return to_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If start is 0 stop transfer, else start it.
|
||||||
|
* CS will be asserted if needed. If different CS othere than the one needed
|
||||||
|
* is asserted. Deassert it and assert correct one */
|
||||||
|
static void _xil_spi_start_transfer(struct spi_desc *desc, uint8_t start)
|
||||||
|
{
|
||||||
|
struct xspi_desc *xdesc;
|
||||||
|
|
||||||
|
xdesc = desc->extra;
|
||||||
|
if (start) {
|
||||||
|
if (xdesc->cs_asserted) {
|
||||||
|
if (desc->chip_select ==
|
||||||
|
g_spi_desc[desc->device_id].chip_select)
|
||||||
|
return ;
|
||||||
|
else
|
||||||
|
/* Stop transfer to start again with new CS */
|
||||||
|
_xil_spi_start_transfer(desc, 0);
|
||||||
|
}
|
||||||
|
_write(xdesc, XSP_SSR_OFFSET, ~(1 << desc->chip_select));
|
||||||
|
_wr_mask(xdesc, XSP_CR_OFFSET, 0, XSP_CR_TRANS_INHIBIT_MASK);
|
||||||
|
} else {
|
||||||
|
_wr_mask(xdesc, XSP_CR_OFFSET, XSP_CR_TRANS_INHIBIT_MASK,
|
||||||
|
XSP_CR_TRANS_INHIBIT_MASK);
|
||||||
|
_write(xdesc, XSP_SSR_OFFSET, xdesc->disable_slaves_mask);
|
||||||
|
}
|
||||||
|
xdesc->cs_asserted = start;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* SPI polled transfer */
|
||||||
|
static int32_t xil_spi_write_and_read_pl(struct spi_desc *desc,
|
||||||
|
uint8_t *data,
|
||||||
|
uint16_t bytes_number)
|
||||||
|
{
|
||||||
|
struct xspi_desc *xdesc;
|
||||||
|
uint32_t rx;
|
||||||
|
uint32_t tx;
|
||||||
|
|
||||||
|
if (!desc || !desc->extra)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
xdesc = desc->extra;
|
||||||
|
_update_mode(desc);
|
||||||
|
|
||||||
|
_xil_spi_start_transfer(desc, 1);
|
||||||
|
rx = 0;
|
||||||
|
tx = 0;
|
||||||
|
while (rx < bytes_number) {
|
||||||
|
if (tx < bytes_number)
|
||||||
|
tx += _wr_fifo(xdesc, data + tx, bytes_number - tx);
|
||||||
|
rx += _rd_fifo(xdesc, data + rx, bytes_number - rx);
|
||||||
|
}
|
||||||
|
_xil_spi_start_transfer(desc, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get type of message. It can be READ, WRITE or both */
|
||||||
|
static uint32_t _get_msg_type(struct spi_msg *msg)
|
||||||
|
{
|
||||||
|
uint32_t type;
|
||||||
|
|
||||||
|
type = 0;
|
||||||
|
if (msg->tx_buff)
|
||||||
|
type |= XPS_TYPE_WRITE;
|
||||||
|
if (msg->rx_buff)
|
||||||
|
type |= XPS_TYPE_READ;
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get information based on current iterator position */
|
||||||
|
static void _get_data(struct msg_iter *it, uint8_t **buff, uint32_t *len,
|
||||||
|
uint32_t *type)
|
||||||
|
{
|
||||||
|
struct spi_msg *msg;
|
||||||
|
|
||||||
|
if (it->i == it->len) {
|
||||||
|
*len = 0;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = it->msgs + it->i;
|
||||||
|
if (it->is_wr)
|
||||||
|
*buff = msg->tx_buff;
|
||||||
|
else
|
||||||
|
*buff = msg->rx_buff;
|
||||||
|
|
||||||
|
if (*buff)
|
||||||
|
*buff += it->buff_i;
|
||||||
|
|
||||||
|
*len = msg->bytes_number - it->buff_i;
|
||||||
|
if (type)
|
||||||
|
*type = _get_msg_type(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Increment iterator position with desired length.
|
||||||
|
* If the new position has a different message type, new_type will be set to 1
|
||||||
|
* If a CS change is needed, cs_change is set
|
||||||
|
*/
|
||||||
|
static void _increment_iter(struct msg_iter *it, uint32_t len,
|
||||||
|
uint8_t *cs_change, uint8_t *new_type)
|
||||||
|
{
|
||||||
|
struct spi_msg *msg;
|
||||||
|
uint32_t type;
|
||||||
|
uint32_t extra_len;
|
||||||
|
|
||||||
|
if (!len)
|
||||||
|
return ;
|
||||||
|
|
||||||
|
*cs_change = 0;
|
||||||
|
*new_type = 0;
|
||||||
|
msg = it->msgs + it->i;
|
||||||
|
if (it->buff_i + len > msg->bytes_number)
|
||||||
|
extra_len = it->buff_i + len - msg->bytes_number;
|
||||||
|
else
|
||||||
|
extra_len = 0;
|
||||||
|
len -= extra_len;
|
||||||
|
it->buff_i += len;
|
||||||
|
if (it->buff_i == msg->bytes_number) {
|
||||||
|
type = _get_msg_type(msg);
|
||||||
|
++it->i;
|
||||||
|
it->buff_i = 0;
|
||||||
|
if (cs_change && msg->cs_change)
|
||||||
|
*cs_change = 1;
|
||||||
|
if (new_type)
|
||||||
|
if (it->i == it->len ||
|
||||||
|
type != _get_msg_type(it->msgs + it->i))
|
||||||
|
*new_type = 1;
|
||||||
|
}
|
||||||
|
if (extra_len)
|
||||||
|
_increment_iter(it, extra_len, cs_change, new_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SPI polling transfer of multiple messages.
|
||||||
|
*/
|
||||||
|
static int32_t xil_spi_transfer_pl(struct spi_desc *desc,
|
||||||
|
struct spi_msg *msgs,
|
||||||
|
uint32_t len)
|
||||||
|
|
||||||
|
{
|
||||||
|
struct xspi_desc *xdesc;
|
||||||
|
uint8_t cs_change;
|
||||||
|
uint8_t new_type;
|
||||||
|
struct msg_iter rx = {.msgs = msgs, .len = len, .is_wr = 0};
|
||||||
|
struct msg_iter tx = {.msgs = msgs, .len = len, .is_wr = 1};
|
||||||
|
uint8_t *buff;
|
||||||
|
uint32_t bytes;
|
||||||
|
uint32_t type;
|
||||||
|
/* Bytes to increment rx when only a write transaction is executed */
|
||||||
|
uint32_t to_inc_rx;
|
||||||
|
/* Difference between rx and tx iterators in bytes */
|
||||||
|
uint32_t tx_advance;
|
||||||
|
/* Save bytes sent during a write loop */
|
||||||
|
uint32_t tx_sent;
|
||||||
|
/* Used to loop if need to empty the RX FIFO */
|
||||||
|
uint32_t loop;
|
||||||
|
|
||||||
|
if (!desc || !desc->extra)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
xdesc = desc->extra;
|
||||||
|
_update_mode(desc);
|
||||||
|
|
||||||
|
tx_advance = 0;
|
||||||
|
to_inc_rx = 0;
|
||||||
|
buff = NULL;
|
||||||
|
type = 0;
|
||||||
|
do {
|
||||||
|
_xil_spi_start_transfer(desc, 1);
|
||||||
|
|
||||||
|
tx_sent = 0;
|
||||||
|
/* Writing loop */
|
||||||
|
do {
|
||||||
|
_get_data(&tx, &buff, &bytes, &type);
|
||||||
|
if (type & XPS_TYPE_READ)
|
||||||
|
/*
|
||||||
|
* Do not write more bytes than fifo_depth if
|
||||||
|
* they haven't been read.
|
||||||
|
*/
|
||||||
|
bytes = min(bytes,
|
||||||
|
xdesc->fifo_depth - tx_advance);
|
||||||
|
bytes = _wr_fifo(xdesc, buff, bytes);
|
||||||
|
tx_sent += bytes;
|
||||||
|
_increment_iter(&tx, bytes, &cs_change, &new_type);
|
||||||
|
tx_advance += bytes;
|
||||||
|
} while (!cs_change && !new_type && bytes);
|
||||||
|
|
||||||
|
if (type & XPS_TYPE_READ) {
|
||||||
|
loop = 1;
|
||||||
|
/*
|
||||||
|
* Loop only when no more data to write otherwise read
|
||||||
|
* only available data.
|
||||||
|
*/
|
||||||
|
while (loop) {
|
||||||
|
if (!new_type)
|
||||||
|
loop = 0;
|
||||||
|
_get_data(&rx, &buff, &bytes, NULL);
|
||||||
|
bytes = _rd_fifo(xdesc, buff, bytes);
|
||||||
|
_increment_iter(&rx, bytes, &cs_change, &new_type);
|
||||||
|
tx_advance -= bytes;
|
||||||
|
if (loop && new_type)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Clean RX FIFO if it was only a WRITE message */
|
||||||
|
to_inc_rx += tx_sent;
|
||||||
|
if (new_type) {
|
||||||
|
/* Wait for TX to be sent */
|
||||||
|
while (!(_read(xdesc, XSP_SR_OFFSET) &
|
||||||
|
XSP_SR_TX_EMPTY_MASK))
|
||||||
|
;
|
||||||
|
/* Reset fifo. Only write was performed */
|
||||||
|
_wr_mask(xdesc, XSP_CR_OFFSET,
|
||||||
|
XSP_CR_RXFIFO_RESET_MASK,
|
||||||
|
XSP_CR_RXFIFO_RESET_MASK);
|
||||||
|
|
||||||
|
_increment_iter(&rx, to_inc_rx, NULL, NULL);
|
||||||
|
tx_advance -= to_inc_rx;
|
||||||
|
to_inc_rx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cs_change && rx.i != len) || (!cs_change && rx.i == len))
|
||||||
|
_xil_spi_start_transfer(desc, 0);
|
||||||
|
} while (rx.i < len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct spi_platform_ops xil_spi_pl_ops = {
|
||||||
|
.init = xil_spi_init_pl,
|
||||||
|
.remove = xil_spi_remove_pl,
|
||||||
|
.write_and_read = xil_spi_write_and_read_pl,
|
||||||
|
.transfer = xil_spi_transfer_pl
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // XPAR_XSPI_NUM_INSTANCES
|
||||||
@@ -0,0 +1,456 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file xilinx/xilinx_timer.c
|
||||||
|
* @brief Timer and GIC control module source.
|
||||||
|
* @author Andrei Drimbarean ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2020(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY
|
||||||
|
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <xparameters.h>
|
||||||
|
#include "timer.h"
|
||||||
|
#include "xilinx_timer.h"
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/********************** Macros and Constants Definitions **********************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#if defined(_XPARAMETERS_PS_H_)
|
||||||
|
#define CORE_PRIVATE_TIMER_CLOCK (XPAR_CPU_CORTEXA9_CORE_CLOCK_FREQ_HZ / 2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Definitions *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the current counter value of the timer.
|
||||||
|
* @param [in] desc - Pointer to the device handler.
|
||||||
|
* @param [in] new_val - New value for the timer counter.
|
||||||
|
* @return 0 in case of success, -1 otherwise
|
||||||
|
*/
|
||||||
|
int32_t xilinx_timer_counter_set(struct timer_desc *desc,
|
||||||
|
uint32_t new_val)
|
||||||
|
{
|
||||||
|
struct xil_timer_desc *xdesc;
|
||||||
|
|
||||||
|
if (!desc)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
xdesc = desc->extra;
|
||||||
|
|
||||||
|
switch (xdesc->type) {
|
||||||
|
case TIMER_PS:
|
||||||
|
#ifdef XSCUTIMER_H
|
||||||
|
XScuTimer_LoadTimer((XScuTimer *)xdesc->instance, new_val - 1);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
case TIMER_PL:
|
||||||
|
#ifdef XTMRCTR_H
|
||||||
|
XTmrCtr_SetResetValue(xdesc->instance, xdesc->active_tmr, new_val);
|
||||||
|
XTmrCtr_Reset(xdesc->instance, xdesc->active_tmr);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the timer clock frequency.
|
||||||
|
* @param [in] desc - Pointer to the device handler.
|
||||||
|
* @param [in] freq_hz - New timer frequency in hertz.
|
||||||
|
* @return 0 in case of success, -1 otherwise
|
||||||
|
*/
|
||||||
|
int32_t xilinx_timer_count_clk_set(struct timer_desc *desc,
|
||||||
|
uint32_t freq_hz)
|
||||||
|
{
|
||||||
|
struct xil_timer_desc *xdesc;
|
||||||
|
|
||||||
|
if (!desc || !freq_hz)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
xdesc = desc->extra;
|
||||||
|
|
||||||
|
switch (xdesc->type) {
|
||||||
|
case TIMER_PS:
|
||||||
|
#ifdef XSCUTIMER_H
|
||||||
|
;
|
||||||
|
uint32_t prescaler = CORE_PRIVATE_TIMER_CLOCK / freq_hz;
|
||||||
|
if (prescaler == 0 || prescaler >= 256)
|
||||||
|
return -1;
|
||||||
|
XScuTimer_SetPrescaler(xdesc->instance, prescaler - 1);
|
||||||
|
desc->freq_hz = CORE_PRIVATE_TIMER_CLOCK / prescaler;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
case TIMER_PL:
|
||||||
|
#ifdef XTMRCTR_H
|
||||||
|
(void *)xdesc;
|
||||||
|
/** Cannot be done. */
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize hardware timer and the handler structure associated with
|
||||||
|
* it.
|
||||||
|
* @param [out] desc - Pointer to the reference of the device handler.
|
||||||
|
* @param [in] param - Initialization structure.
|
||||||
|
* @return 0 in case of success, -1 otherwise
|
||||||
|
*/
|
||||||
|
int32_t xilinx_timer_init(struct timer_desc **desc,
|
||||||
|
const struct timer_init_param *param)
|
||||||
|
{
|
||||||
|
int32_t ret;
|
||||||
|
struct timer_desc *dev;
|
||||||
|
struct xil_timer_desc *xdesc;
|
||||||
|
struct xil_timer_init_param *xinit;
|
||||||
|
|
||||||
|
if (!desc || !param)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
xinit = param->extra;
|
||||||
|
|
||||||
|
dev = (struct timer_desc *)calloc(1, sizeof(*dev));
|
||||||
|
if(!dev)
|
||||||
|
return -1;
|
||||||
|
xdesc = (struct xil_timer_desc *)calloc(1, sizeof(*xdesc));
|
||||||
|
if(!xdesc)
|
||||||
|
goto error_desc;
|
||||||
|
|
||||||
|
dev->id = param->id;
|
||||||
|
dev->freq_hz = param->freq_hz;
|
||||||
|
dev->ticks_count = param->ticks_count;
|
||||||
|
dev->extra = xdesc;
|
||||||
|
xdesc->active_tmr = xinit->active_tmr;
|
||||||
|
xdesc->type = xinit->type;
|
||||||
|
|
||||||
|
switch (xdesc->type) {
|
||||||
|
case TIMER_PS:
|
||||||
|
#ifdef XSCUTIMER_H
|
||||||
|
xdesc->config = XScuTimer_LookupConfig(dev->id);
|
||||||
|
xdesc->instance = calloc(1, sizeof(XScuTimer));
|
||||||
|
if (!xdesc->instance)
|
||||||
|
goto error_xdesc;
|
||||||
|
ret = XScuTimer_CfgInitialize(xdesc->instance, xdesc->config,
|
||||||
|
((XScuTimer_Config *)xdesc->config)->BaseAddr);
|
||||||
|
if (ret != XST_SUCCESS) {
|
||||||
|
free(xdesc->instance);
|
||||||
|
goto error_xdesc;
|
||||||
|
}
|
||||||
|
ret = xilinx_timer_count_clk_set(dev, param->freq_hz);
|
||||||
|
if (IS_ERR_VALUE(ret))
|
||||||
|
goto error_xdesc;
|
||||||
|
|
||||||
|
ret = xilinx_timer_counter_set(dev, dev->ticks_count);
|
||||||
|
if (IS_ERR_VALUE(ret))
|
||||||
|
goto error_xdesc;
|
||||||
|
|
||||||
|
XScuTimer_EnableAutoReload((XScuTimer *)xdesc->instance);
|
||||||
|
XScuTimer_EnableInterrupt((XScuTimer *)xdesc->instance);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
goto error_xdesc;
|
||||||
|
case TIMER_PL:
|
||||||
|
#ifdef XTMRCTR_H
|
||||||
|
xdesc->instance = (XTmrCtr *)calloc(1, sizeof(XTmrCtr));
|
||||||
|
if (!xdesc->instance)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
xdesc->config = XTmrCtr_LookupConfig(dev->id);
|
||||||
|
if (!xdesc->config) {
|
||||||
|
free(xdesc->instance);
|
||||||
|
goto error_desc;
|
||||||
|
}
|
||||||
|
XTmrCtr_CfgInitialize(xdesc->instance, xdesc->config,
|
||||||
|
((XTmrCtr_Config *)xdesc->config)->BaseAddress);
|
||||||
|
ret = XTmrCtr_InitHw(xdesc->instance);
|
||||||
|
if (ret != 0) {
|
||||||
|
free(xdesc->instance);
|
||||||
|
goto error_desc;
|
||||||
|
}
|
||||||
|
dev->freq_hz = ((XTmrCtr_Config *)xdesc->config)->SysClockFreqHz;
|
||||||
|
|
||||||
|
ret = XTmrCtr_SelfTest(xdesc->instance, dev->id);
|
||||||
|
if(ret != 0)
|
||||||
|
goto error_desc;
|
||||||
|
XTmrCtr_SetOptions(xdesc->instance, xdesc->active_tmr,
|
||||||
|
XTC_DOWN_COUNT_OPTION | XTC_INT_MODE_OPTION |
|
||||||
|
XTC_AUTO_RELOAD_OPTION);
|
||||||
|
XTmrCtr_SetResetValue(xdesc->instance, xdesc->active_tmr,
|
||||||
|
dev->ticks_count);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
goto error_xdesc;
|
||||||
|
default:
|
||||||
|
goto error_xdesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
*desc = dev;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_xdesc:
|
||||||
|
free(xdesc);
|
||||||
|
error_desc:
|
||||||
|
free(dev);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free the memory allocated by timer_setup().
|
||||||
|
* @param [in] desc - Pointer to the device handler.
|
||||||
|
* @return 0 in case of success, -1 otherwise
|
||||||
|
*/
|
||||||
|
int32_t xilinx_timer_remove(struct timer_desc *desc)
|
||||||
|
{
|
||||||
|
struct xil_timer_desc *xdesc;
|
||||||
|
|
||||||
|
if(!desc)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
xdesc = desc->extra;
|
||||||
|
|
||||||
|
switch (xdesc->type) {
|
||||||
|
case TIMER_PS:
|
||||||
|
#ifdef XSCUTIMER_H
|
||||||
|
XScuTimer_Stop(xdesc->instance);
|
||||||
|
free(xdesc->instance);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
case TIMER_PL:
|
||||||
|
#ifdef XTMRCTR_H
|
||||||
|
XTmrCtr_Stop(xdesc->instance, xdesc->active_tmr);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(xdesc);
|
||||||
|
free(desc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start a timer.
|
||||||
|
* @param [in] desc - Pointer to the device handler.
|
||||||
|
* @return 0 in case of success, -1 otherwise
|
||||||
|
*/
|
||||||
|
int32_t xilinx_timer_start(struct timer_desc *desc)
|
||||||
|
{
|
||||||
|
struct xil_timer_desc *xdesc;
|
||||||
|
|
||||||
|
if (!desc)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
xdesc = desc->extra;
|
||||||
|
|
||||||
|
switch (xdesc->type) {
|
||||||
|
case TIMER_PS:
|
||||||
|
#ifdef XSCUTIMER_H
|
||||||
|
XScuTimer_Start(xdesc->instance);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
case TIMER_PL:
|
||||||
|
#ifdef XTMRCTR_H
|
||||||
|
XTmrCtr_Start(xdesc->instance, xdesc->active_tmr);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stop a timer from counting.
|
||||||
|
* @param [in] desc - Pointer to the device handler.
|
||||||
|
* @return 0 in case of success, -1 otherwise
|
||||||
|
*/
|
||||||
|
int32_t xilinx_timer_stop(struct timer_desc *desc)
|
||||||
|
{
|
||||||
|
struct xil_timer_desc *xdesc;
|
||||||
|
|
||||||
|
if (!desc)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
xdesc = desc->extra;
|
||||||
|
|
||||||
|
switch (xdesc->type) {
|
||||||
|
case TIMER_PS:
|
||||||
|
#ifdef XSCUTIMER_H
|
||||||
|
XScuTimer_Stop(xdesc->instance);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
case TIMER_PL:
|
||||||
|
#ifdef XTMRCTR_H
|
||||||
|
XTmrCtr_Stop(xdesc->instance, xdesc->active_tmr);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the current counter value of the timer.
|
||||||
|
* @param [in] desc - Pointer to the device handler.
|
||||||
|
* @param [out] counter - Pointer to the current counter value.
|
||||||
|
* @return 0 in case of success, -1 otherwise
|
||||||
|
*/
|
||||||
|
int32_t xilinx_timer_counter_get(struct timer_desc *desc,
|
||||||
|
uint32_t *counter)
|
||||||
|
{
|
||||||
|
struct xil_timer_desc *xdesc;
|
||||||
|
|
||||||
|
if (!desc || !counter)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
xdesc = desc->extra;
|
||||||
|
|
||||||
|
switch (xdesc->type) {
|
||||||
|
case TIMER_PS:
|
||||||
|
#ifdef XSCUTIMER_H
|
||||||
|
*counter = XScuTimer_GetCounterValue((XScuTimer *)xdesc->instance);
|
||||||
|
++(*counter);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
case TIMER_PL:
|
||||||
|
#ifdef XTMRCTR_H
|
||||||
|
*counter = XTmrCtr_GetValue(xdesc->instance, xdesc->active_tmr);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
*counter = 0;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the timer clock frequency.
|
||||||
|
* @param [in] desc - Pointer to the device handler.
|
||||||
|
* @param [out] freq_hz - Pointer to the returned frequency.
|
||||||
|
* @return 0 in case of success, -1 otherwise
|
||||||
|
*/
|
||||||
|
int32_t xilinx_timer_count_clk_get(struct timer_desc *desc,
|
||||||
|
uint32_t *freq_hz)
|
||||||
|
{
|
||||||
|
struct xil_timer_desc *xdesc;
|
||||||
|
|
||||||
|
if (!desc || !freq_hz)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
xdesc = desc->extra;
|
||||||
|
|
||||||
|
switch (xdesc->type) {
|
||||||
|
case TIMER_PS:
|
||||||
|
#ifdef XSCUTIMER_H
|
||||||
|
*freq_hz = desc->freq_hz;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
case TIMER_PL:
|
||||||
|
#ifdef XTMRCTR_H
|
||||||
|
*freq_hz = ((XTmrCtr_Config *)xdesc->config)->SysClockFreqHz;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
*freq_hz = 0;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the elapsed time in nsec for the timer.
|
||||||
|
* @param [in] desc - Pointer to the device handler.
|
||||||
|
* @param [in] elapsed_time - The elapsed time in nsec.
|
||||||
|
* @return -ENOSYS.
|
||||||
|
*/
|
||||||
|
int32_t xilinx_timer_get_elapsed_time_nsec(struct timer_desc *desc,
|
||||||
|
uint64_t *elapsed_time)
|
||||||
|
{
|
||||||
|
/* Function not implemented */
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Xilinx platform specific timer platform ops structure
|
||||||
|
*/
|
||||||
|
const struct timer_platform_ops xil_timer_ops = {
|
||||||
|
.init = &xilinx_timer_init,
|
||||||
|
.start = &xilinx_timer_start,
|
||||||
|
.stop = &xilinx_timer_stop,
|
||||||
|
.counter_get = &xilinx_timer_counter_get,
|
||||||
|
.counter_set = &xilinx_timer_counter_set,
|
||||||
|
.count_clk_get = &xilinx_timer_count_clk_get,
|
||||||
|
.count_clk_set = &xilinx_timer_count_clk_set,
|
||||||
|
.get_elapsed_time_nsec = &xilinx_timer_get_elapsed_time_nsec,
|
||||||
|
.remove = &xilinx_timer_remove
|
||||||
|
};
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file xilinx_timer.h
|
||||||
|
* @brief Timer control module header.
|
||||||
|
* @author Andrei Drimbarean ([email protected])
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2020(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY
|
||||||
|
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef XILINX_TIMER_H_
|
||||||
|
#define XILINX_TIMER_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <xparameters.h>
|
||||||
|
#ifdef XPAR_XSCUTIMER_NUM_INSTANCES
|
||||||
|
#include <xscutimer.h>
|
||||||
|
#endif
|
||||||
|
#ifdef XPAR_XTMRCTR_NUM_INSTANCES
|
||||||
|
#include <xtmrctr.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum xil_timer_type
|
||||||
|
* @brief Xilinx platform architecture sections
|
||||||
|
*/
|
||||||
|
enum xil_timer_type {
|
||||||
|
/** Programmable Logic */
|
||||||
|
TIMER_PL,
|
||||||
|
/** Processing System */
|
||||||
|
TIMER_PS
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct xil_timer_desc
|
||||||
|
* @brief Xilinx specific timer descriptor
|
||||||
|
*/
|
||||||
|
struct xil_timer_desc {
|
||||||
|
/** Pointer to the BSP driver handler */
|
||||||
|
void *instance;
|
||||||
|
/** Pointer to the BSP driver configuration handler */
|
||||||
|
void *config;
|
||||||
|
/** Timer used from the PL 3-timer core */
|
||||||
|
uint8_t active_tmr;
|
||||||
|
/** Platform selection parameter */
|
||||||
|
enum xil_timer_type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct xil_timer_init_param
|
||||||
|
* @brief Xilinx specific timer initialization structure
|
||||||
|
*/
|
||||||
|
struct xil_timer_init_param {
|
||||||
|
/** Timer used from the PL 3-timer core */
|
||||||
|
uint8_t active_tmr;
|
||||||
|
/** Platform selection parameter */
|
||||||
|
enum xil_timer_type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Xilinx platform specific timer platform ops structure
|
||||||
|
*/
|
||||||
|
extern const struct timer_platform_ops xil_timer_ops;
|
||||||
|
|
||||||
|
#endif /* XILINX_TIMER_H_ */
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,552 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file ad9361_api.h
|
||||||
|
* @brief Header file of AD9361 API Driver.
|
||||||
|
* @author DBogdan (dragos.bogdan@analog.com)
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2013(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef AD9361_API_H_
|
||||||
|
#define AD9361_API_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#include "ad9361_util.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "spi.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
typedef struct {
|
||||||
|
/* Device selection */
|
||||||
|
enum dev_id dev_sel;
|
||||||
|
/* Reference Clock */
|
||||||
|
uint32_t reference_clk_rate;
|
||||||
|
/* Base Configuration */
|
||||||
|
uint8_t two_rx_two_tx_mode_enable; /* adi,2rx-2tx-mode-enable */
|
||||||
|
uint8_t one_rx_one_tx_mode_use_rx_num; /* adi,1rx-1tx-mode-use-rx-num */
|
||||||
|
uint8_t one_rx_one_tx_mode_use_tx_num; /* adi,1rx-1tx-mode-use-tx-num */
|
||||||
|
uint8_t frequency_division_duplex_mode_enable; /* adi,frequency-division-duplex-mode-enable */
|
||||||
|
uint8_t frequency_division_duplex_independent_mode_enable; /* adi,frequency-division-duplex-independent-mode-enable */
|
||||||
|
uint8_t tdd_use_dual_synth_mode_enable; /* adi,tdd-use-dual-synth-mode-enable */
|
||||||
|
uint8_t tdd_skip_vco_cal_enable; /* adi,tdd-skip-vco-cal-enable */
|
||||||
|
uint32_t tx_fastlock_delay_ns; /* adi,tx-fastlock-delay-ns */
|
||||||
|
uint32_t rx_fastlock_delay_ns; /* adi,rx-fastlock-delay-ns */
|
||||||
|
uint8_t rx_fastlock_pincontrol_enable; /* adi,rx-fastlock-pincontrol-enable */
|
||||||
|
uint8_t tx_fastlock_pincontrol_enable; /* adi,tx-fastlock-pincontrol-enable */
|
||||||
|
uint8_t external_rx_lo_enable; /* adi,external-rx-lo-enable */
|
||||||
|
uint8_t external_tx_lo_enable; /* adi,external-tx-lo-enable */
|
||||||
|
uint8_t dc_offset_tracking_update_event_mask; /* adi,dc-offset-tracking-update-event-mask */
|
||||||
|
uint8_t dc_offset_attenuation_high_range; /* adi,dc-offset-attenuation-high-range */
|
||||||
|
uint8_t dc_offset_attenuation_low_range; /* adi,dc-offset-attenuation-low-range */
|
||||||
|
uint8_t dc_offset_count_high_range; /* adi,dc-offset-count-high-range */
|
||||||
|
uint8_t dc_offset_count_low_range; /* adi,dc-offset-count-low-range */
|
||||||
|
uint8_t split_gain_table_mode_enable; /* adi,split-gain-table-mode-enable */
|
||||||
|
uint32_t trx_synthesizer_target_fref_overwrite_hz; /* adi,trx-synthesizer-target-fref-overwrite-hz */
|
||||||
|
uint8_t qec_tracking_slow_mode_enable; /* adi,qec-tracking-slow-mode-enable */
|
||||||
|
/* ENSM Control */
|
||||||
|
uint8_t ensm_enable_pin_pulse_mode_enable; /* adi,ensm-enable-pin-pulse-mode-enable */
|
||||||
|
uint8_t ensm_enable_txnrx_control_enable; /* adi,ensm-enable-txnrx-control-enable */
|
||||||
|
/* LO Control */
|
||||||
|
uint64_t rx_synthesizer_frequency_hz; /* adi,rx-synthesizer-frequency-hz */
|
||||||
|
uint64_t tx_synthesizer_frequency_hz; /* adi,tx-synthesizer-frequency-hz */
|
||||||
|
uint8_t tx_lo_powerdown_managed_enable; /* adi,tx-lo-powerdown-managed-enable */
|
||||||
|
/* Rate & BW Control */
|
||||||
|
uint32_t rx_path_clock_frequencies[6]; /* adi,rx-path-clock-frequencies */
|
||||||
|
uint32_t tx_path_clock_frequencies[6]; /* adi,tx-path-clock-frequencies */
|
||||||
|
uint32_t rf_rx_bandwidth_hz; /* adi,rf-rx-bandwidth-hz */
|
||||||
|
uint32_t rf_tx_bandwidth_hz; /* adi,rf-tx-bandwidth-hz */
|
||||||
|
/* RF Port Control */
|
||||||
|
uint32_t rx_rf_port_input_select; /* adi,rx-rf-port-input-select */
|
||||||
|
uint32_t tx_rf_port_input_select; /* adi,tx-rf-port-input-select */
|
||||||
|
/* TX Attenuation Control */
|
||||||
|
int32_t tx_attenuation_mdB; /* adi,tx-attenuation-mdB */
|
||||||
|
uint8_t update_tx_gain_in_alert_enable; /* adi,update-tx-gain-in-alert-enable */
|
||||||
|
/* Reference Clock Control */
|
||||||
|
uint8_t xo_disable_use_ext_refclk_enable; /* adi,xo-disable-use-ext-refclk-enable */
|
||||||
|
uint32_t dcxo_coarse_and_fine_tune[2]; /* adi,dcxo-coarse-and-fine-tune */
|
||||||
|
uint32_t clk_output_mode_select; /* adi,clk-output-mode-select */
|
||||||
|
/* Gain Control */
|
||||||
|
uint8_t gc_rx1_mode; /* adi,gc-rx1-mode */
|
||||||
|
uint8_t gc_rx2_mode; /* adi,gc-rx2-mode */
|
||||||
|
uint8_t gc_adc_large_overload_thresh; /* adi,gc-adc-large-overload-thresh */
|
||||||
|
uint8_t gc_adc_ovr_sample_size; /* adi,gc-adc-ovr-sample-size */
|
||||||
|
uint8_t gc_adc_small_overload_thresh; /* adi,gc-adc-small-overload-thresh */
|
||||||
|
uint16_t gc_dec_pow_measurement_duration; /* adi,gc-dec-pow-measurement-duration */
|
||||||
|
uint8_t gc_dig_gain_enable; /* adi,gc-dig-gain-enable */
|
||||||
|
uint16_t gc_lmt_overload_high_thresh; /* adi,gc-lmt-overload-high-thresh */
|
||||||
|
uint16_t gc_lmt_overload_low_thresh; /* adi,gc-lmt-overload-low-thresh */
|
||||||
|
uint8_t gc_low_power_thresh; /* adi,gc-low-power-thresh */
|
||||||
|
uint8_t gc_max_dig_gain; /* adi,gc-max-dig-gain */
|
||||||
|
uint8_t gc_use_rx_fir_out_for_dec_pwr_meas_enable; /* adi,gc-use-rx-fir-out-for-dec-pwr-meas-enable */
|
||||||
|
/* Gain MGC Control */
|
||||||
|
uint8_t mgc_dec_gain_step; /* adi,mgc-dec-gain-step */
|
||||||
|
uint8_t mgc_inc_gain_step; /* adi,mgc-inc-gain-step */
|
||||||
|
uint8_t mgc_rx1_ctrl_inp_enable; /* adi,mgc-rx1-ctrl-inp-enable */
|
||||||
|
uint8_t mgc_rx2_ctrl_inp_enable; /* adi,mgc-rx2-ctrl-inp-enable */
|
||||||
|
uint8_t mgc_split_table_ctrl_inp_gain_mode; /* adi,mgc-split-table-ctrl-inp-gain-mode */
|
||||||
|
/* Gain AGC Control */
|
||||||
|
uint8_t agc_adc_large_overload_exceed_counter; /* adi,agc-adc-large-overload-exceed-counter */
|
||||||
|
uint8_t agc_adc_large_overload_inc_steps; /* adi,agc-adc-large-overload-inc-steps - Name is misleading should be dec-steps*/
|
||||||
|
uint8_t agc_adc_lmt_small_overload_prevent_gain_inc_enable; /* adi,agc-adc-lmt-small-overload-prevent-gain-inc-enable */
|
||||||
|
uint8_t agc_adc_small_overload_exceed_counter; /* adi,agc-adc-small-overload-exceed-counter */
|
||||||
|
uint8_t agc_dig_gain_step_size; /* adi,agc-dig-gain-step-size */
|
||||||
|
uint8_t agc_dig_saturation_exceed_counter; /* adi,agc-dig-saturation-exceed-counter */
|
||||||
|
uint32_t agc_gain_update_interval_us; /* adi,agc-gain-update-interval-us */
|
||||||
|
uint8_t agc_immed_gain_change_if_large_adc_overload_enable; /* adi,agc-immed-gain-change-if-large-adc-overload-enable */
|
||||||
|
uint8_t agc_immed_gain_change_if_large_lmt_overload_enable; /* adi,agc-immed-gain-change-if-large-lmt-overload-enable */
|
||||||
|
uint8_t agc_inner_thresh_high; /* adi,agc-inner-thresh-high */
|
||||||
|
uint8_t agc_inner_thresh_high_dec_steps; /* adi,agc-inner-thresh-high-dec-steps */
|
||||||
|
uint8_t agc_inner_thresh_low; /* adi,agc-inner-thresh-low */
|
||||||
|
uint8_t agc_inner_thresh_low_inc_steps; /* adi,agc-inner-thresh-low-inc-steps */
|
||||||
|
uint8_t agc_lmt_overload_large_exceed_counter; /* adi,agc-lmt-overload-large-exceed-counter */
|
||||||
|
uint8_t agc_lmt_overload_large_inc_steps; /* adi,agc-lmt-overload-large-inc-steps */
|
||||||
|
uint8_t agc_lmt_overload_small_exceed_counter; /* adi,agc-lmt-overload-small-exceed-counter */
|
||||||
|
uint8_t agc_outer_thresh_high; /* adi,agc-outer-thresh-high */
|
||||||
|
uint8_t agc_outer_thresh_high_dec_steps; /* adi,agc-outer-thresh-high-dec-steps */
|
||||||
|
uint8_t agc_outer_thresh_low; /* adi,agc-outer-thresh-low */
|
||||||
|
uint8_t agc_outer_thresh_low_inc_steps; /* adi,agc-outer-thresh-low-inc-steps */
|
||||||
|
uint32_t agc_attack_delay_extra_margin_us; /* adi,agc-attack-delay-extra-margin-us */
|
||||||
|
uint8_t agc_sync_for_gain_counter_enable; /* adi,agc-sync-for-gain-counter-enable */
|
||||||
|
/* Fast AGC */
|
||||||
|
uint32_t fagc_dec_pow_measuremnt_duration; /* adi,fagc-dec-pow-measurement-duration */
|
||||||
|
uint32_t fagc_state_wait_time_ns; /* adi,fagc-state-wait-time-ns */
|
||||||
|
/* Fast AGC - Low Power */
|
||||||
|
uint8_t fagc_allow_agc_gain_increase; /* adi,fagc-allow-agc-gain-increase-enable */
|
||||||
|
uint32_t fagc_lp_thresh_increment_time; /* adi,fagc-lp-thresh-increment-time */
|
||||||
|
uint32_t fagc_lp_thresh_increment_steps; /* adi,fagc-lp-thresh-increment-steps */
|
||||||
|
/* Fast AGC - Lock Level (Lock Level is set via slow AGC inner high threshold) */
|
||||||
|
uint8_t fagc_lock_level_lmt_gain_increase_en; /* adi,fagc-lock-level-lmt-gain-increase-enable */
|
||||||
|
uint32_t fagc_lock_level_gain_increase_upper_limit; /* adi,fagc-lock-level-gain-increase-upper-limit */
|
||||||
|
/* Fast AGC - Peak Detectors and Final Settling */
|
||||||
|
uint32_t fagc_lpf_final_settling_steps; /* adi,fagc-lpf-final-settling-steps */
|
||||||
|
uint32_t fagc_lmt_final_settling_steps; /* adi,fagc-lmt-final-settling-steps */
|
||||||
|
uint32_t fagc_final_overrange_count; /* adi,fagc-final-overrange-count */
|
||||||
|
/* Fast AGC - Final Power Test */
|
||||||
|
uint8_t fagc_gain_increase_after_gain_lock_en; /* adi,fagc-gain-increase-after-gain-lock-enable */
|
||||||
|
/* Fast AGC - Unlocking the Gain */
|
||||||
|
uint32_t fagc_gain_index_type_after_exit_rx_mode; /* adi,fagc-gain-index-type-after-exit-rx-mode */
|
||||||
|
uint8_t fagc_use_last_lock_level_for_set_gain_en; /* adi,fagc-use-last-lock-level-for-set-gain-enable */
|
||||||
|
uint8_t fagc_rst_gla_stronger_sig_thresh_exceeded_en; /* adi,fagc-rst-gla-stronger-sig-thresh-exceeded-enable */
|
||||||
|
uint32_t fagc_optimized_gain_offset; /* adi,fagc-optimized-gain-offset */
|
||||||
|
uint32_t fagc_rst_gla_stronger_sig_thresh_above_ll; /* adi,fagc-rst-gla-stronger-sig-thresh-above-ll */
|
||||||
|
uint8_t fagc_rst_gla_engergy_lost_sig_thresh_exceeded_en; /* adi,fagc-rst-gla-engergy-lost-sig-thresh-exceeded-enable */
|
||||||
|
uint8_t fagc_rst_gla_engergy_lost_goto_optim_gain_en; /* adi,fagc-rst-gla-engergy-lost-goto-optim-gain-enable */
|
||||||
|
uint32_t fagc_rst_gla_engergy_lost_sig_thresh_below_ll; /* adi,fagc-rst-gla-engergy-lost-sig-thresh-below-ll */
|
||||||
|
uint32_t fagc_energy_lost_stronger_sig_gain_lock_exit_cnt; /* adi,fagc-energy-lost-stronger-sig-gain-lock-exit-cnt */
|
||||||
|
uint8_t fagc_rst_gla_large_adc_overload_en; /* adi,fagc-rst-gla-large-adc-overload-enable */
|
||||||
|
uint8_t fagc_rst_gla_large_lmt_overload_en; /* adi,fagc-rst-gla-large-lmt-overload-enable */
|
||||||
|
uint8_t fagc_rst_gla_en_agc_pulled_high_en; /* adi,fagc-rst-gla-en-agc-pulled-high-enable */
|
||||||
|
uint32_t fagc_rst_gla_if_en_agc_pulled_high_mode; /* adi,fagc-rst-gla-if-en-agc-pulled-high-mode */
|
||||||
|
uint32_t fagc_power_measurement_duration_in_state5; /* adi,fagc-power-measurement-duration-in-state5 */
|
||||||
|
uint32_t fagc_large_overload_inc_steps; /* adi,fagc-adc-large-overload-inc-steps - Name is misleading should be dec-steps */
|
||||||
|
/* RSSI Control */
|
||||||
|
uint32_t rssi_delay; /* adi,rssi-delay */
|
||||||
|
uint32_t rssi_duration; /* adi,rssi-duration */
|
||||||
|
uint8_t rssi_restart_mode; /* adi,rssi-restart-mode */
|
||||||
|
uint8_t rssi_unit_is_rx_samples_enable; /* adi,rssi-unit-is-rx-samples-enable */
|
||||||
|
uint32_t rssi_wait; /* adi,rssi-wait */
|
||||||
|
/* Aux ADC Control */
|
||||||
|
uint32_t aux_adc_decimation; /* adi,aux-adc-decimation */
|
||||||
|
uint32_t aux_adc_rate; /* adi,aux-adc-rate */
|
||||||
|
/* AuxDAC Control */
|
||||||
|
uint8_t aux_dac_manual_mode_enable; /* adi,aux-dac-manual-mode-enable */
|
||||||
|
uint32_t aux_dac1_default_value_mV; /* adi,aux-dac1-default-value-mV */
|
||||||
|
uint8_t aux_dac1_active_in_rx_enable; /* adi,aux-dac1-active-in-rx-enable */
|
||||||
|
uint8_t aux_dac1_active_in_tx_enable; /* adi,aux-dac1-active-in-tx-enable */
|
||||||
|
uint8_t aux_dac1_active_in_alert_enable; /* adi,aux-dac1-active-in-alert-enable */
|
||||||
|
uint32_t aux_dac1_rx_delay_us; /* adi,aux-dac1-rx-delay-us */
|
||||||
|
uint32_t aux_dac1_tx_delay_us; /* adi,aux-dac1-tx-delay-us */
|
||||||
|
uint32_t aux_dac2_default_value_mV; /* adi,aux-dac2-default-value-mV */
|
||||||
|
uint8_t aux_dac2_active_in_rx_enable; /* adi,aux-dac2-active-in-rx-enable */
|
||||||
|
uint8_t aux_dac2_active_in_tx_enable; /* adi,aux-dac2-active-in-tx-enable */
|
||||||
|
uint8_t aux_dac2_active_in_alert_enable; /* adi,aux-dac2-active-in-alert-enable */
|
||||||
|
uint32_t aux_dac2_rx_delay_us; /* adi,aux-dac2-rx-delay-us */
|
||||||
|
uint32_t aux_dac2_tx_delay_us; /* adi,aux-dac2-tx-delay-us */
|
||||||
|
/* Temperature Sensor Control */
|
||||||
|
uint32_t temp_sense_decimation; /* adi,temp-sense-decimation */
|
||||||
|
uint16_t temp_sense_measurement_interval_ms; /* adi,temp-sense-measurement-interval-ms */
|
||||||
|
int8_t temp_sense_offset_signed; /* adi,temp-sense-offset-signed */
|
||||||
|
uint8_t temp_sense_periodic_measurement_enable; /* adi,temp-sense-periodic-measurement-enable */
|
||||||
|
/* Control Out Setup */
|
||||||
|
uint8_t ctrl_outs_enable_mask; /* adi,ctrl-outs-enable-mask */
|
||||||
|
uint8_t ctrl_outs_index; /* adi,ctrl-outs-index */
|
||||||
|
/* External LNA Control */
|
||||||
|
uint32_t elna_settling_delay_ns; /* adi,elna-settling-delay-ns */
|
||||||
|
uint32_t elna_gain_mdB; /* adi,elna-gain-mdB */
|
||||||
|
uint32_t elna_bypass_loss_mdB; /* adi,elna-bypass-loss-mdB */
|
||||||
|
uint8_t elna_rx1_gpo0_control_enable; /* adi,elna-rx1-gpo0-control-enable */
|
||||||
|
uint8_t elna_rx2_gpo1_control_enable; /* adi,elna-rx2-gpo1-control-enable */
|
||||||
|
uint8_t elna_gaintable_all_index_enable; /* adi,elna-gaintable-all-index-enable */
|
||||||
|
/* Digital Interface Control */
|
||||||
|
uint8_t digital_interface_tune_skip_mode; /* adi,digital-interface-tune-skip-mode */
|
||||||
|
uint8_t digital_interface_tune_fir_disable; /* adi,digital-interface-tune-fir-disable */
|
||||||
|
uint8_t pp_tx_swap_enable; /* adi,pp-tx-swap-enable */
|
||||||
|
uint8_t pp_rx_swap_enable; /* adi,pp-rx-swap-enable */
|
||||||
|
uint8_t tx_channel_swap_enable; /* adi,tx-channel-swap-enable */
|
||||||
|
uint8_t rx_channel_swap_enable; /* adi,rx-channel-swap-enable */
|
||||||
|
uint8_t rx_frame_pulse_mode_enable; /* adi,rx-frame-pulse-mode-enable */
|
||||||
|
uint8_t two_t_two_r_timing_enable; /* adi,2t2r-timing-enable */
|
||||||
|
uint8_t invert_data_bus_enable; /* adi,invert-data-bus-enable */
|
||||||
|
uint8_t invert_data_clk_enable; /* adi,invert-data-clk-enable */
|
||||||
|
uint8_t fdd_alt_word_order_enable; /* adi,fdd-alt-word-order-enable */
|
||||||
|
uint8_t invert_rx_frame_enable; /* adi,invert-rx-frame-enable */
|
||||||
|
uint8_t fdd_rx_rate_2tx_enable; /* adi,fdd-rx-rate-2tx-enable */
|
||||||
|
uint8_t swap_ports_enable; /* adi,swap-ports-enable */
|
||||||
|
uint8_t single_data_rate_enable; /* adi,single-data-rate-enable */
|
||||||
|
uint8_t lvds_mode_enable; /* adi,lvds-mode-enable */
|
||||||
|
uint8_t half_duplex_mode_enable; /* adi,half-duplex-mode-enable */
|
||||||
|
uint8_t single_port_mode_enable; /* adi,single-port-mode-enable */
|
||||||
|
uint8_t full_port_enable; /* adi,full-port-enable */
|
||||||
|
uint8_t full_duplex_swap_bits_enable; /* adi,full-duplex-swap-bits-enable */
|
||||||
|
uint32_t delay_rx_data; /* adi,delay-rx-data */
|
||||||
|
uint32_t rx_data_clock_delay; /* adi,rx-data-clock-delay */
|
||||||
|
uint32_t rx_data_delay; /* adi,rx-data-delay */
|
||||||
|
uint32_t tx_fb_clock_delay; /* adi,tx-fb-clock-delay */
|
||||||
|
uint32_t tx_data_delay; /* adi,tx-data-delay */
|
||||||
|
uint32_t lvds_bias_mV; /* adi,lvds-bias-mV */
|
||||||
|
uint8_t lvds_rx_onchip_termination_enable; /* adi,lvds-rx-onchip-termination-enable */
|
||||||
|
uint8_t rx1rx2_phase_inversion_en; /* adi,rx1-rx2-phase-inversion-enable */
|
||||||
|
uint8_t lvds_invert1_control; /* adi,lvds-invert1-control */
|
||||||
|
uint8_t lvds_invert2_control; /* adi,lvds-invert2-control */
|
||||||
|
/* GPO Control */
|
||||||
|
uint8_t gpo_manual_mode_enable; /* adi,gpo-manual-mode-enable */
|
||||||
|
uint32_t gpo_manual_mode_enable_mask; /* adi,gpo-manual-mode-enable-mask */
|
||||||
|
uint8_t gpo0_inactive_state_high_enable; /* adi,gpo0-inactive-state-high-enable */
|
||||||
|
uint8_t gpo1_inactive_state_high_enable; /* adi,gpo1-inactive-state-high-enable */
|
||||||
|
uint8_t gpo2_inactive_state_high_enable; /* adi,gpo2-inactive-state-high-enable */
|
||||||
|
uint8_t gpo3_inactive_state_high_enable; /* adi,gpo3-inactive-state-high-enable */
|
||||||
|
uint8_t gpo0_slave_rx_enable; /* adi,gpo0-slave-rx-enable */
|
||||||
|
uint8_t gpo0_slave_tx_enable; /* adi,gpo0-slave-tx-enable */
|
||||||
|
uint8_t gpo1_slave_rx_enable; /* adi,gpo1-slave-rx-enable */
|
||||||
|
uint8_t gpo1_slave_tx_enable; /* adi,gpo1-slave-tx-enable */
|
||||||
|
uint8_t gpo2_slave_rx_enable; /* adi,gpo2-slave-rx-enable */
|
||||||
|
uint8_t gpo2_slave_tx_enable; /* adi,gpo2-slave-tx-enable */
|
||||||
|
uint8_t gpo3_slave_rx_enable; /* adi,gpo3-slave-rx-enable */
|
||||||
|
uint8_t gpo3_slave_tx_enable; /* adi,gpo3-slave-tx-enable */
|
||||||
|
uint8_t gpo0_rx_delay_us; /* adi,gpo0-rx-delay-us */
|
||||||
|
uint8_t gpo0_tx_delay_us; /* adi,gpo0-tx-delay-us */
|
||||||
|
uint8_t gpo1_rx_delay_us; /* adi,gpo1-rx-delay-us */
|
||||||
|
uint8_t gpo1_tx_delay_us; /* adi,gpo1-tx-delay-us */
|
||||||
|
uint8_t gpo2_rx_delay_us; /* adi,gpo2-rx-delay-us */
|
||||||
|
uint8_t gpo2_tx_delay_us; /* adi,gpo2-tx-delay-us */
|
||||||
|
uint8_t gpo3_rx_delay_us; /* adi,gpo3-rx-delay-us */
|
||||||
|
uint8_t gpo3_tx_delay_us; /* adi,gpo3-tx-delay-us */
|
||||||
|
/* Tx Monitor Control */
|
||||||
|
uint32_t low_high_gain_threshold_mdB; /* adi,txmon-low-high-thresh */
|
||||||
|
uint32_t low_gain_dB; /* adi,txmon-low-gain */
|
||||||
|
uint32_t high_gain_dB; /* adi,txmon-high-gain */
|
||||||
|
uint8_t tx_mon_track_en; /* adi,txmon-dc-tracking-enable */
|
||||||
|
uint8_t one_shot_mode_en; /* adi,txmon-one-shot-mode-enable */
|
||||||
|
uint32_t tx_mon_delay; /* adi,txmon-delay */
|
||||||
|
uint32_t tx_mon_duration; /* adi,txmon-duration */
|
||||||
|
uint32_t tx1_mon_front_end_gain; /* adi,txmon-1-front-end-gain */
|
||||||
|
uint32_t tx2_mon_front_end_gain; /* adi,txmon-2-front-end-gain */
|
||||||
|
uint32_t tx1_mon_lo_cm; /* adi,txmon-1-lo-cm */
|
||||||
|
uint32_t tx2_mon_lo_cm; /* adi,txmon-2-lo-cm */
|
||||||
|
/* GPIO definitions */
|
||||||
|
struct gpio_init_param gpio_resetb; /* reset-gpios */
|
||||||
|
/* MCS Sync */
|
||||||
|
struct gpio_init_param gpio_sync; /* sync-gpios */
|
||||||
|
struct gpio_init_param gpio_cal_sw1; /* cal-sw1-gpios */
|
||||||
|
struct gpio_init_param gpio_cal_sw2; /* cal-sw2-gpios */
|
||||||
|
|
||||||
|
struct spi_init_param spi_param;
|
||||||
|
|
||||||
|
/* External LO clocks */
|
||||||
|
uint32_t (*ad9361_rfpll_ext_recalc_rate)(struct refclk_scale *clk_priv);
|
||||||
|
int32_t (*ad9361_rfpll_ext_round_rate)(struct refclk_scale *clk_priv,
|
||||||
|
uint32_t rate);
|
||||||
|
int32_t (*ad9361_rfpll_ext_set_rate)(struct refclk_scale *clk_priv,
|
||||||
|
uint32_t rate);
|
||||||
|
|
||||||
|
} AD9361_InitParam;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t rx; /* 1, 2, 3(both) */
|
||||||
|
int32_t rx_gain; /* -12, -6, 0, 6 */
|
||||||
|
uint32_t rx_dec; /* 1, 2, 4 */
|
||||||
|
int16_t rx_coef[128];
|
||||||
|
uint8_t rx_coef_size;
|
||||||
|
uint32_t rx_path_clks[6];
|
||||||
|
uint32_t rx_bandwidth;
|
||||||
|
} AD9361_RXFIRConfig;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t tx; /* 1, 2, 3(both) */
|
||||||
|
int32_t tx_gain; /* -6, 0 */
|
||||||
|
uint32_t tx_int; /* 1, 2, 4 */
|
||||||
|
int16_t tx_coef[128];
|
||||||
|
uint8_t tx_coef_size;
|
||||||
|
uint32_t tx_path_clks[6];
|
||||||
|
uint32_t tx_bandwidth;
|
||||||
|
} AD9361_TXFIRConfig;
|
||||||
|
|
||||||
|
enum ad9361_ensm_mode {
|
||||||
|
ENSM_MODE_TX,
|
||||||
|
ENSM_MODE_RX,
|
||||||
|
ENSM_MODE_ALERT,
|
||||||
|
ENSM_MODE_FDD,
|
||||||
|
ENSM_MODE_WAIT,
|
||||||
|
ENSM_MODE_SLEEP,
|
||||||
|
ENSM_MODE_PINCTRL,
|
||||||
|
ENSM_MODE_PINCTRL_FDD_INDEP,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ENABLE 1
|
||||||
|
#define DISABLE 0
|
||||||
|
|
||||||
|
#define RX1 0
|
||||||
|
#define RX2 1
|
||||||
|
|
||||||
|
#define TX1 0
|
||||||
|
#define TX2 1
|
||||||
|
|
||||||
|
#define A_BALANCED 0
|
||||||
|
#define B_BALANCED 1
|
||||||
|
#define C_BALANCED 2
|
||||||
|
#define A_N 3
|
||||||
|
#define A_P 4
|
||||||
|
#define B_N 5
|
||||||
|
#define B_P 6
|
||||||
|
#define C_N 7
|
||||||
|
#define C_P 8
|
||||||
|
#define TX_MON1 9
|
||||||
|
#define TX_MON2 10
|
||||||
|
#define TX_MON1_2 11
|
||||||
|
|
||||||
|
#define TXA 0
|
||||||
|
#define TXB 1
|
||||||
|
|
||||||
|
#define MODE_1x1 1
|
||||||
|
#define MODE_2x2 2
|
||||||
|
|
||||||
|
#define HIGHEST_OSR 0
|
||||||
|
#define NOMINAL_OSR 1
|
||||||
|
|
||||||
|
#define INT_LO 0
|
||||||
|
#define EXT_LO 1
|
||||||
|
|
||||||
|
#define ON 0
|
||||||
|
#define OFF 1
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
/* Initialize the AD9361 part. */
|
||||||
|
int32_t ad9361_init (struct ad9361_rf_phy **ad9361_phy,
|
||||||
|
AD9361_InitParam *init_param);
|
||||||
|
/* Free the allocated resources. */
|
||||||
|
int32_t ad9361_remove(struct ad9361_rf_phy *phy);
|
||||||
|
/* Set the Enable State Machine (ENSM) mode. */
|
||||||
|
int32_t ad9361_set_en_state_machine_mode (struct ad9361_rf_phy *phy,
|
||||||
|
uint32_t mode);
|
||||||
|
/* Get the Enable State Machine (ENSM) mode. */
|
||||||
|
int32_t ad9361_get_en_state_machine_mode (struct ad9361_rf_phy *phy,
|
||||||
|
uint32_t *mode);
|
||||||
|
/* Set the receive RF gain for the selected channel. */
|
||||||
|
int32_t ad9361_set_rx_rf_gain (struct ad9361_rf_phy *phy, uint8_t ch,
|
||||||
|
int32_t gain_db);
|
||||||
|
/* Get current receive RF gain for the selected channel. */
|
||||||
|
int32_t ad9361_get_rx_rf_gain (struct ad9361_rf_phy *phy, uint8_t ch,
|
||||||
|
int32_t *gain_db);
|
||||||
|
/* Set the RX RF bandwidth. */
|
||||||
|
int32_t ad9361_set_rx_rf_bandwidth (struct ad9361_rf_phy *phy,
|
||||||
|
uint32_t bandwidth_hz);
|
||||||
|
/* Get the RX RF bandwidth. */
|
||||||
|
int32_t ad9361_get_rx_rf_bandwidth (struct ad9361_rf_phy *phy,
|
||||||
|
uint32_t *bandwidth_hz);
|
||||||
|
/* Set the RX sampling frequency. */
|
||||||
|
int32_t ad9361_set_rx_sampling_freq (struct ad9361_rf_phy *phy,
|
||||||
|
uint32_t sampling_freq_hz);
|
||||||
|
/* Get current RX sampling frequency. */
|
||||||
|
int32_t ad9361_get_rx_sampling_freq (struct ad9361_rf_phy *phy,
|
||||||
|
uint32_t *sampling_freq_hz);
|
||||||
|
/* Set the RX LO frequency. */
|
||||||
|
int32_t ad9361_set_rx_lo_freq (struct ad9361_rf_phy *phy, uint64_t lo_freq_hz);
|
||||||
|
/* Get current RX LO frequency. */
|
||||||
|
int32_t ad9361_get_rx_lo_freq (struct ad9361_rf_phy *phy, uint64_t *lo_freq_hz);
|
||||||
|
/* Switch between internal and external LO. */
|
||||||
|
int32_t ad9361_set_rx_lo_int_ext(struct ad9361_rf_phy *phy, uint8_t int_ext);
|
||||||
|
/* Get the RSSI for the selected channel. */
|
||||||
|
int32_t ad9361_get_rx_rssi (struct ad9361_rf_phy *phy, uint8_t ch,
|
||||||
|
struct rf_rssi *rssi);
|
||||||
|
/* Set the gain control mode for the selected channel. */
|
||||||
|
int32_t ad9361_set_rx_gain_control_mode (struct ad9361_rf_phy *phy, uint8_t ch,
|
||||||
|
uint8_t gc_mode);
|
||||||
|
/* Get the gain control mode for the selected channel. */
|
||||||
|
int32_t ad9361_get_rx_gain_control_mode (struct ad9361_rf_phy *phy, uint8_t ch,
|
||||||
|
uint8_t *gc_mode);
|
||||||
|
/* Set the RX FIR filter configuration. */
|
||||||
|
int32_t ad9361_set_rx_fir_config (struct ad9361_rf_phy *phy,
|
||||||
|
AD9361_RXFIRConfig fir_cfg);
|
||||||
|
/* Get the RX FIR filter configuration. */
|
||||||
|
int32_t ad9361_get_rx_fir_config(struct ad9361_rf_phy *phy, uint8_t rx_ch,
|
||||||
|
AD9361_RXFIRConfig *fir_cfg);
|
||||||
|
/* Enable/disable the RX FIR filter. */
|
||||||
|
int32_t ad9361_set_rx_fir_en_dis (struct ad9361_rf_phy *phy, uint8_t en_dis);
|
||||||
|
/* Get the status of the RX FIR filter. */
|
||||||
|
int32_t ad9361_get_rx_fir_en_dis (struct ad9361_rf_phy *phy, uint8_t *en_dis);
|
||||||
|
/* Enable/disable the RX RFDC Tracking. */
|
||||||
|
int32_t ad9361_set_rx_rfdc_track_en_dis (struct ad9361_rf_phy *phy,
|
||||||
|
uint8_t en_dis);
|
||||||
|
/* Get the status of the RX RFDC Tracking. */
|
||||||
|
int32_t ad9361_get_rx_rfdc_track_en_dis (struct ad9361_rf_phy *phy,
|
||||||
|
uint8_t *en_dis);
|
||||||
|
/* Enable/disable the RX BasebandDC Tracking. */
|
||||||
|
int32_t ad9361_set_rx_bbdc_track_en_dis (struct ad9361_rf_phy *phy,
|
||||||
|
uint8_t en_dis);
|
||||||
|
/* Get the status of the RX BasebandDC Tracking. */
|
||||||
|
int32_t ad9361_get_rx_bbdc_track_en_dis (struct ad9361_rf_phy *phy,
|
||||||
|
uint8_t *en_dis);
|
||||||
|
/* Enable/disable the RX Quadrature Tracking. */
|
||||||
|
int32_t ad9361_set_rx_quad_track_en_dis (struct ad9361_rf_phy *phy,
|
||||||
|
uint8_t en_dis);
|
||||||
|
/* Get the status of the RX Quadrature Tracking. */
|
||||||
|
int32_t ad9361_get_rx_quad_track_en_dis (struct ad9361_rf_phy *phy,
|
||||||
|
uint8_t *en_dis);
|
||||||
|
/* Set the RX RF input port. */
|
||||||
|
int32_t ad9361_set_rx_rf_port_input (struct ad9361_rf_phy *phy, uint32_t mode);
|
||||||
|
/* Get the selected RX RF input port. */
|
||||||
|
int32_t ad9361_get_rx_rf_port_input (struct ad9361_rf_phy *phy, uint32_t *mode);
|
||||||
|
/* Store RX fastlock profile. */
|
||||||
|
int32_t ad9361_rx_fastlock_store(struct ad9361_rf_phy *phy, uint32_t profile);
|
||||||
|
/* Recall RX fastlock profile. */
|
||||||
|
int32_t ad9361_rx_fastlock_recall(struct ad9361_rf_phy *phy, uint32_t profile);
|
||||||
|
/* Load RX fastlock profile. */
|
||||||
|
int32_t ad9361_rx_fastlock_load(struct ad9361_rf_phy *phy, uint32_t profile,
|
||||||
|
uint8_t *values);
|
||||||
|
/* Save RX fastlock profile. */
|
||||||
|
int32_t ad9361_rx_fastlock_save(struct ad9361_rf_phy *phy, uint32_t profile,
|
||||||
|
uint8_t *values);
|
||||||
|
/* Power down the RX Local Oscillator. */
|
||||||
|
int32_t ad9361_rx_lo_powerdown(struct ad9361_rf_phy *phy, uint8_t option);
|
||||||
|
/* Get the RX Local Oscillator power status. */
|
||||||
|
int32_t ad9361_get_rx_lo_power(struct ad9361_rf_phy *phy, uint8_t *option);
|
||||||
|
/* Set the transmit attenuation for the selected channel. */
|
||||||
|
int32_t ad9361_set_tx_attenuation (struct ad9361_rf_phy *phy, uint8_t ch,
|
||||||
|
uint32_t attenuation_mdb);
|
||||||
|
/* Get current transmit attenuation for the selected channel. */
|
||||||
|
int32_t ad9361_get_tx_attenuation (struct ad9361_rf_phy *phy, uint8_t ch,
|
||||||
|
uint32_t *attenuation_mdb);
|
||||||
|
/* Set the TX RF bandwidth. */
|
||||||
|
int32_t ad9361_set_tx_rf_bandwidth (struct ad9361_rf_phy *phy,
|
||||||
|
uint32_t bandwidth_hz);
|
||||||
|
/* Get the TX RF bandwidth. */
|
||||||
|
int32_t ad9361_get_tx_rf_bandwidth (struct ad9361_rf_phy *phy,
|
||||||
|
uint32_t *bandwidth_hz);
|
||||||
|
/* Set the TX sampling frequency. */
|
||||||
|
int32_t ad9361_set_tx_sampling_freq (struct ad9361_rf_phy *phy,
|
||||||
|
uint32_t sampling_freq_hz);
|
||||||
|
/* Get current TX sampling frequency. */
|
||||||
|
int32_t ad9361_get_tx_sampling_freq (struct ad9361_rf_phy *phy,
|
||||||
|
uint32_t *sampling_freq_hz);
|
||||||
|
/* Set the TX LO frequency. */
|
||||||
|
int32_t ad9361_set_tx_lo_freq (struct ad9361_rf_phy *phy, uint64_t lo_freq_hz);
|
||||||
|
/* Get current TX LO frequency. */
|
||||||
|
int32_t ad9361_get_tx_lo_freq (struct ad9361_rf_phy *phy, uint64_t *lo_freq_hz);
|
||||||
|
/* Switch between internal and external LO. */
|
||||||
|
int32_t ad9361_set_tx_lo_int_ext(struct ad9361_rf_phy *phy, uint8_t int_ext);
|
||||||
|
/* Set the TX FIR filter configuration. */
|
||||||
|
int32_t ad9361_set_tx_fir_config (struct ad9361_rf_phy *phy,
|
||||||
|
AD9361_TXFIRConfig fir_cfg);
|
||||||
|
/* Get the TX FIR filter configuration. */
|
||||||
|
int32_t ad9361_get_tx_fir_config(struct ad9361_rf_phy *phy, uint8_t tx_ch,
|
||||||
|
AD9361_TXFIRConfig *fir_cfg);
|
||||||
|
/* Enable/disable the TX FIR filter. */
|
||||||
|
int32_t ad9361_set_tx_fir_en_dis (struct ad9361_rf_phy *phy, uint8_t en_dis);
|
||||||
|
/* Get the status of the TX FIR filter. */
|
||||||
|
int32_t ad9361_get_tx_fir_en_dis (struct ad9361_rf_phy *phy, uint8_t *en_dis);
|
||||||
|
/* Get the TX RSSI for the selected channel. */
|
||||||
|
int32_t ad9361_get_tx_rssi (struct ad9361_rf_phy *phy, uint8_t ch,
|
||||||
|
uint32_t *rssi_db_x_1000);
|
||||||
|
/* Set the TX RF output port. */
|
||||||
|
int32_t ad9361_set_tx_rf_port_output (struct ad9361_rf_phy *phy, uint32_t mode);
|
||||||
|
/* Get the selected TX RF output port. */
|
||||||
|
int32_t ad9361_get_tx_rf_port_output (struct ad9361_rf_phy *phy,
|
||||||
|
uint32_t *mode);
|
||||||
|
/* Enable/disable the auto calibration. */
|
||||||
|
int32_t ad9361_set_tx_auto_cal_en_dis (struct ad9361_rf_phy *phy,
|
||||||
|
uint8_t en_dis);
|
||||||
|
/* Get the status of the auto calibration flag. */
|
||||||
|
int32_t ad9361_get_tx_auto_cal_en_dis (struct ad9361_rf_phy *phy,
|
||||||
|
uint8_t *en_dis);
|
||||||
|
/* Store TX fastlock profile. */
|
||||||
|
int32_t ad9361_tx_fastlock_store(struct ad9361_rf_phy *phy, uint32_t profile);
|
||||||
|
/* Recall TX fastlock profile. */
|
||||||
|
int32_t ad9361_tx_fastlock_recall(struct ad9361_rf_phy *phy, uint32_t profile);
|
||||||
|
/* Load TX fastlock profile. */
|
||||||
|
int32_t ad9361_tx_fastlock_load(struct ad9361_rf_phy *phy, uint32_t profile,
|
||||||
|
uint8_t *values);
|
||||||
|
/* Save TX fastlock profile. */
|
||||||
|
int32_t ad9361_tx_fastlock_save(struct ad9361_rf_phy *phy, uint32_t profile,
|
||||||
|
uint8_t *values);
|
||||||
|
/* Power down the TX Local Oscillator. */
|
||||||
|
int32_t ad9361_tx_lo_powerdown(struct ad9361_rf_phy *phy, uint8_t option);
|
||||||
|
/* Get the TX Local Oscillator power status. */
|
||||||
|
int32_t ad9361_get_tx_lo_power(struct ad9361_rf_phy *phy, uint8_t *option);
|
||||||
|
/* Set the RX and TX path rates. */
|
||||||
|
int32_t ad9361_set_trx_path_clks(struct ad9361_rf_phy *phy,
|
||||||
|
uint32_t *rx_path_clks, uint32_t *tx_path_clks);
|
||||||
|
/* Get the RX and TX path rates. */
|
||||||
|
int32_t ad9361_get_trx_path_clks(struct ad9361_rf_phy *phy,
|
||||||
|
uint32_t *rx_path_clks, uint32_t *tx_path_clks);
|
||||||
|
/* Set the number of channels mode. */
|
||||||
|
int32_t ad9361_set_no_ch_mode(struct ad9361_rf_phy *phy, uint8_t no_ch_mode);
|
||||||
|
/* Do multi chip synchronization. */
|
||||||
|
int32_t ad9361_do_mcs(struct ad9361_rf_phy *phy_master,
|
||||||
|
struct ad9361_rf_phy *phy_slave);
|
||||||
|
/* Enable/disable the TRX FIR filters. */
|
||||||
|
int32_t ad9361_set_trx_fir_en_dis (struct ad9361_rf_phy *phy, uint8_t en_dis);
|
||||||
|
/* Set the OSR rate governor. */
|
||||||
|
int32_t ad9361_set_trx_rate_gov (struct ad9361_rf_phy *phy, uint32_t rate_gov);
|
||||||
|
/* Get the OSR rate governor. */
|
||||||
|
int32_t ad9361_get_trx_rate_gov (struct ad9361_rf_phy *phy, uint32_t *rate_gov);
|
||||||
|
/* Perform the selected calibration. */
|
||||||
|
int32_t ad9361_do_calib(struct ad9361_rf_phy *phy, uint32_t cal, int32_t arg);
|
||||||
|
/* Load and enable TRX FIR filters configurations. */
|
||||||
|
int32_t ad9361_trx_load_enable_fir(struct ad9361_rf_phy *phy,
|
||||||
|
AD9361_RXFIRConfig rx_fir_cfg,
|
||||||
|
AD9361_TXFIRConfig tx_fir_cfg);
|
||||||
|
/* Do DCXO coarse tuning. */
|
||||||
|
int32_t ad9361_do_dcxo_tune_coarse(struct ad9361_rf_phy *phy,
|
||||||
|
uint32_t coarse);
|
||||||
|
/* Do DCXO fine tuning. */
|
||||||
|
int32_t ad9361_do_dcxo_tune_fine(struct ad9361_rf_phy *phy,
|
||||||
|
uint32_t fine);
|
||||||
|
/* Get the temperature. */
|
||||||
|
int32_t ad9361_get_temperature(struct ad9361_rf_phy *phy,
|
||||||
|
int32_t *temp);
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @file ad9361_conv.c
|
||||||
|
* @brief Implementation of AD9361 Conv Driver.
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2014-2015(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "ad9361.h"
|
||||||
|
#include "ad9361_util.h"
|
||||||
|
#include "delay.h"
|
||||||
|
#include "../../../config/app_config.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/********************** Macros and Constants Definitions **********************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HDL loopback enable/disable.
|
||||||
|
* @param phy The AD9361 state structure.
|
||||||
|
* @param enable Enable/disable option.
|
||||||
|
* @return 0 in case of success, negative error code otherwise.
|
||||||
|
*/
|
||||||
|
int32_t ad9361_hdl_loopback(struct ad9361_rf_phy *phy, bool enable)
|
||||||
|
{
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Digital tune.
|
||||||
|
* @param phy The AD9361 state structure.
|
||||||
|
* @param max_freq Maximum frequency.
|
||||||
|
* @param flags Flags: BE_VERBOSE, BE_MOREVERBOSE, DO_IDELAY, DO_ODELAY.
|
||||||
|
* @return 0 in case of success, negative error code otherwise.
|
||||||
|
*/
|
||||||
|
int32_t ad9361_dig_tune(struct ad9361_rf_phy *phy, uint32_t max_freq,
|
||||||
|
enum dig_tune_flags flags)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the AD9361 device.
|
||||||
|
* @param phy The AD9361 state structure.
|
||||||
|
* @return 0 in case of success, negative error code otherwise.
|
||||||
|
*/
|
||||||
|
int32_t ad9361_post_setup(struct ad9361_rf_phy *phy)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,335 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file ad9361_util.c
|
||||||
|
* @brief AD9361 Implementation of Util Driver.
|
||||||
|
* @author DBogdan (dragos.bogdan@analog.com)
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2013(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#include <string.h>
|
||||||
|
#include "ad9361_util.h"
|
||||||
|
#include "../../../include/delay.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Macros Definitions *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#define BITS_PER_LONG 32
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief clk_prepare_enable
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t clk_prepare_enable(struct clk *clk)
|
||||||
|
{
|
||||||
|
if (clk) {
|
||||||
|
// Unused variable - fix compiler warning
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief clk_get_rate
|
||||||
|
*******************************************************************************/
|
||||||
|
uint32_t clk_get_rate(struct ad9361_rf_phy *phy,
|
||||||
|
struct refclk_scale *clk_priv)
|
||||||
|
{
|
||||||
|
uint32_t rate = 0;
|
||||||
|
uint32_t source;
|
||||||
|
|
||||||
|
source = clk_priv->source;
|
||||||
|
|
||||||
|
switch (source) {
|
||||||
|
case TX_REFCLK:
|
||||||
|
case RX_REFCLK:
|
||||||
|
case BB_REFCLK:
|
||||||
|
rate = ad9361_clk_factor_recalc_rate(clk_priv,
|
||||||
|
phy->clk_refin->rate);
|
||||||
|
break;
|
||||||
|
case TX_RFPLL_INT:
|
||||||
|
case RX_RFPLL_INT:
|
||||||
|
rate = ad9361_rfpll_int_recalc_rate(clk_priv,
|
||||||
|
phy->clks[clk_priv->parent_source]->rate);
|
||||||
|
break;
|
||||||
|
case RX_RFPLL_DUMMY:
|
||||||
|
case TX_RFPLL_DUMMY:
|
||||||
|
rate = ad9361_rfpll_dummy_recalc_rate(clk_priv);
|
||||||
|
break;
|
||||||
|
case TX_RFPLL:
|
||||||
|
case RX_RFPLL:
|
||||||
|
rate = ad9361_rfpll_recalc_rate(clk_priv);
|
||||||
|
break;
|
||||||
|
case BBPLL_CLK:
|
||||||
|
rate = ad9361_bbpll_recalc_rate(clk_priv,
|
||||||
|
phy->clks[clk_priv->parent_source]->rate);
|
||||||
|
break;
|
||||||
|
case ADC_CLK:
|
||||||
|
case R2_CLK:
|
||||||
|
case R1_CLK:
|
||||||
|
case CLKRF_CLK:
|
||||||
|
case RX_SAMPL_CLK:
|
||||||
|
case DAC_CLK:
|
||||||
|
case T2_CLK:
|
||||||
|
case T1_CLK:
|
||||||
|
case CLKTF_CLK:
|
||||||
|
case TX_SAMPL_CLK:
|
||||||
|
rate = ad9361_clk_factor_recalc_rate(clk_priv,
|
||||||
|
phy->clks[clk_priv->parent_source]->rate);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief clk_set_rate
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t clk_set_rate(struct ad9361_rf_phy *phy,
|
||||||
|
struct refclk_scale *clk_priv,
|
||||||
|
uint32_t rate)
|
||||||
|
{
|
||||||
|
uint32_t source;
|
||||||
|
int32_t i;
|
||||||
|
uint32_t round_rate;
|
||||||
|
|
||||||
|
source = clk_priv->source;
|
||||||
|
if(phy->clks[source]->rate != rate)
|
||||||
|
{
|
||||||
|
switch (source) {
|
||||||
|
case TX_REFCLK:
|
||||||
|
case RX_REFCLK:
|
||||||
|
case BB_REFCLK:
|
||||||
|
round_rate = ad9361_clk_factor_round_rate(clk_priv, rate,
|
||||||
|
&phy->clk_refin->rate);
|
||||||
|
ad9361_clk_factor_set_rate(clk_priv, round_rate,
|
||||||
|
phy->clk_refin->rate);
|
||||||
|
phy->clks[source]->rate = ad9361_clk_factor_recalc_rate(clk_priv,
|
||||||
|
phy->clk_refin->rate);
|
||||||
|
break;
|
||||||
|
case TX_RFPLL_INT:
|
||||||
|
case RX_RFPLL_INT:
|
||||||
|
round_rate = ad9361_rfpll_int_round_rate(clk_priv, rate,
|
||||||
|
&phy->clks[clk_priv->parent_source]->rate);
|
||||||
|
ad9361_rfpll_int_set_rate(clk_priv, round_rate,
|
||||||
|
phy->clks[clk_priv->parent_source]->rate);
|
||||||
|
phy->clks[source]->rate = ad9361_rfpll_int_recalc_rate(clk_priv,
|
||||||
|
phy->clks[clk_priv->parent_source]->rate);
|
||||||
|
break;
|
||||||
|
case RX_RFPLL_DUMMY:
|
||||||
|
case TX_RFPLL_DUMMY:
|
||||||
|
ad9361_rfpll_dummy_set_rate(clk_priv, rate);
|
||||||
|
break;
|
||||||
|
case TX_RFPLL:
|
||||||
|
case RX_RFPLL:
|
||||||
|
round_rate = ad9361_rfpll_round_rate(clk_priv, rate);
|
||||||
|
ad9361_rfpll_set_rate(clk_priv, round_rate);
|
||||||
|
phy->clks[source]->rate = ad9361_rfpll_recalc_rate(clk_priv);
|
||||||
|
break;
|
||||||
|
case BBPLL_CLK:
|
||||||
|
round_rate = ad9361_bbpll_round_rate(clk_priv, rate,
|
||||||
|
&phy->clks[clk_priv->parent_source]->rate);
|
||||||
|
ad9361_bbpll_set_rate(clk_priv, round_rate,
|
||||||
|
phy->clks[clk_priv->parent_source]->rate);
|
||||||
|
phy->clks[source]->rate = ad9361_bbpll_recalc_rate(clk_priv,
|
||||||
|
phy->clks[clk_priv->parent_source]->rate);
|
||||||
|
phy->bbpll_initialized = true;
|
||||||
|
break;
|
||||||
|
case ADC_CLK:
|
||||||
|
case R2_CLK:
|
||||||
|
case R1_CLK:
|
||||||
|
case CLKRF_CLK:
|
||||||
|
case RX_SAMPL_CLK:
|
||||||
|
case DAC_CLK:
|
||||||
|
case T2_CLK:
|
||||||
|
case T1_CLK:
|
||||||
|
case CLKTF_CLK:
|
||||||
|
case TX_SAMPL_CLK:
|
||||||
|
round_rate = ad9361_clk_factor_round_rate(clk_priv, rate,
|
||||||
|
&phy->clks[clk_priv->parent_source]->rate);
|
||||||
|
ad9361_clk_factor_set_rate(clk_priv, round_rate,
|
||||||
|
phy->clks[clk_priv->parent_source]->rate);
|
||||||
|
phy->clks[source]->rate = ad9361_clk_factor_recalc_rate(clk_priv,
|
||||||
|
phy->clks[clk_priv->parent_source]->rate);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for(i = BB_REFCLK; i < BBPLL_CLK; i++)
|
||||||
|
{
|
||||||
|
phy->clks[i]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[i],
|
||||||
|
phy->clk_refin->rate);
|
||||||
|
}
|
||||||
|
phy->clks[BBPLL_CLK]->rate = ad9361_bbpll_recalc_rate(phy->ref_clk_scale[BBPLL_CLK],
|
||||||
|
phy->clks[phy->ref_clk_scale[BBPLL_CLK]->parent_source]->rate);
|
||||||
|
for(i = ADC_CLK; i < RX_RFPLL_INT; i++)
|
||||||
|
{
|
||||||
|
phy->clks[i]->rate = ad9361_clk_factor_recalc_rate(phy->ref_clk_scale[i],
|
||||||
|
phy->clks[phy->ref_clk_scale[i]->parent_source]->rate);
|
||||||
|
}
|
||||||
|
for(i = RX_RFPLL_INT; i < RX_RFPLL_DUMMY; i++)
|
||||||
|
{
|
||||||
|
phy->clks[i]->rate = ad9361_rfpll_int_recalc_rate(phy->ref_clk_scale[i],
|
||||||
|
phy->clks[phy->ref_clk_scale[i]->parent_source]->rate);
|
||||||
|
}
|
||||||
|
for(i = RX_RFPLL_DUMMY; i < RX_RFPLL; i++)
|
||||||
|
{
|
||||||
|
phy->clks[i]->rate = ad9361_rfpll_dummy_recalc_rate(phy->ref_clk_scale[i]);
|
||||||
|
}
|
||||||
|
for(i = RX_RFPLL; i < NUM_AD9361_CLKS; i++)
|
||||||
|
{
|
||||||
|
phy->clks[i]->rate = ad9361_rfpll_recalc_rate(phy->ref_clk_scale[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((source == BBPLL_CLK) && !phy->bbpll_initialized) {
|
||||||
|
round_rate = ad9361_bbpll_round_rate(clk_priv, rate,
|
||||||
|
&phy->clks[clk_priv->parent_source]->rate);
|
||||||
|
ad9361_bbpll_set_rate(clk_priv, round_rate,
|
||||||
|
phy->clks[clk_priv->parent_source]->rate);
|
||||||
|
phy->clks[source]->rate = ad9361_bbpll_recalc_rate(clk_priv,
|
||||||
|
phy->clks[clk_priv->parent_source]->rate);
|
||||||
|
phy->bbpll_initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief int_sqrt
|
||||||
|
*******************************************************************************/
|
||||||
|
uint32_t int_sqrt(uint32_t x)
|
||||||
|
{
|
||||||
|
uint32_t b, m, y = 0;
|
||||||
|
|
||||||
|
if (x <= 1)
|
||||||
|
return x;
|
||||||
|
|
||||||
|
m = 1UL << (BITS_PER_LONG - 2);
|
||||||
|
while (m != 0) {
|
||||||
|
b = y + m;
|
||||||
|
y >>= 1;
|
||||||
|
|
||||||
|
if (x >= b) {
|
||||||
|
x -= b;
|
||||||
|
y += m;
|
||||||
|
}
|
||||||
|
m >>= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief ilog2
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t ilog2(int32_t x)
|
||||||
|
{
|
||||||
|
int32_t A = !(!(x >> 16));
|
||||||
|
int32_t count = 0;
|
||||||
|
int32_t x_copy = x;
|
||||||
|
|
||||||
|
count = count + (A << 4);
|
||||||
|
|
||||||
|
x_copy = (((~A + 1) & (x >> 16)) + (~(~A + 1) & x));
|
||||||
|
|
||||||
|
A = !(!(x_copy >> 8));
|
||||||
|
count = count + (A << 3);
|
||||||
|
x_copy = (((~A + 1) & (x_copy >> 8)) + (~(~A + 1) & x_copy));
|
||||||
|
|
||||||
|
A = !(!(x_copy >> 4));
|
||||||
|
count = count + (A << 2);
|
||||||
|
x_copy = (((~A + 1) & (x_copy >> 4)) + (~(~A + 1) & x_copy));
|
||||||
|
|
||||||
|
A = !(!(x_copy >> 2));
|
||||||
|
count = count + (A << 1);
|
||||||
|
x_copy = (((~A + 1) & (x_copy >> 2)) + (~(~A + 1) & x_copy));
|
||||||
|
|
||||||
|
A = !(!(x_copy >> 1));
|
||||||
|
count = count + A;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief find_first_bit
|
||||||
|
*******************************************************************************/
|
||||||
|
uint32_t find_first_bit(uint32_t word)
|
||||||
|
{
|
||||||
|
int32_t num = 0;
|
||||||
|
|
||||||
|
if ((word & 0xffff) == 0) {
|
||||||
|
num += 16;
|
||||||
|
word >>= 16;
|
||||||
|
}
|
||||||
|
if ((word & 0xff) == 0) {
|
||||||
|
num += 8;
|
||||||
|
word >>= 8;
|
||||||
|
}
|
||||||
|
if ((word & 0xf) == 0) {
|
||||||
|
num += 4;
|
||||||
|
word >>= 4;
|
||||||
|
}
|
||||||
|
if ((word & 0x3) == 0) {
|
||||||
|
num += 2;
|
||||||
|
word >>= 2;
|
||||||
|
}
|
||||||
|
if ((word & 0x1) == 0)
|
||||||
|
num += 1;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief ERR_PTR
|
||||||
|
*******************************************************************************/
|
||||||
|
void * ERR_PTR(long error)
|
||||||
|
{
|
||||||
|
return (void *) error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief zmalloc
|
||||||
|
*******************************************************************************/
|
||||||
|
void *zmalloc(size_t size)
|
||||||
|
{
|
||||||
|
void *ptr = malloc(size);
|
||||||
|
if (ptr)
|
||||||
|
memset(ptr, 0, size);
|
||||||
|
mdelay(1);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file ad9361_util.h
|
||||||
|
* @brief AD9361 Header file of Util driver.
|
||||||
|
* @author DBogdan (dragos.bogdan@analog.com)
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2013(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef __AD9361_UTIL_H__
|
||||||
|
#define __AD9361_UTIL_H__
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "ad9361.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/********************** Macros and Constants Definitions **********************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#define CLK_IGNORE_UNUSED BIT(3)
|
||||||
|
#define CLK_GET_RATE_NOCACHE BIT(6)
|
||||||
|
|
||||||
|
#if defined(HAVE_VERBOSE_MESSAGES)
|
||||||
|
#define dev_err(dev, format, ...) ({printf(format, ## __VA_ARGS__);printf("\n"); })
|
||||||
|
#define dev_warn(dev, format, ...) ({printf(format, ## __VA_ARGS__);printf("\n"); })
|
||||||
|
#if defined(HAVE_DEBUG_MESSAGES)
|
||||||
|
#define dev_dbg(dev, format, ...) ({printf(format, ## __VA_ARGS__);printf("\n"); })
|
||||||
|
#else
|
||||||
|
#define dev_dbg(dev, format, ...) ({ if (0) printf(format, ## __VA_ARGS__); })
|
||||||
|
#endif
|
||||||
|
#define printk(format, ...) printf(format, ## __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define dev_err(dev, format, ...) ({ if (0) printf(format, ## __VA_ARGS__); })
|
||||||
|
#define dev_warn(dev, format, ...) ({ if (0) printf(format, ## __VA_ARGS__); })
|
||||||
|
#define dev_dbg(dev, format, ...) ({ if (0) printf(format, ## __VA_ARGS__); })
|
||||||
|
#define printk(format, ...) ({ if (0) printf(format, ## __VA_ARGS__); })
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct device {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct spi_device {
|
||||||
|
struct device dev;
|
||||||
|
uint8_t id_no;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct axiadc_state {
|
||||||
|
struct ad9361_rf_phy *phy;
|
||||||
|
uint32_t pcore_version;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct axiadc_chip_info {
|
||||||
|
char *name;
|
||||||
|
int32_t num_channels;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct axiadc_converter {
|
||||||
|
struct axiadc_chip_info *chip_info;
|
||||||
|
uint32_t scratch_reg[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include "basetsd.h"
|
||||||
|
typedef SSIZE_T ssize_t;
|
||||||
|
#define strsep(s, ct) 0
|
||||||
|
#define snprintf(s, n, format, ...) 0
|
||||||
|
#define __func__ __FUNCTION__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
int32_t clk_prepare_enable(struct clk *clk);
|
||||||
|
uint32_t clk_get_rate(struct ad9361_rf_phy *phy,
|
||||||
|
struct refclk_scale *clk_priv);
|
||||||
|
int32_t clk_set_rate(struct ad9361_rf_phy *phy,
|
||||||
|
struct refclk_scale *clk_priv,
|
||||||
|
uint32_t rate);
|
||||||
|
uint32_t int_sqrt(uint32_t x);
|
||||||
|
int32_t ilog2(int32_t x);
|
||||||
|
uint32_t find_first_bit(uint32_t word);
|
||||||
|
void * ERR_PTR(long error);
|
||||||
|
void *zmalloc(size_t size);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file common.h
|
||||||
|
* @brief Header file of Common Driver.
|
||||||
|
* @author DBogdan (dragos.bogdan@analog.com)
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2013(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef __AD9361_COMMON_H_
|
||||||
|
#define __AD9361_COMMON_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "../../../include/error.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#if defined (__STDC__) && (__STDC_VERSION__ >= 199901L)
|
||||||
|
#include <stdbool.h>
|
||||||
|
#else
|
||||||
|
typedef enum { false, true } bool;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct clk {
|
||||||
|
const char *name;
|
||||||
|
uint32_t rate;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct clk_hw {
|
||||||
|
struct clk *clk;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __AD9361_COMMON_H_
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file ad9361_reg.c
|
||||||
|
* @brief Implementation of AD9680 Driver.
|
||||||
|
* @author DBogdan (dragos.bogdan@analog.com)
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2014-2016(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#include "ad9361_reg.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../../../include/error.h"
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief ad9361_reg_read
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t ad9361_reg_read(struct ad9361_reg_dev *dev,
|
||||||
|
uint16_t reg_addr,
|
||||||
|
uint8_t *reg_data)
|
||||||
|
{
|
||||||
|
uint8_t tx_buf[2];
|
||||||
|
uint8_t rx_buf[1];
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
tx_buf[0] = reg_addr >> 8;
|
||||||
|
tx_buf[1] = reg_addr & 0xFF;
|
||||||
|
|
||||||
|
|
||||||
|
ret = spi_write_and_read_3wire(dev->spi_desc,
|
||||||
|
tx_buf, rx_buf, 2, 1);
|
||||||
|
|
||||||
|
*reg_data = rx_buf[0];
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief ad9361_reg_write
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t ad9361_reg_write(struct ad9361_reg_dev *dev,
|
||||||
|
uint16_t reg_addr,
|
||||||
|
uint8_t reg_data)
|
||||||
|
{
|
||||||
|
uint8_t buf[3];
|
||||||
|
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
buf[0] = 0x80 | reg_addr >> 8;
|
||||||
|
buf[1] = reg_addr & 0xFF;
|
||||||
|
buf[2] = reg_data;
|
||||||
|
|
||||||
|
ret = spi_write_and_read_3wire(dev->spi_desc,
|
||||||
|
buf, NULL, 3, 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief ad9361_reg_init
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t ad9361_reg_init(struct ad9361_reg_dev **device,
|
||||||
|
const struct ad9361_reg_init_param *init_param)
|
||||||
|
{
|
||||||
|
int ret = SUCCESS;
|
||||||
|
struct ad9361_reg_dev *dev;
|
||||||
|
|
||||||
|
dev = (struct ad9361_reg_dev *)malloc(sizeof(*dev));
|
||||||
|
if (!dev)
|
||||||
|
return FAILURE;
|
||||||
|
|
||||||
|
/* SPI */
|
||||||
|
ret = spi_init(&dev->spi_desc, init_param->spi_init);
|
||||||
|
ret |= gpio_get(&dev->gpio_desc_resetb, init_param->gpio_resetb);
|
||||||
|
|
||||||
|
gpio_direction_output(dev->gpio_desc_resetb, 0);
|
||||||
|
|
||||||
|
ad9361_reg_reset(dev);
|
||||||
|
|
||||||
|
*device = dev;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AD9361 Device Reset
|
||||||
|
* @param phy The AD9361 state structure.
|
||||||
|
* @return 0 in case of success, negative error code otherwise.
|
||||||
|
*/
|
||||||
|
int32_t ad9361_reg_reset(struct ad9361_reg_dev *dev)
|
||||||
|
{
|
||||||
|
if (dev->gpio_desc_resetb) {
|
||||||
|
gpio_set_value(dev->gpio_desc_resetb, 0);
|
||||||
|
mdelay(10);
|
||||||
|
gpio_set_value(dev->gpio_desc_resetb, 1);
|
||||||
|
mdelay(10);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************//**
|
||||||
|
* @brief Free the resources allocated by ad9361_reg_setup().
|
||||||
|
*
|
||||||
|
* @param dev - The device structure.
|
||||||
|
*
|
||||||
|
* @return SUCCESS in case of success, negative error code otherwise.
|
||||||
|
*******************************************************************************/
|
||||||
|
int32_t ad9361_reg_remove(struct ad9361_reg_dev *dev)
|
||||||
|
{
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
ret = spi_remove(dev->spi_desc);
|
||||||
|
|
||||||
|
free(dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file ad9361_reg.h
|
||||||
|
* @brief Header file of ad9361_reg Driver.
|
||||||
|
* @author DBogdan (dragos.bogdan@analog.com)
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2014-2016(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef ad9361_reg_H_
|
||||||
|
#define ad9361_reg_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "delay.h"
|
||||||
|
#include "spi.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/********************** Macros and Constants Definitions **********************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
struct ad9361_reg_dev {
|
||||||
|
/* SPI */
|
||||||
|
struct spi_desc *spi_desc;
|
||||||
|
struct gpio_desc *gpio_desc_resetb;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ad9361_reg_init_param {
|
||||||
|
/* SPI */
|
||||||
|
struct spi_init_param *spi_init;
|
||||||
|
struct gpio_init_param *gpio_resetb;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Operation_Type{
|
||||||
|
AD9361_WRITE,
|
||||||
|
AD9361_READ,
|
||||||
|
AD9361_WAIT,
|
||||||
|
AD9361_WHEN
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ad9361_reg_config {
|
||||||
|
int operation;
|
||||||
|
uint16_t val1;
|
||||||
|
uint16_t val2;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
int32_t ad9361_reg_read(struct ad9361_reg_dev *dev,
|
||||||
|
uint16_t reg_addr,
|
||||||
|
uint8_t *reg_data);
|
||||||
|
|
||||||
|
int32_t ad9361_reg_write(struct ad9361_reg_dev *dev,
|
||||||
|
uint16_t reg_addr,
|
||||||
|
uint8_t reg_data);
|
||||||
|
|
||||||
|
int32_t ad9361_reg_init(struct ad9361_reg_dev **device,
|
||||||
|
const struct ad9361_reg_init_param *init_param);
|
||||||
|
|
||||||
|
int32_t ad9361_reg_reset(struct ad9361_reg_dev *dev);
|
||||||
|
|
||||||
|
int32_t ad9361_reg_remove(struct ad9361_reg_dev *dev);
|
||||||
|
|
||||||
|
#endif
|
||||||
+474
@@ -0,0 +1,474 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* Description: hwconfig.h
|
||||||
|
*
|
||||||
|
|
||||||
|
* Date: 2024-02-20 13:19
|
||||||
|
* Last Edit Time: [2024-02-20 13:19]
|
||||||
|
*
|
||||||
|
* Revisions: Rev 0.0
|
||||||
|
* History:
|
||||||
|
* [2023-05-07]: Initial edition.
|
||||||
|
*
|
||||||
|
* Copyright(c) 2024 Beijing Institute of Technology.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
// Standard
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
// Xilinx
|
||||||
|
#include "xgpiops.h"
|
||||||
|
#include "drivers/rf-transceiver/ad9361_reg/ad9361_reg.h"
|
||||||
|
#include "drivers/rf-transceiver/ad9361/ad9361_api.h"
|
||||||
|
#include "drivers/axi_core/spi_engine/spi_engine.h"
|
||||||
|
// App
|
||||||
|
#include "common.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "delay.h"
|
||||||
|
#include "system_monitor.h"
|
||||||
|
#include "hwconfig.h"
|
||||||
|
#include "config/app_config.h"
|
||||||
|
#include "dev_profile/dev_profile.h"
|
||||||
|
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
/*********************** Driver Instance Definitions **************************/
|
||||||
|
static struct hmc7044_dev *hmc7044_inst = NULL;
|
||||||
|
static struct ad9361_reg_dev *ad9361_1_reg_inst = NULL;
|
||||||
|
static struct ad9361_reg_dev *ad9361_2_reg_inst = NULL;
|
||||||
|
// static struct ad9361_rf_phy *ad9361_phy;
|
||||||
|
// static struct ad9361_rf_phy *ad9361_2_phy;
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Hardware_Init
|
||||||
|
*
|
||||||
|
* @param none.
|
||||||
|
*
|
||||||
|
* @return None.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t Hardware_Init(void)
|
||||||
|
{
|
||||||
|
int32_t Status;
|
||||||
|
XGpioPs Gpio;
|
||||||
|
XGpioPs_Config *ConfigPtr;
|
||||||
|
ConfigPtr = XGpioPs_LookupConfig(AD9361_GPIO_DEVICE_ID);
|
||||||
|
Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************/
|
||||||
|
/****************** HMC7044 Configuration *****************/
|
||||||
|
/**********************************************************/
|
||||||
|
Status = hmc7044_init(&hmc7044_inst, &hmc7044_default_init_param);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("hmc7044_init() error: %" PRId32 "\n", Status);
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************/
|
||||||
|
/***************** AD9361-1 Configuration *****************/
|
||||||
|
/**********************************************************/
|
||||||
|
XGpioPs_SetDirectionPin(&Gpio, AD9361_1_TXNRX, AD9361_GPIO_OUTPUT);
|
||||||
|
XGpioPs_SetDirectionPin(&Gpio, AD9361_1_ENABLE, AD9361_GPIO_OUTPUT);
|
||||||
|
XGpioPs_SetDirectionPin(&Gpio, AD9361_1_EN_AGC, AD9361_GPIO_OUTPUT);
|
||||||
|
XGpioPs_SetDirectionPin(&Gpio, AD9361_1_RESET_B, AD9361_GPIO_OUTPUT);
|
||||||
|
|
||||||
|
ad9361_reg_init(&ad9361_1_reg_inst, &ad9361_1_reg_default_init_param);
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_1_ENABLE, 0);
|
||||||
|
ad9361_reg_config(ad9361_1_reg_inst);
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_1_ENABLE, 1);
|
||||||
|
|
||||||
|
// Status = ad9361_init(&ad9361_phy, &ad9361_default_init_param);
|
||||||
|
// if (Status != XST_SUCCESS){
|
||||||
|
// return XST_FAILURE;
|
||||||
|
// }else{
|
||||||
|
// printf("Configurate AD9361 Completely!\n");
|
||||||
|
// }
|
||||||
|
// ad9361_set_tx_fir_config(ad9361_phy, tx_fir_config);
|
||||||
|
// ad9361_set_rx_fir_config(ad9361_phy, rx_fir_config);
|
||||||
|
|
||||||
|
/**********************************************************/
|
||||||
|
/***************** AD9361-2 Configuration *****************/
|
||||||
|
/**********************************************************/
|
||||||
|
XGpioPs_SetDirectionPin(&Gpio, AD9361_2_TXNRX, AD9361_GPIO_OUTPUT);
|
||||||
|
XGpioPs_SetDirectionPin(&Gpio, AD9361_2_ENABLE, AD9361_GPIO_OUTPUT);
|
||||||
|
XGpioPs_SetDirectionPin(&Gpio, AD9361_2_EN_AGC, AD9361_GPIO_OUTPUT);
|
||||||
|
XGpioPs_SetDirectionPin(&Gpio, AD9361_2_RESET_B, AD9361_GPIO_OUTPUT);
|
||||||
|
|
||||||
|
ad9361_reg_init(&ad9361_2_reg_inst, &ad9361_2_reg_default_init_param);
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_2_ENABLE, 0);
|
||||||
|
ad9361_reg_config(ad9361_2_reg_inst);
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_2_ENABLE, 1);
|
||||||
|
|
||||||
|
// uint8_t rd_back;
|
||||||
|
// Status = ad9361_reg_read(ad9361_1_reg_inst, 0x0002, &rd_back);
|
||||||
|
// Status = ad9361_reg_read(ad9361_2_reg_inst, 0x0002, &rd_back);
|
||||||
|
|
||||||
|
/**********************************************************/
|
||||||
|
/******* AD9361 Baseband Multichip Synchronization ********/
|
||||||
|
/**********************************************************/
|
||||||
|
XGpioPs_SetDirectionPin(&Gpio, AD9361_SYNC, AD9361_GPIO_OUTPUT);
|
||||||
|
XGpioPs_SetDirectionPin(&Gpio, AD9361_RX_FIFO_RST, AD9361_GPIO_OUTPUT);
|
||||||
|
|
||||||
|
// SYNC BBPLL and DIGITAL SAMPLING CLOCKS
|
||||||
|
ad9361_reg_write(ad9361_1_reg_inst, 0x0001, 0x0D); // MCS RF Enable; MCS BBPLL Enable; MCS BB Enable
|
||||||
|
ad9361_reg_write(ad9361_2_reg_inst, 0x0001, 0x0D);
|
||||||
|
ad9361_reg_write(ad9361_1_reg_inst, 0x0047, 0x80); // MCS refclk Scale Enable
|
||||||
|
ad9361_reg_write(ad9361_2_reg_inst, 0x0047, 0x80);
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_SYNC, 0);
|
||||||
|
mdelay(20);
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_SYNC, 1); // Input a rising-edge pulse to the SYNC_IN pin
|
||||||
|
mdelay(500);
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_SYNC, 0);
|
||||||
|
mdelay(2000);
|
||||||
|
ad9361_reg_write(ad9361_1_reg_inst, 0x0001, 0x0B); // MCS RF Enable; MCS Digital CLK Enable ; MCS BB Enable
|
||||||
|
ad9361_reg_write(ad9361_2_reg_inst, 0x0001, 0x0B);
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_SYNC, 1); // Input another rising-edge pulse to the SYNC_IN pin
|
||||||
|
mdelay(500);
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_SYNC, 0);
|
||||||
|
ad9361_reg_write(ad9361_1_reg_inst, 0x0001, 0x08); // clear MCS bits
|
||||||
|
ad9361_reg_write(ad9361_2_reg_inst, 0x0001, 0x08);
|
||||||
|
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_RX_FIFO_RST, 0);
|
||||||
|
mdelay(20);
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_RX_FIFO_RST, 1);
|
||||||
|
mdelay(20);
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_RX_FIFO_RST, 0);
|
||||||
|
|
||||||
|
/**********************************************************/
|
||||||
|
/********* AD9361 Multichip Rx Phase Calibration **********/
|
||||||
|
/**********************************************************/
|
||||||
|
XGpioPs_SetDirectionPin(&Gpio, AD9361_TX_SWITCH, AD9361_GPIO_OUTPUT);
|
||||||
|
XGpioPs_SetDirectionPin(&Gpio, AD9361_1_CAL_START, AD9361_GPIO_OUTPUT);
|
||||||
|
XGpioPs_SetDirectionPin(&Gpio, AD9361_1_CAL_DONE, AD9361_GPIO_INPUT);
|
||||||
|
XGpioPs_SetDirectionPin(&Gpio, AD9361_2_CAL_START, AD9361_GPIO_OUTPUT);
|
||||||
|
XGpioPs_SetDirectionPin(&Gpio, AD9361_2_CAL_DONE, AD9361_GPIO_INPUT);
|
||||||
|
|
||||||
|
// switch to lower frequency
|
||||||
|
Status = Hardware_SwitchFreq(ad9361_1_reg_inst, TX_FREQ_126);
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_TX_SWITCH, 1);
|
||||||
|
mdelay(20);
|
||||||
|
|
||||||
|
// switch rx channel
|
||||||
|
Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0004, 0x30);
|
||||||
|
Status = ad9361_reg_write(ad9361_2_reg_inst, 0x0004, 0x30);
|
||||||
|
|
||||||
|
// enable dual ad9361 tx channels
|
||||||
|
Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0002, 0xE4); // Setup Tx Digital Filters/ Channels
|
||||||
|
|
||||||
|
// switch ad9361 tx channel
|
||||||
|
Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0004, 0x70); // Select Rx input pin(A,B,C)/ Tx out pin (A,B)
|
||||||
|
mdelay(20);
|
||||||
|
|
||||||
|
// begin to calibrate the 1st ad9361
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_1_CAL_START, 0);
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_1_CAL_START, 1);
|
||||||
|
mdelay(1);
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_1_CAL_START, 0);
|
||||||
|
|
||||||
|
// read calibration status
|
||||||
|
int32_t time_out_cnt = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
mdelay(1); // Wait 1ms
|
||||||
|
time_out_cnt++;
|
||||||
|
} while (((XGpioPs_ReadPin(&Gpio, AD9361_1_CAL_DONE) == 0) && time_out_cnt <= AD9361_TIMEOUT_TH));
|
||||||
|
|
||||||
|
if (time_out_cnt == AD9361_TIMEOUT_TH)
|
||||||
|
{
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// begin to calibrate the 2nd ad9361
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_2_CAL_START, 1);
|
||||||
|
mdelay(1);
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_2_CAL_START, 0);
|
||||||
|
|
||||||
|
// read calibration status
|
||||||
|
time_out_cnt = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
mdelay(1); // Wait 1ms
|
||||||
|
time_out_cnt++;
|
||||||
|
} while (((XGpioPs_ReadPin(&Gpio, AD9361_2_CAL_DONE) == 0) && time_out_cnt <= AD9361_TIMEOUT_TH));
|
||||||
|
|
||||||
|
if (time_out_cnt == AD9361_TIMEOUT_TH)
|
||||||
|
{
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable single ad9361 tx channels
|
||||||
|
Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0002, 0xA4); // Setup Tx Digital Filters/ Channels
|
||||||
|
|
||||||
|
// switch ad9361 tx & rx channel
|
||||||
|
Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0004, 0x03);
|
||||||
|
Status = ad9361_reg_write(ad9361_2_reg_inst, 0x0004, 0x03);
|
||||||
|
|
||||||
|
// switch to higher frequency
|
||||||
|
Status = Hardware_SwitchFreq(ad9361_1_reg_inst, TX_FREQ_4125);
|
||||||
|
XGpioPs_WritePin(&Gpio, AD9361_TX_SWITCH, 0);
|
||||||
|
|
||||||
|
Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0109, 0x00); // Rx Gain
|
||||||
|
Status = ad9361_reg_write(ad9361_1_reg_inst, 0x010C, 0x00); // Rx Gain
|
||||||
|
Status = ad9361_reg_write(ad9361_2_reg_inst, 0x0109, 0x00); // Rx Gain
|
||||||
|
Status = ad9361_reg_write(ad9361_2_reg_inst, 0x010C, 0x00); // Rx Gain
|
||||||
|
|
||||||
|
DBG_PRINT("Done.\n");
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Hardware_SwitchFreq
|
||||||
|
*
|
||||||
|
* @param devSysMonitor_UpdateHardwareStatus(newHwState);
|
||||||
|
* @param freq
|
||||||
|
*
|
||||||
|
* @return None.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t Hardware_SwitchFreq(struct ad9361_reg_dev *dev, ad9361TxFreq freq)
|
||||||
|
{
|
||||||
|
int32_t status = 0;
|
||||||
|
uint8_t value = 0;
|
||||||
|
int32_t time_out_cnt = 0;
|
||||||
|
|
||||||
|
switch (freq)
|
||||||
|
{
|
||||||
|
case TX_FREQ_125:
|
||||||
|
{
|
||||||
|
//************************************************************
|
||||||
|
// Setup Tx Frequency-Dependent Syntheisizer Registers
|
||||||
|
//************************************************************
|
||||||
|
status = ad9361_reg_write(dev, 0x027A, 0x4A); // Set VCO Output level[3:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0279, 0xC1); // Set Init ALC Value[3:0] and VCO Varactor[3:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0282, 0x0E); // Set VCO Bias Tcf[1:0] and VCO Bias Ref[2:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0278, 0x78); // Set VCO Cal Offset[3:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0285, 0x00); // Set VCO Cal Ref Tcf[2:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0291, 0x0B); // Set VCO Varactor Reference[3:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0290, 0x70); // Set VCO Varactor Ref Tcf[2:0] and VCO Varactor Offset[3:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x027B, 0x94); // Set Synth Loop Filter charge pump current (Icp)
|
||||||
|
status = ad9361_reg_write(dev, 0x027E, 0xF4); // Set Synth Loop Filter C2 and C1
|
||||||
|
status = ad9361_reg_write(dev, 0x027F, 0xDF); // Set Synth Loop Filter R1 and C3
|
||||||
|
status = ad9361_reg_write(dev, 0x0280, 0x0A); // Set Synth Loop Filter R3
|
||||||
|
|
||||||
|
//************************************************************
|
||||||
|
// Write Tx Frequency Words
|
||||||
|
//************************************************************
|
||||||
|
status = ad9361_reg_write(dev, 0x0273, 0x00); // Write Tx Synth Fractional Freq Word[7:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0274, 0x00); // Write Tx Synth Fractional Freq Word[15:8]
|
||||||
|
status = ad9361_reg_write(dev, 0x0275, 0x00); // Write Tx Synth Fractional Freq Word[22:16]
|
||||||
|
status = ad9361_reg_write(dev, 0x0272, 0x00); // Write Tx Synth Integer Freq Word[10:8]
|
||||||
|
status = ad9361_reg_write(dev, 0x0271, 0xA0); // Write Tx Synth Integer Freq Word[7:0] (starts VCO cal)
|
||||||
|
status = ad9361_reg_write(dev, 0x0005, 0x57); // Set LO divider setting
|
||||||
|
|
||||||
|
//************************************************************
|
||||||
|
// Tx Quadrature Calibration Settings
|
||||||
|
//************************************************************
|
||||||
|
status = ad9361_reg_write(dev, 0x00A0, 0x75); // Set TxQuadcal NCO frequency
|
||||||
|
status = ad9361_reg_write(dev, 0x00A3, 0xC0); // Set TxQuadcal NCO frequency (Only update bits [7:6])
|
||||||
|
status = ad9361_reg_write(dev, 0x00A1, 0x7B); // Tx Quad Cal Configuration, Phase and Gain Cal Enable
|
||||||
|
status = ad9361_reg_write(dev, 0x00A9, 0xFF); // Set Tx Quad Cal Count
|
||||||
|
status = ad9361_reg_write(dev, 0x00A2, 0x7F); // Set Tx Quad Cal Kexp
|
||||||
|
status = ad9361_reg_write(dev, 0x00A5, 0x01); // Set Tx Quad Cal Magnitude Threshhold
|
||||||
|
status = ad9361_reg_write(dev, 0x00A6, 0x01); // Set Tx Quad Cal Magnitude Threshhold
|
||||||
|
status = ad9361_reg_write(dev, 0x00AA, 0x22); // Set Tx Quad Cal Gain Table index
|
||||||
|
status = ad9361_reg_write(dev, 0x00A4, 0xF0); // Set Tx Quad Cal Settle Count
|
||||||
|
status = ad9361_reg_write(dev, 0x00AE, 0x00); // Set Tx Quad Cal LPF Gain index incase Split table mode used
|
||||||
|
|
||||||
|
status = ad9361_reg_write(dev, 0x0169, 0xC0); // Disable Rx Quadrature Calibration before Running Tx Quadrature Calibration
|
||||||
|
status = ad9361_reg_write(dev, 0x0016, 0x10); // Start Tx Quad cal
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TX_FREQ_126:
|
||||||
|
{
|
||||||
|
//************************************************************
|
||||||
|
// Setup Tx Frequency-Dependent Syntheisizer Registers
|
||||||
|
//************************************************************
|
||||||
|
status = ad9361_reg_write(dev, 0x027A, 0x4A); // Set VCO Output level[3:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0279, 0xC1); // Set Init ALC Value[3:0] and VCO Varactor[3:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0282, 0x0E); // Set VCO Bias Tcf[1:0] and VCO Bias Ref[2:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0278, 0x78); // Set VCO Cal Offset[3:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0285, 0x00); // Set VCO Cal Ref Tcf[2:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0291, 0x0B); // Set VCO Varactor Reference[3:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0290, 0x70); // Set VCO Varactor Ref Tcf[2:0] and VCO Varactor Offset[3:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x027B, 0x93); // Set Synth Loop Filter charge pump current (Icp)
|
||||||
|
status = ad9361_reg_write(dev, 0x027E, 0xF4); // Set Synth Loop Filter C2 and C1
|
||||||
|
status = ad9361_reg_write(dev, 0x027F, 0xDF); // Set Synth Loop Filter R1 and C3
|
||||||
|
status = ad9361_reg_write(dev, 0x0280, 0x0A); // Set Synth Loop Filter R3
|
||||||
|
|
||||||
|
//************************************************************
|
||||||
|
// Write Tx Frequency Words
|
||||||
|
//************************************************************
|
||||||
|
status = ad9361_reg_write(dev, 0x0273, 0x06); // Write Tx Synth Fractional Freq Word[7:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0274, 0xD7); // Write Tx Synth Fractional Freq Word[15:8]
|
||||||
|
status = ad9361_reg_write(dev, 0x0275, 0x23); // Write Tx Synth Fractional Freq Word[22:16]
|
||||||
|
status = ad9361_reg_write(dev, 0x0272, 0x00); // Write Tx Synth Integer Freq Word[10:8]
|
||||||
|
status = ad9361_reg_write(dev, 0x0271, 0xA1); // Write Tx Synth Integer Freq Word[7:0] (starts VCO cal)
|
||||||
|
status = ad9361_reg_write(dev, 0x0005, 0x57); // Set LO divider setting
|
||||||
|
|
||||||
|
//************************************************************
|
||||||
|
// Tx Quadrature Calibration Settings
|
||||||
|
//************************************************************
|
||||||
|
status = ad9361_reg_write(dev, 0x00A0, 0x75); // Set TxQuadcal NCO frequency
|
||||||
|
status = ad9361_reg_write(dev, 0x00A3, 0xC0); // Set TxQuadcal NCO frequency (Only update bits [7:6])
|
||||||
|
status = ad9361_reg_write(dev, 0x00A1, 0x7B); // Tx Quad Cal Configuration, Phase and Gain Cal Enable
|
||||||
|
status = ad9361_reg_write(dev, 0x00A9, 0xFF); // Set Tx Quad Cal Count
|
||||||
|
status = ad9361_reg_write(dev, 0x00A2, 0x7F); // Set Tx Quad Cal Kexp
|
||||||
|
status = ad9361_reg_write(dev, 0x00A5, 0x01); // Set Tx Quad Cal Magnitude Threshhold
|
||||||
|
status = ad9361_reg_write(dev, 0x00A6, 0x01); // Set Tx Quad Cal Magnitude Threshhold
|
||||||
|
status = ad9361_reg_write(dev, 0x00AA, 0x22); // Set Tx Quad Cal Gain Table index
|
||||||
|
status = ad9361_reg_write(dev, 0x00A4, 0xF0); // Set Tx Quad Cal Settle Count
|
||||||
|
status = ad9361_reg_write(dev, 0x00AE, 0x00); // Set Tx Quad Cal LPF Gain index incase Split table mode used
|
||||||
|
|
||||||
|
status = ad9361_reg_write(dev, 0x0169, 0xC0); // Disable Rx Quadrature Calibration before Running Tx Quadrature Calibration
|
||||||
|
status = ad9361_reg_write(dev, 0x0016, 0x10); // Start Tx Quad cal
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TX_FREQ_4125:
|
||||||
|
{
|
||||||
|
//************************************************************
|
||||||
|
// Setup Tx Frequency-Dependent Syntheisizer Registers
|
||||||
|
//************************************************************
|
||||||
|
status = ad9361_reg_write(dev, 0x027A, 0x4A); // Set VCO Output level[3:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0279, 0xC1); // Set Init ALC Value[3:0] and VCO Varactor[3:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0282, 0x0E); // Set VCO Bias Tcf[1:0] and VCO Bias Ref[2:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0278, 0x78); // Set VCO Cal Offset[3:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0285, 0x00); // Set VCO Cal Ref Tcf[2:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0291, 0x0B); // Set VCO Varactor Reference[3:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0290, 0x70); // Set VCO Varactor Ref Tcf[2:0] and VCO Varactor Offset[3:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x027B, 0x93); // Set Synth Loop Filter charge pump current (Icp)
|
||||||
|
status = ad9361_reg_write(dev, 0x027E, 0xF4); // Set Synth Loop Filter C2 and C1
|
||||||
|
status = ad9361_reg_write(dev, 0x027F, 0xDF); // Set Synth Loop Filter R1 and C3
|
||||||
|
status = ad9361_reg_write(dev, 0x0280, 0x0A); // Set Synth Loop Filter R3
|
||||||
|
|
||||||
|
//************************************************************
|
||||||
|
// Write Rx Frequency Words
|
||||||
|
//************************************************************
|
||||||
|
status = ad9361_reg_write(dev, 0x0273, 0x00); // Write Tx Synth Fractional Freq Word[7:0]
|
||||||
|
status = ad9361_reg_write(dev, 0x0274, 0x00); // Write Tx Synth Fractional Freq Word[15:8]
|
||||||
|
status = ad9361_reg_write(dev, 0x0275, 0x00); // Write Tx Synth Fractional Freq Word[22:16]
|
||||||
|
status = ad9361_reg_write(dev, 0x0272, 0x00); // Write Tx Synth Integer Freq Word[10:8]
|
||||||
|
status = ad9361_reg_write(dev, 0x0271, 0xA5); // Write Tx Synth Integer Freq Word[7:0] (starts VCO cal)
|
||||||
|
status = ad9361_reg_write(dev, 0x0005, 0x07); // Set LO divider setting
|
||||||
|
|
||||||
|
//************************************************************
|
||||||
|
// Tx Quadrature Calibration Settings
|
||||||
|
//************************************************************
|
||||||
|
status = ad9361_reg_write(dev, 0x00A0, 0x75); // Set TxQuadcal NCO frequency
|
||||||
|
status = ad9361_reg_write(dev, 0x00A3, 0xC0); // Set TxQuadcal NCO frequency (Only update bits [7:6])
|
||||||
|
status = ad9361_reg_write(dev, 0x00A1, 0x7B); // Tx Quad Cal Configuration, Phase and Gain Cal Enable
|
||||||
|
status = ad9361_reg_write(dev, 0x00A9, 0xFF); // Set Tx Quad Cal Count
|
||||||
|
status = ad9361_reg_write(dev, 0x00A2, 0x7F); // Set Tx Quad Cal Kexp
|
||||||
|
status = ad9361_reg_write(dev, 0x00A5, 0x01); // Set Tx Quad Cal Magnitude Threshhold
|
||||||
|
status = ad9361_reg_write(dev, 0x00A6, 0x01); // Set Tx Quad Cal Magnitude Threshhold
|
||||||
|
status = ad9361_reg_write(dev, 0x00AA, 0x28); // Set Tx Quad Cal Gain Table index
|
||||||
|
status = ad9361_reg_write(dev, 0x00A4, 0xF0); // Set Tx Quad Cal Settle Count
|
||||||
|
status = ad9361_reg_write(dev, 0x00AE, 0x04); // Set Tx Quad Cal LPF Gain index incase Split table mode used
|
||||||
|
|
||||||
|
status = ad9361_reg_write(dev, 0x0169, 0xC0); // Disable Rx Quadrature Calibration before Running Tx Quadrature Calibration
|
||||||
|
status = ad9361_reg_write(dev, 0x0016, 0x10); // Start Tx Quad cal
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for cal to complete (Done when 0x016[4]==0)
|
||||||
|
time_out_cnt = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
status |= ad9361_reg_read(dev, 0x0016, &value);
|
||||||
|
mdelay(1); // Wait 1ms
|
||||||
|
time_out_cnt++;
|
||||||
|
} while ((value & 0x10) != 0x00 && time_out_cnt <= AD9361_TIMEOUT_TH);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ Get AD9361 - 1 temperature (Celsius Degree)
|
||||||
|
/**
|
||||||
|
* Read corresponding register to get AD9361 - 1 current temperature.
|
||||||
|
*/
|
||||||
|
int8_t Hardware_GetAD9361Temp_1(void)
|
||||||
|
{
|
||||||
|
int8_t scaleTemp;
|
||||||
|
double temp;
|
||||||
|
|
||||||
|
ad9361_reg_write(ad9361_1_reg_inst, 0x000B, -64);
|
||||||
|
ad9361_reg_write(ad9361_1_reg_inst, 0x001D, 0x01); // disable aux adc
|
||||||
|
ad9361_reg_read(ad9361_1_reg_inst, 0x000E, (uint8_t*)&scaleTemp);
|
||||||
|
ad9361_reg_write(ad9361_1_reg_inst, 0x001D, 0x00); // enable aux adc
|
||||||
|
|
||||||
|
temp = ((double)scaleTemp + 64)/1.16;
|
||||||
|
return ((temp > INT8_MAX) ? INT8_MAX : (int8_t)temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ Get AD9361 - 2 temperature (Celsius Degree)
|
||||||
|
/**
|
||||||
|
* Read corresponding register to get AD9361 - 2 current temperature.
|
||||||
|
*/
|
||||||
|
int8_t Hardware_GetAD9361Temp_2(void)
|
||||||
|
{
|
||||||
|
int8_t scaleTemp;
|
||||||
|
double temp;
|
||||||
|
|
||||||
|
ad9361_reg_write(ad9361_2_reg_inst, 0x000B, -64);
|
||||||
|
ad9361_reg_write(ad9361_2_reg_inst, 0x001D, 0x01); // disable aux adc
|
||||||
|
ad9361_reg_read(ad9361_2_reg_inst, 0x000E, (uint8_t*)&scaleTemp);
|
||||||
|
ad9361_reg_write(ad9361_2_reg_inst, 0x001D, 0x00); // enable aux adc
|
||||||
|
temp = ((double)scaleTemp + 64)/1.16;
|
||||||
|
return ((temp > INT8_MAX) ? INT8_MAX : (int8_t)temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ Determine AD9361 lock state
|
||||||
|
/**
|
||||||
|
* Read corresponding register to determine AD9361(both) lock state.
|
||||||
|
*/
|
||||||
|
uint8_t Hardware_GetAD9361LockStatus(void)
|
||||||
|
{
|
||||||
|
uint8_t ret = 0;
|
||||||
|
uint8_t regVal;
|
||||||
|
|
||||||
|
// bbpll
|
||||||
|
ad9361_reg_read(ad9361_1_reg_inst, 0x005E, ®Val); // [D7] is lock indicator
|
||||||
|
ret |= ((regVal & 0x80) == 0x80) ? CLK_AD0_BBPLL_LOCK : 0;
|
||||||
|
ad9361_reg_read(ad9361_2_reg_inst, 0x005E, ®Val); // [D7] is lock indicator
|
||||||
|
ret |= ((regVal & 0x80) == 0x80) ? CLK_AD1_BBPLL_LOCK : 0;
|
||||||
|
|
||||||
|
// rfpll
|
||||||
|
ad9361_reg_read(ad9361_1_reg_inst, 0x0287, ®Val); // [D1] is lock indicator
|
||||||
|
ret |= ((regVal & 0x02) == 0x02) ? CLK_AD0_RFPLL_LOCK : 0;
|
||||||
|
ad9361_reg_read(ad9361_2_reg_inst, 0x0287, ®Val); // [D1] is lock indicator
|
||||||
|
ret |= ((regVal & 0x02) == 0x02) ? CLK_AD1_RFPLL_LOCK : 0;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ Determine HMC7044 lock state
|
||||||
|
/**
|
||||||
|
* Read corresponding register to determine clock lock state.
|
||||||
|
*/
|
||||||
|
uint8_t Hardware_GetHMC7044LockStatus(void)
|
||||||
|
{
|
||||||
|
uint8_t ret = 0;
|
||||||
|
uint8_t regVal;
|
||||||
|
|
||||||
|
// pll1
|
||||||
|
hmc7044_read(hmc7044_inst, 0x007C, ®Val); // [D5] is lock indicator
|
||||||
|
ret |= ((regVal & 0xE0) != 0x00) ? CLK_SP_PLL0_LOCK : 0;
|
||||||
|
|
||||||
|
// pll2
|
||||||
|
hmc7044_read(hmc7044_inst, 0x007D, ®Val); // [D0] is lock indicator
|
||||||
|
ret |= ((regVal & 0x01) == 0x01) ? CLK_SP_PLL1_LOCK : 0;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* Description: hwconfig.h
|
||||||
|
*
|
||||||
|
|
||||||
|
* Date: 2024-02-20 13:19
|
||||||
|
* Last Edit Time: [2024-02-20 13:19]
|
||||||
|
*
|
||||||
|
* Revisions: Rev 0.0
|
||||||
|
* History:
|
||||||
|
* [2023-05-07]: Initial edition.
|
||||||
|
*
|
||||||
|
* Copyright(c) 2024 Beijing Institute of Technology.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
#ifndef HWCONFIG_H_
|
||||||
|
#define HWCONFIG_H_
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
// Standard
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "config/app_config.h"
|
||||||
|
#include "drivers/rf-transceiver/ad9361_reg/ad9361_reg.h"
|
||||||
|
#include "drivers/rf-transceiver/ad9361/ad9361_api.h"
|
||||||
|
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
int32_t Hardware_Init(void);
|
||||||
|
int32_t Hardware_SwitchFreq(struct ad9361_reg_dev *dev, ad9361TxFreq freq);
|
||||||
|
int8_t Hardware_GetAD9361Temp_1(void);
|
||||||
|
int8_t Hardware_GetAD9361Temp_2(void);
|
||||||
|
uint8_t Hardware_GetAD9361LockStatus(void);
|
||||||
|
uint8_t Hardware_GetHMC7044LockStatus(void);
|
||||||
|
|
||||||
|
#endif // HWCONFIG_H_
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file axi_io.h
|
||||||
|
* @brief Header file of AXI IO.
|
||||||
|
* @author Antoniu Miclaus (antoniu.miclaus@analog.com)
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _AXI_IO_H_
|
||||||
|
#define _AXI_IO_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/* AXI IO Read data */
|
||||||
|
int32_t axi_io_read(uint32_t base, uint32_t offset, uint32_t *data);
|
||||||
|
|
||||||
|
/* AXI IO Write data */
|
||||||
|
int32_t axi_io_write(uint32_t base, uint32_t offset, uint32_t data);
|
||||||
|
|
||||||
|
#endif // _AXI_IO_H_
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file circ_queue.h
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief A simple circular FIFO bounded queue
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-02-23
|
||||||
|
* @note Forked from https://github.com/chrismerck/rpa_queue.git
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup Utility
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup CircularQueue
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CIRC_QUEUE_H
|
||||||
|
#define CIRC_QUEUE_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct CIRC_QUEUE
|
||||||
|
* @brief Circular queue Instance
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
void **data;
|
||||||
|
volatile uint32_t nelts; ///< number of elements
|
||||||
|
uint32_t in; ///< next empty location
|
||||||
|
uint32_t out; ///< next filled location
|
||||||
|
uint32_t bounds; ///< max size of queue
|
||||||
|
} CIRC_QUEUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief create a FIFO queue
|
||||||
|
* @param queue The new queue
|
||||||
|
* @param queue_capacity maximum size of the queue
|
||||||
|
*/
|
||||||
|
bool CircQueueCreate(CIRC_QUEUE **queue, uint32_t queue_capacity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief free queue memory -- call after destroy
|
||||||
|
*/
|
||||||
|
void CircQueueFree(CIRC_QUEUE *queue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Detects when the CIRC_QUEUE is full. This utility function is expected
|
||||||
|
* to be called from within critical sections, and is not threadsafe.
|
||||||
|
*/
|
||||||
|
bool isCircQueueFull(CIRC_QUEUE *queue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Detects when the CIRC_QUEUE is empty. This utility function is expected
|
||||||
|
* to be called from within critical sections, and is not threadsafe.
|
||||||
|
*/
|
||||||
|
bool isCircQueueEmpty(CIRC_QUEUE *queue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief push/add an object to the queue, blocking if the queue is already full
|
||||||
|
*
|
||||||
|
* @param queue the queue
|
||||||
|
* @param data the data
|
||||||
|
* @return True on a successful push
|
||||||
|
* @return False push failed
|
||||||
|
*/
|
||||||
|
bool CircQueuePush(CIRC_QUEUE *queue, void *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief pop/get an object from the queue, blocking if the queue is already empty
|
||||||
|
*
|
||||||
|
* @param queue the queue
|
||||||
|
* @param data the data
|
||||||
|
* @return false pop failed
|
||||||
|
* @return true on a successful pop
|
||||||
|
*/
|
||||||
|
bool CircQueuePop(CIRC_QUEUE *queue, void **data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief returns the size of the queue.
|
||||||
|
*
|
||||||
|
* @param queue the queue
|
||||||
|
* @return the size of the queue
|
||||||
|
*/
|
||||||
|
uint32_t CircQueueSize(CIRC_QUEUE *queue);
|
||||||
|
|
||||||
|
#endif /* CIRC_QUEUE_H */
|
||||||
|
|
||||||
|
/** @} CircularQueue*/
|
||||||
|
|
||||||
|
/** @} Utility*/
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file clist.h
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief A basic list data structure
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-02-23
|
||||||
|
* @note Forked from https://github.com/clibs/list
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup Utility
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup cList
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CLIST_H__
|
||||||
|
#define __CLIST_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum clist_direction_t
|
||||||
|
* @brief clist_t iterator direction.
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
LIST_HEAD,
|
||||||
|
LIST_TAIL
|
||||||
|
} clist_direction_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct clist_node_t
|
||||||
|
* @brief clist_t node struct.
|
||||||
|
*/
|
||||||
|
typedef struct clist_node
|
||||||
|
{
|
||||||
|
struct clist_node *prev; ///< previous node
|
||||||
|
struct clist_node *next; ///< next node
|
||||||
|
void *val;
|
||||||
|
} clist_node_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct clist_t
|
||||||
|
* @brief clist_t struct.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
clist_node_t *head; ///< first node
|
||||||
|
clist_node_t *tail; ///< last node
|
||||||
|
uint32_t len; ///< list length
|
||||||
|
void (*free)(void *val); ///< node free function handle
|
||||||
|
int8_t (*compare)(void *a, void *b); ///< node compare function handle
|
||||||
|
} clist_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct clist_iterator_t
|
||||||
|
* @brief clist_t iterator struct.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
clist_node_t *next; ///< next element
|
||||||
|
clist_direction_t direction; ///< iter direction
|
||||||
|
} clist_iterator_t;
|
||||||
|
|
||||||
|
// Node prototypes.
|
||||||
|
|
||||||
|
clist_node_t *
|
||||||
|
clist_node_new(void *val);
|
||||||
|
|
||||||
|
// clist_t prototypes.
|
||||||
|
|
||||||
|
clist_t *
|
||||||
|
clist_new(void);
|
||||||
|
|
||||||
|
clist_node_t *
|
||||||
|
clist_rpush(clist_t *self, clist_node_t *node);
|
||||||
|
|
||||||
|
clist_node_t *
|
||||||
|
clist_lpush(clist_t *self, clist_node_t *node);
|
||||||
|
|
||||||
|
clist_node_t *
|
||||||
|
clist_find(clist_t *self, void *val);
|
||||||
|
|
||||||
|
clist_node_t *
|
||||||
|
clist_at(clist_t *self, int index);
|
||||||
|
|
||||||
|
clist_node_t *
|
||||||
|
clist_rpop(clist_t *self);
|
||||||
|
|
||||||
|
clist_node_t *
|
||||||
|
clist_lpop(clist_t *self);
|
||||||
|
|
||||||
|
void
|
||||||
|
clist_remove(clist_t *self, clist_node_t *node);
|
||||||
|
|
||||||
|
void
|
||||||
|
clist_clear(clist_t *self);
|
||||||
|
|
||||||
|
void
|
||||||
|
clist_destroy(clist_t *self);
|
||||||
|
|
||||||
|
// clist_t iterator prototypes.
|
||||||
|
|
||||||
|
clist_iterator_t *
|
||||||
|
clist_iterator_new(clist_t *list, clist_direction_t direction);
|
||||||
|
|
||||||
|
clist_iterator_t *
|
||||||
|
clist_iterator_new_from_node(clist_node_t *node, clist_direction_t direction);
|
||||||
|
|
||||||
|
clist_node_t *
|
||||||
|
clist_iterator_next(clist_iterator_t *self);
|
||||||
|
|
||||||
|
void
|
||||||
|
clist_iterator_destroy(clist_iterator_t *self);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __CLIBS_LIST_H__ */
|
||||||
|
|
||||||
|
/** @} cList*/
|
||||||
|
|
||||||
|
/** @} Utility*/
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file common.h
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief Common macros
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2022-07-16
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* @defgroup COMMON_MACRO
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#ifndef __COMMON_H_
|
||||||
|
#define __COMMON_H_
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/************************** Constant Definitions *****************************/
|
||||||
|
/***************** Macros (Inline Functions) Definitions *********************/
|
||||||
|
#define __PRINT_BLOCK(block) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
block \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ASSERT(exp) ((exp) ? (void)0 : AppAssert(__FILE__, __LINE__))
|
||||||
|
#define _nop_() __asm__("nop")
|
||||||
|
|
||||||
|
/* Stringify */
|
||||||
|
#define STR(x) #x
|
||||||
|
|
||||||
|
// #define _DEBUG_LEVEL 3
|
||||||
|
|
||||||
|
#if _DEBUG_LEVEL > 0
|
||||||
|
#define DBG_PRINT(...) printf(__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
#if _DEBUG_LEVEL >= 1
|
||||||
|
#define DBG_ERROR(...) __PRINT_BLOCK( \
|
||||||
|
printf("in "__FILE__ \
|
||||||
|
":%d [error]\t", \
|
||||||
|
__LINE__); \
|
||||||
|
printf(__VA_ARGS__);)
|
||||||
|
#endif
|
||||||
|
#if _DEBUG_LEVEL >= 2
|
||||||
|
#define DBG_WARNING(...) __PRINT_BLOCK( \
|
||||||
|
printf("[warning]\t"); \
|
||||||
|
printf(__VA_ARGS__);)
|
||||||
|
#endif
|
||||||
|
#if _DEBUG_LEVEL >= 3
|
||||||
|
#define DBG_INFO(...) __PRINT_BLOCK( \
|
||||||
|
printf("[Info]\t"); \
|
||||||
|
printf(__VA_ARGS__);)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DBG_ERROR
|
||||||
|
#define DBG_ERROR(...) \
|
||||||
|
{ \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifndef DBG_WARNING
|
||||||
|
#define DBG_WARNING(...) \
|
||||||
|
{ \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifndef DBG_INFO
|
||||||
|
#define DBG_INFO(...) \
|
||||||
|
{ \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifndef DBG_PRINT
|
||||||
|
#define DBG_PRINT(...) \
|
||||||
|
{ \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/**************************** Type Definitions *******************************/
|
||||||
|
|
||||||
|
/************************** Variable Definitions *****************************/
|
||||||
|
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
void AppAssert(const char *file, int line);
|
||||||
|
#endif /* __COMMON_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file delay.h
|
||||||
|
* @brief Header file of Delay functions
|
||||||
|
* @author DBogdan (dragos.bogdan@analog.com)
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _DELAY_H_
|
||||||
|
#define _DELAY_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct time
|
||||||
|
* @brief Structure holding time data (seconds, microseconds).
|
||||||
|
*/
|
||||||
|
struct time {
|
||||||
|
unsigned int s, us;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/* Generate microseconds delay. */
|
||||||
|
void udelay(uint32_t usecs);
|
||||||
|
|
||||||
|
/* Generate miliseconds delay. */
|
||||||
|
void mdelay(uint32_t msecs);
|
||||||
|
|
||||||
|
/* Get current time */
|
||||||
|
struct time get_time(void);
|
||||||
|
|
||||||
|
#endif // _DELAY_H_
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file common.h
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief Common error numbers
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2022-06-18
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup COMMON_MACRO
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRC_ERROR_H_
|
||||||
|
#define SRC_ERROR_H_
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/********************** Macros and Constants Definitions **********************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ERRORNO
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef SUCCESS
|
||||||
|
#undef SUCCESS
|
||||||
|
#endif
|
||||||
|
#define SUCCESS 0
|
||||||
|
#ifdef FAILURE
|
||||||
|
#undef FAILURE
|
||||||
|
#endif
|
||||||
|
#define FAILURE -1
|
||||||
|
|
||||||
|
#define EPARAM -2 /*!< Data crc check failed */
|
||||||
|
#define ECRC -3 /*!< Data crc check failed */
|
||||||
|
#define EDINVAL -4 /*!< Device is invalid (sleep or power off) */
|
||||||
|
#define EDCONF -5 /*!< Device confugure error */
|
||||||
|
#define ETIMEOUT -6 /*!< Timeout error */
|
||||||
|
#define EIGNORE -7 /*!< Received an unsupported command, and ignore it */
|
||||||
|
#define EQUEUE -8 /*!< Queue overflow */
|
||||||
|
#define EUNEXP -9 /*!< Encounter an unexpected error */
|
||||||
|
|
||||||
|
#define IS_ERR_VALUE(x) ((x) != SUCCESS)
|
||||||
|
|
||||||
|
#endif // ERROR_H_
|
||||||
|
|
||||||
|
/** @} ERRORNO*/
|
||||||
|
|
||||||
|
/** @} COMMON_MACRO*/
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
#ifndef SRC_GLOBAL_TIMER_H_
|
||||||
|
#define SRC_GLOBAL_TIMER_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct timer_init_param
|
||||||
|
* @brief Structure holding the parameters for timer initialization
|
||||||
|
*/
|
||||||
|
struct global_timer_init_param {
|
||||||
|
/** timer ID */
|
||||||
|
uintptr_t base_addr;
|
||||||
|
/** timer ID */
|
||||||
|
uint16_t id;
|
||||||
|
/** timer count frequency (Hz) */
|
||||||
|
uint32_t freq_hz;
|
||||||
|
/** counter start value */
|
||||||
|
uint64_t load_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct timer_desc
|
||||||
|
* @brief Structure holding timer descriptor
|
||||||
|
*/
|
||||||
|
struct global_timer_desc {
|
||||||
|
/** timer ID */
|
||||||
|
uintptr_t base_addr;
|
||||||
|
/** timer ID */
|
||||||
|
uint16_t id;
|
||||||
|
/** timer count frequency (Hz) */
|
||||||
|
uint32_t freq_hz;
|
||||||
|
/** counter start value */
|
||||||
|
uint64_t load_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/* Initialize hardware timer and the handler structure associated with it. */
|
||||||
|
int32_t global_timer_init(struct global_timer_desc **desc,
|
||||||
|
struct global_timer_init_param *param);
|
||||||
|
|
||||||
|
/* Free the memory allocated by timer_setup(). */
|
||||||
|
int32_t global_timer_remove(struct global_timer_desc *desc);
|
||||||
|
|
||||||
|
/* Start a timer. */
|
||||||
|
int32_t global_timer_start(struct global_timer_desc *desc);
|
||||||
|
|
||||||
|
/* Stop a timer from counting. */
|
||||||
|
int32_t global_timer_stop(struct global_timer_desc *desc);
|
||||||
|
|
||||||
|
/* Get the value of the counter register for the timer. */
|
||||||
|
int32_t global_timer_counter_get(struct global_timer_desc *desc, uint64_t *counter);
|
||||||
|
|
||||||
|
/* Set the timer counter register value. */
|
||||||
|
int32_t global_timer_counter_set(struct global_timer_desc *desc, uint64_t new_val);
|
||||||
|
|
||||||
|
/* Get the timer clock frequency. */
|
||||||
|
int32_t global_timer_count_clk_get(struct global_timer_desc *desc, uint32_t *freq_hz);
|
||||||
|
|
||||||
|
/* Set the timer clock frequency. */
|
||||||
|
int32_t global_timer_count_clk_set(struct global_timer_desc *desc, uint32_t freq_hz);
|
||||||
|
|
||||||
|
/* Enable global timer interrupt. */
|
||||||
|
int32_t global_timer_irq_enable(struct global_timer_desc *desc);
|
||||||
|
|
||||||
|
/* Disable global timer interrupt. */
|
||||||
|
int32_t global_timer_irq_disable(struct global_timer_desc *desc);
|
||||||
|
|
||||||
|
/* Implement a acknowledgment global timer interrupt. */
|
||||||
|
int32_t global_timer_irq_ack(struct global_timer_desc *desc);
|
||||||
|
|
||||||
|
/* Set comparator register. */
|
||||||
|
int32_t global_timer_compara_set(struct global_timer_desc *desc, uint64_t com_val);
|
||||||
|
|
||||||
|
/* Set auto increment register . */
|
||||||
|
int32_t global_timer_auto_inc_set(struct global_timer_desc *desc, uint32_t inc_val);
|
||||||
|
|
||||||
|
/* Enable global timer auto increment mode. */
|
||||||
|
int32_t global_timer_auto_inc_enable(struct global_timer_desc *desc);
|
||||||
|
|
||||||
|
/* Disable global timer auto increment mode. */
|
||||||
|
int32_t global_timer_auto_inc_disable(struct global_timer_desc *desc);
|
||||||
|
|
||||||
|
#endif /* SRC_TIMER_H_ */
|
||||||
|
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file gpio.h
|
||||||
|
* @brief Header file of GPIO Interface
|
||||||
|
* @author DBogdan (dragos.bogdan@analog.com)
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _GPIO_H_
|
||||||
|
#define _GPIO_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/********************** Macros and Constants Definitions **********************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#define GPIO_OUT 0x01
|
||||||
|
#define GPIO_IN 0x00
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct gpio_platform_ops
|
||||||
|
* @brief Structure holding gpio function pointers that point to the platform
|
||||||
|
* specific function
|
||||||
|
*/
|
||||||
|
struct gpio_platform_ops ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum gpio_pull_up
|
||||||
|
* @brief Enum that holds the possible pull up/ pull down resistor configuration.
|
||||||
|
*/
|
||||||
|
enum gpio_pull_up {
|
||||||
|
PULL_NONE,
|
||||||
|
/** Strong pull up */
|
||||||
|
PULL_UP,
|
||||||
|
/** Strong pull down */
|
||||||
|
PULL_DOWN,
|
||||||
|
PULL_UP_WEAK,
|
||||||
|
PULL_DOWN_WEAK
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct gpio_init_param
|
||||||
|
* @brief Structure holding the parameters for GPIO initialization.
|
||||||
|
*/
|
||||||
|
struct gpio_init_param {
|
||||||
|
/** Port number */
|
||||||
|
int32_t port;
|
||||||
|
/** GPIO number */
|
||||||
|
int32_t number;
|
||||||
|
/** Pull up/down resistor configuration */
|
||||||
|
enum gpio_pull_up pull;
|
||||||
|
/** GPIO platform specific functions */
|
||||||
|
const struct gpio_platform_ops *platform_ops;
|
||||||
|
/** GPIO extra parameters (device specific) */
|
||||||
|
void *extra;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct gpio_desc
|
||||||
|
* @brief Structure holding the GPIO descriptor.
|
||||||
|
*/
|
||||||
|
struct gpio_desc {
|
||||||
|
/** Port number */
|
||||||
|
int32_t port;
|
||||||
|
/** GPIO number */
|
||||||
|
int32_t number;
|
||||||
|
/** Pull up/down resistor configuration */
|
||||||
|
enum gpio_pull_up pull;
|
||||||
|
/** GPIO platform specific functions */
|
||||||
|
const struct gpio_platform_ops *platform_ops;
|
||||||
|
/** GPIO extra parameters (device specific) */
|
||||||
|
void *extra;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum gpio_values
|
||||||
|
* @brief Enum that holds the possible output states of a GPIO.
|
||||||
|
*/
|
||||||
|
enum gpio_values {
|
||||||
|
/** GPIO logic low */
|
||||||
|
GPIO_LOW,
|
||||||
|
/** GPIO logic high */
|
||||||
|
GPIO_HIGH,
|
||||||
|
/** GPIO high impedance */
|
||||||
|
GPIO_HIGH_Z
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct gpio_platform_ops
|
||||||
|
* @brief Structure holding gpio function pointers that point to the platform
|
||||||
|
* specific function
|
||||||
|
*/
|
||||||
|
struct gpio_platform_ops {
|
||||||
|
/** gpio initialization function pointer */
|
||||||
|
int32_t (*gpio_ops_get)(struct gpio_desc **,
|
||||||
|
const struct gpio_init_param *);
|
||||||
|
/** gpio optional descriptor function pointer */
|
||||||
|
int32_t (*gpio_ops_get_optional)(struct gpio_desc **,
|
||||||
|
const struct gpio_init_param *);
|
||||||
|
/** gpio remove function pointer */
|
||||||
|
int32_t (*gpio_ops_remove)(struct gpio_desc *);
|
||||||
|
/** gpio direction input function pointer */
|
||||||
|
int32_t (*gpio_ops_direction_input)(struct gpio_desc *);
|
||||||
|
/** gpio direction output function pointer */
|
||||||
|
int32_t (*gpio_ops_direction_output)(struct gpio_desc *, uint8_t);
|
||||||
|
/** gpio get direction function pointer */
|
||||||
|
int32_t (*gpio_ops_get_direction)(struct gpio_desc *, uint8_t *);
|
||||||
|
/** gpio set value function pointer */
|
||||||
|
int32_t (*gpio_ops_set_value)(struct gpio_desc *, uint8_t);
|
||||||
|
/** gpio get value function pointer */
|
||||||
|
int32_t (*gpio_ops_get_value)(struct gpio_desc *, uint8_t *);
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/* Obtain the GPIO decriptor. */
|
||||||
|
int32_t gpio_get(struct gpio_desc **desc,
|
||||||
|
const struct gpio_init_param *param);
|
||||||
|
|
||||||
|
/* Obtain optional GPIO descriptor. */
|
||||||
|
int32_t gpio_get_optional(struct gpio_desc **desc,
|
||||||
|
const struct gpio_init_param *param);
|
||||||
|
|
||||||
|
/* Free the resources allocated by gpio_get(). */
|
||||||
|
int32_t gpio_remove(struct gpio_desc *desc);
|
||||||
|
|
||||||
|
/* Enable the input direction of the specified GPIO. */
|
||||||
|
int32_t gpio_direction_input(struct gpio_desc *desc);
|
||||||
|
|
||||||
|
/* Enable the output direction of the specified GPIO. */
|
||||||
|
int32_t gpio_direction_output(struct gpio_desc *desc,
|
||||||
|
uint8_t value);
|
||||||
|
|
||||||
|
/* Get the direction of the specified GPIO. */
|
||||||
|
int32_t gpio_get_direction(struct gpio_desc *desc,
|
||||||
|
uint8_t *direction);
|
||||||
|
|
||||||
|
/* Set the value of the specified GPIO. */
|
||||||
|
int32_t gpio_set_value(struct gpio_desc *desc,
|
||||||
|
uint8_t value);
|
||||||
|
|
||||||
|
/* Get the value of the specified GPIO. */
|
||||||
|
int32_t gpio_get_value(struct gpio_desc *desc,
|
||||||
|
uint8_t *value);
|
||||||
|
|
||||||
|
#endif // _GPIO_H_
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file i2c.h
|
||||||
|
* @brief Header file of I2C Interface
|
||||||
|
* @author DBogdan (dragos.bogdan@analog.com)
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _I2C_H_
|
||||||
|
#define _I2C_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct i2c_platform_ops
|
||||||
|
* @brief Structure holding I2C function pointers that point to the platform
|
||||||
|
* specific function
|
||||||
|
*/
|
||||||
|
struct i2c_platform_ops ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct i2c_init_param
|
||||||
|
* @brief Structure holding the parameters for I2C initialization.
|
||||||
|
*/
|
||||||
|
struct i2c_init_param {
|
||||||
|
/** Device ID */
|
||||||
|
uint32_t device_id;
|
||||||
|
/** I2C maximum transfer speed supported */
|
||||||
|
uint32_t max_speed_hz;
|
||||||
|
/** Slave address */
|
||||||
|
uint8_t slave_address;
|
||||||
|
/** I2C platform specific functions */
|
||||||
|
const struct i2c_platform_ops *platform_ops;
|
||||||
|
/** I2C extra parameters (device specific parameters) */
|
||||||
|
void *extra;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct i2c_desc
|
||||||
|
* @brief Structure holding I2C descriptor
|
||||||
|
*/
|
||||||
|
struct i2c_desc {
|
||||||
|
/** Device ID */
|
||||||
|
uint32_t device_id;
|
||||||
|
/** I2C maximum transfer speed supported */
|
||||||
|
uint32_t max_speed_hz;
|
||||||
|
/** Slave address */
|
||||||
|
uint8_t slave_address;
|
||||||
|
/** I2C platform specific functions */
|
||||||
|
const struct i2c_platform_ops *platform_ops;
|
||||||
|
/** I2C extra parameters (device specific parameters) */
|
||||||
|
void *extra;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct i2c_platform_ops
|
||||||
|
* @brief Structure holding i2c function pointers that point to the platform
|
||||||
|
* specific function
|
||||||
|
*/
|
||||||
|
struct i2c_platform_ops {
|
||||||
|
/** i2c initialization function pointer */
|
||||||
|
int32_t (*i2c_ops_init)(struct i2c_desc **,
|
||||||
|
const struct i2c_init_param *);
|
||||||
|
/** i2c write function pointer */
|
||||||
|
int32_t (*i2c_ops_write)(struct i2c_desc *, uint8_t *, uint8_t, uint8_t);
|
||||||
|
/** i2c write function pointer */
|
||||||
|
int32_t (*i2c_ops_read)(struct i2c_desc *, uint8_t *, uint8_t, uint8_t);
|
||||||
|
/** i2c remove function pointer */
|
||||||
|
int32_t (*i2c_ops_remove)(struct i2c_desc *);
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/* Initialize the I2C communication peripheral. */
|
||||||
|
int32_t i2c_init(struct i2c_desc **desc,
|
||||||
|
const struct i2c_init_param *param);
|
||||||
|
|
||||||
|
/* Free the resources allocated by i2c_init(). */
|
||||||
|
int32_t i2c_remove(struct i2c_desc *desc);
|
||||||
|
|
||||||
|
/* Write data to a slave device. */
|
||||||
|
int32_t i2c_write(struct i2c_desc *desc,
|
||||||
|
uint8_t *data,
|
||||||
|
uint8_t bytes_number,
|
||||||
|
uint8_t stop_bit);
|
||||||
|
|
||||||
|
/* Read data from a slave device. */
|
||||||
|
int32_t i2c_read(struct i2c_desc *desc,
|
||||||
|
uint8_t *data,
|
||||||
|
uint8_t bytes_number,
|
||||||
|
uint8_t stop_bit);
|
||||||
|
|
||||||
|
#endif // _I2C_H_
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file irq.h
|
||||||
|
* @brief Header file of IRQ interface.
|
||||||
|
* @author Cristian Pop (cristian.pop@analog.com)
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _IRQ_H_
|
||||||
|
#define _IRQ_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum irq_uart_event_e
|
||||||
|
* @brief Possible events for uart interrupt
|
||||||
|
* @todo replace this with enum irq_event
|
||||||
|
*/
|
||||||
|
enum irq_uart_event_e {
|
||||||
|
/** Write operation finalized */
|
||||||
|
IRQ_WRITE_DONE,
|
||||||
|
/** Read operation finalized */
|
||||||
|
IRQ_READ_DONE,
|
||||||
|
/** An error occurred */
|
||||||
|
IRQ_ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
enum irq_event {
|
||||||
|
EVT_GPIO,
|
||||||
|
EVT_UART_TX_COMPLETE,
|
||||||
|
EVT_UART_RX_COMPLETE,
|
||||||
|
EVT_UART_ERROR,
|
||||||
|
EVT_RTC,
|
||||||
|
EVT_XINT,
|
||||||
|
EVT_TIM_ELAPSED
|
||||||
|
};
|
||||||
|
|
||||||
|
enum irq_trig_level {
|
||||||
|
IRQ_LEVEL_LOW,
|
||||||
|
IRQ_LEVEL_HIGH,
|
||||||
|
IRQ_EDGE_FALLING,
|
||||||
|
IRQ_EDGE_RISING,
|
||||||
|
IRQ_EDGE_BOTH
|
||||||
|
};
|
||||||
|
|
||||||
|
enum irq_peripheral {
|
||||||
|
GPIO_IRQ,
|
||||||
|
UART_IRQ,
|
||||||
|
RTC_IRQ,
|
||||||
|
TIM_IRQ
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct irq_platform_ops
|
||||||
|
* @brief Structure holding IRQ function pointers that point to the platform
|
||||||
|
* specific function
|
||||||
|
*/
|
||||||
|
struct irq_platform_ops ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct irq_init_param
|
||||||
|
* @brief Structure holding the initial parameters for Interrupt Request.
|
||||||
|
*/
|
||||||
|
struct irq_init_param {
|
||||||
|
/** Interrupt request controller ID. */
|
||||||
|
uint32_t irq_ctrl_id;
|
||||||
|
/** Platform specific IRQ platform ops structure. */
|
||||||
|
const struct irq_platform_ops *platform_ops;
|
||||||
|
/**
|
||||||
|
* This is intended to store irq controller specific configurations,
|
||||||
|
* it should not be a reference to any peripheral descriptor.
|
||||||
|
*/
|
||||||
|
void *extra;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct irq_desc
|
||||||
|
* @brief Structure for Interrupt Request descriptor.
|
||||||
|
*/
|
||||||
|
struct irq_ctrl_desc {
|
||||||
|
/** Interrupt request controller ID. */
|
||||||
|
uint32_t irq_ctrl_id;
|
||||||
|
/** Platform specific IRQ platform ops structure. */
|
||||||
|
const struct irq_platform_ops *platform_ops;
|
||||||
|
/**
|
||||||
|
* This is intended to store irq controller specific configurations,
|
||||||
|
* it should not be a reference to any peripheral descriptor.
|
||||||
|
*/
|
||||||
|
void *extra;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct callback_desc
|
||||||
|
* @brief Structure describing a callback to be registered
|
||||||
|
* @todo: remove this, use struct irq_callback instead.
|
||||||
|
*/
|
||||||
|
struct callback_desc {
|
||||||
|
/** Callback to be called when the event an event occurs. */
|
||||||
|
void (*callback)(void *context);
|
||||||
|
/**
|
||||||
|
* Callback to be called when the event an event occurs
|
||||||
|
* @param ctx - Same as \ref callback_desc.ctx
|
||||||
|
* @param event - Event that generated the callback
|
||||||
|
* @param extra - Platform specific data
|
||||||
|
*/
|
||||||
|
void (*legacy_callback)(void *ctx, uint32_t event,
|
||||||
|
void *extra); /* TODO: remove this. */
|
||||||
|
/** Parameter to be passed when the callback is called */
|
||||||
|
void *ctx;
|
||||||
|
/** Platform specific configuration for a callback */
|
||||||
|
void *legacy_config; /* TODO: remove this. */
|
||||||
|
/** Platform specific event that triggers the calling of the callback. */
|
||||||
|
enum irq_event event;
|
||||||
|
/** Interrupt source peripheral specifier. */
|
||||||
|
enum irq_peripheral peripheral;
|
||||||
|
/** This will be used to store HAL specific descriptors */
|
||||||
|
void *handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct irq_platform_ops
|
||||||
|
* @brief Structure holding IRQ function pointers that point to the platform
|
||||||
|
* specific function
|
||||||
|
*/
|
||||||
|
struct irq_platform_ops {
|
||||||
|
/** Initialize a interrupt controller peripheral. */
|
||||||
|
int32_t (*init)(struct irq_ctrl_desc **desc,
|
||||||
|
const struct irq_init_param *param);
|
||||||
|
/** Register a legacy_callback to handle the irq events */
|
||||||
|
int32_t (*register_callback)(struct irq_ctrl_desc *desc, uint32_t irq_id,
|
||||||
|
struct callback_desc *callback);
|
||||||
|
/** Unregisters a generic IRQ handling function */
|
||||||
|
int32_t (*unregister_callback)(struct irq_ctrl_desc *desc,
|
||||||
|
uint32_t irq_id,
|
||||||
|
struct callback_desc *callback);
|
||||||
|
/** Global interrupt enable */
|
||||||
|
int32_t (*global_enable)(struct irq_ctrl_desc *desc);
|
||||||
|
/** Global interrupt disable */
|
||||||
|
int32_t (*global_disable)(struct irq_ctrl_desc *desc);
|
||||||
|
/** Set interrupt trigger level. */
|
||||||
|
int32_t (*trigger_level_set)(struct irq_ctrl_desc *desc, uint32_t irq_id,
|
||||||
|
enum irq_trig_level trig);
|
||||||
|
/** Enable specific interrupt */
|
||||||
|
int32_t (*enable)(struct irq_ctrl_desc *desc, uint32_t irq_id);
|
||||||
|
/** Disable specific interrupt */
|
||||||
|
int32_t (*disable)(struct irq_ctrl_desc *desc, uint32_t irq_id);
|
||||||
|
/** Set the priority level for a specific interrupt */
|
||||||
|
int32_t (*set_priority)(struct irq_ctrl_desc *desc, uint32_t irq_id,
|
||||||
|
uint32_t priority_level);
|
||||||
|
/** IRQ remove function pointer */
|
||||||
|
int32_t (*remove)(struct irq_ctrl_desc *desc);
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/* Initialize a interrupt controller peripheral. */
|
||||||
|
int32_t irq_ctrl_init(struct irq_ctrl_desc **desc,
|
||||||
|
const struct irq_init_param *param);
|
||||||
|
|
||||||
|
/* Free the resources allocated by irq_ctrl_init(). */
|
||||||
|
int32_t irq_ctrl_remove(struct irq_ctrl_desc *desc);
|
||||||
|
|
||||||
|
/* Register a callback to handle the irq events */
|
||||||
|
int32_t irq_register_callback(struct irq_ctrl_desc *desc,
|
||||||
|
uint32_t irq_id,
|
||||||
|
struct callback_desc *callback_desc);
|
||||||
|
|
||||||
|
/* Unregisters a generic IRQ handling function */
|
||||||
|
int32_t irq_unregister_callback(struct irq_ctrl_desc *desc,
|
||||||
|
uint32_t irq_id,
|
||||||
|
struct callback_desc *callback_desc);
|
||||||
|
|
||||||
|
/* Global interrupt enable */
|
||||||
|
int32_t irq_global_enable(struct irq_ctrl_desc *desc);
|
||||||
|
|
||||||
|
/* Global interrupt disable */
|
||||||
|
int32_t irq_global_disable(struct irq_ctrl_desc *desc);
|
||||||
|
|
||||||
|
/* Set interrupt trigger level. */
|
||||||
|
int32_t irq_trigger_level_set(struct irq_ctrl_desc *desc,
|
||||||
|
uint32_t irq_id,
|
||||||
|
enum irq_trig_level trig);
|
||||||
|
|
||||||
|
/* Enable specific interrupt */
|
||||||
|
int32_t irq_enable(struct irq_ctrl_desc *desc, uint32_t irq_id);
|
||||||
|
|
||||||
|
/* Disable specific interrupt */
|
||||||
|
int32_t irq_disable(struct irq_ctrl_desc *desc, uint32_t irq_id);
|
||||||
|
|
||||||
|
/** Set the priority level for a specific interrupt */
|
||||||
|
int32_t irq_set_priority(struct irq_ctrl_desc *desc,
|
||||||
|
uint32_t irq_id,
|
||||||
|
uint32_t priority_level);
|
||||||
|
#endif // _IRQ_H_
|
||||||
@@ -0,0 +1,327 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file list.h
|
||||||
|
* @brief List library header
|
||||||
|
* @author Mihail Chindris (mihail.chindris@analog.com)
|
||||||
|
********************************************************************************
|
||||||
|
* @copyright
|
||||||
|
* Copyright 2020(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
********************************************************************************
|
||||||
|
*
|
||||||
|
* @section list_details Library description
|
||||||
|
* This library handles double linked lists and it expose inseart,
|
||||||
|
* read, get and delete functions. \n
|
||||||
|
* It also can be accesed using it member functions which wrapp function for
|
||||||
|
* usual list types.\n
|
||||||
|
* @subsection example Sample code
|
||||||
|
* @code{.c}
|
||||||
|
* // -- Use a generic list
|
||||||
|
* struct list_desc *list1;
|
||||||
|
* struct iterator *it;
|
||||||
|
* uint32_t a;
|
||||||
|
* // Create list list1
|
||||||
|
* list_init(&list1, LIST_DEFAULT, NULL);
|
||||||
|
* // Add items to the list
|
||||||
|
* list_add_last(list1, 1);
|
||||||
|
* list_add_last(list1, 2);
|
||||||
|
* list_add_last(list1, 3);
|
||||||
|
* // Here the list will be: 1 -> 2 - > 3
|
||||||
|
*
|
||||||
|
* list_read_last(list1, &a);
|
||||||
|
* printf("Last: %d\n", a);
|
||||||
|
* // 3 will be printed
|
||||||
|
* // Create an iterator on the end of the list
|
||||||
|
* iterator_init(&it, list1, 0);
|
||||||
|
* // Move the iterator backword with one position
|
||||||
|
* iterator_move(it, -1);
|
||||||
|
* // Read the data at the current position
|
||||||
|
* iterator_read(it, &a);
|
||||||
|
* printf("Current: %d\n", a);
|
||||||
|
* // 2 will be printed
|
||||||
|
* iterator_remove(it);
|
||||||
|
* list_remove(list1);
|
||||||
|
*
|
||||||
|
* // -- Use a popular list
|
||||||
|
* struct list_desc *stack;
|
||||||
|
* // Create a FIFO list
|
||||||
|
* list_init(&stack, LIST_STACK, NULL);
|
||||||
|
* // Put elements in the list
|
||||||
|
* stack->push(stack, 1);
|
||||||
|
* stack->push(stack, 2);
|
||||||
|
* stack->push(stack, 3);
|
||||||
|
* // Read from the stack
|
||||||
|
* stack->pop(stack, &a);
|
||||||
|
* printf("Last: %d\n", a);
|
||||||
|
* // 3 will be printed
|
||||||
|
* list_remove(stack);
|
||||||
|
* @endcode
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _LIST_H_
|
||||||
|
#define _LIST_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct list_desc
|
||||||
|
* @brief Structure storing the list and function wrapper for usual list types
|
||||||
|
*
|
||||||
|
* With this structure the funtionalities of usual list types
|
||||||
|
* ( \ref adapter_type ) can be accesed with the functions referenced in this
|
||||||
|
* structure.
|
||||||
|
* For example:
|
||||||
|
* @code{.c}
|
||||||
|
* my_queue->push(my_queue, my_data);
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
struct list_desc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct list_iterator
|
||||||
|
* @brief Structure used to iterate through the list using Iterator functions.
|
||||||
|
*/
|
||||||
|
struct iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prototype of the compare function.
|
||||||
|
*
|
||||||
|
* The function used to compare the elements of the liste when doing
|
||||||
|
* operations on an ordered list.
|
||||||
|
* @param data1 - First element to be compared
|
||||||
|
* @param data2 - Second element to be compared
|
||||||
|
* @return
|
||||||
|
* - -1 - If data1 < data2
|
||||||
|
* - 0 - If data1 == data2
|
||||||
|
* - 1 - If data1 > data2
|
||||||
|
*/
|
||||||
|
typedef int32_t (*f_cmp)(void *data1, void *data2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Generic functions
|
||||||
|
* Each function interacting with the list have one of the following formats.\n
|
||||||
|
* Aditionaly they may have one more parametere for specific functionalities.\n
|
||||||
|
* In the Iterator functions, the list reference is replaced by the iterator's
|
||||||
|
* one.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add an element in the list.
|
||||||
|
*
|
||||||
|
* The element of the list is created and the data field is stored in it.
|
||||||
|
* @param list_desc - Reference to the list. Created by \ref list_init.
|
||||||
|
* @param data - Data to store in a list element
|
||||||
|
* @return
|
||||||
|
* - 0 : On success
|
||||||
|
* - -1 : Otherwise
|
||||||
|
*/
|
||||||
|
typedef int32_t (*f_add)(struct list_desc *list_desc, void *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Edit an element in the list. The content is replaced by new_data.
|
||||||
|
* @param list_desc - Reference to the list. Created by \ref list_init.
|
||||||
|
* @param new_data - New data to replace the old one
|
||||||
|
* @return
|
||||||
|
* - 0 : On success
|
||||||
|
* - -1 : Otherwise
|
||||||
|
*/
|
||||||
|
typedef int32_t (*f_edit)(struct list_desc *list_desc, void *new_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read an element from the list.
|
||||||
|
* @param list_desc - Reference to the list. Created by \ref list_init.
|
||||||
|
* @param result - If not null, result is filled with:
|
||||||
|
* @param data - Content of the list element, NULL if some error occur.
|
||||||
|
* @return \n
|
||||||
|
* - 0 : On success
|
||||||
|
* - -1 : Otherwise
|
||||||
|
* @note If the content of an element can be 0 then the result must be checked
|
||||||
|
* to see if the functions has succeded
|
||||||
|
*/
|
||||||
|
typedef int32_t (*f_read)(struct list_desc *list_desc, void **data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read and remove an element from the list.
|
||||||
|
* @param list_desc - Reference to the list. Created by \ref list_init.
|
||||||
|
* @param result - If not null, result is filled with:
|
||||||
|
* @param data - Content of the list element, NULL if some error occur.
|
||||||
|
* @return
|
||||||
|
* - 0 : On success
|
||||||
|
* - -1 : Otherwise
|
||||||
|
*/
|
||||||
|
typedef int32_t (*f_get)(struct list_desc *list_desc, void **data);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum adapter_type
|
||||||
|
* @brief Selects functionalities for functions in \ref list_desc
|
||||||
|
*/
|
||||||
|
enum adapter_type {
|
||||||
|
/** Default type is LIST_STACK */
|
||||||
|
LIST_DEFAULT,
|
||||||
|
/**
|
||||||
|
* Functions for a FIFO list (First-in first-out). Elements are inserted
|
||||||
|
* in one end and extracted from the other end.
|
||||||
|
* - \e Push: Insert element
|
||||||
|
* - \e Pop: Get next element (Read and remove)
|
||||||
|
* - \e Top_next: Read next element
|
||||||
|
* - \e Back: Read first element
|
||||||
|
* - \e Swap: Edit the content of the next element
|
||||||
|
*/
|
||||||
|
LIST_QUEUE,
|
||||||
|
/**
|
||||||
|
* Functions for a LIFO list (Last-in first-out). Elements are inserted
|
||||||
|
* and extracted only from the same end.
|
||||||
|
* - \e Push: Insert element
|
||||||
|
* - \e Pop: Get top element (Read and remove)
|
||||||
|
* - \e Top_next: Read top element
|
||||||
|
* - \e Back: Read bottom element
|
||||||
|
* - \e Swap: Edit the content of the top element
|
||||||
|
*/
|
||||||
|
LIST_STACK,
|
||||||
|
/**
|
||||||
|
* Functions for ordered list. The order of element is determinated
|
||||||
|
* usinge the \ref f_cmp.
|
||||||
|
* - \e Push: Insert element
|
||||||
|
* - \e Pop: Get lowest element (Read and remove)
|
||||||
|
* - \e Top_next: Read lowest element
|
||||||
|
* - \e Back: Read the biggest element
|
||||||
|
* - \e Swap: Edit the lowest element
|
||||||
|
*/
|
||||||
|
LIST_PRIORITY_LIST
|
||||||
|
};
|
||||||
|
|
||||||
|
struct list_desc {
|
||||||
|
/** Refer to \ref adapter_type */
|
||||||
|
f_add push;
|
||||||
|
/** Refer to \ref adapter_type */
|
||||||
|
f_get pop;
|
||||||
|
/** Refer to \ref adapter_type */
|
||||||
|
f_read top_next;
|
||||||
|
/** Refer to \ref adapter_type */
|
||||||
|
f_read back;
|
||||||
|
/** Refer to \ref adapter_type */
|
||||||
|
f_edit swap;
|
||||||
|
/** Structure storing the list internal parameters */
|
||||||
|
void *priv_desc;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
int32_t list_init(struct list_desc **list_desc,
|
||||||
|
enum adapter_type type,
|
||||||
|
f_cmp comparator);
|
||||||
|
int32_t list_remove(struct list_desc *list_desc);
|
||||||
|
int32_t list_get_size(struct list_desc *list_desc,
|
||||||
|
uint32_t *out_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Iterator functions
|
||||||
|
* An iterator is used to iterate through the list. For a list, any number of
|
||||||
|
* iterators can be created. All must be removed before removing a list.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
int32_t iterator_init(struct iterator **iter,
|
||||||
|
struct list_desc *list_desc,
|
||||||
|
bool start);
|
||||||
|
int32_t iterator_remove(struct iterator *iter);
|
||||||
|
int32_t iterator_move(struct iterator *iter, int32_t steps);
|
||||||
|
int32_t iterator_move_to_idx(struct iterator *iter, int32_t idx);
|
||||||
|
int32_t iterator_find(struct iterator *iter, void *cmp_data);
|
||||||
|
int32_t iterator_insert(struct iterator *iter, void *data,
|
||||||
|
bool after);
|
||||||
|
int32_t iterator_edit(struct iterator *iter, void *new_data);
|
||||||
|
int32_t iterator_read(struct iterator *iter, void **data);
|
||||||
|
int32_t iterator_get(struct iterator *iter, void **data);
|
||||||
|
/** @}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Operations on the ends of the list
|
||||||
|
* These functions will operate on the first or last element of the list
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
int32_t list_add_first(struct list_desc *list_desc, void *data);
|
||||||
|
int32_t list_edit_first(struct list_desc *list_desc,
|
||||||
|
void *new_data);
|
||||||
|
int32_t list_read_first(struct list_desc *list_desc, void **data);
|
||||||
|
int32_t list_get_first(struct list_desc *list_desc, void **data);
|
||||||
|
|
||||||
|
int32_t list_add_last(struct list_desc *list_desc, void *data);
|
||||||
|
int32_t list_edit_last(struct list_desc *list_desc, void *new_data);
|
||||||
|
int32_t list_read_last(struct list_desc *list_desc, void **data);
|
||||||
|
int32_t list_get_last(struct list_desc *list_desc, void **data);
|
||||||
|
/** @}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Operations by index
|
||||||
|
* These functions use an index to identify the element in the list.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
int32_t list_add_idx(struct list_desc *list_desc, void *data,
|
||||||
|
uint32_t idx);
|
||||||
|
int32_t list_edit_idx(struct list_desc *list_desc, void *new_data,
|
||||||
|
uint32_t idx);
|
||||||
|
int32_t list_read_idx(struct list_desc *list_desc, void **data,
|
||||||
|
uint32_t idx);
|
||||||
|
int32_t list_get_idx(struct list_desc *list_desc, void **data,
|
||||||
|
uint32_t idx);
|
||||||
|
/** @}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Operations by comparation
|
||||||
|
* These functions use the specified \ref f_cmp at \ref list_init to identify
|
||||||
|
* the element this will operate on.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
int32_t list_add_find(struct list_desc *list_desc, void *data);
|
||||||
|
int32_t list_edit_find(struct list_desc *list_desc, void *new_data,
|
||||||
|
void *cmp_data);
|
||||||
|
int32_t list_read_find(struct list_desc *list_desc, void **data,
|
||||||
|
void *cmp_data);
|
||||||
|
int32_t list_get_find(struct list_desc *list_desc, void **data,
|
||||||
|
void *cmp_data);
|
||||||
|
/** @}*/
|
||||||
|
|
||||||
|
#endif // _LIST_H_
|
||||||
@@ -0,0 +1,209 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file spi.h
|
||||||
|
* @brief Header file of SPI Interface
|
||||||
|
* @author DBogdan (dragos.bogdan@analog.com)
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SPI_H_
|
||||||
|
#define _SPI_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/********************** Macros and Constants Definitions **********************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#define SPI_CPHA 0x01
|
||||||
|
#define SPI_CPOL 0x02
|
||||||
|
#define SPI_3WIRE 0x04
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum spi_mode
|
||||||
|
* @brief SPI configuration for clock phase and polarity.
|
||||||
|
*/
|
||||||
|
enum spi_mode {
|
||||||
|
/** Data on rising, shift out on falling */
|
||||||
|
SPI_MODE_0 = (0 | 0),
|
||||||
|
/** Data on falling, shift out on rising */
|
||||||
|
SPI_MODE_1 = (0 | SPI_CPHA),
|
||||||
|
/** Data on rising, shift out on falling */
|
||||||
|
SPI_MODE_2 = (SPI_CPOL | 0),
|
||||||
|
/** Data on falling, shift out on rising */
|
||||||
|
SPI_MODE_3 = (SPI_CPOL | SPI_CPHA),
|
||||||
|
/** Data on rising, shift out on falling */
|
||||||
|
SPI_MODE_4 = SPI_3WIRE
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum spi_bit_order
|
||||||
|
* @brief SPI configuration for bit order (MSB/LSB).
|
||||||
|
*/
|
||||||
|
enum spi_bit_order {
|
||||||
|
/** Most-significant bit (MSB) first */
|
||||||
|
SPI_BIT_ORDER_MSB_FIRST = 0,
|
||||||
|
/** Least-significant bit (LSB) first */
|
||||||
|
SPI_BIT_ORDER_LSB_FIRST = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct spi_msg_list
|
||||||
|
* @brief List item describing a SPI transfer
|
||||||
|
*/
|
||||||
|
struct spi_msg {
|
||||||
|
/** Buffer with data to send. If NULL, 0x00 will be sent */
|
||||||
|
uint8_t *tx_buff;
|
||||||
|
/** Buffer where to store data. If NULL, incoming data won't be saved */
|
||||||
|
uint8_t *rx_buff;
|
||||||
|
/** Length of buffers. Must have equal size. */
|
||||||
|
uint32_t bytes_number;
|
||||||
|
/** If set, CS will be deasserted after the transfer */
|
||||||
|
uint8_t cs_change;
|
||||||
|
/**
|
||||||
|
* Minimum delay (in us) between the CS de-assert event of the current message
|
||||||
|
* and the assert of the next one.
|
||||||
|
*/
|
||||||
|
uint32_t cs_change_delay;
|
||||||
|
/** Delay (in us) between the CS assert and the first SCLK edge. */
|
||||||
|
uint32_t cs_delay_first;
|
||||||
|
/** Delay (in us) between the last SCLK edge and the CS deassert */
|
||||||
|
uint32_t cs_delay_last;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct spi_platform_ops
|
||||||
|
* @brief Structure holding SPI function pointers that point to the platform
|
||||||
|
* specific function
|
||||||
|
*/
|
||||||
|
struct spi_platform_ops ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct spi_init_param
|
||||||
|
* @brief Structure holding the parameters for SPI initialization
|
||||||
|
*/
|
||||||
|
struct spi_init_param {
|
||||||
|
/** Device ID */
|
||||||
|
uint32_t device_id;
|
||||||
|
/** maximum transfer speed */
|
||||||
|
uint32_t max_speed_hz;
|
||||||
|
/** SPI chip select */
|
||||||
|
uint8_t chip_select;
|
||||||
|
/** SPI mode */
|
||||||
|
enum spi_mode mode;
|
||||||
|
/** SPI bit order */
|
||||||
|
enum spi_bit_order bit_order;
|
||||||
|
const struct spi_platform_ops *platform_ops;
|
||||||
|
/** SPI extra parameters (device specific) */
|
||||||
|
void *extra;
|
||||||
|
/** Parent of the device */
|
||||||
|
struct spi_desc *parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct spi_desc
|
||||||
|
* @brief Structure holding SPI descriptor.
|
||||||
|
*/
|
||||||
|
struct spi_desc {
|
||||||
|
/** Device ID */
|
||||||
|
uint32_t device_id;
|
||||||
|
/** maximum transfer speed */
|
||||||
|
uint32_t max_speed_hz;
|
||||||
|
/** SPI chip select */
|
||||||
|
uint8_t chip_select;
|
||||||
|
/** SPI mode */
|
||||||
|
enum spi_mode mode;
|
||||||
|
/** SPI bit order */
|
||||||
|
enum spi_bit_order bit_order;
|
||||||
|
const struct spi_platform_ops *platform_ops;
|
||||||
|
/** SPI extra parameters (device specific) */
|
||||||
|
void *extra;
|
||||||
|
/** Parent of the device */
|
||||||
|
struct spi_desc *parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct spi_platform_ops
|
||||||
|
* @brief Structure holding SPI function pointers that point to the platform
|
||||||
|
* specific function
|
||||||
|
*/
|
||||||
|
struct spi_platform_ops {
|
||||||
|
/** SPI initialization function pointer */
|
||||||
|
int32_t (*init)(struct spi_desc **, const struct spi_init_param *);
|
||||||
|
/** SPI write/read function pointer */
|
||||||
|
int32_t (*write_and_read)(struct spi_desc *, uint8_t *, uint16_t);
|
||||||
|
/** SPI write function pointer */
|
||||||
|
int32_t (*write_and_read_3wire)(struct spi_desc *, uint8_t *,uint8_t *,uint16_t, uint16_t);
|
||||||
|
/** Iterate over the spi_msg array and send all messages at once */
|
||||||
|
int32_t (*transfer)(struct spi_desc *, struct spi_msg *, uint32_t);
|
||||||
|
/** SPI remove function pointer */
|
||||||
|
int32_t (*remove)(struct spi_desc *);
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/* Initialize the SPI communication peripheral. */
|
||||||
|
int32_t spi_init(struct spi_desc **desc,
|
||||||
|
const struct spi_init_param *param);
|
||||||
|
|
||||||
|
/* Free the resources allocated by spi_init(). */
|
||||||
|
int32_t spi_remove(struct spi_desc *desc);
|
||||||
|
|
||||||
|
/* Write and read data to/from SPI. */
|
||||||
|
int32_t spi_write_and_read(struct spi_desc *desc,
|
||||||
|
uint8_t *data,
|
||||||
|
uint16_t bytes_number);
|
||||||
|
int32_t spi_write_and_read_3wire(struct spi_desc *desc,
|
||||||
|
uint8_t *write_data,
|
||||||
|
uint8_t *read_data,
|
||||||
|
uint16_t write_bytes_number,
|
||||||
|
uint16_t read_bytes_number);
|
||||||
|
|
||||||
|
/* Iterate over the spi_msg array and send all messages at once */
|
||||||
|
int32_t spi_transfer(struct spi_desc *desc,
|
||||||
|
struct spi_msg *msgs,
|
||||||
|
uint32_t len);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _SPI_H_
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file timer.h
|
||||||
|
* @brief Timer control module header.
|
||||||
|
* @author Andrei Drimbarean (andrei.drimbarean@analog.com)
|
||||||
|
********************************************************************************
|
||||||
|
* Copyright 2019(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY
|
||||||
|
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SRC_TIMER_H_
|
||||||
|
#define _SRC_TIMER_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct timer_desc
|
||||||
|
* @brief Structure holding timer descriptor
|
||||||
|
*/
|
||||||
|
struct timer_desc {
|
||||||
|
/** timer ID */
|
||||||
|
uint16_t id;
|
||||||
|
/** timer count frequency (Hz) */
|
||||||
|
uint32_t freq_hz;
|
||||||
|
/** the number of ticks the timer counts until it resets */
|
||||||
|
uint32_t ticks_count;
|
||||||
|
/** Timer platform operations */
|
||||||
|
const struct timer_platform_ops *platform_ops;
|
||||||
|
/** timer extra parameters (device specific) */
|
||||||
|
void *extra;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct timer_platform_ops
|
||||||
|
* @brief Structure holding timer function pointers that point to the platform
|
||||||
|
* specific function
|
||||||
|
*/
|
||||||
|
struct timer_platform_ops ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct timer_init_param
|
||||||
|
* @brief Structure holding the parameters for timer initialization
|
||||||
|
*/
|
||||||
|
struct timer_init_param {
|
||||||
|
/** timer ID */
|
||||||
|
uint16_t id;
|
||||||
|
/** timer count frequency (Hz) */
|
||||||
|
uint32_t freq_hz;
|
||||||
|
/** the number of ticks the timer counts until it resets */
|
||||||
|
uint32_t ticks_count;
|
||||||
|
/** Timer platform operations */
|
||||||
|
const struct timer_platform_ops *platform_ops;
|
||||||
|
/** timer extra parameters (device specific) */
|
||||||
|
void *extra;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct timer_platform_ops
|
||||||
|
* @brief Structure holding timer function pointers that point to the platform
|
||||||
|
* specific function
|
||||||
|
*/
|
||||||
|
struct timer_platform_ops {
|
||||||
|
/** timer initialization function pointer */
|
||||||
|
int32_t (*init)(struct timer_desc **,
|
||||||
|
const struct timer_init_param *);
|
||||||
|
/** timer start function pointer */
|
||||||
|
int32_t (*start)(struct timer_desc *);
|
||||||
|
/** timer stop function pointer */
|
||||||
|
int32_t (*stop)(struct timer_desc *);
|
||||||
|
/** timer get counter function pointer */
|
||||||
|
int32_t (*counter_get)(struct timer_desc *, uint32_t *counter);
|
||||||
|
/** timer set counter function pointer */
|
||||||
|
int32_t (*counter_set)(struct timer_desc *, uint32_t new_val);
|
||||||
|
/** timer get clock frequency function pointer */
|
||||||
|
int32_t (*count_clk_get)(struct timer_desc *, uint32_t *freq_hz);
|
||||||
|
/** timer set clock frequency function pointer */
|
||||||
|
int32_t (*count_clk_set)(struct timer_desc *, uint32_t freq_hz);
|
||||||
|
/** timer get elapsed time in nsec */
|
||||||
|
int32_t (*get_elapsed_time_nsec)(struct timer_desc *,
|
||||||
|
uint64_t *elapsed_time);
|
||||||
|
/** timer remove function pointer */
|
||||||
|
int32_t (*remove)(struct timer_desc *);
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/* Initialize hardware timer and the handler structure associated with it. */
|
||||||
|
int32_t timer_init(struct timer_desc **desc,
|
||||||
|
struct timer_init_param *param);
|
||||||
|
|
||||||
|
/* Free the memory allocated by timer_setup(). */
|
||||||
|
int32_t timer_remove(struct timer_desc *desc);
|
||||||
|
|
||||||
|
/* Start a timer. */
|
||||||
|
int32_t timer_start(struct timer_desc *desc);
|
||||||
|
|
||||||
|
/* Stop a timer from counting. */
|
||||||
|
int32_t timer_stop(struct timer_desc *desc);
|
||||||
|
|
||||||
|
/* Get the value of the counter register for the timer. */
|
||||||
|
int32_t timer_counter_get(struct timer_desc *desc,
|
||||||
|
uint32_t *counter);
|
||||||
|
|
||||||
|
/* Set the timer counter register value. */
|
||||||
|
int32_t timer_counter_set(struct timer_desc *desc,
|
||||||
|
uint32_t new_val);
|
||||||
|
|
||||||
|
/* Get the timer clock frequency. */
|
||||||
|
int32_t timer_count_clk_get(struct timer_desc *desc,
|
||||||
|
uint32_t *freq_hz);
|
||||||
|
|
||||||
|
/* Set the timer clock frequency. */
|
||||||
|
int32_t timer_count_clk_set(struct timer_desc *desc,
|
||||||
|
uint32_t freq_hz);
|
||||||
|
|
||||||
|
/* Get the elapsed time in nsec for the timer. */
|
||||||
|
int32_t timer_get_elapsed_time_nsec(struct timer_desc *desc,
|
||||||
|
uint64_t *elapsed_time);
|
||||||
|
|
||||||
|
#endif // _SRC_TIMER_H_
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
/***************************************************************************//**
|
||||||
|
* @file trng.h
|
||||||
|
* @brief Header file of true random number generator
|
||||||
|
* @author Mihail Chindris (mihail.chindris@analog.com)
|
||||||
|
********************************************************************************
|
||||||
|
* @copyright
|
||||||
|
* Copyright 2020(c) Analog Devices, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
* - The use of this software may or may not infringe the patent rights
|
||||||
|
* of one or more patent holders. This license does not release you
|
||||||
|
* from the requirement that you obtain separate licenses from these
|
||||||
|
* patent holders to use this software.
|
||||||
|
* - Use of the software either in source or binary form, must be run
|
||||||
|
* on or directly connected to an Analog Devices Inc. component.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _TRNG_H_
|
||||||
|
#define _TRNG_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*************************** Types Declarations *******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct trng_platform_ops
|
||||||
|
* @brief Structure holding TRNG function pointers that point to the platform
|
||||||
|
* specific function
|
||||||
|
*/
|
||||||
|
struct trng_platform_ops;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct trng_desc
|
||||||
|
* @brief TRNG Descriptor
|
||||||
|
*/
|
||||||
|
struct trng_desc {
|
||||||
|
/** Platform ops */
|
||||||
|
const struct trng_platform_ops *platform_ops;
|
||||||
|
/** Platform specific parameters */
|
||||||
|
void *extra;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct trng_init_param
|
||||||
|
* @brief Init parameter for TRNG
|
||||||
|
*/
|
||||||
|
struct trng_init_param {
|
||||||
|
/** Device id */
|
||||||
|
uint32_t dev_id;
|
||||||
|
/** Platform specific parameter */
|
||||||
|
void *extra;
|
||||||
|
/** Platform ops */
|
||||||
|
const struct trng_platform_ops *platform_ops;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct trng_platform_ops
|
||||||
|
* @brief Structure holding TRNG function pointers that point to the platform
|
||||||
|
* specific function
|
||||||
|
*/
|
||||||
|
struct trng_platform_ops {
|
||||||
|
/** TRNG initialization function pointer */
|
||||||
|
int (*init)(struct trng_desc **,
|
||||||
|
const struct trng_init_param *);
|
||||||
|
/** Fill buffer with random numbers */
|
||||||
|
int (*fill_buffer)(struct trng_desc *, uint8_t *, uint32_t);
|
||||||
|
/** TRNG remove function pointer */
|
||||||
|
int (*remove)(struct trng_desc *);
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/* Initialize descriptor */
|
||||||
|
int trng_init(struct trng_desc **desc,
|
||||||
|
const struct trng_init_param *param);
|
||||||
|
|
||||||
|
/* Free resources allocated in descriptor */
|
||||||
|
int trng_remove(struct trng_desc *desc);
|
||||||
|
|
||||||
|
/* Fill buffer with random numbers */
|
||||||
|
int trng_fill_buffer(struct trng_desc *desc, uint8_t *buff,
|
||||||
|
uint32_t len);
|
||||||
|
|
||||||
|
#endif // _TRNG_H_
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file util.h
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief Utility functions header file
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup Utility
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __UTIL_H_
|
||||||
|
#define __UTIL_H_
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/***************************** Include Files **********************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
/******************************************************************************/
|
||||||
|
/********************** Macros and Constants Definitions **********************/
|
||||||
|
/******************************************************************************/
|
||||||
|
// #define __CRC_LSB
|
||||||
|
#define __BITSWAP_TABLE
|
||||||
|
#define __CRC_LSB
|
||||||
|
#define CRC16_INIT 0x0000
|
||||||
|
#define CRC8_INIT 0x00
|
||||||
|
|
||||||
|
#define BIT(x) (1 << (x))
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(x) \
|
||||||
|
(sizeof(x) / sizeof((x)[0]))
|
||||||
|
|
||||||
|
#define DIV_ROUND_UP(x, y) \
|
||||||
|
(((x) + (y)-1) / (y))
|
||||||
|
#define DIV_ROUND_CLOSEST(x, y) \
|
||||||
|
(((x) + (y) / 2) / (y))
|
||||||
|
#define DIV_ROUND_CLOSEST_ULL(x, y) \
|
||||||
|
DIV_ROUND_CLOSEST(x, y)
|
||||||
|
|
||||||
|
#define min(x, y) \
|
||||||
|
(((x) < (y)) ? (x) : (y))
|
||||||
|
#define min_t(type, x, y) \
|
||||||
|
(type) min((type)(x), (type)(y))
|
||||||
|
|
||||||
|
#define max(x, y) \
|
||||||
|
(((x) > (y)) ? (x) : (y))
|
||||||
|
#define max_t(type, x, y) \
|
||||||
|
(type) max((type)(x), (type)(y))
|
||||||
|
|
||||||
|
#define clamp(val, min_val, max_val) \
|
||||||
|
(max(min((val), (max_val)), (min_val)))
|
||||||
|
#define clamp_t(type, val, min_val, max_val) \
|
||||||
|
(type) clamp((type)(val), (type)(min_val), (type)(max_val))
|
||||||
|
|
||||||
|
#define swap(x, y) \
|
||||||
|
{ \
|
||||||
|
typeof(x) _tmp_ = (x); \
|
||||||
|
(x) = (y); \
|
||||||
|
(y) = _tmp_; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define round_up(x, y) \
|
||||||
|
(((x) + (y)-1) / (y))
|
||||||
|
|
||||||
|
#define BITS_PER_LONG 32
|
||||||
|
|
||||||
|
#define GENMASK(h, l) ({ \
|
||||||
|
uint32_t t = (uint32_t)(~0UL); \
|
||||||
|
t = t << (BITS_PER_LONG - (h - l + 1)); \
|
||||||
|
t = t >> (BITS_PER_LONG - (h + 1)); \
|
||||||
|
t; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define bswap_constant_32(x) \
|
||||||
|
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
|
||||||
|
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
|
||||||
|
|
||||||
|
#define bswap_constant_16(x) ((((x) & (uint16_t)0xff00) >> 8) | \
|
||||||
|
(((x) & (uint16_t)0x00ff) << 8))
|
||||||
|
|
||||||
|
#define bit_swap_constant_8(x) \
|
||||||
|
((((x) & 0x80) >> 7) | \
|
||||||
|
(((x) & 0x40) >> 5) | \
|
||||||
|
(((x) & 0x20) >> 3) | \
|
||||||
|
(((x) & 0x10) >> 1) | \
|
||||||
|
(((x) & 0x08) << 1) | \
|
||||||
|
(((x) & 0x04) << 3) | \
|
||||||
|
(((x) & 0x02) << 5) | \
|
||||||
|
(((x) & 0x01) << 7))
|
||||||
|
|
||||||
|
#define U16_MAX ((uint16_t)~0U)
|
||||||
|
#define S16_MAX ((int16_t)(U16_MAX >> 1))
|
||||||
|
|
||||||
|
#define DIV_U64(x, y) (x / y)
|
||||||
|
|
||||||
|
#define UNUSED_PARAM(x) ((void)x)
|
||||||
|
|
||||||
|
#define shift_right(x, s) ((x) < 0 ? -(-(x) >> (s)) : (x) >> (s))
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/************************ Functions Declarations ******************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
void IO_Out32(uintptr_t addr, uint32_t value);
|
||||||
|
uint32_t IO_In32(uintptr_t addr);
|
||||||
|
|
||||||
|
/* flip a byte left to right*/
|
||||||
|
uint8_t byte_bit_swap(uint8_t byte);
|
||||||
|
|
||||||
|
/* flip a 32bit word left to right */
|
||||||
|
uint32_t word_bit_swap(uint32_t word);
|
||||||
|
|
||||||
|
/* Returns the number of 1-bits in digit. */
|
||||||
|
uint32_t count_ones(uint32_t word);
|
||||||
|
|
||||||
|
/* convert a fixed number to a double. */
|
||||||
|
double fix2double(int32_t val, uint8_t frac_bits);
|
||||||
|
|
||||||
|
/* Find first set bit in word. */
|
||||||
|
uint32_t find_first_set_bit(uint32_t word);
|
||||||
|
/* Find last set bit in word. */
|
||||||
|
uint32_t find_last_set_bit(uint32_t word);
|
||||||
|
/* Locate the closest element in an array. */
|
||||||
|
uint32_t find_closest(int32_t val,
|
||||||
|
const int32_t *array,
|
||||||
|
uint32_t size);
|
||||||
|
/* Shift the value and apply the specified mask. */
|
||||||
|
uint32_t field_prep(uint32_t mask, uint32_t val);
|
||||||
|
/* Get a field specified by a mask from a word. */
|
||||||
|
uint32_t field_get(uint32_t mask, uint32_t word);
|
||||||
|
/* Log base 2 of the given number. */
|
||||||
|
int32_t log_base_2(uint32_t x);
|
||||||
|
/* Find greatest common divisor of the given two numbers. */
|
||||||
|
uint32_t greatest_common_divisor(uint32_t a,
|
||||||
|
uint32_t b);
|
||||||
|
/* Calculate best rational approximation for a given fraction. */
|
||||||
|
void rational_best_approximation(uint32_t given_numerator,
|
||||||
|
uint32_t given_denominator,
|
||||||
|
uint32_t max_numerator,
|
||||||
|
uint32_t max_denominator,
|
||||||
|
uint32_t *best_numerator,
|
||||||
|
uint32_t *best_denominator);
|
||||||
|
/* Calculate the number of set bits. */
|
||||||
|
uint32_t hweight8(uint32_t word);
|
||||||
|
/* Calculate the quotient and the remainder of an integer division. */
|
||||||
|
uint64_t do_div(uint64_t *n,
|
||||||
|
uint64_t base);
|
||||||
|
/* Unsigned 64bit divide with 64bit divisor and remainder */
|
||||||
|
uint64_t div64_u64_rem(uint64_t dividend, uint64_t divisor,
|
||||||
|
uint64_t *remainder);
|
||||||
|
/* Unsigned 64bit divide with 32bit divisor with remainder */
|
||||||
|
uint64_t div_u64_rem(uint64_t dividend, uint32_t divisor, uint32_t *remainder);
|
||||||
|
int64_t div_s64_rem(int64_t dividend, int32_t divisor, int32_t *remainder);
|
||||||
|
/* Unsigned 64bit divide with 32bit divisor */
|
||||||
|
uint64_t div_u64(uint64_t dividend, uint32_t divisor);
|
||||||
|
int64_t div_s64(int64_t dividend, int32_t divisor);
|
||||||
|
/* Converts from string to int32_t */
|
||||||
|
int32_t str_to_int32(const char *str);
|
||||||
|
/* Converts from string to uint32_t */
|
||||||
|
uint32_t srt_to_uint32(const char *str);
|
||||||
|
|
||||||
|
int crc16_gen(uint8_t *buffPtr, uint32_t dataLen, uint16_t poly, uint16_t *crcVal);
|
||||||
|
bool crc16_check(uint8_t *buffPtr, uint32_t dataLen, uint32_t crcOffset, uint16_t poly);
|
||||||
|
int crc8_gen(uint8_t *buffPtr, uint32_t dataLen, uint16_t poly, uint8_t *crcVal);
|
||||||
|
bool crc8_check(uint8_t *buffPtr, uint32_t dataLen, uint32_t crcOffset, uint16_t poly);
|
||||||
|
#endif // __UTIL_H_
|
||||||
|
|
||||||
|
/** @} */
|
||||||
+476
@@ -0,0 +1,476 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* Description: main.c
|
||||||
|
*
|
||||||
|
|
||||||
|
* Date: 2023-05-07 13:19
|
||||||
|
* Last Edit Time: [2023-05-07 20:32]
|
||||||
|
*
|
||||||
|
* Revisions: Rev 0.0
|
||||||
|
* History:
|
||||||
|
* [2023-05-07]: Initial edition.
|
||||||
|
*
|
||||||
|
* Copyright(c) 2024 Beijing Institute of Technology.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
// Standard
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
// Xilinx
|
||||||
|
#include "xscugic.h"
|
||||||
|
#include "drivers/platform/xilinx_irq.h"
|
||||||
|
#include "drivers/platform/xilinx_timer.h"
|
||||||
|
// App
|
||||||
|
#include "common.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "timer.h"
|
||||||
|
#include "hwconfig.h"
|
||||||
|
#include "system_monitor.h"
|
||||||
|
#include "config/app_config.h"
|
||||||
|
#include "dev_profile/dev_profile.h"
|
||||||
|
#include "systembus/systembus.h"
|
||||||
|
#include "networking/phy_layer/phy_layer.h"
|
||||||
|
#include "networking/link_layer/link_layer.h"
|
||||||
|
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
int32_t SetupInterruptSystem(struct irq_ctrl_desc *descPtr);
|
||||||
|
void Phy_IntrHandler(void *context);
|
||||||
|
void PeriodicPull_Handler(void *callBackRef);
|
||||||
|
void ScuTimer_IntrHandler(void *context);
|
||||||
|
void Systembus_IntrHandler(void *context);
|
||||||
|
|
||||||
|
/************************** Constant Definitions *****************************/
|
||||||
|
struct callback_desc phy_callback_desc = {
|
||||||
|
.callback = Phy_IntrHandler,
|
||||||
|
.ctx = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
struct callback_desc periodicpull_callback_desc = {
|
||||||
|
.callback = PeriodicPull_Handler,
|
||||||
|
.ctx = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct callback_desc sysbus_callback_desc = {
|
||||||
|
.callback = Systembus_IntrHandler,
|
||||||
|
.ctx = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
struct callback_desc scutm_callback_desc = {
|
||||||
|
.callback = ScuTimer_IntrHandler,
|
||||||
|
.ctx = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
L2_CONFIG linkConfig = {
|
||||||
|
.myType = L2_NODE_HEAD,
|
||||||
|
.clustId = 1U,
|
||||||
|
.myId = 1U,
|
||||||
|
.headId = 1U,
|
||||||
|
.netScale = 2U,
|
||||||
|
.phyInstPtr = NULL, // physical layer reference
|
||||||
|
.tmcInstPtr = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
// L2_CONFIG linkConfig = {
|
||||||
|
// .myType = L2_NODE_MEMBER,
|
||||||
|
// .clustId = 1U,
|
||||||
|
// .myId = 2U,
|
||||||
|
// .headId = 1U,
|
||||||
|
// .netScale = 2U,
|
||||||
|
// .phyInstPtr = NULL, // physical layer reference
|
||||||
|
// .tmcInstPtr = NULL
|
||||||
|
// };
|
||||||
|
|
||||||
|
static PHY_CONFIG phyConfig = {
|
||||||
|
.devId = PHY_DEVICE_ID,
|
||||||
|
.baseAddr = PHY_BASEADDR,
|
||||||
|
.antBramId = PHY_ANTCONFIG_BRAM_DEVICE_ID,
|
||||||
|
.antInfoBramId = PHY_ANTINFO_BRAM_DEVICE_ID,
|
||||||
|
.txBramId = PHY_TXBUFF_BRAM_DEVICE_ID,
|
||||||
|
.rxBramId = PHY_RXBUFF_BRAM_DEVICE_ID,
|
||||||
|
.hwXadcId = PHY_HW_XADC_DEVICE_ID,
|
||||||
|
.get_clk_state = Hardware_GetHMC7044LockStatus,
|
||||||
|
.get_ad_lock_state = Hardware_GetAD9361LockStatus,
|
||||||
|
.get_ad0_temp = Hardware_GetAD9361Temp_1,
|
||||||
|
.get_ad1_temp = Hardware_GetAD9361Temp_2
|
||||||
|
};
|
||||||
|
|
||||||
|
TMC_CONFIG tmcConfig = {
|
||||||
|
.baseAddr = TIME_CONTROLLER_BASEADDR,
|
||||||
|
.reset = 10U
|
||||||
|
};
|
||||||
|
|
||||||
|
static SYSBUS_CONFIG sysbusConfig = {
|
||||||
|
.uartConfig = {
|
||||||
|
.devId = SYSBUS_DEV_ID,
|
||||||
|
.baudRate = 115200U,
|
||||||
|
.dataBits = SYSBUS_PSUART_8_BITS,
|
||||||
|
.parity = SYSBUS_PSUART_NO_PARITY,
|
||||||
|
.stopBits = SYSBUS_PSUART_1_STOP_BIT,
|
||||||
|
.timeout = 16U,
|
||||||
|
.crcPoly = 0x1021U,
|
||||||
|
},
|
||||||
|
.txQueueMax = 16U,
|
||||||
|
.rxQueueMax = 16U
|
||||||
|
};
|
||||||
|
/*********************** Driver Instance Definitions **************************/
|
||||||
|
static struct irq_ctrl_desc *intcDescPtr = NULL; // General interrupt controller descriptor
|
||||||
|
static struct timer_desc *logTmPtr = NULL;
|
||||||
|
static SYSBUS *sysbusDescPtr = NULL;
|
||||||
|
static PHY_INST *phyInstPtr = NULL;
|
||||||
|
static TMC_INST *tmcInstPtr = NULL;
|
||||||
|
L2_INST *linkInstPtr = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
/**
|
||||||
|
* This function is responsible for initializing the SCUGIC instance, looking
|
||||||
|
* for the device configuration based on the unique device ID, initializing a
|
||||||
|
* SCUGIC instance, and initialize the interrupt at IRQ_F2P[0:0]
|
||||||
|
*
|
||||||
|
* @param intcDesc A pointer to INTC descriptor
|
||||||
|
*
|
||||||
|
* @return SUCCESS if initialize successful.
|
||||||
|
* FAILURE if initialization failed.
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
int32_t SetupInterruptSystem(struct irq_ctrl_desc *descPtr)
|
||||||
|
{
|
||||||
|
int32_t Status;
|
||||||
|
struct xil_irq_desc *xil_dev;
|
||||||
|
|
||||||
|
Status = irq_ctrl_init(&descPtr, &intc_init_param);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Intc Init FAILED, ErrorCode: %" PRId32 ".\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
xil_dev = (struct xil_irq_desc *)(descPtr->extra);
|
||||||
|
|
||||||
|
// Clear any pending interrupt flags
|
||||||
|
uint32_t intrState = XScuGic_CPUReadReg((XScuGic *)(xil_dev->instance), XSCUGIC_INT_ACK_OFFSET);
|
||||||
|
XScuGic_CPUWriteReg((XScuGic *)(xil_dev->instance), XSCUGIC_EOI_OFFSET, intrState);
|
||||||
|
|
||||||
|
/* Initialize physical layer interrupt. */
|
||||||
|
Status = irq_trigger_level_set(descPtr, PHY_INTR_ID, IRQ_EDGE_RISING);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("PHY_INTR trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
// Set highest interrupt priority
|
||||||
|
Status = irq_set_priority(descPtr, PHY_INTR_ID, 0x08);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("PHY_INTR priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
// Connect the interrupt service routine isr1 to the interrupt controller
|
||||||
|
Status = irq_register_callback(descPtr, PHY_INTR_ID, &phy_callback_desc);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize linklayer layer interrupt. */
|
||||||
|
Status = irq_trigger_level_set(descPtr, PERIODIC_5MS_INTR_ID, IRQ_EDGE_RISING);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("PERIODIC_5MS_INTR_ID trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
// Set highest interrupt priority
|
||||||
|
Status = irq_set_priority(descPtr, PERIODIC_5MS_INTR_ID, 0x00);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("PERIODIC_5MS_INTR_ID priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
// Connect the interrupt service routine isr1 to the interrupt controller
|
||||||
|
Status = irq_register_callback(descPtr, PERIODIC_5MS_INTR_ID, &periodicpull_callback_desc);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize system bus interrupt. */
|
||||||
|
Status = irq_trigger_level_set(descPtr, SYSBUS_INTR_ID, IRQ_EDGE_RISING);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("PHY_INTR trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
// Set interrupt priority
|
||||||
|
Status = irq_set_priority(descPtr, SYSBUS_INTR_ID, 0x10);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("PHY_INTR priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect the interrupt service routine isr1 to the interrupt controller
|
||||||
|
Status = irq_register_callback(descPtr, SYSBUS_INTR_ID, &sysbus_callback_desc);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize Scu timer interrupt. */
|
||||||
|
// Connect the interrupt service routine isr1 to the interrupt controller
|
||||||
|
Status = irq_register_callback(descPtr, SCUTIMER_INTR_ID, &scutm_callback_desc);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable interrupts
|
||||||
|
irq_enable(descPtr, PHY_INTR_ID);
|
||||||
|
irq_enable(descPtr, PERIODIC_5MS_INTR_ID);
|
||||||
|
irq_enable(descPtr, SYSBUS_INTR_ID);
|
||||||
|
irq_enable(descPtr, SCUTIMER_INTR_ID);
|
||||||
|
|
||||||
|
// Enable Exceptions
|
||||||
|
Status = irq_global_enable(descPtr);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("IRQ global enable FAILED, ErrorCode: %" PRId32 ".\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
} // SetupInterruptSystem
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
/**
|
||||||
|
* This function is a interrupt service routine for IRQ_F2P[1:1], IRQ_F2P[1:1]
|
||||||
|
* tells CPU that the data in OCM is ready!
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
*
|
||||||
|
* @return None.
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
void Phy_IntrHandler(void *context)
|
||||||
|
{
|
||||||
|
Phy_UpdateState(phyInstPtr);
|
||||||
|
} // PhyIntr_Handler
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
/**
|
||||||
|
* Handler of periodic 5ms interrupt
|
||||||
|
*
|
||||||
|
* @param callBackRef is the linklayer instance pointer.
|
||||||
|
*
|
||||||
|
* @return None.
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
void PeriodicPull_Handler(void *callBackRef)
|
||||||
|
{
|
||||||
|
int32_t Status;
|
||||||
|
Status = Linklayer_Proc(linkInstPtr);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Link layer runs failed, with error code: %" PRId32 "\n", Status);
|
||||||
|
_nop_();
|
||||||
|
}
|
||||||
|
} // PeriodicPull_Handler
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Handler of System Bus TX done interrupt.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
*
|
||||||
|
* @return None.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void Systembus_IntrHandler(void *context)
|
||||||
|
{
|
||||||
|
int32_t Status;
|
||||||
|
Status = SystemBus_IntrHandler(sysbusDescPtr);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("SystemBus_TxIntrHandler exit with error code %" PRId32 ",\n", Status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Handler of ScuTimer interrupt.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
*
|
||||||
|
* @return None.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void ScuTimer_IntrHandler(void *context)
|
||||||
|
{
|
||||||
|
int32_t Status;
|
||||||
|
struct xil_timer_desc *xdesc;
|
||||||
|
xdesc = (struct xil_timer_desc *)(logTmPtr->extra);
|
||||||
|
if (XScuTimer_IsExpired((XScuTimer *)xdesc->instance))
|
||||||
|
{
|
||||||
|
// Refresh log
|
||||||
|
Phy_RefreshHwSate(phyInstPtr);
|
||||||
|
Phy_UpdateLogging(phyInstPtr);
|
||||||
|
Status = SystemBus_GenRemoteCheckRsp(sysbusDescPtr);
|
||||||
|
if(Status != SUCCESS) {
|
||||||
|
DBG_ERROR("Failed to generate remote check.\n");
|
||||||
|
}
|
||||||
|
// if (TimeCtrl_GetIntCnt(tmcInstPtr) - phyInstPtr->lastLogTime >= PHY_LOG_EXPIRE)
|
||||||
|
// {
|
||||||
|
// Phy_UpdateLogging(phyInstPtr);
|
||||||
|
// }
|
||||||
|
|
||||||
|
XScuTimer_ClearInterruptStatus((XScuTimer *)xdesc->instance);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG_WARNING("UNEXPECTED CALL of ScuTimer_IntrHandler\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Main function, initialize all the device needed, initialize
|
||||||
|
* interrupt system, halt in while(1) wait for event interrupt.
|
||||||
|
*
|
||||||
|
* @param none.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int32_t Status;
|
||||||
|
DBG_PRINT("Application Version: %2d.%2d.%4d.\n", _APP_VER_MAIN, _APP_VER_MINOR, _APP_VER_PATCH);
|
||||||
|
|
||||||
|
/* System Monitor Initialize */
|
||||||
|
Status = SysMonitor_Init();
|
||||||
|
if (Status == SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_PRINT("System monitor Init SUCCESS! \n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG_PRINT("System monitor Init FAILED! \n");
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hardware Initialize */
|
||||||
|
Status = Hardware_Init();
|
||||||
|
if (Status == SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_PRINT("Hardware Init SUCCESS! \n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG_PRINT("Hardware Init FAILED! \n");
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Time controller Initialize */
|
||||||
|
Status = TimeCtrl_Init(&tmcInstPtr, &tmcConfig);
|
||||||
|
if (Status == SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_PRINT("TmcCtrl Init SUCCESS! \n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG_PRINT("TmcCtrl Init FAILED! \n");
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Physical Layer Initialize */
|
||||||
|
Status = Phy_Init(&phyInstPtr, &phyConfig);
|
||||||
|
if (Status == SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_PRINT("Physical layer Init SUCCESS! \n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG_PRINT("Physical layer FAILED! \n");
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Link Layer Initialize */
|
||||||
|
linkConfig.phyInstPtr = phyInstPtr;
|
||||||
|
linkConfig.tmcInstPtr = tmcInstPtr;
|
||||||
|
Status = Linklayer_Init(&linkInstPtr, &linkConfig);
|
||||||
|
if (Status == SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_PRINT("LinkLayer Init SUCCESS! \n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG_PRINT("Linklayer Init FAILED! \n");
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* System Bus Initialize */
|
||||||
|
Status = SystemBus_Init(&sysbusDescPtr, &sysbusConfig);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Systembus init FAILED, with error code: %" PRId32 "\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* System Monitor log timer Initialize */
|
||||||
|
Status = timer_init(&logTmPtr, &scutimer_init_param);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("SCU Timer init FAILED, with error code: %" PRId32 "\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* interrupts Initialize */
|
||||||
|
Status = SetupInterruptSystem(intcDescPtr);
|
||||||
|
if (Status == SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_INFO("Interrupt system setup SUCCESS!\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG_ERROR("Interrupt system setup FAILED, ErrorCode: %" PRId32 ".\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start System Monitor logging.
|
||||||
|
timer_start(logTmPtr);
|
||||||
|
|
||||||
|
DBG_PRINT("Physical started...\n");
|
||||||
|
Phy_Start(phyInstPtr);
|
||||||
|
|
||||||
|
// Linklayer_Start(linkInstPtr);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// System bus handler
|
||||||
|
if (SystemBus_IsReqPending(sysbusDescPtr))
|
||||||
|
{
|
||||||
|
Status = SystemBus_HandleCmd(sysbusDescPtr);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("SystemBus_HandleCmd exit with ErrorCode: %" PRId32 ".\n", Status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (SystemBus_IsRsqPending(sysbusDescPtr) && (!SystemBus_IsTxBusy(sysbusDescPtr)))
|
||||||
|
{
|
||||||
|
// FIXME: Required by 12 (CASC)
|
||||||
|
udelay(4000);
|
||||||
|
Status = SystemBus_MakeResp(sysbusDescPtr);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("SystemBus_HandleCmd exit with ErrorCode: %" PRId32 ".\n", Status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // main
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file framing.h
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief DF Linklayer framing functions.
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer_Framing
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "error.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "msg_def.h"
|
||||||
|
#include "link_layer.h"
|
||||||
|
|
||||||
|
/************************** Constant Definitions *****************************/
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Insert a data chunk to a bit array.
|
||||||
|
*
|
||||||
|
* @param frame pointer to target bit array.
|
||||||
|
* @param offset offset of insert start position.
|
||||||
|
* @param bytes number of insert bytes
|
||||||
|
* @param chunk pointer to data chunk
|
||||||
|
*
|
||||||
|
* @return NONE
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void L2_FrameInsertChunk(uint8_t *frame, size_t offset, size_t bytes, const void *chunk)
|
||||||
|
{
|
||||||
|
ASSERT(frame != NULL);
|
||||||
|
ASSERT(chunk != NULL);
|
||||||
|
memcpy(frame + offset, chunk, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Get a data chunk to a frame buff.
|
||||||
|
*
|
||||||
|
* @param frame pointer to target bit array.
|
||||||
|
* @param offset offset of data chunk start position.
|
||||||
|
* @param bytes number of data bytes
|
||||||
|
* @param chunk pointer to data chunk
|
||||||
|
*
|
||||||
|
* @return NONE
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void L2_FrameGetChunk(uint8_t *frame, size_t offset, size_t bytes, void *chunk)
|
||||||
|
{
|
||||||
|
ASSERT(frame != NULL);
|
||||||
|
ASSERT(chunk != NULL);
|
||||||
|
memcpy(chunk, frame + offset, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Generate crc of specified data.
|
||||||
|
*
|
||||||
|
* @param dataBuff pointer to data buffer.
|
||||||
|
* @param dataLen length of specified data.
|
||||||
|
* @param crcType type of crc
|
||||||
|
* @param crc a pointer to 32 bit crc container.
|
||||||
|
*
|
||||||
|
* @return FAILURE crc type not support.
|
||||||
|
* SUCCESS
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
static int32_t L2_CrcGen(uint8_t *dataBuff, uint32_t dataLen, L2_CRC_TYPE crcType, uint32_t *crc)
|
||||||
|
{
|
||||||
|
ASSERT(dataBuff != NULL);
|
||||||
|
int32_t Status;
|
||||||
|
switch (crcType)
|
||||||
|
{
|
||||||
|
case L2_CRC16_1021:
|
||||||
|
Status = crc16_gen(dataBuff, dataLen, 0x1021, (uint16_t *)crc);
|
||||||
|
break;
|
||||||
|
case L2_CRC16_8005:
|
||||||
|
Status = crc16_gen(dataBuff, dataLen, 0x8005, (uint16_t *)crc);
|
||||||
|
break;
|
||||||
|
case L2_CRC8_31:
|
||||||
|
Status = crc8_gen(dataBuff, dataLen, 0x31, (uint8_t *)crc);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Status = EPARAM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Append a crc of specified data, to a specified position.
|
||||||
|
*
|
||||||
|
* @param dataBuff pointer to data buffer.
|
||||||
|
* @param dataLen length of specified data.
|
||||||
|
* @param crcPos position of crc insert position
|
||||||
|
* @param crcType type of crc
|
||||||
|
*
|
||||||
|
* @return FAILURE crc type not support.
|
||||||
|
* SUCCESS
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_CrcAppend(uint8_t *dataBuff, uint32_t dataLen, uint32_t crcPos, L2_CRC_TYPE crcType)
|
||||||
|
{
|
||||||
|
ASSERT(dataBuff != NULL);
|
||||||
|
int32_t Status;
|
||||||
|
uint32_t crcVal;
|
||||||
|
uint8_t *crcPtr;
|
||||||
|
crcPtr = dataBuff + crcPos;
|
||||||
|
Status = L2_CrcGen(dataBuff, dataLen, crcType, &crcVal);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
switch (crcType)
|
||||||
|
{
|
||||||
|
case L2_CRC16_1021:
|
||||||
|
*(crcPtr + 1) = (uint8_t)(crcVal >> 8);
|
||||||
|
*crcPtr = (uint8_t)(crcVal);
|
||||||
|
break;
|
||||||
|
case L2_CRC16_8005:
|
||||||
|
*(crcPtr + 1) = (uint8_t)(crcVal >> 8);
|
||||||
|
*crcPtr = (uint8_t)(crcVal);
|
||||||
|
break;
|
||||||
|
case L2_CRC8_31:
|
||||||
|
*crcPtr = (uint8_t)crcVal;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Status = EPARAM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Check data validation by crc.
|
||||||
|
*
|
||||||
|
* @param dataBuff pointer to data buffer.
|
||||||
|
* @param dataLen length of specified data.
|
||||||
|
* @param crcType type of crc
|
||||||
|
*
|
||||||
|
* @return FAILURE crc type not support.
|
||||||
|
* SUCCESS
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
bool L2_CrcCheck(uint8_t *dataBuff, uint32_t dataLen, L2_CRC_TYPE crcType)
|
||||||
|
{
|
||||||
|
ASSERT(dataBuff != NULL);
|
||||||
|
int32_t Status;
|
||||||
|
uint32_t crcVal;
|
||||||
|
crcVal = 0U;
|
||||||
|
Status = L2_CrcGen(dataBuff, dataLen, crcType, &crcVal);
|
||||||
|
if (Status == SUCCESS)
|
||||||
|
{
|
||||||
|
if (crcVal == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} LinkLayer_Framing*/
|
||||||
|
|
||||||
|
/** @} LinkLayer*/
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file coord.c
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayerGeometry
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayerGeometry_Coord
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include "coord.h"
|
||||||
|
|
||||||
|
const COORD COORD_NIL = {NAN, NAN, NAN};
|
||||||
|
const COORD COORD_ZERO = {0.0, 0.0, 0.0};
|
||||||
|
const COORD COORD_ONE = {1.0, 1.0, 1.0};
|
||||||
|
const COORD COORD_X_AXIS = {1.0, 0.0, 0.0};
|
||||||
|
const COORD COORD_Y_AXIS = {0.0, 1.0, 0.0};
|
||||||
|
const COORD COORD_Z_AXIS = {0.0, 0.0, 1.0};
|
||||||
|
|
||||||
|
/** @brief Subtracts two coordinate vectors. */
|
||||||
|
COORD Coord_Sub(COORD a, COORD b)
|
||||||
|
{
|
||||||
|
COORD ret;
|
||||||
|
ret.x = a.x - b.x;
|
||||||
|
ret.y = a.y - b.y;
|
||||||
|
ret.z = a.z - b.z;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Adds two coordinate vectors. */
|
||||||
|
COORD Coord_Add(COORD a, COORD b)
|
||||||
|
{
|
||||||
|
COORD ret;
|
||||||
|
ret.x = a.x + b.x;
|
||||||
|
ret.y = a.y + b.y;
|
||||||
|
ret.z = a.z + b.z;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Multiplies a coordinate vector by a real number. */
|
||||||
|
void Coord_ScalarMult(COORD *a, double t)
|
||||||
|
{
|
||||||
|
a->x *= t;
|
||||||
|
a->y *= t;
|
||||||
|
a->z *= t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Multiplies a coordinate vector by a real number. */
|
||||||
|
COORD Coord_GetScalarMult(COORD a, double t)
|
||||||
|
{
|
||||||
|
COORD ret;
|
||||||
|
ret.x = a.x * t;
|
||||||
|
ret.y = a.y * t;
|
||||||
|
ret.z = a.z * t;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Divides a coordinate vector by a real number. */
|
||||||
|
void Coord_ScalarDiv(COORD *a, double t)
|
||||||
|
{
|
||||||
|
if (t == 0.0) {
|
||||||
|
*a = COORD_NIL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
a->x /= t;
|
||||||
|
a->y /= t;
|
||||||
|
a->z /= t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Divides a coordinate vector by a real number. */
|
||||||
|
COORD Coord_GetScalarDiv(COORD a, double t)
|
||||||
|
{
|
||||||
|
if (t == 0.0) {
|
||||||
|
return COORD_NIL;
|
||||||
|
}
|
||||||
|
COORD ret;
|
||||||
|
ret.x = a.x / t;
|
||||||
|
ret.y = a.y / t;
|
||||||
|
ret.z = a.z / t;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Dot product. */
|
||||||
|
inline double Coord_Dot(COORD a, COORD b)
|
||||||
|
{
|
||||||
|
return (a.x * b.x + a.y * b.y + a.z * b.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Cross product. */
|
||||||
|
COORD Coord_Cross(COORD a, COORD b)
|
||||||
|
{
|
||||||
|
COORD ret;
|
||||||
|
ret.x = a.y * b.z - a.z * b.y;
|
||||||
|
ret.y = a.z * b.x - a.x * b.z;
|
||||||
|
ret.z = a.x * b.y - a.y * b.x;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Multiplies two coordinate vector in elementwise. */
|
||||||
|
COORD Coord_ElementwiseMult(COORD a, COORD b)
|
||||||
|
{
|
||||||
|
COORD ret;
|
||||||
|
ret.x = a.x * b.x;
|
||||||
|
ret.y = a.y * b.y;
|
||||||
|
ret.z = a.z * b.z;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Divides two coordinate vector in elementwise. */
|
||||||
|
COORD Coord_ElementwiseDiv(COORD a, COORD b)
|
||||||
|
{
|
||||||
|
COORD ret;
|
||||||
|
ret.x = a.x / b.x;
|
||||||
|
ret.y = a.y / b.y;
|
||||||
|
ret.z = a.z / b.z;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Calculate a coordinate vector length^2 (omits calling square root). */
|
||||||
|
double Coord_SquareLength(COORD a)
|
||||||
|
{
|
||||||
|
return (a.x * a.x + a.y * a.y + a.z * a.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Calculate a coordinate vector length. */
|
||||||
|
double Coord_Length(COORD a)
|
||||||
|
{
|
||||||
|
return sqrt(Coord_SquareLength(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Calculate two coordinates' distance. */
|
||||||
|
double Coord_Distance(COORD a, COORD b)
|
||||||
|
{
|
||||||
|
return Coord_Length(Coord_Sub(a, b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Normalize coordinate vector. */
|
||||||
|
void Coord_Normalize(COORD *a)
|
||||||
|
{
|
||||||
|
Coord_ScalarDiv(a, Coord_Length(*a));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Normalize coordinate vector. */
|
||||||
|
COORD Coord_GetNormalized(COORD a)
|
||||||
|
{
|
||||||
|
Coord_Normalize(&a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Returns the angle between the two vectors. */
|
||||||
|
double Coord_Angle(COORD a, COORD b)
|
||||||
|
{
|
||||||
|
Coord_Normalize(&a);
|
||||||
|
Coord_Normalize(&b);
|
||||||
|
return acos(Coord_Dot(a, b));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional Coordinates convert
|
||||||
|
// TODO: Confirm correctness
|
||||||
|
/** @brief Convert coordinate from Launch coordinate system to ECEF. */
|
||||||
|
COORD Coord_Launch2Ecef(COORD o, COORD p, double A, double B, double lambda)
|
||||||
|
{
|
||||||
|
COORD ret;
|
||||||
|
double sinA, cosA, sinB, cosB, sinL, cosL;
|
||||||
|
double S11, S12, S13, S21, S22, S23, S31, S32, S33;
|
||||||
|
sinA = sin(A);
|
||||||
|
cosA = cos(A);
|
||||||
|
sinB = sin(B);
|
||||||
|
cosB = cos(B);
|
||||||
|
sinL = sin(lambda);
|
||||||
|
cosL = cos(lambda);
|
||||||
|
|
||||||
|
S11 = -sinA * sinL - cosA * sinB * cosL;
|
||||||
|
S12 = cosB * cosL;
|
||||||
|
S13 = -cosA * sinL + sinA * sinB * cosL;
|
||||||
|
|
||||||
|
S21 = sinA * cosL - cosA * sinB * sinL;
|
||||||
|
S22 = cosB * sinL;
|
||||||
|
S23 = cosA * cosL + sinA * sinB * sinL;
|
||||||
|
|
||||||
|
S31 = cosA * cosB;
|
||||||
|
S32 = sinB;
|
||||||
|
S33 = -sinA * cosB;
|
||||||
|
|
||||||
|
ret.x = p.x * (S11 + S21 + S31) + o.x;
|
||||||
|
ret.y = p.y * (S12 + S22 + S32) + o.y;
|
||||||
|
ret.z = p.z * (S13 + S23 + S33) + o.z;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Convert coordinate from launch coordinate system to Inertia coordinate system. */
|
||||||
|
COORD Coord_Launch2Inertia(COORD o, COORD p, double A, double B, double we, double t)
|
||||||
|
{
|
||||||
|
COORD ret;
|
||||||
|
double OmgX, OmgY, OmgZ, sinwet, coswet;
|
||||||
|
double M11, M12, M13, M21, M22, M23, M31, M32, M33;
|
||||||
|
OmgX = cos(A) * cos(B);
|
||||||
|
OmgY = sin(B);
|
||||||
|
OmgZ = -sin(A) * cos(B);
|
||||||
|
sinwet = sin(we * t);
|
||||||
|
coswet = cos(we * t);
|
||||||
|
|
||||||
|
M11 = 1 - (1 - OmgX * OmgX) * (1 - coswet);
|
||||||
|
M12 = OmgX * OmgY * (1 - coswet) + OmgZ * sinwet;
|
||||||
|
M13 = OmgX * OmgZ * (1 - coswet) - OmgY * sinwet;
|
||||||
|
|
||||||
|
M21 = OmgY * OmgX * (1 - coswet) - OmgZ * sinwet;
|
||||||
|
M22 = 1 - (1 - OmgY * OmgY) * (1 - coswet);
|
||||||
|
M23 = OmgY * OmgZ * (1 - coswet) + OmgX * sinwet;
|
||||||
|
|
||||||
|
M31 = OmgZ * OmgX * (1 - coswet) + OmgY * sinwet;
|
||||||
|
M32 = OmgZ * OmgY * (1 - coswet) - OmgX * sinwet;
|
||||||
|
M33 = 1 - (1 - OmgZ * OmgZ) * (1 - coswet);
|
||||||
|
|
||||||
|
ret.x = p.x * (M11 + M21 + M31) + o.x;
|
||||||
|
ret.y = p.y * (M12 + M22 + M32) + o.y;
|
||||||
|
ret.z = p.z * (M13 + M23 + M33) + o.z;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} LinkLayerGeometry_Coord */
|
||||||
|
|
||||||
|
/** @} LinkLayerGeometry */
|
||||||
|
|
||||||
|
/** @} LinkLayer */
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file coord.h
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _COORD_H
|
||||||
|
#define _COORD_H
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LinkLayerGeometry
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LinkLayerGeometry_Coord
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct COORD
|
||||||
|
* @brief Structure for storing 3D coordinates.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double z;
|
||||||
|
} COORD;
|
||||||
|
|
||||||
|
extern const COORD COORD_NIL;
|
||||||
|
extern const COORD COORD_ZERO;
|
||||||
|
extern const COORD COORD_ONE;
|
||||||
|
extern const COORD COORD_X_AXIS;
|
||||||
|
extern const COORD COORD_Y_AXIS;
|
||||||
|
extern const COORD COORD_Z_AXIS;
|
||||||
|
|
||||||
|
/** @brief Subtracts two coordinate vectors. */
|
||||||
|
COORD Coord_Sub(COORD a, COORD b);
|
||||||
|
|
||||||
|
/** @brief Adds two coordinate vectors. */
|
||||||
|
COORD Coord_Add(COORD a, COORD b);
|
||||||
|
|
||||||
|
/** @brief Multiplies a coordinate vector by a real number. */
|
||||||
|
void Coord_ScalarMult(COORD *a, double t);
|
||||||
|
|
||||||
|
/** @brief Multiplies a coordinate vector by a real number. */
|
||||||
|
COORD Coord_GetScalarMult(COORD a, double t);
|
||||||
|
|
||||||
|
/** @brief Divides a coordinate vector by a real number. */
|
||||||
|
void Coord_ScalarDiv(COORD *a, double t);
|
||||||
|
|
||||||
|
/** @brief Divides a coordinate vector by a real number. */
|
||||||
|
COORD Coord_GetScalarDiv(COORD a, double t);
|
||||||
|
|
||||||
|
/** @brief Dot product. */
|
||||||
|
double Coord_Dot(COORD a, COORD b);
|
||||||
|
|
||||||
|
/** @brief Cross product. */
|
||||||
|
COORD Coord_Cross(COORD a, COORD b);
|
||||||
|
|
||||||
|
/** @brief Multiplies two coordinate vector in elementwise. */
|
||||||
|
COORD Coord_ElementwiseMult(COORD a, COORD b);
|
||||||
|
|
||||||
|
/** @brief Divides two coordinate vector in elementwise. */
|
||||||
|
COORD Coord_ElementwiseDiv(COORD a, COORD b);
|
||||||
|
|
||||||
|
/** @brief Calculate a coordinate vector length^2 (omits calling square root). */
|
||||||
|
double Coord_SquareLength(COORD a);
|
||||||
|
|
||||||
|
/** @brief Calculate a coordinate vector length. */
|
||||||
|
double Coord_Length(COORD a);
|
||||||
|
|
||||||
|
/** @brief Calculate two coordinates' distance. */
|
||||||
|
double Coord_Distance(COORD a, COORD b);
|
||||||
|
|
||||||
|
/** @brief Normalize coordinate vector. */
|
||||||
|
void Coord_Normalize(COORD *a);
|
||||||
|
|
||||||
|
/** @brief Normalize coordinate vector. */
|
||||||
|
COORD Coord_GetNormalized(COORD a);
|
||||||
|
|
||||||
|
/** @brief Returns the angle between the two vectors. */
|
||||||
|
double Coord_Angle(COORD a, COORD b);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @} LinkLayerGeometry_Coord */
|
||||||
|
|
||||||
|
/** @} LinkLayerGeometry */
|
||||||
|
|
||||||
|
/** @} LinkLayer */
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file eulerangles.c
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayerGeometry
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayerGeometry_EulerAngles
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include "eulerangles.h"
|
||||||
|
|
||||||
|
const EULERANGLES EULERANGLES_NIL = {NAN, NAN, NAN};
|
||||||
|
const EULERANGLES EULERANGLES_ZERO = {0.0, 0.0, 0.0};
|
||||||
|
|
||||||
|
/** @brief Add two EulerAngles. */
|
||||||
|
EULERANGLES EulerAngles_Add(EULERANGLES e1, EULERANGLES e2)
|
||||||
|
{
|
||||||
|
EULERANGLES ret;
|
||||||
|
ret.alpha = e1.alpha + e2.alpha;
|
||||||
|
ret.beta = e1.beta + e2.beta;
|
||||||
|
ret.gamma = e1.gamma + e2.gamma;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Subtracts two EulerAngles. */
|
||||||
|
EULERANGLES EulerAngles_Sub(EULERANGLES e1, EULERANGLES e2)
|
||||||
|
{
|
||||||
|
EULERANGLES ret;
|
||||||
|
ret.alpha = e1.alpha - e2.alpha;
|
||||||
|
ret.beta = e1.beta - e2.beta;
|
||||||
|
ret.gamma = e1.gamma - e2.gamma;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Multiplies EulerAngles by a real number. */
|
||||||
|
void EulerAngles_ScalarMult(EULERANGLES *e, double f)
|
||||||
|
{
|
||||||
|
e->alpha *= f;
|
||||||
|
e->beta *= f;
|
||||||
|
e->gamma *= f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Multiplies EulerAngles by a real number. */
|
||||||
|
EULERANGLES EulerAngles_GetScalarMult(EULERANGLES e, double f)
|
||||||
|
{
|
||||||
|
EulerAngles_ScalarMult(&e, f);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Normalize EulerAngles. */
|
||||||
|
void EulerAngles_Normalize(EULERANGLES *e)
|
||||||
|
{
|
||||||
|
e->alpha = fmod(e->alpha, 2.0 * EUL_PI);
|
||||||
|
e->beta = fmod(e->beta, 2.0 * EUL_PI);
|
||||||
|
e->gamma = fmod(e->gamma, 2.0 * EUL_PI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Normalize EulerAngles. */
|
||||||
|
EULERANGLES EulerAngles_GetNormalize(EULERANGLES e)
|
||||||
|
{
|
||||||
|
EulerAngles_Normalize(&e);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} LinkLayerGeometry_EulerAngles */
|
||||||
|
|
||||||
|
/** @} LinkLayerGeometry */
|
||||||
|
|
||||||
|
/** @} LinkLayer */
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file eulerangles.h
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayerGeometry
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LinkLayerGeometry_EulerAngles
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __EULERANGLES_H
|
||||||
|
#define __EULERANGLES_H
|
||||||
|
|
||||||
|
#define EUL_PI 3.14159265358979323846
|
||||||
|
|
||||||
|
#define DEG2RAD(d) ((EUL_PI / 180.0) * (d))
|
||||||
|
#define RAD2DEG(r) ((180.0 / EUL_PI) * (r))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Orientations are represented by 3D double precision Tait-Bryan (Euler) tuples
|
||||||
|
* called EulerAngles. The angles are in Z, Y', X" order that is often called
|
||||||
|
* intrinsic rotations, they are measured in radians. The default (unrotated)
|
||||||
|
* orientation is along the X axis. Conceptually, the Z axis rotation is heading,
|
||||||
|
* the Y' axis rotation is descending (negative elevation), the X" axis rotation is bank.
|
||||||
|
* For example, positive rotation along the Z axis rotates X into Y (turns left), positive
|
||||||
|
* rotation along the Y axis rotates Z into X (leans forward), positive rotation
|
||||||
|
* along the X axis rotates Y into Z (leans right).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct EULERANGLES
|
||||||
|
* @brief Structure for standard quaternion
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
double alpha; // unit rad
|
||||||
|
double beta; // unit rad
|
||||||
|
double gamma; // unit rad
|
||||||
|
} EULERANGLES;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
EULERANGLES_NONE = 0,
|
||||||
|
EULERANGLES_ZYX = 1,
|
||||||
|
EULERANGLES_ZYZ = 2,
|
||||||
|
EULERANGLES_XYZ = 3,
|
||||||
|
} EULERANGLES_TYPE;
|
||||||
|
|
||||||
|
extern const EULERANGLES EULERANGLES_ZERO;
|
||||||
|
extern const EULERANGLES EULERANGLES_NIL;
|
||||||
|
|
||||||
|
/** @brief Add two EulerAngles. */
|
||||||
|
EULERANGLES EulerAngles_Add(EULERANGLES e1, EULERANGLES e2);
|
||||||
|
|
||||||
|
/** @brief Subtracts two EulerAngles. */
|
||||||
|
EULERANGLES EulerAngles_Sub(EULERANGLES e1, EULERANGLES e2);
|
||||||
|
|
||||||
|
/** @brief Multiplies EulerAngles by a real number. */
|
||||||
|
void EulerAngles_ScalarMult(EULERANGLES *e, double f);
|
||||||
|
|
||||||
|
/** @brief Multiplies EulerAngles by a real number. */
|
||||||
|
EULERANGLES EulerAngles_GetScalarMult(EULERANGLES e, double f);
|
||||||
|
|
||||||
|
/** @brief Normalize EulerAngles. */
|
||||||
|
void EulerAngles_Normalize(EULERANGLES *e);
|
||||||
|
|
||||||
|
/** @brief Normalize EulerAngles. */
|
||||||
|
EULERANGLES EulerAngles_GetNormalize(EULERANGLES e);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @} LinkLayerGeometry_EulerAngles */
|
||||||
|
|
||||||
|
/** @} LinkLayerGeometry */
|
||||||
|
|
||||||
|
/** @} LinkLayer */
|
||||||
@@ -0,0 +1,499 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file quaternion.c
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayerGeometry
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayerGeometry_Quaternion
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "coord.h"
|
||||||
|
#include "eulerangles.h"
|
||||||
|
#include "quaternion.h"
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
float value;
|
||||||
|
uint32_t raw;
|
||||||
|
} SOFT_FLOAT;
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
double value;
|
||||||
|
uint64_t raw;
|
||||||
|
} SOFT_DOUBLE;
|
||||||
|
|
||||||
|
const SOFT_FLOAT EPS_FLOAT = {.raw = 0x34000000};
|
||||||
|
const SOFT_DOUBLE EPS_DOUBLE = {.raw = 0x3CB0000000000000};
|
||||||
|
|
||||||
|
const QUATERNION QUATERNION_IDENTITY = {1.0, 0.0, 0.0, 0.0};
|
||||||
|
const QUATERNION QUATERNION_NIL = {NAN, NAN, NAN, NAN};
|
||||||
|
|
||||||
|
/** @brief Subtracts two quaternions. */
|
||||||
|
QUATERNION Quaternion_Sub(QUATERNION q1, QUATERNION q2)
|
||||||
|
{
|
||||||
|
QUATERNION ret;
|
||||||
|
ret.s = q1.s - q2.s;
|
||||||
|
ret.i = q1.i - q2.i;
|
||||||
|
ret.j = q1.j - q2.j;
|
||||||
|
ret.k = q1.k - q2.k;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Adds two quaternions. */
|
||||||
|
QUATERNION Quaternion_Add(QUATERNION q1, QUATERNION q2)
|
||||||
|
{
|
||||||
|
QUATERNION ret;
|
||||||
|
ret.s = q1.s + q2.s;
|
||||||
|
ret.i = q1.i + q2.i;
|
||||||
|
ret.j = q1.j + q2.j;
|
||||||
|
ret.k = q1.k + q2.k;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Multiplies a quaternion by a real number. */
|
||||||
|
void Quaternion_ScalarMult(QUATERNION *q, double t)
|
||||||
|
{
|
||||||
|
q->s *= t;
|
||||||
|
q->i *= t;
|
||||||
|
q->j *= t;
|
||||||
|
q->k *= t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Multiplies a quaternion by a real number. */
|
||||||
|
QUATERNION Quaternion_GetScalarMult(QUATERNION a, double t)
|
||||||
|
{
|
||||||
|
Quaternion_ScalarMult(&a, t);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Divides a quaternion by a real number. */
|
||||||
|
void Quaternion_ScalarDiv(QUATERNION *q, double t)
|
||||||
|
{
|
||||||
|
if (t == 0.0) {
|
||||||
|
*q = QUATERNION_NIL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
q->s /= t;
|
||||||
|
q->i /= t;
|
||||||
|
q->j /= t;
|
||||||
|
q->k /= t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Divides a quaternion by a real number. */
|
||||||
|
QUATERNION Quaternion_GetScalarDiv(QUATERNION q, double t)
|
||||||
|
{
|
||||||
|
Quaternion_ScalarDiv(&q, t);
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Multiplies two quaternions. */
|
||||||
|
QUATERNION Quaternion_Mult(QUATERNION q1, QUATERNION q2)
|
||||||
|
{
|
||||||
|
QUATERNION ret;
|
||||||
|
ret.s = q1.s * q2.s - (q1.i * q2.i + q1.j * q2.j + q1.k * q2.k);
|
||||||
|
ret.i = q1.j * q2.k - q1.k * q2.j + q1.s * q2.i + q1.i * q2.s;
|
||||||
|
ret.j = q1.k * q2.i - q1.i * q2.k + q1.s * q2.j + q1.j * q2.s;
|
||||||
|
ret.k = q1.i * q2.j - q1.j * q2.i + q1.s * q2.k + q1.k * q2.s;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Divides two quaternions. */
|
||||||
|
QUATERNION Quaternion_Div(QUATERNION q1, QUATERNION q2)
|
||||||
|
{
|
||||||
|
Quaternion_Inverse(&q2);
|
||||||
|
return Quaternion_Mult(q1, q2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Dot product. */
|
||||||
|
inline double Quaternion_Dot(QUATERNION q1, QUATERNION q2)
|
||||||
|
{
|
||||||
|
return (q1.s * q2.s + q1.i * q2.i + q1.j * q2.j + q1.k * q2.k);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Calculate a quaternion length^2 (omits calling square root). */
|
||||||
|
inline double Quaternion_SquareLength(QUATERNION q)
|
||||||
|
{
|
||||||
|
return (q.s * q.s + q.i * q.i + q.j * q.j + q.k * q.k);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Calculate a quaternion length. */
|
||||||
|
inline double Quaternion_Length(QUATERNION q)
|
||||||
|
{
|
||||||
|
return sqrt(Quaternion_SquareLength(q));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Normalize quaternion. */
|
||||||
|
void Quaternion_Normalize(QUATERNION *q)
|
||||||
|
{
|
||||||
|
Quaternion_ScalarDiv(q, Quaternion_Length(*q));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Normalize quaternion. */
|
||||||
|
QUATERNION Quaternion_GetNormalized(QUATERNION q)
|
||||||
|
{
|
||||||
|
Quaternion_Normalize(&q);
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Conjugated quaternion. */
|
||||||
|
void Quaternion_Conjugated(QUATERNION *q)
|
||||||
|
{
|
||||||
|
q->i = -q->i;
|
||||||
|
q->j = -q->j;
|
||||||
|
q->k = -q->k;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Conjugated quaternion. */
|
||||||
|
QUATERNION Quaternion_GetConjugated(QUATERNION q)
|
||||||
|
{
|
||||||
|
Quaternion_Conjugated(&q);
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Inverse quaternion. */
|
||||||
|
void Quaternion_Inverse(QUATERNION *q)
|
||||||
|
{
|
||||||
|
Quaternion_Conjugated(q);
|
||||||
|
Quaternion_ScalarDiv(q, Quaternion_SquareLength(*q));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Inverse quaternion. */
|
||||||
|
QUATERNION Quaternion_GeInverse(QUATERNION q)
|
||||||
|
{
|
||||||
|
Quaternion_Inverse(&q);
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double Quaternion_GetRotationAngle(QUATERNION q)
|
||||||
|
{
|
||||||
|
return (acos(q.s) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Get axis of quaternion. */
|
||||||
|
COORD Quaternion_GetRotationAxis(QUATERNION q)
|
||||||
|
{
|
||||||
|
if ((q.s > 1.0) || (q.s < -1.0)) {
|
||||||
|
return COORD_NIL;
|
||||||
|
}
|
||||||
|
double sin_theta_inv;
|
||||||
|
COORD ret;
|
||||||
|
sin_theta_inv = 1.0 / sin(acos(q.s));
|
||||||
|
ret.x = q.i * sin_theta_inv;
|
||||||
|
ret.y = q.j * sin_theta_inv;
|
||||||
|
ret.z = q.k * sin_theta_inv;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Get the axis and rotate angle of a unit Quaternion */
|
||||||
|
void Quaternion_GetRotationAxisAndAngle(QUATERNION q, COORD *axis, double *angle)
|
||||||
|
{
|
||||||
|
if ((q.s > 1.0) || (q.s < -1.0)) {
|
||||||
|
*axis = COORD_NIL;
|
||||||
|
*angle = NAN;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double sin_theta_inv;
|
||||||
|
*angle = acos(q.s);
|
||||||
|
|
||||||
|
// pre-compute to save time
|
||||||
|
sin_theta_inv = 1.0 / sin(*angle);
|
||||||
|
|
||||||
|
// now the vector
|
||||||
|
axis->x = q.i * sin_theta_inv;
|
||||||
|
axis->y = q.j * sin_theta_inv;
|
||||||
|
axis->z = q.k * sin_theta_inv;
|
||||||
|
*angle = (*angle) * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Decompose the rotation on to 2 parts. */
|
||||||
|
void Quaternion_GetSwingAndTwist(QUATERNION q, COORD axis, QUATERNION *swing, QUATERNION *twist)
|
||||||
|
{
|
||||||
|
if ((swing == NULL) || (twist == NULL))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double p;
|
||||||
|
COORD v;
|
||||||
|
v.x = q.i;
|
||||||
|
v.y = q.j;
|
||||||
|
v.z = q.k;
|
||||||
|
// return projection v1 on to v2 (parallel component)
|
||||||
|
p = Coord_Dot(v, axis);
|
||||||
|
v = Coord_GetScalarMult(axis, p);
|
||||||
|
twist->s = q.s;
|
||||||
|
twist->i = v.x;
|
||||||
|
twist->j = v.y;
|
||||||
|
twist->k = v.z;
|
||||||
|
Quaternion_Normalize(twist);
|
||||||
|
*swing = Quaternion_Mult(q, Quaternion_GetConjugated(*twist));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief rotates v by this quaternion (quaternion must be unit) */
|
||||||
|
COORD Quaternion_Rotate(QUATERNION q, COORD v)
|
||||||
|
{
|
||||||
|
QUATERNION temp;
|
||||||
|
COORD ret;
|
||||||
|
temp.s = 0;
|
||||||
|
temp.i = v.x;
|
||||||
|
temp.j = v.y;
|
||||||
|
temp.k = v.z;
|
||||||
|
temp = Quaternion_Mult(q, temp);
|
||||||
|
Quaternion_Conjugated(&q);
|
||||||
|
temp = Quaternion_Mult(temp, q);
|
||||||
|
ret.x = temp.i;
|
||||||
|
ret.y = temp.j;
|
||||||
|
ret.z = temp.k;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief returns the euler angles from a rotation Quaternion */
|
||||||
|
EULERANGLES Quaternion_ToEulerAngles(QUATERNION q, EULERANGLES_TYPE type)
|
||||||
|
{
|
||||||
|
EULERANGLES ret;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case EULERANGLES_ZYX:
|
||||||
|
{
|
||||||
|
/* Covert form matlab 2023a */
|
||||||
|
// Cap all inputs to asin to 1, since values >1 produce complex
|
||||||
|
// results
|
||||||
|
// Since the quaternion is of unit length, this should never happen,
|
||||||
|
// but some code generation configuration seem to hit this edge case
|
||||||
|
// under some circumstances.
|
||||||
|
|
||||||
|
double asinValue;
|
||||||
|
bool mask1, mask2;
|
||||||
|
|
||||||
|
asinValue = -2.0 * (q.i * q.k - q.s * q.j);
|
||||||
|
mask1 = asinValue >= 1.0 - 10 * EPS_DOUBLE.value;
|
||||||
|
mask2 = asinValue <= -1.0 + 10 * EPS_DOUBLE.value;
|
||||||
|
if (mask1)
|
||||||
|
asinValue = 1;
|
||||||
|
if (mask2)
|
||||||
|
asinValue = -1;
|
||||||
|
|
||||||
|
if (mask1 || mask2)
|
||||||
|
{
|
||||||
|
ret.alpha = (asinValue > 0) ? (-2.0 * atan2(q.i, q.s)) : (2.0 * atan2(q.i, q.s));
|
||||||
|
ret.gamma = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret.alpha = atan2(2.0 * (q.i * q.j + q.s * q.k), q.s * q.s + q.i * q.i - q.j * q.j - q.k * q.k);
|
||||||
|
ret.gamma = atan2(2.0 * (q.j * q.k + q.s * q.i), q.s * q.s - q.i * q.i - q.j * q.j + q.k * q.k);
|
||||||
|
}
|
||||||
|
ret.beta = asin(asinValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EULERANGLES_ZYZ:
|
||||||
|
{
|
||||||
|
// TODO;
|
||||||
|
ret = EULERANGLES_NIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EULERANGLES_XYZ:
|
||||||
|
{
|
||||||
|
/* Covert form matlab 2023a */
|
||||||
|
// Prevent singularities as done in ZYX case
|
||||||
|
// Alternative to rotm2eul(quat2rotm(q), 'XYZ') with fewer
|
||||||
|
// operations
|
||||||
|
// sin(y) = R13 = 2 * (qx*qz + qy*qw)
|
||||||
|
// tan(x) = sin(x) / cos(x) = -R23 / R33
|
||||||
|
// = -2 * (qy*qz - qx*qw) / (1 - 2*(qx^2 + qy^2))
|
||||||
|
// = -2 * (qy*qz - qx*qw) / (qw^2 - qx^2 - qy^2 + qz^2)
|
||||||
|
// tan(z) = sin(z) / cos(z) = -R12 / R11
|
||||||
|
// = -2 * (qx*qy - qz*qw) / (1 - 2*(qy^2 + qz^2))
|
||||||
|
// = -2 * (qy*qz - qx*qw) / (qw^2 + qx^2 - qy^2 - qz^2)
|
||||||
|
|
||||||
|
double asinValue;
|
||||||
|
bool mask1, mask2;
|
||||||
|
|
||||||
|
asinValue = 2.0 * (q.i * q.k + q.s * q.j);
|
||||||
|
mask1 = asinValue >= 1.0 - 10 * EPS_DOUBLE.value;
|
||||||
|
mask2 = asinValue <= -1.0 + 10 * EPS_DOUBLE.value;
|
||||||
|
if (mask1)
|
||||||
|
asinValue = 1;
|
||||||
|
if (mask2)
|
||||||
|
asinValue = -1;
|
||||||
|
if (mask1 || mask2)
|
||||||
|
{
|
||||||
|
ret.alpha = 0;
|
||||||
|
ret.gamma = (asinValue > 0.0) ? (2.0 * atan2(q.i, q.s)) : (-2.0 * atan2(q.i, q.s));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret.alpha = atan2(-2.0 * (q.j * q.k - q.s * q.i), q.s * q.s - q.i * q.i - q.j * q.j + q.k * q.k);
|
||||||
|
ret.gamma = atan2(-2.0 * (q.i * q.j - q.s * q.k), q.s * q.s + q.i * q.i - q.j * q.j - q.k * q.k);
|
||||||
|
}
|
||||||
|
ret.beta = asin(asinValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = EULERANGLES_NIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief returns the rotation Quaternion from a euler angles */
|
||||||
|
QUATERNION Quaternion_FromeEulerAngles(EULERANGLES e, EULERANGLES_TYPE type)
|
||||||
|
{
|
||||||
|
QUATERNION ret;
|
||||||
|
double cosx, sinx, cosy, siny, cosz, sinz;
|
||||||
|
cosx = cos(e.alpha * 0.5);
|
||||||
|
sinx = sin(e.alpha * 0.5);
|
||||||
|
cosy = cos(e.beta * 0.5);
|
||||||
|
siny = sin(e.beta * 0.5);
|
||||||
|
cosz = cos(e.gamma * 0.5);
|
||||||
|
sinz = sin(e.gamma * 0.5);
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case EULERANGLES_ZYX:
|
||||||
|
ret.s = cosx * cosy * cosz + sinx * siny * sinz;
|
||||||
|
ret.i = cosx * cosy * sinz - sinx * siny * cosz;
|
||||||
|
ret.j = cosx * siny * cosz + sinx * cosy * sinz;
|
||||||
|
ret.k = sinx * cosy * cosz - cosx * siny * sinz;
|
||||||
|
break;
|
||||||
|
case EULERANGLES_ZYZ:
|
||||||
|
ret.s = cosx * cosy * cosz - sinx * cosy * sinz;
|
||||||
|
ret.i = cosx * siny * sinz - sinx * siny * cosz;
|
||||||
|
ret.j = cosx * siny * cosz + sinx * siny * sinz;
|
||||||
|
ret.k = sinx * cosy * cosz + cosx * cosy * sinz;
|
||||||
|
break;
|
||||||
|
case EULERANGLES_XYZ:
|
||||||
|
ret.s = cosx * cosy * cosz - sinx * siny * sinz;
|
||||||
|
ret.i = sinx * cosy * cosz + cosx * siny * sinz;
|
||||||
|
ret.j = -sinx * cosy * sinz + cosx * siny * cosz;
|
||||||
|
ret.k = cosx * cosy * sinz + sinx * siny * cosz;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = QUATERNION_NIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief adapted from https://svn.code.sf.net/p/irrlicht/code/trunk/include/quaternion.h */
|
||||||
|
QUATERNION Quaternion_RotationFromTo(COORD from, COORD to)
|
||||||
|
{
|
||||||
|
// Based on Stan Melax's article in Game Programming Gems
|
||||||
|
COORD axis;
|
||||||
|
QUATERNION ret;
|
||||||
|
double c, s;
|
||||||
|
Coord_Normalize(&from);
|
||||||
|
Coord_Normalize(&to);
|
||||||
|
|
||||||
|
c = Coord_Dot(from, to);
|
||||||
|
|
||||||
|
if (c >= 1.0)
|
||||||
|
{ // If dot == 1, vectors are the same
|
||||||
|
return QUATERNION_IDENTITY; // identity
|
||||||
|
}
|
||||||
|
else if (c <= -1.0)
|
||||||
|
{ // exactly opposite
|
||||||
|
axis = Coord_Cross(COORD_X_AXIS, from);
|
||||||
|
|
||||||
|
if (Coord_Length(axis) == 0)
|
||||||
|
axis = Coord_Cross(COORD_Y_AXIS, from);
|
||||||
|
|
||||||
|
// same as fromAxisAngle(axis, PI).normalize();
|
||||||
|
ret.s = 0;
|
||||||
|
ret.i = axis.x;
|
||||||
|
ret.j = axis.y;
|
||||||
|
ret.k = axis.z;
|
||||||
|
Quaternion_Normalize(&ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = sqrt((1 + c) * 2);
|
||||||
|
axis = Coord_Cross(from, to);
|
||||||
|
Coord_ScalarDiv(&axis, s);
|
||||||
|
ret.s = s * 0.5;
|
||||||
|
ret.i = axis.x;
|
||||||
|
ret.j = axis.y;
|
||||||
|
ret.k = axis.z;
|
||||||
|
Quaternion_Normalize(&ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief linear quaternion interpolation */
|
||||||
|
QUATERNION Quaternion_Lerp(QUATERNION q1, QUATERNION q2, double t)
|
||||||
|
{
|
||||||
|
QUATERNION ret;
|
||||||
|
Quaternion_ScalarMult(&q1, 1.0 - t);
|
||||||
|
Quaternion_ScalarMult(&q1, t);
|
||||||
|
ret = Quaternion_Add(q1, q2);
|
||||||
|
Quaternion_Normalize(&ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief spherical linear interpolation */
|
||||||
|
QUATERNION Quaternion_Slerp(QUATERNION q1, QUATERNION q2, double t)
|
||||||
|
{
|
||||||
|
double dot;
|
||||||
|
QUATERNION q3, ret;
|
||||||
|
dot = Quaternion_Dot(q1, q2);
|
||||||
|
/* dot = cos(theta)
|
||||||
|
if (dot < 0), q1 and q2 are more than 90 degrees apart,
|
||||||
|
so we can invert one to reduce spinning */
|
||||||
|
if (dot < 0)
|
||||||
|
{
|
||||||
|
dot = -dot;
|
||||||
|
q3.s = -q2.s;
|
||||||
|
q3.i = -q2.i;
|
||||||
|
q3.j = -q2.j;
|
||||||
|
q3.k = -q2.k;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
q3 = q2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dot < 0.95)
|
||||||
|
{
|
||||||
|
double angle = acos(dot);
|
||||||
|
Quaternion_ScalarMult(&q1, sin(angle * (1 - t)));
|
||||||
|
Quaternion_ScalarMult(&q3, sin(angle * t));
|
||||||
|
ret = Quaternion_Add(q1, q3);
|
||||||
|
Quaternion_ScalarDiv(&ret, sin(angle));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
// if the angle is small, use linear interpolation
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Quaternion_Lerp(q1, q3, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} LinkLayerGeometry_Quaternion */
|
||||||
|
|
||||||
|
/** @} LinkLayerGeometry */
|
||||||
|
|
||||||
|
/** @} LinkLayer */
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file quaternion.h
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayerGeometry
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LinkLayerGeometry_Quaternion
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __QUATERNION_H
|
||||||
|
#define __QUATERNION_H
|
||||||
|
|
||||||
|
#include "coord.h"
|
||||||
|
#include "eulerangles.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct QUATERNION
|
||||||
|
* @brief Structure for standard quaternion
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
double s;
|
||||||
|
double i;
|
||||||
|
double j;
|
||||||
|
double k;
|
||||||
|
} QUATERNION;
|
||||||
|
|
||||||
|
extern const QUATERNION QUATERNION_IDENTITY;
|
||||||
|
extern const QUATERNION QUATERNION_NIL;
|
||||||
|
|
||||||
|
/** @brief Subtracts two quaternions. */
|
||||||
|
QUATERNION Quaternion_Sub(QUATERNION q1, QUATERNION q2);
|
||||||
|
|
||||||
|
/** @brief Adds two quaternions. */
|
||||||
|
QUATERNION Quaternion_Add(QUATERNION q1, QUATERNION q2);
|
||||||
|
|
||||||
|
/** @brief Multiplies a quaternion by a real number. */
|
||||||
|
void Quaternion_ScalarMult(QUATERNION *q, double t);
|
||||||
|
|
||||||
|
/** @brief Multiplies a quaternion by a real number. */
|
||||||
|
QUATERNION Quaternion_GetScalarMult(QUATERNION q, double t);
|
||||||
|
|
||||||
|
/** @brief Divides a quaternion by a real number. */
|
||||||
|
void Quaternion_ScalarDiv(QUATERNION *q, double t);
|
||||||
|
|
||||||
|
/** @brief Divides a quaternion by a real number. */
|
||||||
|
QUATERNION Quaternion_GetScalarDiv(QUATERNION q, double t);
|
||||||
|
|
||||||
|
/** @brief Multiplies two quaternions. */
|
||||||
|
QUATERNION Quaternion_Mult(QUATERNION q1, QUATERNION q2);
|
||||||
|
|
||||||
|
/** @brief Divides two quaternions. */
|
||||||
|
QUATERNION Quaternion_Div(QUATERNION q1, QUATERNION q2);
|
||||||
|
|
||||||
|
/** @brief Dot product. */
|
||||||
|
double Quaternion_Dot(QUATERNION q1, QUATERNION q2);
|
||||||
|
|
||||||
|
/** @brief Calculate a quaternion length^2 (omits calling square root). */
|
||||||
|
double Quaternion_SquareLength(QUATERNION q);
|
||||||
|
|
||||||
|
/** @brief Calculate a quaternion length. */
|
||||||
|
double Quaternion_Length(QUATERNION q);
|
||||||
|
|
||||||
|
/** @brief Normalize quaternion. */
|
||||||
|
void Quaternion_Normalize(QUATERNION *q);
|
||||||
|
|
||||||
|
/** @brief Normalize quaternion. */
|
||||||
|
QUATERNION Quaternion_GetNormalized(QUATERNION q);
|
||||||
|
|
||||||
|
/** @brief Conjugated quaternion. */
|
||||||
|
void Quaternion_Conjugated(QUATERNION *q);
|
||||||
|
|
||||||
|
/** @brief Conjugated quaternion. */
|
||||||
|
QUATERNION Quaternion_GetConjugated(QUATERNION q);
|
||||||
|
|
||||||
|
/** @brief Inverse quaternion. */
|
||||||
|
void Quaternion_Inverse(QUATERNION *q);
|
||||||
|
|
||||||
|
/** @brief Inverse quaternion. */
|
||||||
|
QUATERNION Quaternion_GeInverse(QUATERNION q);
|
||||||
|
|
||||||
|
/** @brief Get rotate angle of quaternion. */
|
||||||
|
double Quaternion_GetRotationAngle(QUATERNION q);
|
||||||
|
|
||||||
|
/** @brief Get axis of quaternion. */
|
||||||
|
COORD Quaternion_GetRotationAxis(QUATERNION q);
|
||||||
|
|
||||||
|
/** @brief Get the axis and rotate angle of a unit Quaternion */
|
||||||
|
void Quaternion_GetRotationAxisAndAngle(QUATERNION q, COORD *axis, double *angle);
|
||||||
|
|
||||||
|
/** @brief Decompose the rotation on to 2 parts.
|
||||||
|
1. Twist - rotation around the "direction" vector
|
||||||
|
2. Swing - rotation around axis that is perpendicular to "direction" vector
|
||||||
|
The rotation can be composed back by rotation = swing * twist
|
||||||
|
|
||||||
|
has singularity in case of swing_rotation close to 180 degrees rotation.
|
||||||
|
if the input quaternion is of non-unit length, the outputs are non-unit as well
|
||||||
|
otherwise, outputs are both unit
|
||||||
|
*/
|
||||||
|
void Quaternion_GetSwingAndTwist(QUATERNION q, COORD axis, QUATERNION *swing, QUATERNION *twist);
|
||||||
|
|
||||||
|
/** @brief rotates v by this quaternion (quaternion must be unit) */
|
||||||
|
COORD Quaternion_Rotate(QUATERNION q, COORD v);
|
||||||
|
|
||||||
|
/** @brief returns the euler angles from a rotation Quaternion */
|
||||||
|
EULERANGLES Quaternion_ToEulerAngles(QUATERNION q, EULERANGLES_TYPE type);
|
||||||
|
|
||||||
|
/** @brief returns the rotation Quaternion from a euler angles */
|
||||||
|
QUATERNION Quaternion_FromeEulerAngles(EULERANGLES e, EULERANGLES_TYPE type);
|
||||||
|
|
||||||
|
/** @brief adapted from https://svn.code.sf.net/p/irrlicht/code/trunk/include/quaternion.h */
|
||||||
|
QUATERNION Quaternion_RotationFromTo(COORD from, COORD to);
|
||||||
|
|
||||||
|
/** @brief linear quaternion interpolation */
|
||||||
|
QUATERNION Quaternion_Lerp(QUATERNION q1, QUATERNION q2, double t);
|
||||||
|
|
||||||
|
/** @brief spherical linear interpolation */
|
||||||
|
QUATERNION Quaternion_Slerp(QUATERNION q1, QUATERNION q2, double t);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @} LinkLayerGeometry_Quaternion */
|
||||||
|
|
||||||
|
/** @} LinkLayerGeometry */
|
||||||
|
|
||||||
|
/** @} LinkLayer */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,220 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file link_layer.h
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief DF Linklayer header file.
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LINK_LAYER_H_
|
||||||
|
#define __LINK_LAYER_H_
|
||||||
|
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "link_layer_types.h"
|
||||||
|
#include "schdevent.h"
|
||||||
|
#include "node_list.h"
|
||||||
|
#include "circ_queue.h"
|
||||||
|
#include "../phy_layer/phy_layer.h"
|
||||||
|
#include "../../system_monitor.h"
|
||||||
|
/************************** Constant Definitions *****************************/
|
||||||
|
/***************** Macros (Inline Functions) Definitions *********************/
|
||||||
|
#define AssertL2Event(instPtr, event) (Linklayer_EventHandler((instPtr), (event)))
|
||||||
|
/**************************** Type Definitions *******************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct L2_CONFIG
|
||||||
|
* @brief A struct holds all linklayer initialization parameters
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
L2_NODE_TYPE myType; ///< node type
|
||||||
|
uint8_t clustId; ///< node cluster id
|
||||||
|
uint8_t myId; ///< node id
|
||||||
|
uint8_t headId; ///< head node id
|
||||||
|
uint8_t netScale; ///< net scale
|
||||||
|
PHY_INST *phyInstPtr; ///< pointer to system physical layer instance
|
||||||
|
TMC_INST *tmcInstPtr; ///< pointer to system timer controller layer instance
|
||||||
|
} L2_CONFIG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct L2_LOG
|
||||||
|
* @brief A struct holds linklayer operating log
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t frameRx; ///< total rx frame count
|
||||||
|
uint32_t frameTx; ///< total tx frame count
|
||||||
|
uint32_t frameRecv; ///< total received frame count
|
||||||
|
uint32_t frameCorrect; ///< total correctly received frame count
|
||||||
|
|
||||||
|
uint32_t advRxCnt; ///< advertise rx frame count
|
||||||
|
uint32_t advTxCnt; ///< advertise tx frame count
|
||||||
|
uint32_t advRecvCnt; ///< advertise received frame count
|
||||||
|
uint32_t advCorrectCnt; ///< advertise correctly received frame count
|
||||||
|
|
||||||
|
uint32_t cfmRxCnt; ///< confirm rx frame count
|
||||||
|
uint32_t cfmTxCnt; ///< confirm tx frame count
|
||||||
|
uint32_t cfmRecvCnt; ///< confirm received frame count
|
||||||
|
uint32_t cfmCorrectCnt; ///< confirm correctly received frame count
|
||||||
|
|
||||||
|
uint32_t svcRxCnt; ///< service rx frame count
|
||||||
|
uint32_t svcTxCnt; ///< service tx frame count
|
||||||
|
uint32_t svcRecvCnt; ///< service received frame count
|
||||||
|
uint32_t svcCorrectCnt; ///< service correctly received frame count
|
||||||
|
|
||||||
|
int64_t timeDev; ///< last time deviation estimation result
|
||||||
|
uint8_t lastBeamWidth; ///< last beam width
|
||||||
|
uint32_t reconnectCnt; ///< reconnect trial count
|
||||||
|
|
||||||
|
PAYLOAD rxLog;
|
||||||
|
PAYLOAD txLog;
|
||||||
|
} L2_LOG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct L2_INST
|
||||||
|
* @brief A linklayer instance
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
L2_CONFIG config; ///< linklayer configuration parameters
|
||||||
|
L2_NODE_INFO myInfo; ///< current node info
|
||||||
|
NODE_LIST *nodeList; ///< discovered node list
|
||||||
|
L2_SCHD_POOL *schdEventPool; ///< event schedule pool
|
||||||
|
uint32_t netStartTime; ///< network start time
|
||||||
|
bool isEnable; ///< indicates if the node is connected to the network
|
||||||
|
bool dataAvail; ///< indicates if there is a valid received frame data in rx buffer
|
||||||
|
bool cxn2Net; ///< indicates if the node is connected to the network
|
||||||
|
L2_RCD frameNum; ///< stores the last current and next frame number.
|
||||||
|
L2_RCD slotNum; ///< stores the last current and next slot number.
|
||||||
|
L2_RCD frame; ///< stores the last current and next link layer frame type.
|
||||||
|
L2_RCD tor; ///< stores the last current and next link layer tx/rx state.
|
||||||
|
L2_NODE_STATE mainState; ///< the main state of link layer state
|
||||||
|
L2_NODE_STATE nextState; ///< next state of link layer state, which will be applied to mainState every second.
|
||||||
|
L2_RTNE_CONFIG rtneConfig; ///< current routine table configuration and status.
|
||||||
|
L2_SCAN_FSM *scanFSM; ///< FSM of scan net (link set up)
|
||||||
|
L2_SVC_FSM *serviceFSM; ///< FSM of service net (data service)
|
||||||
|
uint8_t *sendPktData; ///< send data buffer
|
||||||
|
uint8_t *recvPktData; ///< received data buffer
|
||||||
|
L2_LOG log; ///< Linklayer operating log
|
||||||
|
// for system log
|
||||||
|
SYSINFO sysInfo; ///< system info
|
||||||
|
LINKLOG linkLog; ///< linklayer log for system monitor
|
||||||
|
} L2_INST;
|
||||||
|
|
||||||
|
/************************** Variable Definitions *****************************/
|
||||||
|
extern L2_RTNE_TABLE_ENTRY *initTable[L2_INIT_RTNE_PERIOD];
|
||||||
|
extern L2_RTNE_TABLE_ENTRY *normalTable[L2_NORMAL_RTNE_PERIOD];
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
/**
|
||||||
|
* @defgroup LinkLayer_Main
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
int32_t Linklayer_Init(L2_INST **instPtr, const L2_CONFIG *config);
|
||||||
|
int32_t Linklayer_Reconfig(L2_INST *instPtr, const L2_CONFIG *config);
|
||||||
|
void Linklayer_Destroy(L2_INST *instPtr);
|
||||||
|
int32_t Linklayer_Start(L2_INST *instPtr);
|
||||||
|
int32_t Linklayer_Halt(L2_INST *instPtr);
|
||||||
|
int32_t Linklayer_Proc(L2_INST *instPtr);
|
||||||
|
int32_t Linklayer_EventHandler(L2_INST *instPtr, const L2_EVENT *l2Event);
|
||||||
|
int32_t Linklayer_PktHandler(L2_INST *instPtr, L2_FRAME_TYPE frameType);
|
||||||
|
int32_t L2_SteerBeam2Node(L2_INST *instPtr, uint8_t nodeId);
|
||||||
|
int32_t L2_SetupNextSlot(L2_INST *instPtr, L2_TOR_TYPE txrxMode, L2_FRAME_TYPE frameType);
|
||||||
|
/** @} LinkLayer_Main*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LinkLayer_Framing
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
void L2_FrameInsertChunk(uint8_t *frame, size_t offset, size_t bytes, const void *chunk);
|
||||||
|
void L2_FrameGetChunk(uint8_t *frame, size_t offset, size_t bytes, void *chunk);
|
||||||
|
int32_t L2_CrcAppend(uint8_t *dataBuff, uint32_t dataLen, uint32_t crcPos, L2_CRC_TYPE crcType);
|
||||||
|
bool L2_CrcCheck(uint8_t *dataBuff, uint32_t dataLen, L2_CRC_TYPE crcType);
|
||||||
|
/** @} LinkLayer_Framing*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LinkLayer_Scheduler
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
void L2_EventPoolHandler(L2_INST *instPtr);
|
||||||
|
int32_t L2_ScheduleEventAt(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t frameNo, uint32_t slotNo);
|
||||||
|
int32_t L2_ScheduleEventAfter(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t numSlots);
|
||||||
|
int32_t L2_RescheduleEventAt(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t frameNo, uint32_t slotNo);
|
||||||
|
int32_t L2_RescheduleEventAfter(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t numSlots);
|
||||||
|
/** @} LinkLayer_Scheduler*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LinkLayer_Scan
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
int32_t L2_Scan_Init(L2_SCAN_FSM **scanFSMPtr);
|
||||||
|
void L2_Scan_RefreashScanTable(L2_INST *instPtr);
|
||||||
|
void L2_Scan_Reset(L2_SCAN_FSM *scanFSMPtr);
|
||||||
|
void L2_Scan_Destroy(L2_SCAN_FSM *scanFSMPtr);
|
||||||
|
int32_t L2_Scan_Proc(L2_INST *instPtr);
|
||||||
|
int32_t L2_Scan_PktHandler(L2_INST *instPtr, uint8_t *msg);
|
||||||
|
int32_t L2_Scan_Routine(L2_INST *instPtr, const L2_RTNE_TABLE_ENTRY *schedEntry);
|
||||||
|
/** @} LinkLayer_Scan*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LinkLayer_Service
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
int32_t L2_Service_Init(L2_SVC_FSM **svcFSMPtr);
|
||||||
|
void L2_Service_Reset(L2_SVC_FSM *svcFSMPtr);
|
||||||
|
void L2_Service_Destroy(L2_SVC_FSM *svcFSMPtr);
|
||||||
|
int32_t L2_Service_PktHandler(L2_INST *instPtr, uint8_t *msg);
|
||||||
|
int32_t L2_Service_Proc(L2_INST *instPtr);
|
||||||
|
int32_t L2_Service_Routine(L2_INST *instPtr, const L2_RTNE_TABLE_ENTRY *schedEntry);
|
||||||
|
/** @} LinkLayer_Service*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LinkLayer_TimeSync
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
int32_t L2_GetTimeDeviation(L2_INST *instPtr, uint32_t frameNum, uint32_t slotNum, bool relative, int64_t *timeDev);
|
||||||
|
void L2_TimeAdjust(L2_INST *instPtr, const int64_t *timeDev);
|
||||||
|
/** @} LinkLayer_TimeSync*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LinkLayer_Utility
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
uint8_t L2_GetNodeId(L2_INST *instPtr);
|
||||||
|
uint8_t L2_GetClusterId(L2_INST *instPtr);
|
||||||
|
uint8_t L2_GetHeadId(L2_INST *instPtr);
|
||||||
|
L2_NODE_TYPE L2_GetNodeType(L2_INST *instPtr);
|
||||||
|
L2_NODE_STATE L2_GetMainState(L2_INST *instPtr);
|
||||||
|
bool L2_isStarted(L2_INST *instPtr);
|
||||||
|
bool L2_isDataAvail(L2_INST *instPtr);
|
||||||
|
bool L2_isCxn2Net(L2_INST *instPtr);
|
||||||
|
uint32_t L2_GetFrameLen(L2_FRAME_TYPE l2FrameType);
|
||||||
|
uint32_t L2_GetLastFrameNum(L2_INST *instPtr);
|
||||||
|
uint32_t L2_GetLastSlotNum(L2_INST *instPtr);
|
||||||
|
L2_FRAME_TYPE L2_GetLastFrameType(L2_INST *instPtr);
|
||||||
|
L2_TOR_TYPE L2_GetLastTor(L2_INST *instPtr);
|
||||||
|
uint32_t L2_GetCurrentFrameNum(L2_INST *instPtr);
|
||||||
|
uint32_t L2_GetCurrentSlotNum(L2_INST *instPtr);
|
||||||
|
L2_FRAME_TYPE L2_GetCurrentFrameType(L2_INST *instPtr);
|
||||||
|
L2_TOR_TYPE L2_GetCurrentTor(L2_INST *instPtr);
|
||||||
|
uint32_t L2_GetNextFrameNum(L2_INST *instPtr);
|
||||||
|
uint32_t L2_GetNextSlotNum(L2_INST *instPtr);
|
||||||
|
L2_FRAME_TYPE L2_GetNextFrameType(L2_INST *instPtr);
|
||||||
|
L2_TOR_TYPE L2_GetNextTor(L2_INST *instPtr);
|
||||||
|
L2_FRAME_TYPE L2_GetLastOptFrameType(L2_INST *instPtr);
|
||||||
|
L1_FRAME_TYPE L2_L2frame2L1frame(L2_FRAME_TYPE l2Frame);
|
||||||
|
/** @} LinkLayer_Utility*/
|
||||||
|
|
||||||
|
#endif /* __LINK_LAYER_H_ */
|
||||||
|
|
||||||
|
/** @} LinkLayer*/
|
||||||
@@ -0,0 +1,262 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file link_layer_types.h
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief DF Linklayer types definition.
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* @defgroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LINK_LAYER_DEF_H_
|
||||||
|
#define __LINK_LAYER_DEF_H_
|
||||||
|
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "geometry/coord.h"
|
||||||
|
#include "geometry/quaternion.h"
|
||||||
|
#include "../phy_layer/phy_layer.h"
|
||||||
|
#ifndef EMULATION
|
||||||
|
#include "../config/app_config.h"
|
||||||
|
#endif
|
||||||
|
/************************** Constant Definitions *****************************/
|
||||||
|
/**
|
||||||
|
* @name Linklayer_Common_Constants
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
// Common node ID definition
|
||||||
|
#define L2_BROADCAST_ID 0xFF
|
||||||
|
#define L2_NONE_ID 0
|
||||||
|
|
||||||
|
// Routine configure
|
||||||
|
#define L2_INIT_RTNE_PERIOD 1
|
||||||
|
#define L2_NORMAL_RTNE_PERIOD 1
|
||||||
|
|
||||||
|
// Common slot number definition
|
||||||
|
#define L2_SLOTNO_NONE 0
|
||||||
|
#define L2_FRAMENO_NONE 0
|
||||||
|
|
||||||
|
// Common number of slots definition
|
||||||
|
#define L2_SLOTS_PER_FRAME 100
|
||||||
|
#define L2_SLOTS_PER_SUBFRAME 20
|
||||||
|
|
||||||
|
#define L2_NUM_SLOTS_NONE UINT32_MAX
|
||||||
|
#define L2_NUM_SLOTS_100MS 20
|
||||||
|
#define L2_NUM_SLOTS_20MS 4
|
||||||
|
#define L2_NUM_SLOTS_10MS 2
|
||||||
|
#define L2_NUM_SLOTS_5MS 1
|
||||||
|
#define L2_NUM_SLOTS_SKIP 0
|
||||||
|
/** @} Linklayer_Common_Constants*/
|
||||||
|
|
||||||
|
/**************************** Type Definitions *******************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct L2_RCD
|
||||||
|
* @brief Linklayer recode buffer
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t last;
|
||||||
|
uint32_t curr;
|
||||||
|
uint32_t next;
|
||||||
|
} L2_RCD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum L2_TOR_TYPE
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
L2_TOR_SUSPEND = 0,
|
||||||
|
L2_TOR_TX = 1,
|
||||||
|
L2_TOR_RX = 2
|
||||||
|
} L2_TOR_TYPE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum L2_NODE_TYPE
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
L2_NODE_NONE = 0,
|
||||||
|
L2_NODE_HEAD = 1,
|
||||||
|
L2_NODE_MEMBER = 2,
|
||||||
|
L2_NODE_BACKUP = 3
|
||||||
|
} L2_NODE_TYPE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum L2_NODE_STATE
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
L2_NONE_STATE = 0,
|
||||||
|
L2_INIT_STATE = 1,
|
||||||
|
L2_NORMAL_STATE = 2,
|
||||||
|
L2_INTRA_SEEK_STATE = 3,
|
||||||
|
L2_INTER_SEEK_STATE = 4,
|
||||||
|
L2_SEEK_STATE = 5
|
||||||
|
} L2_NODE_STATE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct L2_NODE_INFO
|
||||||
|
* @brief Node information struct contains the detail node info which needed by the link layer.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t nodeId; ///< node ID
|
||||||
|
uint8_t clustId; ///< node cluster ID
|
||||||
|
uint8_t headId; ///< cluster head ID
|
||||||
|
L2_NODE_TYPE nodeType; ///< node type
|
||||||
|
uint8_t beamNo; ///< beam number to this node
|
||||||
|
COORD pos; ///< node position
|
||||||
|
COORD speed; ///< node speed
|
||||||
|
QUATERNION attitude; ///< node attitude
|
||||||
|
} L2_NODE_INFO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum L2_EVENT_TYPE
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
L2_EV_NONE = 0,
|
||||||
|
L2_EV_SCAN_PROC_DONE = 1,
|
||||||
|
L2_EV_NET_ADV_UPDATE = 2,
|
||||||
|
L2_EV_NET_SETUP_DONE = 3,
|
||||||
|
L2_EV_TIME_SYNC = 4,
|
||||||
|
L2_EV_LOST_CXN = 5,
|
||||||
|
L2_EV_LOST_NODE = 6,
|
||||||
|
L2_EV_SET_FRAME_NUM = 7,
|
||||||
|
L2_EV_SET_SLOT_NUM = 8,
|
||||||
|
L2_EV_MAIN_STATE_UPDATE = 9,
|
||||||
|
L2_ROUTINE_FINISH = 10,
|
||||||
|
L2_ROUTINE_UPDATE = 11
|
||||||
|
} L2_EVENT_TYPE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct L2_EVENT
|
||||||
|
* @brief Linklayer event instance
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
L2_EVENT_TYPE event; ///< event type
|
||||||
|
void *msg; ///< event message (MUST be a heap item)
|
||||||
|
} L2_EVENT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum L2_SLOT_TYPE
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
L2_SLOT_NONE = 0,
|
||||||
|
L2_SLOT_IDLE = 1,
|
||||||
|
L2_SLOT_SCAN = 2,
|
||||||
|
L2_SLOT_ADVERTISE = 3,
|
||||||
|
L2_SLOT_CONFIRM = 4,
|
||||||
|
L2_SLOT_SERVICE = 5,
|
||||||
|
} L2_SLOT_TYPE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum L2_FRAME_TYPE
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
L2_NONE_FRAME = 0,
|
||||||
|
L2_SCAN_FRAME = 1,
|
||||||
|
L2_ADV_FRAME = 2,
|
||||||
|
L2_CFM_FRAME = 3,
|
||||||
|
L2_SVC_FRAME = 4
|
||||||
|
} L2_FRAME_TYPE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum L2_CRC_TYPE
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
L2_CRC_NONE = 0,
|
||||||
|
L2_CRC16_1021 = 1,
|
||||||
|
L2_CRC16_8005 = 2,
|
||||||
|
L2_CRC8_31 = 3
|
||||||
|
} L2_CRC_TYPE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct L2_RTNE_TABLE_ENTRY
|
||||||
|
* @brief Linklayer routine table entry
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
L2_SLOT_TYPE slotType : 8; ///< slot type
|
||||||
|
uint8_t slotSeq; ///< slot sequence number
|
||||||
|
uint8_t src; ///< source node ID
|
||||||
|
uint8_t dst; ///< destination node ID
|
||||||
|
} L2_RTNE_TABLE_ENTRY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum SCAN_STAGE
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
L2_SCAN_NONE_STAGE = 0,
|
||||||
|
L2_SCAN_INIT_STAGE = 1,
|
||||||
|
L2_SCAN_ADV_STAGE = 2,
|
||||||
|
L2_SCAN_CFM_STAGE = 3
|
||||||
|
} SCAN_STAGE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct L2_SCAN_FSM
|
||||||
|
* @brief Linklayer scan process FSM instance
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
bool isLocked; ///< indicates if init acq done(beam locked).
|
||||||
|
bool isAdvRecvd; ///< indicates if advertisement frame done(beam locked).
|
||||||
|
bool isAckPending; ///< indicates if confirm message acked
|
||||||
|
uint8_t scanCnt; ///< scan count
|
||||||
|
uint8_t advTimeout; ///< adv receive try count
|
||||||
|
uint8_t cfmTimeout; ///< cmf receive try count
|
||||||
|
SCAN_STAGE scanStage; ///< scan stage \n
|
||||||
|
/// only for member node
|
||||||
|
uint8_t beamNo; ///< locked beam number
|
||||||
|
uint8_t tableNo; ///< scan table index
|
||||||
|
} L2_SCAN_FSM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct L2_SVC_FSM
|
||||||
|
* @brief Linklayer service process FSM
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t txCnt; ///< tx frame count
|
||||||
|
uint32_t rxCnt; ///< rx frame count
|
||||||
|
uint32_t rxdCnt; ///< received frame count
|
||||||
|
#ifdef DATALINK_ENABLE_BERTEST
|
||||||
|
uint32_t bitTotal; ///< received bits count
|
||||||
|
uint32_t bitError; ///< error bits count
|
||||||
|
double lossRate; ///< packet loss rate
|
||||||
|
double errorRate; ///< bit error rate
|
||||||
|
#endif
|
||||||
|
} L2_SVC_FSM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct L2_RTNE_CONFIG
|
||||||
|
* @brief Linklayer routine table configuration
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
L2_RTNE_TABLE_ENTRY **rtneTable; ///< routine table
|
||||||
|
uint32_t rtnePrd; ///< period of routine table
|
||||||
|
L2_RTNE_TABLE_ENTRY *last; ///< last routine entry
|
||||||
|
L2_RTNE_TABLE_ENTRY *curr; ///< curent routine entry
|
||||||
|
L2_RTNE_TABLE_ENTRY *next; ///< next routine entry
|
||||||
|
} L2_RTNE_CONFIG;
|
||||||
|
|
||||||
|
/************************** Variable Definitions *****************************/
|
||||||
|
|
||||||
|
#endif /* __LINK_LAYER_DEF_H_ */
|
||||||
|
|
||||||
|
/** @} LinkLayer*/
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file msg_def.c
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief DF Linklayer message definition constants.
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name LinkLayer_MSG_Constants
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#ifndef __L2_MSG_DEF_H_
|
||||||
|
#define __L2_MSG_DEF_H_
|
||||||
|
|
||||||
|
#define L2_PACK_LEN_MAX 512 // bytes
|
||||||
|
|
||||||
|
#define L2_ADV_PACK_LEN 28 // bytes
|
||||||
|
#define L2_CMF_PACK_LEN 268 // bytes
|
||||||
|
#define L2_SVC_PACK_LEN 268 // bytes
|
||||||
|
|
||||||
|
// Common structure:
|
||||||
|
// [bytes] [name]
|
||||||
|
// 4 fame number
|
||||||
|
// 1 slot number
|
||||||
|
// 1 source id
|
||||||
|
// 1 destination id
|
||||||
|
// 1 message type
|
||||||
|
#define L2_MSG_FRAME_NUM 0
|
||||||
|
#define L2_MSG_FRAME_NUM_LEN 4
|
||||||
|
#define L2_MSG_SLOT_NUM 4
|
||||||
|
#define L2_MSG_SLOT_NUM_LEN 1
|
||||||
|
#define L2_MSG_SRC_ID 5
|
||||||
|
#define L2_MSG_SRC_ID_LEN 1
|
||||||
|
#define L2_MSG_DST_ID 6
|
||||||
|
#define L2_MSG_DST_ID_LEN 1
|
||||||
|
#define L2_MSG_TYPE 7
|
||||||
|
#define L2_MSG_TYPE_LEN 1
|
||||||
|
#define L2_MSG_PAYLOAD 8
|
||||||
|
|
||||||
|
// advertisement payload structure:
|
||||||
|
// [bytes] [name]
|
||||||
|
// 4 position x
|
||||||
|
// 4 position y
|
||||||
|
// 4 position z
|
||||||
|
// 4 net start time
|
||||||
|
// 2 crc
|
||||||
|
#define L2_MSG_ADV_SRC_POSX 8
|
||||||
|
#define L2_MSG_ADV_SRC_POSX_LEN 4
|
||||||
|
#define L2_MSG_ADV_SRC_POSY 12
|
||||||
|
#define L2_MSG_ADV_SRC_POSY_LEN 4
|
||||||
|
#define L2_MSG_ADV_SRC_POSZ 16
|
||||||
|
#define L2_MSG_ADV_SRC_POSZ_LEN 4
|
||||||
|
#define L2_MSG_ADV_SRC_NETSTART_TIME 20
|
||||||
|
#define L2_MSG_ADV_SRC_NETSTART_TIME_LEN 4
|
||||||
|
#define L2_MSG_ADV_SVC_CRC 26
|
||||||
|
#define L2_MSG_ADV_SVC_CRC_LEN 2
|
||||||
|
|
||||||
|
// confirm payload structure:
|
||||||
|
// [bytes] [name]
|
||||||
|
// 4 position x
|
||||||
|
// 4 position y
|
||||||
|
// 4 position z
|
||||||
|
// 4 speed x
|
||||||
|
// 4 speed y
|
||||||
|
// 4 speed z
|
||||||
|
// 2 crc
|
||||||
|
#define L2_MSG_CFM_SRC_POSX 8
|
||||||
|
#define L2_MSG_CFM_SRC_POSX_LEN 4
|
||||||
|
#define L2_MSG_CFM_SRC_POSY 12
|
||||||
|
#define L2_MSG_CFM_SRC_POSY_LEN 4
|
||||||
|
#define L2_MSG_CFM_SRC_POSZ 16
|
||||||
|
#define L2_MSG_CFM_SRC_POSZ_LEN 4
|
||||||
|
#define L2_MSG_CFM_SRC_SPEEDX 20
|
||||||
|
#define L2_MSG_CFM_SRC_SPEEDX_LEN 4
|
||||||
|
#define L2_MSG_CFM_SRC_SPEEDY 24
|
||||||
|
#define L2_MSG_CFM_SRC_SPEEDY_LEN 4
|
||||||
|
#define L2_MSG_CFM_SRC_SPEEDZ 28
|
||||||
|
#define L2_MSG_CFM_SRC_SPEEDZ_LEN 4
|
||||||
|
#define L2_MSG_CFM_PAYLOAD_ID 32
|
||||||
|
#define L2_MSG_CFM_PAYLOAD_ID_LEN 4
|
||||||
|
#define L2_MSG_CFM_PAYLOAD 36
|
||||||
|
#define L2_MSG_CFM_PAYLOAD_LEN 230
|
||||||
|
#define L2_MSG_CFM_CRC 266
|
||||||
|
#define L2_MSG_CFM_CRC_LEN 2
|
||||||
|
|
||||||
|
// service payload structure:
|
||||||
|
// [bytes] [name]
|
||||||
|
// 4 position x
|
||||||
|
// 4 position y
|
||||||
|
// 4 position z
|
||||||
|
// 4 speed x
|
||||||
|
// 4 speed y
|
||||||
|
// 4 speed z
|
||||||
|
// 234 payload
|
||||||
|
// 2 crc
|
||||||
|
#define L2_MSG_SVC_SRC_POSX 8
|
||||||
|
#define L2_MSG_SVC_SRC_POSX_LEN 4
|
||||||
|
#define L2_MSG_SVC_SRC_POSY 12
|
||||||
|
#define L2_MSG_SVC_SRC_POSY_LEN 4
|
||||||
|
#define L2_MSG_SVC_SRC_POSZ 16
|
||||||
|
#define L2_MSG_SVC_SRC_POSZ_LEN 4
|
||||||
|
#define L2_MSG_SVC_SRC_SPEEDX 20
|
||||||
|
#define L2_MSG_SVC_SRC_SPEEDX_LEN 4
|
||||||
|
#define L2_MSG_SVC_SRC_SPEEDY 24
|
||||||
|
#define L2_MSG_SVC_SRC_SPEEDY_LEN 4
|
||||||
|
#define L2_MSG_SVC_SRC_SPEEDZ 28
|
||||||
|
#define L2_MSG_SVC_SRC_SPEEDZ_LEN 4
|
||||||
|
#define L2_MSG_SVC_PAYLOAD_ID 32
|
||||||
|
#define L2_MSG_SVC_PAYLOAD_ID_LEN 4
|
||||||
|
#define L2_MSG_SVC_PAYLOAD 36
|
||||||
|
#define L2_MSG_SVC_PAYLOAD_LEN 230
|
||||||
|
#define L2_MSG_SVC_CRC 266
|
||||||
|
#define L2_MSG_SVC_CRC_LEN 2
|
||||||
|
|
||||||
|
#endif //__L2_MSG_DEF_H_
|
||||||
|
|
||||||
|
/** @} LinkLayer_MSG_Constants*/
|
||||||
|
|
||||||
|
/** @} LinkLayer*/
|
||||||
@@ -0,0 +1,561 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file node_list.c
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief DF Linklayer node list implementation file
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer_NodeList
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "link_layer_types.h"
|
||||||
|
#include "node_list.h"
|
||||||
|
#include "clist.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
/***************** Macros (Inline Functions) Definitions *********************/
|
||||||
|
/**
|
||||||
|
* @brief Get the node list length
|
||||||
|
* @param list pointer to node list
|
||||||
|
*/
|
||||||
|
inline uint32_t L2_GetNodeListLen(NODE_LIST *list)
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
return list->len;
|
||||||
|
}
|
||||||
|
/**************************** Type Definitions *******************************/
|
||||||
|
|
||||||
|
/************************** Variable Definitions *****************************/
|
||||||
|
static NODE_ENTRY util_entry = { 0 };
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
/**
|
||||||
|
* @brief helper function to free node entry.
|
||||||
|
*/
|
||||||
|
static void entry_free(void *val)
|
||||||
|
{
|
||||||
|
free(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief helper function to match node entries by nodeIds
|
||||||
|
*/
|
||||||
|
static int8_t entry_compare(void *a, void *b)
|
||||||
|
{
|
||||||
|
ASSERT(a != NULL);
|
||||||
|
ASSERT(b != NULL);
|
||||||
|
register uint8_t idA, idB;
|
||||||
|
idA = ((NODE_ENTRY *)a)->nodeInfo.nodeId;
|
||||||
|
idB = ((NODE_ENTRY *)b)->nodeInfo.nodeId;
|
||||||
|
if (idA == idB)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (idA < idB)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Initialize node list
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
*
|
||||||
|
* @return SUCCESS
|
||||||
|
* ENOMEM - not enough memory.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_NodeList_Init(NODE_LIST **list)
|
||||||
|
{
|
||||||
|
(*list) = clist_new();
|
||||||
|
if (*list == NULL)
|
||||||
|
{
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
(*list)->free = entry_free;
|
||||||
|
(*list)->compare = entry_compare;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Clear all nodes in the node list, free allocated memory.
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @return NONE
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void L2_NodeList_Clear(NODE_LIST *list)
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
clist_clear(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Completely destroy node list.
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
*
|
||||||
|
* @return NONE
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void L2_NodeList_Destroy(NODE_LIST *list)
|
||||||
|
{
|
||||||
|
clist_destroy(list);
|
||||||
|
}
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Get node entry from node list base on node id.
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param nodeId
|
||||||
|
*
|
||||||
|
* @return Node entry \n
|
||||||
|
* NULL if node dose not exist.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
NODE_ENTRY *L2_GetNodeById(NODE_LIST *list, uint8_t nodeId)
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
if (nodeId == L2_BROADCAST_ID || nodeId == L2_NONE_ID)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
util_entry.nodeInfo.nodeId = nodeId;
|
||||||
|
clist_node_t *node = clist_find(list, &util_entry);
|
||||||
|
if (node == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ((NODE_ENTRY *)node->val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Append a new node entry to the node list
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param nodeId
|
||||||
|
* @param nodeType
|
||||||
|
*
|
||||||
|
* @return SUCCESS Node was added successfully.\n
|
||||||
|
* Other Error occurred.(Node already exist, memory alloc error ect.)
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
NODE_ENTRY *L2_AppendNode(NODE_LIST *list, uint8_t nodeId, L2_NODE_TYPE nodeType)
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
if (L2_isNodeInList(list, nodeId))
|
||||||
|
{
|
||||||
|
DBG_WARNING("Node [%" PRIu8 "] already exist.\n", nodeId);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
DBG_INFO("Link layer appending node [%" PRIu8 "] to node list.\n", nodeId);
|
||||||
|
NODE_ENTRY *nodeEntry = (NODE_ENTRY *)malloc(sizeof(NODE_ENTRY));
|
||||||
|
if (nodeEntry == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to allocated memory for nodeEntry.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
clist_node_t *node = clist_node_new(nodeEntry);
|
||||||
|
if (node == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to allocated memory for list node.\n");
|
||||||
|
free(nodeEntry);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
nodeEntry->nodeInfo.nodeId = nodeId;
|
||||||
|
nodeEntry->nodeInfo.nodeType = (uint8_t)nodeType;
|
||||||
|
nodeEntry->nodeInfo.pos.x = 0;
|
||||||
|
nodeEntry->nodeInfo.pos.y = 0;
|
||||||
|
nodeEntry->nodeInfo.pos.z = 0;
|
||||||
|
nodeEntry->nodeInfo.speed.x = 0;
|
||||||
|
nodeEntry->nodeInfo.speed.y = 0;
|
||||||
|
nodeEntry->nodeInfo.speed.z = 0;
|
||||||
|
nodeEntry->nodeInfo.beamNo = 0;
|
||||||
|
nodeEntry->ttlCnt = 0;
|
||||||
|
clist_rpush(list, node);
|
||||||
|
return nodeEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Delete a node in list based on node id.
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param nodeId
|
||||||
|
*
|
||||||
|
* @return SUCCESS Node has been successfully deleted.\n
|
||||||
|
* Other Node not exist.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_DeleteNodeById(NODE_LIST *list, uint8_t nodeId)
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
util_entry.nodeInfo.nodeId = nodeId;
|
||||||
|
clist_node_t *node = clist_find(list, &util_entry);
|
||||||
|
if (node == NULL)
|
||||||
|
{
|
||||||
|
DBG_WARNING("Node [%" PRIu8 "] in not in node list, skip deleting process.\n", nodeId);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
DBG_INFO("Deleting node [%" PRIu8 "].\n", nodeId);
|
||||||
|
clist_remove(list, node);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Check whether the node is already in the node list.
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param nodeId
|
||||||
|
*
|
||||||
|
* @return true node in the list\n
|
||||||
|
* false node not in the list
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
bool L2_isNodeInList(NODE_LIST *list, uint8_t nodeId)
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
return (L2_GetNodeById(list, nodeId) != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Get the distance between me and the node.
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param nodeId
|
||||||
|
* @param dst A pointer to store distance.
|
||||||
|
*
|
||||||
|
* @return SUCCESS distance has been successfully store in dst\n
|
||||||
|
* FAILURE Node dose not exit.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
int32_t L2_GetDistance(NODE_LIST *list, COORD myCoord, uint8_t nodeId, double *dst)
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||||
|
if (nodeEntry == NULL)
|
||||||
|
{
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*dst = Coord_Distance(myCoord, nodeEntry->nodeInfo.pos);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Update node positions information.
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param nodeId
|
||||||
|
* @param newPos A structure stores the corresponding node position info.
|
||||||
|
*
|
||||||
|
* @return SUCCESS update successfully.\n
|
||||||
|
* FAILURE node not exist.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_UpdateNodePos(NODE_LIST *list, uint8_t nodeId, const COORD *newPos)
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||||
|
if (nodeEntry == NULL)
|
||||||
|
{
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(&(nodeEntry->nodeInfo.pos), newPos, sizeof(COORD));
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Get node positions information.
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param nodeId
|
||||||
|
* @param newPos A structure stores the corresponding node position info.
|
||||||
|
*
|
||||||
|
* @return SUCCESS update successfully.\n
|
||||||
|
* FAILURE node not exist.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_GetNodePos(NODE_LIST *list, uint8_t nodeId, COORD *pos)
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||||
|
if (nodeEntry == NULL)
|
||||||
|
{
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(pos, &(nodeEntry->nodeInfo.pos), sizeof(COORD));
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Update node speed information.
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param nodeId
|
||||||
|
* @param newSpeed A structure stores the corresponding node speed info.
|
||||||
|
*
|
||||||
|
* @return SUCCESS update successfully.\n
|
||||||
|
* FAILURE node not exist.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_UpdateNodeSpeed(NODE_LIST *list, uint8_t nodeId, const COORD *newSpeed)
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||||
|
if (nodeEntry == NULL)
|
||||||
|
{
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(&(nodeEntry->nodeInfo.speed), newSpeed, sizeof(COORD));
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Get node speed information.
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param nodeId
|
||||||
|
* @param newSpeed A structure stores the corresponding node speed info.
|
||||||
|
*
|
||||||
|
* @return SUCCESS update successfully.\n
|
||||||
|
* FAILURE node not exist.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_GetNodeSpeed(NODE_LIST *list, uint8_t nodeId, COORD *speed)
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||||
|
if (nodeEntry == NULL)
|
||||||
|
{
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(speed, &(nodeEntry->nodeInfo.speed), sizeof(COORD));
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Update node ACK status.
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param nodeId
|
||||||
|
* @param devi
|
||||||
|
*
|
||||||
|
* @return SUCCESS update successfully.\n
|
||||||
|
* FAILURE Node not exist.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_UpdateNodeTimeDeviation(NODE_LIST *list, uint8_t nodeId, int32_t devi)
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||||
|
if (nodeEntry == NULL)
|
||||||
|
{
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nodeEntry->timeDevi = devi;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Increase TTL of specified node in the list.
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param inc cnt of slot to add
|
||||||
|
* @param nodeId
|
||||||
|
*
|
||||||
|
* @return NONE
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_IncNodeTTL(NODE_LIST *list, uint8_t nodeId, uint32_t inc)
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||||
|
if (nodeEntry == NULL)
|
||||||
|
{
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nodeEntry->ttlCnt += inc;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Reset node TTL based on node id.
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param nodeId
|
||||||
|
*
|
||||||
|
* @return SUCCESS TTL has been successfully cleared.\n
|
||||||
|
* FAILURE Node not exist.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_RstNodeTTL(NODE_LIST *list, uint8_t nodeId)
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||||
|
if (nodeEntry == NULL)
|
||||||
|
{
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nodeEntry->ttlCnt = 0;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Get TTL of specified node in the list.
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param nodeId
|
||||||
|
* @param ttl
|
||||||
|
*
|
||||||
|
* @return NONE
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_GetNodeTTL(NODE_LIST *list, uint8_t nodeId, uint32_t *ttl)
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
|
||||||
|
if (nodeEntry == NULL)
|
||||||
|
{
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*ttl = nodeEntry->ttlCnt;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Implements a edit operations to each node.
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param param
|
||||||
|
* @param operation A pointer to a function handled "NODE_ENTRY*" as input
|
||||||
|
* which defines the operations need to be apply.
|
||||||
|
*
|
||||||
|
* @return SUCCESS Operations has been applied successfully to all nodes.\n
|
||||||
|
* Other Error occurred.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_IterEditNode(NODE_LIST *list, const void *param, int32_t (*operation)(NODE_ENTRY *, const void *))
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
int32_t Status;
|
||||||
|
clist_node_t *node;
|
||||||
|
clist_iterator_t *iter = clist_iterator_new(list, LIST_HEAD);
|
||||||
|
if (iter == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to initialize list iteration process.\n");
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
while ((node = clist_iterator_next(iter)))
|
||||||
|
{
|
||||||
|
Status = operation((NODE_ENTRY *)node->val, param);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Error occurred when iteratively edit node entry.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clist_iterator_destroy(iter);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Filter all node, delete all the node not satisfied the condition.
|
||||||
|
*
|
||||||
|
* @param list
|
||||||
|
* @param condition A pointer to a function handled "NODE_ENTRY*" as input
|
||||||
|
* which defines the condition need to be verify.
|
||||||
|
*
|
||||||
|
* @return SUCCESS
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_IterDeleteNode(NODE_LIST *list, bool (*condition)(NODE_ENTRY *))
|
||||||
|
{
|
||||||
|
ASSERT(list != NULL);
|
||||||
|
clist_node_t *node;
|
||||||
|
clist_iterator_t *iter = clist_iterator_new(list, LIST_HEAD);
|
||||||
|
if (iter == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to initialize list iteration process.\n");
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
while ((node = clist_iterator_next(iter)))
|
||||||
|
{
|
||||||
|
if (condition((NODE_ENTRY *)node->val) == false)
|
||||||
|
{
|
||||||
|
clist_remove(list, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clist_iterator_destroy(iter);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} LinkLayer_NodeList*/
|
||||||
|
|
||||||
|
/** @} LinkLayer*/
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file node_list.h
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief DF Linklayer node list header file
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LinkLayer_NodeList
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#ifndef NODE_LIST_H_
|
||||||
|
#define NODE_LIST_H_
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "link_layer_types.h"
|
||||||
|
#include "geometry/coord.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "clist.h"
|
||||||
|
|
||||||
|
/************************** Constant Definitions *****************************/
|
||||||
|
/***************** Macros (Inline Functions) Definitions *********************/
|
||||||
|
/**************************** Type Definitions *******************************/
|
||||||
|
/**
|
||||||
|
* @struct NODE_ENTRY
|
||||||
|
* @brief Linklayer discovered node list node entry
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
L2_NODE_INFO nodeInfo;
|
||||||
|
uint32_t ttlCnt;
|
||||||
|
int32_t timeDevi;
|
||||||
|
} NODE_ENTRY;
|
||||||
|
|
||||||
|
typedef clist_t NODE_LIST;
|
||||||
|
|
||||||
|
/************************** Variable Definitions *****************************/
|
||||||
|
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
int32_t L2_NodeList_Init(NODE_LIST **list);
|
||||||
|
void L2_NodeList_Clear(NODE_LIST *list);
|
||||||
|
void L2_NodeList_Destroy(NODE_LIST *list);
|
||||||
|
uint32_t L2_GetNodeListLen(NODE_LIST *list);
|
||||||
|
NODE_ENTRY *L2_GetNodeById(NODE_LIST *list, uint8_t nodeId);
|
||||||
|
NODE_ENTRY *L2_AppendNode(NODE_LIST *list, uint8_t nodeId, L2_NODE_TYPE nodeType);
|
||||||
|
int32_t L2_DeleteNodeById(NODE_LIST *list, uint8_t nodeId);
|
||||||
|
int32_t L2_UpdateNodePos(NODE_LIST *list, uint8_t nodeId, const COORD *newPos);
|
||||||
|
bool L2_isNodeInList(NODE_LIST *list, uint8_t nodeId);
|
||||||
|
int32_t L2_GetNodePos(NODE_LIST *list, uint8_t nodeId, COORD *newPos);
|
||||||
|
int32_t L2_UpdateNodeSpeed(NODE_LIST *list, uint8_t nodeId, const COORD *newSpeed);
|
||||||
|
int32_t L2_GetNodeSpeed(NODE_LIST *list, uint8_t nodeId, COORD *speed);
|
||||||
|
int32_t L2_UpdateNodeTimeDeviation(NODE_LIST *list, uint8_t nodeId, int32_t devi);
|
||||||
|
int32_t L2_GetDistance(NODE_LIST *list, COORD myCoord, uint8_t nodeId, double *dst);
|
||||||
|
int32_t L2_RstNodeTTL(NODE_LIST *list, uint8_t nodeId);
|
||||||
|
int32_t L2_IncNodeTTL(NODE_LIST *list, uint8_t nodeId, uint32_t inc);
|
||||||
|
int32_t L2_GetNodeTTL(NODE_LIST *list, uint8_t nodeId, uint32_t *ttl);
|
||||||
|
int32_t L2_IterEditNode(NODE_LIST *list, const void *param, int32_t (*operation)(NODE_ENTRY *, const void *));
|
||||||
|
int32_t L2_IterDeleteNode(NODE_LIST *list, bool (*condition)(NODE_ENTRY *));
|
||||||
|
|
||||||
|
#endif /* NODE_LIST_H_ */
|
||||||
|
|
||||||
|
/** @} LinkLayer_NodeList*/
|
||||||
|
/** @} LinkLayer*/
|
||||||
@@ -0,0 +1,263 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file routine_table.c
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief DF Linklayer node list implementation file
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name RoutineTable
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "link_layer.h"
|
||||||
|
#include "link_layer_types.h"
|
||||||
|
|
||||||
|
L2_RTNE_TABLE_ENTRY intraScanSubT[L2_SLOTS_PER_FRAME] = {
|
||||||
|
// SubFrame 0
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
|
||||||
|
// SubFrame 1
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
|
||||||
|
// SubFrame 2
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
|
||||||
|
// SubFrame 3
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_ADVERTISE, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_ADVERTISE, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_ADVERTISE, 0x02, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_ADVERTISE, 0x03, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
|
||||||
|
// SubFrame 4
|
||||||
|
{L2_SLOT_CONFIRM, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_CONFIRM, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_CONFIRM, 0x02, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_CONFIRM, 0x03, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_CONFIRM, 0x00, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_CONFIRM, 0x01, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_CONFIRM, 0x02, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_CONFIRM, 0x03, 0x01, 0xFF},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_CONFIRM, 0x00, 0xFF, 0x01},
|
||||||
|
{L2_SLOT_CONFIRM, 0x01, 0xFF, 0x01},
|
||||||
|
{L2_SLOT_CONFIRM, 0x02, 0xFF, 0x01},
|
||||||
|
{L2_SLOT_CONFIRM, 0x03, 0xFF, 0x01},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_CONFIRM, 0x00, 0xFF, 0x01},
|
||||||
|
{L2_SLOT_CONFIRM, 0x01, 0xFF, 0x01},
|
||||||
|
{L2_SLOT_CONFIRM, 0x02, 0xFF, 0x01},
|
||||||
|
{L2_SLOT_CONFIRM, 0x03, 0xFF, 0x01},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
};
|
||||||
|
|
||||||
|
L2_RTNE_TABLE_ENTRY normalSub[L2_SLOTS_PER_FRAME] = {
|
||||||
|
// SubFrame 0
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
|
||||||
|
// SubFrame 1
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
|
||||||
|
// SubFrame 2
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
|
||||||
|
// SubFrame 3
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
|
||||||
|
// SubFrame 4
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
|
||||||
|
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
|
||||||
|
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
|
||||||
|
};
|
||||||
|
|
||||||
|
L2_RTNE_TABLE_ENTRY *initTable[L2_INIT_RTNE_PERIOD] =
|
||||||
|
{
|
||||||
|
intraScanSubT
|
||||||
|
};
|
||||||
|
|
||||||
|
L2_RTNE_TABLE_ENTRY *normalTable[L2_NORMAL_RTNE_PERIOD] =
|
||||||
|
{
|
||||||
|
normalSub
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @} RoutineTable*/
|
||||||
|
/** @} LinkLayer*/
|
||||||
@@ -0,0 +1,909 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file scan.c
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief DF Linklayer scan implementation file.
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer_Scan
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#include <string.h>
|
||||||
|
#include "link_layer.h"
|
||||||
|
#include "link_layer_types.h"
|
||||||
|
#include "msg_def.h"
|
||||||
|
#include "node_list.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "../phy_layer/phy_layer.h"
|
||||||
|
|
||||||
|
/************************** Constant Definitions *****************************/
|
||||||
|
#define ADV_LISTEN_TIMEOUT 40
|
||||||
|
#define CFM_LISTEN_TIMEOUT 5
|
||||||
|
#define ADV_FRAME_SLOTS 4
|
||||||
|
#define CFM_FRAME_SLOTS 5
|
||||||
|
/***************** Macros (In-line Functions) Definitions *********************/
|
||||||
|
|
||||||
|
/**************************** Type Definitions *******************************/
|
||||||
|
|
||||||
|
/************************** Variable Definitions *****************************/
|
||||||
|
// Pair by regex
|
||||||
|
// Regex: ((\{\.oaxis = [0-9]+[ ,]+\.raxis = [0-9]+[ ]*\}, ){2})
|
||||||
|
PHY_ANT_ANGLE antNrrwPattern_0[L1_NUM_ANT_NRRW_PATTERN] =
|
||||||
|
{
|
||||||
|
{.oaxis = 0 , .raxis = 0 },
|
||||||
|
{.oaxis = 139, .raxis = 2225},
|
||||||
|
{.oaxis = 152, .raxis = 850 },
|
||||||
|
{.oaxis = 138, .raxis = 3155},
|
||||||
|
{.oaxis = 159, .raxis = 1680},
|
||||||
|
{.oaxis = 168, .raxis = 285 },
|
||||||
|
{.oaxis = 195, .raxis = 2630},
|
||||||
|
{.oaxis = 211, .raxis = 1204},
|
||||||
|
{.oaxis = 225, .raxis = 3429},
|
||||||
|
{.oaxis = 249, .raxis = 2022},
|
||||||
|
{.oaxis = 272, .raxis = 629 },
|
||||||
|
{.oaxis = 265, .raxis = 2934},
|
||||||
|
{.oaxis = 277, .raxis = 1499},
|
||||||
|
{.oaxis = 289, .raxis = 124 },
|
||||||
|
{.oaxis = 300, .raxis = 2349},
|
||||||
|
{.oaxis = 311, .raxis = 959 },
|
||||||
|
{.oaxis = 321, .raxis = 3199},
|
||||||
|
{.oaxis = 331, .raxis = 1824},
|
||||||
|
{.oaxis = 341, .raxis = 389 },
|
||||||
|
{.oaxis = 351, .raxis = 2674},
|
||||||
|
{.oaxis = 360, .raxis = 1268},
|
||||||
|
{.oaxis = 364, .raxis = 3483},
|
||||||
|
{.oaxis = 378, .raxis = 2118},
|
||||||
|
{.oaxis = 387, .raxis = 733 },
|
||||||
|
{.oaxis = 416, .raxis = 3028},
|
||||||
|
{.oaxis = 404, .raxis = 1623},
|
||||||
|
{.oaxis = 433, .raxis = 248 },
|
||||||
|
{.oaxis = 421, .raxis = 2473},
|
||||||
|
{.oaxis = 429, .raxis = 1098},
|
||||||
|
{.oaxis = 437, .raxis = 3303},
|
||||||
|
{.oaxis = 445, .raxis = 1948},
|
||||||
|
{.oaxis = 443, .raxis = 543 },
|
||||||
|
{.oaxis = 450, .raxis = 2828},
|
||||||
|
{.oaxis = 448, .raxis = 1422},
|
||||||
|
{.oaxis = 455, .raxis = 47 },
|
||||||
|
{.oaxis = 453, .raxis = 2272},
|
||||||
|
{.oaxis = 450, .raxis = 897 }
|
||||||
|
};
|
||||||
|
|
||||||
|
PHY_ANT_ANGLE antNrrwPattern_1[L1_NUM_ANT_NRRW_PATTERN] =
|
||||||
|
{
|
||||||
|
{.oaxis = 0 , .raxis = 0 },
|
||||||
|
{.oaxis = 139, .raxis = 1155},
|
||||||
|
{.oaxis = 152, .raxis = 3380},
|
||||||
|
{.oaxis = 138, .raxis = 2085},
|
||||||
|
{.oaxis = 159, .raxis = 610 },
|
||||||
|
{.oaxis = 168, .raxis = 2815},
|
||||||
|
{.oaxis = 195, .raxis = 1560},
|
||||||
|
{.oaxis = 211, .raxis = 134 },
|
||||||
|
{.oaxis = 225, .raxis = 2359},
|
||||||
|
{.oaxis = 249, .raxis = 952 },
|
||||||
|
{.oaxis = 272, .raxis = 3159},
|
||||||
|
{.oaxis = 265, .raxis = 1864},
|
||||||
|
{.oaxis = 277, .raxis = 429 },
|
||||||
|
{.oaxis = 289, .raxis = 2654},
|
||||||
|
{.oaxis = 300, .raxis = 1279},
|
||||||
|
{.oaxis = 311, .raxis = 3489},
|
||||||
|
{.oaxis = 321, .raxis = 2129},
|
||||||
|
{.oaxis = 331, .raxis = 754 },
|
||||||
|
{.oaxis = 341, .raxis = 2919},
|
||||||
|
{.oaxis = 351, .raxis = 1604},
|
||||||
|
{.oaxis = 360, .raxis = 198 },
|
||||||
|
{.oaxis = 364, .raxis = 2413},
|
||||||
|
{.oaxis = 378, .raxis = 1048},
|
||||||
|
{.oaxis = 387, .raxis = 3263},
|
||||||
|
{.oaxis = 416, .raxis = 1958},
|
||||||
|
{.oaxis = 404, .raxis = 553 },
|
||||||
|
{.oaxis = 433, .raxis = 2778},
|
||||||
|
{.oaxis = 421, .raxis = 1403},
|
||||||
|
{.oaxis = 429, .raxis = 28 },
|
||||||
|
{.oaxis = 437, .raxis = 2233},
|
||||||
|
{.oaxis = 445, .raxis = 878 },
|
||||||
|
{.oaxis = 443, .raxis = 3073},
|
||||||
|
{.oaxis = 450, .raxis = 1758},
|
||||||
|
{.oaxis = 448, .raxis = 352 },
|
||||||
|
{.oaxis = 455, .raxis = 2577},
|
||||||
|
{.oaxis = 453, .raxis = 1202},
|
||||||
|
{.oaxis = 450, .raxis = 3427},
|
||||||
|
};
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
static void LockStateUpdate(L2_SCAN_FSM *scanFsmPtr, bool state);
|
||||||
|
static void AdvRecvStateUpdate(L2_SCAN_FSM *scanFsmPtr, bool state);
|
||||||
|
static void StageUpdate(L2_SCAN_FSM *scanFsmPtr, SCAN_STAGE newStage);
|
||||||
|
static void PendCfmAck(L2_SCAN_FSM *scanFsmPtr);
|
||||||
|
|
||||||
|
static int32_t Scan_InitScanHandler(L2_INST *instPtr);
|
||||||
|
static int32_t Scan_AdvHandler(L2_INST *instPtr);
|
||||||
|
static int32_t Scan_CfmHandler(L2_INST *instPtr);
|
||||||
|
|
||||||
|
static int32_t ScanMsg_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dstId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update Init-Scan lock state.
|
||||||
|
*/
|
||||||
|
static inline void LockStateUpdate(L2_SCAN_FSM *scanFsmPtr, bool state)
|
||||||
|
{
|
||||||
|
ASSERT(scanFsmPtr != NULL);
|
||||||
|
DBG_INFO("Update BeamLockState from [%" PRId8 "] to [%" PRId8 "].\n",
|
||||||
|
scanFsmPtr->isLocked, state);
|
||||||
|
scanFsmPtr->isLocked = state;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update Base-info Advertisement state.
|
||||||
|
*/
|
||||||
|
static void AdvRecvStateUpdate(L2_SCAN_FSM *scanFsmPtr, bool state)
|
||||||
|
{
|
||||||
|
ASSERT(scanFsmPtr != NULL);
|
||||||
|
DBG_INFO("Update AdvRecvState from [%" PRId8 "] to [%" PRId8 "].\n",
|
||||||
|
scanFsmPtr->isAdvRecvd, state);
|
||||||
|
scanFsmPtr->isAdvRecvd = state;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update 2-Way Acquisition ack state.
|
||||||
|
*/
|
||||||
|
static void PendCfmAck(L2_SCAN_FSM *scanFsmPtr)
|
||||||
|
{
|
||||||
|
ASSERT(scanFsmPtr != NULL);
|
||||||
|
DBG_INFO("Pending Cfm-Ack...\n");
|
||||||
|
scanFsmPtr->isAckPending = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Update current Scan-Net stage
|
||||||
|
*
|
||||||
|
* @param scanFsmPtr A pointer to scan net fsm.
|
||||||
|
* newStage New state.
|
||||||
|
*
|
||||||
|
* @return NONE.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
static void StageUpdate(L2_SCAN_FSM *scanFsmPtr, SCAN_STAGE newStage)
|
||||||
|
{
|
||||||
|
ASSERT((newStage >= L2_SCAN_NONE_STAGE) && (newStage <= L2_SCAN_CFM_STAGE));
|
||||||
|
DBG_INFO("ScanNet current stage: %" PRIu8 " -> ScanNet new stage: %" PRIu8 " \n",
|
||||||
|
scanFsmPtr->scanStage, newStage);
|
||||||
|
scanFsmPtr->scanStage = newStage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Member node scan net InitScan stage handler.
|
||||||
|
*
|
||||||
|
* @param instPtr A pointer to l2 instance
|
||||||
|
*
|
||||||
|
* @return used slot (5ms slot).
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
static int32_t Scan_InitScanHandler(L2_INST *instPtr)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
||||||
|
L2_SCAN_FSM *scanFsmPtr = instPtr->scanFSM;
|
||||||
|
DBG_INFO("** Net-Setup - InitScan Procedure (Attempts: %" PRIu8 ")**\n", scanFsmPtr->scanCnt);
|
||||||
|
|
||||||
|
if (scanFsmPtr->scanCnt == 0)
|
||||||
|
{
|
||||||
|
// Update scan beam table
|
||||||
|
L2_Scan_RefreashScanTable(instPtr);
|
||||||
|
}
|
||||||
|
else if (Phy_IsFrameDetected(phyRef))
|
||||||
|
{
|
||||||
|
// last scan beam number
|
||||||
|
scanFsmPtr->beamNo = Phy_LastScanBeamNo(phyRef);
|
||||||
|
// Update scan beam table
|
||||||
|
L2_Scan_RefreashScanTable(instPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scanFsmPtr->isLocked == true)
|
||||||
|
{
|
||||||
|
scanFsmPtr->beamNo = Phy_LastScanBeamNo(phyRef);
|
||||||
|
Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
|
||||||
|
L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_ADV_FRAME);
|
||||||
|
StageUpdate(scanFsmPtr, L2_SCAN_ADV_STAGE);
|
||||||
|
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
|
||||||
|
} /* Otherwise remain L2_SCAN_INIT_STAGE */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Antenna steering (reserved, automatically accomplished by physical layer) */
|
||||||
|
Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
|
||||||
|
L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_SCAN_FRAME);
|
||||||
|
scanFsmPtr->scanCnt++;
|
||||||
|
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Member node scan net BmAdvt stage handler.
|
||||||
|
*
|
||||||
|
* @param scanFsmPtr A pointer to scan net fsm.
|
||||||
|
* mainState A pointer to main node state.
|
||||||
|
*
|
||||||
|
* @return used slot (5ms slot).
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
static int32_t Scan_AdvHandler(L2_INST *instPtr)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
L2_SCAN_FSM *scanFsmPtr = instPtr->scanFSM;
|
||||||
|
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
||||||
|
TMC_INST *tmcRef = instPtr->config.tmcInstPtr;
|
||||||
|
DBG_INFO("** Net-Setup - Advertisement Procedure (Timeout: %" PRIu8 ") **\n", scanFsmPtr->advTimeout);
|
||||||
|
|
||||||
|
// if received a valid bm frame.
|
||||||
|
if (scanFsmPtr->isAdvRecvd == true)
|
||||||
|
{
|
||||||
|
// last scan beam number
|
||||||
|
scanFsmPtr->beamNo = Phy_LastScanBeamNo(phyRef);
|
||||||
|
// reset listen counter.
|
||||||
|
scanFsmPtr->advTimeout = 0;
|
||||||
|
|
||||||
|
// Update scan stage
|
||||||
|
StageUpdate(scanFsmPtr, L2_SCAN_CFM_STAGE);
|
||||||
|
|
||||||
|
// start a confirm frame reception if in the target slot
|
||||||
|
if ((TimeCtrl_GetIntCnt(tmcRef) + 1) % CFM_FRAME_SLOTS == 0)
|
||||||
|
{
|
||||||
|
// using pull mode to receive confirm frame
|
||||||
|
// since first time sync procedure is accomplished in ADV stage.
|
||||||
|
(void)Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_16);
|
||||||
|
(void)Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
|
||||||
|
(void)Phy_SetMode(phyRef, PHY_MODE_PULL);
|
||||||
|
(void)L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_CFM_FRAME);
|
||||||
|
scanFsmPtr->cfmTimeout++; // increase counter.
|
||||||
|
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
|
||||||
|
}
|
||||||
|
// otherwise skip...
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
// no valid bm frame was received.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* if time out reached, go back to init scan stage. */
|
||||||
|
if (scanFsmPtr->advTimeout > ADV_LISTEN_TIMEOUT)
|
||||||
|
{
|
||||||
|
/* Antenna steering (reserved, automatically accomplished by physical layer) */
|
||||||
|
(void)Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
|
||||||
|
(void)L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_SCAN_FRAME);
|
||||||
|
DBG_WARNING("Adv timeout, restart net scan from L2_SCAN_INIT_STAGE.\n");
|
||||||
|
(void)L2_Scan_Reset(scanFsmPtr);
|
||||||
|
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Antenna steering (reserved, automatically accomplished by physical layer) */
|
||||||
|
(void)Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
|
||||||
|
(void)L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_ADV_FRAME);
|
||||||
|
scanFsmPtr->advTimeout++;
|
||||||
|
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Scan net 2Way-Acq stage handler.
|
||||||
|
*
|
||||||
|
* @param instPtr a pointer to linklayer layer instance
|
||||||
|
*
|
||||||
|
* @return used slot (5ms slot).
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
static int32_t Scan_CfmHandler(L2_INST *instPtr)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
L2_SCAN_FSM *scanFsmPtr = instPtr->scanFSM;
|
||||||
|
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
||||||
|
DBG_INFO("** Net-Setup - Confirm Procedure (Timeout: %" PRIu8 ") **\n", scanFsmPtr->cfmTimeout);
|
||||||
|
|
||||||
|
// 2 way acq failed, back to init stage.
|
||||||
|
if (scanFsmPtr->cfmTimeout >= CFM_LISTEN_TIMEOUT)
|
||||||
|
{
|
||||||
|
DBG_WARNING("Cmf timeout, restart net scan from L2_SCAN_INIT_STAGE.\n");
|
||||||
|
L2_Scan_Reset(scanFsmPtr);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
if (L2_GetNextSlotNum(instPtr) % CFM_FRAME_SLOTS == 0)
|
||||||
|
{
|
||||||
|
// using pull mode to receive confirm frame
|
||||||
|
// since first time sync procedure is accomplished in ADV stage.
|
||||||
|
(void)Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_16);
|
||||||
|
(void)Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
|
||||||
|
(void)Phy_SetMode(phyRef, PHY_MODE_PULL);
|
||||||
|
(void)L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_CFM_FRAME);
|
||||||
|
scanFsmPtr->cfmTimeout++; // increase counter.
|
||||||
|
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Packing Scan message to a bit array.
|
||||||
|
*
|
||||||
|
* @param bitarr pointer to bit array buffer.
|
||||||
|
* @param msgType message type.
|
||||||
|
*
|
||||||
|
* @return EPARAM
|
||||||
|
* SUCCESS
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
static int32_t ScanMsg_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dstId)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
int32_t Status;
|
||||||
|
uint32_t dataChunk;
|
||||||
|
uint8_t *buff = instPtr->sendPktData;
|
||||||
|
if ((type < L2_ADV_FRAME) || (type > L2_CFM_FRAME))
|
||||||
|
{
|
||||||
|
DBG_ERROR("Unexpected frame type: %" PRId8 ".\n", type);
|
||||||
|
return EPARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common section of link layer package
|
||||||
|
dataChunk = L2_GetNextFrameNum(instPtr);
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &dataChunk);
|
||||||
|
dataChunk = L2_GetNextSlotNum(instPtr);
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &dataChunk);
|
||||||
|
dataChunk = L2_GetNodeId(instPtr);
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &dataChunk);
|
||||||
|
dataChunk = dstId;
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_DST_ID, L2_MSG_DST_ID_LEN, &dataChunk);
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case L2_ADV_FRAME:
|
||||||
|
{
|
||||||
|
dataChunk = L2_ADV_FRAME;
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &dataChunk);
|
||||||
|
|
||||||
|
SysMonitor_GetSysinfo(&(instPtr->sysInfo));
|
||||||
|
// insert position and speed info
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_ADV_SRC_POSX, L2_MSG_ADV_SRC_POSX_LEN, &(instPtr->sysInfo.posX));
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_ADV_SRC_POSY, L2_MSG_ADV_SRC_POSY_LEN, &(instPtr->sysInfo.posY));
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_ADV_SRC_POSZ, L2_MSG_ADV_SRC_POSZ_LEN, &(instPtr->sysInfo.posZ));
|
||||||
|
|
||||||
|
// Insert net start time
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_ADV_SRC_NETSTART_TIME, L2_MSG_ADV_SRC_NETSTART_TIME_LEN, &(instPtr->netStartTime));
|
||||||
|
|
||||||
|
// Append CRC
|
||||||
|
Status = L2_CrcAppend(buff, L2_ADV_PACK_LEN - L2_MSG_ADV_SVC_CRC_LEN, L2_MSG_ADV_SVC_CRC, L2_CRC16_1021);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Fail to append CRC, error code: %" PRId32 ".\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case L2_CFM_FRAME:
|
||||||
|
{
|
||||||
|
dataChunk = L2_CFM_FRAME;
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &dataChunk);
|
||||||
|
|
||||||
|
SysMonitor_GetSysinfo(&(instPtr->sysInfo));
|
||||||
|
// insert position and speed info
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_POSX, L2_MSG_CFM_SRC_POSX_LEN, &(instPtr->sysInfo.posX));
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_POSY, L2_MSG_CFM_SRC_POSY_LEN, &(instPtr->sysInfo.posY));
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_POSZ, L2_MSG_CFM_SRC_POSZ_LEN, &(instPtr->sysInfo.posZ));
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_SPEEDX, L2_MSG_CFM_SRC_SPEEDX_LEN, &(instPtr->sysInfo.vX));
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_SPEEDY, L2_MSG_CFM_SRC_SPEEDY_LEN, &(instPtr->sysInfo.vY));
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_SPEEDZ, L2_MSG_CFM_SRC_SPEEDZ_LEN, &(instPtr->sysInfo.vZ));
|
||||||
|
|
||||||
|
// Packing extra payload
|
||||||
|
uint32_t dataId;
|
||||||
|
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
|
||||||
|
{
|
||||||
|
SysMonitor_GetSendPayload(buff + L2_MSG_CFM_PAYLOAD, &dataId, PAYLOAD_LEN_FLJ_TX);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SysMonitor_GetSendPayload(buff + L2_MSG_CFM_PAYLOAD, &dataId, PAYLOAD_LEN_LJ_TX);
|
||||||
|
}
|
||||||
|
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_CFM_PAYLOAD_ID, L2_MSG_CFM_PAYLOAD_ID_LEN, &dataId);
|
||||||
|
if (dataId == DATA_ID_NONE)
|
||||||
|
{
|
||||||
|
memset(buff + L2_MSG_CFM_PAYLOAD, 0xAA, L2_MSG_CFM_PAYLOAD_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append CRC
|
||||||
|
Status = L2_CrcAppend(buff, L2_CMF_PACK_LEN - L2_MSG_CFM_CRC_LEN, L2_MSG_CFM_CRC, L2_CRC16_1021);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Fail to append CRC, error code: %" PRId32 ".\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logging...
|
||||||
|
memcpy(instPtr->log.txLog.data, buff, L2_CMF_PACK_LEN);
|
||||||
|
instPtr->log.txLog.dataId = dataId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
DBG_ERROR("Unexpected frame type: %" PRId8 ".\n", type);
|
||||||
|
return EPARAM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Scan net packet handler.
|
||||||
|
*
|
||||||
|
* @param instPtr a pointer to linklayer layer instance
|
||||||
|
* @param msg A pointer to frame data buffer.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_Scan_PktHandler(L2_INST *instPtr, uint8_t *msg)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
ASSERT(msg != NULL);
|
||||||
|
int32_t Status;
|
||||||
|
L2_SCAN_FSM *scanFsmPtr = instPtr->scanFSM;
|
||||||
|
L2_FRAME_TYPE frameType = L2_NONE_FRAME;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &frameType);
|
||||||
|
switch (frameType)
|
||||||
|
{
|
||||||
|
case L2_SCAN_FRAME:
|
||||||
|
case L2_ADV_FRAME:
|
||||||
|
{
|
||||||
|
if (L2_GetLastOptFrameType(instPtr) == L2_SCAN_FRAME)
|
||||||
|
{
|
||||||
|
LockStateUpdate(scanFsmPtr, true);
|
||||||
|
StageUpdate(scanFsmPtr, L2_SCAN_ADV_STAGE);
|
||||||
|
}
|
||||||
|
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Unexpected call from head node, only member Node can handle L2_SCAN_FRAME and L2_ADV_FRAME.\n");
|
||||||
|
Status = EUNEXP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uint8_t nodeId;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &nodeId);
|
||||||
|
NODE_ENTRY *node;
|
||||||
|
node = L2_GetNodeById(instPtr->nodeList, nodeId);
|
||||||
|
if (node == NULL)
|
||||||
|
{
|
||||||
|
node = L2_AppendNode(instPtr->nodeList, nodeId, L2_NODE_MEMBER);
|
||||||
|
if (node == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to append new node [id: %" PRId8 "]", nodeId);
|
||||||
|
Status = ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update node info.
|
||||||
|
float nodePos;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_ADV_SRC_POSX, L2_MSG_ADV_SRC_POSX_LEN, &nodePos);
|
||||||
|
node->nodeInfo.pos.x = (double)nodePos;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_ADV_SRC_POSY, L2_MSG_ADV_SRC_POSY_LEN, &nodePos);
|
||||||
|
node->nodeInfo.pos.y = (double)nodePos;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_ADV_SRC_POSZ, L2_MSG_ADV_SRC_POSZ_LEN, &nodePos);
|
||||||
|
node->nodeInfo.pos.z = (double)nodePos;
|
||||||
|
node->nodeInfo.beamNo = Phy_LastScanBeamNo(instPtr->config.phyInstPtr);
|
||||||
|
|
||||||
|
// Reset node ttl
|
||||||
|
node->ttlCnt = 0;
|
||||||
|
|
||||||
|
uint32_t netstartTime;
|
||||||
|
// Update net start time.
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_ADV_SRC_NETSTART_TIME, L2_MSG_ADV_SRC_NETSTART_TIME_LEN, &netstartTime);
|
||||||
|
L2_EVENT netSetupDoneEvent = {
|
||||||
|
.event = L2_EV_NET_ADV_UPDATE,
|
||||||
|
.msg = &netstartTime};
|
||||||
|
AssertL2Event(instPtr, &netSetupDoneEvent);
|
||||||
|
|
||||||
|
// Calculate time deviation
|
||||||
|
uint32_t frameNum, slotNum = 0;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &frameNum);
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &slotNum);
|
||||||
|
Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev));
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to compute time deviation.\n")
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time sync.
|
||||||
|
L2_TimeAdjust(instPtr, &(instPtr->log.timeDev));
|
||||||
|
|
||||||
|
// trigger flag
|
||||||
|
AdvRecvStateUpdate(scanFsmPtr, true);
|
||||||
|
Status = SUCCESS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case L2_CFM_FRAME:
|
||||||
|
{
|
||||||
|
uint8_t nodeId;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &nodeId);
|
||||||
|
NODE_ENTRY *node;
|
||||||
|
node = L2_GetNodeById(instPtr->nodeList, nodeId);
|
||||||
|
if (node == NULL)
|
||||||
|
{
|
||||||
|
node = L2_AppendNode(instPtr->nodeList, nodeId, L2_NODE_MEMBER);
|
||||||
|
if (node == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to append new node [id: %" PRId8 "]", nodeId);
|
||||||
|
Status = ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update node info.
|
||||||
|
float nodePos;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_POSX, L2_MSG_CFM_SRC_POSX_LEN, &nodePos);
|
||||||
|
node->nodeInfo.pos.x = (double)nodePos;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_POSY, L2_MSG_CFM_SRC_POSY_LEN, &nodePos);
|
||||||
|
node->nodeInfo.pos.y = (double)nodePos;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_POSZ, L2_MSG_CFM_SRC_POSZ_LEN, &nodePos);
|
||||||
|
node->nodeInfo.pos.z = (double)nodePos;
|
||||||
|
float nodeSpeed;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_SPEEDX, L2_MSG_CFM_SRC_SPEEDX_LEN, &nodeSpeed);
|
||||||
|
node->nodeInfo.speed.x = (double)nodePos;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_SPEEDY, L2_MSG_CFM_SRC_SPEEDY_LEN, &nodeSpeed);
|
||||||
|
node->nodeInfo.speed.y = (double)nodePos;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_SPEEDZ, L2_MSG_CFM_SRC_SPEEDZ_LEN, &nodeSpeed);
|
||||||
|
node->nodeInfo.speed.z = (double)nodePos;
|
||||||
|
|
||||||
|
// Reset node ttl
|
||||||
|
node->ttlCnt = 0;
|
||||||
|
|
||||||
|
// Calculate time deviation
|
||||||
|
uint32_t frameNum, slotNum = 0;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &frameNum);
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &slotNum);
|
||||||
|
Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev));
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to compute time deviation.\n")
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
|
||||||
|
{
|
||||||
|
// check if net setup finished.
|
||||||
|
if (L2_isCxn2Net(instPtr) == false)
|
||||||
|
{
|
||||||
|
// Assert Net-Setup Done.
|
||||||
|
L2_EVENT l2Event;
|
||||||
|
l2Event.event = L2_EV_NET_SETUP_DONE;
|
||||||
|
l2Event.msg = NULL;
|
||||||
|
AssertL2Event(instPtr, &l2Event);
|
||||||
|
|
||||||
|
// Assert update routine event...
|
||||||
|
L2_RTNE_CONFIG newRtneConfig = {0};
|
||||||
|
L2_EVENT rtneUpEvent =
|
||||||
|
{
|
||||||
|
.event = L2_ROUTINE_UPDATE,
|
||||||
|
.msg = &newRtneConfig
|
||||||
|
};
|
||||||
|
newRtneConfig.rtneTable = initTable;
|
||||||
|
newRtneConfig.rtnePrd = ARRAY_SIZE(initTable);
|
||||||
|
(void)AssertL2Event(instPtr, &rtneUpEvent);
|
||||||
|
}
|
||||||
|
PendCfmAck(instPtr->scanFSM);
|
||||||
|
// Time sync.
|
||||||
|
L2_TimeAdjust(instPtr, &(instPtr->log.timeDev));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (L2_GetMainState(instPtr) == L2_INIT_STATE
|
||||||
|
&& L2_GetNodeListLen(instPtr->nodeList) >= instPtr->config.netScale - 1)
|
||||||
|
{
|
||||||
|
// Assert Net-Setup Done.
|
||||||
|
L2_EVENT l2Event;
|
||||||
|
L2_NODE_STATE newState = L2_NORMAL_STATE;
|
||||||
|
l2Event.event = L2_EV_MAIN_STATE_UPDATE;
|
||||||
|
l2Event.msg = &newState;
|
||||||
|
(void)AssertL2Event(instPtr, &l2Event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get data payload
|
||||||
|
uint32_t dataId;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_CFM_PAYLOAD_ID, L2_MSG_CFM_PAYLOAD_ID_LEN, &dataId);
|
||||||
|
|
||||||
|
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
|
||||||
|
{
|
||||||
|
SysMonitor_UpdateRecvPayload(msg + L2_MSG_CFM_PAYLOAD, dataId, PAYLOAD_LEN_FLJ_RX);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SysMonitor_UpdateRecvPayload(msg + L2_MSG_CFM_PAYLOAD, dataId, PAYLOAD_LEN_LJ_RX);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logging...
|
||||||
|
memcpy(instPtr->log.rxLog.data, msg, L2_CMF_PACK_LEN);
|
||||||
|
instPtr->log.rxLog.dataId = dataId;
|
||||||
|
|
||||||
|
Status = SUCCESS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
DBG_ERROR("Unsupported frame type: %" PRId8 ".\n", frameType);
|
||||||
|
Status = EUNEXP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Initialize scan FSM.
|
||||||
|
*
|
||||||
|
* @param instPtr
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_Scan_Init(L2_SCAN_FSM **scanFSMPtr)
|
||||||
|
{
|
||||||
|
ASSERT(scanFSMPtr != NULL);
|
||||||
|
*scanFSMPtr = (L2_SCAN_FSM *)malloc(sizeof(L2_SCAN_FSM));
|
||||||
|
if (*scanFSMPtr == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to allocate memory for scanFsmPtr.\n");
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
L2_Scan_Reset(*scanFSMPtr);
|
||||||
|
(*scanFSMPtr)->beamNo = 0;
|
||||||
|
(*scanFSMPtr)->tableNo = 0;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Reset ScanNet FSM
|
||||||
|
*
|
||||||
|
* @param scanFsmPtr a pointer to scan net finite state machine
|
||||||
|
*
|
||||||
|
* @return NONE
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void L2_Scan_Reset(L2_SCAN_FSM *scanFSMPtr)
|
||||||
|
{
|
||||||
|
ASSERT(scanFSMPtr != NULL);
|
||||||
|
scanFSMPtr->isLocked = false;
|
||||||
|
scanFSMPtr->isAdvRecvd = false;
|
||||||
|
scanFSMPtr->isAckPending = false;
|
||||||
|
scanFSMPtr->scanCnt = 0;
|
||||||
|
scanFSMPtr->advTimeout = 0;
|
||||||
|
scanFSMPtr->cfmTimeout = 0;
|
||||||
|
scanFSMPtr->scanStage = L2_SCAN_NONE_STAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Destroy ScanNet FSM, free memory
|
||||||
|
*
|
||||||
|
* @param scanFsmPtr a pointer to scan net finite state machine
|
||||||
|
*
|
||||||
|
* @return NONE
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void L2_Scan_Destroy(L2_SCAN_FSM *scanFSMPtr)
|
||||||
|
{
|
||||||
|
free(scanFSMPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Refresh scan beam table.
|
||||||
|
*
|
||||||
|
* @param instPtr a pointer to linklayer layer instance
|
||||||
|
*
|
||||||
|
* @return NONE
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void L2_Scan_RefreashScanTable(L2_INST *instPtr)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
L2_SCAN_FSM *scanFsmPtr = instPtr->scanFSM;
|
||||||
|
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
||||||
|
if (scanFsmPtr->tableNo == 0)
|
||||||
|
{
|
||||||
|
Phy_SetBeamTable(phyRef, antNrrwPattern_0, scanFsmPtr->beamNo);
|
||||||
|
scanFsmPtr->tableNo = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Phy_SetBeamTable(phyRef, antNrrwPattern_1, scanFsmPtr->beamNo);
|
||||||
|
scanFsmPtr->tableNo = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Execute a member node scan net procedure.
|
||||||
|
*
|
||||||
|
* @param instPtr a pointer to linklayer layer instance
|
||||||
|
*
|
||||||
|
* @return used slot (5ms slot).
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_Scan_Proc(L2_INST *instPtr)
|
||||||
|
{
|
||||||
|
L2_SCAN_FSM *scanFSM = instPtr->scanFSM;
|
||||||
|
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Only member node needs to execute L2_Scan_Proc. \n");
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
int32_t Status;
|
||||||
|
DBG_INFO("-------- ScanNet Process --------\n");
|
||||||
|
switch (scanFSM->scanStage)
|
||||||
|
{
|
||||||
|
case L2_SCAN_NONE_STAGE:
|
||||||
|
/* Start Scan. */
|
||||||
|
StageUpdate(scanFSM, L2_SCAN_INIT_STAGE);
|
||||||
|
Status = Scan_InitScanHandler(instPtr);
|
||||||
|
break;
|
||||||
|
case L2_SCAN_INIT_STAGE:
|
||||||
|
Status = Scan_InitScanHandler(instPtr);
|
||||||
|
break;
|
||||||
|
case L2_SCAN_ADV_STAGE:
|
||||||
|
Status = Scan_AdvHandler(instPtr);
|
||||||
|
break;
|
||||||
|
case L2_SCAN_CFM_STAGE:
|
||||||
|
Status = Scan_CfmHandler(instPtr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBG_ERROR("Unexpected scan net stage: %" PRId8 ".\n", scanFSM->scanStage);
|
||||||
|
Status = FAILURE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Execute a scan net Routine procedure.
|
||||||
|
*
|
||||||
|
* @param rtneEntry Routine configuration
|
||||||
|
*
|
||||||
|
* @return used slot (5ms slot).
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_Scan_Routine(L2_INST *instPtr, const L2_RTNE_TABLE_ENTRY *rtneEntry)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
L2_TOR_TYPE torState;
|
||||||
|
const NODE_ENTRY *commNode;
|
||||||
|
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
||||||
|
DBG_INFO("-------- Scan Routine --------\n");
|
||||||
|
|
||||||
|
if (rtneEntry->slotSeq != 0)
|
||||||
|
{
|
||||||
|
return SUCCESS; // skip
|
||||||
|
}
|
||||||
|
|
||||||
|
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
|
||||||
|
{
|
||||||
|
if (rtneEntry->dst == L2_GetNodeId(instPtr) || rtneEntry->dst == L2_BROADCAST_ID)
|
||||||
|
{
|
||||||
|
torState = L2_TOR_RX;
|
||||||
|
commNode = L2_GetNodeById(instPtr->nodeList, rtneEntry->src);
|
||||||
|
}
|
||||||
|
else if (rtneEntry->src == L2_GetNodeId(instPtr) || rtneEntry->src == L2_BROADCAST_ID)
|
||||||
|
{
|
||||||
|
torState = L2_TOR_TX;
|
||||||
|
commNode = L2_GetNodeById(instPtr->nodeList, rtneEntry->dst);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
torState = L2_TOR_SUSPEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup antenna beam
|
||||||
|
Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_16);
|
||||||
|
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
|
||||||
|
if (commNode != NULL)
|
||||||
|
{
|
||||||
|
(void)Phy_SetBeamNo(phyRef, commNode->nodeInfo.beamNo, PHY_ANT_BEAM_16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rtneEntry->dst == L2_GetNodeId(instPtr))
|
||||||
|
{
|
||||||
|
torState = L2_TOR_RX;
|
||||||
|
}
|
||||||
|
else if (rtneEntry->src == L2_GetNodeId(instPtr))
|
||||||
|
{
|
||||||
|
torState = L2_TOR_TX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
torState = L2_TOR_SUSPEND;
|
||||||
|
}
|
||||||
|
// Setup antenna beam
|
||||||
|
(void)Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_120);
|
||||||
|
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_120;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (rtneEntry->slotType)
|
||||||
|
{
|
||||||
|
case L2_SLOT_SCAN:
|
||||||
|
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD && torState == L2_TOR_TX)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Only head node can send init-scan Frame.\n");
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
(void)L2_SetupNextSlot(instPtr, torState, L2_SCAN_FRAME);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case L2_SLOT_ADVERTISE:
|
||||||
|
if (torState == L2_TOR_TX)
|
||||||
|
{
|
||||||
|
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Only head node can send ADV Frame.\n");
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
memset(instPtr->sendPktData, 0xAA, L2_PACK_LEN_MAX);
|
||||||
|
if (ScanMsg_Packing(instPtr, L2_ADV_FRAME, rtneEntry->dst) != SUCCESS)
|
||||||
|
{
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Antenna setting (reserved.) */
|
||||||
|
(void)L2_SetupNextSlot(instPtr, torState, L2_ADV_FRAME);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case L2_SLOT_CONFIRM:
|
||||||
|
if (torState == L2_TOR_TX)
|
||||||
|
{
|
||||||
|
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
|
||||||
|
{
|
||||||
|
if (instPtr->scanFSM->isAckPending == false)
|
||||||
|
{
|
||||||
|
DBG_INFO("Member node has no pending CFM-Ack frame.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memset(instPtr->sendPktData, 0xAA, L2_PACK_LEN_MAX);
|
||||||
|
if (ScanMsg_Packing(instPtr, L2_CFM_FRAME, rtneEntry->dst) != SUCCESS)
|
||||||
|
{
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Antenna setting (reserved.) */
|
||||||
|
(void)L2_SetupNextSlot(instPtr, torState, L2_CFM_FRAME);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBG_ERROR("Cannot start a routine for slot type [%" PRId8 "] properly.\n", rtneEntry->slotType);
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} LinkLayer_Scan*/
|
||||||
|
/** @} LinkLayer*/
|
||||||
@@ -0,0 +1,438 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file schdevent.c
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief DF Linklayer Event scheduling implementation file.
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer_Scheduler
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "schdevent.h"
|
||||||
|
#include "link_layer.h"
|
||||||
|
#include "link_layer_types.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "clist.h"
|
||||||
|
/***************** Macros (Inline Functions) Definitions *********************/
|
||||||
|
/**************************** Type Definitions *******************************/
|
||||||
|
/************************** Variable Definitions *****************************/
|
||||||
|
static L2_SCHD_EVENT util_schdevent;
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
/**
|
||||||
|
* @brief helper function to free schedule events.
|
||||||
|
*/
|
||||||
|
static void schdevent_free(void *val)
|
||||||
|
{
|
||||||
|
if (val == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
free(((L2_SCHD_EVENT *)val)->l2Event.msg);
|
||||||
|
free(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief helper function to match events by ids.
|
||||||
|
*/
|
||||||
|
static int8_t schdevent_compare(void *a, void *b)
|
||||||
|
{
|
||||||
|
ASSERT(a == NULL);
|
||||||
|
ASSERT(b != NULL);
|
||||||
|
register uint32_t idA, idB;
|
||||||
|
idA = ((L2_SCHD_EVENT *)a)->eventId;
|
||||||
|
idB = ((L2_SCHD_EVENT *)b)->eventId;
|
||||||
|
if (idA == idB)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (idA < idB)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Creat a schedule event pool.
|
||||||
|
*
|
||||||
|
* @param schdPool a pointer to schedule pool instance.
|
||||||
|
*
|
||||||
|
* @return SUCCESS
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_CreateSchedEventPool(L2_SCHD_POOL **schdPool)
|
||||||
|
{
|
||||||
|
(*schdPool) = malloc(sizeof(L2_SCHD_POOL));
|
||||||
|
if (*schdPool == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to allocated memory for schdPool.\n");
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
(*schdPool)->schdList = clist_new();
|
||||||
|
if ((*schdPool)->schdList == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to allocated memory for schdPool->schdList.\n");
|
||||||
|
free(*schdPool);
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
(*schdPool)->schdList->free = schdevent_free;
|
||||||
|
(*schdPool)->schdList->compare = schdevent_compare;
|
||||||
|
(*schdPool)->envCnt = 0;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Clear schedule event pool, delete all events in pool and
|
||||||
|
* free allocated memory.
|
||||||
|
*
|
||||||
|
* @param schdPool a pointer to schedule pool instance.
|
||||||
|
*
|
||||||
|
* @return SUCCESS
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void L2_ClearSchedEventPool(L2_SCHD_POOL *schdPool)
|
||||||
|
{
|
||||||
|
ASSERT(schdPool != NULL);
|
||||||
|
clist_clear(schdPool->schdList);
|
||||||
|
schdPool->envCnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Completely destroy schedule event pool.
|
||||||
|
*
|
||||||
|
* @param schdPool a pointer to schedule pool instance.
|
||||||
|
*
|
||||||
|
* @return SUCCESS
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void L2_DestroySchedEventPool(L2_SCHD_POOL *schdPool)
|
||||||
|
{
|
||||||
|
if (schdPool == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clist_destroy(schdPool->schdList);
|
||||||
|
free(schdPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Creat a new schedule event, register event in schedule event pool.
|
||||||
|
*
|
||||||
|
* @param schdPool a pointer to schedule pool instance.
|
||||||
|
* @param event event type of the new schedule event.
|
||||||
|
* @param isVolatile event type of the new schedule event.
|
||||||
|
*
|
||||||
|
* @return NULL error occurred
|
||||||
|
* Pointer to schedule event.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
L2_SCHD_EVENT *L2_CreatNewSchdEvent(L2_SCHD_POOL *schdPool, L2_EVENT_TYPE event, bool isVolatile)
|
||||||
|
{
|
||||||
|
ASSERT(schdPool != NULL);
|
||||||
|
if (event < L2_EV_SCAN_PROC_DONE || event > L2_ROUTINE_UPDATE)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Unknown event type: %" PRId8 ".\n", event);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
L2_SCHD_EVENT *schdEvent = (L2_SCHD_EVENT *)malloc(sizeof(L2_SCHD_EVENT));
|
||||||
|
if (schdEvent == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to allocate schedule event.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
clist_node_t *node = clist_node_new(schdEvent);
|
||||||
|
if (node == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to allocate schedule event list node.\n");
|
||||||
|
free(schdEvent);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
schdEvent->eventId = schdPool->envCnt++;
|
||||||
|
schdEvent->occurCnt = 0;
|
||||||
|
schdEvent->l2Event.event = event;
|
||||||
|
schdEvent->l2Event.msg = NULL;
|
||||||
|
schdEvent->isSchd = false;
|
||||||
|
schdEvent->isVolatile = isVolatile;
|
||||||
|
schdEvent->schdSlot = L2_SLOTNO_NONE;
|
||||||
|
schdEvent->schdFrame = L2_FRAMENO_NONE;
|
||||||
|
clist_rpush(schdPool->schdList, node);
|
||||||
|
return schdEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Get a schedule event by its id.
|
||||||
|
*
|
||||||
|
* @param schdPool a pointer to schedule pool instance.
|
||||||
|
* @param id ID of the event
|
||||||
|
*
|
||||||
|
* @return NULL
|
||||||
|
* Pointer to the schedule event.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
L2_SCHD_EVENT *L2_GetEventById(L2_SCHD_POOL *schdPool, uint32_t id)
|
||||||
|
{
|
||||||
|
ASSERT(schdPool != NULL);
|
||||||
|
util_schdevent.eventId = id;
|
||||||
|
clist_node_t *node = clist_find(schdPool->schdList, &util_schdevent);
|
||||||
|
if (node != NULL)
|
||||||
|
{
|
||||||
|
DBG_WARNING("Event with id=%" PRIu32 ", dose not exist.\n", id);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return ((L2_SCHD_EVENT *)node->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Delete a schedule event, remove the event from event pool,
|
||||||
|
* release memory.
|
||||||
|
*
|
||||||
|
* @param schdPool a pointer to schedule pool instance.
|
||||||
|
* @param id ID of the event
|
||||||
|
*
|
||||||
|
* @return SUCCESS
|
||||||
|
* error code
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_DeleteSchdEventById(L2_SCHD_POOL *schdPool, uint32_t id)
|
||||||
|
{
|
||||||
|
ASSERT(schdPool != NULL);
|
||||||
|
util_schdevent.eventId = id;
|
||||||
|
clist_node_t *node = clist_find(schdPool->schdList, &util_schdevent);
|
||||||
|
if (node != NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Event with id=%" PRIu32 ", dose not exist.\n", id);
|
||||||
|
return EIGNORE;
|
||||||
|
}
|
||||||
|
clist_remove(schdPool->schdList, node);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Schedule a event at a specific time(indexed by frame and slot number)
|
||||||
|
*
|
||||||
|
* @param instPtr a pointer to linklayer instance
|
||||||
|
* @param schdEvent pointer to the schedule event.
|
||||||
|
* @param frameNum schedule frame number
|
||||||
|
* @param slotNum schedule slot number
|
||||||
|
*
|
||||||
|
* @return FAILURE, event has already been scheduled/schedule time not allowed.
|
||||||
|
* SUCCESS
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_ScheduleEventAt(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t frameNum, uint32_t slotNum)
|
||||||
|
{
|
||||||
|
ASSERT(schdEvent != NULL);
|
||||||
|
if (L2_isEventScheduled(schdEvent) == true)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Event %" PRIu32 " has already been scheduled.\n", schdEvent->eventId);
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
if (frameNum <= L2_GetCurrentFrameNum(instPtr) && slotNum < L2_GetCurrentSlotNum(instPtr))
|
||||||
|
{
|
||||||
|
DBG_ERROR("Cannot schedule event %" PRIu32 " to the past(current: [%" PRIu32 "-%" PRIu32 "], schedule: [%" PRIu32 "-%" PRIu32 "]).\n",
|
||||||
|
schdEvent->eventId, L2_GetCurrentFrameNum(instPtr), L2_GetCurrentSlotNum(instPtr), frameNum, slotNum);
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
DBG_INFO("Schedule event (type:%" PRIu8 ") [%" PRIu32 "] at %" PRIu32 "-%" PRIu32 ".\n",
|
||||||
|
schdEvent->l2Event.event, schdEvent->eventId,
|
||||||
|
frameNum, slotNum);
|
||||||
|
schdEvent->isSchd = true;
|
||||||
|
schdEvent->schdFrame = frameNum;
|
||||||
|
schdEvent->schdSlot = slotNum;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Schedule a event after a specific time period.
|
||||||
|
*
|
||||||
|
* @param instPtr a pointer to linklayer instance
|
||||||
|
* @param schdEvent pointer to the schedule event.
|
||||||
|
* @param numSlots how many slot later the event should be scheduled
|
||||||
|
*
|
||||||
|
* @return FAILURE, event has already been scheduled/schedule time not allowed.
|
||||||
|
* SUCCESS
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_ScheduleEventAfter(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t numSlots)
|
||||||
|
{
|
||||||
|
ASSERT(schdEvent != NULL);
|
||||||
|
if (L2_isEventScheduled(schdEvent) == true)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Event %" PRIu32 " has already been scheduled.\n", schdEvent->eventId);
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
uint32_t frameNum = L2_GetCurrentFrameNum(instPtr) + (numSlots / L2_SLOTS_PER_FRAME);
|
||||||
|
uint32_t slotNum = L2_GetCurrentSlotNum(instPtr) + (numSlots % L2_SLOTS_PER_FRAME);
|
||||||
|
return L2_ScheduleEventAt(instPtr, schdEvent, frameNum, slotNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Reschedule a event at a specific time(indexed by frame and slot number)
|
||||||
|
*
|
||||||
|
* @param instPtr a pointer to linklayer instance
|
||||||
|
* @param schdEvent pointer to the schedule event.
|
||||||
|
* @param frameNum schedule frame number
|
||||||
|
* @param slotNum schedule slot number
|
||||||
|
*
|
||||||
|
* @return FAILURE, event has already been scheduled/schedule time not allowed.
|
||||||
|
* SUCCESS
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_RescheduleEventAt(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t frameNum, uint32_t slotNum)
|
||||||
|
{
|
||||||
|
ASSERT(schdEvent != NULL);
|
||||||
|
if (schdEvent->isSchd == false)
|
||||||
|
{
|
||||||
|
DBG_WARNING("Event %" PRIu32 " has not been scheduled yet.\n", schdEvent->eventId);
|
||||||
|
}
|
||||||
|
schdEvent->isSchd = false;
|
||||||
|
return L2_ScheduleEventAt(instPtr, schdEvent, frameNum, slotNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Reschedule a event after a specific time period.
|
||||||
|
*
|
||||||
|
* @param instPtr a pointer to linklayer instance
|
||||||
|
* @param schdEvent pointer to the schedule event.
|
||||||
|
* @param numSlots how many slot later the event should be scheduled
|
||||||
|
*
|
||||||
|
* @return FAILURE, event has already been scheduled/schedule time not allowed.
|
||||||
|
* SUCCESS
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_RescheduleEventAfter(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t numSlots)
|
||||||
|
{
|
||||||
|
ASSERT(schdEvent != NULL);
|
||||||
|
if (schdEvent->isSchd == false)
|
||||||
|
{
|
||||||
|
DBG_WARNING("Event %" PRIu32 " has not been scheduled yet.\n", schdEvent->eventId);
|
||||||
|
}
|
||||||
|
return L2_ScheduleEventAfter(instPtr, schdEvent, numSlots);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Check and excute schedule event in event pool illiterate.
|
||||||
|
*
|
||||||
|
* @param instPtr a pointer to linklayer instance
|
||||||
|
*
|
||||||
|
* @return NONE.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void L2_EventPoolHandler(L2_INST *instPtr)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
clist_node_t *node;
|
||||||
|
L2_SCHD_EVENT *event;
|
||||||
|
L2_SCHD_POOL *pool = instPtr->schdEventPool;
|
||||||
|
clist_iterator_t *iter = clist_iterator_new(pool->schdList, LIST_HEAD);
|
||||||
|
if (iter == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to initialize schedule event pool iteration.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while ((node = clist_iterator_next(iter)))
|
||||||
|
{
|
||||||
|
event = (L2_SCHD_EVENT *)node->val;
|
||||||
|
if (L2_isEventScheduled(event))
|
||||||
|
{
|
||||||
|
if (event->schdFrame == L2_GetCurrentFrameNum(instPtr) && event->schdSlot == L2_GetCurrentSlotNum(instPtr))
|
||||||
|
{
|
||||||
|
DBG_INFO("Asserting scheduled event [%" PRIu32 "].\n", event->eventId);
|
||||||
|
(void)AssertL2Event(instPtr, &(event->l2Event));
|
||||||
|
if (event->isVolatile == true)
|
||||||
|
{
|
||||||
|
DBG_INFO("Deleting scheduled event [%" PRIu32 "], since it is volatile.\n", event->eventId);
|
||||||
|
clist_remove(pool->schdList, node);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
event->occurCnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clist_iterator_destroy(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Append extra message content to specific schedule event.
|
||||||
|
*
|
||||||
|
* @param schdEvent pointer to the schedule event.
|
||||||
|
* msg pointer to the append content.
|
||||||
|
*
|
||||||
|
* @return SUCCESS.
|
||||||
|
* error code.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
inline void L2_SchdEventAppendMsg(L2_SCHD_EVENT *schdEvent, void *msg)
|
||||||
|
{
|
||||||
|
ASSERT(schdEvent != NULL);
|
||||||
|
schdEvent->l2Event.msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Cancel a scheduled event.
|
||||||
|
*
|
||||||
|
* @param schdEvent pointer to the schedule event.
|
||||||
|
*
|
||||||
|
* @return SUCCESS.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
inline int32_t L2_CancelEvent(L2_SCHD_EVENT *schdEvent)
|
||||||
|
{
|
||||||
|
ASSERT(schdEvent != NULL);
|
||||||
|
if (schdEvent->isSchd == false)
|
||||||
|
{
|
||||||
|
DBG_WARNING("Event %" PRIu32 " has not been scheduled yet.\n", schdEvent->eventId);
|
||||||
|
}
|
||||||
|
schdEvent->isSchd = false;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Check if the event was scheduled.
|
||||||
|
*
|
||||||
|
* @param schdEvent pointer to the schedule event.
|
||||||
|
*
|
||||||
|
* @return true.
|
||||||
|
* false.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
inline bool L2_isEventScheduled(const L2_SCHD_EVENT *schdEvent)
|
||||||
|
{
|
||||||
|
ASSERT(schdEvent != NULL);
|
||||||
|
return schdEvent->isSchd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} LinkLayer_Scheduler*/
|
||||||
|
/** @} LinkLayer*/
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file schdevent.c
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief DF Linklayer Event scheduling header file.
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer_Scheduler
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#ifndef SCHDEVENT_H_
|
||||||
|
#define SCHDEVENT_H_
|
||||||
|
|
||||||
|
#define SCHDEVENT_ID_NONE UINT32_MAX
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "link_layer_types.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "clist.h"
|
||||||
|
/***************** Macros (Inline Functions) Definitions *********************/
|
||||||
|
/**************************** Type Definitions *******************************/
|
||||||
|
/**
|
||||||
|
* @struct L2_SCHD_EVENT
|
||||||
|
* @brief Linklayer scheduled event descriptor
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
bool isSchd;
|
||||||
|
bool isVolatile;
|
||||||
|
L2_EVENT l2Event;
|
||||||
|
uint32_t eventId;
|
||||||
|
uint32_t occurCnt;
|
||||||
|
uint32_t schdFrame;
|
||||||
|
uint32_t schdSlot;
|
||||||
|
} L2_SCHD_EVENT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct L2_SCHD_POOL
|
||||||
|
* @brief Linklayer schedule event pool instance
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
clist_t *schdList;
|
||||||
|
uint32_t envCnt;
|
||||||
|
} L2_SCHD_POOL;
|
||||||
|
|
||||||
|
/************************** Variable Definitions *****************************/
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
// Scheduling Event
|
||||||
|
int32_t L2_CreateSchedEventPool(L2_SCHD_POOL **schdPool);
|
||||||
|
void L2_ClearSchedEventPool(L2_SCHD_POOL *schdPool);
|
||||||
|
void L2_DestroySchedEventPool(L2_SCHD_POOL *schdPool);
|
||||||
|
|
||||||
|
L2_SCHD_EVENT *L2_CreatNewSchdEvent(L2_SCHD_POOL *schdPool, L2_EVENT_TYPE event, bool isVolatile);
|
||||||
|
L2_SCHD_EVENT *L2_GetEventById(L2_SCHD_POOL *schdPool, uint32_t id);
|
||||||
|
int32_t L2_DeleteSchdEventById(L2_SCHD_POOL *schdPool, uint32_t id);
|
||||||
|
|
||||||
|
void L2_SchdEventAppendMsg(L2_SCHD_EVENT *schdEvent, void *msg);
|
||||||
|
bool L2_isEventScheduled(const L2_SCHD_EVENT *schdEvent);
|
||||||
|
int32_t L2_CancelEvent(L2_SCHD_EVENT *schdEvent);
|
||||||
|
|
||||||
|
#endif // SCHDEVENT_H_
|
||||||
|
|
||||||
|
/** @} LinkLayer_Scheduler*/
|
||||||
|
/** @} LinkLayer*/
|
||||||
@@ -0,0 +1,438 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file service.c
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief DF Linklayer service implementation file.
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer_Service
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "link_layer.h"
|
||||||
|
#include "link_layer_types.h"
|
||||||
|
#include "msg_def.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "circ_queue.h"
|
||||||
|
#ifndef EMULATION
|
||||||
|
#include "../config/app_config.h"
|
||||||
|
#endif
|
||||||
|
/************************** Constant Definitions *****************************/
|
||||||
|
/***************** Macros (Inline Functions) Definitions *********************/
|
||||||
|
/**************************** Type Definitions *******************************/
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
static int32_t Service_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dstId);
|
||||||
|
/************************** Variable Definitions *****************************/
|
||||||
|
|
||||||
|
static uint8_t testData[L2_PACK_LEN_MAX] =
|
||||||
|
{
|
||||||
|
0x39, 0x85, 0x02, 0xF0, 0xC7, 0x6A, 0xE8, 0xB4, 0xE7, 0xAB, 0xC9, 0xDC, 0x0B, 0x41, 0x42, 0xE0,
|
||||||
|
0xED, 0x21, 0x07, 0x62, 0x4E, 0x80, 0xA0, 0xE1, 0xAC, 0x77, 0x9B, 0x1F, 0x48, 0x0B, 0x58, 0xB9,
|
||||||
|
0x45, 0xA5, 0x24, 0xEF, 0xF3, 0x71, 0x2E, 0x84, 0x6C, 0x22, 0xB3, 0x05, 0xEB, 0x75, 0xF2, 0x0B,
|
||||||
|
0x45, 0x73, 0x01, 0xA8, 0x1E, 0x00, 0x21, 0x3E, 0x03, 0x86, 0x55, 0x59, 0x98, 0x5C, 0x61, 0xA2,
|
||||||
|
0xE8, 0x20, 0x0E, 0x7A, 0xD5, 0x72, 0xAF, 0xF4, 0xBC, 0xB3, 0x6F, 0xFE, 0xB3, 0x78, 0x6A, 0x59,
|
||||||
|
0x73, 0xBD, 0x97, 0xBE, 0x44, 0xA4, 0x9B, 0x71, 0x11, 0x45, 0x37, 0xFE, 0xB3, 0x71, 0xEF, 0x1E,
|
||||||
|
0x3A, 0x2B, 0x58, 0x07, 0xF6, 0x01, 0x1C, 0x73, 0x28, 0x11, 0xA8, 0x15, 0xA2, 0x58, 0x32, 0x2E,
|
||||||
|
0x7D, 0x35, 0x9C, 0xE4, 0x98, 0x7F, 0x9C, 0x81, 0x32, 0xAA, 0xC4, 0x87, 0x16, 0x26, 0x23, 0x95,
|
||||||
|
0x57, 0xC9, 0xD4, 0x34, 0xCE, 0x63, 0x78, 0x7E, 0xD4, 0x3C, 0x16, 0x1D, 0x80, 0xC0, 0x55, 0xBF,
|
||||||
|
0xB5, 0xD6, 0x0C, 0xA5, 0xB9, 0x0A, 0x14, 0x5B, 0x4D, 0x52, 0xF2, 0xA9, 0x7A, 0x08, 0x67, 0x8E,
|
||||||
|
0xEB, 0x67, 0x34, 0x7F, 0x7A, 0x35, 0xAF, 0xD9, 0x07, 0x52, 0x30, 0x38, 0x70, 0xC9, 0x41, 0xF8,
|
||||||
|
0x36, 0x61, 0x32, 0x72, 0xA4, 0x7A, 0xEA, 0x21, 0xB4, 0xBF, 0xAA, 0xCF, 0x93, 0x4F, 0xE1, 0x5C,
|
||||||
|
0xA0, 0xFB, 0xD0, 0x2B, 0xA3, 0x82, 0x2E, 0x69, 0x7D, 0xB7, 0x76, 0x88, 0xF7, 0x5C, 0xF3, 0x82,
|
||||||
|
0xC6, 0x6D, 0x49, 0x92, 0x64, 0x88, 0x9A, 0x43, 0xEE, 0xE9, 0x93, 0xC3, 0x70, 0x50, 0x22, 0xF1,
|
||||||
|
0xD3, 0x2B, 0xCF, 0xA9, 0xE5, 0x69, 0x22, 0xF9, 0xBF, 0x78, 0x9A, 0xA4, 0x5A, 0x3D, 0x2E, 0x2A,
|
||||||
|
0x23, 0xE3, 0x51, 0x8F, 0x1A, 0xC1, 0xAF, 0x47, 0x9C, 0x14, 0xCE, 0xB9, 0xCD, 0xD0, 0x02, 0xB7,
|
||||||
|
0xB8, 0x81, 0xCC, 0x44, 0xE7, 0xA2, 0x6F, 0x32, 0x8C, 0x78, 0x79, 0x10, 0xF3, 0xE1, 0xB0, 0x7C,
|
||||||
|
0xAB, 0x40, 0xDB, 0xF9, 0x99, 0xE7, 0x27, 0x30, 0x53, 0x67, 0x00, 0xE8, 0x33, 0x6D, 0xFC, 0x4D,
|
||||||
|
0xDC, 0xB0, 0xFC, 0x3D, 0xEF, 0x8D, 0x43, 0xAF, 0x7E, 0x41, 0x69, 0xDA, 0xFD, 0xDF, 0x2F, 0xF8,
|
||||||
|
0xEC, 0xFB, 0x6A, 0x65, 0xE7, 0xEC, 0xC7, 0x53, 0x1B, 0x14, 0xDF, 0xBD, 0x0C, 0x54, 0x57, 0xD2,
|
||||||
|
0x56, 0x15, 0xF4, 0x34, 0xE2, 0xFB, 0x12, 0xA0, 0xA2, 0xDE, 0x82, 0xF5, 0x04, 0x81, 0x9B, 0x08,
|
||||||
|
0xB6, 0x8C, 0x7B, 0xE0, 0xAA, 0xDF, 0xC9, 0x92, 0x9D, 0x5F, 0x2D, 0xF7, 0x4A, 0x0B, 0xFF, 0xA5,
|
||||||
|
0xAA, 0xDC, 0xD6, 0x3F, 0x56, 0xB2, 0x6A, 0x3C, 0x6F, 0xAA, 0xAC, 0x84, 0xAC, 0x3F, 0x3D, 0x05,
|
||||||
|
0x96, 0x12, 0x44, 0x39, 0x1C, 0xD1, 0xFA, 0xBE, 0x6B, 0x1A, 0xCD, 0x31, 0x29, 0x41, 0x31, 0xA3,
|
||||||
|
0xA8, 0x0D, 0x87, 0xEB, 0x96, 0x21, 0x39, 0xD6, 0x3B, 0x11, 0x50, 0xB5, 0xFE, 0x44, 0x0E, 0x74,
|
||||||
|
0x31, 0x12, 0xA1, 0x66, 0x49, 0xFD, 0x2D, 0x75, 0x72, 0xF9, 0xC8, 0xD9, 0x6C, 0xC9, 0x11, 0x74,
|
||||||
|
0x2E, 0xEB, 0x20, 0x33, 0x3D, 0x2C, 0x5E, 0xEA, 0x39, 0x31, 0x88, 0xC7, 0xD1, 0x93, 0x95, 0xD8,
|
||||||
|
0x9E, 0x87, 0x93, 0xBC, 0x09, 0x17, 0xC9, 0xA2, 0x59, 0x18, 0x51, 0x8F, 0xBF, 0x55, 0x45, 0x81,
|
||||||
|
0x8D, 0xFD, 0xAF, 0xB2, 0x21, 0xB7, 0xD8, 0xA8, 0x00, 0x2E, 0x70, 0x73, 0x2F, 0x74, 0xBC, 0x61,
|
||||||
|
0x0A, 0x8E, 0xE3, 0x0A, 0x92, 0x82, 0xD2, 0x82, 0xBA, 0xE4, 0x3E, 0x8E, 0xBB, 0xC7, 0xA2, 0x8F,
|
||||||
|
0x68, 0xE1, 0x29, 0x34, 0x7C, 0xB4, 0x22, 0xCF, 0x36, 0x8F, 0x9D, 0x63, 0x9D, 0x04, 0x8F, 0x4A,
|
||||||
|
0xFB, 0x84, 0xBB, 0x6B, 0x97, 0x2C, 0x15, 0xC9, 0x37, 0x4F, 0x40, 0xD7, 0x47, 0x50, 0x39, 0x97
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Packing Service message
|
||||||
|
*
|
||||||
|
* @param instPtr pointer to linklayer instance
|
||||||
|
* type message type.
|
||||||
|
* dstId destination node address.
|
||||||
|
*
|
||||||
|
* @return EPARAM
|
||||||
|
* SUCCESS
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
static int32_t Service_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dstId)
|
||||||
|
{
|
||||||
|
#ifndef DATALINK_ENABLE_BERTEST
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
int32_t Status;
|
||||||
|
uint32_t dataChunk;
|
||||||
|
uint8_t *buff = instPtr->sendPktData;
|
||||||
|
|
||||||
|
// Common section of link layer package
|
||||||
|
dataChunk = L2_GetNextFrameNum(instPtr);
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &dataChunk);
|
||||||
|
dataChunk = L2_GetNextSlotNum(instPtr);
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &dataChunk);
|
||||||
|
dataChunk = L2_GetNodeId(instPtr);
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &dataChunk);
|
||||||
|
dataChunk = dstId;
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_DST_ID, L2_MSG_DST_ID_LEN, &dataChunk);
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case L2_SVC_FRAME:
|
||||||
|
{
|
||||||
|
dataChunk = L2_SVC_FRAME;
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &dataChunk);
|
||||||
|
|
||||||
|
SysMonitor_GetSysinfo(&(instPtr->sysInfo));
|
||||||
|
// insert position and speed info
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_POSX, L2_MSG_SVC_SRC_POSX_LEN, &(instPtr->sysInfo.posX));
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_POSY, L2_MSG_SVC_SRC_POSY_LEN, &(instPtr->sysInfo.posY));
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_POSZ, L2_MSG_SVC_SRC_POSZ_LEN, &(instPtr->sysInfo.posZ));
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_SPEEDX, L2_MSG_SVC_SRC_SPEEDX_LEN, &(instPtr->sysInfo.vX));
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_SPEEDY, L2_MSG_SVC_SRC_SPEEDY_LEN, &(instPtr->sysInfo.vY));
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_SPEEDZ, L2_MSG_SVC_SRC_SPEEDZ_LEN, &(instPtr->sysInfo.vZ));
|
||||||
|
|
||||||
|
uint32_t dataId;
|
||||||
|
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
|
||||||
|
{
|
||||||
|
SysMonitor_GetSendPayload(buff + L2_MSG_SVC_PAYLOAD, &dataId, PAYLOAD_LEN_FLJ_TX);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SysMonitor_GetSendPayload(buff + L2_MSG_SVC_PAYLOAD, &dataId, PAYLOAD_LEN_LJ_TX);
|
||||||
|
}
|
||||||
|
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_SVC_PAYLOAD_ID, L2_MSG_SVC_PAYLOAD_ID_LEN, &dataId);
|
||||||
|
if (dataId == DATA_ID_NONE)
|
||||||
|
{
|
||||||
|
L2_FrameInsertChunk(buff, L2_MSG_SVC_PAYLOAD, L2_MSG_SVC_PAYLOAD_LEN, testData);
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = L2_CrcAppend(buff, L2_SVC_PACK_LEN - L2_MSG_SVC_CRC_LEN, L2_MSG_SVC_CRC, L2_CRC16_1021);
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Fail to append CRC...\n");
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(instPtr->log.txLog.data, buff, L2_SVC_PACK_LEN);
|
||||||
|
instPtr->log.txLog.dataId = dataId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
DBG_ERROR("Unexpected frame type: %" PRIu8 ".\n", type);
|
||||||
|
return EPARAM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
#else
|
||||||
|
DBG_ERROR("Unexpected call of Service_Packing in BER test mode.\n");
|
||||||
|
return EUNEXP;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Handle service received packet. Send data up to MPC
|
||||||
|
*
|
||||||
|
* @param msg A point32_ter the the message frame.
|
||||||
|
*
|
||||||
|
* @return SUCCESS message has been successfully handled.
|
||||||
|
* other error occurred.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_Service_PktHandler(L2_INST *instPtr, uint8_t *msg)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
ASSERT(msg != NULL);
|
||||||
|
int32_t Status;
|
||||||
|
#ifndef DATALINK_ENABLE_BERTEST
|
||||||
|
L2_FRAME_TYPE frameType = L2_NONE_FRAME;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &frameType);
|
||||||
|
switch (frameType)
|
||||||
|
{
|
||||||
|
case L2_SVC_FRAME:
|
||||||
|
{
|
||||||
|
uint8_t nodeId;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &nodeId);
|
||||||
|
NODE_ENTRY *node;
|
||||||
|
node = L2_GetNodeById(instPtr->nodeList, nodeId);
|
||||||
|
if (node == NULL)
|
||||||
|
{
|
||||||
|
node = L2_AppendNode(instPtr->nodeList, nodeId, L2_NODE_MEMBER);
|
||||||
|
if (node == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to append new node [id: %" PRIu8 "]", nodeId);
|
||||||
|
Status = ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update node info.
|
||||||
|
float nodePos;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_POSX, L2_MSG_SVC_SRC_POSX_LEN, &nodePos);
|
||||||
|
node->nodeInfo.pos.x = (double)nodePos;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_POSY, L2_MSG_SVC_SRC_POSY_LEN, &nodePos);
|
||||||
|
node->nodeInfo.pos.y = (double)nodePos;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_POSZ, L2_MSG_SVC_SRC_POSZ_LEN, &nodePos);
|
||||||
|
node->nodeInfo.pos.z = (double)nodePos;
|
||||||
|
float nodeSpeed;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_SPEEDX, L2_MSG_SVC_SRC_SPEEDX_LEN, &nodeSpeed);
|
||||||
|
node->nodeInfo.speed.x = (double)nodePos;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_SPEEDY, L2_MSG_SVC_SRC_SPEEDY_LEN, &nodeSpeed);
|
||||||
|
node->nodeInfo.speed.y = (double)nodePos;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_SPEEDZ, L2_MSG_SVC_SRC_SPEEDZ_LEN, &nodeSpeed);
|
||||||
|
node->nodeInfo.speed.z = (double)nodePos;
|
||||||
|
|
||||||
|
// Reset node ttl
|
||||||
|
node->ttlCnt = 0;
|
||||||
|
|
||||||
|
// Calculate time deviation
|
||||||
|
uint32_t frameNum, slotNum = 0;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &frameNum);
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &slotNum);
|
||||||
|
Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev));
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to compute time deviation.\n")
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t dataId;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_SVC_PAYLOAD_ID, L2_MSG_SVC_PAYLOAD_ID_LEN, &dataId);
|
||||||
|
|
||||||
|
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
|
||||||
|
{
|
||||||
|
SysMonitor_UpdateRecvPayload(msg + L2_MSG_SVC_PAYLOAD, dataId, PAYLOAD_LEN_FLJ_RX);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SysMonitor_UpdateRecvPayload(msg + L2_MSG_SVC_PAYLOAD, dataId, PAYLOAD_LEN_LJ_RX);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logging
|
||||||
|
memcpy(instPtr->log.rxLog.data, msg, L2_SVC_PACK_LEN);
|
||||||
|
instPtr->log.rxLog.dataId = dataId;
|
||||||
|
instPtr->serviceFSM->rxdCnt++;
|
||||||
|
|
||||||
|
#ifdef DATALINK_ENABLE_AUTOTIMESYNC
|
||||||
|
// Implement a auto time sync.
|
||||||
|
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
|
||||||
|
{
|
||||||
|
// Time sync.
|
||||||
|
L2_TimeAdjust(instPtr, &(instPtr->log.timeDev));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
DBG_ERROR("Unsupported frame type: %" PRIu8 ".\n", frameType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Status;
|
||||||
|
#else
|
||||||
|
uint32_t errorBits = 0;
|
||||||
|
for (int i = 0; i < L2_SVC_PACK_LEN; i++)
|
||||||
|
{
|
||||||
|
errorBits += count_ones(msg[i] ^ testData[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
instPtr->serviceFSM->bitError += errorBits;
|
||||||
|
instPtr->serviceFSM->bitTotal += L2_SVC_PACK_LEN * 8;
|
||||||
|
|
||||||
|
// Calculate time deviation
|
||||||
|
uint32_t frameNum, slotNum = 0;
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &frameNum);
|
||||||
|
L2_FrameGetChunk(msg, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &slotNum);
|
||||||
|
Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev));
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to compute time deviation.\n")
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
// Implement a auto time sync.
|
||||||
|
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
|
||||||
|
{
|
||||||
|
// Time sync.
|
||||||
|
L2_TimeAdjust(instPtr, &(instPtr->log.timeDev));
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Initialize service net FSM
|
||||||
|
*
|
||||||
|
* @param serviceFSM A pointer to service FSM instance.
|
||||||
|
*
|
||||||
|
* @return SUCCESS Initialize successfully.
|
||||||
|
* Other Initialize failed.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_Service_Init(L2_SVC_FSM **svcFSMPtr)
|
||||||
|
{
|
||||||
|
ASSERT(svcFSMPtr != NULL);
|
||||||
|
*svcFSMPtr = (L2_SVC_FSM *)malloc(sizeof(L2_SVC_FSM));
|
||||||
|
if (*svcFSMPtr == NULL)
|
||||||
|
{
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
L2_Service_Reset(*svcFSMPtr);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Reset ServiceNet FSM
|
||||||
|
*
|
||||||
|
* @param scanFsmPtr a pointer to service net finite state machine
|
||||||
|
*
|
||||||
|
* @return NONE
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void L2_Service_Reset(L2_SVC_FSM *svcFSMPtr)
|
||||||
|
{
|
||||||
|
ASSERT(svcFSMPtr != NULL);
|
||||||
|
svcFSMPtr->txCnt = 0;
|
||||||
|
svcFSMPtr->rxCnt = 0;
|
||||||
|
svcFSMPtr->rxdCnt = 0;
|
||||||
|
#ifdef DATALINK_ENABLE_BERTEST
|
||||||
|
svcFSMPtr->bitTotal = 0;
|
||||||
|
svcFSMPtr->bitError = 0;
|
||||||
|
svcFSMPtr->lossRate = 0;
|
||||||
|
svcFSMPtr->errorRate = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Destroy ServiceNet FSM, free memory
|
||||||
|
*
|
||||||
|
* @param scanFsmPtr a pointer to service net finite state machine
|
||||||
|
*
|
||||||
|
* @return NONE
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void L2_Service_Destroy(L2_SVC_FSM *serviceFSM)
|
||||||
|
{
|
||||||
|
free(serviceFSM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Service FSM Routine.
|
||||||
|
*
|
||||||
|
* @param instPtr
|
||||||
|
* @param schedEntry
|
||||||
|
*
|
||||||
|
* @return Slot has been used.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_Service_Routine(L2_INST *instPtr, const L2_RTNE_TABLE_ENTRY *rtneEntry)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
DBG_INFO("-------- ServiceNet Routine --------\n");
|
||||||
|
|
||||||
|
if (rtneEntry->slotSeq != 0)
|
||||||
|
{
|
||||||
|
return SUCCESS; // skip
|
||||||
|
}
|
||||||
|
|
||||||
|
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
||||||
|
L2_SVC_FSM *svcFSMPtr = instPtr->serviceFSM;
|
||||||
|
L2_TOR_TYPE torState;
|
||||||
|
const NODE_ENTRY *commNode;
|
||||||
|
if (rtneEntry->src == L2_GetNodeId(instPtr))
|
||||||
|
{
|
||||||
|
torState = L2_TOR_TX;
|
||||||
|
commNode = L2_GetNodeById(instPtr->nodeList, rtneEntry->dst);
|
||||||
|
}
|
||||||
|
else if (rtneEntry->dst == L2_GetNodeId(instPtr))
|
||||||
|
{
|
||||||
|
torState = L2_TOR_RX;
|
||||||
|
commNode = L2_GetNodeById(instPtr->nodeList, rtneEntry->src);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
torState = L2_TOR_SUSPEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup antenna beam
|
||||||
|
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD && commNode != NULL)
|
||||||
|
{
|
||||||
|
Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_16);
|
||||||
|
Phy_SetBeamNo(phyRef, commNode->nodeInfo.beamNo, PHY_ANT_BEAM_16);
|
||||||
|
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_120);
|
||||||
|
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_120;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (rtneEntry->slotType)
|
||||||
|
{
|
||||||
|
case L2_SLOT_SERVICE:
|
||||||
|
if (torState == L2_TOR_TX)
|
||||||
|
{
|
||||||
|
svcFSMPtr->txCnt++;
|
||||||
|
#ifndef DATALINK_ENABLE_BERTEST
|
||||||
|
// Packing service data
|
||||||
|
Service_Packing(instPtr, L2_SVC_FRAME, rtneEntry->dst);
|
||||||
|
#else
|
||||||
|
memcpy(instPtr->sendPktData, testData, L2_SVC_PACK_LEN);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
svcFSMPtr->rxCnt++;
|
||||||
|
}
|
||||||
|
L2_SetupNextSlot(instPtr, torState, L2_SVC_FRAME);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBG_ERROR("UNKNOWN slot type [%" PRIu8 "].\n", rtneEntry->slotType);
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
#ifdef DATALINK_ENABLE_BERTEST
|
||||||
|
uint32_t pktLoss;
|
||||||
|
pktLoss = svcFSMPtr->rxCnt - svcFSMPtr->rxdCnt;
|
||||||
|
svcFSMPtr->lossRate = (svcFSMPtr->rxCnt == 0) ? 0 : (double)pktLoss / (double)svcFSMPtr->rxCnt;
|
||||||
|
svcFSMPtr->errorRate = (svcFSMPtr->bitTotal == 0) ? 0 : (double)svcFSMPtr->bitError / (double)svcFSMPtr->bitTotal;
|
||||||
|
DBG_PRINT("Packet Loss Rate -- Total: %lu, Loss: %lu.\n", instPtr->log.svcRxCnt, pktLoss);
|
||||||
|
DBG_PRINT("Bit Error Rate -- Total:%lu, Error:%lu.\n", svcFSMPtr->bitTotal, svcFSMPtr->bitError);
|
||||||
|
#endif
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} LinkLayer_Service*/
|
||||||
|
/** @} LinkLayer*/
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file time_sync.c
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief DF Linklayer time sync implementation file.
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LinkLayer_TimeSync
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "link_layer.h"
|
||||||
|
#include "../phy_layer/phy_layer.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
/************************** Constant Definitions *****************************/
|
||||||
|
/***************** Macros (Inline Functions) Definitions *********************/
|
||||||
|
/**************************** Type Definitions *******************************/
|
||||||
|
/************************** Variable Definitions *****************************/
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Get time deviation to the specified frame and slot number.
|
||||||
|
*
|
||||||
|
* @param instPtr a pointer to linklayer layer instance
|
||||||
|
* @param frameNum
|
||||||
|
* @param slotNum
|
||||||
|
* @param relative
|
||||||
|
* @param timeDev
|
||||||
|
*
|
||||||
|
* @return SUCCESS
|
||||||
|
* EIGNORE there is no received frame
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t L2_GetTimeDeviation(L2_INST *instPtr, uint32_t frameNum, uint32_t slotNum, bool relative, int64_t *timeDev)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
ASSERT(timeDev != NULL);
|
||||||
|
L1_FRAME_TYPE lastRecvdFrame;
|
||||||
|
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
||||||
|
lastRecvdFrame = Phy_GetLastRecvFrameType(phyRef);
|
||||||
|
if (lastRecvdFrame == L1_NONE_FRAME)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Invalid TimeAlign operation, no frame was received.");
|
||||||
|
return EIGNORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG_INFO("Starting TimeAlign operation...\n");
|
||||||
|
// read nextSendTime from physical layer
|
||||||
|
uint64_t currTime, expectTime;
|
||||||
|
TIME_WORD timeStamp;
|
||||||
|
expectTime = ((uint64_t)(frameNum * L2_SLOTS_PER_FRAME + slotNum)) * TIME_FRAC_MAX;
|
||||||
|
expectTime += Phy_GetTimeComp(lastRecvdFrame);
|
||||||
|
|
||||||
|
if (relative)
|
||||||
|
{
|
||||||
|
expectTime += (uint64_t)instPtr->netStartTime * L2_SLOTS_PER_FRAME * TIME_FRAC_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
Phy_GetLastReceivedFrameSyncTimeStamp(phyRef, &timeStamp);
|
||||||
|
currTime = (uint64_t)timeStamp.frac_part;
|
||||||
|
currTime += ((uint64_t)timeStamp.int_part) * TIME_FRAC_MAX;
|
||||||
|
|
||||||
|
*timeDev = (int64_t)(expectTime - currTime);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Implement time adjustment by applying time deviation.
|
||||||
|
*
|
||||||
|
* @param instPtr a pointer to linklayer layer instance
|
||||||
|
* @param timeDev
|
||||||
|
*
|
||||||
|
* @return NONE
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void L2_TimeAdjust(L2_INST *instPtr, const int64_t *timeDev)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
ASSERT(timeDev != NULL);
|
||||||
|
TIME_WORD slotTimerAdjmet;
|
||||||
|
slotTimerAdjmet.int_part = (uint32_t)(*timeDev / TIME_FRAC_MAX);
|
||||||
|
slotTimerAdjmet.frac_part = (uint32_t)(*timeDev % TIME_FRAC_MAX);
|
||||||
|
TimeCtrl_TimeAdjust(instPtr->config.tmcInstPtr, &slotTimerAdjmet, TM_ADJ_ADD);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} LinkLayer_TimeSync*/
|
||||||
|
|
||||||
|
/** @} LinkLayer*/
|
||||||
@@ -0,0 +1,428 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file phy_antenna.h
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief Physical layer control antenna configuration functions.
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-04-24
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup PhysicalLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup PhysicalLayer_AntennaControl
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "error.h"
|
||||||
|
#include "phy_layer.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name PhysicalLayer_AntennaConfig_Constants
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ANT_PI 3.14159265358979323846
|
||||||
|
|
||||||
|
#define ANT_COINFO_HEAD 0xAA
|
||||||
|
#define ANT_COINFO_TAIL 0xCC
|
||||||
|
|
||||||
|
#define CTRL_WORD_DEFAULT 0x00
|
||||||
|
|
||||||
|
#define ANT_MODE_BEAM_MASK 0xF0
|
||||||
|
#define ANT_BEAM_NARROR 0x00 // 8
|
||||||
|
#define ANT_BEAM_SUBNARROR_0 0x10 // 25
|
||||||
|
#define ANT_BEAM_SUBNARROR_1 0x20 // 60
|
||||||
|
#define ANT_BEAM_WIDE 0x30 // 120
|
||||||
|
|
||||||
|
#define ANT_MODE_POWER_MASK 0x0F
|
||||||
|
#define ANT_POWER_FULL 0x00
|
||||||
|
#define ANT_POWER_LOW 0x04
|
||||||
|
#define ANT_POWER_STANDBY 0x0F
|
||||||
|
#define ATN_MODE_SILENT (ANT_BEAM_SUBNARROR_0 | ANT_POWER_STANDBY)
|
||||||
|
#define ATN_MODE_LOWPOWER (ANT_BEAM_SUBNARROR_0 | ANT_POWER_LOW)
|
||||||
|
#define ATN_MODE_FULLPOWER (ANT_BEAM_SUBNARROR_0 | ANT_POWER_FULL)
|
||||||
|
#define ATN_MODE_DEFAULT ATN_MODE_SILENT
|
||||||
|
|
||||||
|
#define DEFAULT_CENTRTAL_FREQ 0x06D7 // 26.25GHz
|
||||||
|
|
||||||
|
#define RXTXMODE_RX 0x00
|
||||||
|
#define RXTXMODE_TX 0x01
|
||||||
|
|
||||||
|
#define RXTXMODE_DEFAULT 0x00
|
||||||
|
|
||||||
|
#define CALIBRMODE_NORMAL 0x00
|
||||||
|
#define CALIBRMODE_SINGLE_TR_CAL 0x01
|
||||||
|
|
||||||
|
#define RF_CTRL_DEFAULT 0x00
|
||||||
|
|
||||||
|
// Pair by regex
|
||||||
|
// Regex: (([0-9]+, ){8})
|
||||||
|
const uint16_t freqTable[L1_FRAME_MAX_HOPS] =
|
||||||
|
{
|
||||||
|
1084U, 1097U, 1110U, 1123U, 1136U, 1149U, 1162U, 1175U,
|
||||||
|
1188U, 1201U, 1214U, 1227U, 1240U, 1253U, 1266U, 1279U,
|
||||||
|
1292U, 1305U, 1318U, 1331U, 1344U, 1357U, 1370U, 1383U,
|
||||||
|
1396U, 1409U, 1422U, 1435U, 1448U, 1461U, 1474U, 1487U,
|
||||||
|
1500U, 1513U, 1526U, 1539U, 1552U, 1565U, 1578U, 1591U,
|
||||||
|
1604U, 1617U, 1630U, 1643U, 1656U, 1669U, 1682U, 1695U,
|
||||||
|
1708U, 1721U, 1734U, 1747U, 1760U, 1773U, 1786U, 1799U,
|
||||||
|
1812U, 1825U, 1838U, 1851U, 1864U, 1877U, 1890U, 1903U,
|
||||||
|
1916U, 1929U, 1942U, 1955U, 1968U, 1981U, 1994U, 2007U,
|
||||||
|
2020U, 2033U, 2046U, 2059U, 2072U, 2085U, 2098U, 2111U,
|
||||||
|
2124U
|
||||||
|
};
|
||||||
|
|
||||||
|
const int16_t antCalTable[L1_FRAME_MAX_HOPS][L1_ANT_NUM_CH] =
|
||||||
|
//Antenna-JG01
|
||||||
|
{
|
||||||
|
{ 0, 2525, -7533, -6846}, { 0, 12726, -7818, -6860},
|
||||||
|
{ 0, 2490, -7836, -6907}, { 0, 4479, -7716, -6837},
|
||||||
|
{ 0, 6409, -7770, -6776}, { 0, 14616, -7977, -6816},
|
||||||
|
{ 0, -22557, -8002, -6911}, { 0, -22587, -8121, -6918},
|
||||||
|
{ 0, -1124, -8123, -7030}, { 0, -152, -8219, -7042},
|
||||||
|
{ 0, 1823, -8209, -7130}, { 0, 1790, -8290, -7214},
|
||||||
|
{ 0, 1669, -8362, -7283}, { 0, 1634, -8459, -7276},
|
||||||
|
{ 0, 1615, -8315, -7415}, { 0, 1698, -8168, -7366},
|
||||||
|
{ 0, 1535, -8285, -7520}, { 0, 1619, -8285, -7532},
|
||||||
|
{ 0, 1609, -8201, -7693}, { 0, 1671, -8145, -7769},
|
||||||
|
{ 0, 1676, -8135, -7805}, { 0, 951, -10279, -8871},
|
||||||
|
{ 0, 976, -10235, -8978}, { 0, 1118, -10127, -9019},
|
||||||
|
{ 0, 1175, -10003, -9007}, { 0, 1386, -9847, -9039},
|
||||||
|
{ 0, 1535, -9572, -9058}, { 0, 1729, -9493, -9006},
|
||||||
|
{ 0, -1158, -9312, -9003}, { 0, 23771, -9147, -8928},
|
||||||
|
{ 0, 20733, -9074, -8924}, { 0, 2455, -8841, -8886},
|
||||||
|
{ 0, 2622, -8718, -8735}, { 0, 2791, -8615, -8705},
|
||||||
|
{ 0, 2861, -8168, -8331}, { 0, 3076, -8091, -8218},
|
||||||
|
{ 0, 3257, -8046, -8100}, { 0, 3331, -7923, -8073},
|
||||||
|
{ 0, 3396, -7826, -7994}, { 0, 3478, -7842, -8016},
|
||||||
|
{ 0, 3518, -7846, -7765}, { 0, 3585, -7753, -7715},
|
||||||
|
{ 0, 150, -8145, -8591}, { 0, 192, -8090, -8570},
|
||||||
|
{ 0, 207, -8150, -8597}, { 0, 178, -8142, -8656},
|
||||||
|
{ 0, 89, -8557, -8688}, { 0, 107, -8614, -8733},
|
||||||
|
{ 0, 194, -8605, -8782}, { 0, 153, -8655, -8881},
|
||||||
|
{ 0, 70, -8615, -8952}, { 0, 35, -8596, -9148},
|
||||||
|
{ 0, 49, -8636, -9286}, { 0, 6, -8587, -9435},
|
||||||
|
{ 0, -51, -8540, -9549}, { 0, -65, -8588, -9700},
|
||||||
|
{ 0, -55, -8503, -9820}, { 0, -20, -8414, -9907},
|
||||||
|
{ 0, -112, -8481, -10031}, { 0, -69, -8535, -10185},
|
||||||
|
{ 0, 2, -8550, -10052}, { 0, -1, -8493, -10291},
|
||||||
|
{ 0, -73, -8441, -10380}, { 0, 1958, -6930, -8295},
|
||||||
|
{ 0, -1148, -6939, -8396}, { 0, 1915, -6784, -8370},
|
||||||
|
{ 0, 1871, -6970, -8514}, { 0, 1821, -6974, -8387},
|
||||||
|
{ 0, 1781, -6906, -8431}, { 0, 1736, -6897, -8462},
|
||||||
|
{ 0, 1664, -7024, -8377}, { 0, 1629, -7127, -8436},
|
||||||
|
{ 0, 1603, -7148, -8528}, { 0, 1577, -7198, -8500},
|
||||||
|
{ 0, 1528, -7311, -8512}, { 0, 1577, -7390, -8570},
|
||||||
|
{ 0, 1616, -7436, -8572}, { 0, 1589, -7597, -8590},
|
||||||
|
{ 0, 1722, -7550, -8568}, { 0, 1741, -7691, -8449},
|
||||||
|
{ 0, 1767, -7775, -8328},
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t hopPattern_2KBPS_20MS[L1_FRAME_2KBPS_20MS_HOPS] =
|
||||||
|
{
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t hopPattern_2KBPS_100MS[L1_FRAME_2KBPS_100MS_HOPS] =
|
||||||
|
{
|
||||||
|
0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U,
|
||||||
|
8U, 9U, 10U, 11U, 12U, 13U, 14U, 15U,
|
||||||
|
16U, 17U, 18U, 19U, 20U, 21U, 22U, 23U,
|
||||||
|
24U, 25U, 26U, 27U, 28U, 29U, 30U, 31U,
|
||||||
|
32U, 33U, 34U, 35U, 36U, 37U, 38U, 39U,
|
||||||
|
40U, 41U, 42U, 43U, 44U, 45U, 46U, 47U,
|
||||||
|
48U, 49U, 50U, 51U, 52U, 53U, 54U, 55U,
|
||||||
|
56U, 57U, 58U, 59U, 60U, 61U, 62U, 63U,
|
||||||
|
64U, 65U, 66U, 67U, 68U, 69U, 70U, 71U,
|
||||||
|
72U, 73U, 74U, 75U, 76U, 77U, 78U, 79U,
|
||||||
|
80U
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t hopPattern_10KBPS_10MS[L1_FRAME_10KBPS_10MS_HOPS] =
|
||||||
|
{
|
||||||
|
80U
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t hopPattern_10KBPS_20MS[L1_FRAME_10KBPS_20MS_HOPS] =
|
||||||
|
{
|
||||||
|
80U, 1U, 2U, 3U, 4U, 5U, 6U, 7U,
|
||||||
|
8U, 9U, 10U
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t hopPattern_40KBPS_10MS[L1_FRAME_40KBPS_10MS_HOPS] =
|
||||||
|
{
|
||||||
|
0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U,
|
||||||
|
8U,
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t hopPattern_40KBPS_20MS[L1_FRAME_40KBPS_20MS_HOPS] =
|
||||||
|
{
|
||||||
|
0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U,
|
||||||
|
8U, 9U, 10U, 11U, 12U, 13U, 14U, 15U,
|
||||||
|
16U, 17U, 18U
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t hopPattern_200KBPS_5MS[L1_FRAME_200KBPS_5MS_HOPS] =
|
||||||
|
{
|
||||||
|
0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U,
|
||||||
|
8U, 9U, 10U, 11U, 12U, 13U, 14U, 15U,
|
||||||
|
16U, 17U, 18U, 19U
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t hopPattern_1M2BPS_5MS[L1_FRAME_1M2BPS_5MS_HOPS] =
|
||||||
|
{
|
||||||
|
0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U,
|
||||||
|
8U, 9U, 10U, 11U, 12U, 13U, 14U, 15U,
|
||||||
|
16U, 17U, 18U, 19U
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @} PhysicalLayer_AntennaConfig_Constants*/
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Initialize antenna configurations (load preset values)
|
||||||
|
*
|
||||||
|
* @param antConfig pointer to antenna configure
|
||||||
|
*
|
||||||
|
* @return None.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void Phy_AntConfigInit(PHY_ANT_CONFIG *antConfig)
|
||||||
|
{
|
||||||
|
ASSERT(antConfig != NULL);
|
||||||
|
|
||||||
|
antConfig->ctrlWord = CTRL_WORD_DEFAULT;
|
||||||
|
antConfig->antMode = ATN_MODE_DEFAULT;
|
||||||
|
|
||||||
|
// FIXME: Dummy default value.
|
||||||
|
// off axis angle setting
|
||||||
|
antConfig->oaxis[0] = 0;
|
||||||
|
antConfig->oaxis[1] = 0;
|
||||||
|
// round axis angle setting
|
||||||
|
antConfig->raxis[0] = 0;
|
||||||
|
antConfig->raxis[1] = 0;
|
||||||
|
// ***********************
|
||||||
|
|
||||||
|
antConfig->antFreq[0] = (uint8_t)(DEFAULT_CENTRTAL_FREQ);
|
||||||
|
antConfig->antFreq[1] = (uint8_t)(DEFAULT_CENTRTAL_FREQ >> 8);
|
||||||
|
|
||||||
|
// FIXME: Dummy default value.
|
||||||
|
// trSelect
|
||||||
|
antConfig->trSlect = 0;
|
||||||
|
// Antenna attenuation setting
|
||||||
|
antConfig->antAtt = 0;
|
||||||
|
// phase setting
|
||||||
|
antConfig->phase = 0;
|
||||||
|
// ***********************
|
||||||
|
|
||||||
|
antConfig->rxtxMode = RXTXMODE_DEFAULT;
|
||||||
|
antConfig->calibrMode = CALIBRMODE_NORMAL;
|
||||||
|
antConfig->antReserved = 0x00;
|
||||||
|
|
||||||
|
// FIXME: Dummy default value.
|
||||||
|
// RF mode control
|
||||||
|
antConfig->rfCtrl = RF_CTRL_DEFAULT;
|
||||||
|
// RF frequency
|
||||||
|
antConfig->rfFreq[0] = (uint8_t)(DEFAULT_CENTRTAL_FREQ);
|
||||||
|
antConfig->rfFreq[1] = (uint8_t)(DEFAULT_CENTRTAL_FREQ >> 8);
|
||||||
|
// RF MGC control
|
||||||
|
antConfig->rfTxMgc = 0;
|
||||||
|
// RF channel 1&2 calibration mgc
|
||||||
|
antConfig->rf12CalMgc = 0;
|
||||||
|
// RF channel 2&3 calibration mgc
|
||||||
|
antConfig->rf34CalMgc = 0;
|
||||||
|
// Receive channel 1-4 MGC
|
||||||
|
antConfig->rcvMgc = 0;
|
||||||
|
antConfig->rfReserved0 = 0x00;
|
||||||
|
antConfig->rfReserved1 = 0x00;
|
||||||
|
// ***********************
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Update antenna power mode setting
|
||||||
|
*
|
||||||
|
* @param instPtr pointer to physical layer instance
|
||||||
|
* @param mode new antenna mode
|
||||||
|
*
|
||||||
|
* @return None.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void Phy_AntConfigMode(PHY_INST *instPtr, PHY_ANT_MODE mode)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
uint8_t config = instPtr->antConfig.antMode & ANT_MODE_BEAM_MASK;
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case PHY_ANT_MODE_STANDBY:
|
||||||
|
config |= ANT_POWER_STANDBY;
|
||||||
|
break;
|
||||||
|
case PHY_ANT_MODE_POWER_LOW:
|
||||||
|
config |= ANT_POWER_LOW;
|
||||||
|
break;
|
||||||
|
case PHY_ANT_MODE_POWER_FULL:
|
||||||
|
config |= ANT_POWER_FULL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBG_ERROR("Unknown antenna mode: %" PRIu8 ", remain previous mode.\n", mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
instPtr->phyLog.antMode = mode;
|
||||||
|
instPtr->antConfig.antMode = config;
|
||||||
|
// Sync logs to system monitor
|
||||||
|
SysMonitor_UpdatePhysicalLayerLog(&(instPtr->phyLog));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Update antenna beam table
|
||||||
|
*
|
||||||
|
* @param instPtr pointer to physical layer instance
|
||||||
|
* @param table new beam table
|
||||||
|
* @param offset table offset
|
||||||
|
*
|
||||||
|
* @return None
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void Phy_SetBeamTable(PHY_INST *instPtr, PHY_ANT_ANGLE *table, uint32_t offset)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
ASSERT(table != NULL);
|
||||||
|
for (int i = 0; i < L1_NUM_ANT_NRRW_PATTERN; i++)
|
||||||
|
{
|
||||||
|
instPtr->antNrrwPattern[i] = table[(i + offset) % L1_NUM_ANT_NRRW_PATTERN];
|
||||||
|
}
|
||||||
|
memcpy((uint32_t *)instPtr->antInfoAddr, instPtr->antNrrwPattern,
|
||||||
|
L1_NUM_ANT_NRRW_PATTERN * sizeof(PHY_ANT_ANGLE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Update antenna point direction using predefined beam table
|
||||||
|
*
|
||||||
|
* @param instPtr pointer to physical layer instance
|
||||||
|
* @param beamNo new beam index
|
||||||
|
*
|
||||||
|
* @return SUCCESS.
|
||||||
|
* FAILURE beamNo exceeds the table size
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t Phy_SetBeamNo(PHY_INST *instPtr, size_t beamNo, PHY_ANT_BEAM_WIDTH beamWidth)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
|
||||||
|
if (beamWidth == PHY_ANT_BEAM_16)
|
||||||
|
{
|
||||||
|
if (beamNo >= L1_NUM_ANT_NRRW_PATTERN)
|
||||||
|
{
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
instPtr->beamNo.next = beamNo;
|
||||||
|
instPtr->antConfig.oaxis[0] = (uint8_t)(instPtr->antNrrwPattern[beamNo].oaxis >> 8);
|
||||||
|
instPtr->antConfig.oaxis[1] = (uint8_t)(instPtr->antNrrwPattern[beamNo].oaxis);
|
||||||
|
instPtr->antConfig.raxis[0] = (uint8_t)(instPtr->antNrrwPattern[beamNo].raxis >> 8);
|
||||||
|
instPtr->antConfig.raxis[1] = (uint8_t)(instPtr->antNrrwPattern[beamNo].raxis);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Beam number assign not support.
|
||||||
|
// Assign default angle (0,0)
|
||||||
|
instPtr->beamNo.next = 0;
|
||||||
|
instPtr->antConfig.oaxis[0] = 0;
|
||||||
|
instPtr->antConfig.oaxis[1] = 0;
|
||||||
|
instPtr->antConfig.raxis[0] = 0;
|
||||||
|
instPtr->antConfig.raxis[1] = 0;
|
||||||
|
DBG_WARNING("Using default beam number...\n");
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Update antenna beam width setting
|
||||||
|
*
|
||||||
|
* @param instPtr pointer to physical layer instance
|
||||||
|
* @param beamWidth new beam width
|
||||||
|
*
|
||||||
|
* @return SUCCESS.
|
||||||
|
* EPARAM
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t Phy_SetBeamWidth(PHY_INST *instPtr, PHY_ANT_BEAM_WIDTH beamWidth)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
uint8_t beamConfig = instPtr->antConfig.antMode & (~ANT_MODE_BEAM_MASK);
|
||||||
|
switch (beamWidth)
|
||||||
|
{
|
||||||
|
case PHY_ANT_BEAM_120:
|
||||||
|
beamConfig |= ANT_BEAM_WIDE;
|
||||||
|
break;
|
||||||
|
case PHY_ANT_BEAM_60:
|
||||||
|
beamConfig |= ANT_BEAM_SUBNARROR_1;
|
||||||
|
break;
|
||||||
|
case PHY_ANT_BEAM_25:
|
||||||
|
beamConfig |= ANT_BEAM_SUBNARROR_0;
|
||||||
|
break;
|
||||||
|
case PHY_ANT_BEAM_16:
|
||||||
|
beamConfig |= ANT_BEAM_NARROR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBG_ERROR("Beam width code: 0x%08X is illegal.\n\r", beamWidth);
|
||||||
|
return EPARAM;
|
||||||
|
}
|
||||||
|
instPtr->antConfig.antMode = beamConfig;
|
||||||
|
instPtr->beamWd.next = beamWidth;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Set antenna to a specific direction
|
||||||
|
*
|
||||||
|
* @param instPtr pointer to physical layer instance
|
||||||
|
* @param offAx elevation angle
|
||||||
|
* @param rndAx azimuth angle
|
||||||
|
*
|
||||||
|
* @return SUCCESS.
|
||||||
|
* EPARAM - the direction is exceeds predefined range
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t Phy_SetBeamAngle(PHY_INST *instPtr, double offAx, double rndAx)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
uint16_t offAxDeg = 0;
|
||||||
|
uint16_t rndAxDeg = 0;
|
||||||
|
offAxDeg = (offAx >= 0) ? (((int32_t)(offAx * 180.0 / ANT_PI)) % 360) : (((int32_t)(offAx * 180.0 / ANT_PI)) % 360 + 360);
|
||||||
|
rndAxDeg = (rndAx >= 0) ? (((int32_t)(rndAx * 180.0 / ANT_PI)) % 360) : (((int32_t)(rndAx * 180.0 / ANT_PI)) % 360 + 360);
|
||||||
|
if (offAxDeg > 60)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Angle out of range, off axis angle: %" PRIu16 " (should be 0~60), round axis angle: %" PRIu16 " (should be 0~360).\n",
|
||||||
|
offAxDeg, rndAxDeg);
|
||||||
|
return EPARAM;
|
||||||
|
}
|
||||||
|
offAxDeg = offAxDeg * 10;
|
||||||
|
rndAxDeg = rndAxDeg * 10;
|
||||||
|
instPtr->antConfig.oaxis[0] = (uint8_t)(offAxDeg >> 8);
|
||||||
|
instPtr->antConfig.oaxis[1] = (uint8_t)offAxDeg;
|
||||||
|
instPtr->antConfig.raxis[0] = (uint8_t)(rndAxDeg >> 8);
|
||||||
|
instPtr->antConfig.raxis[1] = (uint8_t)rndAxDeg;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} PhysicalLayer_AntennaControl*/
|
||||||
|
|
||||||
|
/** @} PhysicalLayer*/
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,315 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file phy_layer.c
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief Physical layer control header file.
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-04-24
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup PhysicalLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PHY_CTRL_H_
|
||||||
|
#define PHY_CTRL_H_
|
||||||
|
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "common.h"
|
||||||
|
#ifndef EMULATION
|
||||||
|
#include "xbram.h"
|
||||||
|
#include "xadcps.h"
|
||||||
|
#include "../config/app_config.h"
|
||||||
|
#endif
|
||||||
|
#include "../../system_monitor.h"
|
||||||
|
#include "../../time_ctrl/time_ctrl.h"
|
||||||
|
/************************** Constant Definitions *****************************/
|
||||||
|
/**
|
||||||
|
* @name PhysicalLayer_Common_Constant
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define L1_NUM_ANT_NRRW_PATTERN 37U
|
||||||
|
#define L1_INIT_BEAM_NO 0U
|
||||||
|
#define L1_INIT_ANT_WD PHY_ANT_BEAM_120
|
||||||
|
#define L1_ANT_NUM_CH 4U
|
||||||
|
|
||||||
|
#define L1_FRAME_NONE_LEN UINT32_MAX // byte
|
||||||
|
#define L1_FRAME_NONE_COMP UINT32_MAX // *10ns(Timer_L)
|
||||||
|
#define L1_FRAME_NONE_HOPS UINT32_MAX
|
||||||
|
#define L1_FRAME_MAX_HOPS 81U
|
||||||
|
#define L1_FRAME_2KBPS_20MS_HOPS 1U
|
||||||
|
#define L1_FRAME_2KBPS_100MS_HOPS 81U
|
||||||
|
#define L1_FRAME_10KBPS_10MS_HOPS 1U
|
||||||
|
#define L1_FRAME_10KBPS_20MS_HOPS 11U
|
||||||
|
#define L1_FRAME_40KBPS_20MS_HOPS 19U
|
||||||
|
#define L1_FRAME_40KBPS_10MS_HOPS 9U
|
||||||
|
#define L1_FRAME_200KBPS_5MS_HOPS 20U
|
||||||
|
#define L1_FRAME_1M2BPS_5MS_HOPS 20U
|
||||||
|
#define PHY_LOG_EXPIRE 40U // 50*5ms
|
||||||
|
/** @} */
|
||||||
|
/***************** Macros (Inline Functions) Definitions *********************/
|
||||||
|
/**************************** Type Definitions *******************************/
|
||||||
|
/**
|
||||||
|
* @enum L1_FRAME_TYPE
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
L1_NONE_FRAME = 0,
|
||||||
|
L1_2KBPS_20MS_FRAME = 1,
|
||||||
|
L1_2KBPS_100MS_FRAME = 2,
|
||||||
|
L1_10KBPS_10MS_FRAME = 3,
|
||||||
|
L1_10KBPS_20MS_FRAME = 4,
|
||||||
|
L1_40KBPS_20MS_FRAME = 5,
|
||||||
|
L1_40KBPS_10MS_FRAME = 6,
|
||||||
|
L1_200KBPS_5MS_FRAME = 7,
|
||||||
|
L1_1M2BPS_5MS_FRAME = 8
|
||||||
|
} L1_FRAME_TYPE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct PHY_ANT_CONFIG
|
||||||
|
* @brief PhysicalLayer antenna config
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/*** Ant Control ***/
|
||||||
|
uint8_t ctrlWord; ///< Antenna control frame head 0xAA\n
|
||||||
|
/// default 0, reserved for further use
|
||||||
|
uint8_t antMode; ///< high 4 bits specified beam mode.\n
|
||||||
|
/// low 4 bits specified power control
|
||||||
|
uint8_t oaxis[2]; ///< off-axis angle range is 0~60 \n
|
||||||
|
/// 0.1 degree each LSB
|
||||||
|
uint8_t raxis[2]; ///< round-axis angle range is 0~360, \n
|
||||||
|
/// 0.1 degree each LSB
|
||||||
|
uint8_t antFreq[2]; ///< 0~3500Mhz, step 1MHz
|
||||||
|
uint8_t trSlect; ///< in single tr mode, 0~63 specified tr channel \n
|
||||||
|
/// in single subarray mode, 0~3 specified the subarray
|
||||||
|
/// ! Only in debug mode!
|
||||||
|
uint8_t antAtt; ///< Antenna attenuation 0~31, 0.5dB each LSB, Only in debug mode
|
||||||
|
uint8_t phase; ///< 0~63, 5.625 degree each LSB, Only in debug mode
|
||||||
|
uint8_t rxtxMode; ///< Only for debug \n
|
||||||
|
/// default 0x00
|
||||||
|
uint8_t calibrMode; ///< 0x00 Normal, 0x01 single tr calibration
|
||||||
|
uint8_t antReserved; ///< reserved for further use
|
||||||
|
|
||||||
|
/*** RF Control ***/
|
||||||
|
uint8_t rfCtrl; ///< [7:4]RF enable: 0-On, 1-Off(Default); [3:0]Work mode: 0(default)
|
||||||
|
uint8_t rfFreq[2]; ///< 0~3500Mhz, step 1MHz
|
||||||
|
uint8_t rfTxMgc; ///< RF MGC control: 0~31, 1dB each LSB
|
||||||
|
uint8_t rf12CalMgc; ///< RF channel 1&2 calibration mgc\n
|
||||||
|
/// [7:4] Channle1 - max 15db, 1dB each LSB \n
|
||||||
|
/// [3:0] Channle2 - max 15db, 1dB each LSB
|
||||||
|
uint8_t rf34CalMgc; ///< RF channel 3&4 calibration mgc\n
|
||||||
|
/// [7:4] Channle3 - max 15db, 1dB each LSB
|
||||||
|
/// [3:0] Channle4 - max 15db, 1dB each LSB
|
||||||
|
uint8_t rcvMgc; ///< Receive channel 1-4 MGC: 0~31, 1dB each LSB
|
||||||
|
uint8_t rfMonitor; ///< Receive monitor, 0-normal, 1-switch to monitor port
|
||||||
|
uint8_t rfReserved0; ///< reserved for further use
|
||||||
|
uint8_t rfReserved1; ///< reserved for further use
|
||||||
|
uint8_t ch0Cal[2];
|
||||||
|
uint8_t ch1Cal[2];
|
||||||
|
uint8_t ch2Cal[2];
|
||||||
|
uint8_t ch3Cal[2];
|
||||||
|
} PHY_ANT_CONFIG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct PHY_ANT_ANGLE
|
||||||
|
* @brief Describe the PhysicalLayer antenna angle
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t oaxis; ///< off-axis angle range is 0~60
|
||||||
|
/// 0.1 degree each LSB
|
||||||
|
uint16_t raxis; ///< round-axis angle range is 0~360
|
||||||
|
/// 0.1 degree each LSB
|
||||||
|
} PHY_ANT_ANGLE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum PHY_TIME_WORD_TYPE
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PHY_TIME_WORD_NONE = 0,
|
||||||
|
PHY_TIME_WORD_POLL = 1,
|
||||||
|
PHY_TIME_WORD_LISTEN_TIMEOUT = 2
|
||||||
|
} PHY_TIME_WORD_TYPE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum PHY_ANT_BEAM_WIDTH
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PHY_ANT_BEAM_NONE = 0,
|
||||||
|
PHY_ANT_BEAM_120 = 1,
|
||||||
|
PHY_ANT_BEAM_60 = 2,
|
||||||
|
PHY_ANT_BEAM_25 = 3,
|
||||||
|
PHY_ANT_BEAM_16 = 4
|
||||||
|
} PHY_ANT_BEAM_WIDTH;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum PHY_TOR_TYPE
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PHY_TOR_SUSPEND = 0,
|
||||||
|
PHY_TOR_TX = 1,
|
||||||
|
PHY_TOR_RX = 2
|
||||||
|
} PHY_TOR_TYPE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum PHY_MODE
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PHY_MODE_NONE = 0,
|
||||||
|
PHY_MODE_LISTEN = 1,
|
||||||
|
PHY_MODE_SCHEDULE = 2,
|
||||||
|
PHY_MODE_PULL = 3
|
||||||
|
} PHY_MODE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum PHY_ANT_MODE
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
PHY_ANT_MODE_NONE = 0,
|
||||||
|
PHY_ANT_MODE_STANDBY = 1,
|
||||||
|
PHY_ANT_MODE_POWER_LOW = 2,
|
||||||
|
PHY_ANT_MODE_POWER_FULL = 3,
|
||||||
|
} PHY_ANT_MODE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct PHY_RCD
|
||||||
|
* @brief Physical Layer recode buffer
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int32_t last;
|
||||||
|
int32_t curr;
|
||||||
|
int32_t next;
|
||||||
|
} PHY_RCD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct PHY_CONFIG
|
||||||
|
* @brief struct holds all physical layer initialization parameters
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t devId; ///< device ID
|
||||||
|
uint32_t txBramId; ///< tx bram ID
|
||||||
|
uint32_t rxBramId; ///< rx bram ID
|
||||||
|
uint32_t antBramId; ///< antenna config bram ID
|
||||||
|
uint32_t antInfoBramId; ///< antenna beam info bram ID
|
||||||
|
uint32_t hwXadcId; ///< hardware xadc device ID
|
||||||
|
uintptr_t baseAddr; ///< Physical layer controller base address
|
||||||
|
#ifndef EMULATION
|
||||||
|
uint8_t (*get_clk_state)(void); ///< function handle returns hardware clock state
|
||||||
|
uint8_t (*get_ad_lock_state)(void); ///< function handle returns adc lock state
|
||||||
|
int8_t (*get_ad0_temp)(void); ///< function handle returns adc0 temperature state
|
||||||
|
int8_t (*get_ad1_temp)(void); ///< function handle returns adc1 temperature state
|
||||||
|
#endif
|
||||||
|
} PHY_CONFIG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct PHY_INST
|
||||||
|
* @brief Physical Layer operating instance
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
PHY_CONFIG phyCofig; ///< physical layer configuration parameters
|
||||||
|
uintptr_t recvDataAddr; ///< receive data bram address
|
||||||
|
uintptr_t sendDataAddr; ///< send data bram address
|
||||||
|
uintptr_t antConfigAddr; ///< antenna config data bram address
|
||||||
|
uintptr_t antInfoAddr; ///< antenna beam info data bram address
|
||||||
|
bool isPhyEn; ///< indicates if physical layer running
|
||||||
|
bool isAcq; ///< indicates if last reception acquisition success
|
||||||
|
bool isFrameSync; ///< indicates if last reception frame sync success
|
||||||
|
bool isDecode; ///< indicates if last reception decode success
|
||||||
|
bool isValid; ///< indicates if last reception frame data valid (crc check pass)
|
||||||
|
TIME_WORD recvSlotTime; ///< last slot start time stamp
|
||||||
|
TIME_WORD recvFsTime; ///< last frame sync time stamp
|
||||||
|
PHY_RCD beamNo; ///< beam number record
|
||||||
|
PHY_RCD beamWd; ///< beam width record
|
||||||
|
PHY_RCD tor; ///< tx rx state record
|
||||||
|
PHY_RCD frameType; ///< frame type record
|
||||||
|
uint32_t sendDataOffset; ///< antenna configuration bram offset (to implement ping-pong data flow)
|
||||||
|
uint32_t antConfigOffset; ///< antenna configuration bram offset (to implement ping-pong data flow)
|
||||||
|
PHY_ANT_CONFIG antConfig; ///< antenna configuration pointer
|
||||||
|
#ifndef EMULATION
|
||||||
|
XAdcPs hwXadc; ///< hardware Xadc instance
|
||||||
|
#endif
|
||||||
|
PHY_ANT_ANGLE antNrrwPattern[L1_NUM_ANT_NRRW_PATTERN]; ///< antenna beam scan pattern
|
||||||
|
HWSTATE hwSate; ///< hardware state log
|
||||||
|
PHYLOG phyLog; ///< physical state log
|
||||||
|
uint32_t lastLogTime; /// physical state log time stamp
|
||||||
|
} PHY_INST;
|
||||||
|
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup PhysicalLayer_Main
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
int32_t Phy_Init(PHY_INST **instPtr, PHY_CONFIG *phyConfig);
|
||||||
|
void Phy_Destroy(PHY_INST *instPtr);
|
||||||
|
void Phy_Start(PHY_INST *instPtr);
|
||||||
|
void Phy_Halt(PHY_INST *instPtr);
|
||||||
|
|
||||||
|
int32_t Phy_SetMode(PHY_INST *instPtr, PHY_MODE modeCod);
|
||||||
|
int32_t Phy_SetTimeWord(PHY_INST *instPtr, const TIME_WORD *tmWord, PHY_TIME_WORD_TYPE tmType);
|
||||||
|
int32_t Phy_SetupNextSlot(PHY_INST *instPtr, PHY_TOR_TYPE txrxMode, L1_FRAME_TYPE frameType, uint8_t *dataBuff);
|
||||||
|
void Phy_UpdateState(PHY_INST *instPtr);
|
||||||
|
void Phy_PeekRecvData(PHY_INST *instPtr, uint8_t *dataBuff);
|
||||||
|
void Phy_RetrieveRecvData(PHY_INST *instPtr, uint8_t *dataBuff);
|
||||||
|
void Phy_UpdateLogging(PHY_INST *instPtr);
|
||||||
|
void Phy_RefreshHwSate(PHY_INST *instPtr);
|
||||||
|
/** @} PhysicalLayer_Main*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup PhysicalLayer_Utility
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
bool Phy_IsFrameDetected(PHY_INST *instPtr);
|
||||||
|
bool Phy_IsFrameReceived(PHY_INST *instPtr);
|
||||||
|
bool Phy_IsFrameValid(PHY_INST *instPtr);
|
||||||
|
uint32_t Phy_GetFrameLen(L1_FRAME_TYPE frameType);
|
||||||
|
uint32_t Phy_GetHopLength(L1_FRAME_TYPE frameType);
|
||||||
|
uint32_t Phy_GetTimeComp(L1_FRAME_TYPE frameType);
|
||||||
|
L1_FRAME_TYPE Phy_GetLastRecvFrameType(PHY_INST *instPtr);
|
||||||
|
L1_FRAME_TYPE Phy_GetLastSendFrameType(PHY_INST *instPtr);
|
||||||
|
/** @} PhysicalLayer_Utility*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup PhysicalLayer_Receive_Estimations
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
uint8_t Phy_LastScanBeamNo(PHY_INST *instPtr);
|
||||||
|
double Phy_GetFreqEst(PHY_INST *instPtr);
|
||||||
|
double Phy_GetCoarseFreqEst(PHY_INST *instPtr);
|
||||||
|
double Phy_GetFineFreqEst(PHY_INST *instPtr);
|
||||||
|
void Phy_GetFrameSyncTimeStamp(PHY_INST *instPtr, TIME_WORD *frameSyncT);
|
||||||
|
void Phy_GetLastReceivedFrameSyncTimeStamp(PHY_INST *instPtr, TIME_WORD *frameSyncT);
|
||||||
|
void Phy_GetSlotStartTimeStamp(PHY_INST *instPtr, TIME_WORD *slotStart);
|
||||||
|
void Phy_GetLastReceivedSlotStartTimeStamp(PHY_INST *instPtr, TIME_WORD *slotStart);
|
||||||
|
/** @} PhysicalLayer_Receive_Estimations*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup PhysicalLayer_AntennaControl
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
void Phy_AntConfigInit(PHY_ANT_CONFIG *antConfig);
|
||||||
|
void Phy_AntConfigMode(PHY_INST *instPtr, PHY_ANT_MODE mode);
|
||||||
|
void Phy_SetBeamTable(PHY_INST *instPtr, PHY_ANT_ANGLE *table, uint32_t offset);
|
||||||
|
int32_t Phy_SetBeamWidth(PHY_INST *instPtr, PHY_ANT_BEAM_WIDTH beamWidth);
|
||||||
|
int32_t Phy_SetBeamNo(PHY_INST *instPtr, size_t beamNo, PHY_ANT_BEAM_WIDTH beamWidth);
|
||||||
|
int32_t Phy_SetBeamAngle(PHY_INST *phyInstPtr, double offAx, double rndAx);
|
||||||
|
/** @} PhysicalLayer_AntennaControl*/
|
||||||
|
|
||||||
|
#endif // PHY_CTRL_H_
|
||||||
|
|
||||||
|
/** @} PhysicalLayer*/
|
||||||
@@ -0,0 +1,497 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file phy_layer.h
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief Physical layer controller register definition
|
||||||
|
* @version 0.0
|
||||||
|
* @date 2023-04-24
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* @defgroup PhysicalLayer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name PhysicalLayer_REG_Constants
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#ifndef PHY_REG_H_
|
||||||
|
#define PHY_REG_H_
|
||||||
|
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/***************** Macros (Inline Functions) Definitions *********************/
|
||||||
|
#define PhyRead(instPtr, addr) IO_In32((instPtr)->phyCofig.baseAddr + (addr))
|
||||||
|
#define PhyWrite(instPtr, addr, value) IO_Out32((instPtr)->phyCofig.baseAddr + (addr), (value))
|
||||||
|
|
||||||
|
/************************** Constant Definitions *****************************/
|
||||||
|
/**
|
||||||
|
* Register: PHY_MAIN_CTRL
|
||||||
|
*/
|
||||||
|
#define PHY_MAIN_CTRL 0x00000000U
|
||||||
|
#define PHY_MAIN_CTRL_EN_SHIFT 0
|
||||||
|
#define PHY_MAIN_CTRL_EN_WIDTH 1
|
||||||
|
#define PHY_MAIN_CTRL_EN_MASK 0x00000001U
|
||||||
|
#define PHY_MAIN_CTRL_MODE_SHIFT 8
|
||||||
|
#define PHY_MAIN_CTRL_MODE_WIDTH 8
|
||||||
|
#define PHY_MAIN_CTRL_MODE_MASK 0x0000FF00U
|
||||||
|
#define PHY_MAIN_CTRL_NSCAN_SHIFT 16
|
||||||
|
#define PHY_MAIN_CTRL_NSCAN_WIDTH 8
|
||||||
|
#define PHY_MAIN_CTRL_NSCAN_MASK 0x00FF0000U
|
||||||
|
|
||||||
|
#define PHY_MAIN_CTRL_EN_EN 0x00000001U
|
||||||
|
#define PHY_MAIN_CTRL_EN_DSBL 0x00000000U
|
||||||
|
#define PHY_MAIN_CTRL_MODE_NONE 0x00000000U
|
||||||
|
#define PHY_MAIN_CTRL_MODE_LISTEN 0x00000100U
|
||||||
|
#define PHY_MAIN_CTRL_MODE_SCHEDULE 0x00000200U
|
||||||
|
#define PHY_MAIN_CTRL_MODE_PULL 0x00000300U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: TXRX_CTRL
|
||||||
|
*/
|
||||||
|
#define PHY_MODE_CTRL 0x00000004U
|
||||||
|
#define PHY_MODE_CTRL_TOR_SHIFT 0
|
||||||
|
#define PHY_MODE_CTRL_TOR_WIDTH 8
|
||||||
|
#define PHY_MODE_CTRL_TOR_MASK 0x000000FFU
|
||||||
|
#define PHY_MODE_CTRL_FRAME_SHIFT 8
|
||||||
|
#define PHY_MODE_CTRL_FRAME_WIDTH 8
|
||||||
|
#define PHY_MODE_CTRL_FRAME_MASK 0x0000FF00U
|
||||||
|
#define PHY_MODE_CTRL_CRC_SHIFT 8
|
||||||
|
#define PHY_MODE_CTRL_CRC_WIDTH 16
|
||||||
|
#define PHY_MODE_CTRL_CRC_MASK 0x00FF0000U
|
||||||
|
|
||||||
|
#define PHY_MODE_CTRL_TOR_SUSPEND 0x00000000U
|
||||||
|
#define PHY_MODE_CTRL_TOR_TX 0x00000001U
|
||||||
|
#define PHY_MODE_CTRL_TOR_RX 0x00000002U
|
||||||
|
|
||||||
|
#define PHY_MODE_CTRL_FRAME_NONE 0x00000000U
|
||||||
|
#define PHY_MODE_CTRL_FRAME_2KBPS_20MS 0x00000100U
|
||||||
|
#define PHY_MODE_CTRL_FRAME_2KBPS_100MS 0x00000200U
|
||||||
|
#define PHY_MODE_CTRL_FRAME_10KBPS_10MS 0x00000300U // Initial Scan Frame
|
||||||
|
#define PHY_MODE_CTRL_FRAME_10KBPS_20MS 0x00000400U // Benchmark Frame
|
||||||
|
#define PHY_MODE_CTRL_FRAME_40KBPS_20MS 0x00000500U
|
||||||
|
#define PHY_MODE_CTRL_FRAME_40KBPS_10MS 0x00000600U
|
||||||
|
#define PHY_MODE_CTRL_FRAME_200KBPS_5MS 0x00000700U // 2-Way ACQ Frame, Management Frame, Service Frame
|
||||||
|
#define PHY_MODE_CTRL_FRAME_1M2BPS_5MS 0x00000800U // Bistatic Synthetic Aperture Radar Frame
|
||||||
|
|
||||||
|
#define PHY_MODE_CTRL_CRC_EN 0x00010000U
|
||||||
|
#define PHY_MODE_CTRL_CRC_DSBL 0x00000000U
|
||||||
|
/**
|
||||||
|
* Register: POLLTIME_L
|
||||||
|
*/
|
||||||
|
#define POLLTIME_L 0x00000008U
|
||||||
|
#define POLLTIME_L_SHIFT 0
|
||||||
|
#define POLLTIME_L_WIDTH 32
|
||||||
|
#define POLLTIME_L_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: POLLTIME_H
|
||||||
|
*/
|
||||||
|
#define POLLTIME_H 0x0000000CU
|
||||||
|
#define POLLTIME_H_SHIFT 0
|
||||||
|
#define POLLTIME_H_WIDTH 32
|
||||||
|
#define POLLTIME_H_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: TIMEOUT_L
|
||||||
|
*/
|
||||||
|
#define LISTENTIMEOUT_L 0x00000010U
|
||||||
|
#define LISTENTIMEOUT_L_SHIFT 0
|
||||||
|
#define LISTENTIMEOUT_L_WIDTH 32
|
||||||
|
#define LISTENTIMEOUT_L_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: TIMEOUT_H
|
||||||
|
*/
|
||||||
|
#define LISTENTIMEOUT_H 0x00000014U
|
||||||
|
#define LISTENTIMEOUT_H_SHIFT 0
|
||||||
|
#define LISTENTIMEOUT_H_WIDTH 32
|
||||||
|
#define LISTENTIMEOUT_H_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: ANT_CTRL
|
||||||
|
*/
|
||||||
|
#define ANT_CONFIG 0x00000018U
|
||||||
|
#define ANT_CONFIG_OFFSET_SHIFT 0
|
||||||
|
#define ANT_CONFIG_OFFSET_WIDTH 16
|
||||||
|
#define ANT_CONFIG_OFFSET_MASK 0x0000FFFFU
|
||||||
|
#define ANT_CONFIG_LEN_SHIFT 16
|
||||||
|
#define ANT_CONFIG_LEN_WIDTH 8
|
||||||
|
#define ANT_CONFIG_LEN_MASK 0x00FF0000U
|
||||||
|
#define ANT_CONFIG_NUM_SHIFT 24
|
||||||
|
#define ANT_CONFIG_NUM_WIDTH 8
|
||||||
|
#define ANT_CONFIG_NUM_MASK 0xFF000000U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: SEND_DATA_CMD
|
||||||
|
*/
|
||||||
|
#define SEND_DATA_CMD 0x0000001CU
|
||||||
|
#define SEND_DATA_CMD_SHIFT 0
|
||||||
|
#define SEND_DATA_CMD_WIDTH 32
|
||||||
|
#define SEND_DATA_CMD_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
#define SEND_DATA_CMD_LEN_SHIFT 0
|
||||||
|
#define SEND_DATA_CMD_LEN_WIDTH 16
|
||||||
|
#define SEND_DATA_CMD_LEN_MASK 0x0000FFFFU
|
||||||
|
#define SEND_DATA_CMD_OFFSET_SHIFT 16
|
||||||
|
#define SEND_DATA_CMD_OFFSET_WIDTH 16
|
||||||
|
#define SEND_DATA_CMD_OFFSET_MASK 0xFFFF0000U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: SLOT_CONFIG_CMD
|
||||||
|
*/
|
||||||
|
#define SLOT_CMD 0x00000020U
|
||||||
|
#define SLOT_CMD_SHIFT 0
|
||||||
|
#define SLOT_CMD_WIDTH 32
|
||||||
|
#define SLOT_CMD_MASK 0xFFFFFFFFU
|
||||||
|
#define SLOT_CMD_KEY 0x434D442EU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: TXRX_STATE
|
||||||
|
*/
|
||||||
|
#define TXRX_STATE 0x00000024U
|
||||||
|
#define TXRX_STATE_ACQ_SHIFT 0
|
||||||
|
#define TXRX_STATE_ACQ_WIDTH 8
|
||||||
|
#define TXRX_STATE_ACQ_MASK 0x000000FFU
|
||||||
|
#define TXRX_STATE_ACQ_SUCCESS 0x00000001U
|
||||||
|
#define TXRX_STATE_ACQ_FAIL 0x00000002U
|
||||||
|
|
||||||
|
#define TXRX_STATE_FSYNC_SHIFT 8
|
||||||
|
#define TXRX_STATE_FSYNC_WIDTH 8
|
||||||
|
#define TXRX_STATE_FSYNC_MASK 0x0000FF00U
|
||||||
|
#define TXRX_STATE_FSYNC_SUCCESS 0x00000100U
|
||||||
|
#define TXRX_STATE_FSYNC_FAIL 0x00000200U
|
||||||
|
|
||||||
|
#define TXRX_STATE_DECODE_SHIFT 16
|
||||||
|
#define TXRX_STATE_DECODE_WIDTH 8
|
||||||
|
#define TXRX_STATE_DECODE_MASK 0x00FF0000U
|
||||||
|
#define TXRX_STATE_DECODE_SUCCESS 0x00010000U
|
||||||
|
#define TXRX_STATE_DECODE_FAIL 0x00020000U
|
||||||
|
|
||||||
|
#define TXRX_STATE_CRC_SHIFT 24
|
||||||
|
#define TXRX_STATE_CRC_WIDTH 8
|
||||||
|
#define TXRX_STATE_CRC_MASK 0xFF000000U
|
||||||
|
#define TXRX_STATE_CRC_OK 0x01000000U
|
||||||
|
#define TXRX_STATE_CRC_ERROR 0x02000000U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: RECVDATA_STATE
|
||||||
|
*/
|
||||||
|
#define RECVDATA_STATE 0x00000028U
|
||||||
|
#define RECVDATA_STATE_LEN_SHIFT 0
|
||||||
|
#define RECVDATA_STATE_LEN_WIDTH 16
|
||||||
|
#define RECVDATA_STATE_LEN_MASK 0x0000FFFFU
|
||||||
|
|
||||||
|
#define RECVDATA_STATE_OFFSET_SHIFT 16
|
||||||
|
#define RECVDATA_STATE_OFFSET_WIDTH 16
|
||||||
|
#define RECVDATA_STATE_OFFSET_MASK 0xFFFF0000U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: FSTIME_L
|
||||||
|
*/
|
||||||
|
#define FSTIME_L 0x0000002CU
|
||||||
|
#define FSTIME_L_SHIFT 0
|
||||||
|
#define FSTIME_L_WIDTH 32
|
||||||
|
#define FSTIME_L_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: FSTIME_INT1
|
||||||
|
*/
|
||||||
|
#define FSTIME_H 0x00000030U
|
||||||
|
#define FSTIME_H_SHIFT 0
|
||||||
|
#define FSTIME_H_WIDTH 32
|
||||||
|
#define FSTIME_H_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: TM_TARGET_L
|
||||||
|
*/
|
||||||
|
#define TM_TARGET_L 0x00000064U
|
||||||
|
#define TM_TARGET_L_SHIFT 0
|
||||||
|
#define TM_TARGET_L_WIDTH 32
|
||||||
|
#define TM_TARGET_L_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: TM_TARGET_H
|
||||||
|
*/
|
||||||
|
#define TM_TARGET_H 0x00000038U
|
||||||
|
#define TM_TARGET_H_SHIFT 0
|
||||||
|
#define TM_TARGET_H_WIDTH 32
|
||||||
|
#define TM_TARGET_H_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: COASEFREQEST
|
||||||
|
*/
|
||||||
|
#define COASE_FREQEST 0x0000003CU
|
||||||
|
#define COASE_FREQEST_ACQ_SHIFT 0
|
||||||
|
#define COASE_FREQEST_ACQ_WIDTH 8
|
||||||
|
#define COASE_FREQEST_ACQ_MASK 0x000000FFU
|
||||||
|
#define COASE_FREQEST_SYNC_SHIFT 8
|
||||||
|
#define COASE_FREQEST_SYNC_WIDTH 8
|
||||||
|
#define COASE_FREQEST_SYNC_MASK 0x0000FF00U
|
||||||
|
#define COASE_TYPE_SHIFT 16
|
||||||
|
#define COASE_TYPE_WIDTH 8
|
||||||
|
#define COASE_TYPE_MASK 0x00FF0000U
|
||||||
|
#define COASE_TYPE_2KBPS_20MS 0x00010000U
|
||||||
|
#define COASE_TYPE_2KBPS_100MS 0x00020000U
|
||||||
|
#define COASE_TYPE_10KBPS_10MS 0x00030000U
|
||||||
|
#define COASE_TYPE_10KBPS_20MS 0x00040000U
|
||||||
|
#define COASE_TYPE_40KBPS_20MS 0x00050000U
|
||||||
|
#define COASE_TYPE_40KBPS_10MS 0x00060000U
|
||||||
|
#define COASE_TYPE_200KBPS_5MS 0x00070000U
|
||||||
|
#define COASE_TYPE_1M2BPS_5MS 0x00080000U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: FINE_FREQEST
|
||||||
|
*/
|
||||||
|
#define FINE_FREQEST 0x00000040U
|
||||||
|
#define FINE_FREQEST_VAL_SHIFT 0
|
||||||
|
#define FINE_FREQEST_VAL_WIDTH 24
|
||||||
|
#define FINE_FREQEST_VAL_MASK 0x00FFFFFFU
|
||||||
|
#define FINE_FREQEST_SIGN_SHIFT 24
|
||||||
|
#define FINE_FREQEST_SIGN_WIDTH 8
|
||||||
|
#define FINE_FREQEST_SIGN_MASK 0xFF000000U
|
||||||
|
#define FINE_FREQEST_SIGN_POS 0x00000000U
|
||||||
|
#define FINE_FREQEST_SIGN_NEG 0x01000000U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: BEAM_SELECT
|
||||||
|
*/
|
||||||
|
#define BEAM_SELECT_INDEX 0x00000044U
|
||||||
|
#define BEAM_SELECT_INDEX_SHIFT 0
|
||||||
|
#define BEAM_SELECT_INDEX_WIDTH 32
|
||||||
|
#define BEAM_SELECT_INDEX_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: BEAM_AXIS
|
||||||
|
*/
|
||||||
|
#define BEAM_AXIS 0x00000044U
|
||||||
|
#define BEAM_AXIS_EL_SHIFT 0
|
||||||
|
#define BEAM_AXIS_EL_WIDTH 16
|
||||||
|
#define BEAM_AXIS_EL_MASK 0x0000FFFFU
|
||||||
|
#define BEAM_AXIS_AZ_SHIFT 16
|
||||||
|
#define BEAM_AXIS_AZ_WIDTH 16
|
||||||
|
#define BEAM_AXIS_AZ_MASK 0xFFFF0000U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: ANT_STATUS
|
||||||
|
*/
|
||||||
|
#define ANT_STATUS 0x00000100U
|
||||||
|
#define ANT_STATUS_ANT_VOLT_SHIFT 0
|
||||||
|
#define ANT_STATUS_ANT_VOLT_WIDTH 8
|
||||||
|
#define ANT_STATUS_ANT_VOLT_MASK 0x000000FFU
|
||||||
|
#define ANT_STATUS_ANT_VOLT_OK 0x00000001U
|
||||||
|
|
||||||
|
#define ANT_STATUS_RF_VOLT_SHIFT 8
|
||||||
|
#define ANT_STATUS_RF_VOLT_WIDTH 8
|
||||||
|
#define ANT_STATUS_RF_VOLT_MASK 0x0000FF00U
|
||||||
|
#define ANT_STATUS_RF_VOLT_OK 0x00000100U
|
||||||
|
|
||||||
|
#define ANT_STATUS_NIL_VOLT_SHIFT 16
|
||||||
|
#define ANT_STATUS_NIL_VOLT_WIDTH 8
|
||||||
|
#define ANT_STATUS_NIL_VOLT_MASK 0x00FF0000U
|
||||||
|
#define ANT_STATUS_NIL_VOLT_OK 0x00010000U
|
||||||
|
|
||||||
|
#define ANT_STATUS_CODE_SHIFT 24
|
||||||
|
#define ANT_STATUS_CODE_WIDTH 8
|
||||||
|
#define ANT_STATUS_CODE_MASK 0xFF000000U
|
||||||
|
#define ANT_STATUS_CODE_OK 0x00000000U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: ANT_FRAME_CNT
|
||||||
|
*/
|
||||||
|
#define ANT_FRAME_CNT 0x00000104U
|
||||||
|
#define ANT_FRAME_CNT_SHIFT 0
|
||||||
|
#define ANT_FRAME_CNT_WIDTH 32
|
||||||
|
#define ANT_FRAME_CNT_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: ANT_RF_STATUS
|
||||||
|
*/
|
||||||
|
#define ANT_RF_STATUS 0x00000108U
|
||||||
|
#define ANT_RF_STATUS_TEMP_SHIFT 0
|
||||||
|
#define ANT_RF_STATUS_TEMP_WIDTH 8
|
||||||
|
#define ANT_RF_STATUS_TEMP_MASK 0x000000FFU
|
||||||
|
|
||||||
|
#define ANT_RF_STATUS_BBLOCK_SHIFT 8
|
||||||
|
#define ANT_RF_STATUS_BBLOCK_WIDTH 8
|
||||||
|
#define ANT_RF_STATUS_BBLOCK_MASK 0x0000FF00U
|
||||||
|
#define ANT_RF_STATUS_BBLOCK_OK 0x00000100U
|
||||||
|
|
||||||
|
#define ANT_RF_STATUS_PLLA_SHIFT 16
|
||||||
|
#define ANT_RF_STATUS_PLLA_WIDTH 8
|
||||||
|
#define ANT_RF_STATUS_PLLA_MASK 0x00FF0000U
|
||||||
|
#define ANT_RF_STATUS_PLLA_OK 0x00010000U
|
||||||
|
|
||||||
|
#define ANT_RF_STATUS_PLLB_SHIFT 24
|
||||||
|
#define ANT_RF_STATUS_PLLB_WIDTH 8
|
||||||
|
#define ANT_RF_STATUS_PLLB_MASK 0xFF000000U
|
||||||
|
#define ANT_RF_STATUS_PLLB_OK 0x01000000U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: ANT_RF_MGC
|
||||||
|
*/
|
||||||
|
#define ANT_RF_MGC 0x0000010CU
|
||||||
|
#define ANT_RF_MGC_CH1_SHIFT 0
|
||||||
|
#define ANT_RF_MGC_CH1_WIDTH 4
|
||||||
|
#define ANT_RF_MGC_CH1_MASK 0x0000000FU
|
||||||
|
#define ANT_RF_MGC_CH2_SHIFT 8
|
||||||
|
#define ANT_RF_MGC_CH2_WIDTH 4
|
||||||
|
#define ANT_RF_MGC_CH2_MASK 0x00000F00U
|
||||||
|
#define ANT_RF_MGC_CH3_SHIFT 16
|
||||||
|
#define ANT_RF_MGC_CH3_WIDTH 4
|
||||||
|
#define ANT_RF_MGC_CH3_MASK 0x000F0000U
|
||||||
|
#define ANT_RF_MGC_CH4_SHIFT 24
|
||||||
|
#define ANT_RF_MGC_CH4_WIDTH 4
|
||||||
|
#define ANT_RF_MGC_CH4_MASK 0x0F000000U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: ANT_RF_FRAME_CNT
|
||||||
|
*/
|
||||||
|
#define ANT_RF_FRAME_CNT 0x00000110U
|
||||||
|
#define ANT_RF_FRAME_CNT_SHIFT 0
|
||||||
|
#define ANT_RF_FRAME_CNT_WIDTH 32
|
||||||
|
#define ANT_RF_FRAME_CNT_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: PHY_ACQ_CNT
|
||||||
|
*/
|
||||||
|
#define PHY_ACQ_CNT 0x00000114U
|
||||||
|
#define PHY_ACQ_CNT_SHIFT 0
|
||||||
|
#define PHY_ACQ_CNT_WIDTH 32
|
||||||
|
#define PHY_ACQ_CNT_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: PHY_FRAME_SYNC_CNT
|
||||||
|
*/
|
||||||
|
#define PHY_FRAME_SYNC_CNT 0x00000118U
|
||||||
|
#define PHY_FRAME_SYNC_CNT_SHIFT 0
|
||||||
|
#define PHY_FRAME_SYNC_CNT_WIDTH 32
|
||||||
|
#define PHY_FRAME_SYNC_CNT_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: PHY_DECODE_CNT
|
||||||
|
*/
|
||||||
|
#define PHY_DECODE_CNT 0x0000011CU
|
||||||
|
#define PHY_DECODE_CNT_SHIFT 0
|
||||||
|
#define PHY_DECODE_CNT_WIDTH 32
|
||||||
|
#define PHY_DECODE_CNT_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: PHY_CRC_OK_CNT
|
||||||
|
*/
|
||||||
|
#define PHY_CRC_OK_CNT 0x00000120U
|
||||||
|
#define PHY_CRC_OK_CNT_SHIFT 0
|
||||||
|
#define PHY_CRC_OK_CNT_WIDTH 32
|
||||||
|
#define PHY_CRC_OK_CNT_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: PHY_ACQ_PEAK_H
|
||||||
|
*/
|
||||||
|
#define PHY_ACQ_PEAK_H 0x00000124U
|
||||||
|
#define PHY_ACQ_PEAK_H_SHIFT 0
|
||||||
|
#define PHY_ACQ_PEAK_H_WIDTH 32
|
||||||
|
#define PHY_ACQ_PEAK_H_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: PHY_ACQ_PEAK_L
|
||||||
|
*/
|
||||||
|
#define PHY_ACQ_PEAK_L 0x00000128U
|
||||||
|
#define PHY_ACQ_PEAK_L_SHIFT 0
|
||||||
|
#define PHY_ACQ_PEAK_L_WIDTH 32
|
||||||
|
#define PHY_ACQ_PEAK_L_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: PHY_ACQ_MEAN_H
|
||||||
|
*/
|
||||||
|
#define PHY_ACQ_MEAN_H 0x0000012CU
|
||||||
|
#define PHY_ACQ_MEAN_H_SHIFT 0
|
||||||
|
#define PHY_ACQ_MEAN_H_WIDTH 32
|
||||||
|
#define PHY_ACQ_MEAN_H_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: PHY_ACQ_MEAN_L
|
||||||
|
*/
|
||||||
|
#define PHY_ACQ_MEAN_L 0x00000130U
|
||||||
|
#define PHY_ACQ_MEAN_L_SHIFT 0
|
||||||
|
#define PHY_ACQ_MEAN_L_WIDTH 32
|
||||||
|
#define PHY_ACQ_MEAN_L_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: PHY_ACQ_FREQEST
|
||||||
|
*/
|
||||||
|
#define PHY_ACQ_FREQEST 0x00000134U
|
||||||
|
#define PHY_ACQ_FREQEST_SHIFT 0
|
||||||
|
#define PHY_ACQ_FREQEST_WIDTH 32
|
||||||
|
#define PHY_ACQ_FREQEST_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
#define PHY_ACQ_FREQEST_PHASE_SHIFT 0
|
||||||
|
#define PHY_ACQ_FREQEST_PHASE_WIDTH 8
|
||||||
|
#define PHY_ACQ_FREQEST_PHASE_MASK 0x000000FFU
|
||||||
|
#define PHY_ACQ_FREQEST_CHANNEL_SHIFT 8
|
||||||
|
#define PHY_ACQ_FREQEST_CHANNEL_WIDTH 8
|
||||||
|
#define PHY_ACQ_FREQEST_CHANNEL_MASK 0x0000FF00U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: PHY_FRAME_SYNC_PEAK_H
|
||||||
|
*/
|
||||||
|
#define PHY_FRAME_SYNC_PEAK_H 0x00000138U
|
||||||
|
#define PHY_FRAME_SYNC_PEAK_H_SHIFT 0
|
||||||
|
#define PHY_FRAME_SYNC_PEAK_H_WIDTH 32
|
||||||
|
#define PHY_FRAME_SYNC_PEAK_H_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: PHY_FRAME_SYNC_PEAK_L
|
||||||
|
*/
|
||||||
|
#define PHY_FRAME_SYNC_PEAK_L 0x0000013CU
|
||||||
|
#define PHY_FRAME_SYNC_PEAK_L_SHIFT 0
|
||||||
|
#define PHY_FRAME_SYNC_PEAK_L_WIDTH 32
|
||||||
|
#define PHY_FRAME_SYNC_PEAK_L_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: PHY_FRAME_SYNC_MEAN_H
|
||||||
|
*/
|
||||||
|
#define PHY_FRAME_SYNC_MEAN_H 0x00000140U
|
||||||
|
#define PHY_FRAME_SYNC_MEAN_H_SHIFT 0
|
||||||
|
#define PHY_FRAME_SYNC_MEAN_H_WIDTH 32
|
||||||
|
#define PHY_FRAME_SYNC_MEAN_H_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: PHY_FRAME_SYNC_MEAN_L
|
||||||
|
*/
|
||||||
|
#define PHY_FRAME_SYNC_MEAN_L 0x00000144U
|
||||||
|
#define PHY_FRAME_SYNC_MEAN_L_SHIFT 0
|
||||||
|
#define PHY_FRAME_SYNC_MEAN_L_WIDTH 32
|
||||||
|
#define PHY_FRAME_SYNC_MEAN_L_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: PHY_FRAME_SYNC_FREQEST
|
||||||
|
*/
|
||||||
|
#define PHY_FRAME_SYNC_FREQEST 0x00000148U
|
||||||
|
#define PHY_FRAME_SYNC_FREQEST_SHIFT 0
|
||||||
|
#define PHY_FRAME_SYNC_FREQEST_WIDTH 32
|
||||||
|
#define PHY_FRAME_SYNC_FREQEST_MASK 0xFFFFFFFFU
|
||||||
|
|
||||||
|
#define PHY_FRAME_SYNC_FREQEST_CHANNEL_SHIFT 0
|
||||||
|
#define PHY_FRAME_SYNC_FREQEST_CHANNEL_WIDTH 8
|
||||||
|
#define PHY_FRAME_SYNC_FREQEST_CHANNEL_MASK 0x000000FFU
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register: PHY_DEINTLV_AMPEST
|
||||||
|
*/
|
||||||
|
#define PHY_DEINTLV_AMPEST 0x0000014CU
|
||||||
|
#define PHY_DEINTLV_AMPEST_SHIFT 0
|
||||||
|
#define PHY_DEINTLV_AMPEST_WIDTH 16
|
||||||
|
#define PHY_DEINTLV_AMPEST_MASK 0x0000FFFFU
|
||||||
|
|
||||||
|
#endif /* PHY_REG_H_ */
|
||||||
|
|
||||||
|
/** @} PhysicalLayer_REG_Constants*/
|
||||||
|
|
||||||
|
/** @} PhysicalLayer*/
|
||||||
@@ -0,0 +1,410 @@
|
|||||||
|
/**
|
||||||
|
* @addtogroup SystemMonitor
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "system_monitor.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
/************************** Constant Definitions *****************************/
|
||||||
|
/**
|
||||||
|
* @name SystemMonitor_Private_Constants
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define BUFF_A 0x00
|
||||||
|
#define BUFF_B 0x01
|
||||||
|
#define BUFF_NONE 0xFF
|
||||||
|
|
||||||
|
#define SYSINFO_PACK_LEN 54 // bytes
|
||||||
|
#define PAYLOAD_PACK_LEN 46 // bytes
|
||||||
|
#define SLOTLOG_PACK_LEN 88 // bytes
|
||||||
|
#define PRTCLLOG_PACK_ELN 24 // bytes
|
||||||
|
#define HWSTATE_PACK_ELN 12 // bytes
|
||||||
|
/** @} SystemMonitor_Private_Constants*/
|
||||||
|
/************************** Data Type Definitions ****************************/
|
||||||
|
/**
|
||||||
|
* @struct PINGPONG
|
||||||
|
* @brief PingPing Control
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t latest; ///< latest available index
|
||||||
|
uint8_t rBusy; ///< current read busy index
|
||||||
|
uint8_t wBusy; ///< current write busy index
|
||||||
|
} PINGPONG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct SYSMONITOR
|
||||||
|
* @brief System Monitor struct holds all the system log info
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
PINGPONG recvCtrl;
|
||||||
|
PAYLOAD recv[2];
|
||||||
|
PINGPONG sendCtrl;
|
||||||
|
PAYLOAD send[2];
|
||||||
|
PINGPONG sysInfoCtrl;
|
||||||
|
SYSINFO sysInfo[2];
|
||||||
|
PINGPONG linkLogCtrl;
|
||||||
|
LINKLOG linkLog[2];
|
||||||
|
PINGPONG phyLogCtrl;
|
||||||
|
PHYLOG phyLog[2];
|
||||||
|
PINGPONG hwStateCtrl;
|
||||||
|
HWSTATE hwState[2];
|
||||||
|
} SYSMONITOR;
|
||||||
|
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
static uint8_t GetWritable(PINGPONG ctrllor);
|
||||||
|
static uint8_t GetReadable(PINGPONG ctrllor);
|
||||||
|
/************************** Variable Definitions *****************************/
|
||||||
|
static SYSMONITOR *sysMonitorInst;
|
||||||
|
|
||||||
|
/*********************** Function Implementations ***************************/
|
||||||
|
inline static uint8_t GetWritable(PINGPONG ctrllor)
|
||||||
|
{
|
||||||
|
// Allow only one write.
|
||||||
|
ASSERT(ctrllor.wBusy == BUFF_NONE);
|
||||||
|
if (ctrllor.rBusy == BUFF_NONE)
|
||||||
|
return ((ctrllor.latest == BUFF_B) ? BUFF_A : BUFF_B);
|
||||||
|
else
|
||||||
|
return ((ctrllor.rBusy == BUFF_B) ? BUFF_A : BUFF_B);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static uint8_t GetReadable(PINGPONG ctrllor)
|
||||||
|
{
|
||||||
|
if (ctrllor.wBusy == BUFF_NONE || ctrllor.wBusy != ctrllor.latest)
|
||||||
|
return ((ctrllor.latest == BUFF_NONE) ? BUFF_A : BUFF_B);
|
||||||
|
else
|
||||||
|
return ((ctrllor.wBusy == BUFF_B) ? BUFF_A : BUFF_B);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize System monitor
|
||||||
|
*
|
||||||
|
* @return SUCCESS
|
||||||
|
*/
|
||||||
|
int32_t SysMonitor_Init(void)
|
||||||
|
{
|
||||||
|
sysMonitorInst = calloc(1, sizeof(SYSMONITOR));
|
||||||
|
if (sysMonitorInst == NULL)
|
||||||
|
{
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
memset(&(sysMonitorInst->recvCtrl), BUFF_NONE, sizeof(PINGPONG));
|
||||||
|
memset(&(sysMonitorInst->sendCtrl), BUFF_NONE, sizeof(PINGPONG));
|
||||||
|
memset(&(sysMonitorInst->sysInfoCtrl), BUFF_NONE, sizeof(PINGPONG));
|
||||||
|
memset(&(sysMonitorInst->linkLogCtrl), BUFF_NONE, sizeof(PINGPONG));
|
||||||
|
memset(&(sysMonitorInst->phyLogCtrl), BUFF_NONE, sizeof(PINGPONG));
|
||||||
|
memset(&(sysMonitorInst->hwStateCtrl), BUFF_NONE, sizeof(PINGPONG));
|
||||||
|
|
||||||
|
sysMonitorInst->recv[0].dataId = DATA_ID_NONE;
|
||||||
|
sysMonitorInst->recv[1].dataId = DATA_ID_NONE;
|
||||||
|
sysMonitorInst->send[0].dataId = DATA_ID_NONE;
|
||||||
|
sysMonitorInst->send[1].dataId = DATA_ID_NONE;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroy system monitor release all allocated memory
|
||||||
|
*/
|
||||||
|
void SysMonitor_Destroy(void)
|
||||||
|
{
|
||||||
|
free(sysMonitorInst);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name SystemInfo_API
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update system info.
|
||||||
|
*
|
||||||
|
* @param info
|
||||||
|
*/
|
||||||
|
void SysMonitor_UpdateSysinfo(const SYSINFO *info)
|
||||||
|
{
|
||||||
|
ASSERT(info != NULL);
|
||||||
|
uint8_t buffIndx;
|
||||||
|
buffIndx = GetWritable(sysMonitorInst->sysInfoCtrl);
|
||||||
|
sysMonitorInst->sysInfoCtrl.wBusy = buffIndx;
|
||||||
|
memcpy(&(sysMonitorInst->sysInfo[buffIndx]), info, sizeof(SYSINFO));
|
||||||
|
sysMonitorInst->sysInfoCtrl.latest = buffIndx;
|
||||||
|
sysMonitorInst->sysInfoCtrl.wBusy = BUFF_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get system info.
|
||||||
|
*
|
||||||
|
* @param info
|
||||||
|
*/
|
||||||
|
void SysMonitor_GetSysinfo(SYSINFO *info)
|
||||||
|
{
|
||||||
|
ASSERT(sysMonitorInst != NULL);
|
||||||
|
ASSERT(info != NULL);
|
||||||
|
uint8_t buffIndx, buffIndex_old;
|
||||||
|
buffIndex_old = sysMonitorInst->sysInfoCtrl.rBusy;
|
||||||
|
if (buffIndex_old != BUFF_NONE)
|
||||||
|
buffIndx = buffIndex_old; // Keep it busy
|
||||||
|
else
|
||||||
|
buffIndx = GetReadable(sysMonitorInst->sysInfoCtrl);
|
||||||
|
sysMonitorInst->sysInfoCtrl.rBusy = buffIndx;
|
||||||
|
memcpy(info, &(sysMonitorInst->sysInfo[buffIndx]), sizeof(SYSINFO));
|
||||||
|
sysMonitorInst->sysInfoCtrl.rBusy = buffIndex_old;
|
||||||
|
}
|
||||||
|
/** @} SystemInfo_API*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ServicePayload_API
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update send payload by
|
||||||
|
*
|
||||||
|
* @param buff
|
||||||
|
* @param len
|
||||||
|
*/
|
||||||
|
void SysMonitor_UpdateSendPayload(const uint8_t *buff, size_t len)
|
||||||
|
{
|
||||||
|
ASSERT(sysMonitorInst != NULL);
|
||||||
|
if (len > PAYLOAD_LEN_MAX)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t buffIndx;
|
||||||
|
buffIndx = GetWritable(sysMonitorInst->sendCtrl);
|
||||||
|
sysMonitorInst->sendCtrl.wBusy = buffIndx;
|
||||||
|
memcpy(sysMonitorInst->send[buffIndx].data, buff, len);
|
||||||
|
sysMonitorInst->send[buffIndx].dataId++;
|
||||||
|
sysMonitorInst->sendCtrl.latest = buffIndx;
|
||||||
|
sysMonitorInst->sendCtrl.wBusy = BUFF_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the latest send payload.
|
||||||
|
*
|
||||||
|
* @param buff
|
||||||
|
* @param id
|
||||||
|
* @param len
|
||||||
|
*/
|
||||||
|
void SysMonitor_GetSendPayload(uint8_t *buff, uint32_t *id, size_t len)
|
||||||
|
{
|
||||||
|
ASSERT(sysMonitorInst != NULL);
|
||||||
|
ASSERT(buff != NULL);
|
||||||
|
ASSERT(id != NULL);
|
||||||
|
if (len > PAYLOAD_LEN_MAX)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t buffIndx, buffIndex_old;
|
||||||
|
buffIndex_old = sysMonitorInst->sendCtrl.rBusy;
|
||||||
|
if (buffIndex_old != BUFF_NONE)
|
||||||
|
{
|
||||||
|
buffIndx = buffIndex_old; // Keep it busy
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffIndx = GetReadable(sysMonitorInst->sendCtrl);
|
||||||
|
}
|
||||||
|
sysMonitorInst->sendCtrl.rBusy = buffIndx;
|
||||||
|
if (sysMonitorInst->send[buffIndx].dataId != DATA_ID_NONE)
|
||||||
|
{
|
||||||
|
memcpy(buff, sysMonitorInst->send[buffIndx].data, len);
|
||||||
|
}
|
||||||
|
*id = sysMonitorInst->send[buffIndx].dataId;
|
||||||
|
sysMonitorInst->sendCtrl.rBusy = buffIndex_old;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update receive payload.
|
||||||
|
*
|
||||||
|
* @param buff
|
||||||
|
* @param id
|
||||||
|
* @param len
|
||||||
|
*/
|
||||||
|
void SysMonitor_UpdateRecvPayload(const uint8_t *buff, uint32_t id, size_t len)
|
||||||
|
{
|
||||||
|
ASSERT(sysMonitorInst != NULL);
|
||||||
|
ASSERT(buff != NULL);
|
||||||
|
if (id == DATA_ID_NONE || len > PAYLOAD_LEN_MAX)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t buffIndx;
|
||||||
|
buffIndx = GetWritable(sysMonitorInst->recvCtrl);
|
||||||
|
sysMonitorInst->recvCtrl.wBusy = buffIndx;
|
||||||
|
memcpy(sysMonitorInst->recv[buffIndx].data, buff, len);
|
||||||
|
sysMonitorInst->recv[buffIndx].dataId = id;
|
||||||
|
sysMonitorInst->recvCtrl.latest = buffIndx;
|
||||||
|
sysMonitorInst->recvCtrl.wBusy = BUFF_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the latest receive payload.
|
||||||
|
*
|
||||||
|
* @param buff
|
||||||
|
* @param id
|
||||||
|
* @param len
|
||||||
|
*/
|
||||||
|
void SysMonitor_GetRecvPayload(uint8_t *buff, uint32_t *id, size_t len)
|
||||||
|
{
|
||||||
|
ASSERT(sysMonitorInst != NULL);
|
||||||
|
ASSERT(buff != NULL);
|
||||||
|
ASSERT(id != NULL);
|
||||||
|
if (len > PAYLOAD_LEN_MAX)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t buffIndx, buffIndex_old;
|
||||||
|
buffIndex_old = sysMonitorInst->recvCtrl.rBusy;
|
||||||
|
if (buffIndex_old != BUFF_NONE)
|
||||||
|
buffIndx = buffIndex_old; // Keep it busy
|
||||||
|
else
|
||||||
|
buffIndx = GetReadable(sysMonitorInst->recvCtrl);
|
||||||
|
sysMonitorInst->recvCtrl.rBusy = buffIndx;
|
||||||
|
if (sysMonitorInst->recv[buffIndx].dataId != DATA_ID_NONE)
|
||||||
|
{
|
||||||
|
memcpy(buff, sysMonitorInst->recv[buffIndx].data, len);
|
||||||
|
}
|
||||||
|
*id = sysMonitorInst->recv[buffIndx].dataId;
|
||||||
|
sysMonitorInst->recvCtrl.rBusy = buffIndex_old;
|
||||||
|
}
|
||||||
|
/** @} ServicePayload_API*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Linklayer_Log_API
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update link layer log
|
||||||
|
*
|
||||||
|
* @param log
|
||||||
|
*/
|
||||||
|
void SysMonitor_UpdateLinklayerLog(const LINKLOG *log)
|
||||||
|
{
|
||||||
|
ASSERT(sysMonitorInst != NULL);
|
||||||
|
ASSERT(log != NULL);
|
||||||
|
uint8_t buffIndx;
|
||||||
|
buffIndx = GetWritable(sysMonitorInst->linkLogCtrl);
|
||||||
|
sysMonitorInst->linkLogCtrl.wBusy = buffIndx;
|
||||||
|
memcpy(&(sysMonitorInst->linkLog[buffIndx]), log, sizeof(LINKLOG));
|
||||||
|
sysMonitorInst->linkLogCtrl.latest = buffIndx;
|
||||||
|
sysMonitorInst->linkLogCtrl.wBusy = BUFF_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the latest link layer log
|
||||||
|
*
|
||||||
|
* @param log
|
||||||
|
*/
|
||||||
|
void SysMonitor_GetLinklayerLog(LINKLOG *log)
|
||||||
|
{
|
||||||
|
ASSERT(sysMonitorInst != NULL);
|
||||||
|
ASSERT(log != NULL);
|
||||||
|
uint8_t buffIndx, buffIndex_old;
|
||||||
|
buffIndex_old = sysMonitorInst->linkLogCtrl.rBusy;
|
||||||
|
if (buffIndex_old != BUFF_NONE)
|
||||||
|
buffIndx = buffIndex_old; // Keep it busy
|
||||||
|
else
|
||||||
|
buffIndx = GetReadable(sysMonitorInst->linkLogCtrl);
|
||||||
|
sysMonitorInst->linkLogCtrl.rBusy = buffIndx;
|
||||||
|
memcpy(log, &(sysMonitorInst->linkLog[buffIndx]), sizeof(LINKLOG));
|
||||||
|
sysMonitorInst->linkLogCtrl.rBusy = buffIndex_old;
|
||||||
|
}
|
||||||
|
/** @} Linklayer_Log_API*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name PhysicalLayer_Log_API
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update physical layer log
|
||||||
|
*
|
||||||
|
* @param log
|
||||||
|
*/
|
||||||
|
void SysMonitor_UpdatePhysicalLayerLog(const PHYLOG *log)
|
||||||
|
{
|
||||||
|
ASSERT(sysMonitorInst != NULL);
|
||||||
|
ASSERT(log != NULL);
|
||||||
|
uint8_t buffIndx;
|
||||||
|
buffIndx = GetWritable(sysMonitorInst->phyLogCtrl);
|
||||||
|
sysMonitorInst->phyLogCtrl.wBusy = buffIndx;
|
||||||
|
memcpy(&(sysMonitorInst->phyLog[buffIndx]), log, sizeof(PHYLOG));
|
||||||
|
sysMonitorInst->phyLogCtrl.latest = buffIndx;
|
||||||
|
sysMonitorInst->phyLogCtrl.wBusy = BUFF_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the latest physical layer log
|
||||||
|
*
|
||||||
|
* @param log
|
||||||
|
*/
|
||||||
|
void SysMonitor_GetPhysicalLayerLog(PHYLOG *log)
|
||||||
|
{
|
||||||
|
ASSERT(sysMonitorInst != NULL);
|
||||||
|
ASSERT(log != NULL);
|
||||||
|
uint8_t buffIndx, buffIndex_old;
|
||||||
|
buffIndex_old = sysMonitorInst->phyLogCtrl.rBusy;
|
||||||
|
if (buffIndex_old != BUFF_NONE)
|
||||||
|
buffIndx = buffIndex_old; // Keep it busy
|
||||||
|
else
|
||||||
|
buffIndx = GetReadable(sysMonitorInst->phyLogCtrl);
|
||||||
|
sysMonitorInst->phyLogCtrl.rBusy = buffIndx;
|
||||||
|
memcpy(log, &(sysMonitorInst->phyLog[buffIndx]), sizeof(PHYLOG));
|
||||||
|
sysMonitorInst->phyLogCtrl.rBusy = buffIndex_old;
|
||||||
|
}
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name HardwareState_Log_API
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Log hardware running status.
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
*/
|
||||||
|
void SysMonitor_UpdateHardwareStatus(const HWSTATE *state)
|
||||||
|
{
|
||||||
|
ASSERT(sysMonitorInst != NULL);
|
||||||
|
ASSERT(state != NULL);
|
||||||
|
uint8_t buffIndx;
|
||||||
|
buffIndx = GetWritable(sysMonitorInst->hwStateCtrl);
|
||||||
|
sysMonitorInst->hwStateCtrl.wBusy = buffIndx;
|
||||||
|
memcpy(&(sysMonitorInst->hwState[buffIndx]), state, sizeof(HWSTATE));
|
||||||
|
sysMonitorInst->hwStateCtrl.latest = buffIndx;
|
||||||
|
sysMonitorInst->hwStateCtrl.wBusy = BUFF_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the latest hardware running status.
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
*/
|
||||||
|
void SysMonitor_GetHardwareStatus(HWSTATE *state)
|
||||||
|
{
|
||||||
|
ASSERT(sysMonitorInst != NULL);
|
||||||
|
ASSERT(state != NULL);
|
||||||
|
uint8_t buffIndx, buffIndex_old;
|
||||||
|
buffIndex_old = sysMonitorInst->hwStateCtrl.rBusy;
|
||||||
|
if (buffIndex_old != BUFF_NONE)
|
||||||
|
buffIndx = buffIndex_old; // Keep it busy
|
||||||
|
else
|
||||||
|
buffIndx = GetReadable(sysMonitorInst->hwStateCtrl);
|
||||||
|
sysMonitorInst->hwStateCtrl.rBusy = buffIndx;
|
||||||
|
memcpy(state, &(sysMonitorInst->hwState[buffIndx]), sizeof(HWSTATE));
|
||||||
|
sysMonitorInst->hwStateCtrl.rBusy = buffIndex_old;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} HardwareState_Log_API */
|
||||||
|
|
||||||
|
/** @} SystemMonitor*/
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
/**
|
||||||
|
* @defgroup SystemMonitor
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SYSTEM_MONITOR_H_
|
||||||
|
#define __SYSTEM_MONITOR_H_
|
||||||
|
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/************************* Constant Definitions ******************************/
|
||||||
|
/**
|
||||||
|
* @name SystemMonitor_Constants
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define PAYLOAD_LEN_MAX 256
|
||||||
|
#define PAYLOAD_LEN_FLJ_RX 168
|
||||||
|
#define PAYLOAD_LEN_FLJ_TX 66
|
||||||
|
#define PAYLOAD_LEN_LJ_RX 66
|
||||||
|
#define PAYLOAD_LEN_LJ_TX 168
|
||||||
|
|
||||||
|
#define DATA_ID_NONE UINT32_MAX
|
||||||
|
#define DATA_ID_TEST 0x02030203
|
||||||
|
|
||||||
|
#define VOLTAGE_LSB 0.01 // volt
|
||||||
|
#define VOLTAGE_MAX 2.55 // volt
|
||||||
|
|
||||||
|
#define VOLT_PS_STD 1.0
|
||||||
|
#define VOLT_PSAUX_STD 1.8
|
||||||
|
#define VOLT_DDR_STD 1.5
|
||||||
|
#define VOLT_PL_STD 1.0
|
||||||
|
#define VOLT_PLAUX_STD 1.8
|
||||||
|
#define VOLT_BRAM_STD 1.0
|
||||||
|
|
||||||
|
#define VOLT_PS_OK BIT(0)
|
||||||
|
#define VOLT_PSAUX_OK BIT(1)
|
||||||
|
#define VOLT_DDR_OK BIT(2)
|
||||||
|
#define VOLT_PL_OK BIT(3)
|
||||||
|
#define VOLT_PLAUX_OK BIT(4)
|
||||||
|
#define VOLT_BRAM_OK BIT(5)
|
||||||
|
|
||||||
|
#define VOLT_ANT_PROC_OK BIT(0)
|
||||||
|
#define VOLT_ANT_RF_OK BIT(2)
|
||||||
|
#define VOLT_ANT_NIL_OK BIT(4)
|
||||||
|
#define ANT_STATE_OK BIT(6)
|
||||||
|
|
||||||
|
// Xilinx Recommended
|
||||||
|
// #define IS_PS_VALID(x) (x <= 1.05 && x >= 0.95)
|
||||||
|
// #define IS_PSAUX_VALID(x) (x <= 1.89 && x >= 1.71)
|
||||||
|
// #define IS_DDR_VALID(x) (x <= 1.89 && x >= 1.14)
|
||||||
|
// #define IS_PL_VALID(x) (x <= 1.03 && x >= 0.97)
|
||||||
|
// #define IS_PLAUX_VALID(x) (x <= 1.89 && x >= 1.71)
|
||||||
|
// #define IS_BRAM_VALID(x) (x <= 1.03 && x >= 0.97)
|
||||||
|
#define IS_PS_VALID(x) ((x) <= 1.1 && (x) >= 0.9)
|
||||||
|
#define IS_PSAUX_VALID(x) ((x) <= 2.0 && (x) >= 1.6)
|
||||||
|
#define IS_DDR_VALID(x) ((x) <= 1.7 && (x) >= 1.3)
|
||||||
|
#define IS_PL_VALID(x) (x <= 1.1 && (x) >= 0.9)
|
||||||
|
#define IS_PLAUX_VALID(x) ((x) <= 2.0 && (x) >= 1.6)
|
||||||
|
#define IS_BRAM_VALID(x) ((x) <= 1.1 && (x) >= 0.9)
|
||||||
|
|
||||||
|
#define CLK_SP_PLL0_LOCK BIT(0)
|
||||||
|
#define CLK_SP_PLL1_LOCK BIT(2)
|
||||||
|
|
||||||
|
#define CLK_AD0_BBPLL_LOCK BIT(0)
|
||||||
|
#define CLK_AD0_RFPLL_LOCK BIT(2)
|
||||||
|
#define CLK_AD1_BBPLL_LOCK BIT(4)
|
||||||
|
#define CLK_AD1_RFPLL_LOCK BIT(6)
|
||||||
|
|
||||||
|
#define CLK_ANT_BBPLL_LOCK BIT(0)
|
||||||
|
#define CLK_ANT_RFPLL0_LOCK BIT(2)
|
||||||
|
#define CLK_ANT_RFPLL1_LOCK BIT(4)
|
||||||
|
|
||||||
|
#define TEMPERATURE_LSB 1.0 // Celsius degree
|
||||||
|
#define TEMPERATURE_MAX 127.0 // Celsius degree
|
||||||
|
#define TEMPERATURE_MIN -128.0 // Celsius degree
|
||||||
|
/** @} SystemMonitor_Constants */
|
||||||
|
|
||||||
|
/************************* Data Type Definitions ****************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct SYSINFO
|
||||||
|
* @brief System Infomation log
|
||||||
|
*/
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
uint32_t psBDS; ///< -- unit: ms, 0~604799999
|
||||||
|
uint16_t pBDS; ///< -- unit: week, 0~0~8191
|
||||||
|
uint32_t psGPS; ///< -- unit: ms, 0~604799999
|
||||||
|
uint16_t pGPS; ///< -- unit: week, 0~0~8191
|
||||||
|
uint8_t tmInd; ///< Time validation indicator \n
|
||||||
|
// -- [0] GPS\n
|
||||||
|
// -- [1] reserve.\n
|
||||||
|
// -- [2] UTC\n
|
||||||
|
// -- [3] BDS\n
|
||||||
|
float tmFly; ///< Time of flying uint: s
|
||||||
|
uint8_t stFly; ///< Status of flying \n
|
||||||
|
// [7:6] departure status 11 - departed/00 - not departed \n
|
||||||
|
// [5:4] ready status 11 - ready/00 - not ready \n
|
||||||
|
// [3:2] attitude status 11 - attitude ok/00 - attitude not ok \n
|
||||||
|
// [1:0] attitude adjust status 11 - adjusted/00 - not adjusted
|
||||||
|
float posX; ///< coord X Position in launch coordinate system
|
||||||
|
float posY; ///< coord Y Position in launch coordinate system
|
||||||
|
float posZ; ///< coord Z Position in launch coordinate system
|
||||||
|
float vX; ///< Speed X in launch coordinate system
|
||||||
|
float vY; ///< Speed Y in launch coordinate system
|
||||||
|
float vZ; ///< Speed Z in launch coordinate system
|
||||||
|
float pitch; ///< Pitch Attitude in launch inertia coordinate system
|
||||||
|
float yaw; ///< Yaw Attitude in launch inertia coordinate system
|
||||||
|
float roll; ///< Roll Attitude in launch inertia coordinate system
|
||||||
|
} SYSINFO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct SYSBUSLOG
|
||||||
|
* @brief System Info holds the system bus log
|
||||||
|
*/
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
// SystemBus log
|
||||||
|
|
||||||
|
uint16_t lastConfig; ///< Last valid config \n
|
||||||
|
// byte 0: 0x11 FLJ, 0x00 LJ \n
|
||||||
|
// byte 1: 0x66 Full Power, 0x88 Low Power
|
||||||
|
uint32_t pollCnt; ///< number of poll commands
|
||||||
|
uint32_t svcCnt; ///< number of service commands
|
||||||
|
uint32_t remoteCnt; ///< number of remote check commands
|
||||||
|
} SYSBUSLOG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct LINKLOG
|
||||||
|
* @brief Linklayer Log struct holds the Linklayer log
|
||||||
|
*/
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
// Network log
|
||||||
|
uint32_t tuNum; ///< current time unite number
|
||||||
|
uint8_t slotNum; ///< current slot number
|
||||||
|
uint8_t nodeType; ///< current node type
|
||||||
|
uint8_t cxnStatus; ///< current connection status
|
||||||
|
uint8_t linkStage; ///< current linklayer working stage
|
||||||
|
uint32_t recxnCnt; ///< reconnect trial count
|
||||||
|
uint8_t beamNo; ///< current working beam number
|
||||||
|
uint8_t beamWidth; ///< current working beam width
|
||||||
|
uint16_t beamAz; ///< current working beam angle Az
|
||||||
|
uint16_t beamEl; ///< current working beam angle Ez
|
||||||
|
uint16_t advTxCnt; ///< adv frame send count
|
||||||
|
uint16_t advRecvCnt; ///< adv frame received count
|
||||||
|
uint16_t advCorrectCnt; ///< adv frame received correctly count
|
||||||
|
uint32_t cfmTxCnt; ///< cfm frame send count
|
||||||
|
uint32_t cfmRecvCnt; ///< cfm frame received count
|
||||||
|
uint32_t cfmCorrectCnt; ///< adv frame received correctly count
|
||||||
|
uint32_t svcTxCnt; ///< svc frame send count
|
||||||
|
uint32_t svcRecvCnt; ///< svc frame received count
|
||||||
|
uint32_t svcCorrectCnt; ///< svc frame received correctly count
|
||||||
|
int32_t timeDev; ///< last time deviation result
|
||||||
|
uint32_t sendId; ///< last send data id
|
||||||
|
uint32_t recvId; ///< last received data id
|
||||||
|
uint8_t reserve[4]; ///< reserved data
|
||||||
|
} LINKLOG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct PHYLOG
|
||||||
|
* @brief Physical Layer Log struct holds the Linklayer log
|
||||||
|
*/
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
uint32_t acqCnt; ///< aquisition count
|
||||||
|
uint32_t fsyncCnt; ///< frame sync count
|
||||||
|
uint32_t decodeCnt; ///< decode count
|
||||||
|
uint32_t crcCnt; ///< crc valid count
|
||||||
|
double doppler; ///< last doppler estimation result
|
||||||
|
uint64_t recvStamp; ///< last frame arrival time
|
||||||
|
double acqPAPR; ///< last acquisition peak-average ration
|
||||||
|
uint8_t acqPhase; ///< last acquisition phase estimation
|
||||||
|
uint8_t acqFreqCh; ///< last acquisition frequency deviation estimation
|
||||||
|
double fsyncPAPR; ///< last frame sync peak-average ration
|
||||||
|
uint8_t fsyncFreqCh; ///< last frame sync frequency estimation
|
||||||
|
uint16_t deintlvAmpEst; ///< de-interleave amplitude estimation
|
||||||
|
uint8_t antMode; ///< current antenna working mode
|
||||||
|
uint8_t reserve[3]; ///< reserved data
|
||||||
|
} PHYLOG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct HWSTATE
|
||||||
|
* @brief Hardware Status Log struct holds all hardware status
|
||||||
|
*/
|
||||||
|
typedef struct __attribute__((packed))
|
||||||
|
{
|
||||||
|
bool isSpOk; ///< signal processor state
|
||||||
|
bool isAntOk; ///< antenna state
|
||||||
|
// -- Signal processor status
|
||||||
|
uint8_t spFpgaVolt; ///< Signal processor voltage state indicator
|
||||||
|
uint8_t spClkState; ///< Signal processor clock state indicator
|
||||||
|
uint8_t spAdLockState; ///< Signal processor adc lock state indicator
|
||||||
|
int8_t spAdTemp_0; ///< Signal processor adc0 temperature
|
||||||
|
int8_t spAdTemp_1; ///< Signal processor adc1 temperature
|
||||||
|
int8_t spFpgaTemp; ///< Signal processor FPGA temperature
|
||||||
|
// -- Antenna status
|
||||||
|
uint8_t antVolt; ///< Antenna voltage state indicator
|
||||||
|
int8_t antTemp; ///< Antenna rf temperature
|
||||||
|
uint8_t antPll; ///< Antenna rf lock state indicator
|
||||||
|
uint8_t antMgc0; ///< Antenna rf mgc0~1 indicator
|
||||||
|
uint8_t antMgc1; ///< Antenna rf mgc2~3 indicator
|
||||||
|
uint8_t phyId;
|
||||||
|
uint8_t reserve[1];
|
||||||
|
} HWSTATE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct PAYLOAD
|
||||||
|
* @brief Payload struct holds the service payload
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t dataId;
|
||||||
|
uint8_t data[PAYLOAD_LEN_MAX];
|
||||||
|
} PAYLOAD;
|
||||||
|
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
int32_t SysMonitor_Init(void);
|
||||||
|
void SysMonitor_Destroy(void);
|
||||||
|
|
||||||
|
void SysMonitor_UpdateSysinfo(const SYSINFO *info);
|
||||||
|
void SysMonitor_GetSysinfo(SYSINFO *info);
|
||||||
|
|
||||||
|
void SysMonitor_UpdateSendPayload(const uint8_t *buff, size_t len);
|
||||||
|
void SysMonitor_UpdateRecvPayload(const uint8_t *buff, uint32_t id, size_t len);
|
||||||
|
void SysMonitor_GetSendPayload(uint8_t *buff, uint32_t *id, size_t len);
|
||||||
|
void SysMonitor_GetRecvPayload(uint8_t *buff, uint32_t *id, size_t len);
|
||||||
|
|
||||||
|
void SysMonitor_UpdateLinklayerLog(const LINKLOG *log);
|
||||||
|
void SysMonitor_UpdatePhysicalLayerLog(const PHYLOG *log);
|
||||||
|
void SysMonitor_UpdateHardwareStatus(const HWSTATE *state);
|
||||||
|
void SysMonitor_GetLinklayerLog(LINKLOG *log);
|
||||||
|
void SysMonitor_GetPhysicalLayerLog(PHYLOG *log);
|
||||||
|
void SysMonitor_GetHardwareStatus(HWSTATE *state);
|
||||||
|
|
||||||
|
#endif //__SYSTEM_MONITOR_H_
|
||||||
|
|
||||||
|
/** @} */
|
||||||
@@ -0,0 +1,564 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file systembus.c
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief System bus protocol implementation file.
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup SystemBus
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "systembus.h"
|
||||||
|
#include "systembus_msg.h"
|
||||||
|
#include "systembus_psuart.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "circ_queue.h"
|
||||||
|
#include "../system_monitor.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup SystemBus_Protocol_Routine
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
static int32_t SystemBus_StartListen(SYSBUS *instPtr);
|
||||||
|
static int32_t SystemBus_GenSelfTestRsp(SYSBUS *instPtr);
|
||||||
|
static int32_t SystemBus_BindingConfig(SYSBUS *instPtr, uint16_t *msg);
|
||||||
|
static int32_t SystemBus_PowerUp(SYSBUS *instPtr, uint16_t *msg);
|
||||||
|
static int32_t SystemBus_ModeSwicth(SYSBUS *instPtr, uint16_t *msg);
|
||||||
|
/**************************** Type Definitions *******************************/
|
||||||
|
/************************** Variable Definitions *****************************/
|
||||||
|
// TODO: better approach?
|
||||||
|
#include "../networking/link_layer/link_layer.h"
|
||||||
|
#include "../networking/phy_layer/phy_layer.h"
|
||||||
|
extern L2_INST *linkInstPtr;
|
||||||
|
extern L2_CONFIG linkConfig;
|
||||||
|
|
||||||
|
inline bool SystemBus_IsReqPending(SYSBUS *instPtr)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
return (!isCircQueueEmpty(instPtr->rxQueue));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool SystemBus_IsRsqPending(SYSBUS *instPtr)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
return (!isCircQueueEmpty(instPtr->txQueue));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool SystemBus_IsTxBusy(SYSBUS *instPtr)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
return SysbusPSUart_IsTxBusy(instPtr->uartInst);
|
||||||
|
}
|
||||||
|
inline bool SystemBus_IsRxBusy(SYSBUS *instPtr)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
return SysbusPSUart_IsRxBusy(instPtr->uartInst);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start listening income messages
|
||||||
|
*/
|
||||||
|
static int32_t SystemBus_StartListen(SYSBUS *instPtr) {
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
int32_t Status;
|
||||||
|
SYSBUS_PSUART_FRAME *nextReq = malloc(sizeof(SYSBUS_PSUART_FRAME));
|
||||||
|
if (nextReq == NULL) {
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
Status = SysbusPSUart_Recv(instPtr->uartInst, nextReq);
|
||||||
|
if (Status != SUCCESS) {
|
||||||
|
free(nextReq);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate System Bus SelfTest response.
|
||||||
|
*/
|
||||||
|
static int32_t SystemBus_GenSelfTestRsp(SYSBUS *instPtr)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
SYSBUS_PSUART_FRAME *sysbusRsp = malloc(sizeof(SYSBUS_PSUART_FRAME));
|
||||||
|
if (sysbusRsp == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to allocate memory for SELF TEST Response!\n");
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
HWSTATE *hwStatsPtr = &(instPtr->hwState);
|
||||||
|
uint16_t *rsp = (uint16_t*)sysbusRsp->data;
|
||||||
|
memset(rsp, 0x00, RSP_SELF_TEST_LEN);
|
||||||
|
rsp[WD_CMD] = RSP_SELF_TEST;
|
||||||
|
SysMonitor_GetHardwareStatus(hwStatsPtr);
|
||||||
|
if (L2_isStarted(linkInstPtr))
|
||||||
|
{
|
||||||
|
rsp[WD_RSP_ST_STATE] = (hwStatsPtr->isSpOk && hwStatsPtr->isAntOk) ? RSP_ST_OK : RSP_ST_ERROR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rsp[WD_RSP_ST_STATE] = (hwStatsPtr->isSpOk) ? RSP_ST_OK : RSP_ST_ERROR;
|
||||||
|
}
|
||||||
|
sysbusRsp->len = RSP_SELF_TEST_LEN;
|
||||||
|
|
||||||
|
if (CircQueuePush(instPtr->txQueue, (void *)sysbusRsp) == false)
|
||||||
|
{
|
||||||
|
free(sysbusRsp);
|
||||||
|
DBG_ERROR("SystemBus::TX Queue overflowed!\n");
|
||||||
|
return EQUEUE;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Binding system configuration
|
||||||
|
*/
|
||||||
|
static int32_t SystemBus_BindingConfig(SYSBUS *instPtr, uint16_t *msg)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
ASSERT(msg != NULL);
|
||||||
|
// TODO: frequency and hopping pattern configure...
|
||||||
|
SYSBUS_PSUART_FRAME *sysbusRsp = malloc(sizeof(SYSBUS_PSUART_FRAME));
|
||||||
|
if (sysbusRsp == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to allocate memory for SELF TEST Response!\n");
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
uint16_t* rsp = (uint16_t*)sysbusRsp->data;
|
||||||
|
rsp[WD_CMD] = RSP_CONFIG;
|
||||||
|
rsp[WD_RSP_STATE] = RSP_STA_OK; // TODO:
|
||||||
|
sysbusRsp->len = RSP_CONFIG_LEN;
|
||||||
|
if (CircQueuePush(instPtr->txQueue, (void *)sysbusRsp) == false)
|
||||||
|
{
|
||||||
|
free(sysbusRsp);
|
||||||
|
DBG_ERROR("SystemBus::TX Queue overflowed!\n");
|
||||||
|
return EQUEUE;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Apply system parameter configuration
|
||||||
|
*/
|
||||||
|
static int32_t SystemBus_PowerUp(SYSBUS *instPtr, uint16_t *msg)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
ASSERT(msg != NULL);
|
||||||
|
if (msg[WD_CMD] != CMD_POWERUP || msg[WD_PWUP_SATID] != SATID_NEW) {
|
||||||
|
return EIGNORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: configure speed, power mode
|
||||||
|
PHY_INST *phyRef = linkInstPtr->config.phyInstPtr;
|
||||||
|
TMC_INST *tmcRef = linkInstPtr->config.tmcInstPtr;
|
||||||
|
bool reconfig = false;
|
||||||
|
|
||||||
|
if (msg[WD_PWUP_SATMODE] == PWUP_SATMODE_UP) {
|
||||||
|
// full power config
|
||||||
|
Phy_AntConfigMode(phyRef, PHY_ANT_MODE_POWER_FULL);
|
||||||
|
if (reconfig || !L2_isStarted(linkInstPtr))
|
||||||
|
{
|
||||||
|
Linklayer_Reconfig(linkInstPtr, &linkConfig);
|
||||||
|
}
|
||||||
|
Linklayer_Start(linkInstPtr);
|
||||||
|
}
|
||||||
|
else if (msg[WD_PWUP_SATMODE] == PWUP_SATMODE_DOWN)
|
||||||
|
{
|
||||||
|
// silence config
|
||||||
|
// TODO: better approach?
|
||||||
|
Linklayer_Halt(linkInstPtr);
|
||||||
|
Phy_AntConfigMode(phyRef, PHY_ANT_MODE_STANDBY);
|
||||||
|
TIME_WORD pullTime = {0, 0};
|
||||||
|
pullTime.int_part = TimeCtrl_GetIntCnt(tmcRef) + 1;
|
||||||
|
if (Phy_SetTimeWord(phyRef, &pullTime, PHY_TIME_WORD_POLL) != SUCCESS)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Physical set pull time failed.\n");
|
||||||
|
}
|
||||||
|
Phy_SetupNextSlot(phyRef, PHY_TOR_RX, L1_10KBPS_10MS_FRAME, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Ignore current command
|
||||||
|
DBG_ERROR("Unexpected config command 0x%02X:0x%02X",
|
||||||
|
WD_EN_CMD, msg[WD_EN_CMD]);
|
||||||
|
return EIGNORE;
|
||||||
|
}
|
||||||
|
// TODO: speed configure.
|
||||||
|
instPtr->sysbusLog.lastConfig = msg[WD_PWUP_SATMODE];
|
||||||
|
|
||||||
|
|
||||||
|
SYSBUS_PSUART_FRAME *sysbusRsp = malloc(sizeof(SYSBUS_PSUART_FRAME));
|
||||||
|
if (sysbusRsp == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to allocate memory for SELF TEST Response!\n");
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
uint16_t* rsp = (uint16_t*)sysbusRsp->data;
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_CMD, RSP_POWERUP);
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_PWUP_SATE, RSP_PWUP_OK); // TODO:
|
||||||
|
sysbusRsp->len = RSP_POWERUP_LEN;
|
||||||
|
if (CircQueuePush(instPtr->txQueue, (void *)sysbusRsp) == false)
|
||||||
|
{
|
||||||
|
free(sysbusRsp);
|
||||||
|
DBG_ERROR("SystemBus::TX Queue overflowed!\n");
|
||||||
|
return EQUEUE;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Switch working mode
|
||||||
|
*/
|
||||||
|
static int32_t SystemBus_ModeSwicth(SYSBUS *instPtr, uint16_t *msg)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
ASSERT(msg != NULL);
|
||||||
|
PHY_INST *phyRef = linkInstPtr->config.phyInstPtr;
|
||||||
|
// TODO: To confirm
|
||||||
|
if (msg[WD_CMD] != CMD_MODE_SWITCH || msg[WD_MODESW_SATID_0] != SATID_NEW) {
|
||||||
|
return EIGNORE;
|
||||||
|
}
|
||||||
|
if (msg[WD_MODESW_ANTMODE_0] == MODESW_ANTMODE_FULL_POWER)
|
||||||
|
{
|
||||||
|
// full power config
|
||||||
|
Phy_AntConfigMode(phyRef, PHY_ANT_MODE_POWER_FULL);
|
||||||
|
}
|
||||||
|
else if (msg[WD_MODESW_ANTMODE_0] == MODESW_ANTMODE_LOW_POWER)
|
||||||
|
{
|
||||||
|
// low power config
|
||||||
|
Phy_AntConfigMode(phyRef, PHY_ANT_MODE_POWER_LOW);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Ignore current command
|
||||||
|
DBG_ERROR("Unexpected config command 0x%02X:0x%02X",
|
||||||
|
WD_EN_CMD, msg[WD_EN_CMD]);
|
||||||
|
return EIGNORE;
|
||||||
|
}
|
||||||
|
instPtr->sysbusLog.lastConfig = msg[WD_MODESW_SATMODE_0];
|
||||||
|
|
||||||
|
|
||||||
|
SYSBUS_PSUART_FRAME *sysbusRsp = malloc(sizeof(SYSBUS_PSUART_FRAME));
|
||||||
|
if (sysbusRsp == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to allocate memory for SELF TEST Response!\n");
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
uint16_t* rsp = (uint16_t*)sysbusRsp->data;
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_CMD, RSP_MODE_SWITCH);
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_PWUP_SATE, RSP_MODESW_OK); // TODO:
|
||||||
|
sysbusRsp->len = RSP_MODE_SWITCH_LEN;
|
||||||
|
if (CircQueuePush(instPtr->txQueue, (void *)sysbusRsp) == false)
|
||||||
|
{
|
||||||
|
free(sysbusRsp);
|
||||||
|
DBG_ERROR("SystemBus::TX Queue overflowed!\n");
|
||||||
|
return EQUEUE;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate System Bus remote check command response
|
||||||
|
*/
|
||||||
|
int32_t SystemBus_GenRemoteCheckRsp(SYSBUS *instPtr)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
SYSBUS_PSUART_FRAME *sysbusRsp = malloc(sizeof(SYSBUS_PSUART_FRAME));
|
||||||
|
if (sysbusRsp == NULL)
|
||||||
|
{
|
||||||
|
DBG_ERROR("Failed to allocate memory for LJ REMOTE TEST Response!\n");
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
SysMonitor_GetLinklayerLog(&(instPtr->linkLog));
|
||||||
|
SysMonitor_GetPhysicalLayerLog(&(instPtr->phyLog));
|
||||||
|
SysMonitor_GetHardwareStatus(&(instPtr->hwState));
|
||||||
|
const LINKLOG *linkLog = &(instPtr->linkLog);
|
||||||
|
const HWSTATE *hwState = &(instPtr->hwState);
|
||||||
|
const PHYLOG *phyLog = &(instPtr->phyLog);
|
||||||
|
const SYSBUSLOG *sysbusLog = &(instPtr->sysbusLog);
|
||||||
|
|
||||||
|
uint16_t *rsp = (uint16_t*)sysbusRsp->data;
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_CMD, RSP_REMOTE_TEST);
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_SATID, SATID_NEW);
|
||||||
|
if (phyLog->antMode == PHY_ANT_MODE_POWER_LOW) {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_SATMODE, RSP_RT_SATMODE_LOWPOWER);
|
||||||
|
}
|
||||||
|
else if(phyLog->antMode == PHY_ANT_MODE_POWER_FULL) {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_SATMODE, RSP_RT_SATMODE_FULLPOWER);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_SATMODE, 0x0000);
|
||||||
|
}
|
||||||
|
if(L2_GetMainState(linkInstPtr) == L2_INIT_STATE) {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_NETSTATE, RSP_RT_NETSTATE_JOIN);
|
||||||
|
}
|
||||||
|
else if(L2_GetMainState(linkInstPtr) == L2_NORMAL_STATE) {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_NETSTATE, RSP_RT_NETSTATE_INSERVICE);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_NETSTATE, RSP_RT_NETSTATE_NOCXN);
|
||||||
|
}
|
||||||
|
ASSEMBLE_MSG_SCALAR(rsp, WD_RSP_RT_CNT, sysbusLog->remoteCnt);
|
||||||
|
ASSEMBLE_MSG_SCALAR(rsp, WD_RSP_RT_RECXN_CNT, linkLog->recxnCnt);
|
||||||
|
ASSEMBLE_MSG_SCALAR(rsp, WD_RSP_RT_TXSVC_CNT, linkLog->svcTxCnt);
|
||||||
|
ASSEMBLE_MSG_SCALAR(rsp, WD_RSP_RT_RXSVC_CNT, linkLog->svcRecvCnt);
|
||||||
|
ASSEMBLE_MSG_SCALAR(rsp, WD_RSP_RT_CRCTSVC_CNT, linkLog->svcCorrectCnt);
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_ANT_BEAMID, linkLog->beamNo);
|
||||||
|
float tempAngel;
|
||||||
|
tempAngel = (float)linkLog->beamEl;
|
||||||
|
ASSEMBLE_MSG_SCALAR(rsp, WD_RSP_RT_ANT_OFFAX, tempAngel);
|
||||||
|
tempAngel = (float)linkLog->beamAz;
|
||||||
|
ASSEMBLE_MSG_SCALAR(rsp, WD_RSP_RT_ANT_RNDAX, tempAngel);
|
||||||
|
if (hwState->isSpOk && hwState->isAntOk){
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_HWSTATE, RSP_RT_HWSTATE_OK);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_HWSTATE, 0x0000U);
|
||||||
|
}
|
||||||
|
if (hwState->spFpgaVolt == (VOLT_PS_OK | VOLT_PSAUX_OK | VOLT_DDR_OK | VOLT_PL_OK | VOLT_PLAUX_OK | VOLT_BRAM_OK)) {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_FPGA_VOLT, RSP_RT_FPGA_VOLT_OK);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_FPGA_VOLT, 0x0000);
|
||||||
|
}
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_FPGA_TEMP, hwState->spFpgaTemp);
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_ZYNQ_TEMP, hwState->spFpgaTemp);
|
||||||
|
if (hwState->spFpgaVolt == (VOLT_PS_OK | VOLT_PSAUX_OK | VOLT_DDR_OK | VOLT_PL_OK | VOLT_PLAUX_OK | VOLT_BRAM_OK)) {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_FPGA_VOLT, RSP_RT_FPGA_VOLT_OK);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_FPGA_VOLT, 0x0000);
|
||||||
|
}
|
||||||
|
if(hwState->spClkState == (CLK_SP_PLL0_LOCK | CLK_SP_PLL1_LOCK)
|
||||||
|
&& hwState->spClkState == (CLK_AD0_BBPLL_LOCK | CLK_AD0_RFPLL_LOCK | CLK_AD1_BBPLL_LOCK | CLK_AD1_RFPLL_LOCK)) {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_CLK_LOCK, RSP_RT_CLK_LOCK_OK);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_CLK_LOCK, 0x0000);
|
||||||
|
}
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_ANTID, ANTID_PAA);
|
||||||
|
if (phyLog->antMode == PHY_ANT_MODE_POWER_LOW) {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_ANTMODE, RSP_RT_ANTMODE_LOWPOWER);
|
||||||
|
}
|
||||||
|
else if(phyLog->antMode == PHY_ANT_MODE_POWER_FULL) {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_ANTMODE, RSP_RT_ANTMODE_FULLPOWER);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_ANTMODE, 0x0000);
|
||||||
|
}
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_ANT_VOLT, hwState->antVolt);
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_ANT_TEMP, hwState->antTemp);
|
||||||
|
if (hwState->antPll == (CLK_ANT_BBPLL_LOCK | CLK_ANT_RFPLL0_LOCK | CLK_ANT_RFPLL1_LOCK)) {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_ANT_LOCK, RSP_RT_ANT_LOCK_OK);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_ANT_LOCK, 0x0000);
|
||||||
|
}
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_ANT_MGC_0, hwState->antMgc0);
|
||||||
|
ASSEMBLE_MSG_IMMEDIATE(rsp, WD_RSP_RT_ANT_MGC_1, hwState->antMgc1);
|
||||||
|
sysbusRsp->len = RSP_REMOTE_TEST_LEN;
|
||||||
|
if (CircQueuePush(instPtr->txQueue, (void *)sysbusRsp) == false)
|
||||||
|
{
|
||||||
|
free(sysbusRsp);
|
||||||
|
DBG_WARNING("SystemBus::TX Queue overflowed!\n");
|
||||||
|
return EQUEUE;
|
||||||
|
}
|
||||||
|
instPtr->sysbusLog.remoteCnt++;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief A handler function. This handler evaluate the message from system
|
||||||
|
* bus receive queue, and make appropriate response.
|
||||||
|
*
|
||||||
|
* @param instPtr A pointer to System Bus instance.
|
||||||
|
*
|
||||||
|
* @return None
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t SystemBus_HandleCmd(SYSBUS *instPtr)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
int32_t Status;
|
||||||
|
SYSBUS_PSUART_FRAME *sysbusReq;
|
||||||
|
uint16_t *msg;
|
||||||
|
if (CircQueuePop(instPtr->rxQueue, (void **)(&sysbusReq)) == false)
|
||||||
|
{
|
||||||
|
DBG_WARNING("SystemBus::Nothing to be handled.\n");
|
||||||
|
return EIGNORE;
|
||||||
|
}
|
||||||
|
msg = (uint16_t*)sysbusReq->data;
|
||||||
|
|
||||||
|
switch (msg[WD_CMD])
|
||||||
|
{
|
||||||
|
case CMD_CONFIG:
|
||||||
|
Status = SystemBus_BindingConfig(instPtr, msg);
|
||||||
|
break;
|
||||||
|
case CMD_SELF_TEST:
|
||||||
|
if(msg[WD_ST_CMD] == ST_COMMAND) {
|
||||||
|
Status = SystemBus_GenSelfTestRsp(instPtr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Status = EIGNORE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CMD_POWERUP:
|
||||||
|
Status = SystemBus_PowerUp(instPtr, msg);
|
||||||
|
break;
|
||||||
|
case CMD_MODE_SWITCH:
|
||||||
|
Status = SystemBus_ModeSwicth(instPtr, msg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBG_ERROR("SystemBus::Unknown command code!\n");
|
||||||
|
Status = FAILURE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(sysbusReq);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief This function send a repose frame from system bus tx queue.
|
||||||
|
*
|
||||||
|
* @param instPtr A pointer to System Bus instance.
|
||||||
|
*
|
||||||
|
* @return None
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t SystemBus_MakeResp(SYSBUS *instPtr)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
int32_t Status;
|
||||||
|
SYSBUS_PSUART_FRAME *sysbusRsp;
|
||||||
|
if (CircQueuePop(instPtr->txQueue, (void **)(&sysbusRsp)) == false) {
|
||||||
|
DBG_WARNING("SystemBus::Nothing to be sent.\n");
|
||||||
|
return EIGNORE;
|
||||||
|
}
|
||||||
|
Status = SysbusPSUart_Send(instPtr->uartInst, sysbusRsp);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Initialize System Bus instance.
|
||||||
|
*
|
||||||
|
* @param InstPtr A double pointer to System Bus instance.
|
||||||
|
* @param config A pointer to System Bus configurations.
|
||||||
|
*
|
||||||
|
* @return Error code.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t SystemBus_Init(SYSBUS **instPtr, SYSBUS_CONFIG *config)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
ASSERT(config != NULL);
|
||||||
|
int32_t Status;
|
||||||
|
(*instPtr) = malloc(sizeof(SYSBUS));
|
||||||
|
if ((*instPtr) == NULL)
|
||||||
|
{
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
(*instPtr)->rxQueue = NULL;
|
||||||
|
(*instPtr)->txQueue = NULL;
|
||||||
|
(*instPtr)->uartInst = NULL;
|
||||||
|
memcpy(&((*instPtr)->config), config, sizeof(SYSBUS_CONFIG));
|
||||||
|
memset(&((*instPtr)->sysbusLog), 0x00, sizeof(SYSBUSLOG));
|
||||||
|
memset(&((*instPtr)->linkLog), 0x00, sizeof(LINKLOG));
|
||||||
|
memset(&((*instPtr)->phyLog), 0x00, sizeof(PHYLOG));
|
||||||
|
memset(&((*instPtr)->hwState), 0x00, sizeof(HWSTATE));
|
||||||
|
Status = SysbusPSUart_Init(&((*instPtr)->uartInst), &(config->uartConfig));
|
||||||
|
if (Status != SUCCESS)
|
||||||
|
{
|
||||||
|
SystemBus_Destroy(*instPtr);
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
if (CircQueueCreate(&((*instPtr)->txQueue), (*instPtr)->config.txQueueMax) == false)
|
||||||
|
{
|
||||||
|
SystemBus_Destroy(*instPtr);
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
if (CircQueueCreate(&((*instPtr)->rxQueue), (*instPtr)->config.rxQueueMax) == false)
|
||||||
|
{
|
||||||
|
SystemBus_Destroy(*instPtr);
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
return SystemBus_StartListen(*instPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief Destroy System Bus instance.
|
||||||
|
*
|
||||||
|
* @param InstPtr A pointer to System Bus instance.
|
||||||
|
*
|
||||||
|
* @return None.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
void SystemBus_Destroy(SYSBUS *instPtr)
|
||||||
|
{
|
||||||
|
if (instPtr == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SysbusPSUart_Destroy(instPtr->uartInst);
|
||||||
|
free(instPtr->txQueue);
|
||||||
|
free(instPtr->rxQueue);
|
||||||
|
free(instPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief This function handles the systembus rx irq events.
|
||||||
|
*
|
||||||
|
* @param instPtr A pointer to System Bus instance.
|
||||||
|
*
|
||||||
|
* @return None
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
int32_t SystemBus_IntrHandler(SYSBUS *instPtr)
|
||||||
|
{
|
||||||
|
ASSERT(instPtr != NULL);
|
||||||
|
int32_t Status;
|
||||||
|
Status = SystemBus_PSUART_IntrHandler(instPtr->uartInst);
|
||||||
|
if (Status != SUCCESS) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
if(instPtr->uartInst->rxDone == true) {
|
||||||
|
SYSBUS_PSUART_FRAME *sysbusReq = SysbusPSUart_GetLastRecvMsg(instPtr->uartInst);
|
||||||
|
if(sysbusReq != NULL) {
|
||||||
|
if (CircQueuePush(instPtr->rxQueue, (void *)sysbusReq) == false) {
|
||||||
|
DBG_ERROR("SystemBus::RX Queue overflowed!\n");
|
||||||
|
return EQUEUE;
|
||||||
|
}
|
||||||
|
// restart receiving, constantly listening income messages
|
||||||
|
Status = SystemBus_StartListen(instPtr);
|
||||||
|
if (Status != SUCCESS) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} SystemBus*/
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* @file systembus.h
|
||||||
|
* @author FanHao (hao_fan_bit_ee@163.com)
|
||||||
|
* @brief System bus protocol header file.
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-05-06
|
||||||
|
*
|
||||||
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
||||||
|
* Lab of Communication and Network
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup SystemBus
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#ifndef __SYSTEMBUS_H_
|
||||||
|
#define __SYSTEMBUS_H_
|
||||||
|
|
||||||
|
/***************************** Include Files *********************************/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "systembus_psuart.h"
|
||||||
|
#include "circ_queue.h"
|
||||||
|
#include "../system_monitor.h"
|
||||||
|
|
||||||
|
/************************** Constant Definitions *****************************/
|
||||||
|
/************************** Data Type Definitions ****************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct SYSBUS_CONFIG
|
||||||
|
* @brief SystemBus Config struct holds SystemBus initialization parameters
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SYSBUS_PSUART_CONFIG uartConfig;
|
||||||
|
uint32_t txQueueMax; ///< maximum tx queue length
|
||||||
|
uint32_t rxQueueMax; ///< maximum rx queue length
|
||||||
|
} SYSBUS_CONFIG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct SYSBUS
|
||||||
|
* @brief SystemBus Instance struct
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SYSBUS_CONFIG config; ///< SystemBus initialization parameters
|
||||||
|
SYSBUSLOG sysbusLog; ///< SystemBus log
|
||||||
|
LINKLOG linkLog; ///< Link layer log
|
||||||
|
PHYLOG phyLog; ///< Physical layer log
|
||||||
|
HWSTATE hwState; ///< Hardware status
|
||||||
|
SYSBUS_PSUART *uartInst; ///< physical uart controller instance
|
||||||
|
CIRC_QUEUE *txQueue; ///< tx queue
|
||||||
|
CIRC_QUEUE *rxQueue; ///< rx queue
|
||||||
|
} SYSBUS;
|
||||||
|
|
||||||
|
/************************** Function Prototypes ******************************/
|
||||||
|
|
||||||
|
int32_t SystemBus_Init(SYSBUS **instPtr, SYSBUS_CONFIG *config);
|
||||||
|
void SystemBus_Destroy(SYSBUS *instPtr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup SystemBus_Protocol_Routine
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
int32_t SystemBus_HandleCmd(SYSBUS *instPtr);
|
||||||
|
int32_t SystemBus_MakeResp(SYSBUS *instPtr);
|
||||||
|
int32_t SystemBus_GenRemoteCheckRsp(SYSBUS *instPtr);
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
int32_t SystemBus_IntrHandler(SYSBUS *instPtr);
|
||||||
|
|
||||||
|
bool SystemBus_IsReqPending(SYSBUS *instPtr);
|
||||||
|
bool SystemBus_IsRsqPending(SYSBUS *instPtr);
|
||||||
|
|
||||||
|
bool SystemBus_IsTxBusy(SYSBUS *instPtr);
|
||||||
|
bool SystemBus_IsRxBusy(SYSBUS *instPtr);
|
||||||
|
|
||||||
|
#endif //__SYSTEMBUS_H_
|
||||||
|
|
||||||
|
/** @} SystemBus*/
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user