Compare commits
25
Commits
pin-io-improv
...
dac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f40c6e4dd
|
||
|
|
b2066a9010
|
||
|
|
590d550a09
|
||
|
|
274f2be6e0
|
||
|
|
76d1cd3a24
|
||
|
|
3654bf2206
|
||
|
|
5687196bdd
|
||
|
|
da330b4b73
|
||
|
|
0b14e5dda4
|
||
|
|
887887b675
|
||
|
|
e96ecceec9
|
||
|
|
d8bdaf7203
|
||
|
|
3fdd51ba2e
|
||
|
|
5dd350ffe4
|
||
|
|
4b8d24ae0f
|
||
|
|
ed7a4c80a0
|
||
|
|
78897f84b3
|
||
|
|
8410c273ab
|
||
|
|
2812f962d9
|
||
|
|
7f4c06ae4b
|
||
|
|
5019bf225d
|
||
|
|
41ad18cc7c
|
||
|
|
101d2534f4
|
||
|
|
1f2d346e23
|
||
|
|
639031fc38
|
+2
-2
@@ -110,7 +110,7 @@ extern uint32_t SystemCoreClock;
|
||||
#define configCHECK_FOR_STACK_OVERFLOW 2
|
||||
#define configENABLE_BACKWARD_COMPATIBILITY 0
|
||||
|
||||
#define configUSE_TIMERS 1
|
||||
#define configUSE_TIMERS 0
|
||||
#define configTIMER_TASK_PRIORITY TSK_TIMERS_PRIO // above normal
|
||||
#define configTIMER_TASK_STACK_DEPTH TSK_STACK_TIMERS //128
|
||||
#define configTIMER_QUEUE_LENGTH 4
|
||||
@@ -151,7 +151,7 @@ to exclude the API function. */
|
||||
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
|
||||
|
||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||
#elif defined(GEX_PLAT_F072_DISCOVERY)
|
||||
#elif defined(STM32F072xB)
|
||||
// This is for F072
|
||||
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 3
|
||||
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 1
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "task_main.h"
|
||||
|
||||
#include "USB/usbd_cdc_if.h"
|
||||
#include "USB/usb_device.h"
|
||||
#include "TinyFrame.h"
|
||||
|
||||
extern osSemaphoreId semVcomTxReadyHandle;
|
||||
@@ -15,6 +16,30 @@ extern osMutexId mutTinyFrameTxHandle;
|
||||
|
||||
void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
|
||||
{
|
||||
#if 1
|
||||
const uint32_t real_size = len;
|
||||
|
||||
// Padding to a multiple of 64 bytes - this is supposed to maximize the bulk transfer speed
|
||||
if (len&0x3F) {
|
||||
uint32_t pad = (64 - (len&0x3F));
|
||||
memset((void *) (buff + len), 0, pad);
|
||||
len += pad; // padding to a multiple of 64 (size of the endpoint)
|
||||
}
|
||||
|
||||
// We bypass the USBD driver library's overhead by using the HAL function directly
|
||||
assert_param(HAL_OK == HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) buff, len));
|
||||
|
||||
// The buffer is the TF transmit buffer, we can't leave it to work asynchronously because
|
||||
// the next call could modify it before it's been transmitted (in the case of a chunked / multi-part frame)
|
||||
|
||||
// the assumption here is that all until the last chunk use the full buffer capacity
|
||||
if (real_size == TF_SENDBUF_LEN) {
|
||||
if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 100)) {
|
||||
TF_Error("Tx stalled in WriteImpl");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void) tf;
|
||||
#define CHUNK 64 // same as TF_SENDBUF_LEN, so we should always have only one run of the loop
|
||||
int32_t total = (int32_t) len;
|
||||
@@ -26,21 +51,36 @@ void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
|
||||
}
|
||||
|
||||
const uint16_t chunksize = (uint16_t) MIN(total, CHUNK);
|
||||
assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, chunksize));
|
||||
|
||||
// this is an attempt to speed it up a little by removing a couple levels of indirection
|
||||
assert_param(HAL_OK == HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) buff, chunksize));
|
||||
|
||||
// USBD_LL_Transmit(&hUsbDeviceFS, CDC_IN_EP, (uint8_t *) buff, chunksize);
|
||||
// assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, chunksize));
|
||||
|
||||
buff += chunksize;
|
||||
total -= chunksize;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Claim the TX interface before composing and sending a frame */
|
||||
bool TF_ClaimTx(TinyFrame *tf)
|
||||
{
|
||||
(void) tf;
|
||||
// assert_param(osThreadGetId() != tskMainHandle);
|
||||
assert_param(!inIRQ());
|
||||
// assert_param(!inIRQ()); // useless delay
|
||||
assert_param(pdTRUE == xSemaphoreTake(mutTinyFrameTxHandle, 5000)); // trips the wd
|
||||
|
||||
// The last chunk from some previous frame may still be being transmitted,
|
||||
// wait for it to finish (the semaphore is given in the CDC tx done handler)
|
||||
if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 100)) {
|
||||
TF_Error("Tx stalled in Claim");
|
||||
|
||||
// release the guarding mutex again
|
||||
assert_param(pdTRUE == xSemaphoreGive(mutTinyFrameTxHandle));
|
||||
return false;
|
||||
}
|
||||
|
||||
assert_param(osOK == osMutexWait(mutTinyFrameTxHandle, 5000));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -48,5 +88,7 @@ bool TF_ClaimTx(TinyFrame *tf)
|
||||
void TF_ReleaseTx(TinyFrame *tf)
|
||||
{
|
||||
(void) tf;
|
||||
assert_param(osOK == osMutexRelease(mutTinyFrameTxHandle));
|
||||
assert_param(pdTRUE == xSemaphoreGive(mutTinyFrameTxHandle));
|
||||
|
||||
// the last payload is sent asynchronously
|
||||
}
|
||||
|
||||
@@ -870,7 +870,11 @@ static inline uint32_t _TF_FN TF_ComposeTail(uint8_t *outbuff, TF_CKSUM *cksum)
|
||||
*/
|
||||
static bool _TF_FN TF_SendFrame_Begin(TinyFrame *tf, TF_Msg *msg, TF_Listener listener, TF_TICKS timeout)
|
||||
{
|
||||
TF_TRY(TF_ClaimTx(tf));
|
||||
bool suc = TF_ClaimTx(tf);
|
||||
if (!suc) {
|
||||
TF_Error("TF lock not free");
|
||||
return false;
|
||||
}
|
||||
|
||||
tf->tx_pos = (uint32_t) TF_ComposeHead(tf, tf->sendbuf, msg); // frame ID is incremented here if it's not a response
|
||||
tf->tx_len = msg->len;
|
||||
@@ -1031,10 +1035,10 @@ bool _TF_FN TF_Query_Multipart(TinyFrame *tf, TF_Msg *msg, TF_Listener listener,
|
||||
return TF_Query(tf, msg, listener, timeout);
|
||||
}
|
||||
|
||||
void _TF_FN TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg)
|
||||
bool _TF_FN TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg)
|
||||
{
|
||||
msg->data = NULL;
|
||||
TF_Respond(tf, msg);
|
||||
return TF_Respond(tf, msg);
|
||||
}
|
||||
|
||||
void _TF_FN TF_Multipart_Payload(TinyFrame *tf, const uint8_t *buff, uint32_t length)
|
||||
|
||||
@@ -369,7 +369,7 @@ bool TF_Query_Multipart(TinyFrame *tf, TF_Msg *msg, TF_Listener listener, TF_TIC
|
||||
* TF_Respond() with multipart payload.
|
||||
* msg.data is ignored and set to NULL
|
||||
*/
|
||||
void TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg);
|
||||
bool TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg);
|
||||
|
||||
/**
|
||||
* Send the payload for a started multipart frame. This can be called multiple times
|
||||
|
||||
@@ -66,6 +66,7 @@ PCD_HandleTypeDef hpcd_USB_FS;
|
||||
/* init function */
|
||||
void MX_USB_DEVICE_Init(void)
|
||||
{
|
||||
dbg("USB device init ...");
|
||||
/* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */
|
||||
|
||||
/* USER CODE END USB_DEVICE_Init_PreTreatment */
|
||||
|
||||
+1
-1
@@ -314,7 +314,7 @@ void USBD_CDC_TransmitDone(USBD_HandleTypeDef *pdev)
|
||||
assert_param(inIRQ());
|
||||
|
||||
portBASE_TYPE taskWoken = pdFALSE;
|
||||
assert_param(xSemaphoreGiveFromISR(semVcomTxReadyHandle, &taskWoken) == pdTRUE);
|
||||
assert_param(pdTRUE == xSemaphoreGiveFromISR(semVcomTxReadyHandle, &taskWoken));
|
||||
portYIELD_FROM_ISR(taskWoken);
|
||||
}
|
||||
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
|
||||
|
||||
+6
-6
@@ -84,13 +84,13 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle)
|
||||
__HAL_RCC_USB_CLK_ENABLE();
|
||||
|
||||
/* Peripheral interrupt init */
|
||||
#if defined(GEX_PLAT_F103_BLUEPILL)
|
||||
#if GEX_PLAT_F103_BLUEPILL
|
||||
HAL_NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 5, 0);
|
||||
HAL_NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
|
||||
#elif defined(GEX_PLAT_F072_DISCOVERY)
|
||||
#elif STM32F072xB
|
||||
HAL_NVIC_SetPriority(USB_IRQn, 3, 0);
|
||||
HAL_NVIC_EnableIRQ(USB_IRQn);
|
||||
#elif defined(GEX_PLAT_F303_DISCOVERY)
|
||||
#elif GEX_PLAT_F303_DISCOVERY
|
||||
// Pins need to be configured here
|
||||
|
||||
/**USB GPIO Configuration
|
||||
@@ -149,11 +149,11 @@ void HAL_PCD_MspDeInit(PCD_HandleTypeDef* pcdHandle)
|
||||
__HAL_RCC_USB_CLK_DISABLE();
|
||||
|
||||
/* Peripheral interrupt Deinit*/
|
||||
#if defined(GEX_PLAT_F103_BLUEPILL)
|
||||
#if GEX_PLAT_F103_BLUEPILL
|
||||
HAL_NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
|
||||
#elif defined(GEX_PLAT_F072_DISCOVERY)
|
||||
#elif STM32F072xB
|
||||
HAL_NVIC_DisableIRQ(USB_IRQn);
|
||||
#elif defined(GEX_PLAT_F303_DISCOVERY)
|
||||
#elif GEX_PLAT_F303_DISCOVERY
|
||||
HAL_NVIC_DisableIRQ(USB_LP_CAN_RX0_IRQn);
|
||||
#else
|
||||
#error "BAD PLATFORM"
|
||||
|
||||
+9
-4
@@ -2,6 +2,7 @@
|
||||
// Created by MightyPork on 2017/11/21.
|
||||
//
|
||||
|
||||
#include <platform/status_led.h>
|
||||
#include "platform.h"
|
||||
#include "framework/settings.h"
|
||||
#include "utils/ini_parser.h"
|
||||
@@ -64,7 +65,7 @@ static void settings_bulkread_cb(BulkRead *bulk, uint32_t chunk, uint8_t *buffer
|
||||
if (buffer == NULL) {
|
||||
free_ck(bulk);
|
||||
iw_end();
|
||||
dbg("INI read complete.");
|
||||
// dbg("INI read complete.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -80,7 +81,7 @@ static void settings_bulkread_cb(BulkRead *bulk, uint32_t chunk, uint8_t *buffer
|
||||
*/
|
||||
static TF_Result lst_ini_export(TinyFrame *tf, TF_Msg *msg)
|
||||
{
|
||||
dbg("Bulk read INI file");
|
||||
// dbg("Bulk read INI file");
|
||||
|
||||
BulkRead *bulk = malloc_ck(sizeof(BulkRead));
|
||||
assert_param(bulk != NULL);
|
||||
@@ -91,6 +92,7 @@ static TF_Result lst_ini_export(TinyFrame *tf, TF_Msg *msg)
|
||||
bulk->userdata = NULL;
|
||||
|
||||
bulkread_start(tf, bulk);
|
||||
Indicator_Effect(STATUS_DISK_BUSY_SHORT);
|
||||
|
||||
return TF_STAY;
|
||||
}
|
||||
@@ -112,7 +114,7 @@ static void settings_bulkwrite_cb(BulkWrite *bulk, const uint8_t *chunk, uint32_
|
||||
|
||||
if (bulk->offset > 0) {
|
||||
settings_load_ini_end();
|
||||
dbg("INI write complete");
|
||||
// dbg("INI write complete");
|
||||
} else {
|
||||
dbg("INI write failed");
|
||||
}
|
||||
@@ -129,7 +131,7 @@ static void settings_bulkwrite_cb(BulkWrite *bulk, const uint8_t *chunk, uint32_
|
||||
*/
|
||||
static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg)
|
||||
{
|
||||
dbg("Bulk write INI file");
|
||||
// dbg("Bulk write INI file");
|
||||
|
||||
BulkWrite *bulk = malloc_ck(sizeof(BulkWrite));
|
||||
assert_param(bulk);
|
||||
@@ -152,6 +154,8 @@ static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg)
|
||||
|
||||
bulkwrite_start(tf, bulk);
|
||||
|
||||
Indicator_Effect(STATUS_DISK_BUSY);
|
||||
|
||||
done:
|
||||
return TF_STAY;
|
||||
}
|
||||
@@ -161,6 +165,7 @@ done:
|
||||
/** Listener: Save settings to Flash */
|
||||
static TF_Result lst_persist_cfg(TinyFrame *tf, TF_Msg *msg)
|
||||
{
|
||||
Indicator_Effect(STATUS_DISK_REMOVED);
|
||||
settings_save();
|
||||
return TF_STAY;
|
||||
}
|
||||
|
||||
+3
-1
@@ -13,8 +13,10 @@
|
||||
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
GEX_MsTick();
|
||||
// OS first, avoids jitter
|
||||
osSystickHandler();
|
||||
// GEX periodic updates
|
||||
GEX_MsTick();
|
||||
}
|
||||
|
||||
|
||||
|
||||
+10
-9
@@ -33,12 +33,6 @@ const char * rsc_get_name(Resource rsc)
|
||||
// we assume the returned value is not stored anywhere
|
||||
// and is directly used in a sprintf call, hence a static buffer is OK to use
|
||||
|
||||
if (rsc >= R_EXTI0 && rsc <= R_EXTI15) {
|
||||
uint8_t index = rsc - R_EXTI0;
|
||||
SNPRINTF(gpionamebuf, 8, "EXTI%d", index);
|
||||
return gpionamebuf;
|
||||
}
|
||||
|
||||
// R_PA0 is 0
|
||||
if (rsc <= R_PF15) {
|
||||
// we assume the returned value is not stored anywhere
|
||||
@@ -48,6 +42,12 @@ const char * rsc_get_name(Resource rsc)
|
||||
return gpionamebuf;
|
||||
}
|
||||
|
||||
if (rsc >= R_EXTI0 && rsc <= R_EXTI15) {
|
||||
uint8_t index = rsc - R_EXTI0;
|
||||
SNPRINTF(gpionamebuf, 8, "EXTI%d", index);
|
||||
return gpionamebuf;
|
||||
}
|
||||
|
||||
return rsc_names[rsc - R_EXTI15 - 1];
|
||||
}
|
||||
|
||||
@@ -85,11 +85,12 @@ const char * rsc_get_owner_name(Resource rsc)
|
||||
|
||||
void rsc_init_registry(void)
|
||||
{
|
||||
for(uint32_t i = 0; i < RSCMAP_LEN; i++) {
|
||||
UNIT_PLATFORM.resources[i] = global_rscmap[i] = 0xFF;
|
||||
}
|
||||
memset(UNIT_PLATFORM.resources, 0xFF, RSCMAP_LEN);
|
||||
memset(global_rscmap, 0xFF, RSCMAP_LEN);
|
||||
|
||||
rsc_initialized = true;
|
||||
|
||||
rsc_dbg("Total %d hw resources, bitmap has %d bytes.", RESOURCE_COUNT, RSCMAP_LEN);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
X(SPI1) X(SPI2) X(SPI3) \
|
||||
X(I2C1) X(I2C2) X(I2C3) \
|
||||
X(ADC1) X(ADC2) X(ADC3) X(ADC4) \
|
||||
X(DAC1) X(DAC2) \
|
||||
X(DAC1) \
|
||||
X(TSC) \
|
||||
X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \
|
||||
X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \
|
||||
X(TIM6) X(TIM7) X(TIM8) X(TIM9) X(TIM10) X(TIM11) X(TIM12) X(TIM13) X(TIM14) \
|
||||
@@ -24,7 +25,6 @@
|
||||
// X(I2S1) X(I2S2) X(I2S3)
|
||||
// X(OPAMP1) X(OPAMP2) X(OPAMP3) X(OPAMP4)
|
||||
// X(CAN1) X(CAN2)
|
||||
// X(TSC)
|
||||
// X(DCMI)
|
||||
// X(ETH)
|
||||
// X(FSMC)
|
||||
@@ -59,8 +59,12 @@ typedef enum hw_resource Resource;
|
||||
/** Enum of all resources */
|
||||
enum hw_resource {
|
||||
#define X(res_name) R_##res_name,
|
||||
// GPIO are at the beginning, because some units use the constants in their config to represent
|
||||
// selected pins and those must not change with adding more stuff to the main list
|
||||
XX_RESOURCES_GPIO
|
||||
// EXTIs (same like GPIOs) have dynamically generated labels to save rom space. Must be contiguous.
|
||||
XX_RESOURCES_EXTI
|
||||
// All the rest ...
|
||||
XX_RESOURCES
|
||||
#undef X
|
||||
R_NONE,
|
||||
|
||||
+1
-1
@@ -147,7 +147,7 @@ void MX_FREERTOS_Init(void) {
|
||||
stackmon_register("Main", mainTaskStack, sizeof(mainTaskStack));
|
||||
stackmon_register("Job+Msg", msgJobQueTaskStack, sizeof(msgJobQueTaskStack));
|
||||
stackmon_register("Idle", xIdleStack, sizeof(xIdleStack));
|
||||
stackmon_register("Timers", xTimersStack, sizeof(xTimersStack));
|
||||
// stackmon_register("Timers", xTimersStack, sizeof(xTimersStack));
|
||||
/* USER CODE END Init */
|
||||
|
||||
/* Create the mutex(es) */
|
||||
|
||||
@@ -16,6 +16,9 @@ GEX_SRC_DIR = \
|
||||
User/units/adc \
|
||||
User/units/sipo \
|
||||
User/units/fcap \
|
||||
User/units/touch \
|
||||
User/units/simple_pwm \
|
||||
User/units/dac \
|
||||
User/TinyFrame \
|
||||
User/CWPack \
|
||||
User/tasks
|
||||
@@ -95,7 +98,7 @@ GEX_CDEFS = $(GEX_CDEFS_BASE) \
|
||||
-DUSE_STACK_MONITOR=1 \
|
||||
-DUSE_DEBUG_UART=1 \
|
||||
-DDEBUG_MALLOC=0 \
|
||||
-DDEBUG_RSC=1
|
||||
-DDEBUG_RSC=0
|
||||
|
||||
endif
|
||||
|
||||
|
||||
+12
@@ -43,6 +43,18 @@ void GEX_PreInit(void)
|
||||
dbg("\r\n\033[37;1m*** GEX "GEX_VERSION" on "GEX_PLATFORM" ***\033[m");
|
||||
dbg("Build "__DATE__" "__TIME__);
|
||||
|
||||
PRINTF("Reset cause:");
|
||||
if (LL_RCC_IsActiveFlag_LPWRRST()) PRINTF(" LPWR");
|
||||
if (LL_RCC_IsActiveFlag_WWDGRST()) PRINTF(" WWDG");
|
||||
if (LL_RCC_IsActiveFlag_IWDGRST()) PRINTF(" IWDG");
|
||||
if (LL_RCC_IsActiveFlag_SFTRST()) PRINTF(" SFT");
|
||||
if (LL_RCC_IsActiveFlag_PORRST()) PRINTF(" POR");
|
||||
if (LL_RCC_IsActiveFlag_PINRST()) PRINTF(" PIN");
|
||||
if (LL_RCC_IsActiveFlag_OBLRST()) PRINTF(" OBL");
|
||||
if (LL_RCC_IsActiveFlag_V18PWRRST()) PRINTF(" V18PWR");
|
||||
PUTNL();
|
||||
LL_RCC_ClearResetFlags();
|
||||
|
||||
plat_init();
|
||||
|
||||
MX_USB_DEVICE_Init();
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#define DEBUG_USART_BAUD 115200
|
||||
|
||||
#if GEX_PLAT_F072_DISCOVERY
|
||||
#if GEX_PLAT_F072_DISCOVERY || GEX_PLAT_F072_HUB
|
||||
|
||||
#define DEBUG_USART USART1
|
||||
#define DEBUG_USART_RSC R_USART1
|
||||
|
||||
+38
-3
@@ -3,7 +3,6 @@
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "utils/avrlibc.h"
|
||||
#include "hw_utils.h"
|
||||
|
||||
/** Convert pin number to LL bitfield */
|
||||
@@ -131,6 +130,30 @@ error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af)
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/** Configure a pin to alternate function */
|
||||
error_t hw_configure_gpiorsc_af(Resource rsc, uint32_t ll_af)
|
||||
{
|
||||
#if PLAT_NO_AFNUM
|
||||
trap("Illegal call to hw_configure_gpio_af() on this platform");
|
||||
#else
|
||||
|
||||
bool suc = true;
|
||||
GPIO_TypeDef *port;
|
||||
uint32_t ll_pin;
|
||||
suc = hw_pinrsc2ll(rsc, &port, &ll_pin);
|
||||
if (!suc) return E_BAD_CONFIG;
|
||||
|
||||
if (ll_pin & 0xFF)
|
||||
LL_GPIO_SetAFPin_0_7(port, ll_pin, ll_af);
|
||||
else
|
||||
LL_GPIO_SetAFPin_8_15(port, ll_pin, ll_af);
|
||||
|
||||
LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ALTERNATE);
|
||||
|
||||
#endif
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/** Configure pins using sparse map */
|
||||
error_t hw_configure_sparse_pins(char port_name, uint16_t mask, GPIO_TypeDef **port_dest,
|
||||
uint32_t ll_mode, uint32_t ll_otype)
|
||||
@@ -240,7 +263,7 @@ void hw_periph_clock_enable(void *periph)
|
||||
else if (periph == TIM5) __HAL_RCC_TIM5_CLK_ENABLE();
|
||||
#endif
|
||||
#ifdef TIM6
|
||||
else if (periph == TIM6) __HAL_RCC_TIM7_CLK_ENABLE();
|
||||
else if (periph == TIM6) __HAL_RCC_TIM6_CLK_ENABLE();
|
||||
#endif
|
||||
#ifdef TIM7
|
||||
else if (periph == TIM7) __HAL_RCC_TIM7_CLK_ENABLE();
|
||||
@@ -288,6 +311,12 @@ void hw_periph_clock_enable(void *periph)
|
||||
#ifdef DAC2
|
||||
else if (periph == DAC2) __HAL_RCC_DAC2_CLK_ENABLE();
|
||||
#endif
|
||||
|
||||
// --- TSC ---
|
||||
#ifdef TSC
|
||||
else if (periph == TSC) __HAL_RCC_TSC_CLK_ENABLE();
|
||||
#endif
|
||||
|
||||
else {
|
||||
dbg("Periph 0x%p missing in hw clock enable func", periph);
|
||||
trap("BUG");
|
||||
@@ -345,7 +374,7 @@ void hw_periph_clock_disable(void *periph)
|
||||
else if (periph == TIM5) __HAL_RCC_TIM5_CLK_DISABLE();
|
||||
#endif
|
||||
#ifdef TIM6
|
||||
else if (periph == TIM6) __HAL_RCC_TIM7_CLK_DISABLE();
|
||||
else if (periph == TIM6) __HAL_RCC_TIM6_CLK_DISABLE();
|
||||
#endif
|
||||
#ifdef TIM7
|
||||
else if (periph == TIM7) __HAL_RCC_TIM7_CLK_DISABLE();
|
||||
@@ -393,6 +422,12 @@ void hw_periph_clock_disable(void *periph)
|
||||
#ifdef DAC2
|
||||
else if (periph == DAC2) __HAL_RCC_DAC2_CLK_DISABLE();
|
||||
#endif
|
||||
|
||||
// --- TSC ---
|
||||
#ifdef TSC
|
||||
else if (periph == TSC) __HAL_RCC_TSC_CLK_DISABLE();
|
||||
#endif
|
||||
|
||||
else {
|
||||
dbg("Periph 0x%p missing in hw clock disable func", periph);
|
||||
trap("BUG");
|
||||
|
||||
@@ -88,6 +88,9 @@ void hw_deinit_unit_pins(Unit *unit);
|
||||
*/
|
||||
error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af) __attribute__((warn_unused_result));
|
||||
|
||||
/** Configure a pin to alternate function via rsc */
|
||||
error_t hw_configure_gpiorsc_af(Resource rsc, uint32_t ll_af) __attribute__((warn_unused_result));
|
||||
|
||||
/**
|
||||
* Configure multiple pins using the bitmap pattern
|
||||
*
|
||||
|
||||
@@ -69,6 +69,7 @@ static struct callbacks_ {
|
||||
struct cbslot tim16;
|
||||
|
||||
struct cbslot adc1;
|
||||
struct cbslot tsc;
|
||||
|
||||
// XXX add more callbacks here when needed
|
||||
} callbacks;
|
||||
@@ -92,7 +93,8 @@ void irqd_init(void)
|
||||
HAL_NVIC_SetPriority(EXTI2_3_IRQn, 2, 0);
|
||||
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 2, 0);
|
||||
|
||||
// NVIC_EnableIRQ(TSC_IRQn); /*!< Touch Sensing Controller Interrupts */
|
||||
NVIC_EnableIRQ(TSC_IRQn); /*!< Touch Sensing Controller Interrupts */
|
||||
HAL_NVIC_SetPriority(TSC_IRQn, 2, 0);
|
||||
|
||||
NVIC_EnableIRQ(DMA1_Channel1_IRQn); /*!< DMA1 Channel 1 Interrupt */
|
||||
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); /*!< DMA1 Channel 2 and Channel 3 Interrupt */
|
||||
@@ -111,7 +113,7 @@ void irqd_init(void)
|
||||
// NVIC_EnableIRQ(TIM3_IRQn); /*!< TIM3 global Interrupt */
|
||||
|
||||
NVIC_EnableIRQ(TIM6_DAC_IRQn); /*!< TIM6 global and DAC channel underrun error Interrupt */
|
||||
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0); // Used for DAC timing
|
||||
HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 2, 0); // Used for DAC timing
|
||||
|
||||
NVIC_EnableIRQ(TIM7_IRQn); /*!< TIM7 global Interrupt */
|
||||
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0);// this will be for dac (?)
|
||||
@@ -178,6 +180,8 @@ static struct cbslot *get_slot_for_periph(void *periph)
|
||||
else if (periph == TIM16) slot = &callbacks.tim16;
|
||||
// 17 - used by timebase
|
||||
|
||||
else if (periph == TSC) slot = &callbacks.tsc;
|
||||
|
||||
else if (periph == ADC1) slot = &callbacks.adc1;
|
||||
|
||||
else if (periph >= EXTIS[0] && periph <= EXTIS[15]) {
|
||||
@@ -352,6 +356,11 @@ void ADC1_COMP_IRQHandler(void)
|
||||
CALL_IRQ_HANDLER(callbacks.adc1);
|
||||
}
|
||||
|
||||
void TSC_IRQHandler(void)
|
||||
{
|
||||
CALL_IRQ_HANDLER(callbacks.tsc);
|
||||
}
|
||||
|
||||
|
||||
// other ISRs...
|
||||
|
||||
|
||||
+35
-14
@@ -21,7 +21,7 @@
|
||||
#endif
|
||||
|
||||
// 180 is normally enough if not doing extensive debug logging
|
||||
#define TSK_STACK_MSG 200 // TF message handler task stack size (all unit commands run on this thread)
|
||||
#define TSK_STACK_MSG 220 // TF message handler task stack size (all unit commands run on this thread)
|
||||
#define TSK_STACK_IDLE 64 //configMINIMAL_STACK_SIZE
|
||||
#define TSK_STACK_TIMERS 64 //configTIMER_TASK_STACK_DEPTH
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
|
||||
#define BULK_READ_BUF_LEN 256 // Buffer for TF bulk reads
|
||||
#define UNIT_TMP_LEN 512 // Buffer for internal unit operations
|
||||
#define UNIT_TMP_LEN 256 // Buffer for internal unit operations
|
||||
|
||||
#define FLASH_SAVE_BUF_LEN 128 // Malloc'd buffer for saving to flash
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#define RX_QUE_CAPACITY 16 // TinyFrame rx queue size (64 bytes each)
|
||||
|
||||
#define TF_MAX_PAYLOAD_RX 512 // TF max Rx payload
|
||||
#define TF_SENDBUF_LEN 64 // TF transmit buffer (can be less than a full frame)
|
||||
#define TF_SENDBUF_LEN 512 // TF transmit buffer (can be less than a full frame)
|
||||
|
||||
#define TF_MAX_ID_LST 4 // Frame ID listener count
|
||||
#define TF_MAX_TYPE_LST 6 // Frame Type listener count
|
||||
@@ -70,6 +70,7 @@
|
||||
// PLAT_LOCK_BTN - use a lock button instead of a lock jumper (push to toggle)
|
||||
// PLAT_LOCK_1CLOSED - lock jumper is active (closed / button pressed) in logical 1
|
||||
// PLAT_NO_AFNUM - legacy platform without numbered AF alternatives
|
||||
// PLAT_FULL_XTAL - use two-wire xtal attachment
|
||||
|
||||
#if defined(GEX_PLAT_F103_BLUEPILL)
|
||||
|
||||
@@ -124,10 +125,8 @@
|
||||
#define STATUS_LED_PORT 'C'
|
||||
#define STATUS_LED_PIN 13
|
||||
|
||||
#elif defined(GEX_PLAT_F072_DISCOVERY)
|
||||
#elif defined(STM32F072xB)
|
||||
|
||||
// platform name for the version string
|
||||
#define GEX_PLATFORM "STM32F072-Discovery"
|
||||
#define PLAT_AHB_MHZ 48
|
||||
#define PLAT_APB1_MHZ 48
|
||||
|
||||
@@ -162,15 +161,37 @@
|
||||
// Number of GPIO ports A,B,C...
|
||||
#define PORTS_COUNT 6
|
||||
|
||||
// Lock jumper config
|
||||
#define LOCK_JUMPER_PORT 'A'
|
||||
#define LOCK_JUMPER_PIN 0
|
||||
#define PLAT_LOCK_BTN 1 // toggle button instead of a jumper
|
||||
#define PLAT_LOCK_1CLOSED 1 // toggle button active in log. 1
|
||||
#if defined(GEX_PLAT_F072_DISCOVERY)
|
||||
// platform name for the version string
|
||||
#define GEX_PLATFORM "STM32F072-Discovery"
|
||||
|
||||
// Status LED config
|
||||
#define STATUS_LED_PORT 'C'
|
||||
#define STATUS_LED_PIN 6 // RED LED "UP"
|
||||
// Lock jumper config
|
||||
#define LOCK_JUMPER_PORT 'A'
|
||||
#define LOCK_JUMPER_PIN 0
|
||||
#define PLAT_LOCK_BTN 1 // toggle button instead of a jumper
|
||||
#define PLAT_LOCK_1CLOSED 1 // toggle button active in log. 1
|
||||
|
||||
// Status LED config
|
||||
#define STATUS_LED_PORT 'C'
|
||||
#define STATUS_LED_PIN 6 // RED LED "UP"
|
||||
#elif defined(GEX_PLAT_F072_HUB)
|
||||
// platform name for the version string
|
||||
#define GEX_PLATFORM "STM32F072-HUB"
|
||||
|
||||
#define PLAT_FULL_XTAL 1
|
||||
|
||||
// Lock jumper config
|
||||
#define LOCK_JUMPER_PORT 'D'
|
||||
#define LOCK_JUMPER_PIN 2
|
||||
#define PLAT_LOCK_BTN 1 // toggle button instead of a jumper
|
||||
#define PLAT_LOCK_1CLOSED 0 // toggle button active in log. 1
|
||||
|
||||
// Status LED config
|
||||
#define STATUS_LED_PORT 'A'
|
||||
#define STATUS_LED_PIN 15 // RED LED "UP"
|
||||
#else
|
||||
#error Bad platform
|
||||
#endif
|
||||
|
||||
#elif defined(GEX_PLAT_F303_DISCOVERY)
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "debug_uart.h"
|
||||
#include "irq_dispatcher.h"
|
||||
#include "timebase.h"
|
||||
#include "watchdog.h"
|
||||
|
||||
void plat_init(void)
|
||||
{
|
||||
@@ -39,4 +40,6 @@ void plat_init(void)
|
||||
settings_load(); // XXX maybe this should be moved to the main task
|
||||
|
||||
comm_init();
|
||||
|
||||
wd_init();
|
||||
}
|
||||
|
||||
+18
-8
@@ -2,7 +2,7 @@
|
||||
// Created by MightyPork on 2017/11/26.
|
||||
//
|
||||
|
||||
#include <units/fcap/unit_fcap.h>
|
||||
#include <units/dac/unit_dac.h>
|
||||
#include "platform.h"
|
||||
#include "usbd_core.h"
|
||||
#include "USB/usb_device.h"
|
||||
@@ -19,6 +19,9 @@
|
||||
#include "units/usart/unit_usart.h"
|
||||
#include "units/spi/unit_spi.h"
|
||||
#include "units/sipo/unit_sipo.h"
|
||||
#include "units/fcap/unit_fcap.h"
|
||||
#include "units/touch/unit_touch.h"
|
||||
#include "units/simple_pwm/unit_pwmdim.h"
|
||||
#include "hw_utils.h"
|
||||
|
||||
void plat_init_resources(void)
|
||||
@@ -73,7 +76,7 @@ void plat_init_resources(void)
|
||||
// BOOT pin(s)
|
||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PB2); // BOOT1
|
||||
}
|
||||
#elif defined(GEX_PLAT_F072_DISCOVERY)
|
||||
#elif defined(STM32F072xB)
|
||||
// Platform STM32F073RBT
|
||||
|
||||
// Additional GPIO ports
|
||||
@@ -90,6 +93,9 @@ void plat_init_resources(void)
|
||||
ureg_add_type(&UNIT_ADC);
|
||||
ureg_add_type(&UNIT_SIPO);
|
||||
ureg_add_type(&UNIT_FCAP);
|
||||
ureg_add_type(&UNIT_TOUCH);
|
||||
ureg_add_type(&UNIT_PWMDIM);
|
||||
ureg_add_type(&UNIT_DAC);
|
||||
|
||||
// Free all present resources
|
||||
{
|
||||
@@ -98,7 +104,7 @@ void plat_init_resources(void)
|
||||
// rsc_free_range(NULL, R_COMP1, R_COMP2);
|
||||
rsc_free(NULL, R_DAC1);
|
||||
// rsc_free(NULL, R_HDMI_CEC);
|
||||
// rsc_free(NULL, R_TSC);
|
||||
rsc_free(NULL, R_TSC);
|
||||
rsc_free_range(NULL, R_I2C1, R_I2C2);
|
||||
// rsc_free_range(NULL, R_I2S1, R_I2S2);
|
||||
rsc_free_range(NULL, R_SPI1, R_SPI2);
|
||||
@@ -118,13 +124,17 @@ void plat_init_resources(void)
|
||||
// Claim resources not available due to board layout or internal usage
|
||||
{
|
||||
// HAL timebase
|
||||
rv |= rsc_claim(&UNIT_SYSTEM, R_TIM1);
|
||||
rv |= rsc_claim(&UNIT_SYSTEM, R_TIM17);
|
||||
// HSE crystal
|
||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PF0);
|
||||
//rv |= rsc_claim(&UNIT_SYSTEM, R_PF1); // - not used in BYPASS mode
|
||||
|
||||
#if PLAT_FULL_XTAL
|
||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PF1); // - not used in BYPASS mode
|
||||
#endif
|
||||
|
||||
// SWD
|
||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA13);
|
||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA14);
|
||||
// rv |= rsc_claim(&UNIT_SYSTEM, R_PA13);
|
||||
// rv |= rsc_claim(&UNIT_SYSTEM, R_PA14);
|
||||
// USB
|
||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA11);
|
||||
rv |= rsc_claim(&UNIT_SYSTEM, R_PA12);
|
||||
@@ -154,7 +164,7 @@ void plat_init_resources(void)
|
||||
rsc_free_range(NULL, R_TIM1, R_TIM4);
|
||||
rsc_free_range(NULL, R_TIM6, R_TIM8);
|
||||
rsc_free_range(NULL, R_TIM15, R_TIM17);
|
||||
// rsc_free(NULL, R_TSC);
|
||||
rsc_free(NULL, R_TSC);
|
||||
rsc_free_range(NULL, R_USART1, R_USART5);
|
||||
|
||||
rsc_free_range(NULL, R_PA0, R_PA15);
|
||||
|
||||
+15
-1
@@ -61,6 +61,12 @@ void Indicator_Effect(enum GEX_StatusIndicator indicator)
|
||||
led_on();
|
||||
}
|
||||
|
||||
// prevent the two disk ops interfering (happens in write-reload)
|
||||
if (indicator == STATUS_DISK_BUSY && active_effect == STATUS_DISK_BUSY_SHORT) return;
|
||||
if (indicator == STATUS_DISK_BUSY_SHORT && active_effect == STATUS_DISK_BUSY) return;
|
||||
|
||||
// TODO add some better protection against effect overlap?
|
||||
|
||||
active_effect = indicator;
|
||||
effect_time = 0;
|
||||
}
|
||||
@@ -119,7 +125,15 @@ void Indicator_Tick(void)
|
||||
active_effect = STATUS_NONE;
|
||||
}
|
||||
else if (effect_time % 100 == 0) led_on();
|
||||
else if (effect_time % 100 == 50) led_off();
|
||||
else if (effect_time % 100 == 20) led_off();
|
||||
}
|
||||
else if (active_effect == STATUS_DISK_BUSY_SHORT) {
|
||||
if (effect_time >= 200) {
|
||||
led_off();
|
||||
active_effect = STATUS_NONE;
|
||||
}
|
||||
else if (effect_time % 100 == 0) led_on();
|
||||
else if (effect_time % 100 == 20) led_off();
|
||||
}
|
||||
else if (active_effect == STATUS_WELCOME) {
|
||||
if (effect_time == 0) led_on();
|
||||
|
||||
@@ -16,6 +16,7 @@ enum GEX_StatusIndicator {
|
||||
STATUS_NONE = 0,
|
||||
STATUS_FAULT,
|
||||
STATUS_DISK_BUSY,
|
||||
STATUS_DISK_BUSY_SHORT,
|
||||
STATUS_DISK_ATTACHED,
|
||||
STATUS_DISK_REMOVED,
|
||||
STATUS_WELCOME,
|
||||
|
||||
+20
-7
@@ -7,8 +7,6 @@
|
||||
|
||||
// ---------------------------- HAL TIMEBASE -----------------------------
|
||||
|
||||
#define TIMEBASE_TIMER TIM17
|
||||
|
||||
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
|
||||
{
|
||||
// EDIT - used 17 instead because 14 was needed for fcap
|
||||
@@ -102,21 +100,36 @@ uint64_t PTIM_GetMicrotime(void)
|
||||
return (uint64_t) uwMillis * 1000 + uwMicros;
|
||||
}
|
||||
|
||||
|
||||
/** microsecond delay */
|
||||
void PTIM_MicroDelay(uint16_t usec)
|
||||
void PTIM_MicroDelayAligned(uint32_t usec, register const uint32_t start)
|
||||
{
|
||||
assert_param(usec < 1000);
|
||||
|
||||
const uint16_t start = (uint16_t) TIMEBASE_TIMER->CNT;
|
||||
const uint16_t remain = (uint16_t) (999 - start);
|
||||
register const uint32_t remain = (1000 - start);
|
||||
|
||||
if (remain > usec) {
|
||||
// timer still has enough space going forward to pass the required wait time
|
||||
for (; TIMEBASE_TIMER->CNT < start + usec;);
|
||||
register const uint32_t end = start + usec;
|
||||
while (TIMEBASE_TIMER->CNT < end) {
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// timer is too close to the end
|
||||
usec -= remain;
|
||||
for (; TIMEBASE_TIMER->CNT >= start || TIMEBASE_TIMER->CNT < usec;);
|
||||
while (1) {
|
||||
register const uint32_t t = TIMEBASE_TIMER->CNT;
|
||||
if (t < start && t >= usec) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** microsecond delay */
|
||||
void PTIM_MicroDelay(const uint32_t usec)
|
||||
{
|
||||
PTIM_MicroDelayAligned(usec, TIMEBASE_TIMER->CNT);
|
||||
}
|
||||
|
||||
+21
-1
@@ -13,6 +13,8 @@
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#define TIMEBASE_TIMER TIM17
|
||||
|
||||
/**
|
||||
* Precision timer: get microtime as uint64_t
|
||||
* This timestamp should be monotonously increasing with a precision of ±0.5µs
|
||||
@@ -36,6 +38,24 @@ static inline uint32_t PTIM_GetTime(void)
|
||||
*
|
||||
* @param usec - max 998
|
||||
*/
|
||||
void PTIM_MicroDelay(uint16_t usec);
|
||||
void PTIM_MicroDelay(uint32_t usec);
|
||||
|
||||
/**
|
||||
* Microsecond busy delay with alignment (reduced length jitter but possible up to 1 us delay)
|
||||
*
|
||||
* @param usec
|
||||
*/
|
||||
void PTIM_MicroDelayAligned(uint32_t usec, uint32_t start);
|
||||
|
||||
/**
|
||||
* Wait until the next micro timer tick
|
||||
*/
|
||||
static inline uint32_t PTIM_MicroDelayAlign(void)
|
||||
{
|
||||
const uint32_t c = TIMEBASE_TIMER->CNT;
|
||||
uint32_t res;
|
||||
while ((res = TIMEBASE_TIMER->CNT) == c);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif //GEX_F072_TIMEBASE_H
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/27.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "watchdog.h"
|
||||
|
||||
static volatile uint16_t suspend_depth = 0;
|
||||
static volatile bool restart_pending = false;
|
||||
|
||||
void wd_init(void)
|
||||
{
|
||||
dbg("IWDG init, time 2s");
|
||||
|
||||
LL_IWDG_Enable(IWDG);
|
||||
LL_IWDG_EnableWriteAccess(IWDG);
|
||||
LL_IWDG_SetPrescaler(IWDG, LL_IWDG_PRESCALER_32); // 0.8 ms
|
||||
LL_IWDG_SetReloadCounter(IWDG, 2500); // 2s. max 4095
|
||||
while (!LL_IWDG_IsReady(IWDG));
|
||||
|
||||
// reload
|
||||
LL_IWDG_ReloadCounter(IWDG);
|
||||
}
|
||||
|
||||
void wd_suspend(void)
|
||||
{
|
||||
vPortEnterCritical();
|
||||
if (suspend_depth < 0xFFFF) {
|
||||
suspend_depth++;
|
||||
}
|
||||
vPortExitCritical();
|
||||
}
|
||||
|
||||
void wd_resume(void)
|
||||
{
|
||||
vPortEnterCritical();
|
||||
if (suspend_depth > 0) {
|
||||
suspend_depth--;
|
||||
|
||||
if (suspend_depth == 0 && restart_pending) {
|
||||
restart_pending = false;
|
||||
LL_IWDG_ReloadCounter(IWDG);
|
||||
}
|
||||
}
|
||||
vPortExitCritical();
|
||||
}
|
||||
|
||||
void wd_restart(void)
|
||||
{
|
||||
vPortEnterCritical();
|
||||
if (suspend_depth == 0) {
|
||||
LL_IWDG_ReloadCounter(IWDG);
|
||||
} else {
|
||||
restart_pending = true;
|
||||
}
|
||||
vPortExitCritical();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/27.
|
||||
//
|
||||
|
||||
#ifndef GEX_F072_WATCHDOG_H
|
||||
#define GEX_F072_WATCHDOG_H
|
||||
|
||||
/**
|
||||
* Initialize the application watchdog
|
||||
*/
|
||||
void wd_init(void);
|
||||
|
||||
/**
|
||||
* Suspend watchdog restarts until resumed
|
||||
* (used in other tasks to prevent the main task clearing the wd if the other task is locked up)
|
||||
*
|
||||
* The suspend/resume calls can be stacked.
|
||||
*/
|
||||
void wd_suspend(void);
|
||||
|
||||
/**
|
||||
* Resume restarts
|
||||
*/
|
||||
void wd_resume(void);
|
||||
|
||||
/**
|
||||
* Restart the wd. If restarts are suspended, postpone the restart until resumed
|
||||
* and then restart immediately.
|
||||
*/
|
||||
void wd_restart(void);
|
||||
|
||||
#endif //GEX_F072_WATCHDOG_H
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "platform.h"
|
||||
#include "platform/lock_jumper.h"
|
||||
#include "platform/watchdog.h"
|
||||
#include "status_led.h"
|
||||
#include "utils/stacksmon.h"
|
||||
#include "vfs/vfs_manager.h"
|
||||
@@ -45,6 +46,8 @@ void TaskMain(void const * argument)
|
||||
|
||||
cnt++;
|
||||
Indicator_Heartbeat();
|
||||
|
||||
wd_restart();
|
||||
}
|
||||
|
||||
// if no message and it just timed out, go wait some more...
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "platform/watchdog.h"
|
||||
#include "comm/messages.h"
|
||||
#include "task_msg.h"
|
||||
|
||||
@@ -85,7 +86,9 @@ void TaskMsgJob(const void *argument)
|
||||
#if CDC_LOOPBACK_TEST
|
||||
TF_WriteImpl(comm, slot.msg.data, slot.msg.len);
|
||||
#else
|
||||
wd_suspend();
|
||||
TF_Accept(comm, slot.msg.data, slot.msg.len);
|
||||
wd_resume();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -14,15 +14,6 @@ error_t OW_preInit(Unit *unit)
|
||||
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
|
||||
if (priv == NULL) return E_OUT_OF_MEM;
|
||||
|
||||
// the timer is not started until needed
|
||||
priv->busyWaitTimer = xTimerCreate("1w_tim", // name
|
||||
750, // interval (will be changed when starting it)
|
||||
true, // periodic (we use this only for the polling variant, the one-shot will stop the timer in the CB)
|
||||
unit, // user data
|
||||
OW_TimerCb); // callback
|
||||
|
||||
if (priv->busyWaitTimer == NULL) return E_OUT_OF_MEM;
|
||||
|
||||
// some defaults
|
||||
priv->pin_number = 0;
|
||||
priv->port_name = 'A';
|
||||
@@ -63,9 +54,6 @@ void OW_deInit(Unit *unit)
|
||||
// Release all resources
|
||||
rsc_teardown(unit);
|
||||
|
||||
// Delete the software timer
|
||||
assert_param(pdPASS == xTimerDelete(priv->busyWaitTimer, 1000));
|
||||
|
||||
// Free memory
|
||||
free_ck(unit->data);
|
||||
}
|
||||
|
||||
@@ -64,5 +64,5 @@ void OW_writeIni(Unit *unit, IniWriter *iw)
|
||||
iw_entry(iw, "pin", "%c%d", priv->port_name, priv->pin_number);
|
||||
|
||||
iw_comment(iw, "Parasitic (bus-powered) mode");
|
||||
iw_entry(iw, "parasitic", str_yn(priv->parasitic));
|
||||
iw_entry_s(iw, "parasitic", str_yn(priv->parasitic));
|
||||
}
|
||||
|
||||
+16
-13
@@ -38,12 +38,13 @@ static void OW_TimerRespCb(Job *job)
|
||||
*
|
||||
* @param xTimer
|
||||
*/
|
||||
void OW_TimerCb(TimerHandle_t xTimer)
|
||||
void OW_tickHandler(Unit *unit)
|
||||
{
|
||||
Unit *unit = pvTimerGetTimerID(xTimer);
|
||||
assert_param(unit);
|
||||
struct priv *priv = unit->data;
|
||||
assert_param(priv->busy);
|
||||
if(!priv->busy) {
|
||||
dbg("ow tick should be disabled now!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (priv->parasitic) {
|
||||
// this is the end of the 750ms measurement time
|
||||
@@ -56,7 +57,8 @@ void OW_TimerCb(TimerHandle_t xTimer)
|
||||
|
||||
uint32_t time = PTIM_GetTime();
|
||||
if (time - priv->busyStart > 1000) {
|
||||
xTimerStop(xTimer, 100);
|
||||
unit->tick_interval = 0;
|
||||
unit->_tick_cnt = 0;
|
||||
|
||||
Job j = {
|
||||
.unit = unit,
|
||||
@@ -69,7 +71,8 @@ void OW_TimerCb(TimerHandle_t xTimer)
|
||||
|
||||
return;
|
||||
halt_ok:
|
||||
xTimerStop(xTimer, 100);
|
||||
unit->tick_interval = 0;
|
||||
unit->_tick_cnt = 0;
|
||||
|
||||
Job j = {
|
||||
.unit = unit,
|
||||
@@ -79,7 +82,6 @@ halt_ok:
|
||||
scheduleJob(&j);
|
||||
}
|
||||
|
||||
|
||||
enum PinCmd_ {
|
||||
CMD_CHECK_PRESENCE = 0, // simply tests that any devices are attached
|
||||
CMD_SEARCH_ADDR = 1, // perform a scan of the bus, retrieving all found device ROMs
|
||||
@@ -87,7 +89,7 @@ enum PinCmd_ {
|
||||
CMD_SEARCH_CONTINUE = 3, // continue the previously started scan, retrieving more devices
|
||||
CMD_READ_ADDR = 4, // read the ROM code from a single device (for single-device bus)
|
||||
|
||||
CMD_WRITE = 10, // write multiple bytes using the SKIP_ROM command
|
||||
CMD_QUERY = 10, // write multiple bytes using the SKIP_ROM command
|
||||
CMD_READ = 11, // write multiple bytes using a ROM address
|
||||
|
||||
CMD_POLL_FOR_1 = 20,
|
||||
@@ -120,13 +122,13 @@ static error_t OW_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Pay
|
||||
*/
|
||||
case CMD_POLL_FOR_1:
|
||||
// This can't be exposed via the UU API, due to being async
|
||||
unit->_tick_cnt = 0;
|
||||
unit->tick_interval = 750;
|
||||
if (priv->parasitic) {
|
||||
assert_param(pdPASS == xTimerChangePeriod(priv->busyWaitTimer, 750, 100));
|
||||
unit->tick_interval = 750;
|
||||
} else {
|
||||
// every 10 ticks
|
||||
assert_param(pdPASS == xTimerChangePeriod(priv->busyWaitTimer, 10, 100));
|
||||
unit->tick_interval = 10;
|
||||
}
|
||||
assert_param(pdPASS == xTimerStart(priv->busyWaitTimer, 100));
|
||||
priv->busy = true;
|
||||
priv->busyStart = PTIM_GetTime();
|
||||
priv->busyRequestId = frame_id;
|
||||
@@ -192,7 +194,7 @@ static error_t OW_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Pay
|
||||
* addr:u64, rest:write_data
|
||||
* if addr is 0, use SKIP_ROM
|
||||
*/
|
||||
case CMD_WRITE:
|
||||
case CMD_QUERY:
|
||||
addr = pp_u64(pp);
|
||||
tail = pp_tail(pp, &remain);
|
||||
TRY(UU_1WIRE_Write(unit, addr, tail, remain));
|
||||
@@ -242,4 +244,5 @@ const UnitDriver UNIT_1WIRE = {
|
||||
.deInit = OW_deInit,
|
||||
// Function
|
||||
.handleRequest = OW_handleRequest,
|
||||
.updateTick = OW_tickHandler,
|
||||
};
|
||||
|
||||
@@ -40,7 +40,8 @@ static void UADC_JobSendBlockChunk(Job *job)
|
||||
.len = (TF_LEN) (1 /*seq*/ + count * sizeof(uint16_t)),
|
||||
.type = type,
|
||||
};
|
||||
TF_Respond_Multipart(comm, &msg);
|
||||
|
||||
assert_param(true == TF_Respond_Multipart(comm, &msg));
|
||||
TF_Multipart_Payload(comm, &priv->stream_serial, 1);
|
||||
TF_Multipart_Payload(comm, (uint8_t *) (priv->dma_buffer + start), count * sizeof(uint16_t));
|
||||
TF_Multipart_Close(comm);
|
||||
@@ -171,7 +172,7 @@ static void handle_httc(Unit *unit, bool tc)
|
||||
const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP;
|
||||
|
||||
if (ht) {
|
||||
end = (priv->buf_itemcount / 2);
|
||||
end = (priv->buf_itemcount >> 1); // div2
|
||||
}
|
||||
else {
|
||||
end = priv->buf_itemcount;
|
||||
@@ -234,7 +235,7 @@ static void handle_httc(Unit *unit, bool tc)
|
||||
priv->stream_startpos = 0;
|
||||
}
|
||||
else {
|
||||
priv->stream_startpos = priv->buf_itemcount / 2;
|
||||
priv->stream_startpos = priv->buf_itemcount >> 1; // div2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,7 +290,7 @@ void UADC_DMA_Handler(void *arg)
|
||||
const bool m_stream = priv->opmode == ADC_OPMODE_STREAM;
|
||||
const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP;
|
||||
if (m_trigd || m_stream || m_fixcpt) {
|
||||
const uint32_t half = (uint32_t) (priv->buf_itemcount / 2);
|
||||
const uint32_t half = (uint32_t) (priv->buf_itemcount >> 1); // div2
|
||||
if (ht && tc) {
|
||||
// dual event interrupt - may happen if we missed both and they were pending after
|
||||
// interrupts became enabled again (this can happen due to the EOS or other higher prio irq's)
|
||||
@@ -336,8 +337,10 @@ void UADC_ADC_EOS_Handler(void *arg)
|
||||
if (priv->opmode == ADC_OPMODE_UNINIT) return;
|
||||
|
||||
// Wait for the DMA to complete copying the last sample
|
||||
uint32_t dmapos;
|
||||
hw_wait_while((dmapos = DMA_POS(priv)) % priv->nb_channels != 0, 100); // XXX this could be changed to reading it from the DR instead
|
||||
uint32_t dmapos = DMA_POS(priv);
|
||||
if ((DMA_POS(priv) % priv->nb_channels) != 0) {
|
||||
hw_wait_while((dmapos = DMA_POS(priv)) % priv->nb_channels != 0, 100); // XXX this could be changed to reading it from the DR instead
|
||||
}
|
||||
|
||||
uint32_t sample_pos;
|
||||
if (dmapos == 0) {
|
||||
|
||||
@@ -80,14 +80,14 @@ void UADC_writeIni(Unit *unit, IniWriter *iw)
|
||||
iw_comment(iw, "Enabled channels, comma separated");
|
||||
iw_comment(iw, " 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17");
|
||||
iw_comment(iw, "A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 C0 C1 C2 C3 C4 C5 Tsens Vref");
|
||||
iw_entry(iw, "channels", cfg_pinmask_encode(priv->cfg.channels, unit_tmp512, true));
|
||||
iw_entry_s(iw, "channels", cfg_pinmask_encode(priv->cfg.channels, unit_tmp512, true));
|
||||
|
||||
iw_cmt_newline(iw);
|
||||
iw_comment(iw, "Sampling time (0-7)");
|
||||
iw_entry(iw, "sample_time", "%d", (int)priv->cfg.sample_time);
|
||||
iw_entry_d(iw, "sample_time", priv->cfg.sample_time);
|
||||
|
||||
iw_comment(iw, "Sampling frequency (Hz)");
|
||||
iw_entry(iw, "frequency", "%d", (int)priv->cfg.frequency);
|
||||
iw_entry_d(iw, "frequency", priv->cfg.frequency);
|
||||
|
||||
iw_cmt_newline(iw);
|
||||
iw_comment(iw, "Sample buffer size");
|
||||
@@ -95,12 +95,12 @@ void UADC_writeIni(Unit *unit, IniWriter *iw)
|
||||
iw_comment(iw, "- defines the maximum pre-trigger size (divide by # of channels)");
|
||||
iw_comment(iw, "- captured data is sent in half-buffer chunks");
|
||||
iw_comment(iw, "- buffer overrun aborts the data capture");
|
||||
iw_entry(iw, "buffer_size", "%d", (int)priv->cfg.buffer_size);
|
||||
iw_entry_d(iw, "buffer_size", priv->cfg.buffer_size);
|
||||
|
||||
iw_cmt_newline(iw);
|
||||
iw_comment(iw, "Exponential averaging coefficient (permil, range 0-1000 ~ 0.000-1.000)");
|
||||
iw_comment(iw, "- used formula: y[t]=(1-k)*y[t-1]+k*u[t]");
|
||||
iw_comment(iw, "- not available when a capture is running");
|
||||
iw_entry(iw, "avg_factor", "%d", priv->cfg.averaging_factor);
|
||||
iw_entry_d(iw, "avg_factor", priv->cfg.averaging_factor);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
#include "unit_dac.h"
|
||||
|
||||
#define DAC_INTERNAL
|
||||
#include "_dac_internal.h"
|
||||
|
||||
/**
|
||||
* Re-configure the
|
||||
* @param unit
|
||||
*/
|
||||
void UDAC_Reconfigure(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
// back-up IT state
|
||||
bool IT_enabled = (bool) LL_TIM_IsEnabledIT_UPDATE(priv->TIMx);
|
||||
if (IT_enabled) {
|
||||
LL_TIM_DisableIT_UPDATE(priv->TIMx);
|
||||
}
|
||||
|
||||
// ...
|
||||
DAC->CR &= ~(DAC_CR_EN1 | DAC_CR_EN2);
|
||||
|
||||
uint32_t CR = 0;
|
||||
if (priv->cfg.ch[0].enable) {
|
||||
CR |=
|
||||
(priv->cfg.ch[0].buffered ? 0 : DAC_CR_BOFF1) |
|
||||
(priv->ch[0].noise_type << DAC_CR_WAVE1_Pos) |
|
||||
(priv->ch[0].noise_level & 0xF) << DAC_CR_MAMP1_Pos |
|
||||
DAC_CR_TEN1 |
|
||||
(0b111 << DAC_CR_TSEL1_Pos); // software trigger;
|
||||
|
||||
CR |= DAC_CR_EN1;
|
||||
}
|
||||
|
||||
if (priv->cfg.ch[1].enable) {
|
||||
CR |=
|
||||
(priv->cfg.ch[1].buffered ? 0 : DAC_CR_BOFF2) |
|
||||
(priv->ch[1].noise_type << DAC_CR_WAVE2_Pos) |
|
||||
(priv->ch[1].noise_level & 0xF) << DAC_CR_MAMP2_Pos |
|
||||
DAC_CR_TEN2 |
|
||||
(0b111 << DAC_CR_TSEL2_Pos); // software trigger
|
||||
CR |= DAC_CR_EN2;
|
||||
}
|
||||
|
||||
DAC->CR = CR;
|
||||
// ...
|
||||
|
||||
if (IT_enabled) {
|
||||
LL_TIM_EnableIT_UPDATE(priv->TIMx);
|
||||
}
|
||||
}
|
||||
|
||||
error_t UDAC_SetFreq(Unit *unit, int channel, float freq)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
priv->ch[channel].increment = (uint32_t) roundf(25.0f * freq * UDAC_VALUE_COUNT * // FIXME constant seems derived from the divide ...?
|
||||
((float)UDAC_TIM_FREQ_DIVIDER / PLAT_AHB_MHZ)
|
||||
);
|
||||
|
||||
// dbg("Ch %d: Computed increment: %d", channel+1, (int)priv->ch[channel].increment);
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
void UDAC_ToggleTimerIfNeeded(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
if (priv->ch[0].waveform == UDAC_WAVE_DC && priv->ch[1].waveform == UDAC_WAVE_DC) {
|
||||
LL_TIM_DisableCounter(priv->TIMx);
|
||||
|
||||
// manually call the interrupt function to update the level
|
||||
UDAC_HandleIT(unit);
|
||||
} else {
|
||||
LL_TIM_EnableCounter(priv->TIMx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,392 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/03/10.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_dac.h"
|
||||
|
||||
#define DAC_INTERNAL
|
||||
#include "_dac_internal.h"
|
||||
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("O2")
|
||||
void UDAC_HandleIT(void *arg)
|
||||
{
|
||||
Unit *unit = arg;
|
||||
struct priv *priv = unit->data;
|
||||
LL_TIM_ClearFlag_UPDATE(priv->TIMx);
|
||||
|
||||
// TODO optimize to allow faster update speed
|
||||
|
||||
uint16_t vals[2];
|
||||
for (int i = 0; i < 2; i++) {
|
||||
struct udac_channel_live *const ch = &priv->ch[i];
|
||||
|
||||
if (ch->waveform == UDAC_WAVE_DC) {
|
||||
// skip the whole counter thing for DC
|
||||
vals[i] = ch->dc_level;
|
||||
continue;
|
||||
}
|
||||
|
||||
ch->counter += ch->increment;
|
||||
const uint16_t index = (uint16_t) (ch->counter >> UDAC_INDEX_SHIFT);
|
||||
|
||||
switch (ch->waveform) {
|
||||
case UDAC_WAVE_SINE: {
|
||||
const uint32_t phase = index >> (UDAC_INDEX_WIDTH - 2);
|
||||
|
||||
uint32_t pos = (uint32_t) index & (((1<<(UDAC_INDEX_WIDTH - 2)) - 1));
|
||||
|
||||
if (phase & 0b01) {
|
||||
// 2nd and 4th quarter (01, 11)
|
||||
pos = (UDAC_VALUE_COUNT/4 - 1) - pos;
|
||||
}
|
||||
|
||||
uint32_t value;
|
||||
|
||||
/* unpack */
|
||||
const uint32_t nthbyte = (pos * 3) / 2;
|
||||
const uint8_t topbyte = LUT_sine_8192_quad_packed[nthbyte];
|
||||
const uint8_t botbyte = LUT_sine_8192_quad_packed[nthbyte + 1];
|
||||
if (pos & 1) {
|
||||
// odd index
|
||||
value = (uint32_t) (((topbyte & 0xF) << 8) | botbyte);
|
||||
}
|
||||
else {
|
||||
value = (uint32_t) ((topbyte << 4) | ((botbyte & 0xF0) >> 4));
|
||||
}
|
||||
/* end unpack -> value */
|
||||
|
||||
if (phase & 0b10) {
|
||||
// 3rd and 4th quarter (10, 11)
|
||||
value = 2047 - value;
|
||||
}
|
||||
else {
|
||||
// 1st and 2nd quarter (00, 01)
|
||||
value = 2048 + value;
|
||||
}
|
||||
|
||||
vals[i] = (uint16_t) value;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case UDAC_WAVE_RECTANGLE:
|
||||
if (index < ch->rectangle_ontime) {
|
||||
vals[i] = ch->rectangle_high;
|
||||
} else {
|
||||
vals[i] = ch->rectangle_low;
|
||||
}
|
||||
break;
|
||||
|
||||
case UDAC_WAVE_SAWTOOTH_UP:
|
||||
vals[i] = (uint16_t) (index / 2); // for 8192 steps, this will produce 0-4095
|
||||
break;
|
||||
|
||||
case UDAC_WAVE_SAWTOOTH_DOWN:
|
||||
vals[i] = (uint16_t) (4095 - (index / 2)); // for 8192 steps, this will produce 0-4095
|
||||
break;
|
||||
|
||||
case UDAC_WAVE_TRIANGLE: {
|
||||
if (index < 4096) {
|
||||
vals[i] = index;
|
||||
}
|
||||
else {
|
||||
vals[i] = (uint16_t) (8191 - index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
vals[i] = 0; // this shouldn't happen
|
||||
break;
|
||||
} // end select waveform
|
||||
} // end for 0,1
|
||||
|
||||
DAC->DHR12RD = (vals[1] << 16) | vals[0];
|
||||
|
||||
// Trigger a conversion
|
||||
DAC->SWTRIGR = (DAC_SWTR_CH1 | DAC_SWTR_CH2);
|
||||
}
|
||||
#pragma GCC pop_options
|
||||
|
||||
|
||||
/**
|
||||
* This is the first 1/4 of a 12-bit sine wave sampled in 8192 points, each two points packed into three bytes (saves 1/4 of space used by uint16_t's)
|
||||
* The array holds 2048 data points which can be easily offset / flipped to cover the entire waveform.
|
||||
*
|
||||
* |<-->|
|
||||
* _---_
|
||||
* / \
|
||||
* / \
|
||||
* /---------\---------/
|
||||
* \ /
|
||||
* \_ _/
|
||||
* ---
|
||||
*/
|
||||
#if 0 // this is rail to rail, but the dac doesn't work well at the rails and it gets flattened
|
||||
const uint8_t LUT_sine_8192_quad_packed[] = {
|
||||
0x00, 0x00, 0x02, 0x00, 0x30, 0x05, 0x00, 0x60, 0x08, 0x00, 0x90, 0x0B, 0x00, 0xD0, 0x0E, 0x01, 0x00, 0x11, 0x01, 0x30, 0x14, 0x01, 0x60, 0x18,
|
||||
0x01, 0x90, 0x1B, 0x01, 0xC0, 0x1E, 0x01, 0xF0, 0x21, 0x02, 0x30, 0x24, 0x02, 0x60, 0x27, 0x02, 0x90, 0x2A, 0x02, 0xC0, 0x2E, 0x02, 0xF0, 0x31,
|
||||
0x03, 0x20, 0x34, 0x03, 0x50, 0x37, 0x03, 0x90, 0x3A, 0x03, 0xC0, 0x3D, 0x03, 0xF0, 0x40, 0x04, 0x20, 0x43, 0x04, 0x50, 0x47, 0x04, 0x80, 0x4A,
|
||||
0x04, 0xB0, 0x4D, 0x04, 0xE0, 0x50, 0x05, 0x20, 0x53, 0x05, 0x50, 0x56, 0x05, 0x80, 0x59, 0x05, 0xB0, 0x5D, 0x05, 0xE0, 0x60, 0x06, 0x10, 0x63,
|
||||
0x06, 0x40, 0x66, 0x06, 0x80, 0x69, 0x06, 0xB0, 0x6C, 0x06, 0xE0, 0x6F, 0x07, 0x10, 0x73, 0x07, 0x40, 0x76, 0x07, 0x70, 0x79, 0x07, 0xA0, 0x7C,
|
||||
0x07, 0xE0, 0x7F, 0x08, 0x10, 0x82, 0x08, 0x40, 0x85, 0x08, 0x70, 0x88, 0x08, 0xA0, 0x8C, 0x08, 0xD0, 0x8F, 0x09, 0x00, 0x92, 0x09, 0x30, 0x95,
|
||||
0x09, 0x70, 0x98, 0x09, 0xA0, 0x9B, 0x09, 0xD0, 0x9E, 0x0A, 0x00, 0xA2, 0x0A, 0x30, 0xA5, 0x0A, 0x60, 0xA8, 0x0A, 0x90, 0xAB, 0x0A, 0xC0, 0xAE,
|
||||
0x0B, 0x00, 0xB1, 0x0B, 0x30, 0xB4, 0x0B, 0x60, 0xB7, 0x0B, 0x90, 0xBB, 0x0B, 0xC0, 0xBE, 0x0B, 0xF0, 0xC1, 0x0C, 0x20, 0xC4, 0x0C, 0x60, 0xC7,
|
||||
0x0C, 0x90, 0xCA, 0x0C, 0xC0, 0xCD, 0x0C, 0xF0, 0xD0, 0x0D, 0x20, 0xD4, 0x0D, 0x50, 0xD7, 0x0D, 0x80, 0xDA, 0x0D, 0xB0, 0xDD, 0x0D, 0xF0, 0xE0,
|
||||
0x0E, 0x20, 0xE3, 0x0E, 0x50, 0xE6, 0x0E, 0x80, 0xE9, 0x0E, 0xB0, 0xED, 0x0E, 0xE0, 0xF0, 0x0F, 0x10, 0xF3, 0x0F, 0x40, 0xF6, 0x0F, 0x70, 0xF9,
|
||||
0x0F, 0xB0, 0xFC, 0x0F, 0xE0, 0xFF, 0x10, 0x11, 0x02, 0x10, 0x41, 0x05, 0x10, 0x71, 0x09, 0x10, 0xA1, 0x0C, 0x10, 0xD1, 0x0F, 0x11, 0x01, 0x12,
|
||||
0x11, 0x31, 0x15, 0x11, 0x71, 0x18, 0x11, 0xA1, 0x1B, 0x11, 0xD1, 0x1E, 0x12, 0x01, 0x21, 0x12, 0x31, 0x25, 0x12, 0x61, 0x28, 0x12, 0x91, 0x2B,
|
||||
0x12, 0xC1, 0x2E, 0x12, 0xF1, 0x31, 0x13, 0x31, 0x34, 0x13, 0x61, 0x37, 0x13, 0x91, 0x3A, 0x13, 0xC1, 0x3D, 0x13, 0xF1, 0x41, 0x14, 0x21, 0x44,
|
||||
0x14, 0x51, 0x47, 0x14, 0x81, 0x4A, 0x14, 0xB1, 0x4D, 0x14, 0xE1, 0x50, 0x15, 0x21, 0x53, 0x15, 0x51, 0x56, 0x15, 0x81, 0x59, 0x15, 0xB1, 0x5C,
|
||||
0x15, 0xE1, 0x60, 0x16, 0x11, 0x63, 0x16, 0x41, 0x66, 0x16, 0x71, 0x69, 0x16, 0xA1, 0x6C, 0x16, 0xD1, 0x6F, 0x17, 0x11, 0x72, 0x17, 0x41, 0x75,
|
||||
0x17, 0x71, 0x78, 0x17, 0xA1, 0x7B, 0x17, 0xD1, 0x7E, 0x18, 0x01, 0x81, 0x18, 0x31, 0x85, 0x18, 0x61, 0x88, 0x18, 0x91, 0x8B, 0x18, 0xC1, 0x8E,
|
||||
0x18, 0xF1, 0x91, 0x19, 0x21, 0x94, 0x19, 0x61, 0x97, 0x19, 0x91, 0x9A, 0x19, 0xC1, 0x9D, 0x19, 0xF1, 0xA0, 0x1A, 0x21, 0xA3, 0x1A, 0x51, 0xA6,
|
||||
0x1A, 0x81, 0xA9, 0x1A, 0xB1, 0xAD, 0x1A, 0xE1, 0xB0, 0x1B, 0x11, 0xB3, 0x1B, 0x41, 0xB6, 0x1B, 0x71, 0xB9, 0x1B, 0xA1, 0xBC, 0x1B, 0xD1, 0xBF,
|
||||
0x1C, 0x11, 0xC2, 0x1C, 0x41, 0xC5, 0x1C, 0x71, 0xC8, 0x1C, 0xA1, 0xCB, 0x1C, 0xD1, 0xCE, 0x1D, 0x01, 0xD1, 0x1D, 0x31, 0xD4, 0x1D, 0x61, 0xD7,
|
||||
0x1D, 0x91, 0xDB, 0x1D, 0xC1, 0xDE, 0x1D, 0xF1, 0xE1, 0x1E, 0x21, 0xE4, 0x1E, 0x51, 0xE7, 0x1E, 0x81, 0xEA, 0x1E, 0xB1, 0xED, 0x1E, 0xE1, 0xF0,
|
||||
0x1F, 0x11, 0xF3, 0x1F, 0x41, 0xF6, 0x1F, 0x71, 0xF9, 0x1F, 0xB1, 0xFC, 0x1F, 0xE1, 0xFF, 0x20, 0x12, 0x02, 0x20, 0x42, 0x05, 0x20, 0x72, 0x08,
|
||||
0x20, 0xA2, 0x0B, 0x20, 0xD2, 0x0E, 0x21, 0x02, 0x11, 0x21, 0x32, 0x14, 0x21, 0x62, 0x17, 0x21, 0x92, 0x1A, 0x21, 0xC2, 0x1D, 0x21, 0xF2, 0x20,
|
||||
0x22, 0x22, 0x23, 0x22, 0x52, 0x26, 0x22, 0x82, 0x2A, 0x22, 0xB2, 0x2D, 0x22, 0xE2, 0x30, 0x23, 0x12, 0x33, 0x23, 0x42, 0x36, 0x23, 0x72, 0x39,
|
||||
0x23, 0xA2, 0x3C, 0x23, 0xD2, 0x3F, 0x24, 0x02, 0x42, 0x24, 0x32, 0x45, 0x24, 0x62, 0x48, 0x24, 0x92, 0x4B, 0x24, 0xC2, 0x4E, 0x24, 0xF2, 0x51,
|
||||
0x25, 0x22, 0x54, 0x25, 0x52, 0x57, 0x25, 0x82, 0x5A, 0x25, 0xB2, 0x5D, 0x25, 0xE2, 0x60, 0x26, 0x12, 0x63, 0x26, 0x42, 0x66, 0x26, 0x72, 0x69,
|
||||
0x26, 0xA2, 0x6C, 0x26, 0xD2, 0x6F, 0x27, 0x02, 0x72, 0x27, 0x32, 0x75, 0x27, 0x62, 0x78, 0x27, 0x92, 0x7B, 0x27, 0xC2, 0x7E, 0x27, 0xF2, 0x81,
|
||||
0x28, 0x22, 0x84, 0x28, 0x52, 0x87, 0x28, 0x82, 0x8A, 0x28, 0xB2, 0x8D, 0x28, 0xE2, 0x90, 0x29, 0x12, 0x92, 0x29, 0x42, 0x95, 0x29, 0x72, 0x98,
|
||||
0x29, 0xA2, 0x9B, 0x29, 0xD2, 0x9E, 0x2A, 0x02, 0xA1, 0x2A, 0x32, 0xA4, 0x2A, 0x62, 0xA7, 0x2A, 0x92, 0xAA, 0x2A, 0xC2, 0xAD, 0x2A, 0xF2, 0xB0,
|
||||
0x2B, 0x22, 0xB3, 0x2B, 0x52, 0xB6, 0x2B, 0x82, 0xB9, 0x2B, 0xA2, 0xBC, 0x2B, 0xD2, 0xBF, 0x2C, 0x02, 0xC2, 0x2C, 0x32, 0xC5, 0x2C, 0x62, 0xC8,
|
||||
0x2C, 0x92, 0xCB, 0x2C, 0xC2, 0xCE, 0x2C, 0xF2, 0xD1, 0x2D, 0x22, 0xD4, 0x2D, 0x52, 0xD6, 0x2D, 0x82, 0xD9, 0x2D, 0xB2, 0xDC, 0x2D, 0xE2, 0xDF,
|
||||
0x2E, 0x12, 0xE2, 0x2E, 0x42, 0xE5, 0x2E, 0x72, 0xE8, 0x2E, 0x92, 0xEB, 0x2E, 0xC2, 0xEE, 0x2E, 0xF2, 0xF1, 0x2F, 0x22, 0xF4, 0x2F, 0x52, 0xF7,
|
||||
0x2F, 0x82, 0xFA, 0x2F, 0xB2, 0xFC, 0x2F, 0xE2, 0xFF, 0x30, 0x13, 0x02, 0x30, 0x43, 0x05, 0x30, 0x73, 0x08, 0x30, 0xA3, 0x0B, 0x30, 0xC3, 0x0E,
|
||||
0x30, 0xF3, 0x11, 0x31, 0x23, 0x14, 0x31, 0x53, 0x17, 0x31, 0x83, 0x19, 0x31, 0xB3, 0x1C, 0x31, 0xE3, 0x1F, 0x32, 0x13, 0x22, 0x32, 0x43, 0x25,
|
||||
0x32, 0x73, 0x28, 0x32, 0x93, 0x2B, 0x32, 0xC3, 0x2E, 0x32, 0xF3, 0x31, 0x33, 0x23, 0x33, 0x33, 0x53, 0x36, 0x33, 0x83, 0x39, 0x33, 0xB3, 0x3C,
|
||||
0x33, 0xE3, 0x3F, 0x34, 0x03, 0x42, 0x34, 0x33, 0x45, 0x34, 0x63, 0x48, 0x34, 0x93, 0x4A, 0x34, 0xC3, 0x4D, 0x34, 0xF3, 0x50, 0x35, 0x23, 0x53,
|
||||
0x35, 0x43, 0x56, 0x35, 0x73, 0x59, 0x35, 0xA3, 0x5C, 0x35, 0xD3, 0x5E, 0x36, 0x03, 0x61, 0x36, 0x33, 0x64, 0x36, 0x63, 0x67, 0x36, 0x83, 0x6A,
|
||||
0x36, 0xB3, 0x6D, 0x36, 0xE3, 0x6F, 0x37, 0x13, 0x72, 0x37, 0x43, 0x75, 0x37, 0x73, 0x78, 0x37, 0x93, 0x7B, 0x37, 0xC3, 0x7E, 0x37, 0xF3, 0x80,
|
||||
0x38, 0x23, 0x83, 0x38, 0x53, 0x86, 0x38, 0x73, 0x89, 0x38, 0xA3, 0x8C, 0x38, 0xD3, 0x8F, 0x39, 0x03, 0x91, 0x39, 0x33, 0x94, 0x39, 0x63, 0x97,
|
||||
0x39, 0x83, 0x9A, 0x39, 0xB3, 0x9D, 0x39, 0xE3, 0x9F, 0x3A, 0x13, 0xA2, 0x3A, 0x43, 0xA5, 0x3A, 0x63, 0xA8, 0x3A, 0x93, 0xAB, 0x3A, 0xC3, 0xAD,
|
||||
0x3A, 0xF3, 0xB0, 0x3B, 0x23, 0xB3, 0x3B, 0x43, 0xB6, 0x3B, 0x73, 0xB8, 0x3B, 0xA3, 0xBB, 0x3B, 0xD3, 0xBE, 0x3B, 0xF3, 0xC1, 0x3C, 0x23, 0xC4,
|
||||
0x3C, 0x53, 0xC6, 0x3C, 0x83, 0xC9, 0x3C, 0xA3, 0xCC, 0x3C, 0xD3, 0xCF, 0x3D, 0x03, 0xD1, 0x3D, 0x33, 0xD4, 0x3D, 0x63, 0xD7, 0x3D, 0x83, 0xDA,
|
||||
0x3D, 0xB3, 0xDC, 0x3D, 0xE3, 0xDF, 0x3E, 0x13, 0xE2, 0x3E, 0x33, 0xE5, 0x3E, 0x63, 0xE7, 0x3E, 0x93, 0xEA, 0x3E, 0xB3, 0xED, 0x3E, 0xE3, 0xF0,
|
||||
0x3F, 0x13, 0xF2, 0x3F, 0x43, 0xF5, 0x3F, 0x63, 0xF8, 0x3F, 0x93, 0xFB, 0x3F, 0xC3, 0xFD, 0x3F, 0xF4, 0x00, 0x40, 0x14, 0x03, 0x40, 0x44, 0x05,
|
||||
0x40, 0x74, 0x08, 0x40, 0x94, 0x0B, 0x40, 0xC4, 0x0E, 0x40, 0xF4, 0x10, 0x41, 0x24, 0x13, 0x41, 0x44, 0x16, 0x41, 0x74, 0x18, 0x41, 0xA4, 0x1B,
|
||||
0x41, 0xC4, 0x1E, 0x41, 0xF4, 0x20, 0x42, 0x24, 0x23, 0x42, 0x44, 0x26, 0x42, 0x74, 0x28, 0x42, 0xA4, 0x2B, 0x42, 0xC4, 0x2E, 0x42, 0xF4, 0x30,
|
||||
0x43, 0x24, 0x33, 0x43, 0x54, 0x36, 0x43, 0x74, 0x39, 0x43, 0xA4, 0x3B, 0x43, 0xD4, 0x3E, 0x43, 0xF4, 0x40, 0x44, 0x24, 0x43, 0x44, 0x44, 0x46,
|
||||
0x44, 0x74, 0x48, 0x44, 0xA4, 0x4B, 0x44, 0xC4, 0x4E, 0x44, 0xF4, 0x50, 0x45, 0x24, 0x53, 0x45, 0x44, 0x56, 0x45, 0x74, 0x58, 0x45, 0xA4, 0x5B,
|
||||
0x45, 0xC4, 0x5E, 0x45, 0xF4, 0x60, 0x46, 0x24, 0x63, 0x46, 0x44, 0x65, 0x46, 0x74, 0x68, 0x46, 0x94, 0x6B, 0x46, 0xC4, 0x6D, 0x46, 0xF4, 0x70,
|
||||
0x47, 0x14, 0x73, 0x47, 0x44, 0x75, 0x47, 0x64, 0x78, 0x47, 0x94, 0x7A, 0x47, 0xC4, 0x7D, 0x47, 0xE4, 0x80, 0x48, 0x14, 0x82, 0x48, 0x34, 0x85,
|
||||
0x48, 0x64, 0x87, 0x48, 0x94, 0x8A, 0x48, 0xB4, 0x8D, 0x48, 0xE4, 0x8F, 0x49, 0x04, 0x92, 0x49, 0x34, 0x94, 0x49, 0x64, 0x97, 0x49, 0x84, 0x99,
|
||||
0x49, 0xB4, 0x9C, 0x49, 0xD4, 0x9F, 0x4A, 0x04, 0xA1, 0x4A, 0x24, 0xA4, 0x4A, 0x54, 0xA6, 0x4A, 0x74, 0xA9, 0x4A, 0xA4, 0xAB, 0x4A, 0xD4, 0xAE,
|
||||
0x4A, 0xF4, 0xB0, 0x4B, 0x24, 0xB3, 0x4B, 0x44, 0xB5, 0x4B, 0x74, 0xB8, 0x4B, 0x94, 0xBB, 0x4B, 0xC4, 0xBD, 0x4B, 0xE4, 0xC0, 0x4C, 0x14, 0xC2,
|
||||
0x4C, 0x34, 0xC5, 0x4C, 0x64, 0xC7, 0x4C, 0x84, 0xCA, 0x4C, 0xB4, 0xCC, 0x4C, 0xD4, 0xCF, 0x4D, 0x04, 0xD1, 0x4D, 0x24, 0xD4, 0x4D, 0x54, 0xD6,
|
||||
0x4D, 0x74, 0xD9, 0x4D, 0xA4, 0xDB, 0x4D, 0xC4, 0xDE, 0x4D, 0xF4, 0xE0, 0x4E, 0x14, 0xE3, 0x4E, 0x44, 0xE5, 0x4E, 0x64, 0xE8, 0x4E, 0x94, 0xEA,
|
||||
0x4E, 0xB4, 0xED, 0x4E, 0xE4, 0xEF, 0x4F, 0x04, 0xF2, 0x4F, 0x34, 0xF4, 0x4F, 0x54, 0xF6, 0x4F, 0x84, 0xF9, 0x4F, 0xA4, 0xFB, 0x4F, 0xD4, 0xFE,
|
||||
0x4F, 0xF5, 0x00, 0x50, 0x25, 0x03, 0x50, 0x45, 0x05, 0x50, 0x65, 0x08, 0x50, 0x95, 0x0A, 0x50, 0xB5, 0x0D, 0x50, 0xE5, 0x0F, 0x51, 0x05, 0x11,
|
||||
0x51, 0x35, 0x14, 0x51, 0x55, 0x16, 0x51, 0x75, 0x19, 0x51, 0xA5, 0x1B, 0x51, 0xC5, 0x1D, 0x51, 0xF5, 0x20, 0x52, 0x15, 0x22, 0x52, 0x45, 0x25,
|
||||
0x52, 0x65, 0x27, 0x52, 0x85, 0x2A, 0x52, 0xB5, 0x2C, 0x52, 0xD5, 0x2E, 0x53, 0x05, 0x31, 0x53, 0x25, 0x33, 0x53, 0x45, 0x35, 0x53, 0x75, 0x38,
|
||||
0x53, 0x95, 0x3A, 0x53, 0xB5, 0x3D, 0x53, 0xE5, 0x3F, 0x54, 0x05, 0x41, 0x54, 0x35, 0x44, 0x54, 0x55, 0x46, 0x54, 0x75, 0x48, 0x54, 0xA5, 0x4B,
|
||||
0x54, 0xC5, 0x4D, 0x54, 0xE5, 0x4F, 0x55, 0x15, 0x52, 0x55, 0x35, 0x54, 0x55, 0x55, 0x57, 0x55, 0x85, 0x59, 0x55, 0xA5, 0x5B, 0x55, 0xC5, 0x5E,
|
||||
0x55, 0xF5, 0x60, 0x56, 0x15, 0x62, 0x56, 0x35, 0x64, 0x56, 0x65, 0x67, 0x56, 0x85, 0x69, 0x56, 0xA5, 0x6B, 0x56, 0xD5, 0x6E, 0x56, 0xF5, 0x70,
|
||||
0x57, 0x15, 0x72, 0x57, 0x35, 0x75, 0x57, 0x65, 0x77, 0x57, 0x85, 0x79, 0x57, 0xA5, 0x7C, 0x57, 0xD5, 0x7E, 0x57, 0xF5, 0x80, 0x58, 0x15, 0x82,
|
||||
0x58, 0x35, 0x85, 0x58, 0x65, 0x87, 0x58, 0x85, 0x89, 0x58, 0xA5, 0x8B, 0x58, 0xD5, 0x8E, 0x58, 0xF5, 0x90, 0x59, 0x15, 0x92, 0x59, 0x35, 0x94,
|
||||
0x59, 0x65, 0x97, 0x59, 0x85, 0x99, 0x59, 0xA5, 0x9B, 0x59, 0xC5, 0x9D, 0x59, 0xF5, 0xA0, 0x5A, 0x15, 0xA2, 0x5A, 0x35, 0xA4, 0x5A, 0x55, 0xA6,
|
||||
0x5A, 0x75, 0xA9, 0x5A, 0xA5, 0xAB, 0x5A, 0xC5, 0xAD, 0x5A, 0xE5, 0xAF, 0x5B, 0x05, 0xB1, 0x5B, 0x35, 0xB4, 0x5B, 0x55, 0xB6, 0x5B, 0x75, 0xB8,
|
||||
0x5B, 0x95, 0xBA, 0x5B, 0xB5, 0xBC, 0x5B, 0xD5, 0xBF, 0x5C, 0x05, 0xC1, 0x5C, 0x25, 0xC3, 0x5C, 0x45, 0xC5, 0x5C, 0x65, 0xC7, 0x5C, 0x85, 0xC9,
|
||||
0x5C, 0xB5, 0xCC, 0x5C, 0xD5, 0xCE, 0x5C, 0xF5, 0xD0, 0x5D, 0x15, 0xD2, 0x5D, 0x35, 0xD4, 0x5D, 0x55, 0xD6, 0x5D, 0x75, 0xD9, 0x5D, 0xA5, 0xDB,
|
||||
0x5D, 0xC5, 0xDD, 0x5D, 0xE5, 0xDF, 0x5E, 0x05, 0xE1, 0x5E, 0x25, 0xE3, 0x5E, 0x45, 0xE5, 0x5E, 0x65, 0xE7, 0x5E, 0x95, 0xEA, 0x5E, 0xB5, 0xEC,
|
||||
0x5E, 0xD5, 0xEE, 0x5E, 0xF5, 0xF0, 0x5F, 0x15, 0xF2, 0x5F, 0x35, 0xF4, 0x5F, 0x55, 0xF6, 0x5F, 0x75, 0xF8, 0x5F, 0x95, 0xFA, 0x5F, 0xB5, 0xFC,
|
||||
0x5F, 0xD5, 0xFF, 0x60, 0x06, 0x01, 0x60, 0x26, 0x03, 0x60, 0x46, 0x05, 0x60, 0x66, 0x07, 0x60, 0x86, 0x09, 0x60, 0xA6, 0x0B, 0x60, 0xC6, 0x0D,
|
||||
0x60, 0xE6, 0x0F, 0x61, 0x06, 0x11, 0x61, 0x26, 0x13, 0x61, 0x46, 0x15, 0x61, 0x66, 0x17, 0x61, 0x86, 0x19, 0x61, 0xA6, 0x1B, 0x61, 0xC6, 0x1D,
|
||||
0x61, 0xE6, 0x1F, 0x62, 0x06, 0x21, 0x62, 0x26, 0x23, 0x62, 0x46, 0x25, 0x62, 0x66, 0x27, 0x62, 0x86, 0x29, 0x62, 0xA6, 0x2B, 0x62, 0xC6, 0x2D,
|
||||
0x62, 0xE6, 0x2F, 0x63, 0x06, 0x31, 0x63, 0x26, 0x33, 0x63, 0x46, 0x35, 0x63, 0x66, 0x37, 0x63, 0x86, 0x39, 0x63, 0xA6, 0x3B, 0x63, 0xC6, 0x3D,
|
||||
0x63, 0xE6, 0x3F, 0x64, 0x06, 0x41, 0x64, 0x26, 0x43, 0x64, 0x46, 0x45, 0x64, 0x66, 0x47, 0x64, 0x86, 0x49, 0x64, 0xA6, 0x4B, 0x64, 0xC6, 0x4D,
|
||||
0x64, 0xE6, 0x4F, 0x65, 0x06, 0x51, 0x65, 0x26, 0x53, 0x65, 0x46, 0x54, 0x65, 0x56, 0x56, 0x65, 0x76, 0x58, 0x65, 0x96, 0x5A, 0x65, 0xB6, 0x5C,
|
||||
0x65, 0xD6, 0x5E, 0x65, 0xF6, 0x60, 0x66, 0x16, 0x62, 0x66, 0x36, 0x64, 0x66, 0x56, 0x66, 0x66, 0x76, 0x67, 0x66, 0x86, 0x69, 0x66, 0xA6, 0x6B,
|
||||
0x66, 0xC6, 0x6D, 0x66, 0xE6, 0x6F, 0x67, 0x06, 0x71, 0x67, 0x26, 0x73, 0x67, 0x46, 0x75, 0x67, 0x56, 0x76, 0x67, 0x76, 0x78, 0x67, 0x96, 0x7A,
|
||||
0x67, 0xB6, 0x7C, 0x67, 0xD6, 0x7E, 0x67, 0xF6, 0x80, 0x68, 0x16, 0x81, 0x68, 0x26, 0x83, 0x68, 0x46, 0x85, 0x68, 0x66, 0x87, 0x68, 0x86, 0x89,
|
||||
0x68, 0xA6, 0x8A, 0x68, 0xB6, 0x8C, 0x68, 0xD6, 0x8E, 0x68, 0xF6, 0x90, 0x69, 0x16, 0x92, 0x69, 0x36, 0x93, 0x69, 0x46, 0x95, 0x69, 0x66, 0x97,
|
||||
0x69, 0x86, 0x99, 0x69, 0xA6, 0x9B, 0x69, 0xB6, 0x9C, 0x69, 0xD6, 0x9E, 0x69, 0xF6, 0xA0, 0x6A, 0x16, 0xA2, 0x6A, 0x36, 0xA3, 0x6A, 0x46, 0xA5,
|
||||
0x6A, 0x66, 0xA7, 0x6A, 0x86, 0xA9, 0x6A, 0x96, 0xAA, 0x6A, 0xB6, 0xAC, 0x6A, 0xD6, 0xAE, 0x6A, 0xF6, 0xB0, 0x6B, 0x06, 0xB1, 0x6B, 0x26, 0xB3,
|
||||
0x6B, 0x46, 0xB5, 0x6B, 0x66, 0xB6, 0x6B, 0x76, 0xB8, 0x6B, 0x96, 0xBA, 0x6B, 0xB6, 0xBC, 0x6B, 0xC6, 0xBD, 0x6B, 0xE6, 0xBF, 0x6C, 0x06, 0xC1,
|
||||
0x6C, 0x16, 0xC2, 0x6C, 0x36, 0xC4, 0x6C, 0x56, 0xC6, 0x6C, 0x66, 0xC7, 0x6C, 0x86, 0xC9, 0x6C, 0xA6, 0xCB, 0x6C, 0xB6, 0xCC, 0x6C, 0xD6, 0xCE,
|
||||
0x6C, 0xF6, 0xD0, 0x6D, 0x06, 0xD1, 0x6D, 0x26, 0xD3, 0x6D, 0x46, 0xD4, 0x6D, 0x56, 0xD6, 0x6D, 0x76, 0xD8, 0x6D, 0x96, 0xD9, 0x6D, 0xA6, 0xDB,
|
||||
0x6D, 0xC6, 0xDD, 0x6D, 0xD6, 0xDE, 0x6D, 0xF6, 0xE0, 0x6E, 0x16, 0xE1, 0x6E, 0x26, 0xE3, 0x6E, 0x46, 0xE5, 0x6E, 0x56, 0xE6, 0x6E, 0x76, 0xE8,
|
||||
0x6E, 0x96, 0xE9, 0x6E, 0xA6, 0xEB, 0x6E, 0xC6, 0xEC, 0x6E, 0xD6, 0xEE, 0x6E, 0xF6, 0xF0, 0x6F, 0x06, 0xF1, 0x6F, 0x26, 0xF3, 0x6F, 0x46, 0xF4,
|
||||
0x6F, 0x56, 0xF6, 0x6F, 0x76, 0xF7, 0x6F, 0x86, 0xF9, 0x6F, 0xA6, 0xFA, 0x6F, 0xB6, 0xFC, 0x6F, 0xD6, 0xFE, 0x6F, 0xE6, 0xFF, 0x70, 0x07, 0x01,
|
||||
0x70, 0x17, 0x02, 0x70, 0x37, 0x04, 0x70, 0x47, 0x05, 0x70, 0x67, 0x07, 0x70, 0x77, 0x08, 0x70, 0x97, 0x0A, 0x70, 0xA7, 0x0B, 0x70, 0xC7, 0x0D,
|
||||
0x70, 0xD7, 0x0E, 0x70, 0xF7, 0x10, 0x71, 0x07, 0x11, 0x71, 0x27, 0x12, 0x71, 0x37, 0x14, 0x71, 0x57, 0x15, 0x71, 0x67, 0x17, 0x71, 0x87, 0x18,
|
||||
0x71, 0x97, 0x1A, 0x71, 0xA7, 0x1B, 0x71, 0xC7, 0x1D, 0x71, 0xD7, 0x1E, 0x71, 0xF7, 0x1F, 0x72, 0x07, 0x21, 0x72, 0x27, 0x22, 0x72, 0x37, 0x24,
|
||||
0x72, 0x47, 0x25, 0x72, 0x67, 0x27, 0x72, 0x77, 0x28, 0x72, 0x97, 0x29, 0x72, 0xA7, 0x2B, 0x72, 0xB7, 0x2C, 0x72, 0xD7, 0x2E, 0x72, 0xE7, 0x2F,
|
||||
0x73, 0x07, 0x30, 0x73, 0x17, 0x32, 0x73, 0x27, 0x33, 0x73, 0x47, 0x34, 0x73, 0x57, 0x36, 0x73, 0x67, 0x37, 0x73, 0x87, 0x38, 0x73, 0x97, 0x3A,
|
||||
0x73, 0xA7, 0x3B, 0x73, 0xC7, 0x3C, 0x73, 0xD7, 0x3E, 0x73, 0xE7, 0x3F, 0x74, 0x07, 0x40, 0x74, 0x17, 0x42, 0x74, 0x27, 0x43, 0x74, 0x47, 0x44,
|
||||
0x74, 0x57, 0x46, 0x74, 0x67, 0x47, 0x74, 0x87, 0x48, 0x74, 0x97, 0x4A, 0x74, 0xA7, 0x4B, 0x74, 0xC7, 0x4C, 0x74, 0xD7, 0x4D, 0x74, 0xE7, 0x4F,
|
||||
0x74, 0xF7, 0x50, 0x75, 0x17, 0x51, 0x75, 0x27, 0x53, 0x75, 0x37, 0x54, 0x75, 0x47, 0x55, 0x75, 0x67, 0x56, 0x75, 0x77, 0x58, 0x75, 0x87, 0x59,
|
||||
0x75, 0x97, 0x5A, 0x75, 0xB7, 0x5B, 0x75, 0xC7, 0x5D, 0x75, 0xD7, 0x5E, 0x75, 0xE7, 0x5F, 0x76, 0x07, 0x60, 0x76, 0x17, 0x61, 0x76, 0x27, 0x63,
|
||||
0x76, 0x37, 0x64, 0x76, 0x47, 0x65, 0x76, 0x67, 0x66, 0x76, 0x77, 0x67, 0x76, 0x87, 0x69, 0x76, 0x97, 0x6A, 0x76, 0xA7, 0x6B, 0x76, 0xB7, 0x6C,
|
||||
0x76, 0xD7, 0x6D, 0x76, 0xE7, 0x6E, 0x76, 0xF7, 0x70, 0x77, 0x07, 0x71, 0x77, 0x17, 0x72, 0x77, 0x27, 0x73, 0x77, 0x47, 0x74, 0x77, 0x57, 0x75,
|
||||
0x77, 0x67, 0x76, 0x77, 0x77, 0x78, 0x77, 0x87, 0x79, 0x77, 0x97, 0x7A, 0x77, 0xA7, 0x7B, 0x77, 0xB7, 0x7C, 0x77, 0xD7, 0x7D, 0x77, 0xE7, 0x7E,
|
||||
0x77, 0xF7, 0x7F, 0x78, 0x07, 0x80, 0x78, 0x17, 0x81, 0x78, 0x27, 0x83, 0x78, 0x37, 0x84, 0x78, 0x47, 0x85, 0x78, 0x57, 0x86, 0x78, 0x67, 0x87,
|
||||
0x78, 0x77, 0x88, 0x78, 0x87, 0x89, 0x78, 0x97, 0x8A, 0x78, 0xA7, 0x8B, 0x78, 0xC7, 0x8C, 0x78, 0xD7, 0x8D, 0x78, 0xE7, 0x8E, 0x78, 0xF7, 0x8F,
|
||||
0x79, 0x07, 0x90, 0x79, 0x17, 0x91, 0x79, 0x27, 0x92, 0x79, 0x37, 0x93, 0x79, 0x47, 0x94, 0x79, 0x57, 0x95, 0x79, 0x67, 0x96, 0x79, 0x77, 0x97,
|
||||
0x79, 0x87, 0x98, 0x79, 0x97, 0x99, 0x79, 0xA7, 0x9A, 0x79, 0xB7, 0x9B, 0x79, 0xC7, 0x9C, 0x79, 0xD7, 0x9D, 0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x9F,
|
||||
0x79, 0xF7, 0xA0, 0x7A, 0x07, 0xA1, 0x7A, 0x17, 0xA2, 0x7A, 0x27, 0xA3, 0x7A, 0x37, 0xA4, 0x7A, 0x47, 0xA5, 0x7A, 0x57, 0xA5, 0x7A, 0x67, 0xA6,
|
||||
0x7A, 0x77, 0xA7, 0x7A, 0x87, 0xA8, 0x7A, 0x97, 0xA9, 0x7A, 0xA7, 0xAA, 0x7A, 0xA7, 0xAB, 0x7A, 0xB7, 0xAC, 0x7A, 0xC7, 0xAD, 0x7A, 0xD7, 0xAE,
|
||||
0x7A, 0xE7, 0xAE, 0x7A, 0xF7, 0xAF, 0x7B, 0x07, 0xB0, 0x7B, 0x17, 0xB1, 0x7B, 0x17, 0xB2, 0x7B, 0x27, 0xB3, 0x7B, 0x37, 0xB4, 0x7B, 0x47, 0xB4,
|
||||
0x7B, 0x57, 0xB5, 0x7B, 0x67, 0xB6, 0x7B, 0x77, 0xB7, 0x7B, 0x77, 0xB8, 0x7B, 0x87, 0xB9, 0x7B, 0x97, 0xB9, 0x7B, 0xA7, 0xBA, 0x7B, 0xB7, 0xBB,
|
||||
0x7B, 0xB7, 0xBC, 0x7B, 0xC7, 0xBD, 0x7B, 0xD7, 0xBD, 0x7B, 0xE7, 0xBE, 0x7B, 0xF7, 0xBF, 0x7B, 0xF7, 0xC0, 0x7C, 0x07, 0xC1, 0x7C, 0x17, 0xC1,
|
||||
0x7C, 0x27, 0xC2, 0x7C, 0x27, 0xC3, 0x7C, 0x37, 0xC4, 0x7C, 0x47, 0xC4, 0x7C, 0x57, 0xC5, 0x7C, 0x57, 0xC6, 0x7C, 0x67, 0xC7, 0x7C, 0x77, 0xC7,
|
||||
0x7C, 0x87, 0xC8, 0x7C, 0x87, 0xC9, 0x7C, 0x97, 0xC9, 0x7C, 0xA7, 0xCA, 0x7C, 0xA7, 0xCB, 0x7C, 0xB7, 0xCC, 0x7C, 0xC7, 0xCC, 0x7C, 0xD7, 0xCD,
|
||||
0x7C, 0xD7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x17, 0xD1, 0x7D, 0x17, 0xD2, 0x7D, 0x27, 0xD2,
|
||||
0x7D, 0x37, 0xD3, 0x7D, 0x37, 0xD4, 0x7D, 0x47, 0xD4, 0x7D, 0x57, 0xD5, 0x7D, 0x57, 0xD5, 0x7D, 0x67, 0xD6, 0x7D, 0x67, 0xD7, 0x7D, 0x77, 0xD7,
|
||||
0x7D, 0x87, 0xD8, 0x7D, 0x87, 0xD9, 0x7D, 0x97, 0xD9, 0x7D, 0x97, 0xDA, 0x7D, 0xA7, 0xDA, 0x7D, 0xB7, 0xDB, 0x7D, 0xB7, 0xDC, 0x7D, 0xC7, 0xDC,
|
||||
0x7D, 0xC7, 0xDD, 0x7D, 0xD7, 0xDD, 0x7D, 0xE7, 0xDE, 0x7D, 0xE7, 0xDE, 0x7D, 0xF7, 0xDF, 0x7D, 0xF7, 0xE0, 0x7E, 0x07, 0xE0, 0x7E, 0x07, 0xE1,
|
||||
0x7E, 0x17, 0xE1, 0x7E, 0x17, 0xE2, 0x7E, 0x27, 0xE2, 0x7E, 0x27, 0xE3, 0x7E, 0x37, 0xE3, 0x7E, 0x37, 0xE4, 0x7E, 0x47, 0xE4, 0x7E, 0x57, 0xE5,
|
||||
0x7E, 0x57, 0xE5, 0x7E, 0x67, 0xE6, 0x7E, 0x67, 0xE6, 0x7E, 0x67, 0xE7, 0x7E, 0x77, 0xE7, 0x7E, 0x77, 0xE8, 0x7E, 0x87, 0xE8, 0x7E, 0x87, 0xE9,
|
||||
0x7E, 0x97, 0xE9, 0x7E, 0x97, 0xEA, 0x7E, 0xA7, 0xEA, 0x7E, 0xA7, 0xEA, 0x7E, 0xB7, 0xEB, 0x7E, 0xB7, 0xEB, 0x7E, 0xC7, 0xEC, 0x7E, 0xC7, 0xEC,
|
||||
0x7E, 0xC7, 0xED, 0x7E, 0xD7, 0xED, 0x7E, 0xD7, 0xED, 0x7E, 0xE7, 0xEE, 0x7E, 0xE7, 0xEE, 0x7E, 0xE7, 0xEF, 0x7E, 0xF7, 0xEF, 0x7E, 0xF7, 0xEF,
|
||||
0x7F, 0x07, 0xF0, 0x7F, 0x07, 0xF0, 0x7F, 0x07, 0xF1, 0x7F, 0x17, 0xF1, 0x7F, 0x17, 0xF1, 0x7F, 0x17, 0xF2, 0x7F, 0x27, 0xF2, 0x7F, 0x27, 0xF2,
|
||||
0x7F, 0x37, 0xF3, 0x7F, 0x37, 0xF3, 0x7F, 0x37, 0xF3, 0x7F, 0x47, 0xF4, 0x7F, 0x47, 0xF4, 0x7F, 0x47, 0xF4, 0x7F, 0x57, 0xF5, 0x7F, 0x57, 0xF5,
|
||||
0x7F, 0x57, 0xF5, 0x7F, 0x57, 0xF6, 0x7F, 0x67, 0xF6, 0x7F, 0x67, 0xF6, 0x7F, 0x67, 0xF6, 0x7F, 0x77, 0xF7, 0x7F, 0x77, 0xF7, 0x7F, 0x77, 0xF7,
|
||||
0x7F, 0x77, 0xF8, 0x7F, 0x87, 0xF8, 0x7F, 0x87, 0xF8, 0x7F, 0x87, 0xF8, 0x7F, 0x87, 0xF9, 0x7F, 0x97, 0xF9, 0x7F, 0x97, 0xF9, 0x7F, 0x97, 0xF9,
|
||||
0x7F, 0x97, 0xFA, 0x7F, 0xA7, 0xFA, 0x7F, 0xA7, 0xFA, 0x7F, 0xA7, 0xFA, 0x7F, 0xA7, 0xFA, 0x7F, 0xB7, 0xFB, 0x7F, 0xB7, 0xFB, 0x7F, 0xB7, 0xFB,
|
||||
0x7F, 0xB7, 0xFB, 0x7F, 0xB7, 0xFB, 0x7F, 0xC7, 0xFC, 0x7F, 0xC7, 0xFC, 0x7F, 0xC7, 0xFC, 0x7F, 0xC7, 0xFC, 0x7F, 0xC7, 0xFC, 0x7F, 0xC7, 0xFC,
|
||||
0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFD, 0x7F, 0xD7, 0xFE,
|
||||
0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE,
|
||||
0x7F, 0xE7, 0xFE, 0x7F, 0xE7, 0xFE, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF,
|
||||
0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF,
|
||||
};
|
||||
#else
|
||||
// range 2000
|
||||
const uint8_t LUT_sine_8192_quad_packed[3072] = {
|
||||
0x00, 0x00, 0x02, 0x00, 0x30, 0x05, 0x00, 0x60, 0x08, 0x00, 0x90, 0x0B, 0x00, 0xC0, 0x0E, 0x00, 0xF0, 0x11, 0x01, 0x20, 0x14, 0x01, 0x50, 0x17,
|
||||
0x01, 0x90, 0x1A, 0x01, 0xC0, 0x1D, 0x01, 0xF0, 0x20, 0x02, 0x20, 0x23, 0x02, 0x50, 0x26, 0x02, 0x80, 0x29, 0x02, 0xB0, 0x2C, 0x02, 0xE0, 0x30,
|
||||
0x03, 0x10, 0x33, 0x03, 0x40, 0x36, 0x03, 0x70, 0x39, 0x03, 0xA0, 0x3C, 0x03, 0xD0, 0x3F, 0x04, 0x00, 0x42, 0x04, 0x30, 0x45, 0x04, 0x70, 0x48,
|
||||
0x04, 0xA0, 0x4B, 0x04, 0xD0, 0x4E, 0x05, 0x00, 0x51, 0x05, 0x30, 0x54, 0x05, 0x60, 0x57, 0x05, 0x90, 0x5A, 0x05, 0xC0, 0x5E, 0x05, 0xF0, 0x61,
|
||||
0x06, 0x20, 0x64, 0x06, 0x50, 0x67, 0x06, 0x80, 0x6A, 0x06, 0xB0, 0x6D, 0x06, 0xE0, 0x70, 0x07, 0x10, 0x73, 0x07, 0x50, 0x76, 0x07, 0x80, 0x79,
|
||||
0x07, 0xB0, 0x7C, 0x07, 0xE0, 0x7F, 0x08, 0x10, 0x82, 0x08, 0x40, 0x85, 0x08, 0x70, 0x88, 0x08, 0xA0, 0x8B, 0x08, 0xD0, 0x8F, 0x09, 0x00, 0x92,
|
||||
0x09, 0x30, 0x95, 0x09, 0x60, 0x98, 0x09, 0x90, 0x9B, 0x09, 0xC0, 0x9E, 0x09, 0xF0, 0xA1, 0x0A, 0x20, 0xA4, 0x0A, 0x50, 0xA7, 0x0A, 0x90, 0xAA,
|
||||
0x0A, 0xC0, 0xAD, 0x0A, 0xF0, 0xB0, 0x0B, 0x20, 0xB3, 0x0B, 0x50, 0xB6, 0x0B, 0x80, 0xB9, 0x0B, 0xB0, 0xBC, 0x0B, 0xE0, 0xBF, 0x0C, 0x10, 0xC3,
|
||||
0x0C, 0x40, 0xC6, 0x0C, 0x70, 0xC9, 0x0C, 0xA0, 0xCC, 0x0C, 0xD0, 0xCF, 0x0D, 0x00, 0xD2, 0x0D, 0x30, 0xD5, 0x0D, 0x60, 0xD8, 0x0D, 0x90, 0xDB,
|
||||
0x0D, 0xC0, 0xDE, 0x0D, 0xF0, 0xE1, 0x0E, 0x30, 0xE4, 0x0E, 0x60, 0xE7, 0x0E, 0x90, 0xEA, 0x0E, 0xC0, 0xED, 0x0E, 0xF0, 0xF0, 0x0F, 0x20, 0xF3,
|
||||
0x0F, 0x50, 0xF6, 0x0F, 0x80, 0xF9, 0x0F, 0xB0, 0xFC, 0x0F, 0xE0, 0xFF, 0x10, 0x11, 0x03, 0x10, 0x41, 0x06, 0x10, 0x71, 0x09, 0x10, 0xA1, 0x0C,
|
||||
0x10, 0xD1, 0x0F, 0x11, 0x01, 0x12, 0x11, 0x31, 0x15, 0x11, 0x61, 0x18, 0x11, 0x91, 0x1B, 0x11, 0xC1, 0x1E, 0x11, 0xF1, 0x21, 0x12, 0x21, 0x24,
|
||||
0x12, 0x51, 0x27, 0x12, 0x81, 0x2A, 0x12, 0xC1, 0x2D, 0x12, 0xF1, 0x30, 0x13, 0x21, 0x33, 0x13, 0x51, 0x36, 0x13, 0x81, 0x39, 0x13, 0xB1, 0x3C,
|
||||
0x13, 0xE1, 0x3F, 0x14, 0x11, 0x42, 0x14, 0x41, 0x45, 0x14, 0x71, 0x48, 0x14, 0xA1, 0x4B, 0x14, 0xD1, 0x4E, 0x15, 0x01, 0x51, 0x15, 0x31, 0x54,
|
||||
0x15, 0x61, 0x57, 0x15, 0x91, 0x5A, 0x15, 0xC1, 0x5D, 0x15, 0xF1, 0x60, 0x16, 0x21, 0x64, 0x16, 0x51, 0x67, 0x16, 0x81, 0x6A, 0x16, 0xB1, 0x6D,
|
||||
0x16, 0xE1, 0x70, 0x17, 0x11, 0x73, 0x17, 0x41, 0x76, 0x17, 0x71, 0x79, 0x17, 0xA1, 0x7C, 0x17, 0xD1, 0x7F, 0x18, 0x01, 0x82, 0x18, 0x31, 0x85,
|
||||
0x18, 0x61, 0x88, 0x18, 0x91, 0x8B, 0x18, 0xC1, 0x8E, 0x18, 0xF1, 0x91, 0x19, 0x21, 0x94, 0x19, 0x51, 0x97, 0x19, 0x81, 0x9A, 0x19, 0xB1, 0x9D,
|
||||
0x19, 0xE1, 0xA0, 0x1A, 0x11, 0xA3, 0x1A, 0x41, 0xA6, 0x1A, 0x71, 0xA9, 0x1A, 0xA1, 0xAC, 0x1A, 0xD1, 0xAF, 0x1B, 0x01, 0xB2, 0x1B, 0x31, 0xB5,
|
||||
0x1B, 0x61, 0xB8, 0x1B, 0x91, 0xBB, 0x1B, 0xC1, 0xBE, 0x1B, 0xF1, 0xC1, 0x1C, 0x21, 0xC4, 0x1C, 0x51, 0xC7, 0x1C, 0x81, 0xCA, 0x1C, 0xB1, 0xCD,
|
||||
0x1C, 0xE1, 0xD0, 0x1D, 0x11, 0xD3, 0x1D, 0x41, 0xD6, 0x1D, 0x71, 0xD9, 0x1D, 0xA1, 0xDC, 0x1D, 0xD1, 0xDF, 0x1E, 0x01, 0xE1, 0x1E, 0x31, 0xE4,
|
||||
0x1E, 0x61, 0xE7, 0x1E, 0x91, 0xEA, 0x1E, 0xC1, 0xED, 0x1E, 0xF1, 0xF0, 0x1F, 0x21, 0xF3, 0x1F, 0x51, 0xF6, 0x1F, 0x81, 0xF9, 0x1F, 0xB1, 0xFC,
|
||||
0x1F, 0xE1, 0xFF, 0x20, 0x12, 0x02, 0x20, 0x42, 0x05, 0x20, 0x72, 0x08, 0x20, 0xA2, 0x0B, 0x20, 0xD2, 0x0E, 0x21, 0x02, 0x11, 0x21, 0x22, 0x14,
|
||||
0x21, 0x52, 0x17, 0x21, 0x82, 0x1A, 0x21, 0xB2, 0x1D, 0x21, 0xE2, 0x20, 0x22, 0x12, 0x23, 0x22, 0x42, 0x26, 0x22, 0x72, 0x29, 0x22, 0xA2, 0x2C,
|
||||
0x22, 0xD2, 0x2F, 0x23, 0x02, 0x31, 0x23, 0x32, 0x34, 0x23, 0x62, 0x37, 0x23, 0x92, 0x3A, 0x23, 0xC2, 0x3D, 0x23, 0xF2, 0x40, 0x24, 0x22, 0x43,
|
||||
0x24, 0x52, 0x46, 0x24, 0x82, 0x49, 0x24, 0xA2, 0x4C, 0x24, 0xD2, 0x4F, 0x25, 0x02, 0x52, 0x25, 0x32, 0x55, 0x25, 0x62, 0x58, 0x25, 0x92, 0x5B,
|
||||
0x25, 0xC2, 0x5D, 0x25, 0xF2, 0x60, 0x26, 0x22, 0x63, 0x26, 0x52, 0x66, 0x26, 0x82, 0x69, 0x26, 0xB2, 0x6C, 0x26, 0xE2, 0x6F, 0x27, 0x02, 0x72,
|
||||
0x27, 0x32, 0x75, 0x27, 0x62, 0x78, 0x27, 0x92, 0x7B, 0x27, 0xC2, 0x7E, 0x27, 0xF2, 0x80, 0x28, 0x22, 0x83, 0x28, 0x52, 0x86, 0x28, 0x82, 0x89,
|
||||
0x28, 0xB2, 0x8C, 0x28, 0xE2, 0x8F, 0x29, 0x02, 0x92, 0x29, 0x32, 0x95, 0x29, 0x62, 0x98, 0x29, 0x92, 0x9B, 0x29, 0xC2, 0x9D, 0x29, 0xF2, 0xA0,
|
||||
0x2A, 0x22, 0xA3, 0x2A, 0x52, 0xA6, 0x2A, 0x82, 0xA9, 0x2A, 0xA2, 0xAC, 0x2A, 0xD2, 0xAF, 0x2B, 0x02, 0xB2, 0x2B, 0x32, 0xB5, 0x2B, 0x62, 0xB7,
|
||||
0x2B, 0x92, 0xBA, 0x2B, 0xC2, 0xBD, 0x2B, 0xF2, 0xC0, 0x2C, 0x12, 0xC3, 0x2C, 0x42, 0xC6, 0x2C, 0x72, 0xC9, 0x2C, 0xA2, 0xCB, 0x2C, 0xD2, 0xCE,
|
||||
0x2D, 0x02, 0xD1, 0x2D, 0x32, 0xD4, 0x2D, 0x62, 0xD7, 0x2D, 0x82, 0xDA, 0x2D, 0xB2, 0xDD, 0x2D, 0xE2, 0xE0, 0x2E, 0x12, 0xE2, 0x2E, 0x42, 0xE5,
|
||||
0x2E, 0x72, 0xE8, 0x2E, 0x92, 0xEB, 0x2E, 0xC2, 0xEE, 0x2E, 0xF2, 0xF1, 0x2F, 0x22, 0xF3, 0x2F, 0x52, 0xF6, 0x2F, 0x82, 0xF9, 0x2F, 0xB2, 0xFC,
|
||||
0x2F, 0xD2, 0xFF, 0x30, 0x03, 0x02, 0x30, 0x33, 0x04, 0x30, 0x63, 0x07, 0x30, 0x93, 0x0A, 0x30, 0xC3, 0x0D, 0x30, 0xE3, 0x10, 0x31, 0x13, 0x13,
|
||||
0x31, 0x43, 0x15, 0x31, 0x73, 0x18, 0x31, 0xA3, 0x1B, 0x31, 0xC3, 0x1E, 0x31, 0xF3, 0x21, 0x32, 0x23, 0x23, 0x32, 0x53, 0x26, 0x32, 0x83, 0x29,
|
||||
0x32, 0xA3, 0x2C, 0x32, 0xD3, 0x2F, 0x33, 0x03, 0x31, 0x33, 0x33, 0x34, 0x33, 0x63, 0x37, 0x33, 0x83, 0x3A, 0x33, 0xB3, 0x3D, 0x33, 0xE3, 0x3F,
|
||||
0x34, 0x13, 0x42, 0x34, 0x43, 0x45, 0x34, 0x63, 0x48, 0x34, 0x93, 0x4B, 0x34, 0xC3, 0x4D, 0x34, 0xF3, 0x50, 0x35, 0x23, 0x53, 0x35, 0x43, 0x56,
|
||||
0x35, 0x73, 0x58, 0x35, 0xA3, 0x5B, 0x35, 0xD3, 0x5E, 0x35, 0xF3, 0x61, 0x36, 0x23, 0x64, 0x36, 0x53, 0x66, 0x36, 0x83, 0x69, 0x36, 0xA3, 0x6C,
|
||||
0x36, 0xD3, 0x6F, 0x37, 0x03, 0x71, 0x37, 0x33, 0x74, 0x37, 0x53, 0x77, 0x37, 0x83, 0x7A, 0x37, 0xB3, 0x7C, 0x37, 0xE3, 0x7F, 0x38, 0x03, 0x82,
|
||||
0x38, 0x33, 0x85, 0x38, 0x63, 0x87, 0x38, 0x93, 0x8A, 0x38, 0xB3, 0x8D, 0x38, 0xE3, 0x90, 0x39, 0x13, 0x92, 0x39, 0x43, 0x95, 0x39, 0x63, 0x98,
|
||||
0x39, 0x93, 0x9A, 0x39, 0xC3, 0x9D, 0x39, 0xF3, 0xA0, 0x3A, 0x13, 0xA3, 0x3A, 0x43, 0xA5, 0x3A, 0x73, 0xA8, 0x3A, 0x93, 0xAB, 0x3A, 0xC3, 0xAD,
|
||||
0x3A, 0xF3, 0xB0, 0x3B, 0x13, 0xB3, 0x3B, 0x43, 0xB6, 0x3B, 0x73, 0xB8, 0x3B, 0xA3, 0xBB, 0x3B, 0xC3, 0xBE, 0x3B, 0xF3, 0xC0, 0x3C, 0x23, 0xC3,
|
||||
0x3C, 0x43, 0xC6, 0x3C, 0x73, 0xC8, 0x3C, 0xA3, 0xCB, 0x3C, 0xC3, 0xCE, 0x3C, 0xF3, 0xD0, 0x3D, 0x23, 0xD3, 0x3D, 0x43, 0xD6, 0x3D, 0x73, 0xD8,
|
||||
0x3D, 0xA3, 0xDB, 0x3D, 0xC3, 0xDE, 0x3D, 0xF3, 0xE0, 0x3E, 0x23, 0xE3, 0x3E, 0x43, 0xE6, 0x3E, 0x73, 0xE8, 0x3E, 0xA3, 0xEB, 0x3E, 0xC3, 0xEE,
|
||||
0x3E, 0xF3, 0xF0, 0x3F, 0x23, 0xF3, 0x3F, 0x43, 0xF6, 0x3F, 0x73, 0xF8, 0x3F, 0xA3, 0xFB, 0x3F, 0xC3, 0xFE, 0x3F, 0xF4, 0x00, 0x40, 0x24, 0x03,
|
||||
0x40, 0x44, 0x06, 0x40, 0x74, 0x08, 0x40, 0x94, 0x0B, 0x40, 0xC4, 0x0D, 0x40, 0xF4, 0x10, 0x41, 0x14, 0x13, 0x41, 0x44, 0x15, 0x41, 0x74, 0x18,
|
||||
0x41, 0x94, 0x1A, 0x41, 0xC4, 0x1D, 0x41, 0xE4, 0x20, 0x42, 0x14, 0x22, 0x42, 0x44, 0x25, 0x42, 0x64, 0x28, 0x42, 0x94, 0x2A, 0x42, 0xB4, 0x2D,
|
||||
0x42, 0xE4, 0x2F, 0x43, 0x14, 0x32, 0x43, 0x34, 0x34, 0x43, 0x64, 0x37, 0x43, 0x84, 0x3A, 0x43, 0xB4, 0x3C, 0x43, 0xE4, 0x3F, 0x44, 0x04, 0x41,
|
||||
0x44, 0x34, 0x44, 0x44, 0x54, 0x47, 0x44, 0x84, 0x49, 0x44, 0xA4, 0x4C, 0x44, 0xD4, 0x4E, 0x44, 0xF4, 0x51, 0x45, 0x24, 0x53, 0x45, 0x54, 0x56,
|
||||
0x45, 0x74, 0x58, 0x45, 0xA4, 0x5B, 0x45, 0xC4, 0x5E, 0x45, 0xF4, 0x60, 0x46, 0x14, 0x63, 0x46, 0x44, 0x65, 0x46, 0x64, 0x68, 0x46, 0x94, 0x6A,
|
||||
0x46, 0xB4, 0x6D, 0x46, 0xE4, 0x6F, 0x47, 0x14, 0x72, 0x47, 0x34, 0x74, 0x47, 0x64, 0x77, 0x47, 0x84, 0x79, 0x47, 0xB4, 0x7C, 0x47, 0xD4, 0x7E,
|
||||
0x48, 0x04, 0x81, 0x48, 0x24, 0x83, 0x48, 0x54, 0x86, 0x48, 0x74, 0x88, 0x48, 0xA4, 0x8B, 0x48, 0xC4, 0x8D, 0x48, 0xF4, 0x90, 0x49, 0x14, 0x92,
|
||||
0x49, 0x44, 0x95, 0x49, 0x64, 0x97, 0x49, 0x94, 0x9A, 0x49, 0xB4, 0x9C, 0x49, 0xE4, 0x9F, 0x4A, 0x04, 0xA1, 0x4A, 0x24, 0xA4, 0x4A, 0x54, 0xA6,
|
||||
0x4A, 0x74, 0xA9, 0x4A, 0xA4, 0xAB, 0x4A, 0xC4, 0xAE, 0x4A, 0xF4, 0xB0, 0x4B, 0x14, 0xB2, 0x4B, 0x44, 0xB5, 0x4B, 0x64, 0xB7, 0x4B, 0x94, 0xBA,
|
||||
0x4B, 0xB4, 0xBC, 0x4B, 0xD4, 0xBF, 0x4C, 0x04, 0xC1, 0x4C, 0x24, 0xC4, 0x4C, 0x54, 0xC6, 0x4C, 0x74, 0xC8, 0x4C, 0xA4, 0xCB, 0x4C, 0xC4, 0xCD,
|
||||
0x4C, 0xE4, 0xD0, 0x4D, 0x14, 0xD2, 0x4D, 0x34, 0xD5, 0x4D, 0x64, 0xD7, 0x4D, 0x84, 0xD9, 0x4D, 0xB4, 0xDC, 0x4D, 0xD4, 0xDE, 0x4D, 0xF4, 0xE1,
|
||||
0x4E, 0x24, 0xE3, 0x4E, 0x44, 0xE5, 0x4E, 0x74, 0xE8, 0x4E, 0x94, 0xEA, 0x4E, 0xB4, 0xEC, 0x4E, 0xE4, 0xEF, 0x4F, 0x04, 0xF1, 0x4F, 0x24, 0xF4,
|
||||
0x4F, 0x54, 0xF6, 0x4F, 0x74, 0xF8, 0x4F, 0xA4, 0xFB, 0x4F, 0xC4, 0xFD, 0x4F, 0xE4, 0xFF, 0x50, 0x15, 0x02, 0x50, 0x35, 0x04, 0x50, 0x55, 0x06,
|
||||
0x50, 0x85, 0x09, 0x50, 0xA5, 0x0B, 0x50, 0xC5, 0x0E, 0x50, 0xF5, 0x10, 0x51, 0x15, 0x12, 0x51, 0x35, 0x15, 0x51, 0x65, 0x17, 0x51, 0x85, 0x19,
|
||||
0x51, 0xA5, 0x1C, 0x51, 0xD5, 0x1E, 0x51, 0xF5, 0x20, 0x52, 0x15, 0x22, 0x52, 0x45, 0x25, 0x52, 0x65, 0x27, 0x52, 0x85, 0x29, 0x52, 0xB5, 0x2C,
|
||||
0x52, 0xD5, 0x2E, 0x52, 0xF5, 0x30, 0x53, 0x15, 0x33, 0x53, 0x45, 0x35, 0x53, 0x65, 0x37, 0x53, 0x85, 0x39, 0x53, 0xB5, 0x3C, 0x53, 0xD5, 0x3E,
|
||||
0x53, 0xF5, 0x40, 0x54, 0x15, 0x43, 0x54, 0x45, 0x45, 0x54, 0x65, 0x47, 0x54, 0x85, 0x49, 0x54, 0xA5, 0x4C, 0x54, 0xD5, 0x4E, 0x54, 0xF5, 0x50,
|
||||
0x55, 0x15, 0x52, 0x55, 0x35, 0x55, 0x55, 0x65, 0x57, 0x55, 0x85, 0x59, 0x55, 0xA5, 0x5B, 0x55, 0xC5, 0x5E, 0x55, 0xF5, 0x60, 0x56, 0x15, 0x62,
|
||||
0x56, 0x35, 0x64, 0x56, 0x55, 0x66, 0x56, 0x85, 0x69, 0x56, 0xA5, 0x6B, 0x56, 0xC5, 0x6D, 0x56, 0xE5, 0x6F, 0x57, 0x05, 0x71, 0x57, 0x35, 0x74,
|
||||
0x57, 0x55, 0x76, 0x57, 0x75, 0x78, 0x57, 0x95, 0x7A, 0x57, 0xB5, 0x7C, 0x57, 0xE5, 0x7F, 0x58, 0x05, 0x81, 0x58, 0x25, 0x83, 0x58, 0x45, 0x85,
|
||||
0x58, 0x65, 0x87, 0x58, 0x85, 0x89, 0x58, 0xB5, 0x8C, 0x58, 0xD5, 0x8E, 0x58, 0xF5, 0x90, 0x59, 0x15, 0x92, 0x59, 0x35, 0x94, 0x59, 0x55, 0x96,
|
||||
0x59, 0x75, 0x99, 0x59, 0xA5, 0x9B, 0x59, 0xC5, 0x9D, 0x59, 0xE5, 0x9F, 0x5A, 0x05, 0xA1, 0x5A, 0x25, 0xA3, 0x5A, 0x45, 0xA5, 0x5A, 0x65, 0xA7,
|
||||
0x5A, 0x85, 0xAA, 0x5A, 0xB5, 0xAC, 0x5A, 0xD5, 0xAE, 0x5A, 0xF5, 0xB0, 0x5B, 0x15, 0xB2, 0x5B, 0x35, 0xB4, 0x5B, 0x55, 0xB6, 0x5B, 0x75, 0xB8,
|
||||
0x5B, 0x95, 0xBA, 0x5B, 0xB5, 0xBC, 0x5B, 0xD5, 0xBF, 0x5C, 0x05, 0xC1, 0x5C, 0x25, 0xC3, 0x5C, 0x45, 0xC5, 0x5C, 0x65, 0xC7, 0x5C, 0x85, 0xC9,
|
||||
0x5C, 0xA5, 0xCB, 0x5C, 0xC5, 0xCD, 0x5C, 0xE5, 0xCF, 0x5D, 0x05, 0xD1, 0x5D, 0x25, 0xD3, 0x5D, 0x45, 0xD5, 0x5D, 0x65, 0xD7, 0x5D, 0x85, 0xD9,
|
||||
0x5D, 0xA5, 0xDB, 0x5D, 0xC5, 0xDD, 0x5D, 0xE5, 0xDF, 0x5E, 0x05, 0xE1, 0x5E, 0x25, 0xE3, 0x5E, 0x45, 0xE5, 0x5E, 0x65, 0xE7, 0x5E, 0x85, 0xE9,
|
||||
0x5E, 0xA5, 0xEB, 0x5E, 0xC5, 0xED, 0x5E, 0xE5, 0xEF, 0x5F, 0x05, 0xF1, 0x5F, 0x25, 0xF3, 0x5F, 0x45, 0xF5, 0x5F, 0x65, 0xF7, 0x5F, 0x85, 0xF9,
|
||||
0x5F, 0xA5, 0xFB, 0x5F, 0xC5, 0xFD, 0x5F, 0xE5, 0xFF, 0x60, 0x06, 0x01, 0x60, 0x26, 0x03, 0x60, 0x46, 0x05, 0x60, 0x66, 0x07, 0x60, 0x86, 0x09,
|
||||
0x60, 0xA6, 0x0B, 0x60, 0xC6, 0x0D, 0x60, 0xE6, 0x0F, 0x61, 0x06, 0x11, 0x61, 0x26, 0x13, 0x61, 0x46, 0x15, 0x61, 0x66, 0x17, 0x61, 0x86, 0x19,
|
||||
0x61, 0x96, 0x1A, 0x61, 0xB6, 0x1C, 0x61, 0xD6, 0x1E, 0x61, 0xF6, 0x20, 0x62, 0x16, 0x22, 0x62, 0x36, 0x24, 0x62, 0x56, 0x26, 0x62, 0x76, 0x28,
|
||||
0x62, 0x96, 0x2A, 0x62, 0xB6, 0x2C, 0x62, 0xC6, 0x2D, 0x62, 0xE6, 0x2F, 0x63, 0x06, 0x31, 0x63, 0x26, 0x33, 0x63, 0x46, 0x35, 0x63, 0x66, 0x37,
|
||||
0x63, 0x86, 0x39, 0x63, 0xA6, 0x3A, 0x63, 0xB6, 0x3C, 0x63, 0xD6, 0x3E, 0x63, 0xF6, 0x40, 0x64, 0x16, 0x42, 0x64, 0x36, 0x44, 0x64, 0x56, 0x46,
|
||||
0x64, 0x66, 0x47, 0x64, 0x86, 0x49, 0x64, 0xA6, 0x4B, 0x64, 0xC6, 0x4D, 0x64, 0xE6, 0x4F, 0x65, 0x06, 0x50, 0x65, 0x16, 0x52, 0x65, 0x36, 0x54,
|
||||
0x65, 0x56, 0x56, 0x65, 0x76, 0x58, 0x65, 0x96, 0x59, 0x65, 0xA6, 0x5B, 0x65, 0xC6, 0x5D, 0x65, 0xE6, 0x5F, 0x66, 0x06, 0x61, 0x66, 0x16, 0x62,
|
||||
0x66, 0x36, 0x64, 0x66, 0x56, 0x66, 0x66, 0x76, 0x68, 0x66, 0x86, 0x69, 0x66, 0xA6, 0x6B, 0x66, 0xC6, 0x6D, 0x66, 0xE6, 0x6F, 0x66, 0xF6, 0x70,
|
||||
0x67, 0x16, 0x72, 0x67, 0x36, 0x74, 0x67, 0x56, 0x76, 0x67, 0x66, 0x77, 0x67, 0x86, 0x79, 0x67, 0xA6, 0x7B, 0x67, 0xC6, 0x7C, 0x67, 0xD6, 0x7E,
|
||||
0x67, 0xF6, 0x80, 0x68, 0x16, 0x81, 0x68, 0x26, 0x83, 0x68, 0x46, 0x85, 0x68, 0x66, 0x87, 0x68, 0x76, 0x88, 0x68, 0x96, 0x8A, 0x68, 0xB6, 0x8C,
|
||||
0x68, 0xC6, 0x8D, 0x68, 0xE6, 0x8F, 0x69, 0x06, 0x91, 0x69, 0x16, 0x92, 0x69, 0x36, 0x94, 0x69, 0x56, 0x96, 0x69, 0x66, 0x97, 0x69, 0x86, 0x99,
|
||||
0x69, 0xA6, 0x9B, 0x69, 0xB6, 0x9C, 0x69, 0xD6, 0x9E, 0x69, 0xF6, 0x9F, 0x6A, 0x06, 0xA1, 0x6A, 0x26, 0xA3, 0x6A, 0x36, 0xA4, 0x6A, 0x56, 0xA6,
|
||||
0x6A, 0x76, 0xA8, 0x6A, 0x86, 0xA9, 0x6A, 0xA6, 0xAB, 0x6A, 0xC6, 0xAC, 0x6A, 0xD6, 0xAE, 0x6A, 0xF6, 0xB0, 0x6B, 0x06, 0xB1, 0x6B, 0x26, 0xB3,
|
||||
0x6B, 0x36, 0xB4, 0x6B, 0x56, 0xB6, 0x6B, 0x76, 0xB7, 0x6B, 0x86, 0xB9, 0x6B, 0xA6, 0xBB, 0x6B, 0xB6, 0xBC, 0x6B, 0xD6, 0xBE, 0x6B, 0xE6, 0xBF,
|
||||
0x6C, 0x06, 0xC1, 0x6C, 0x16, 0xC2, 0x6C, 0x36, 0xC4, 0x6C, 0x56, 0xC5, 0x6C, 0x66, 0xC7, 0x6C, 0x86, 0xC8, 0x6C, 0x96, 0xCA, 0x6C, 0xB6, 0xCB,
|
||||
0x6C, 0xC6, 0xCD, 0x6C, 0xE6, 0xCE, 0x6C, 0xF6, 0xD0, 0x6D, 0x16, 0xD1, 0x6D, 0x26, 0xD3, 0x6D, 0x46, 0xD4, 0x6D, 0x56, 0xD6, 0x6D, 0x76, 0xD7,
|
||||
0x6D, 0x86, 0xD9, 0x6D, 0xA6, 0xDA, 0x6D, 0xB6, 0xDC, 0x6D, 0xD6, 0xDD, 0x6D, 0xE6, 0xDF, 0x6D, 0xF6, 0xE0, 0x6E, 0x16, 0xE2, 0x6E, 0x26, 0xE3,
|
||||
0x6E, 0x46, 0xE5, 0x6E, 0x56, 0xE6, 0x6E, 0x76, 0xE7, 0x6E, 0x86, 0xE9, 0x6E, 0xA6, 0xEA, 0x6E, 0xB6, 0xEC, 0x6E, 0xC6, 0xED, 0x6E, 0xE6, 0xEF,
|
||||
0x6E, 0xF6, 0xF0, 0x6F, 0x16, 0xF1, 0x6F, 0x26, 0xF3, 0x6F, 0x36, 0xF4, 0x6F, 0x56, 0xF6, 0x6F, 0x66, 0xF7, 0x6F, 0x86, 0xF8, 0x6F, 0x96, 0xFA,
|
||||
0x6F, 0xA6, 0xFB, 0x6F, 0xC6, 0xFD, 0x6F, 0xD6, 0xFE, 0x6F, 0xF6, 0xFF, 0x70, 0x07, 0x01, 0x70, 0x17, 0x02, 0x70, 0x37, 0x03, 0x70, 0x47, 0x05,
|
||||
0x70, 0x57, 0x06, 0x70, 0x77, 0x07, 0x70, 0x87, 0x09, 0x70, 0x97, 0x0A, 0x70, 0xB7, 0x0B, 0x70, 0xC7, 0x0D, 0x70, 0xD7, 0x0E, 0x70, 0xF7, 0x0F,
|
||||
0x71, 0x07, 0x11, 0x71, 0x17, 0x12, 0x71, 0x37, 0x13, 0x71, 0x47, 0x15, 0x71, 0x57, 0x16, 0x71, 0x67, 0x17, 0x71, 0x87, 0x18, 0x71, 0x97, 0x1A,
|
||||
0x71, 0xA7, 0x1B, 0x71, 0xC7, 0x1C, 0x71, 0xD7, 0x1E, 0x71, 0xE7, 0x1F, 0x71, 0xF7, 0x20, 0x72, 0x17, 0x21, 0x72, 0x27, 0x23, 0x72, 0x37, 0x24,
|
||||
0x72, 0x47, 0x25, 0x72, 0x67, 0x26, 0x72, 0x77, 0x28, 0x72, 0x87, 0x29, 0x72, 0x97, 0x2A, 0x72, 0xB7, 0x2B, 0x72, 0xC7, 0x2C, 0x72, 0xD7, 0x2E,
|
||||
0x72, 0xE7, 0x2F, 0x72, 0xF7, 0x30, 0x73, 0x17, 0x31, 0x73, 0x27, 0x32, 0x73, 0x37, 0x34, 0x73, 0x47, 0x35, 0x73, 0x57, 0x36, 0x73, 0x77, 0x37,
|
||||
0x73, 0x87, 0x38, 0x73, 0x97, 0x3A, 0x73, 0xA7, 0x3B, 0x73, 0xB7, 0x3C, 0x73, 0xC7, 0x3D, 0x73, 0xE7, 0x3E, 0x73, 0xF7, 0x3F, 0x74, 0x07, 0x40,
|
||||
0x74, 0x17, 0x42, 0x74, 0x27, 0x43, 0x74, 0x37, 0x44, 0x74, 0x47, 0x45, 0x74, 0x67, 0x46, 0x74, 0x77, 0x47, 0x74, 0x87, 0x48, 0x74, 0x97, 0x49,
|
||||
0x74, 0xA7, 0x4B, 0x74, 0xB7, 0x4C, 0x74, 0xC7, 0x4D, 0x74, 0xD7, 0x4E, 0x74, 0xE7, 0x4F, 0x74, 0xF7, 0x50, 0x75, 0x17, 0x51, 0x75, 0x27, 0x52,
|
||||
0x75, 0x37, 0x53, 0x75, 0x47, 0x54, 0x75, 0x57, 0x55, 0x75, 0x67, 0x56, 0x75, 0x77, 0x57, 0x75, 0x87, 0x58, 0x75, 0x97, 0x5A, 0x75, 0xA7, 0x5B,
|
||||
0x75, 0xB7, 0x5C, 0x75, 0xC7, 0x5D, 0x75, 0xD7, 0x5E, 0x75, 0xE7, 0x5F, 0x75, 0xF7, 0x60, 0x76, 0x07, 0x61, 0x76, 0x17, 0x62, 0x76, 0x27, 0x63,
|
||||
0x76, 0x37, 0x64, 0x76, 0x47, 0x65, 0x76, 0x57, 0x66, 0x76, 0x67, 0x67, 0x76, 0x77, 0x68, 0x76, 0x87, 0x69, 0x76, 0x97, 0x6A, 0x76, 0xA7, 0x6B,
|
||||
0x76, 0xB7, 0x6C, 0x76, 0xC7, 0x6C, 0x76, 0xD7, 0x6D, 0x76, 0xE7, 0x6E, 0x76, 0xF7, 0x6F, 0x77, 0x07, 0x70, 0x77, 0x17, 0x71, 0x77, 0x27, 0x72,
|
||||
0x77, 0x37, 0x73, 0x77, 0x47, 0x74, 0x77, 0x47, 0x75, 0x77, 0x57, 0x76, 0x77, 0x67, 0x77, 0x77, 0x77, 0x78, 0x77, 0x87, 0x79, 0x77, 0x97, 0x79,
|
||||
0x77, 0xA7, 0x7A, 0x77, 0xB7, 0x7B, 0x77, 0xC7, 0x7C, 0x77, 0xD7, 0x7D, 0x77, 0xD7, 0x7E, 0x77, 0xE7, 0x7F, 0x77, 0xF7, 0x80, 0x78, 0x07, 0x80,
|
||||
0x78, 0x17, 0x81, 0x78, 0x27, 0x82, 0x78, 0x37, 0x83, 0x78, 0x37, 0x84, 0x78, 0x47, 0x85, 0x78, 0x57, 0x85, 0x78, 0x67, 0x86, 0x78, 0x77, 0x87,
|
||||
0x78, 0x87, 0x88, 0x78, 0x87, 0x89, 0x78, 0x97, 0x8A, 0x78, 0xA7, 0x8A, 0x78, 0xB7, 0x8B, 0x78, 0xC7, 0x8C, 0x78, 0xC7, 0x8D, 0x78, 0xD7, 0x8E,
|
||||
0x78, 0xE7, 0x8E, 0x78, 0xF7, 0x8F, 0x79, 0x07, 0x90, 0x79, 0x07, 0x91, 0x79, 0x17, 0x91, 0x79, 0x27, 0x92, 0x79, 0x37, 0x93, 0x79, 0x37, 0x94,
|
||||
0x79, 0x47, 0x94, 0x79, 0x57, 0x95, 0x79, 0x67, 0x96, 0x79, 0x67, 0x97, 0x79, 0x77, 0x97, 0x79, 0x87, 0x98, 0x79, 0x87, 0x99, 0x79, 0x97, 0x9A,
|
||||
0x79, 0xA7, 0x9A, 0x79, 0xB7, 0x9B, 0x79, 0xB7, 0x9C, 0x79, 0xC7, 0x9C, 0x79, 0xD7, 0x9D, 0x79, 0xD7, 0x9E, 0x79, 0xE7, 0x9E, 0x79, 0xF7, 0x9F,
|
||||
0x79, 0xF7, 0xA0, 0x7A, 0x07, 0xA0, 0x7A, 0x17, 0xA1, 0x7A, 0x17, 0xA2, 0x7A, 0x27, 0xA2, 0x7A, 0x37, 0xA3, 0x7A, 0x37, 0xA4, 0x7A, 0x47, 0xA4,
|
||||
0x7A, 0x57, 0xA5, 0x7A, 0x57, 0xA6, 0x7A, 0x67, 0xA6, 0x7A, 0x77, 0xA7, 0x7A, 0x77, 0xA7, 0x7A, 0x87, 0xA8, 0x7A, 0x87, 0xA9, 0x7A, 0x97, 0xA9,
|
||||
0x7A, 0xA7, 0xAA, 0x7A, 0xA7, 0xAA, 0x7A, 0xB7, 0xAB, 0x7A, 0xB7, 0xAC, 0x7A, 0xC7, 0xAC, 0x7A, 0xD7, 0xAD, 0x7A, 0xD7, 0xAD, 0x7A, 0xE7, 0xAE,
|
||||
0x7A, 0xE7, 0xAE, 0x7A, 0xF7, 0xAF, 0x7A, 0xF7, 0xB0, 0x7B, 0x07, 0xB0, 0x7B, 0x07, 0xB1, 0x7B, 0x17, 0xB1, 0x7B, 0x17, 0xB2, 0x7B, 0x27, 0xB2,
|
||||
0x7B, 0x37, 0xB3, 0x7B, 0x37, 0xB3, 0x7B, 0x47, 0xB4, 0x7B, 0x47, 0xB4, 0x7B, 0x57, 0xB5, 0x7B, 0x57, 0xB5, 0x7B, 0x67, 0xB6, 0x7B, 0x67, 0xB6,
|
||||
0x7B, 0x77, 0xB7, 0x7B, 0x77, 0xB7, 0x7B, 0x87, 0xB8, 0x7B, 0x87, 0xB8, 0x7B, 0x97, 0xB9, 0x7B, 0x97, 0xB9, 0x7B, 0x97, 0xBA, 0x7B, 0xA7, 0xBA,
|
||||
0x7B, 0xA7, 0xBB, 0x7B, 0xB7, 0xBB, 0x7B, 0xB7, 0xBB, 0x7B, 0xC7, 0xBC, 0x7B, 0xC7, 0xBC, 0x7B, 0xD7, 0xBD, 0x7B, 0xD7, 0xBD, 0x7B, 0xD7, 0xBE,
|
||||
0x7B, 0xE7, 0xBE, 0x7B, 0xE7, 0xBE, 0x7B, 0xF7, 0xBF, 0x7B, 0xF7, 0xBF, 0x7B, 0xF7, 0xC0, 0x7C, 0x07, 0xC0, 0x7C, 0x07, 0xC0, 0x7C, 0x17, 0xC1,
|
||||
0x7C, 0x17, 0xC1, 0x7C, 0x17, 0xC2, 0x7C, 0x27, 0xC2, 0x7C, 0x27, 0xC2, 0x7C, 0x27, 0xC3, 0x7C, 0x37, 0xC3, 0x7C, 0x37, 0xC3, 0x7C, 0x37, 0xC4,
|
||||
0x7C, 0x47, 0xC4, 0x7C, 0x47, 0xC4, 0x7C, 0x47, 0xC5, 0x7C, 0x57, 0xC5, 0x7C, 0x57, 0xC5, 0x7C, 0x57, 0xC6, 0x7C, 0x67, 0xC6, 0x7C, 0x67, 0xC6,
|
||||
0x7C, 0x67, 0xC7, 0x7C, 0x77, 0xC7, 0x7C, 0x77, 0xC7, 0x7C, 0x77, 0xC7, 0x7C, 0x87, 0xC8, 0x7C, 0x87, 0xC8, 0x7C, 0x87, 0xC8, 0x7C, 0x87, 0xC8,
|
||||
0x7C, 0x97, 0xC9, 0x7C, 0x97, 0xC9, 0x7C, 0x97, 0xC9, 0x7C, 0x97, 0xCA, 0x7C, 0xA7, 0xCA, 0x7C, 0xA7, 0xCA, 0x7C, 0xA7, 0xCA, 0x7C, 0xA7, 0xCA,
|
||||
0x7C, 0xB7, 0xCB, 0x7C, 0xB7, 0xCB, 0x7C, 0xB7, 0xCB, 0x7C, 0xB7, 0xCB, 0x7C, 0xB7, 0xCC, 0x7C, 0xC7, 0xCC, 0x7C, 0xC7, 0xCC, 0x7C, 0xC7, 0xCC,
|
||||
0x7C, 0xC7, 0xCC, 0x7C, 0xC7, 0xCD, 0x7C, 0xD7, 0xCD, 0x7C, 0xD7, 0xCD, 0x7C, 0xD7, 0xCD, 0x7C, 0xD7, 0xCD, 0x7C, 0xD7, 0xCD, 0x7C, 0xD7, 0xCE,
|
||||
0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xE7, 0xCE, 0x7C, 0xF7, 0xCF,
|
||||
0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xCF,
|
||||
0x7C, 0xF7, 0xCF, 0x7C, 0xF7, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0,
|
||||
0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0, 0x7D, 0x07, 0xD0,
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
|
||||
#define DAC_INTERNAL
|
||||
#include "_dac_internal.h"
|
||||
|
||||
/** Allocate data structure and set defaults */
|
||||
error_t UDAC_preInit(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
|
||||
if (priv == NULL) return E_OUT_OF_MEM;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
priv->cfg.ch[i].buffered = true;
|
||||
priv->cfg.ch[i].enable = true;
|
||||
priv->cfg.ch[i].noise_level = 2;
|
||||
priv->cfg.ch[i].noise_type = NOISE_NONE;
|
||||
|
||||
priv->ch[i].waveform = UDAC_WAVE_DC;
|
||||
priv->ch[i].dc_level = 2047;
|
||||
|
||||
priv->ch[i].rectangle_ontime = 4096; // half
|
||||
priv->ch[i].rectangle_high = 4095;
|
||||
priv->ch[i].rectangle_low = 0;
|
||||
|
||||
priv->ch[i].counter = 0;
|
||||
priv->ch[i].increment = 0; // stopped
|
||||
priv->ch[i].phase = 0;
|
||||
}
|
||||
|
||||
UDAC_SetFreq(unit, 0, 1000);
|
||||
UDAC_SetFreq(unit, 1, 1000);
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/** Finalize unit set-up */
|
||||
error_t UDAC_init(Unit *unit)
|
||||
{
|
||||
bool suc = true;
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
// copy noise config
|
||||
priv->ch[0].noise_type = priv->cfg.ch[0].noise_type;
|
||||
priv->ch[0].noise_level = priv->cfg.ch[0].noise_level;
|
||||
|
||||
priv->ch[1].noise_type = priv->cfg.ch[1].noise_type;
|
||||
priv->ch[1].noise_level = priv->cfg.ch[1].noise_level;
|
||||
|
||||
// this may change for different devices
|
||||
const Resource r_ch1 = R_PA4;
|
||||
const Resource r_ch2 = R_PA5;
|
||||
|
||||
TRY(rsc_claim(unit, R_TIM6));
|
||||
priv->TIMx = TIM6;
|
||||
|
||||
const bool e1 = priv->cfg.ch[0].enable;
|
||||
const bool e2 = priv->cfg.ch[1].enable;
|
||||
|
||||
if (e1) {
|
||||
TRY(rsc_claim(unit, r_ch1));
|
||||
}
|
||||
|
||||
if (e2) {
|
||||
TRY(rsc_claim(unit, r_ch2));
|
||||
}
|
||||
|
||||
TRY(rsc_claim(unit, R_DAC1));
|
||||
|
||||
// ensure the peripheral is clean (this may be redundant)
|
||||
__HAL_RCC_DAC1_FORCE_RESET();
|
||||
__HAL_RCC_DAC1_RELEASE_RESET();
|
||||
|
||||
hw_periph_clock_enable(DAC1);
|
||||
hw_periph_clock_enable(priv->TIMx);
|
||||
|
||||
GPIO_TypeDef *port;
|
||||
uint32_t ll;
|
||||
if (e1) {
|
||||
assert_param(hw_pinrsc2ll(r_ch1, &port, &ll));
|
||||
LL_GPIO_SetPinMode(port, ll, LL_GPIO_MODE_ANALOG);
|
||||
}
|
||||
if (e2) {
|
||||
assert_param(hw_pinrsc2ll(r_ch1, &port, &ll));
|
||||
LL_GPIO_SetPinMode(port, ll, LL_GPIO_MODE_ANALOG);
|
||||
}
|
||||
|
||||
uint16_t presc = 1;
|
||||
|
||||
// presets... TODO pick the highest useable one (or find a new one)
|
||||
#if UDAC_TIM_FREQ_DIVIDER == 1
|
||||
uint32_t count = PLAT_AHB_MHZ;
|
||||
#elif UDAC_TIM_FREQ_DIVIDER == 2
|
||||
uint32_t count = PLAT_AHB_MHZ * 2;
|
||||
#elif UDAC_TIM_FREQ_DIVIDER == 4
|
||||
uint32_t count = PLAT_AHB_MHZ * 4;
|
||||
#elif UDAC_TIM_FREQ_DIVIDER == 8
|
||||
uint32_t count = PLAT_AHB_MHZ * 8;
|
||||
#else
|
||||
#error "bad freq"
|
||||
#endif
|
||||
|
||||
// dbg("Presc %d, count %d", (int)presc, (int)count);
|
||||
|
||||
LL_TIM_SetPrescaler(priv->TIMx, (uint32_t) (presc - 1));
|
||||
LL_TIM_SetAutoReload(priv->TIMx, count - 1);
|
||||
LL_TIM_EnableARRPreload(priv->TIMx);
|
||||
LL_TIM_GenerateEvent_UPDATE(priv->TIMx);
|
||||
|
||||
irqd_attach(priv->TIMx, UDAC_HandleIT, unit);
|
||||
LL_TIM_EnableIT_UPDATE(priv->TIMx);
|
||||
|
||||
UDAC_Reconfigure(unit); // works with the timer - it should be inited already
|
||||
|
||||
// do not enbale counter initially - no need
|
||||
// LL_TIM_EnableCounter(priv->TIMx);
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/** Tear down the unit */
|
||||
void UDAC_deInit(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
// de-init peripherals
|
||||
if (unit->status == E_SUCCESS ) {
|
||||
LL_DAC_DeInit(DAC);
|
||||
LL_TIM_DisableCounter(priv->TIMx);
|
||||
|
||||
hw_periph_clock_disable(DAC1);
|
||||
hw_periph_clock_disable(priv->TIMx);
|
||||
|
||||
irqd_detach(priv->TIMx, UDAC_HandleIT);
|
||||
}
|
||||
|
||||
// Release all resources, deinit pins
|
||||
rsc_teardown(unit);
|
||||
|
||||
// Free memory
|
||||
free_ck(unit->data);
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#ifndef GEX_F072_DAC_INTERNAL_H
|
||||
#define GEX_F072_DAC_INTERNAL_H
|
||||
|
||||
#ifndef DAC_INTERNAL
|
||||
#error bad include!
|
||||
#endif
|
||||
|
||||
#include "unit_base.h"
|
||||
|
||||
enum UDAC_Noise {
|
||||
NOISE_NONE = 0b00, // 0
|
||||
NOISE_WHITE = 0b01, // 1
|
||||
NOISE_TRIANGLE = 0b10, // 2
|
||||
};
|
||||
|
||||
enum UDAC_Waveform {
|
||||
UDAC_WAVE_DC,
|
||||
UDAC_WAVE_SINE,
|
||||
UDAC_WAVE_TRIANGLE,
|
||||
UDAC_WAVE_SAWTOOTH_UP,
|
||||
UDAC_WAVE_SAWTOOTH_DOWN,
|
||||
UDAC_WAVE_RECTANGLE,
|
||||
};
|
||||
|
||||
struct udac_channel_cfg {
|
||||
bool enable;
|
||||
bool buffered;
|
||||
enum UDAC_Noise noise_type;
|
||||
uint8_t noise_level; // 0-11
|
||||
};
|
||||
|
||||
// 0 - 1 MHz, 2-500k, 4-250k, 8-125k
|
||||
#define UDAC_TIM_FREQ_DIVIDER 8
|
||||
|
||||
#define UDAC_INDEX_WIDTH 13 // corresponds to 8192 places
|
||||
#define UDAC_INDEX_SHIFT (32 - UDAC_INDEX_WIDTH)
|
||||
#define UDAC_MAX_INDEX ((1 << UDAC_INDEX_WIDTH) - 1)
|
||||
#define UDAC_VALUE_COUNT (1 << UDAC_INDEX_WIDTH)
|
||||
|
||||
extern const uint8_t LUT_sine_8192_quad_packed[];
|
||||
|
||||
struct udac_channel_live {
|
||||
enum UDAC_Noise noise_type;
|
||||
uint8_t noise_level; // 0-11
|
||||
enum UDAC_Waveform waveform;
|
||||
|
||||
uint16_t rectangle_ontime; // for rectangle wave, 0-8191
|
||||
uint16_t rectangle_high;
|
||||
uint16_t rectangle_low;
|
||||
uint16_t dc_level; // for DC wave
|
||||
|
||||
uint32_t counter;
|
||||
uint32_t increment;
|
||||
|
||||
// last set phase if the frequencies are the same
|
||||
// - can be used for live frequency changes without reset (meaningful only with matching increment values)
|
||||
uint16_t phase;
|
||||
uint16_t last_index;
|
||||
uint16_t last_value;
|
||||
};
|
||||
|
||||
/** Private data structure */
|
||||
struct priv {
|
||||
// settings
|
||||
struct {
|
||||
struct udac_channel_cfg ch[2];
|
||||
} cfg;
|
||||
|
||||
// internal state
|
||||
struct udac_channel_live ch[2];
|
||||
TIM_TypeDef *TIMx; // timer used for the DDS function
|
||||
};
|
||||
|
||||
/** Allocate data structure and set defaults */
|
||||
error_t UDAC_preInit(Unit *unit);
|
||||
|
||||
/** Load from a binary buffer stored in Flash */
|
||||
void UDAC_loadBinary(Unit *unit, PayloadParser *pp);
|
||||
|
||||
/** Write to a binary buffer for storing in Flash */
|
||||
void UDAC_writeBinary(Unit *unit, PayloadBuilder *pb);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Parse a key-value pair from the INI file */
|
||||
error_t UDAC_loadIni(Unit *unit, const char *key, const char *value);
|
||||
|
||||
/** Generate INI file section for the unit */
|
||||
void UDAC_writeIni(Unit *unit, IniWriter *iw);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Finalize unit set-up */
|
||||
error_t UDAC_init(Unit *unit);
|
||||
|
||||
/** Tear down the unit */
|
||||
void UDAC_deInit(Unit *unit);
|
||||
|
||||
void UDAC_Reconfigure(Unit *unit);
|
||||
|
||||
void UDAC_HandleIT(void *arg);
|
||||
|
||||
error_t UDAC_SetFreq(Unit *unit, int channel, float freq);
|
||||
|
||||
void UDAC_ToggleTimerIfNeeded(Unit *unit);
|
||||
|
||||
#endif //GEX_F072_DAC_INTERNAL_H
|
||||
@@ -0,0 +1,131 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
|
||||
#define DAC_INTERNAL
|
||||
#include "_dac_internal.h"
|
||||
|
||||
/** Load from a binary buffer stored in Flash */
|
||||
void UDAC_loadBinary(Unit *unit, PayloadParser *pp)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
uint8_t version = pp_u8(pp);
|
||||
(void)version;
|
||||
|
||||
priv->cfg.ch[0].enable = pp_bool(pp);
|
||||
priv->cfg.ch[0].buffered = pp_bool(pp);
|
||||
priv->cfg.ch[0].noise_type = (enum UDAC_Noise) pp_u8(pp);
|
||||
priv->cfg.ch[0].noise_level = pp_u8(pp);
|
||||
|
||||
priv->cfg.ch[1].enable = pp_bool(pp);
|
||||
priv->cfg.ch[1].buffered = pp_bool(pp);
|
||||
priv->cfg.ch[1].noise_type = (enum UDAC_Noise) pp_u8(pp);
|
||||
priv->cfg.ch[1].noise_level = pp_u8(pp);
|
||||
}
|
||||
|
||||
/** Write to a binary buffer for storing in Flash */
|
||||
void UDAC_writeBinary(Unit *unit, PayloadBuilder *pb)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
pb_u8(pb, 0); // version
|
||||
|
||||
pb_bool(pb, priv->cfg.ch[0].enable);
|
||||
pb_bool(pb, priv->cfg.ch[0].buffered);
|
||||
pb_u8(pb, priv->cfg.ch[0].noise_type);
|
||||
pb_u8(pb, priv->cfg.ch[0].noise_level);
|
||||
|
||||
pb_bool(pb, priv->cfg.ch[1].enable);
|
||||
pb_bool(pb, priv->cfg.ch[1].buffered);
|
||||
pb_u8(pb, priv->cfg.ch[1].noise_type);
|
||||
pb_u8(pb, priv->cfg.ch[1].noise_level);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Parse a key-value pair from the INI file */
|
||||
error_t UDAC_loadIni(Unit *unit, const char *key, const char *value)
|
||||
{
|
||||
bool suc = true;
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
// Ch1
|
||||
if (streq(key, "ch1_enable")) {
|
||||
priv->cfg.ch[0].enable = cfg_bool_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "ch1_buff")) {
|
||||
priv->cfg.ch[0].buffered = cfg_bool_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "ch1_noise")) {
|
||||
priv->cfg.ch[0].noise_type =
|
||||
(enum UDAC_Noise) cfg_enum3_parse(value,
|
||||
"NONE", NOISE_NONE,
|
||||
"WHITE", NOISE_WHITE,
|
||||
"TRIANGLE", NOISE_TRIANGLE, &suc);
|
||||
}
|
||||
else if (streq(key, "ch1_noise-level")) {
|
||||
uint8_t x = cfg_u8_parse(value, &suc);
|
||||
if (x == 0) x = 1;
|
||||
if (x > 12) x = 12;
|
||||
priv->cfg.ch[0].noise_level = (uint8_t) (x - 1);
|
||||
}
|
||||
// Ch2
|
||||
else if (streq(key, "ch2_enable")) {
|
||||
priv->cfg.ch[1].enable = cfg_bool_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "ch2_buff")) {
|
||||
priv->cfg.ch[1].buffered = cfg_bool_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "ch2_noise")) {
|
||||
priv->cfg.ch[1].noise_type =
|
||||
(enum UDAC_Noise) cfg_enum3_parse(value,
|
||||
"NONE", NOISE_NONE,
|
||||
"WHITE", NOISE_WHITE,
|
||||
"TRIANGLE", NOISE_TRIANGLE, &suc);
|
||||
}
|
||||
else if (streq(key, "ch2_noise-level")) {
|
||||
uint8_t x = cfg_u8_parse(value, &suc);
|
||||
if (x == 0) x = 1;
|
||||
if (x > 12) x = 12;
|
||||
priv->cfg.ch[1].noise_level = (uint8_t) (x - 1);
|
||||
}
|
||||
// end
|
||||
else {
|
||||
return E_BAD_KEY;
|
||||
}
|
||||
|
||||
if (!suc) return E_BAD_VALUE;
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/** Generate INI file section for the unit */
|
||||
void UDAC_writeIni(Unit *unit, IniWriter *iw)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
iw_comment(iw, "Enabled channels (1:A4, 2:A5)");
|
||||
iw_entry_s(iw, "ch1_enable", str_yn(priv->cfg.ch[0].enable));
|
||||
iw_entry_s(iw, "ch2_enable", str_yn(priv->cfg.ch[1].enable));
|
||||
|
||||
iw_comment(iw, "Enable output buffer");
|
||||
iw_entry_s(iw, "ch1_buff", str_yn(priv->cfg.ch[0].buffered));
|
||||
iw_entry_s(iw, "ch2_buff", str_yn(priv->cfg.ch[1].buffered));
|
||||
|
||||
iw_comment(iw, "Superimposed noise type (NONE,WHITE,TRIANGLE) and nbr. of bits (1-12)");
|
||||
|
||||
iw_entry_s(iw, "ch1_noise", cfg_enum3_encode(priv->cfg.ch[0].noise_type,
|
||||
NOISE_NONE, "NONE",
|
||||
NOISE_WHITE, "WHITE",
|
||||
NOISE_TRIANGLE, "TRIANGLE"));
|
||||
iw_entry_d(iw, "ch1_noise-level", priv->cfg.ch[0].noise_level + 1);
|
||||
|
||||
iw_entry_s(iw, "ch2_noise", cfg_enum3_encode(priv->cfg.ch[1].noise_type,
|
||||
NOISE_NONE, "NONE",
|
||||
NOISE_WHITE, "WHITE",
|
||||
NOISE_TRIANGLE, "TRIANGLE"));
|
||||
iw_entry_d(iw, "ch2_noise-level", priv->cfg.ch[1].noise_level + 1);
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/25.
|
||||
//
|
||||
|
||||
#include "unit_base.h"
|
||||
#include "unit_dac.h"
|
||||
|
||||
#define DAC_INTERNAL
|
||||
#include "_dac_internal.h"
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Works OK up to about 20 kHz, could work faster with a faster interrupt
|
||||
// (may be possible with some optimizations / adjusting priorities...)
|
||||
|
||||
enum DacCmd_ {
|
||||
CMD_WAVE_DC = 0,
|
||||
CMD_WAVE_SINE = 1,
|
||||
CMD_WAVE_TRIANGLE = 2,
|
||||
CMD_WAVE_SAWTOOTH_UP = 3,
|
||||
CMD_WAVE_SAWTOOTH_DOWN = 4,
|
||||
CMD_WAVE_RECTANGLE = 5,
|
||||
|
||||
CMD_SYNC = 10,
|
||||
|
||||
CMD_SET_FREQUENCY = 20,
|
||||
CMD_SET_PHASE = 21,
|
||||
CMD_SET_DITHER = 22,
|
||||
};
|
||||
|
||||
/** Handle a request message */
|
||||
static error_t UDAC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
// Exceptions that aren't per-channel
|
||||
switch (command) {
|
||||
case CMD_SYNC:
|
||||
dbg("Sync");
|
||||
priv->ch[0].counter = priv->ch[0].phase << UDAC_INDEX_SHIFT;
|
||||
priv->ch[1].counter = priv->ch[1].phase << UDAC_INDEX_SHIFT;
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t channels = pp_u8(pp);
|
||||
|
||||
bool want_reinit = false;
|
||||
bool want_tog_timer = false;
|
||||
|
||||
// TODO move this stuff to the api file
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (channels & (1<<i)) {
|
||||
switch (command) {
|
||||
case CMD_SET_FREQUENCY:;
|
||||
float freq = pp_float(pp);
|
||||
TRY(UDAC_SetFreq(unit, i, freq));
|
||||
break;
|
||||
|
||||
case CMD_WAVE_DC:
|
||||
priv->ch[i].dc_level = pp_u16(pp);
|
||||
priv->ch[i].waveform = UDAC_WAVE_DC;
|
||||
want_tog_timer = true;
|
||||
break;
|
||||
|
||||
case CMD_WAVE_SINE:
|
||||
priv->ch[i].waveform = UDAC_WAVE_SINE;
|
||||
want_tog_timer = true;
|
||||
break;
|
||||
|
||||
case CMD_WAVE_TRIANGLE:
|
||||
priv->ch[i].waveform = UDAC_WAVE_TRIANGLE;
|
||||
want_tog_timer = true;
|
||||
break;
|
||||
|
||||
case CMD_WAVE_SAWTOOTH_UP:
|
||||
priv->ch[i].waveform = UDAC_WAVE_SAWTOOTH_UP;
|
||||
want_tog_timer = true;
|
||||
break;
|
||||
|
||||
case CMD_WAVE_SAWTOOTH_DOWN:
|
||||
priv->ch[i].waveform = UDAC_WAVE_SAWTOOTH_DOWN;
|
||||
want_tog_timer = true;
|
||||
break;
|
||||
|
||||
case CMD_WAVE_RECTANGLE:;
|
||||
uint16_t ontime = pp_u16(pp);
|
||||
uint16_t high = pp_u16(pp);
|
||||
uint16_t low = pp_u16(pp);
|
||||
|
||||
// use 0xFFFF to skip setting the value
|
||||
if (high < 4096) priv->ch[i].rectangle_high = high;
|
||||
if (low < 4096) priv->ch[i].rectangle_low = low;
|
||||
if (ontime <= UDAC_VALUE_COUNT) priv->ch[i].rectangle_ontime = ontime;
|
||||
|
||||
// dbg("Set rect hi %d, low %d", (int)priv->ch[i].rectangle_high, (int)priv->ch[i].rectangle_low);
|
||||
|
||||
priv->ch[i].waveform = UDAC_WAVE_RECTANGLE;
|
||||
want_tog_timer = true;
|
||||
break;
|
||||
|
||||
case CMD_SET_PHASE:;
|
||||
uint16_t ph = pp_u16(pp);
|
||||
uint32_t newphase = ph << UDAC_INDEX_SHIFT;
|
||||
uint32_t oldphase = priv->ch[i].phase << UDAC_INDEX_SHIFT;
|
||||
int32_t diff = newphase - oldphase;
|
||||
priv->ch[i].counter += diff;
|
||||
priv->ch[i].phase = ph;
|
||||
break;
|
||||
|
||||
case CMD_SET_DITHER:;
|
||||
uint8_t noisetype = pp_u8(pp); // 0-none, 1-random, 2-triangle
|
||||
uint8_t noisebits = pp_u8(pp);
|
||||
|
||||
// type 0xFF = not set
|
||||
if (noisetype <= 2) {
|
||||
priv->ch[i].noise_type = (enum UDAC_Noise) noisetype;
|
||||
}
|
||||
|
||||
// bits 0xFF = not set
|
||||
if (noisebits >= 1 && noisebits <= 12) {
|
||||
priv->ch[i].noise_level = (uint8_t) (noisebits - 1);
|
||||
}
|
||||
|
||||
// dbg("Ch %d: Dither type %d, level %d", i,
|
||||
// (int)priv->ch[i].noise_type,
|
||||
// (int)priv->ch[i].noise_level);
|
||||
|
||||
want_reinit = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
return E_UNKNOWN_COMMAND;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (want_reinit) {
|
||||
UDAC_Reconfigure(unit);
|
||||
}
|
||||
|
||||
if (want_tog_timer) {
|
||||
UDAC_ToggleTimerIfNeeded(unit);
|
||||
}
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Unit template */
|
||||
const UnitDriver UNIT_DAC = {
|
||||
.name = "DAC",
|
||||
.description = "Two-channel analog output with waveforms",
|
||||
// Settings
|
||||
.preInit = UDAC_preInit,
|
||||
.cfgLoadBinary = UDAC_loadBinary,
|
||||
.cfgWriteBinary = UDAC_writeBinary,
|
||||
.cfgLoadIni = UDAC_loadIni,
|
||||
.cfgWriteIni = UDAC_writeIni,
|
||||
// Init
|
||||
.init = UDAC_init,
|
||||
.deInit = UDAC_deInit,
|
||||
// Function
|
||||
.handleRequest = UDAC_handleRequest,
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/25.
|
||||
//
|
||||
// Digital input unit; single or multiple pin read access on one port (A-F)
|
||||
//
|
||||
|
||||
#ifndef U_DAC_H
|
||||
#define U_DAC_H
|
||||
|
||||
#include "unit.h"
|
||||
|
||||
extern const UnitDriver UNIT_DAC;
|
||||
|
||||
// UU_ prototypes
|
||||
|
||||
#endif //U_DAC_H
|
||||
@@ -92,24 +92,24 @@ void DIn_writeIni(Unit *unit, IniWriter *iw)
|
||||
iw_entry(iw, "port", "%c", priv->port_name);
|
||||
|
||||
iw_comment(iw, "Pins (comma separated, supports ranges)");
|
||||
iw_entry(iw, "pins", cfg_pinmask_encode(priv->pins, unit_tmp512, 0));
|
||||
iw_entry_s(iw, "pins", cfg_pinmask_encode(priv->pins, unit_tmp512, 0));
|
||||
|
||||
iw_comment(iw, "Pins with pull-up");
|
||||
iw_entry(iw, "pull-up", cfg_pinmask_encode(priv->pullup, unit_tmp512, 0));
|
||||
iw_entry_s(iw, "pull-up", cfg_pinmask_encode(priv->pullup, unit_tmp512, 0));
|
||||
|
||||
iw_comment(iw, "Pins with pull-down");
|
||||
iw_entry(iw, "pull-down", cfg_pinmask_encode(priv->pulldown, unit_tmp512, 0));
|
||||
iw_entry_s(iw, "pull-down", cfg_pinmask_encode(priv->pulldown, unit_tmp512, 0));
|
||||
|
||||
iw_cmt_newline(iw);
|
||||
iw_comment(iw, "Trigger pins activated by rising/falling edge");
|
||||
iw_entry(iw, "trig-rise", cfg_pinmask_encode(priv->trig_rise, unit_tmp512, 0));
|
||||
iw_entry(iw, "trig-fall", cfg_pinmask_encode(priv->trig_fall, unit_tmp512, 0));
|
||||
iw_entry_s(iw, "trig-rise", cfg_pinmask_encode(priv->trig_rise, unit_tmp512, 0));
|
||||
iw_entry_s(iw, "trig-fall", cfg_pinmask_encode(priv->trig_fall, unit_tmp512, 0));
|
||||
|
||||
iw_comment(iw, "Trigger pins auto-armed by default");
|
||||
iw_entry(iw, "auto-trigger", cfg_pinmask_encode(priv->def_auto, unit_tmp512, 0));
|
||||
iw_entry_s(iw, "auto-trigger", cfg_pinmask_encode(priv->def_auto, unit_tmp512, 0));
|
||||
|
||||
iw_comment(iw, "Triggers hold-off time (ms)");
|
||||
iw_entry(iw, "hold-off", "%d", (int)priv->trig_holdoff);
|
||||
iw_entry_d(iw, "hold-off", priv->trig_holdoff);
|
||||
|
||||
#if PLAT_NO_FLOATING_INPUTS
|
||||
iw_comment(iw, "NOTE: Pins use pull-up by default.\r\n");
|
||||
|
||||
@@ -7,8 +7,20 @@
|
||||
#include "unit_dout.h"
|
||||
|
||||
#define DOUT_INTERNAL
|
||||
|
||||
#include "_dout_internal.h"
|
||||
|
||||
static void clear_pulse_by_mask(struct priv *priv, uint16_t spread)
|
||||
{
|
||||
assert_param(priv);
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (spread & (1 << i)) {
|
||||
priv->msec_pulse_cnt[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error_t UU_DOut_Write(Unit *unit, uint16_t packed)
|
||||
{
|
||||
CHECK_TYPE(unit, &UNIT_DOUT);
|
||||
@@ -16,6 +28,7 @@ error_t UU_DOut_Write(Unit *unit, uint16_t packed)
|
||||
struct priv *priv = unit->data;
|
||||
uint16_t mask = priv->pins;
|
||||
uint16_t spread = pinmask_spread(packed, mask);
|
||||
clear_pulse_by_mask(priv, spread);
|
||||
|
||||
uint16_t set = spread;
|
||||
uint16_t reset = ((~spread) & mask);
|
||||
@@ -30,6 +43,7 @@ error_t UU_DOut_Set(Unit *unit, uint16_t packed)
|
||||
struct priv *priv = unit->data;
|
||||
uint16_t mask = priv->pins;
|
||||
uint16_t spread = pinmask_spread(packed, mask);
|
||||
clear_pulse_by_mask(priv, spread);
|
||||
|
||||
priv->port->BSRR = spread;
|
||||
return E_SUCCESS;
|
||||
@@ -42,8 +56,9 @@ error_t UU_DOut_Clear(Unit *unit, uint16_t packed)
|
||||
struct priv *priv = unit->data;
|
||||
uint16_t mask = priv->pins;
|
||||
uint16_t spread = pinmask_spread(packed, mask);
|
||||
clear_pulse_by_mask(priv, spread);
|
||||
|
||||
priv->port->BSRR = (spread<<16);
|
||||
priv->port->BSRR = (spread << 16);
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -54,11 +69,12 @@ error_t UU_DOut_Toggle(Unit *unit, uint16_t packed)
|
||||
struct priv *priv = unit->data;
|
||||
uint16_t mask = priv->pins;
|
||||
uint16_t spread = pinmask_spread(packed, mask);
|
||||
clear_pulse_by_mask(priv, spread);
|
||||
|
||||
uint16_t flipped = (uint16_t) (~priv->port->ODR) & mask;
|
||||
uint16_t set = flipped & spread;
|
||||
uint16_t reset = ((~flipped) & mask) & spread;
|
||||
priv->port->BSRR = set | (reset<<16);
|
||||
priv->port->BSRR = set | (reset << 16);
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -68,6 +84,90 @@ error_t UU_DOut_GetPinCount(Unit *unit, uint8_t *count)
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
uint32_t packed = pinmask_pack(0xFFFF, priv->pins);
|
||||
*count = (uint8_t)(32 - __CLZ(packed));
|
||||
*count = (uint8_t) (32 - __CLZ(packed));
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
error_t UU_DOut_Pulse(Unit *unit, uint16_t packed, bool polarity, bool is_usec, uint16_t count)
|
||||
{
|
||||
CHECK_TYPE(unit, &UNIT_DOUT);
|
||||
struct priv *priv = unit->data;
|
||||
assert_param(priv);
|
||||
|
||||
uint16_t mask = priv->pins;
|
||||
uint16_t spread = pinmask_spread(packed, mask);
|
||||
clear_pulse_by_mask(priv, spread);
|
||||
|
||||
vPortEnterCritical();
|
||||
|
||||
if (is_usec) {
|
||||
// we're gonna do this right here as a delay loop.
|
||||
if (count >= 1000) {
|
||||
// too long, fall back to msec
|
||||
count /= 1000;
|
||||
is_usec = false;
|
||||
}
|
||||
else {
|
||||
const uint32_t bsrr1 = spread << (polarity ? 0 : 16);
|
||||
const uint32_t bsrr0 = spread << (polarity ? 16 : 0);
|
||||
|
||||
const uint32_t start = PTIM_MicroDelayAlign();
|
||||
priv->port->BSRR = bsrr1;
|
||||
PTIM_MicroDelayAligned(count, start);
|
||||
priv->port->BSRR = bsrr0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_usec) {
|
||||
// Load the counters
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (spread & (1 << i)) {
|
||||
priv->msec_pulse_cnt[i] = (uint16_t) (count + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (polarity) {
|
||||
priv->msec_pulse_scheduled_1 |= spread;
|
||||
} else {
|
||||
priv->msec_pulse_scheduled_0 |= spread;
|
||||
}
|
||||
|
||||
unit->_tick_cnt = 0;
|
||||
unit->tick_interval = 1;
|
||||
}
|
||||
|
||||
vPortExitCritical();
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
void DOut_Tick(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
uint16_t odr = (uint16_t) priv->port->ODR;
|
||||
int live_cnt = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (priv->msec_pulse_scheduled_1 & (1<<i)) {
|
||||
odr |= (1<<i);
|
||||
} else if (priv->msec_pulse_scheduled_0 & (1<<i)) {
|
||||
odr &= ~(1<<i);
|
||||
}
|
||||
|
||||
if (priv->msec_pulse_cnt[i] > 0) {
|
||||
live_cnt++;
|
||||
priv->msec_pulse_cnt[i]--;
|
||||
if (priv->msec_pulse_cnt[i] == 0) {
|
||||
odr ^= 1 << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
priv->port->ODR = odr;
|
||||
priv->msec_pulse_scheduled_1 = 0;
|
||||
priv->msec_pulse_scheduled_0 = 0;
|
||||
|
||||
if (live_cnt == 0) {
|
||||
unit->_tick_cnt = 0;
|
||||
unit->tick_interval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ struct priv {
|
||||
uint16_t open_drain; // open drain pins
|
||||
|
||||
GPIO_TypeDef *port;
|
||||
uint16_t msec_pulse_cnt[16];
|
||||
uint16_t msec_pulse_scheduled_1;
|
||||
uint16_t msec_pulse_scheduled_0;
|
||||
};
|
||||
|
||||
/** Allocate data structure and set defaults */
|
||||
@@ -46,4 +49,6 @@ error_t DOut_init(Unit *unit);
|
||||
/** Tear down the unit */
|
||||
void DOut_deInit(Unit *unit);
|
||||
|
||||
void DOut_Tick(Unit *unit);
|
||||
|
||||
#endif //GEX_F072_DOUT_INTERNAL_H
|
||||
|
||||
@@ -72,11 +72,11 @@ void DOut_writeIni(Unit *unit, IniWriter *iw)
|
||||
iw_entry(iw, "port", "%c", priv->port_name);
|
||||
|
||||
iw_comment(iw, "Pins (comma separated, supports ranges)");
|
||||
iw_entry(iw, "pins", cfg_pinmask_encode(priv->pins, unit_tmp512, 0));
|
||||
iw_entry_s(iw, "pins", cfg_pinmask_encode(priv->pins, unit_tmp512, 0));
|
||||
|
||||
iw_comment(iw, "Initially high pins");
|
||||
iw_entry(iw, "initial", cfg_pinmask_encode(priv->initial, unit_tmp512, 0));
|
||||
iw_entry_s(iw, "initial", cfg_pinmask_encode(priv->initial, unit_tmp512, 0));
|
||||
|
||||
iw_comment(iw, "Open-drain pins");
|
||||
iw_entry(iw, "open-drain", cfg_pinmask_encode(priv->open_drain, unit_tmp512, 0));
|
||||
iw_entry_s(iw, "open-drain", cfg_pinmask_encode(priv->open_drain, unit_tmp512, 0));
|
||||
}
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
#include "_dout_internal.h"
|
||||
|
||||
enum PinCmd_ {
|
||||
CMD_TEST = 0,
|
||||
CMD_QUERY = 0,
|
||||
CMD_SET = 1,
|
||||
CMD_CLEAR = 2,
|
||||
CMD_TOGGLE = 3,
|
||||
CMD_PULSE = 4,
|
||||
};
|
||||
|
||||
/** Handle a request message */
|
||||
@@ -21,7 +22,7 @@ static error_t DOut_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
|
||||
uint16_t packed = pp_u16(pp);
|
||||
|
||||
switch (command) {
|
||||
case CMD_TEST:
|
||||
case CMD_QUERY:
|
||||
return UU_DOut_Write(unit, packed);
|
||||
|
||||
case CMD_SET:
|
||||
@@ -33,6 +34,12 @@ static error_t DOut_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
|
||||
case CMD_TOGGLE:
|
||||
return UU_DOut_Toggle(unit, packed);
|
||||
|
||||
case CMD_PULSE:;
|
||||
bool polarity = pp_bool(pp);
|
||||
bool is_usec = pp_bool(pp);
|
||||
uint16_t count = pp_u16(pp);
|
||||
return UU_DOut_Pulse(unit, packed, polarity, is_usec, count);
|
||||
|
||||
default:
|
||||
return E_UNKNOWN_COMMAND;
|
||||
}
|
||||
@@ -55,4 +62,5 @@ const UnitDriver UNIT_DOUT = {
|
||||
.deInit = DOut_deInit,
|
||||
// Function
|
||||
.handleRequest = DOut_handleRequest,
|
||||
.updateTick = DOut_Tick,
|
||||
};
|
||||
|
||||
@@ -56,4 +56,16 @@ error_t UU_DOut_Toggle(Unit *unit, uint16_t packed);
|
||||
*/
|
||||
error_t UU_DOut_GetPinCount(Unit *unit, uint8_t *count);
|
||||
|
||||
/**
|
||||
* Send a pulse
|
||||
*
|
||||
* @param unit
|
||||
* @param packed - pins to pulse
|
||||
* @param polarity - pulse active level
|
||||
* @param is_usec - use usec precision (for < 1 ms)
|
||||
* @param count - number of units (msec or usec)
|
||||
* @return success
|
||||
*/
|
||||
error_t UU_DOut_Pulse(Unit *unit, uint16_t packed, bool polarity, bool is_usec, uint16_t count);
|
||||
|
||||
#endif //U_DOUT_H
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Created by MightyPork on 2018/02/20.
|
||||
//
|
||||
|
||||
#include <stm32f072xb.h>
|
||||
#include "platform.h"
|
||||
|
||||
#define FCAP_INTERNAL
|
||||
|
||||
@@ -92,20 +92,20 @@ void UFCAP_writeIni(Unit *unit, IniWriter *iw)
|
||||
iw_cmt_newline(iw);
|
||||
|
||||
iw_comment(iw, "Active level or edge (0-low,falling; 1-high,rising)");
|
||||
iw_entry(iw, "active-level", "%d", (int)priv->conf.active_level);
|
||||
iw_entry_d(iw, "active-level", priv->conf.active_level);
|
||||
|
||||
iw_comment(iw, "Input filtering (0-15)");
|
||||
iw_entry(iw, "input-filter", "%d", (int)priv->conf.dfilter);
|
||||
iw_entry_d(iw, "input-filter", priv->conf.dfilter);
|
||||
|
||||
iw_comment(iw, "Pulse counter pre-divider (1,2,4,8)");
|
||||
iw_entry(iw, "direct-presc", "%d", (int)priv->conf.direct_presc);
|
||||
iw_entry_d(iw, "direct-presc", priv->conf.direct_presc);
|
||||
|
||||
iw_comment(iw, "Pulse counting interval (ms)");
|
||||
iw_entry(iw, "direct-time", "%d", (int)priv->conf.direct_msec);
|
||||
iw_entry_d(iw, "direct-time", priv->conf.direct_msec);
|
||||
iw_cmt_newline(iw);
|
||||
|
||||
iw_comment(iw, "Mode on startup: N-none, I-indirect, D-direct, F-free count");
|
||||
iw_entry(iw, "initial-mode", cfg_enum4_encode(priv->conf.startmode,
|
||||
iw_entry_s(iw, "initial-mode", cfg_enum4_encode(priv->conf.startmode,
|
||||
OPMODE_IDLE, "N",
|
||||
OPMODE_INDIRECT_CONT, "I",
|
||||
OPMODE_DIRECT_CONT, "D",
|
||||
|
||||
@@ -62,7 +62,7 @@ error_t UI2C_init(Unit *unit)
|
||||
uint32_t af_i2c;
|
||||
uint32_t timing; // magic constant from CubeMX
|
||||
|
||||
#if GEX_PLAT_F072_DISCOVERY
|
||||
#if STM32F072xB
|
||||
// scl - 6 or 8 for I2C1, 10 for I2C2
|
||||
// sda - 7 or 9 for I2C1, 11 for I2C2
|
||||
if (priv->periph_num == 1) {
|
||||
|
||||
@@ -74,10 +74,10 @@ void UI2C_writeIni(Unit *unit, IniWriter *iw)
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
iw_comment(iw, "Peripheral number (I2Cx)");
|
||||
iw_entry(iw, "device", "%d", (int)priv->periph_num);
|
||||
iw_entry_d(iw, "device", priv->periph_num);
|
||||
|
||||
iw_comment(iw, "Pin mappings (SCL,SDA)");
|
||||
#if GEX_PLAT_F072_DISCOVERY
|
||||
#if STM32F072xB
|
||||
iw_comment(iw, " I2C1: (0) B6,B7 (1) B8,B9");
|
||||
iw_comment(iw, " I2C2: (0) B10,B11 (1) B13,B14");
|
||||
#elif GEX_PLAT_F103_BLUEPILL
|
||||
@@ -89,15 +89,15 @@ void UI2C_writeIni(Unit *unit, IniWriter *iw)
|
||||
#else
|
||||
#error "BAD PLATFORM!"
|
||||
#endif
|
||||
iw_entry(iw, "remap", "%d", (int)priv->remap);
|
||||
iw_entry_d(iw, "remap", priv->remap);
|
||||
|
||||
iw_cmt_newline(iw);
|
||||
iw_comment(iw, "Speed: 1-Standard, 2-Fast, 3-Fast+");
|
||||
iw_entry(iw, "speed", "%d", (int)priv->speed);
|
||||
iw_entry_d(iw, "speed", priv->speed);
|
||||
|
||||
iw_comment(iw, "Analog noise filter enable (Y,N)");
|
||||
iw_entry(iw, "analog-filter", str_yn(priv->anf));
|
||||
iw_entry_s(iw, "analog-filter", str_yn(priv->anf));
|
||||
|
||||
iw_comment(iw, "Digital noise filter bandwidth (0-15)");
|
||||
iw_entry(iw, "digital-filter", "%d", (int)priv->dnf);
|
||||
iw_entry_d(iw, "digital-filter", priv->dnf);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "_i2c_internal.h"
|
||||
|
||||
enum PinCmd_ {
|
||||
CMD_TEST = 0,
|
||||
CMD_QUERY = 0,
|
||||
CMD_READ = 1,
|
||||
CMD_WRITE_REG = 2,
|
||||
CMD_READ_REG = 3,
|
||||
@@ -30,7 +30,7 @@ static error_t UI2C_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
|
||||
|
||||
switch (command) {
|
||||
/** Write byte(s) - addr:u16, byte(s) */
|
||||
case CMD_TEST:
|
||||
case CMD_QUERY:
|
||||
addr = pp_u16(pp);
|
||||
const uint8_t *bb = pp_tail(pp, &len);
|
||||
|
||||
|
||||
@@ -54,8 +54,8 @@ void Npx_writeIni(Unit *unit, IniWriter *iw)
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
iw_comment(iw, "Data pin");
|
||||
iw_entry(iw, "pin", cfg_pinrsc_encode(priv->cfg.pin));
|
||||
iw_entry_s(iw, "pin", cfg_pinrsc_encode(priv->cfg.pin));
|
||||
|
||||
iw_comment(iw, "Number of pixels");
|
||||
iw_entry(iw, "pixels", "%d", priv->cfg.pixels);
|
||||
iw_entry_d(iw, "pixels", priv->cfg.pixels);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
#include "unit_pwmdim.h"
|
||||
|
||||
#define PWMDIM_INTERNAL
|
||||
#include "_pwmdim_internal.h"
|
||||
|
||||
error_t UPWMDIM_SetFreq(Unit *unit, uint32_t freq)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
uint16_t presc;
|
||||
uint32_t count;
|
||||
float real_freq;
|
||||
if (!hw_solve_timer(PLAT_APB1_HZ, freq, true, &presc, &count, &real_freq)) {
|
||||
dbg("Failed to resolve timer params.");
|
||||
return E_BAD_VALUE;
|
||||
}
|
||||
LL_TIM_SetPrescaler(priv->TIMx, (uint32_t) (presc - 1));
|
||||
LL_TIM_SetAutoReload(priv->TIMx, count - 1);
|
||||
|
||||
// we must re-calculate duty cycles because they are absolute related to the ARR which we just changed
|
||||
UPWMDIM_SetDuty(unit, 0, priv->duty1);
|
||||
UPWMDIM_SetDuty(unit, 1, priv->duty2);
|
||||
UPWMDIM_SetDuty(unit, 2, priv->duty3);
|
||||
UPWMDIM_SetDuty(unit, 3, priv->duty4);
|
||||
|
||||
// LL_TIM_GenerateEvent_UPDATE(priv->TIMx); // - this appears to cause jumpiness
|
||||
priv->freq = freq;
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
error_t UPWMDIM_SetDuty(Unit *unit, uint8_t ch, uint16_t duty1000)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
uint32_t cnt = (LL_TIM_GetAutoReload(priv->TIMx) + 1)*duty1000 / 1000;
|
||||
|
||||
if (ch == 0) {
|
||||
priv->duty1 = duty1000;
|
||||
LL_TIM_OC_SetCompareCH1(priv->TIMx, cnt);
|
||||
}
|
||||
else if (ch == 1) {
|
||||
priv->duty2 = duty1000;
|
||||
LL_TIM_OC_SetCompareCH2(priv->TIMx, cnt);
|
||||
}
|
||||
else if (ch == 2) {
|
||||
priv->duty3 = duty1000;
|
||||
LL_TIM_OC_SetCompareCH3(priv->TIMx, cnt);
|
||||
}
|
||||
else if (ch == 3) {
|
||||
priv->duty4 = duty1000;
|
||||
LL_TIM_OC_SetCompareCH4(priv->TIMx, cnt);
|
||||
} else {
|
||||
return E_BAD_VALUE;
|
||||
}
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
|
||||
#define PWMDIM_INTERNAL
|
||||
#include "_pwmdim_internal.h"
|
||||
|
||||
/** Allocate data structure and set defaults */
|
||||
error_t UPWMDIM_preInit(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
|
||||
if (priv == NULL) return E_OUT_OF_MEM;
|
||||
|
||||
priv->cfg.freq = 1000;
|
||||
priv->cfg.ch1_choice = 1;
|
||||
priv->cfg.ch2_choice = 0;
|
||||
priv->cfg.ch3_choice = 0;
|
||||
priv->cfg.ch4_choice = 0;
|
||||
|
||||
priv->duty1 = 500;
|
||||
priv->duty2 = 500;
|
||||
priv->duty3 = 500;
|
||||
priv->duty4 = 500;
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/** Finalize unit set-up */
|
||||
error_t UPWMDIM_init(Unit *unit)
|
||||
{
|
||||
bool suc = true;
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
TRY(rsc_claim(unit, R_TIM3));
|
||||
priv->TIMx = TIM3;
|
||||
hw_periph_clock_enable(priv->TIMx);
|
||||
|
||||
// copy the default frequency
|
||||
priv->freq = priv->cfg.freq;
|
||||
|
||||
const Resource ch1_pins[] = { R_PA6, R_PB4, R_PC6 };
|
||||
const uint32_t ch1_af[] = { LL_GPIO_AF_1, LL_GPIO_AF_1, LL_GPIO_AF_0 };
|
||||
|
||||
const Resource ch2_pins[] = { R_PA7, R_PB5, R_PC7 };
|
||||
const uint32_t ch2_af[] = { LL_GPIO_AF_1, LL_GPIO_AF_1, LL_GPIO_AF_0 };
|
||||
|
||||
const Resource ch3_pins[] = { R_PB0, R_PC8 };
|
||||
const uint32_t ch3_af[] = { LL_GPIO_AF_1, LL_GPIO_AF_0 };
|
||||
|
||||
const Resource ch4_pins[] = { R_PB1, R_PC9 };
|
||||
const uint32_t ch4_af[] = { LL_GPIO_AF_1, LL_GPIO_AF_0 };
|
||||
|
||||
Resource r[4] = {};
|
||||
uint32_t af[4] = {};
|
||||
|
||||
// --- resolve pins and AFs ---
|
||||
if (priv->cfg.ch1_choice > 0) {
|
||||
if (priv->cfg.ch1_choice > 3) return E_BAD_CONFIG;
|
||||
r[0] = ch1_pins[priv->cfg.ch1_choice - 1];
|
||||
af[0] = ch1_af[priv->cfg.ch1_choice - 1];
|
||||
TRY(rsc_claim(unit, r[0]));
|
||||
}
|
||||
|
||||
if (priv->cfg.ch2_choice > 0) {
|
||||
if (priv->cfg.ch2_choice > 3) return E_BAD_CONFIG;
|
||||
r[1] = ch2_pins[priv->cfg.ch2_choice - 1];
|
||||
af[1] = ch2_af[priv->cfg.ch2_choice - 1];
|
||||
TRY(rsc_claim(unit, r[1]));
|
||||
}
|
||||
|
||||
if (priv->cfg.ch3_choice > 0) {
|
||||
if (priv->cfg.ch3_choice > 2) return E_BAD_CONFIG;
|
||||
r[2] = ch3_pins[priv->cfg.ch3_choice - 1];
|
||||
af[2] = ch3_af[priv->cfg.ch3_choice - 1];
|
||||
TRY(rsc_claim(unit, r[2]));
|
||||
}
|
||||
|
||||
if (priv->cfg.ch4_choice > 0) {
|
||||
if (priv->cfg.ch4_choice > 2) return E_BAD_CONFIG;
|
||||
r[3] = ch4_pins[priv->cfg.ch4_choice - 1];
|
||||
af[3] = ch4_af[priv->cfg.ch4_choice - 1];
|
||||
TRY(rsc_claim(unit, r[3]));
|
||||
}
|
||||
|
||||
// --- configure AF + timer ---
|
||||
LL_TIM_DeInit(priv->TIMx); // force a reset
|
||||
|
||||
uint16_t presc;
|
||||
uint32_t count;
|
||||
float real_freq;
|
||||
if (!hw_solve_timer(PLAT_APB1_HZ, priv->freq, true, &presc, &count, &real_freq)) {
|
||||
dbg("Failed to resolve timer params.");
|
||||
return E_BAD_VALUE;
|
||||
}
|
||||
LL_TIM_SetPrescaler(priv->TIMx, (uint32_t) (presc - 1));
|
||||
LL_TIM_SetAutoReload(priv->TIMx, count - 1);
|
||||
LL_TIM_EnableARRPreload(priv->TIMx);
|
||||
|
||||
dbg("Presc %d, cnt %d", (int)presc, (int)count);
|
||||
|
||||
// TODO this can probably be turned into a loop over an array of structs
|
||||
|
||||
|
||||
if (priv->cfg.ch1_choice > 0) {
|
||||
TRY(hw_configure_gpiorsc_af(r[0], af[0]));
|
||||
|
||||
LL_TIM_OC_EnablePreload(priv->TIMx, LL_TIM_CHANNEL_CH1);
|
||||
LL_TIM_OC_SetMode(priv->TIMx, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM1);
|
||||
LL_TIM_OC_SetCompareCH1(priv->TIMx, count/2);
|
||||
LL_TIM_CC_EnablePreload(priv->TIMx);
|
||||
LL_TIM_CC_EnableChannel(priv->TIMx, LL_TIM_CHANNEL_CH1);
|
||||
}
|
||||
|
||||
if (priv->cfg.ch2_choice > 0) {
|
||||
TRY(hw_configure_gpiorsc_af(r[1], af[1]));
|
||||
|
||||
LL_TIM_OC_EnablePreload(priv->TIMx, LL_TIM_CHANNEL_CH2);
|
||||
LL_TIM_OC_SetMode(priv->TIMx, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_PWM1);
|
||||
LL_TIM_OC_SetCompareCH2(priv->TIMx, count/2);
|
||||
LL_TIM_CC_EnableChannel(priv->TIMx, LL_TIM_CHANNEL_CH2);
|
||||
}
|
||||
|
||||
if (priv->cfg.ch3_choice > 0) {
|
||||
TRY(hw_configure_gpiorsc_af(r[2], af[2]));
|
||||
|
||||
LL_TIM_OC_EnablePreload(priv->TIMx, LL_TIM_CHANNEL_CH3);
|
||||
LL_TIM_OC_SetMode(priv->TIMx, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_PWM1);
|
||||
LL_TIM_OC_SetCompareCH3(priv->TIMx, count/2);
|
||||
LL_TIM_CC_EnableChannel(priv->TIMx, LL_TIM_CHANNEL_CH3);
|
||||
}
|
||||
|
||||
if (priv->cfg.ch4_choice > 0) {
|
||||
TRY(hw_configure_gpiorsc_af(r[3], af[3]));
|
||||
|
||||
LL_TIM_OC_EnablePreload(priv->TIMx, LL_TIM_CHANNEL_CH4);
|
||||
LL_TIM_OC_SetMode(priv->TIMx, LL_TIM_CHANNEL_CH4, LL_TIM_OCMODE_PWM1);
|
||||
LL_TIM_OC_SetCompareCH4(priv->TIMx, count/2);
|
||||
LL_TIM_CC_EnableChannel(priv->TIMx, LL_TIM_CHANNEL_CH4);
|
||||
}
|
||||
|
||||
LL_TIM_GenerateEvent_UPDATE(priv->TIMx);
|
||||
LL_TIM_EnableAllOutputs(priv->TIMx);
|
||||
|
||||
// postpone this for later - when user uses the start command.
|
||||
// prevents beeping right after restart if used for audio.
|
||||
// LL_TIM_EnableCounter(priv->TIMx);
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/** Tear down the unit */
|
||||
void UPWMDIM_deInit(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
// de-init peripherals
|
||||
if (unit->status == E_SUCCESS ) {
|
||||
LL_TIM_DeInit(priv->TIMx);
|
||||
}
|
||||
|
||||
// Release all resources, deinit pins
|
||||
rsc_teardown(unit);
|
||||
|
||||
// Free memory
|
||||
free_ck(unit->data);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#ifndef GEX_F072_PWMDIM_INTERNAL_H
|
||||
#define GEX_F072_PWMDIM_INTERNAL_H
|
||||
|
||||
#ifndef PWMDIM_INTERNAL
|
||||
#error bad include!
|
||||
#endif
|
||||
|
||||
#include "unit_base.h"
|
||||
|
||||
/** Private data structure */
|
||||
struct priv {
|
||||
// settings
|
||||
struct {
|
||||
uint32_t freq;
|
||||
uint8_t ch1_choice;
|
||||
uint8_t ch2_choice;
|
||||
uint8_t ch3_choice;
|
||||
uint8_t ch4_choice;
|
||||
} cfg;
|
||||
|
||||
// internal state
|
||||
uint32_t freq;
|
||||
uint16_t duty1;
|
||||
uint16_t duty2;
|
||||
uint16_t duty3;
|
||||
uint16_t duty4;
|
||||
|
||||
TIM_TypeDef *TIMx;
|
||||
};
|
||||
|
||||
/** Allocate data structure and set defaults */
|
||||
error_t UPWMDIM_preInit(Unit *unit);
|
||||
|
||||
/** Load from a binary buffer stored in Flash */
|
||||
void UPWMDIM_loadBinary(Unit *unit, PayloadParser *pp);
|
||||
|
||||
/** Write to a binary buffer for storing in Flash */
|
||||
void UPWMDIM_writeBinary(Unit *unit, PayloadBuilder *pb);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Parse a key-value pair from the INI file */
|
||||
error_t UPWMDIM_loadIni(Unit *unit, const char *key, const char *value);
|
||||
|
||||
/** Generate INI file section for the unit */
|
||||
void UPWMDIM_writeIni(Unit *unit, IniWriter *iw);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Finalize unit set-up */
|
||||
error_t UPWMDIM_init(Unit *unit);
|
||||
|
||||
/** Tear down the unit */
|
||||
void UPWMDIM_deInit(Unit *unit);
|
||||
|
||||
|
||||
error_t UPWMDIM_SetFreq(Unit *unit, uint32_t freq);
|
||||
|
||||
error_t UPWMDIM_SetDuty(Unit *unit, uint8_t ch, uint16_t duty1000);
|
||||
|
||||
#endif //GEX_F072_PWMDIM_INTERNAL_H
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
|
||||
#define PWMDIM_INTERNAL
|
||||
#include "_pwmdim_internal.h"
|
||||
|
||||
/** Load from a binary buffer stored in Flash */
|
||||
void UPWMDIM_loadBinary(Unit *unit, PayloadParser *pp)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
uint8_t version = pp_u8(pp);
|
||||
(void)version;
|
||||
|
||||
priv->cfg.freq = pp_u32(pp);
|
||||
priv->cfg.ch1_choice = pp_u8(pp);
|
||||
priv->cfg.ch2_choice = pp_u8(pp);
|
||||
priv->cfg.ch3_choice = pp_u8(pp);
|
||||
priv->cfg.ch4_choice = pp_u8(pp);
|
||||
}
|
||||
|
||||
/** Write to a binary buffer for storing in Flash */
|
||||
void UPWMDIM_writeBinary(Unit *unit, PayloadBuilder *pb)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
pb_u8(pb, 0); // version
|
||||
|
||||
pb_u32(pb, priv->cfg.freq);
|
||||
pb_u8(pb, priv->cfg.ch1_choice);
|
||||
pb_u8(pb, priv->cfg.ch2_choice);
|
||||
pb_u8(pb, priv->cfg.ch3_choice);
|
||||
pb_u8(pb, priv->cfg.ch4_choice);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Parse a key-value pair from the INI file */
|
||||
error_t UPWMDIM_loadIni(Unit *unit, const char *key, const char *value)
|
||||
{
|
||||
bool suc = true;
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
if (streq(key, "frequency")) {
|
||||
priv->cfg.freq = cfg_u32_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "ch1_pin")) {
|
||||
priv->cfg.ch1_choice = cfg_u8_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "ch2_pin")) {
|
||||
priv->cfg.ch2_choice = cfg_u8_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "ch3_pin")) {
|
||||
priv->cfg.ch3_choice = cfg_u8_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "ch4_pin")) {
|
||||
priv->cfg.ch4_choice = cfg_u8_parse(value, &suc);
|
||||
}
|
||||
else {
|
||||
return E_BAD_KEY;
|
||||
}
|
||||
|
||||
if (!suc) return E_BAD_VALUE;
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/** Generate INI file section for the unit */
|
||||
void UPWMDIM_writeIni(Unit *unit, IniWriter *iw)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
iw_comment(iw, "Default pulse frequency (Hz)");
|
||||
iw_entry_d(iw, "frequency", priv->cfg.freq);
|
||||
|
||||
iw_comment(iw, "Pin mapping - 0=disabled");
|
||||
iw_comment(iw, "Channel1 - 1:PA6, 2:PB4, 3:PC6");
|
||||
iw_entry_d(iw, "ch1_pin", priv->cfg.ch1_choice);
|
||||
iw_comment(iw, "Channel2 - 1:PA7, 2:PB5, 3:PC7");
|
||||
iw_entry_d(iw, "ch2_pin", priv->cfg.ch2_choice);
|
||||
iw_comment(iw, "Channel3 - 1:PB0, 2:PC8");
|
||||
iw_entry_d(iw, "ch3_pin", priv->cfg.ch3_choice);
|
||||
iw_comment(iw, "Channel4 - 1:PB1, 2:PC9");
|
||||
iw_entry_d(iw, "ch4_pin", priv->cfg.ch4_choice);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/25.
|
||||
//
|
||||
|
||||
#include "unit_base.h"
|
||||
#include "unit_pwmdim.h"
|
||||
|
||||
#define PWMDIM_INTERNAL
|
||||
#include "_pwmdim_internal.h"
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
enum PwmSimpleCmd_ {
|
||||
CMD_SET_FREQUENCY = 0,
|
||||
CMD_SET_DUTY = 1,
|
||||
CMD_STOP = 2,
|
||||
CMD_START = 3,
|
||||
};
|
||||
|
||||
/** Handle a request message */
|
||||
static error_t UPWMDIM_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
switch (command) {
|
||||
case CMD_SET_FREQUENCY:
|
||||
TRY(UPWMDIM_SetFreq(unit, pp_u32(pp)));
|
||||
return E_SUCCESS;
|
||||
|
||||
case CMD_SET_DUTY:
|
||||
for (; pp_length(pp) > 0;) {
|
||||
uint8_t ch = pp_u8(pp);
|
||||
uint16_t duty = pp_u16(pp);
|
||||
TRY(UPWMDIM_SetDuty(unit, ch, duty));
|
||||
}
|
||||
return E_SUCCESS;
|
||||
|
||||
case CMD_STOP:
|
||||
LL_TIM_DisableCounter(priv->TIMx);
|
||||
LL_TIM_SetCounter(priv->TIMx, 0);
|
||||
return E_SUCCESS;
|
||||
|
||||
case CMD_START:
|
||||
LL_TIM_EnableCounter(priv->TIMx);
|
||||
return E_SUCCESS;
|
||||
|
||||
default:
|
||||
return E_UNKNOWN_COMMAND;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Simple PWM dimming output */
|
||||
const UnitDriver UNIT_PWMDIM = {
|
||||
.name = "PWMDIM",
|
||||
.description = "Simple PWM output",
|
||||
// Settings
|
||||
.preInit = UPWMDIM_preInit,
|
||||
.cfgLoadBinary = UPWMDIM_loadBinary,
|
||||
.cfgWriteBinary = UPWMDIM_writeBinary,
|
||||
.cfgLoadIni = UPWMDIM_loadIni,
|
||||
.cfgWriteIni = UPWMDIM_writeIni,
|
||||
// Init
|
||||
.init = UPWMDIM_init,
|
||||
.deInit = UPWMDIM_deInit,
|
||||
// Function
|
||||
.handleRequest = UPWMDIM_handleRequest,
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/25.
|
||||
//
|
||||
// Digital input unit; single or multiple pin read access on one port (A-F)
|
||||
//
|
||||
|
||||
#ifndef U_PWMDIM_H
|
||||
#define U_PWMDIM_H
|
||||
|
||||
#include "unit.h"
|
||||
|
||||
extern const UnitDriver UNIT_PWMDIM;
|
||||
|
||||
// UU_ prototypes
|
||||
|
||||
#endif //U_PWMDIM_H
|
||||
@@ -98,19 +98,19 @@ void USIPO_writeIni(Unit *unit, IniWriter *iw)
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
iw_comment(iw, "Shift pin & its active edge (1-rising,0-falling)");
|
||||
iw_entry(iw, "shift-pin", cfg_pinrsc_encode(priv->cfg.pin_shift));
|
||||
iw_entry(iw, "shift-pol", "%d", priv->cfg.shift_pol);
|
||||
iw_entry_s(iw, "shift-pin", cfg_pinrsc_encode(priv->cfg.pin_shift));
|
||||
iw_entry_d(iw, "shift-pol", priv->cfg.shift_pol);
|
||||
|
||||
iw_comment(iw, "Store pin & its active edge");
|
||||
iw_entry(iw, "store-pin", cfg_pinrsc_encode(priv->cfg.pin_store));
|
||||
iw_entry(iw, "store-pol", "%d", priv->cfg.store_pol);
|
||||
iw_entry_s(iw, "store-pin", cfg_pinrsc_encode(priv->cfg.pin_store));
|
||||
iw_entry_d(iw, "store-pol", priv->cfg.store_pol);
|
||||
|
||||
iw_comment(iw, "Clear pin & its active level");
|
||||
iw_entry(iw, "clear-pin", cfg_pinrsc_encode(priv->cfg.pin_clear));
|
||||
iw_entry(iw, "clear-pol", "%d", priv->cfg.clear_pol);
|
||||
iw_entry_s(iw, "clear-pin", cfg_pinrsc_encode(priv->cfg.pin_clear));
|
||||
iw_entry_d(iw, "clear-pol", priv->cfg.clear_pol);
|
||||
|
||||
iw_comment(iw, "Data port and pins");
|
||||
iw_entry(iw, "data-port", "%c", priv->cfg.data_pname);
|
||||
iw_entry(iw, "data-pins", cfg_pinmask_encode(priv->cfg.data_pins, unit_tmp512, true));
|
||||
iw_entry_s(iw, "data-pins", cfg_pinmask_encode(priv->cfg.data_pins, unit_tmp512, true));
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
enum SipoCmd_ {
|
||||
CMD_WRITE = 0,
|
||||
CMD_QUERY = 0,
|
||||
CMD_DIRECT_DATA = 1,
|
||||
CMD_DIRECT_SHIFT = 2,
|
||||
CMD_DIRECT_CLEAR = 3,
|
||||
@@ -23,7 +23,7 @@ enum SipoCmd_ {
|
||||
static error_t USIPO_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
|
||||
{
|
||||
switch (command) {
|
||||
case CMD_WRITE:
|
||||
case CMD_QUERY:
|
||||
{
|
||||
uint32_t len;
|
||||
uint16_t terminal_packed = pp_u16(pp);
|
||||
|
||||
+17
-17
@@ -63,7 +63,7 @@ error_t USPI_init(Unit *unit)
|
||||
uint32_t af_spi;
|
||||
|
||||
// TODO
|
||||
#if GEX_PLAT_F072_DISCOVERY
|
||||
#if STM32F072xB
|
||||
// SPI1 - many options
|
||||
// sck, miso, mosi, af
|
||||
|
||||
@@ -83,14 +83,14 @@ error_t USPI_init(Unit *unit)
|
||||
pin_miso = 4;
|
||||
pin_mosi = 5;
|
||||
}
|
||||
else if (priv->remap == 2) {
|
||||
// large packages only
|
||||
spi_portname = 'E';
|
||||
af_spi = LL_GPIO_AF_1;
|
||||
pin_sck = 13;
|
||||
pin_miso = 14;
|
||||
pin_mosi = 15;
|
||||
}
|
||||
// else if (priv->remap == 2) {
|
||||
// // large packages only
|
||||
// spi_portname = 'E';
|
||||
// af_spi = LL_GPIO_AF_1;
|
||||
// pin_sck = 13;
|
||||
// pin_miso = 14;
|
||||
// pin_mosi = 15;
|
||||
// }
|
||||
else {
|
||||
return E_BAD_CONFIG;
|
||||
}
|
||||
@@ -104,14 +104,14 @@ error_t USPI_init(Unit *unit)
|
||||
pin_miso = 14;
|
||||
pin_mosi = 15;
|
||||
}
|
||||
else if (priv->remap == 1) {
|
||||
// NOTE: the's also a incomplete remap in PB and PC
|
||||
spi_portname = 'D';
|
||||
af_spi = LL_GPIO_AF_0;
|
||||
pin_sck = 1;
|
||||
pin_miso = 3;
|
||||
pin_mosi = 4;
|
||||
}
|
||||
// else if (priv->remap == 1) {
|
||||
// // NOTE: there's also an incomplete remap in PB and PC
|
||||
// spi_portname = 'D';
|
||||
// af_spi = LL_GPIO_AF_0;
|
||||
// pin_sck = 1;
|
||||
// pin_miso = 3;
|
||||
// pin_mosi = 4;
|
||||
// }
|
||||
else {
|
||||
return E_BAD_CONFIG;
|
||||
}
|
||||
|
||||
+11
-11
@@ -98,13 +98,13 @@ void USPI_writeIni(Unit *unit, IniWriter *iw)
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
iw_comment(iw, "Peripheral number (SPIx)");
|
||||
iw_entry(iw, "device", "%d", (int)priv->periph_num);
|
||||
iw_entry_d(iw, "device", priv->periph_num);
|
||||
|
||||
// TODO show a legend for peripherals and remaps
|
||||
iw_comment(iw, "Pin mappings (SCK,MISO,MOSI)");
|
||||
#if GEX_PLAT_F072_DISCOVERY
|
||||
iw_comment(iw, " SPI1: (0) A5,A6,A7 (1) B3,B4,B5 (2) E13,E14,E15");
|
||||
iw_comment(iw, " SPI2: (0) B13,B14,B15 (1) D1,D3,D4");
|
||||
#if STM32F072xB
|
||||
iw_comment(iw, " SPI1: (0) A5,A6,A7 (1) B3,B4,B5"); // (2) E13,E14,E15
|
||||
iw_comment(iw, " SPI2: (0) B13,B14,B15"); // (1) D1,D3,D4
|
||||
#elif GEX_PLAT_F103_BLUEPILL
|
||||
#error "NO IMPL"
|
||||
#elif GEX_PLAT_F303_DISCOVERY
|
||||
@@ -114,28 +114,28 @@ void USPI_writeIni(Unit *unit, IniWriter *iw)
|
||||
#else
|
||||
#error "BAD PLATFORM!"
|
||||
#endif
|
||||
iw_entry(iw, "remap", "%d", (int)priv->remap);
|
||||
iw_entry_d(iw, "remap", priv->remap);
|
||||
|
||||
iw_cmt_newline(iw);
|
||||
iw_comment(iw, "Prescaller: 2,4,8,...,256");
|
||||
iw_entry(iw, "prescaller", "%d", (int)priv->prescaller);
|
||||
iw_entry_d(iw, "prescaller", priv->prescaller);
|
||||
|
||||
iw_comment(iw, "Clock polarity: 0,1 (clock idle level)");
|
||||
iw_entry(iw, "cpol", "%d", (int)priv->cpol);
|
||||
iw_entry_d(iw, "cpol", priv->cpol);
|
||||
|
||||
iw_comment(iw, "Clock phase: 0,1 (active edge, 0-first, 1-second)");
|
||||
iw_entry(iw, "cpha", "%d", (int)priv->cpha);
|
||||
iw_entry_d(iw, "cpha", priv->cpha);
|
||||
|
||||
iw_comment(iw, "Transmit only, disable MISO");
|
||||
iw_entry(iw, "tx-only", str_yn(priv->tx_only));
|
||||
iw_entry_s(iw, "tx-only", str_yn(priv->tx_only));
|
||||
|
||||
iw_comment(iw, "Bit order (LSB or MSB first)");
|
||||
iw_entry(iw, "first-bit", cfg_enum2_encode((uint32_t) priv->lsb_first, 0, "MSB", 1, "LSB"));
|
||||
iw_entry_s(iw, "first-bit", cfg_enum2_encode((uint32_t) priv->lsb_first, 0, "MSB", 1, "LSB"));
|
||||
|
||||
iw_cmt_newline(iw);
|
||||
iw_comment(iw, "SS port name");
|
||||
iw_entry(iw, "port", "%c", priv->ssn_port_name);
|
||||
|
||||
iw_comment(iw, "SS pins (comma separated, supports ranges)");
|
||||
iw_entry(iw, "pins", cfg_pinmask_encode(priv->ssn_pins, unit_tmp512, 0));
|
||||
iw_entry_s(iw, "pins", cfg_pinmask_encode(priv->ssn_pins, unit_tmp512, 0));
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// SPI master
|
||||
|
||||
enum PinCmd_ {
|
||||
CMD_TEST = 0,
|
||||
CMD_QUERY = 0,
|
||||
CMD_MULTICAST = 1,
|
||||
};
|
||||
|
||||
@@ -33,7 +33,7 @@ static error_t USPI_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
|
||||
|
||||
switch (command) {
|
||||
/** Write and read byte(s) - slave_num:u8, req_len:u16, resp_skip:u16, resp_len:u16, byte(s) */
|
||||
case CMD_TEST:
|
||||
case CMD_QUERY:
|
||||
slave = pp_u8(pp);
|
||||
resp_skip = pp_u16(pp);
|
||||
resp_len = pp_u16(pp);
|
||||
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Enter unit type identifier (empty to cancel):"
|
||||
read x
|
||||
|
||||
if [ -e $x ]; then
|
||||
exit;
|
||||
fi
|
||||
|
||||
xl="${x,,}"
|
||||
xu="${x^^}"
|
||||
|
||||
for f in *.h; do mv -- "$f" "${f//tpl/$xl}"; done
|
||||
for f in *.c; do mv -- "$f" "${f//tpl/$xl}"; done
|
||||
|
||||
sed "s/tpl/$xl/" -i *.h
|
||||
sed "s/TPL/$xu/" -i *.h
|
||||
sed "s/tpl/$xl/" -i *.c
|
||||
sed "s/TPL/$xu/" -i *.c
|
||||
|
||||
echo "Unit $xu set up completed. Removing installer.."
|
||||
rm '!README.TXT'
|
||||
rm $0
|
||||
@@ -0,0 +1,11 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
#include "unit_touch.h"
|
||||
|
||||
#define TOUCH_INTERNAL
|
||||
#include "_touch_internal.h"
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/25.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
#include "unit_touch.h"
|
||||
|
||||
#define TOUCH_INTERNAL
|
||||
|
||||
#include "_touch_internal.h"
|
||||
|
||||
// discharge time in ms
|
||||
#define DIS_TIME 1
|
||||
|
||||
static void startNextPhase(Unit *unit);
|
||||
|
||||
static void UTOUCH_EventReportJob(Job *job)
|
||||
{
|
||||
Unit *unit = job->unit;
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
uint8_t buf[8];
|
||||
PayloadBuilder pb = pb_start(buf, 8, NULL);
|
||||
pb_u32(&pb, pinmask_pack_32(~job->data1, priv->all_channels_mask)); // inverted and packed - all pins (pressed state)
|
||||
pb_u32(&pb, pinmask_pack_32(job->data2, priv->all_channels_mask)); // trigger generating pins
|
||||
assert_param(pb.ok);
|
||||
|
||||
EventReport er = {
|
||||
.unit = unit,
|
||||
.type = 0x00,
|
||||
.length = 8,
|
||||
.data = buf,
|
||||
.timestamp = job->timestamp,
|
||||
};
|
||||
|
||||
EventReport_Send(&er);
|
||||
}
|
||||
|
||||
static void UTOUCH_CheckForBinaryEvents(Unit *const unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
const uint32_t time_ms = PTIM_GetTime();
|
||||
|
||||
if (priv->last_done_ms == 0) {
|
||||
// avoid bug with trigger on first capture
|
||||
priv->last_done_ms = time_ms;
|
||||
}
|
||||
|
||||
const uint64_t ts = PTIM_GetMicrotime();
|
||||
uint32_t eventpins = 0;
|
||||
|
||||
const uint16_t ms_elapsed = (uint16_t) (time_ms - priv->last_done_ms);
|
||||
|
||||
for (uint16_t i = 0; i < 32; i++) {
|
||||
const uint32_t poke = (uint32_t) (1 << i);
|
||||
if (0 == (priv->all_channels_mask & poke)) continue;
|
||||
if (priv->binary_thr[i] == 0) continue; // skip disabled channels
|
||||
|
||||
const bool isactive = (bool) (priv->binary_active_bits & poke);
|
||||
const bool can_go_up = !isactive && (priv->readouts[i] > (priv->binary_thr[i] + priv->binary_hysteresis));
|
||||
const bool can_go_down = isactive && (priv->readouts[i] < priv->binary_thr[i]);
|
||||
|
||||
if (can_go_up) {
|
||||
priv->bin_trig_cnt[i] += ms_elapsed;
|
||||
if (priv->bin_trig_cnt[i] >= priv->binary_debounce_ms) {
|
||||
priv->binary_active_bits |= poke;
|
||||
priv->bin_trig_cnt[i] = 0; // reset for the other direction of the switch
|
||||
|
||||
eventpins |= poke;
|
||||
}
|
||||
}
|
||||
else if (priv->bin_trig_cnt[i] > 0) {
|
||||
priv->bin_trig_cnt[i] = 0;
|
||||
}
|
||||
|
||||
if (can_go_down) {
|
||||
priv->bin_trig_cnt[i] -= ms_elapsed;
|
||||
if (priv->bin_trig_cnt[i] <= -priv->binary_debounce_ms) {
|
||||
priv->binary_active_bits &= ~poke;
|
||||
priv->bin_trig_cnt[i] = 0; // reset for the other direction of the switch
|
||||
|
||||
eventpins |= poke;
|
||||
}
|
||||
}
|
||||
else if (priv->bin_trig_cnt[i] < 0) {
|
||||
priv->bin_trig_cnt[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (eventpins != 0) {
|
||||
Job j = {
|
||||
.timestamp = ts,
|
||||
.data1 = priv->binary_active_bits,
|
||||
.data2 = eventpins,
|
||||
.unit = unit,
|
||||
.cb = UTOUCH_EventReportJob,
|
||||
};
|
||||
|
||||
scheduleJob(&j);
|
||||
}
|
||||
|
||||
priv->last_done_ms = time_ms;
|
||||
}
|
||||
|
||||
void UTOUCH_HandleIrq(void *arg)
|
||||
{
|
||||
Unit *unit = arg;
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
if (TSC->ISR & TSC_ISR_MCEF) {
|
||||
priv->status = UTSC_STATUS_FAIL;
|
||||
dbg_touch("TSC Failure.");
|
||||
TSC->ICR = TSC_ICR_EOAIC | TSC_ICR_MCEIC;
|
||||
}
|
||||
|
||||
if (TSC->ISR & TSC_ISR_EOAF) {
|
||||
TSC->ICR = TSC_ICR_EOAIC;
|
||||
// assert_param((TSC->IOGCSR>>16) == priv->groups_phase[priv->next_phase]);
|
||||
|
||||
// Store captured data
|
||||
const uint32_t chmask = TSC->IOCCR;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (chmask & (1<<i)) {
|
||||
priv->readouts[i] = (uint16_t) (TSC->IOGXCR[i >> 2] & 0x3FFF);
|
||||
}
|
||||
}
|
||||
|
||||
priv->next_phase++;
|
||||
|
||||
if (!priv->cfg.interlaced) {
|
||||
// check if we've run out of existing or populated groups
|
||||
if (priv->next_phase == 3 || priv->groups_phase[priv->next_phase] == 0) {
|
||||
priv->next_phase = 0;
|
||||
priv->status = UTSC_STATUS_READY;
|
||||
UTOUCH_CheckForBinaryEvents(unit);
|
||||
}
|
||||
}
|
||||
|
||||
TSC->CR &= ~TSC_CR_IODEF; // pull low - discharge
|
||||
}
|
||||
|
||||
priv->ongoing = false;
|
||||
priv->discharge_delay = DIS_TIME;
|
||||
}
|
||||
|
||||
#if TSC_DEBUG
|
||||
static volatile uint32_t xcnt=0;
|
||||
#endif
|
||||
|
||||
void UTOUCH_updateTick(Unit *unit)
|
||||
{
|
||||
#if TSC_DEBUG
|
||||
xcnt++;
|
||||
#endif
|
||||
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
if (priv->ongoing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (priv->discharge_delay > 0) {
|
||||
priv->discharge_delay--;
|
||||
} else {
|
||||
startNextPhase(unit);
|
||||
}
|
||||
|
||||
#if TSC_DEBUG
|
||||
if(xcnt >= 250) {
|
||||
xcnt=0;
|
||||
PRINTF("> ");
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (priv->all_channels_mask & (1<<i)) {
|
||||
PRINTF("%d ", (int)priv->readouts[i]);
|
||||
}
|
||||
}
|
||||
PRINTF("\r\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void startNextPhase(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
if (priv->all_channels_mask == 0) return;
|
||||
|
||||
if (priv->cfg.interlaced) {
|
||||
// Find the next non-zero bit, wrap around if needed
|
||||
while ((priv->all_channels_mask & (1<<priv->next_phase))==0) {
|
||||
priv->next_phase++;
|
||||
if (priv->next_phase == 32) {
|
||||
priv->next_phase = 0;
|
||||
priv->status = UTSC_STATUS_READY;
|
||||
UTOUCH_CheckForBinaryEvents(unit);
|
||||
}
|
||||
}
|
||||
TSC->IOGCSR = (uint32_t) (1 << (priv->next_phase >> 2)); // phase divided by 4
|
||||
TSC->IOCCR = (uint32_t) (1 << priv->next_phase);
|
||||
|
||||
// interlaced - float neighbouring electrodes
|
||||
TSC->CR |= TSC_CR_IODEF;
|
||||
} else {
|
||||
TSC->IOGCSR = priv->groups_phase[priv->next_phase];
|
||||
TSC->IOCCR = priv->channels_phase[priv->next_phase];
|
||||
|
||||
// separate - keep neighbouring electrodes at GND
|
||||
}
|
||||
|
||||
TSC->ICR = TSC_ICR_EOAIC | TSC_ICR_MCEIC;
|
||||
|
||||
// Go!
|
||||
priv->ongoing = true;
|
||||
TSC->CR |= TSC_CR_START;
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
|
||||
#define TOUCH_INTERNAL
|
||||
|
||||
#include "_touch_internal.h"
|
||||
|
||||
/** Allocate data structure and set defaults */
|
||||
error_t UTOUCH_preInit(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
|
||||
if (priv == NULL) return E_OUT_OF_MEM;
|
||||
|
||||
priv->cfg.charge_time = 2;
|
||||
priv->cfg.drain_time = 2;
|
||||
priv->cfg.spread_deviation = 0;
|
||||
priv->cfg.ss_presc = 1;
|
||||
priv->cfg.pg_presc = 32;
|
||||
priv->cfg.sense_timeout = 7;
|
||||
memset(priv->cfg.group_scaps, 0, 8);
|
||||
memset(priv->cfg.group_channels, 0, 8);
|
||||
priv->cfg.binary_hysteresis = 10;
|
||||
priv->cfg.binary_debounce_ms = 20;
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/** Finalize unit set-up */
|
||||
error_t UTOUCH_init(Unit *unit)
|
||||
{
|
||||
bool suc = true;
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
unit->tick_interval = 1; // sample every 1 ms
|
||||
|
||||
// copy from conf
|
||||
priv->binary_debounce_ms = priv->cfg.binary_debounce_ms;
|
||||
priv->binary_hysteresis = priv->cfg.binary_hysteresis;
|
||||
|
||||
TRY(rsc_claim(unit, R_TSC));
|
||||
|
||||
// simple bound checks, just clamp without error
|
||||
if (priv->cfg.charge_time > 16) priv->cfg.charge_time = 16;
|
||||
if (priv->cfg.charge_time < 1) priv->cfg.charge_time = 1;
|
||||
|
||||
if (priv->cfg.drain_time > 16) priv->cfg.drain_time = 16;
|
||||
if (priv->cfg.drain_time < 1) priv->cfg.drain_time = 1;
|
||||
|
||||
if (priv->cfg.spread_deviation > 128) priv->cfg.drain_time = 128;
|
||||
|
||||
if (priv->cfg.ss_presc > 2) priv->cfg.ss_presc = 2;
|
||||
if (priv->cfg.ss_presc < 1) priv->cfg.ss_presc = 1;
|
||||
|
||||
if (priv->cfg.sense_timeout > 7) priv->cfg.sense_timeout = 7;
|
||||
if (priv->cfg.sense_timeout < 1) priv->cfg.sense_timeout = 1;
|
||||
|
||||
uint8_t tmppgpresc = priv->cfg.pg_presc;
|
||||
if (tmppgpresc == 0) return E_BAD_CONFIG;
|
||||
uint8_t pgpresc_reg = 0;
|
||||
while ((tmppgpresc & 1) == 0 && tmppgpresc != 0) {
|
||||
pgpresc_reg++;
|
||||
tmppgpresc >>= 1;
|
||||
}
|
||||
if (tmppgpresc != 1 || pgpresc_reg > 7) {
|
||||
dbg("Bad pgpresc");
|
||||
return E_BAD_CONFIG; // TODO better reporting
|
||||
}
|
||||
|
||||
if ((pgpresc_reg==0 && priv->cfg.drain_time<=2) || (pgpresc_reg==1 && priv->cfg.drain_time==0)) {
|
||||
dbg("Illegal PGPSC vs CTPL");
|
||||
return E_BAD_CONFIG;
|
||||
}
|
||||
|
||||
// enable clock
|
||||
hw_periph_clock_enable(TSC);
|
||||
// reset
|
||||
__HAL_RCC_TSC_FORCE_RESET();
|
||||
__HAL_RCC_TSC_RELEASE_RESET();
|
||||
|
||||
priv->all_channels_mask = 0;
|
||||
|
||||
for (int gi = 0; gi < 8; gi++) {
|
||||
const uint8_t cap = priv->cfg.group_scaps[gi];
|
||||
const uint8_t ch = priv->cfg.group_channels[gi];
|
||||
|
||||
if (cap == 0) {
|
||||
if (ch != 0) {
|
||||
dbg_touch("TSC group %d has no cap!", (int) (gi + 1));
|
||||
return E_BAD_CONFIG;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch == 0) continue; // if no channels, don't bother setting up anything
|
||||
|
||||
if (cap != 2 && cap != 4 && cap != 8 && cap != 16) {
|
||||
dbg_touch("TSC group %d has more than 1 cap!", (int) (gi + 1));
|
||||
return E_BAD_CONFIG;
|
||||
}
|
||||
|
||||
if (cap & ch) {
|
||||
dbg_touch("TSC pin can't be both channel and cap! (gpr %d)", (int) (gi + 1));
|
||||
return E_BAD_CONFIG;
|
||||
}
|
||||
|
||||
// This is a loop through the pins in a group gi
|
||||
int phasenum = 0;
|
||||
for (int pi = 0; pi < 4; pi++) {
|
||||
// pin numbers are 1-based in the config
|
||||
const bool iscap = 0 != (cap & (2 << pi));
|
||||
const bool isch = 0 != (ch & (2 << pi));
|
||||
|
||||
if (!iscap && !isch) continue;
|
||||
|
||||
Resource r = utouch_group_rscs[gi][pi];
|
||||
TRY(rsc_claim(unit, r));
|
||||
|
||||
GPIO_TypeDef *port;
|
||||
uint32_t ll;
|
||||
assert_param(hw_pinrsc2ll(r, &port, &ll));
|
||||
LL_GPIO_SetPinOutputType(port, ll, isch ? LL_GPIO_OUTPUT_PUSHPULL : LL_GPIO_OUTPUT_OPENDRAIN);
|
||||
|
||||
// 7 and 8 (1-based) use AF1, else AF3
|
||||
TRY(hw_configure_gpiorsc_af(r, gi >= 6 ? LL_GPIO_AF_1 : LL_GPIO_AF_3));
|
||||
|
||||
uint32_t bit = (uint32_t) (1 << (gi * 4 + pi));
|
||||
|
||||
if (iscap) {
|
||||
dbg_touch("TSC cap @ %s", rsc_get_name(r));
|
||||
// Sampling cap
|
||||
TSC->IOSCR |= bit;
|
||||
|
||||
// Disable pin hysteresis (causes noise)
|
||||
TSC->IOHCR ^= bit;
|
||||
}
|
||||
else {
|
||||
dbg_touch("TSC ch @ %s", rsc_get_name(r));
|
||||
|
||||
if (priv->cfg.interlaced) {
|
||||
// interlaced - only update the mask beforehand
|
||||
priv->all_channels_mask |= bit;
|
||||
} else {
|
||||
// channels are configured individually when read.
|
||||
// we prepare bitmaps to use for the read groups (all can be read in at most 3 steps)
|
||||
priv->channels_phase[phasenum] |= bit; // this is used for the channel selection register
|
||||
priv->groups_phase[phasenum] |= 1 << gi; // this will be used for the group enable register, if all 0, this and any following phases are unused.
|
||||
phasenum++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// common TSC config
|
||||
TSC->CR =
|
||||
((priv->cfg.charge_time - 1) << TSC_CR_CTPH_Pos) |
|
||||
((priv->cfg.drain_time - 1) << TSC_CR_CTPL_Pos) |
|
||||
((priv->cfg.ss_presc - 1) << TSC_CR_SSPSC_Pos) |
|
||||
(pgpresc_reg << TSC_CR_PGPSC_Pos) |
|
||||
((priv->cfg.sense_timeout - 1) << TSC_CR_MCV_Pos) |
|
||||
TSC_CR_TSCE;
|
||||
|
||||
if (priv->cfg.spread_deviation > 0) {
|
||||
TSC->CR |= ((priv->cfg.spread_deviation - 1) << TSC_CR_SSD_Pos) | TSC_CR_SSE;
|
||||
}
|
||||
|
||||
dbg_touch("CR = %08x, ht is %d, lt is %d", (int)TSC->CR,
|
||||
(int)priv->cfg.charge_time,
|
||||
(int)priv->cfg.drain_time);
|
||||
|
||||
// iofloat is used for discharging
|
||||
|
||||
// Enable the interrupts
|
||||
TSC->IER = TSC_IER_EOAIE | TSC_IER_MCEIE;
|
||||
irqd_attach(TSC, UTOUCH_HandleIrq, unit);
|
||||
|
||||
if (!priv->cfg.interlaced) {
|
||||
dbg_touch("TSC phases:");
|
||||
for (int i = 0; i < 3; i++) {
|
||||
priv->all_channels_mask |= priv->channels_phase[i];
|
||||
|
||||
dbg_touch(" %d: ch %08"PRIx32", g %02"PRIx32,
|
||||
i + 1,
|
||||
priv->channels_phase[i],
|
||||
(uint32_t) priv->groups_phase[i]);
|
||||
}
|
||||
}
|
||||
|
||||
priv->status = UTSC_STATUS_BUSY; // first loop ...
|
||||
priv->next_phase = 0;
|
||||
|
||||
// starts in the tick callback
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/** Tear down the unit */
|
||||
void UTOUCH_deInit(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
// de-init peripherals
|
||||
if (unit->status == E_SUCCESS) {
|
||||
hw_periph_clock_disable(TSC);
|
||||
// clear all registers to their default values
|
||||
__HAL_RCC_TSC_FORCE_RESET();
|
||||
__HAL_RCC_TSC_RELEASE_RESET();
|
||||
|
||||
irqd_detach(TSC, UTOUCH_HandleIrq);
|
||||
}
|
||||
|
||||
// Release all resources, deinit pins
|
||||
rsc_teardown(unit);
|
||||
|
||||
// Free memory
|
||||
free_ck(unit->data);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#ifndef GEX_F072_TOUCH_INTERNAL_H
|
||||
#define GEX_F072_TOUCH_INTERNAL_H
|
||||
|
||||
#ifndef TOUCH_INTERNAL
|
||||
#error bad include!
|
||||
#endif
|
||||
|
||||
#include "unit_base.h"
|
||||
|
||||
#define TSC_DEBUG 0
|
||||
|
||||
#if TSC_DEBUG
|
||||
#define dbg_touch(f,...) dbg(f,##__VA_ARGS__)
|
||||
#else
|
||||
#define dbg_touch(f,...) do{}while(0)
|
||||
#endif
|
||||
|
||||
enum utsc_status {
|
||||
UTSC_STATUS_BUSY = 0,
|
||||
UTSC_STATUS_READY = 1,
|
||||
UTSC_STATUS_FAIL = 2
|
||||
};
|
||||
|
||||
/** Private data structure */
|
||||
struct priv {
|
||||
// settings
|
||||
struct {
|
||||
uint8_t charge_time; // 1-16 -> 0..15
|
||||
uint8_t drain_time; // 1-16 -> 0..15
|
||||
uint8_t spread_deviation; // 1-128, 0=off ... 0-127, 0 sets 0 to SSE
|
||||
uint8_t ss_presc; // 1-2 -> 0..1
|
||||
uint8_t pg_presc; // 1,2,4,8,16,32,64,128 -> 0..7 when writing to the periph
|
||||
uint8_t sense_timeout; // 1-7 -> 0..6 hex when writing to the periph
|
||||
// the schmitts must be disabled on all used channels, restored to 0xFFFF on deinit
|
||||
uint8_t group_scaps[8];
|
||||
uint8_t group_channels[8];
|
||||
bool interlaced;
|
||||
uint16_t binary_debounce_ms;
|
||||
uint16_t binary_hysteresis;
|
||||
} cfg;
|
||||
|
||||
uint8_t next_phase;
|
||||
uint8_t discharge_delay;
|
||||
uint32_t channels_phase[3];
|
||||
uint8_t groups_phase[3];
|
||||
uint16_t readouts[32];
|
||||
int16_t bin_trig_cnt[32];
|
||||
uint16_t binary_debounce_ms;
|
||||
uint16_t binary_hysteresis;
|
||||
uint16_t binary_thr[32];
|
||||
uint32_t binary_active_bits;
|
||||
uint32_t all_channels_mask;
|
||||
uint32_t last_done_ms;
|
||||
bool ongoing;
|
||||
|
||||
enum utsc_status status;
|
||||
} __attribute__((packed));
|
||||
|
||||
extern const char *utouch_group_labels[8];
|
||||
extern const Resource utouch_group_rscs[8][4];
|
||||
|
||||
/** Allocate data structure and set defaults */
|
||||
error_t UTOUCH_preInit(Unit *unit);
|
||||
|
||||
/** Load from a binary buffer stored in Flash */
|
||||
void UTOUCH_loadBinary(Unit *unit, PayloadParser *pp);
|
||||
|
||||
/** Write to a binary buffer for storing in Flash */
|
||||
void UTOUCH_writeBinary(Unit *unit, PayloadBuilder *pb);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Parse a key-value pair from the INI file */
|
||||
error_t UTOUCH_loadIni(Unit *unit, const char *key, const char *value);
|
||||
|
||||
/** Generate INI file section for the unit */
|
||||
void UTOUCH_writeIni(Unit *unit, IniWriter *iw);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Finalize unit set-up */
|
||||
error_t UTOUCH_init(Unit *unit);
|
||||
|
||||
/** Tear down the unit */
|
||||
void UTOUCH_deInit(Unit *unit);
|
||||
|
||||
void UTOUCH_updateTick(Unit *unit);
|
||||
|
||||
void UTOUCH_HandleIrq(void *arg);
|
||||
|
||||
#endif //GEX_F072_TOUCH_INTERNAL_H
|
||||
@@ -0,0 +1,187 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/02/03.
|
||||
//
|
||||
|
||||
#include "platform.h"
|
||||
#include "unit_base.h"
|
||||
|
||||
#define TOUCH_INTERNAL
|
||||
#include "_touch_internal.h"
|
||||
|
||||
const char *utouch_group_labels[8] = {
|
||||
"1:A0, 2:A1, 3:A2, 4:A3",
|
||||
"1:A4, 2:A5, 3:A6, 4:A7",
|
||||
"1:C5, 2:B0, 3:B1, 4:B2",
|
||||
"1:A9, 2:A10, 3:A11, 4:A12",
|
||||
"1:B3, 2:B4, 3:B6, 4:B7",
|
||||
"1:B11, 2:B12, 3:B13, 4:B14",
|
||||
"1:E2, 2:E3, 3:E4, 4:E5",
|
||||
"1:D12, 2:D13, 3:D14, 4:D15",
|
||||
};
|
||||
|
||||
const Resource utouch_group_rscs[8][4] = {
|
||||
{R_PA0, R_PA1, R_PA2, R_PA3},
|
||||
{R_PA4, R_PA5, R_PA6, R_PA7},
|
||||
{R_PC5, R_PB0, R_PB1, R_PB2},
|
||||
{R_PA9, R_PA10, R_PA11, R_PA12},
|
||||
{R_PB3, R_PB4, R_PB6, R_PB7},
|
||||
{R_PB11, R_PB12, R_PB13, R_PB14},
|
||||
{R_PE2, R_PE3, R_PE4, R_PE5},
|
||||
{R_PD12, R_PD13, R_PD14, R_PD15},
|
||||
};
|
||||
|
||||
/** Load from a binary buffer stored in Flash */
|
||||
void UTOUCH_loadBinary(Unit *unit, PayloadParser *pp)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
uint8_t version = pp_u8(pp);
|
||||
(void)version;
|
||||
|
||||
priv->cfg.charge_time = pp_u8(pp);
|
||||
priv->cfg.drain_time = pp_u8(pp);
|
||||
priv->cfg.spread_deviation = pp_u8(pp);
|
||||
priv->cfg.ss_presc = pp_u8(pp);
|
||||
priv->cfg.pg_presc = pp_u8(pp);
|
||||
priv->cfg.sense_timeout = pp_u8(pp);
|
||||
pp_buf(pp, priv->cfg.group_scaps, 8);
|
||||
pp_buf(pp, priv->cfg.group_channels, 8);
|
||||
|
||||
if (version >= 1) {
|
||||
priv->cfg.interlaced = pp_bool(pp);
|
||||
}
|
||||
|
||||
if (version >= 2) {
|
||||
priv->cfg.binary_debounce_ms = pp_u16(pp);
|
||||
priv->cfg.binary_hysteresis = pp_u16(pp);
|
||||
}
|
||||
}
|
||||
|
||||
/** Write to a binary buffer for storing in Flash */
|
||||
void UTOUCH_writeBinary(Unit *unit, PayloadBuilder *pb)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
pb_u8(pb, 2); // version
|
||||
|
||||
pb_u8(pb, priv->cfg.charge_time);
|
||||
pb_u8(pb, priv->cfg.drain_time);
|
||||
pb_u8(pb, priv->cfg.spread_deviation);
|
||||
pb_u8(pb, priv->cfg.ss_presc);
|
||||
pb_u8(pb, priv->cfg.pg_presc);
|
||||
pb_u8(pb, priv->cfg.sense_timeout);
|
||||
pb_buf(pb, priv->cfg.group_scaps, 8);
|
||||
pb_buf(pb, priv->cfg.group_channels, 8);
|
||||
pb_bool(pb, priv->cfg.interlaced);
|
||||
pb_u16(pb, priv->cfg.binary_debounce_ms);
|
||||
pb_u16(pb, priv->cfg.binary_hysteresis);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Parse a key-value pair from the INI file */
|
||||
error_t UTOUCH_loadIni(Unit *unit, const char *key, const char *value)
|
||||
{
|
||||
bool suc = true;
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
if (streq(key, "charge-time")) {
|
||||
priv->cfg.charge_time = cfg_u8_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "drain-time")) {
|
||||
priv->cfg.drain_time = cfg_u8_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "ss-deviation")) {
|
||||
priv->cfg.spread_deviation = cfg_u8_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "ss-clock-prediv")) {
|
||||
priv->cfg.ss_presc = cfg_u8_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "pg-clock-prediv")) {
|
||||
priv->cfg.pg_presc = cfg_u8_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "sense-timeout")) {
|
||||
priv->cfg.sense_timeout = cfg_u8_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "interlaced-pads")) {
|
||||
priv->cfg.interlaced = cfg_bool_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "btn-debounce")) {
|
||||
priv->cfg.binary_debounce_ms = cfg_u16_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "btn-hysteresis")) {
|
||||
priv->cfg.binary_hysteresis = cfg_u16_parse(value, &suc);
|
||||
}
|
||||
else {
|
||||
volatile char namebuf[10]; // must be volatile or gcc optimizes out the second compare and fucks it up
|
||||
|
||||
for (int i = 0; i < 6; i++) { // skip 7,8
|
||||
SPRINTF(namebuf, "g%d_cap", i+1);
|
||||
if (streq(key, namebuf)) {
|
||||
priv->cfg.group_scaps[i] = (uint8_t) cfg_pinmask_parse(value, &suc);
|
||||
goto matched;
|
||||
}
|
||||
|
||||
SPRINTF(namebuf, "g%d_ch", i+1);
|
||||
if (streq(key, namebuf)) {
|
||||
priv->cfg.group_channels[i] = (uint8_t) cfg_pinmask_parse(value, &suc);
|
||||
goto matched;
|
||||
}
|
||||
}
|
||||
|
||||
return E_BAD_KEY;
|
||||
}
|
||||
|
||||
matched:
|
||||
if (!suc) return E_BAD_VALUE;
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
/** Generate INI file section for the unit */
|
||||
void UTOUCH_writeIni(Unit *unit, IniWriter *iw)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
iw_comment(iw, "This unit utilizes the touch sensing controller.");
|
||||
iw_comment(iw, "See the reference manual for details about its function.");
|
||||
iw_cmt_newline(iw);
|
||||
|
||||
iw_comment(iw, "Pulse generator clock prescaller (1,2,4,...,128)");
|
||||
iw_entry_d(iw, "pg-clock-prediv", priv->cfg.pg_presc);
|
||||
iw_comment(iw, "Sense pad charging time (1-16)");
|
||||
iw_entry_d(iw, "charge-time", priv->cfg.charge_time);
|
||||
iw_comment(iw, "Charge transfer time (1-16)");
|
||||
iw_entry_d(iw, "drain-time", priv->cfg.drain_time);
|
||||
iw_comment(iw, "Measurement timeout (1-7)");
|
||||
iw_entry_d(iw, "sense-timeout", priv->cfg.sense_timeout);
|
||||
|
||||
iw_cmt_newline(iw);
|
||||
iw_comment(iw, "Spread spectrum max deviation (0-128,0=off)");
|
||||
iw_entry_d(iw, "ss-deviation", priv->cfg.spread_deviation);
|
||||
iw_comment(iw, "Spreading clock prescaller (1,2)");
|
||||
iw_entry_d(iw, "ss-clock-prediv", priv->cfg.ss_presc);
|
||||
|
||||
iw_cmt_newline(iw);
|
||||
iw_comment(iw, "Optimize for interlaced pads (individual sampling with others floating)");
|
||||
iw_entry_s(iw, "interlaced-pads", str_yn(priv->cfg.interlaced));
|
||||
|
||||
iw_cmt_newline(iw);
|
||||
iw_comment(iw, "Button mode debounce (ms) and release hysteresis (lsb)");
|
||||
iw_entry_d(iw, "btn-debounce", priv->cfg.binary_debounce_ms);
|
||||
iw_entry_d(iw, "btn-hysteresis", priv->cfg.binary_hysteresis);
|
||||
|
||||
iw_cmt_newline(iw);
|
||||
iw_comment(iw, "Each used group must have 1 sampling capacitor and 1-3 channels.");
|
||||
iw_comment(iw, "Channels are numbered 1,2,3,4");
|
||||
iw_cmt_newline(iw);
|
||||
|
||||
char namebuf[10];
|
||||
for (int i = 0; i < 6; i++) { // skip 7,8
|
||||
iw_commentf(iw, "Group%d - %s", i+1, utouch_group_labels[i]);
|
||||
SPRINTF(namebuf, "g%d_cap", i+1);
|
||||
iw_entry_s(iw, namebuf, cfg_pinmask_encode(priv->cfg.group_scaps[i], unit_tmp512, true));
|
||||
SPRINTF(namebuf, "g%d_ch", i+1);
|
||||
iw_entry_s(iw, namebuf, cfg_pinmask_encode(priv->cfg.group_channels[i], unit_tmp512, true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/25.
|
||||
//
|
||||
|
||||
#include "unit_base.h"
|
||||
#include "unit_touch.h"
|
||||
|
||||
#define TOUCH_INTERNAL
|
||||
#include "_touch_internal.h"
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
enum TouchCmd_ {
|
||||
CMD_READ=0,
|
||||
CMD_SET_BIN_THR=1,
|
||||
CMD_DISABLE_ALL_REPORTS=2,
|
||||
CMD_SET_DEBOUNCE_TIME=3,
|
||||
CMD_SET_HYSTERESIS=4,
|
||||
CMD_GET_CH_COUNT=10,
|
||||
};
|
||||
|
||||
/** Handle a request message */
|
||||
static error_t UTOUCH_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
|
||||
{
|
||||
struct priv* priv = unit->data;
|
||||
PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL);
|
||||
|
||||
switch (command) {
|
||||
/**
|
||||
* read the current touch pad values (smaller = higher capacity)
|
||||
*
|
||||
* resp: a list of u16 (order: group and pin, ascending)
|
||||
*/
|
||||
case CMD_READ:
|
||||
if (priv->status == UTSC_STATUS_BUSY) return E_BUSY;
|
||||
if (priv->status == UTSC_STATUS_FAIL) return E_HW_TIMEOUT;
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (priv->all_channels_mask & (1<<i)) {
|
||||
pb_u16(&pb, priv->readouts[i]);
|
||||
}
|
||||
}
|
||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Set thresholds for the button mode.
|
||||
*
|
||||
* pld: a list of u16 for the enabled channels (order: group and pin, ascending)
|
||||
*/
|
||||
case CMD_SET_BIN_THR:
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (priv->all_channels_mask & (1<<i)) {
|
||||
priv->bin_trig_cnt[i] = 0;
|
||||
priv->binary_thr[i] = pp_u16(pp);
|
||||
if (priv->readouts[i] >= (priv->binary_thr[i] + priv->binary_hysteresis)) {
|
||||
priv->binary_active_bits |= 1<<i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Set the debounce time in ms (replaces the default value from settings)
|
||||
*
|
||||
* pld: ms:u16
|
||||
*/
|
||||
case CMD_SET_DEBOUNCE_TIME:
|
||||
priv->binary_debounce_ms = pp_u16(pp);
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Set hysteresis (replaces the default value from settings)
|
||||
*
|
||||
* Hysteresis is added to the threshold value for the switch-off level
|
||||
* (switch-off happens when the measured value is exceeded - capacity of the pad drops)
|
||||
*
|
||||
* pld: hyst:u16
|
||||
*/
|
||||
case CMD_SET_HYSTERESIS:
|
||||
priv->binary_hysteresis = pp_u16(pp);
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Disable button mode reports. This effectively sets all thresholds to 0, disabling checking.
|
||||
*/
|
||||
case CMD_DISABLE_ALL_REPORTS:
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (priv->all_channels_mask & (1<<i)) {
|
||||
priv->binary_thr[i] = 0;
|
||||
priv->bin_trig_cnt[i] = 0;
|
||||
}
|
||||
}
|
||||
priv->binary_active_bits = 0;
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Get the number of configured touch pad channels
|
||||
*
|
||||
* resp: count:u8
|
||||
*/
|
||||
case CMD_GET_CH_COUNT:;
|
||||
uint8_t nb = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (priv->all_channels_mask & (1<<i)) {
|
||||
nb++;
|
||||
}
|
||||
}
|
||||
pb_u8(&pb, nb);
|
||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
||||
return E_SUCCESS;
|
||||
|
||||
default:
|
||||
return E_UNKNOWN_COMMAND;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Unit template */
|
||||
const UnitDriver UNIT_TOUCH = {
|
||||
.name = "TOUCH",
|
||||
.description = "Capacitive touch sensing",
|
||||
// Settings
|
||||
.preInit = UTOUCH_preInit,
|
||||
.cfgLoadBinary = UTOUCH_loadBinary,
|
||||
.cfgWriteBinary = UTOUCH_writeBinary,
|
||||
.cfgLoadIni = UTOUCH_loadIni,
|
||||
.cfgWriteIni = UTOUCH_writeIni,
|
||||
// Init
|
||||
.init = UTOUCH_init,
|
||||
.deInit = UTOUCH_deInit,
|
||||
// Function
|
||||
.handleRequest = UTOUCH_handleRequest,
|
||||
.updateTick = UTOUCH_updateTick,
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/25.
|
||||
//
|
||||
// Digital input unit; single or multiple pin read access on one port (A-F)
|
||||
//
|
||||
|
||||
#ifndef U_TOUCH_H
|
||||
#define U_TOUCH_H
|
||||
|
||||
#include "unit.h"
|
||||
|
||||
extern const UnitDriver UNIT_TOUCH;
|
||||
|
||||
// UU_ prototypes
|
||||
|
||||
#endif //U_TOUCH_H
|
||||
@@ -111,7 +111,7 @@ static inline error_t UUSART_configPins(Unit *unit)
|
||||
want_rts_pin(priv)
|
||||
};
|
||||
|
||||
#if GEX_PLAT_F072_DISCOVERY
|
||||
#if STM32F072xB
|
||||
|
||||
const struct PinAF *mappings = NULL;
|
||||
|
||||
|
||||
@@ -156,10 +156,10 @@ void UUSART_writeIni(Unit *unit, IniWriter *iw)
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
iw_comment(iw, "Peripheral number (UARTx 1-4)");
|
||||
iw_entry(iw, "device", "%d", (int)priv->periph_num);
|
||||
iw_entry_d(iw, "device", priv->periph_num);
|
||||
|
||||
iw_comment(iw, "Pin mappings (TX,RX,CK,CTS,RTS/DE)");
|
||||
#if GEX_PLAT_F072_DISCOVERY
|
||||
#if STM32F072xB
|
||||
iw_comment(iw, " USART1: (0) A9,A10,A8,A11,A12 (1) B6,B7,A8,A11,A12");
|
||||
iw_comment(iw, " USART2: (0) A2,A3,A4,A0,A1 (1) A14,A15,A4,A0,A1");
|
||||
iw_comment(iw, " USART3: (0) B10,B11,B12,B13,B14");
|
||||
@@ -173,41 +173,41 @@ void UUSART_writeIni(Unit *unit, IniWriter *iw)
|
||||
#else
|
||||
#error "BAD PLATFORM!"
|
||||
#endif
|
||||
iw_entry(iw, "remap", "%d", (int)priv->remap);
|
||||
iw_entry_d(iw, "remap", priv->remap);
|
||||
|
||||
iw_cmt_newline(iw);
|
||||
iw_comment(iw, "Baud rate in bps (eg. 9600, 115200)"); // TODO examples/range
|
||||
iw_entry(iw, "baud-rate", "%d", (int)priv->baudrate);
|
||||
iw_comment(iw, "Baud rate in bps (eg. 9600)");
|
||||
iw_entry_d(iw, "baud-rate", priv->baudrate);
|
||||
|
||||
iw_comment(iw, "Parity type (NONE, ODD, EVEN)");
|
||||
iw_entry(iw, "parity", cfg_enum3_encode(priv->parity,
|
||||
iw_entry_s(iw, "parity", cfg_enum3_encode(priv->parity,
|
||||
0, "NONE",
|
||||
1, "ODD",
|
||||
2, "EVEN"));
|
||||
|
||||
iw_comment(iw, "Number of stop bits (0.5, 1, 1.5, 2)");
|
||||
iw_entry(iw, "stop-bits", cfg_enum4_encode(priv->stopbits,
|
||||
iw_entry_s(iw, "stop-bits", cfg_enum4_encode(priv->stopbits,
|
||||
0, "0.5",
|
||||
1, "1",
|
||||
2, "1.5",
|
||||
3, "2"));
|
||||
|
||||
iw_comment(iw, "Bit order (LSB or MSB first)");
|
||||
iw_entry(iw, "first-bit", cfg_enum2_encode((uint32_t) priv->lsb_first,
|
||||
iw_entry_s(iw, "first-bit", cfg_enum2_encode((uint32_t) priv->lsb_first,
|
||||
0, "MSB",
|
||||
1, "LSB"));
|
||||
|
||||
iw_comment(iw, "Word width (7,8,9) - including parity bit if used");
|
||||
iw_entry(iw, "word-width", "%d", (int)priv->width);
|
||||
iw_entry_d(iw, "word-width", (int)priv->width);
|
||||
|
||||
iw_comment(iw, "Enabled lines (RX,TX,RXTX)");
|
||||
iw_entry(iw, "direction", cfg_enum3_encode(priv->direction,
|
||||
iw_entry_s(iw, "direction", cfg_enum3_encode(priv->direction,
|
||||
1, "RX",
|
||||
2, "TX",
|
||||
3, "RXTX"));
|
||||
|
||||
iw_comment(iw, "Hardware flow control (NONE, RTS, CTS, FULL)");
|
||||
iw_entry(iw, "hw-flow-control", cfg_enum4_encode(priv->hw_flow_control,
|
||||
iw_entry_s(iw, "hw-flow-control", cfg_enum4_encode(priv->hw_flow_control,
|
||||
0, "NONE",
|
||||
1, "RTS",
|
||||
2, "CTS",
|
||||
@@ -215,19 +215,19 @@ void UUSART_writeIni(Unit *unit, IniWriter *iw)
|
||||
|
||||
iw_cmt_newline(iw);
|
||||
iw_comment(iw, "Generate serial clock (Y,N)");
|
||||
iw_entry(iw, "clock-output", str_yn(priv->clock_output));
|
||||
iw_comment(iw, "Output clock polarity: 0,1 (clock idle level)");
|
||||
iw_entry(iw, "cpol", "%d", (int)priv->cpol);
|
||||
iw_comment(iw, "Output clock phase: 0,1 (active edge, 0-first, 1-second)");
|
||||
iw_entry(iw, "cpha", "%d", (int)priv->cpha);
|
||||
iw_entry_s(iw, "clock-output", str_yn(priv->clock_output));
|
||||
iw_comment(iw, "Clock polarity: 0,1");
|
||||
iw_entry_d(iw, "cpol", priv->cpol);
|
||||
iw_comment(iw, "Clock phase: 0,1");
|
||||
iw_entry_d(iw, "cpha", priv->cpha);
|
||||
|
||||
iw_cmt_newline(iw);
|
||||
iw_comment(iw, "Generate RS485 Driver Enable signal (Y,N) - uses RTS pin");
|
||||
iw_entry(iw, "de-output", str_yn(priv->de_output));
|
||||
iw_entry_s(iw, "de-output", str_yn(priv->de_output));
|
||||
iw_comment(iw, "DE active level: 0,1");
|
||||
iw_entry(iw, "de-polarity", "%d", (int)(priv->de_polarity));
|
||||
iw_entry_d(iw, "de-polarity", (priv->de_polarity));
|
||||
iw_comment(iw, "DE assert time (0-31)");
|
||||
iw_entry(iw, "de-assert-time", "%d", (int)(priv->de_assert_time));
|
||||
iw_entry_d(iw, "de-assert-time", (priv->de_assert_time));
|
||||
iw_comment(iw, "DE clear time (0-31)");
|
||||
iw_entry(iw, "de-clear-time", "%d", (int)(priv->de_clear_time));
|
||||
iw_entry_d(iw, "de-clear-time", (priv->de_clear_time));
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ void UUSART_Tick(Unit *unit)
|
||||
}
|
||||
|
||||
enum PinCmd_ {
|
||||
CMD_WRITE = 0,
|
||||
CMD_QUERY = 0,
|
||||
CMD_WRITE_SYNC = 1,
|
||||
};
|
||||
|
||||
@@ -103,7 +103,7 @@ static error_t UUSART_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command,
|
||||
const uint8_t *pld;
|
||||
switch (command) {
|
||||
/** Write bytes to the USART. Payload consists of the data to send. Waits for completion. */
|
||||
case CMD_WRITE:
|
||||
case CMD_QUERY:
|
||||
pld = pp_tail(pp, &len);
|
||||
TRY(UU_USART_Write(unit, pld, len));
|
||||
return E_SUCCESS;
|
||||
|
||||
+111
-502
@@ -1,526 +1,135 @@
|
||||
|
||||
/* #line 1 "ini_parser.rl" */
|
||||
|
||||
/* Ragel constants block */
|
||||
#include "ini_parser.h"
|
||||
|
||||
// Ragel setup
|
||||
|
||||
/* #line 10 "ini_parser.c" */
|
||||
static const char _ini_actions[] = {
|
||||
0, 1, 1, 1, 2, 1, 3, 1,
|
||||
4, 1, 5, 1, 6, 1, 7, 1,
|
||||
8, 1, 9, 1, 10, 1, 11, 1,
|
||||
13, 2, 0, 4, 2, 12, 4
|
||||
enum nini_state {
|
||||
NINI_IDLE,
|
||||
NINI_SECTION,
|
||||
NINI_KEY,
|
||||
NINI_VALUE,
|
||||
NINI_COMMENT,
|
||||
};
|
||||
|
||||
static const char _ini_eof_actions[] = {
|
||||
0, 23, 5, 5, 15, 15, 15, 15,
|
||||
19, 19, 0, 0, 0, 0, 0, 0,
|
||||
0
|
||||
};
|
||||
static struct {
|
||||
uint8_t section_i;
|
||||
char section[INI_KEY_MAX];
|
||||
|
||||
static const int ini_start = 1;
|
||||
static const int ini_first_final = 12;
|
||||
static const int ini_error = 0;
|
||||
uint8_t key_i;
|
||||
char key[INI_KEY_MAX];
|
||||
|
||||
static const int ini_en_section = 2;
|
||||
static const int ini_en_keyvalue = 4;
|
||||
static const int ini_en_comment = 8;
|
||||
static const int ini_en_discard2eol = 10;
|
||||
static const int ini_en_main = 1;
|
||||
uint8_t value_i;
|
||||
char value[INI_VALUE_MAX];
|
||||
bool val_last_space;
|
||||
|
||||
IniParserCallback cb;
|
||||
void *userdata;
|
||||
enum nini_state state;
|
||||
} nini;
|
||||
|
||||
/* #line 10 "ini_parser.rl" */
|
||||
|
||||
|
||||
// Persistent state
|
||||
static int8_t cs = -1; //!< Ragel's Current State variable
|
||||
static uint32_t buff_i = 0; //!< Write pointer for the buffers
|
||||
static char value_quote = 0; //!< Quote character of the currently collected value
|
||||
static bool value_nextesc = false; //!< Next character is escaped, trated specially, and if quote, as literal quote character
|
||||
static IniParserCallback keyCallback = NULL; //!< Currently assigned callback
|
||||
static void *userdata = NULL; //!< Currently assigned user data for the callback
|
||||
|
||||
// Buffers
|
||||
static char keybuf[INI_KEY_MAX];
|
||||
static char secbuf[INI_KEY_MAX+10];
|
||||
static char valbuf[INI_VALUE_MAX];
|
||||
|
||||
// See header for doxygen!
|
||||
|
||||
void
|
||||
ini_parse_reset_partial(void)
|
||||
void ini_parse_begin(IniParserCallback callback, void *userData)
|
||||
{
|
||||
buff_i = 0;
|
||||
value_quote = 0;
|
||||
value_nextesc = false;
|
||||
ini_parse_reset();
|
||||
nini.cb = callback;
|
||||
nini.userdata = userData;
|
||||
}
|
||||
|
||||
void
|
||||
ini_parse_reset(void)
|
||||
void ini_parse(const char *data, size_t len)
|
||||
{
|
||||
ini_parse_reset_partial();
|
||||
keybuf[0] = secbuf[0] = valbuf[0] = 0;
|
||||
for (; len > 0; len--) {
|
||||
char c = *data++;
|
||||
if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
|
||||
if (nini.state != NINI_VALUE && nini.state != NINI_COMMENT)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* #line 67 "ini_parser.c" */
|
||||
{
|
||||
cs = ini_start;
|
||||
}
|
||||
switch (nini.state) {
|
||||
case NINI_IDLE:
|
||||
if (c == '[') {
|
||||
nini.state = NINI_SECTION;
|
||||
nini.section_i = 0;
|
||||
}
|
||||
else if (c == '#') {
|
||||
nini.state = NINI_COMMENT;
|
||||
}
|
||||
else {
|
||||
nini.state = NINI_KEY;
|
||||
nini.key_i = 0;
|
||||
nini.value_i = 0;
|
||||
nini.val_last_space = false;
|
||||
nini.key[nini.key_i++] = c;
|
||||
}
|
||||
break;
|
||||
|
||||
/* #line 41 "ini_parser.rl" */
|
||||
case NINI_COMMENT:
|
||||
if (c == '\n' || c == '\r') {
|
||||
nini.state = NINI_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case NINI_SECTION:
|
||||
if (c == ']') {
|
||||
nini.section[nini.section_i] = 0;
|
||||
nini.state = NINI_COMMENT; // discard to EOL
|
||||
break;
|
||||
}
|
||||
else if (nini.section_i < INI_KEY_MAX - 1) {
|
||||
nini.section[nini.section_i++] = c;
|
||||
}
|
||||
break;
|
||||
|
||||
case NINI_KEY:
|
||||
if (c == '=') {
|
||||
nini.key[nini.key_i] = 0;
|
||||
nini.state = NINI_VALUE;
|
||||
}
|
||||
else if (nini.key_i < INI_KEY_MAX - 1) {
|
||||
nini.key[nini.key_i++] = c;
|
||||
}
|
||||
break;
|
||||
|
||||
case NINI_VALUE:
|
||||
switch (c) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
if (nini.value_i) nini.val_last_space = true;
|
||||
break;
|
||||
case '\r':
|
||||
case '\n':
|
||||
nini.value[nini.value_i] = 0;
|
||||
nini.state = NINI_IDLE;
|
||||
nini.cb(nini.section, nini.key, nini.value, nini.userdata);
|
||||
break;
|
||||
default:
|
||||
if (nini.val_last_space && nini.value_i < INI_VALUE_MAX - 1) {
|
||||
nini.value[nini.value_i++] = ' ';
|
||||
}
|
||||
|
||||
if (nini.value_i < INI_VALUE_MAX - 1) {
|
||||
nini.value[nini.value_i++] = c;
|
||||
}
|
||||
nini.val_last_space = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ini_parser_error(const char* msg)
|
||||
void *ini_parse_end(void)
|
||||
{
|
||||
ini_error("Parser error: %s", msg);
|
||||
ini_parse_reset_partial();
|
||||
if (nini.state == NINI_VALUE) {
|
||||
nini.value[nini.value_i] = 0;
|
||||
nini.state = NINI_IDLE;
|
||||
nini.cb(nini.section, nini.key, nini.value, nini.userdata);
|
||||
}
|
||||
|
||||
return nini.userdata;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ini_parse_begin(IniParserCallback callback, void *userData)
|
||||
void ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData)
|
||||
{
|
||||
keyCallback = callback;
|
||||
userdata = userData;
|
||||
ini_parse_reset();
|
||||
ini_parse_begin(callback, userData);
|
||||
ini_parse(text, len);
|
||||
ini_parse_end();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
*ini_parse_end(void)
|
||||
void ini_parse_reset(void)
|
||||
{
|
||||
ini_parse("\n", 1);
|
||||
if (keyCallback) {
|
||||
keyCallback = NULL;
|
||||
}
|
||||
|
||||
void *ud = userdata;
|
||||
userdata = NULL;
|
||||
return ud;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData)
|
||||
{
|
||||
ini_parse_begin(callback, userData);
|
||||
ini_parse(text, len);
|
||||
ini_parse_end();
|
||||
}
|
||||
|
||||
static void
|
||||
rtrim_buf(char *buf, int32_t end)
|
||||
{
|
||||
if (end > 0) {
|
||||
while ((uint8_t)buf[--end] < 33);
|
||||
end++; // go past the last character
|
||||
}
|
||||
|
||||
buf[end] = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ini_parse(const char *newstr, size_t len)
|
||||
{
|
||||
int32_t i;
|
||||
char c;
|
||||
bool isnl;
|
||||
bool isquot;
|
||||
|
||||
// Load new data to Ragel vars
|
||||
const uint8_t *p;
|
||||
const uint8_t *eof;
|
||||
const uint8_t *pe;
|
||||
|
||||
if (len == 0) while(newstr[++len] != 0); // alternative to strlen
|
||||
|
||||
p = (const uint8_t *) newstr;
|
||||
eof = NULL;
|
||||
pe = (const uint8_t *) (newstr + len);
|
||||
|
||||
// Init Ragel on the first run
|
||||
if (cs == -1) {
|
||||
ini_parse_reset();
|
||||
}
|
||||
|
||||
// The parser
|
||||
|
||||
/* #line 152 "ini_parser.c" */
|
||||
{
|
||||
const char *_acts;
|
||||
unsigned int _nacts;
|
||||
|
||||
if ( p == pe )
|
||||
goto _test_eof;
|
||||
if ( cs == 0 )
|
||||
goto _out;
|
||||
_resume:
|
||||
switch ( cs ) {
|
||||
case 1:
|
||||
switch( (*p) ) {
|
||||
case 32u: goto tr1;
|
||||
case 35u: goto tr3;
|
||||
case 58u: goto tr0;
|
||||
case 59u: goto tr3;
|
||||
case 61u: goto tr0;
|
||||
case 91u: goto tr4;
|
||||
}
|
||||
if ( (*p) < 9u ) {
|
||||
if ( (*p) <= 8u )
|
||||
goto tr0;
|
||||
} else if ( (*p) > 13u ) {
|
||||
if ( 14u <= (*p) && (*p) <= 31u )
|
||||
goto tr0;
|
||||
} else
|
||||
goto tr1;
|
||||
goto tr2;
|
||||
case 0:
|
||||
goto _out;
|
||||
case 12:
|
||||
goto tr0;
|
||||
case 2:
|
||||
switch( (*p) ) {
|
||||
case 9u: goto tr6;
|
||||
case 32u: goto tr6;
|
||||
case 93u: goto tr5;
|
||||
}
|
||||
if ( (*p) <= 31u )
|
||||
goto tr5;
|
||||
goto tr7;
|
||||
case 3:
|
||||
if ( (*p) == 93u )
|
||||
goto tr8;
|
||||
if ( (*p) > 8u ) {
|
||||
if ( 10u <= (*p) && (*p) <= 31u )
|
||||
goto tr5;
|
||||
} else
|
||||
goto tr5;
|
||||
goto tr7;
|
||||
case 13:
|
||||
goto tr5;
|
||||
case 4:
|
||||
switch( (*p) ) {
|
||||
case 10u: goto tr10;
|
||||
case 58u: goto tr11;
|
||||
case 61u: goto tr11;
|
||||
}
|
||||
goto tr9;
|
||||
case 5:
|
||||
switch( (*p) ) {
|
||||
case 9u: goto tr13;
|
||||
case 10u: goto tr14;
|
||||
case 13u: goto tr15;
|
||||
case 32u: goto tr13;
|
||||
}
|
||||
goto tr12;
|
||||
case 6:
|
||||
switch( (*p) ) {
|
||||
case 10u: goto tr14;
|
||||
case 13u: goto tr15;
|
||||
}
|
||||
goto tr12;
|
||||
case 14:
|
||||
goto tr10;
|
||||
case 7:
|
||||
if ( (*p) == 10u )
|
||||
goto tr14;
|
||||
goto tr10;
|
||||
case 8:
|
||||
switch( (*p) ) {
|
||||
case 10u: goto tr17;
|
||||
case 13u: goto tr18;
|
||||
}
|
||||
goto tr16;
|
||||
case 15:
|
||||
goto tr19;
|
||||
case 9:
|
||||
if ( (*p) == 10u )
|
||||
goto tr17;
|
||||
goto tr19;
|
||||
case 10:
|
||||
switch( (*p) ) {
|
||||
case 10u: goto tr21;
|
||||
case 13u: goto tr22;
|
||||
}
|
||||
goto tr20;
|
||||
case 16:
|
||||
goto tr23;
|
||||
case 11:
|
||||
if ( (*p) == 10u )
|
||||
goto tr21;
|
||||
goto tr23;
|
||||
}
|
||||
|
||||
tr23: cs = 0; goto _again;
|
||||
tr0: cs = 0; goto f0;
|
||||
tr5: cs = 0; goto f4;
|
||||
tr10: cs = 0; goto f7;
|
||||
tr19: cs = 0; goto f11;
|
||||
tr1: cs = 1; goto _again;
|
||||
tr6: cs = 2; goto _again;
|
||||
tr7: cs = 3; goto f5;
|
||||
tr9: cs = 4; goto f8;
|
||||
tr13: cs = 5; goto _again;
|
||||
tr11: cs = 5; goto f9;
|
||||
tr12: cs = 6; goto f10;
|
||||
tr15: cs = 7; goto _again;
|
||||
tr16: cs = 8; goto _again;
|
||||
tr18: cs = 9; goto _again;
|
||||
tr20: cs = 10; goto _again;
|
||||
tr22: cs = 11; goto _again;
|
||||
tr2: cs = 12; goto f1;
|
||||
tr3: cs = 12; goto f2;
|
||||
tr4: cs = 12; goto f3;
|
||||
tr8: cs = 13; goto f6;
|
||||
tr14: cs = 14; goto f10;
|
||||
tr17: cs = 15; goto f12;
|
||||
tr21: cs = 16; goto f13;
|
||||
|
||||
f5: _acts = _ini_actions + 1; goto execFuncs;
|
||||
f6: _acts = _ini_actions + 3; goto execFuncs;
|
||||
f4: _acts = _ini_actions + 5; goto execFuncs;
|
||||
f1: _acts = _ini_actions + 7; goto execFuncs;
|
||||
f8: _acts = _ini_actions + 9; goto execFuncs;
|
||||
f9: _acts = _ini_actions + 11; goto execFuncs;
|
||||
f10: _acts = _ini_actions + 13; goto execFuncs;
|
||||
f7: _acts = _ini_actions + 15; goto execFuncs;
|
||||
f12: _acts = _ini_actions + 17; goto execFuncs;
|
||||
f11: _acts = _ini_actions + 19; goto execFuncs;
|
||||
f13: _acts = _ini_actions + 21; goto execFuncs;
|
||||
f0: _acts = _ini_actions + 23; goto execFuncs;
|
||||
f3: _acts = _ini_actions + 25; goto execFuncs;
|
||||
f2: _acts = _ini_actions + 28; goto execFuncs;
|
||||
|
||||
execFuncs:
|
||||
_nacts = *_acts++;
|
||||
while ( _nacts-- > 0 ) {
|
||||
switch ( *_acts++ ) {
|
||||
case 0:
|
||||
/* #line 130 "ini_parser.rl" */
|
||||
{
|
||||
buff_i = 0;
|
||||
{cs = 2;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
/* #line 135 "ini_parser.rl" */
|
||||
{
|
||||
if (buff_i >= INI_KEY_MAX) {
|
||||
ini_parser_error("Section name too long");
|
||||
{cs = 10;goto _again;}
|
||||
}
|
||||
keybuf[buff_i++] = (*p);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
/* #line 143 "ini_parser.rl" */
|
||||
{
|
||||
// we need a separate buffer for the result, otherwise a failed
|
||||
// partial parse would corrupt the section string
|
||||
rtrim_buf(keybuf, buff_i);
|
||||
for (i = 0; (c = keybuf[i]) != 0; i++) secbuf[i] = c;
|
||||
secbuf[i] = 0;
|
||||
{cs = 1;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
/* #line 155 "ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in [section]");
|
||||
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
/* #line 162 "ini_parser.rl" */
|
||||
{
|
||||
buff_i = 0;
|
||||
keybuf[buff_i++] = (*p); // add the first char
|
||||
{cs = 4;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
/* #line 168 "ini_parser.rl" */
|
||||
{
|
||||
if (buff_i >= INI_KEY_MAX) {
|
||||
ini_parser_error("Key too long");
|
||||
{cs = 10;goto _again;}
|
||||
}
|
||||
keybuf[buff_i++] = (*p);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
/* #line 176 "ini_parser.rl" */
|
||||
{
|
||||
rtrim_buf(keybuf, buff_i);
|
||||
|
||||
// --- Value begin ---
|
||||
buff_i = 0;
|
||||
value_quote = 0;
|
||||
value_nextesc = false;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
/* #line 185 "ini_parser.rl" */
|
||||
{
|
||||
isnl = ((*p) == '\r' || (*p) == '\n');
|
||||
isquot = ((*p) == '\'' || (*p) == '"');
|
||||
|
||||
// detect our starting quote
|
||||
if (isquot && !value_nextesc && buff_i == 0 && value_quote == 0) {
|
||||
value_quote = (*p);
|
||||
goto valueCharDone;
|
||||
}
|
||||
|
||||
if (buff_i >= INI_VALUE_MAX) {
|
||||
ini_parser_error("Value too long");
|
||||
{cs = 10;goto _again;}
|
||||
}
|
||||
|
||||
// end of string - clean up and report
|
||||
if ((!value_nextesc && (*p) == value_quote) || isnl) {
|
||||
if (isnl && value_quote) {
|
||||
ini_parser_error("Unterminated string");
|
||||
{cs = 1;goto _again;}
|
||||
}
|
||||
|
||||
// unquoted: trim from the end
|
||||
if (!value_quote) {
|
||||
rtrim_buf(valbuf, buff_i);
|
||||
} else {
|
||||
valbuf[buff_i] = 0;
|
||||
}
|
||||
|
||||
if (keyCallback) {
|
||||
keyCallback(secbuf, keybuf, valbuf, userdata);
|
||||
}
|
||||
|
||||
// we don't want to discard to eol if the string was terminated by eol
|
||||
// - would delete the next line
|
||||
|
||||
if (isnl) {cs = 1;goto _again;} else {cs = 10;goto _again;}
|
||||
}
|
||||
|
||||
c = (*p);
|
||||
// escape...
|
||||
if (value_nextesc) {
|
||||
if ((*p) == 'n') c = '\n';
|
||||
else if ((*p) == 'r') c = '\r';
|
||||
else if ((*p) == 't') c = '\t';
|
||||
else if ((*p) == 'e') c = '\033';
|
||||
}
|
||||
|
||||
// collecting characters...
|
||||
if (value_nextesc || (*p) != '\\') { // is quoted, or is not a quoting backslash - literal character
|
||||
valbuf[buff_i++] = c;
|
||||
}
|
||||
|
||||
value_nextesc = (!value_nextesc && (*p) == '\\');
|
||||
valueCharDone:;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
/* #line 247 "ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in key=value");
|
||||
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
/* #line 257 "ini_parser.rl" */
|
||||
{ {cs = 1;goto _again;} }
|
||||
break;
|
||||
case 10:
|
||||
/* #line 258 "ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in comment");
|
||||
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
/* #line 265 "ini_parser.rl" */
|
||||
{ {cs = 1;goto _again;} }
|
||||
break;
|
||||
case 12:
|
||||
/* #line 273 "ini_parser.rl" */
|
||||
{ {cs = 8;goto _again;} }
|
||||
break;
|
||||
case 13:
|
||||
/* #line 276 "ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in root");
|
||||
{cs = 10;goto _again;}
|
||||
}
|
||||
break;
|
||||
/* #line 458 "ini_parser.c" */
|
||||
}
|
||||
}
|
||||
goto _again;
|
||||
|
||||
_again:
|
||||
if ( cs == 0 )
|
||||
goto _out;
|
||||
if ( ++p != pe )
|
||||
goto _resume;
|
||||
_test_eof: {}
|
||||
if ( p == eof )
|
||||
{
|
||||
const char *__acts = _ini_actions + _ini_eof_actions[cs];
|
||||
unsigned int __nacts = (unsigned int) *__acts++;
|
||||
while ( __nacts-- > 0 ) {
|
||||
switch ( *__acts++ ) {
|
||||
case 3:
|
||||
/* #line 155 "ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in [section]");
|
||||
if((*p) == '\n') {cs = 1; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;} else {cs = 10; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;}
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
/* #line 247 "ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in key=value");
|
||||
if((*p) == '\n') {cs = 1; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;} else {cs = 10; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;}
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
/* #line 258 "ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in comment");
|
||||
if((*p) == '\n') {cs = 1; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;} else {cs = 10; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;}
|
||||
}
|
||||
break;
|
||||
case 13:
|
||||
/* #line 276 "ini_parser.rl" */
|
||||
{
|
||||
ini_parser_error("Syntax error in root");
|
||||
{cs = 10; if ( p == pe )
|
||||
goto _test_eof;
|
||||
goto _again;}
|
||||
}
|
||||
break;
|
||||
/* #line 517 "ini_parser.c" */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_out: {}
|
||||
}
|
||||
|
||||
/* #line 283 "ini_parser.rl" */
|
||||
|
||||
nini.state = NINI_IDLE;
|
||||
}
|
||||
|
||||
+1
-9
@@ -1,6 +1,5 @@
|
||||
//
|
||||
// INI file parser with a FSM generated by Ragel. This was originally written for ESPTerm
|
||||
// Used to extract sections, keys and values from user-provided settings file
|
||||
// INI file parser. Used to extract sections, keys and values from user-provided settings file
|
||||
//
|
||||
|
||||
#ifndef INIPARSE_STREAM_H
|
||||
@@ -8,13 +7,6 @@
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
// toggleable logging func
|
||||
#ifdef DEBUG_INI
|
||||
#define ini_error(fmt, ...) dbg("! INI err: "#fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define ini_error(fmt, ...)
|
||||
#endif
|
||||
|
||||
// buffer sizes
|
||||
//#define INI_KEY_MAX 20
|
||||
//#define INI_VALUE_MAX 30 // moved to plat_compat.h
|
||||
|
||||
@@ -1,284 +0,0 @@
|
||||
|
||||
/* Ragel constants block */
|
||||
#include "ini_parser.h"
|
||||
|
||||
// Ragel setup
|
||||
%%{
|
||||
machine ini;
|
||||
write data;
|
||||
alphtype unsigned char;
|
||||
}%%
|
||||
|
||||
// Persistent state
|
||||
static int8_t cs = -1; //!< Ragel's Current State variable
|
||||
static uint32_t buff_i = 0; //!< Write pointer for the buffers
|
||||
static char value_quote = 0; //!< Quote character of the currently collected value
|
||||
static bool value_nextesc = false; //!< Next character is escaped, trated specially, and if quote, as literal quote character
|
||||
static IniParserCallback keyCallback = NULL; //!< Currently assigned callback
|
||||
static void *userdata = NULL; //!< Currently assigned user data for the callback
|
||||
|
||||
// Buffers
|
||||
static char keybuf[INI_KEY_MAX];
|
||||
static char secbuf[INI_KEY_MAX];
|
||||
static char valbuf[INI_VALUE_MAX];
|
||||
|
||||
// See header for doxygen!
|
||||
|
||||
void
|
||||
ini_parse_reset_partial(void)
|
||||
{
|
||||
buff_i = 0;
|
||||
value_quote = 0;
|
||||
value_nextesc = false;
|
||||
}
|
||||
|
||||
void
|
||||
ini_parse_reset(void)
|
||||
{
|
||||
ini_parse_reset_partial();
|
||||
keybuf[0] = secbuf[0] = valbuf[0] = 0;
|
||||
%% write init;
|
||||
}
|
||||
|
||||
void
|
||||
ini_parser_error(const char* msg)
|
||||
{
|
||||
ini_error("Parser error: %s", msg);
|
||||
ini_parse_reset_partial();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ini_parse_begin(IniParserCallback callback, void *userData)
|
||||
{
|
||||
keyCallback = callback;
|
||||
userdata = userData;
|
||||
ini_parse_reset();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
*ini_parse_end(void)
|
||||
{
|
||||
ini_parse("\n", 1);
|
||||
if (keyCallback) {
|
||||
keyCallback = NULL;
|
||||
}
|
||||
|
||||
void *ud = userdata;
|
||||
userdata = NULL;
|
||||
return ud;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData)
|
||||
{
|
||||
ini_parse_begin(callback, userData);
|
||||
ini_parse(text, len);
|
||||
ini_parse_end();
|
||||
}
|
||||
|
||||
static void
|
||||
rtrim_buf(char *buf, int32_t end)
|
||||
{
|
||||
if (end > 0) {
|
||||
while ((uint8_t)buf[--end] < 33);
|
||||
end++; // go past the last character
|
||||
}
|
||||
|
||||
buf[end] = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ini_parse(const char *newstr, size_t len)
|
||||
{
|
||||
int32_t i;
|
||||
char c;
|
||||
bool isnl;
|
||||
bool isquot;
|
||||
|
||||
// Load new data to Ragel vars
|
||||
const uint8_t *p;
|
||||
const uint8_t *eof;
|
||||
const uint8_t *pe;
|
||||
|
||||
if (len == 0) while(newstr[++len] != 0); // alternative to strlen
|
||||
|
||||
p = (const uint8_t *) newstr;
|
||||
eof = NULL;
|
||||
pe = (const uint8_t *) (newstr + len);
|
||||
|
||||
// Init Ragel on the first run
|
||||
if (cs == -1) {
|
||||
ini_parse_reset();
|
||||
}
|
||||
|
||||
// The parser
|
||||
%%{
|
||||
#/ *
|
||||
ispace = [ \t]; # inline space
|
||||
wchar = any - 0..8 - 10..31;
|
||||
#apos = '\'';
|
||||
#quot = '\"';
|
||||
nonl = [^\r\n];
|
||||
nl = '\r'? '\n';
|
||||
|
||||
# ---- [SECTION] ----
|
||||
|
||||
action sectionStart {
|
||||
buff_i = 0;
|
||||
fgoto section;
|
||||
}
|
||||
|
||||
action sectionChar {
|
||||
if (buff_i >= INI_KEY_MAX) {
|
||||
ini_parser_error("Section name too long");
|
||||
fgoto discard2eol;
|
||||
}
|
||||
keybuf[buff_i++] = fc;
|
||||
}
|
||||
|
||||
action sectionEnd {
|
||||
// we need a separate buffer for the result, otherwise a failed
|
||||
// partial parse would corrupt the section string
|
||||
rtrim_buf(keybuf, buff_i);
|
||||
for (i = 0; (c = keybuf[i]) != 0; i++) secbuf[i] = c;
|
||||
secbuf[i] = 0;
|
||||
fgoto main;
|
||||
}
|
||||
|
||||
section :=
|
||||
(
|
||||
ispace* <: ((wchar - ']')+ @sectionChar) ']' @sectionEnd
|
||||
) $!{
|
||||
ini_parser_error("Syntax error in [section]");
|
||||
if(fc == '\n') fgoto main; else fgoto discard2eol;
|
||||
};
|
||||
|
||||
# ---- KEY=VALUE ----
|
||||
|
||||
action keyStart {
|
||||
buff_i = 0;
|
||||
keybuf[buff_i++] = fc; // add the first char
|
||||
fgoto keyvalue;
|
||||
}
|
||||
|
||||
action keyChar {
|
||||
if (buff_i >= INI_KEY_MAX) {
|
||||
ini_parser_error("Key too long");
|
||||
fgoto discard2eol;
|
||||
}
|
||||
keybuf[buff_i++] = fc;
|
||||
}
|
||||
|
||||
action keyEnd {
|
||||
rtrim_buf(keybuf, buff_i);
|
||||
|
||||
// --- Value begin ---
|
||||
buff_i = 0;
|
||||
value_quote = 0;
|
||||
value_nextesc = false;
|
||||
}
|
||||
|
||||
action valueChar {
|
||||
isnl = (fc == '\r' || fc == '\n');
|
||||
isquot = (fc == '\'' || fc == '"');
|
||||
|
||||
// detect our starting quote
|
||||
if (isquot && !value_nextesc && buff_i == 0 && value_quote == 0) {
|
||||
value_quote = fc;
|
||||
goto valueCharDone;
|
||||
}
|
||||
|
||||
if (buff_i >= INI_VALUE_MAX) {
|
||||
ini_parser_error("Value too long");
|
||||
fgoto discard2eol;
|
||||
}
|
||||
|
||||
// end of string - clean up and report
|
||||
if ((!value_nextesc && fc == value_quote) || isnl) {
|
||||
if (isnl && value_quote) {
|
||||
ini_parser_error("Unterminated string");
|
||||
fgoto main;
|
||||
}
|
||||
|
||||
// unquoted: trim from the end
|
||||
if (!value_quote) {
|
||||
rtrim_buf(valbuf, buff_i);
|
||||
} else {
|
||||
valbuf[buff_i] = 0;
|
||||
}
|
||||
|
||||
if (keyCallback) {
|
||||
keyCallback(secbuf, keybuf, valbuf, userdata);
|
||||
}
|
||||
|
||||
// we don't want to discard to eol if the string was terminated by eol
|
||||
// - would delete the next line
|
||||
|
||||
if (isnl) fgoto main; else fgoto discard2eol;
|
||||
}
|
||||
|
||||
c = fc;
|
||||
// escape...
|
||||
if (value_nextesc) {
|
||||
if (fc == 'n') c = '\n';
|
||||
else if (fc == 'r') c = '\r';
|
||||
else if (fc == 't') c = '\t';
|
||||
else if (fc == 'e') c = '\033';
|
||||
}
|
||||
|
||||
// collecting characters...
|
||||
if (value_nextesc || fc != '\\') { // is quoted, or is not a quoting backslash - literal character
|
||||
valbuf[buff_i++] = c;
|
||||
}
|
||||
|
||||
value_nextesc = (!value_nextesc && fc == '\\');
|
||||
valueCharDone:;
|
||||
}
|
||||
|
||||
# use * for key, first char is already consumed.
|
||||
keyvalue :=
|
||||
(
|
||||
([^\n=:]* @keyChar %keyEnd)
|
||||
[=:] ispace* <: nonl* @valueChar nl @valueChar
|
||||
) $!{
|
||||
ini_parser_error("Syntax error in key=value");
|
||||
if(fc == '\n') fgoto main; else fgoto discard2eol;
|
||||
};
|
||||
|
||||
# ---- COMMENT ----
|
||||
|
||||
comment :=
|
||||
(
|
||||
nonl* nl
|
||||
@{ fgoto main; }
|
||||
) $!{
|
||||
ini_parser_error("Syntax error in comment");
|
||||
if(fc == '\n') fgoto main; else fgoto discard2eol;
|
||||
};
|
||||
|
||||
# ---- CLEANUP ----
|
||||
|
||||
discard2eol := nonl* nl @{ fgoto main; };
|
||||
|
||||
# ---- ROOT ----
|
||||
|
||||
main :=
|
||||
(space*
|
||||
(
|
||||
'[' @sectionStart |
|
||||
[#;] @{ fgoto comment; } |
|
||||
(wchar - [\t =:]) @keyStart
|
||||
)
|
||||
) $!{
|
||||
ini_parser_error("Syntax error in root");
|
||||
fgoto discard2eol;
|
||||
};
|
||||
|
||||
write exec;
|
||||
#*/
|
||||
}%%
|
||||
}
|
||||
@@ -119,6 +119,25 @@ void iw_entry(IniWriter *iw, const char *key, const char *format, ...)
|
||||
iw_newline(iw); // one newline after entry
|
||||
}
|
||||
|
||||
void iw_entry_s(IniWriter *iw, const char *key, const char *value)
|
||||
{
|
||||
if (iw->count == 0) return;
|
||||
iw_string(iw, key);
|
||||
iw_string(iw, "=");
|
||||
iw_string(iw, value);
|
||||
iw_newline(iw);
|
||||
}
|
||||
|
||||
void iw_entry_d(IniWriter *iw, const char *key, int32_t value)
|
||||
{
|
||||
if (iw->count == 0) return;
|
||||
iw_string(iw, key);
|
||||
iw_string(iw, "=");
|
||||
uint32_t len = (int)fixup_snprintf(&iwbuffer[0], IWBUFFER_LEN, "%d", value);
|
||||
iw_buff(iw, (uint8_t *) iwbuffer, len);
|
||||
iw_newline(iw);
|
||||
}
|
||||
|
||||
uint32_t iw_measure_total(void (*handler)(IniWriter *), uint32_t tag)
|
||||
{
|
||||
IniWriter iw = iw_init(NULL, 0xFFFFFFFF, 1);
|
||||
|
||||
@@ -126,6 +126,9 @@ __attribute__((format(printf,2,3)));
|
||||
void iw_entry(IniWriter *iw, const char *key, const char *format, ...)
|
||||
__attribute__((format(printf,3,4)));
|
||||
|
||||
void iw_entry_s(IniWriter *iw, const char *key, const char *value);
|
||||
void iw_entry_d(IniWriter *iw, const char *key, int32_t value);
|
||||
|
||||
/**
|
||||
* Measure total ini writer length using a dummy write
|
||||
*
|
||||
|
||||
+10
-20
@@ -1,3 +1,4 @@
|
||||
#include <debug.h>
|
||||
#include "payload_parser.h"
|
||||
|
||||
#define pp_check_capacity(pp, needed) \
|
||||
@@ -58,32 +59,21 @@ uint32_t pp_u32(PayloadParser *pp)
|
||||
|
||||
uint64_t pp_u64(PayloadParser *pp)
|
||||
{
|
||||
pp_check_capacity(pp, 4);
|
||||
pp_check_capacity(pp, 8);
|
||||
if (!pp->ok) return 0;
|
||||
|
||||
uint64_t x = 0;
|
||||
uint32_t x0, x1;
|
||||
uint64_t x;
|
||||
|
||||
if (pp->bigendian) {
|
||||
x |= (uint64_t) ((uint64_t) *pp->current++ << 56);
|
||||
x |= (uint64_t) ((uint64_t) *pp->current++ << 48);
|
||||
x |= (uint64_t) ((uint64_t) *pp->current++ << 40);
|
||||
x |= (uint64_t) ((uint64_t) *pp->current++ << 32);
|
||||
|
||||
x |= (uint64_t) (*pp->current++ << 24);
|
||||
x |= (uint64_t) (*pp->current++ << 16);
|
||||
x |= (uint64_t) (*pp->current++ << 8);
|
||||
x |= *pp->current++;
|
||||
x1 = pp_u32(pp);
|
||||
x0 = pp_u32(pp);
|
||||
} else {
|
||||
x |= *pp->current++;
|
||||
x |= (uint64_t) (*pp->current++ << 8);
|
||||
x |= (uint64_t) (*pp->current++ << 16);
|
||||
x |= (uint64_t) (*pp->current++ << 24);
|
||||
|
||||
x |= (uint64_t) ((uint64_t) *pp->current++ << 32);
|
||||
x |= (uint64_t) ((uint64_t) *pp->current++ << 40);
|
||||
x |= (uint64_t) ((uint64_t) *pp->current++ << 48);
|
||||
x |= (uint64_t) ((uint64_t) *pp->current++ << 56);
|
||||
x0 = pp_u32(pp);
|
||||
x1 = pp_u32(pp);
|
||||
}
|
||||
x = ((uint64_t)x1)<<32 | x0;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ static uint32_t read_file_pinout_txt(uint32_t sector_offset, uint8_t *data, uint
|
||||
|
||||
void vfs_user_build_filesystem(void)
|
||||
{
|
||||
dbg("Rebuilding VFS...");
|
||||
vfs_printf("Rebuilding VFS...");
|
||||
|
||||
// Setup the filesystem based on target parameters
|
||||
vfs_init(daplink_drive_name, 0/*unused "disk size"*/);
|
||||
|
||||
Reference in New Issue
Block a user