20 Commits
Author SHA1 Message Date
MightyPork 3654bf2206 various speed-ups in TF_WriteImpl and elsewhere 2018-03-05 11:38:25 +01:00
MightyPork 5687196bdd small speed up using larger buffer and multipart Tx 2018-03-05 10:21:23 +01:00
MightyPork da330b4b73 experimental speed-up of cdc Tx 2018-03-04 13:19:41 +01:00
MightyPork 0b14e5dda4 fix 1wire bugginess with addressing 2018-03-04 00:50:15 +01:00
MightyPork 887887b675 Removed timers use from 1wire, timers disabled, fixed overflow bug 2018-03-04 00:13:31 +01:00
MightyPork e96ecceec9 Merge branch 'simple-pwm' 2018-03-04 00:02:00 +01:00
MightyPork d8bdaf7203 simple pwm 2018-03-04 00:01:28 +01:00
MightyPork 3fdd51ba2e rm commented out crap 2018-03-03 16:46:33 +01:00
MightyPork 5dd350ffe4 fix ini parser wrt spaces in value 2018-03-03 16:04:14 +01:00
MightyPork 4b8d24ae0f rewritten ini parser for smaller size 2018-03-03 15:59:31 +01:00
MightyPork ed7a4c80a0 size reduction by using specialized entry funcs 2018-03-03 11:05:16 +01:00
MightyPork 78897f84b3 touch button mode 2018-03-03 01:32:30 +01:00
MightyPork 8410c273ab Merge branch 'wd' 2018-02-28 08:17:27 +01:00
MightyPork 2812f962d9 added watchdog 2018-02-28 08:17:21 +01:00
MightyPork 7f4c06ae4b Merge branch 'tsc' 2018-02-26 09:02:51 +01:00
MightyPork 5019bf225d touch interleaved sense mode, improved blinking in file writes via the api 2018-02-26 09:02:41 +01:00
MightyPork 41ad18cc7c improvements + added a toggle for interlaced, not yet fully implemented 2018-02-25 22:47:40 +01:00
MightyPork 101d2534f4 tsc disable debug 2018-02-25 13:40:47 +01:00
MightyPork 1f2d346e23 tsc ini structure + debug msgs 2018-02-25 13:37:57 +01:00
MightyPork 639031fc38 added template install script and utouch config 2018-02-25 00:03:05 +01:00
59 changed files with 1884 additions and 945 deletions
+1 -1
View File
@@ -110,7 +110,7 @@ extern uint32_t SystemCoreClock;
#define configCHECK_FOR_STACK_OVERFLOW 2 #define configCHECK_FOR_STACK_OVERFLOW 2
#define configENABLE_BACKWARD_COMPATIBILITY 0 #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_PRIORITY TSK_TIMERS_PRIO // above normal
#define configTIMER_TASK_STACK_DEPTH TSK_STACK_TIMERS //128 #define configTIMER_TASK_STACK_DEPTH TSK_STACK_TIMERS //128
#define configTIMER_QUEUE_LENGTH 4 #define configTIMER_QUEUE_LENGTH 4
+47 -5
View File
@@ -8,6 +8,7 @@
#include "task_main.h" #include "task_main.h"
#include "USB/usbd_cdc_if.h" #include "USB/usbd_cdc_if.h"
#include "USB/usb_device.h"
#include "TinyFrame.h" #include "TinyFrame.h"
extern osSemaphoreId semVcomTxReadyHandle; extern osSemaphoreId semVcomTxReadyHandle;
@@ -15,6 +16,30 @@ extern osMutexId mutTinyFrameTxHandle;
void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len) 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; (void) tf;
#define CHUNK 64 // same as TF_SENDBUF_LEN, so we should always have only one run of the loop #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; 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); 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; buff += chunksize;
total -= chunksize; total -= chunksize;
} }
#endif
} }
/** Claim the TX interface before composing and sending a frame */ /** Claim the TX interface before composing and sending a frame */
bool TF_ClaimTx(TinyFrame *tf) bool TF_ClaimTx(TinyFrame *tf)
{ {
(void) tf; (void) tf;
// assert_param(osThreadGetId() != tskMainHandle); // assert_param(!inIRQ()); // useless delay
assert_param(!inIRQ()); 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; return true;
} }
@@ -48,5 +88,7 @@ bool TF_ClaimTx(TinyFrame *tf)
void TF_ReleaseTx(TinyFrame *tf) void TF_ReleaseTx(TinyFrame *tf)
{ {
(void) tf; (void) tf;
assert_param(osOK == osMutexRelease(mutTinyFrameTxHandle)); assert_param(pdTRUE == xSemaphoreGive(mutTinyFrameTxHandle));
// the last payload is sent asynchronously
} }
+7 -3
View File
@@ -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) 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_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; 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); 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; 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) void _TF_FN TF_Multipart_Payload(TinyFrame *tf, const uint8_t *buff, uint32_t length)
+1 -1
View File
@@ -369,7 +369,7 @@ bool TF_Query_Multipart(TinyFrame *tf, TF_Msg *msg, TF_Listener listener, TF_TIC
* TF_Respond() with multipart payload. * TF_Respond() with multipart payload.
* msg.data is ignored and set to NULL * 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 * Send the payload for a started multipart frame. This can be called multiple times
+1
View File
@@ -66,6 +66,7 @@ PCD_HandleTypeDef hpcd_USB_FS;
/* init function */ /* init function */
void MX_USB_DEVICE_Init(void) void MX_USB_DEVICE_Init(void)
{ {
dbg("USB device init ...");
/* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */ /* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */
/* USER CODE END USB_DEVICE_Init_PreTreatment */ /* USER CODE END USB_DEVICE_Init_PreTreatment */
+1 -1
View File
@@ -314,7 +314,7 @@ void USBD_CDC_TransmitDone(USBD_HandleTypeDef *pdev)
assert_param(inIRQ()); assert_param(inIRQ());
portBASE_TYPE taskWoken = pdFALSE; portBASE_TYPE taskWoken = pdFALSE;
assert_param(xSemaphoreGiveFromISR(semVcomTxReadyHandle, &taskWoken) == pdTRUE); assert_param(pdTRUE == xSemaphoreGiveFromISR(semVcomTxReadyHandle, &taskWoken));
portYIELD_FROM_ISR(taskWoken); portYIELD_FROM_ISR(taskWoken);
} }
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */ /* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
+9 -4
View File
@@ -2,6 +2,7 @@
// Created by MightyPork on 2017/11/21. // Created by MightyPork on 2017/11/21.
// //
#include <platform/status_led.h>
#include "platform.h" #include "platform.h"
#include "framework/settings.h" #include "framework/settings.h"
#include "utils/ini_parser.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) { if (buffer == NULL) {
free_ck(bulk); free_ck(bulk);
iw_end(); iw_end();
dbg("INI read complete."); // dbg("INI read complete.");
return; 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) 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)); BulkRead *bulk = malloc_ck(sizeof(BulkRead));
assert_param(bulk != NULL); assert_param(bulk != NULL);
@@ -91,6 +92,7 @@ static TF_Result lst_ini_export(TinyFrame *tf, TF_Msg *msg)
bulk->userdata = NULL; bulk->userdata = NULL;
bulkread_start(tf, bulk); bulkread_start(tf, bulk);
Indicator_Effect(STATUS_DISK_BUSY_SHORT);
return TF_STAY; return TF_STAY;
} }
@@ -112,7 +114,7 @@ static void settings_bulkwrite_cb(BulkWrite *bulk, const uint8_t *chunk, uint32_
if (bulk->offset > 0) { if (bulk->offset > 0) {
settings_load_ini_end(); settings_load_ini_end();
dbg("INI write complete"); // dbg("INI write complete");
} else { } else {
dbg("INI write failed"); 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) 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)); BulkWrite *bulk = malloc_ck(sizeof(BulkWrite));
assert_param(bulk); assert_param(bulk);
@@ -152,6 +154,8 @@ static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg)
bulkwrite_start(tf, bulk); bulkwrite_start(tf, bulk);
Indicator_Effect(STATUS_DISK_BUSY);
done: done:
return TF_STAY; return TF_STAY;
} }
@@ -161,6 +165,7 @@ done:
/** Listener: Save settings to Flash */ /** Listener: Save settings to Flash */
static TF_Result lst_persist_cfg(TinyFrame *tf, TF_Msg *msg) static TF_Result lst_persist_cfg(TinyFrame *tf, TF_Msg *msg)
{ {
Indicator_Effect(STATUS_DISK_REMOVED);
settings_save(); settings_save();
return TF_STAY; return TF_STAY;
} }
+3 -1
View File
@@ -13,8 +13,10 @@
void SysTick_Handler(void) void SysTick_Handler(void)
{ {
GEX_MsTick(); // OS first, avoids jitter
osSystickHandler(); osSystickHandler();
// GEX periodic updates
GEX_MsTick();
} }
+10 -9
View File
@@ -33,12 +33,6 @@ const char * rsc_get_name(Resource rsc)
// we assume the returned value is not stored anywhere // 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 // 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 // R_PA0 is 0
if (rsc <= R_PF15) { if (rsc <= R_PF15) {
// we assume the returned value is not stored anywhere // we assume the returned value is not stored anywhere
@@ -48,6 +42,12 @@ const char * rsc_get_name(Resource rsc)
return gpionamebuf; 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]; return rsc_names[rsc - R_EXTI15 - 1];
} }
@@ -85,11 +85,12 @@ const char * rsc_get_owner_name(Resource rsc)
void rsc_init_registry(void) void rsc_init_registry(void)
{ {
for(uint32_t i = 0; i < RSCMAP_LEN; i++) { memset(UNIT_PLATFORM.resources, 0xFF, RSCMAP_LEN);
UNIT_PLATFORM.resources[i] = global_rscmap[i] = 0xFF; memset(global_rscmap, 0xFF, RSCMAP_LEN);
}
rsc_initialized = true; rsc_initialized = true;
rsc_dbg("Total %d hw resources, bitmap has %d bytes.", RESOURCE_COUNT, RSCMAP_LEN);
} }
+5 -1
View File
@@ -13,6 +13,7 @@
X(I2C1) X(I2C2) X(I2C3) \ X(I2C1) X(I2C2) X(I2C3) \
X(ADC1) X(ADC2) X(ADC3) X(ADC4) \ X(ADC1) X(ADC2) X(ADC3) X(ADC4) \
X(DAC1) X(DAC2) \ X(DAC1) X(DAC2) \
X(TSC) \
X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \ X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \
X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \ 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) \ 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(I2S1) X(I2S2) X(I2S3)
// X(OPAMP1) X(OPAMP2) X(OPAMP3) X(OPAMP4) // X(OPAMP1) X(OPAMP2) X(OPAMP3) X(OPAMP4)
// X(CAN1) X(CAN2) // X(CAN1) X(CAN2)
// X(TSC)
// X(DCMI) // X(DCMI)
// X(ETH) // X(ETH)
// X(FSMC) // X(FSMC)
@@ -59,8 +59,12 @@ typedef enum hw_resource Resource;
/** Enum of all resources */ /** Enum of all resources */
enum hw_resource { enum hw_resource {
#define X(res_name) R_##res_name, #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 XX_RESOURCES_GPIO
// EXTIs (same like GPIOs) have dynamically generated labels to save rom space. Must be contiguous.
XX_RESOURCES_EXTI XX_RESOURCES_EXTI
// All the rest ...
XX_RESOURCES XX_RESOURCES
#undef X #undef X
R_NONE, R_NONE,
+1 -1
View File
@@ -147,7 +147,7 @@ void MX_FREERTOS_Init(void) {
stackmon_register("Main", mainTaskStack, sizeof(mainTaskStack)); stackmon_register("Main", mainTaskStack, sizeof(mainTaskStack));
stackmon_register("Job+Msg", msgJobQueTaskStack, sizeof(msgJobQueTaskStack)); stackmon_register("Job+Msg", msgJobQueTaskStack, sizeof(msgJobQueTaskStack));
stackmon_register("Idle", xIdleStack, sizeof(xIdleStack)); stackmon_register("Idle", xIdleStack, sizeof(xIdleStack));
stackmon_register("Timers", xTimersStack, sizeof(xTimersStack)); // stackmon_register("Timers", xTimersStack, sizeof(xTimersStack));
/* USER CODE END Init */ /* USER CODE END Init */
/* Create the mutex(es) */ /* Create the mutex(es) */
+3 -1
View File
@@ -16,6 +16,8 @@ GEX_SRC_DIR = \
User/units/adc \ User/units/adc \
User/units/sipo \ User/units/sipo \
User/units/fcap \ User/units/fcap \
User/units/touch \
User/units/simple_pwm \
User/TinyFrame \ User/TinyFrame \
User/CWPack \ User/CWPack \
User/tasks User/tasks
@@ -95,7 +97,7 @@ GEX_CDEFS = $(GEX_CDEFS_BASE) \
-DUSE_STACK_MONITOR=1 \ -DUSE_STACK_MONITOR=1 \
-DUSE_DEBUG_UART=1 \ -DUSE_DEBUG_UART=1 \
-DDEBUG_MALLOC=0 \ -DDEBUG_MALLOC=0 \
-DDEBUG_RSC=1 -DDEBUG_RSC=0
endif endif
+12
View File
@@ -43,6 +43,18 @@ void GEX_PreInit(void)
dbg("\r\n\033[37;1m*** GEX "GEX_VERSION" on "GEX_PLATFORM" ***\033[m"); dbg("\r\n\033[37;1m*** GEX "GEX_VERSION" on "GEX_PLATFORM" ***\033[m");
dbg("Build "__DATE__" "__TIME__); 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(); plat_init();
MX_USB_DEVICE_Init(); MX_USB_DEVICE_Init();
+36 -1
View File
@@ -3,7 +3,6 @@
// //
#include "platform.h" #include "platform.h"
#include "utils/avrlibc.h"
#include "hw_utils.h" #include "hw_utils.h"
/** Convert pin number to LL bitfield */ /** 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; 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 */ /** Configure pins using sparse map */
error_t hw_configure_sparse_pins(char port_name, uint16_t mask, GPIO_TypeDef **port_dest, error_t hw_configure_sparse_pins(char port_name, uint16_t mask, GPIO_TypeDef **port_dest,
uint32_t ll_mode, uint32_t ll_otype) uint32_t ll_mode, uint32_t ll_otype)
@@ -288,6 +311,12 @@ void hw_periph_clock_enable(void *periph)
#ifdef DAC2 #ifdef DAC2
else if (periph == DAC2) __HAL_RCC_DAC2_CLK_ENABLE(); else if (periph == DAC2) __HAL_RCC_DAC2_CLK_ENABLE();
#endif #endif
// --- TSC ---
#ifdef TSC
else if (periph == TSC) __HAL_RCC_TSC_CLK_ENABLE();
#endif
else { else {
dbg("Periph 0x%p missing in hw clock enable func", periph); dbg("Periph 0x%p missing in hw clock enable func", periph);
trap("BUG"); trap("BUG");
@@ -393,6 +422,12 @@ void hw_periph_clock_disable(void *periph)
#ifdef DAC2 #ifdef DAC2
else if (periph == DAC2) __HAL_RCC_DAC2_CLK_DISABLE(); else if (periph == DAC2) __HAL_RCC_DAC2_CLK_DISABLE();
#endif #endif
// --- TSC ---
#ifdef TSC
else if (periph == TSC) __HAL_RCC_TSC_CLK_DISABLE();
#endif
else { else {
dbg("Periph 0x%p missing in hw clock disable func", periph); dbg("Periph 0x%p missing in hw clock disable func", periph);
trap("BUG"); trap("BUG");
+3
View File
@@ -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)); 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 * Configure multiple pins using the bitmap pattern
* *
+10 -1
View File
@@ -69,6 +69,7 @@ static struct callbacks_ {
struct cbslot tim16; struct cbslot tim16;
struct cbslot adc1; struct cbslot adc1;
struct cbslot tsc;
// XXX add more callbacks here when needed // XXX add more callbacks here when needed
} callbacks; } callbacks;
@@ -92,7 +93,8 @@ void irqd_init(void)
HAL_NVIC_SetPriority(EXTI2_3_IRQn, 2, 0); HAL_NVIC_SetPriority(EXTI2_3_IRQn, 2, 0);
HAL_NVIC_SetPriority(EXTI4_15_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_Channel1_IRQn); /*!< DMA1 Channel 1 Interrupt */
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); /*!< DMA1 Channel 2 and Channel 3 Interrupt */ NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); /*!< DMA1 Channel 2 and Channel 3 Interrupt */
@@ -178,6 +180,8 @@ static struct cbslot *get_slot_for_periph(void *periph)
else if (periph == TIM16) slot = &callbacks.tim16; else if (periph == TIM16) slot = &callbacks.tim16;
// 17 - used by timebase // 17 - used by timebase
else if (periph == TSC) slot = &callbacks.tsc;
else if (periph == ADC1) slot = &callbacks.adc1; else if (periph == ADC1) slot = &callbacks.adc1;
else if (periph >= EXTIS[0] && periph <= EXTIS[15]) { else if (periph >= EXTIS[0] && periph <= EXTIS[15]) {
@@ -352,6 +356,11 @@ void ADC1_COMP_IRQHandler(void)
CALL_IRQ_HANDLER(callbacks.adc1); CALL_IRQ_HANDLER(callbacks.adc1);
} }
void TSC_IRQHandler(void)
{
CALL_IRQ_HANDLER(callbacks.tsc);
}
// other ISRs... // other ISRs...
+3 -3
View File
@@ -21,7 +21,7 @@
#endif #endif
// 180 is normally enough if not doing extensive debug logging // 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_IDLE 64 //configMINIMAL_STACK_SIZE
#define TSK_STACK_TIMERS 64 //configTIMER_TASK_STACK_DEPTH #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 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 #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 RX_QUE_CAPACITY 16 // TinyFrame rx queue size (64 bytes each)
#define TF_MAX_PAYLOAD_RX 512 // TF max Rx payload #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_ID_LST 4 // Frame ID listener count
#define TF_MAX_TYPE_LST 6 // Frame Type listener count #define TF_MAX_TYPE_LST 6 // Frame Type listener count
+3
View File
@@ -15,6 +15,7 @@
#include "debug_uart.h" #include "debug_uart.h"
#include "irq_dispatcher.h" #include "irq_dispatcher.h"
#include "timebase.h" #include "timebase.h"
#include "watchdog.h"
void plat_init(void) void plat_init(void)
{ {
@@ -39,4 +40,6 @@ void plat_init(void)
settings_load(); // XXX maybe this should be moved to the main task settings_load(); // XXX maybe this should be moved to the main task
comm_init(); comm_init();
wd_init();
} }
+7 -3
View File
@@ -2,7 +2,6 @@
// Created by MightyPork on 2017/11/26. // Created by MightyPork on 2017/11/26.
// //
#include <units/fcap/unit_fcap.h>
#include "platform.h" #include "platform.h"
#include "usbd_core.h" #include "usbd_core.h"
#include "USB/usb_device.h" #include "USB/usb_device.h"
@@ -19,6 +18,9 @@
#include "units/usart/unit_usart.h" #include "units/usart/unit_usart.h"
#include "units/spi/unit_spi.h" #include "units/spi/unit_spi.h"
#include "units/sipo/unit_sipo.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" #include "hw_utils.h"
void plat_init_resources(void) void plat_init_resources(void)
@@ -90,6 +92,8 @@ void plat_init_resources(void)
ureg_add_type(&UNIT_ADC); ureg_add_type(&UNIT_ADC);
ureg_add_type(&UNIT_SIPO); ureg_add_type(&UNIT_SIPO);
ureg_add_type(&UNIT_FCAP); ureg_add_type(&UNIT_FCAP);
ureg_add_type(&UNIT_TOUCH);
ureg_add_type(&UNIT_PWMDIM);
// Free all present resources // Free all present resources
{ {
@@ -98,7 +102,7 @@ void plat_init_resources(void)
// rsc_free_range(NULL, R_COMP1, R_COMP2); // rsc_free_range(NULL, R_COMP1, R_COMP2);
rsc_free(NULL, R_DAC1); rsc_free(NULL, R_DAC1);
// rsc_free(NULL, R_HDMI_CEC); // 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_I2C1, R_I2C2);
// rsc_free_range(NULL, R_I2S1, R_I2S2); // rsc_free_range(NULL, R_I2S1, R_I2S2);
rsc_free_range(NULL, R_SPI1, R_SPI2); rsc_free_range(NULL, R_SPI1, R_SPI2);
@@ -154,7 +158,7 @@ void plat_init_resources(void)
rsc_free_range(NULL, R_TIM1, R_TIM4); rsc_free_range(NULL, R_TIM1, R_TIM4);
rsc_free_range(NULL, R_TIM6, R_TIM8); rsc_free_range(NULL, R_TIM6, R_TIM8);
rsc_free_range(NULL, R_TIM15, R_TIM17); 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_USART1, R_USART5);
rsc_free_range(NULL, R_PA0, R_PA15); rsc_free_range(NULL, R_PA0, R_PA15);
+15 -1
View File
@@ -61,6 +61,12 @@ void Indicator_Effect(enum GEX_StatusIndicator indicator)
led_on(); 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; active_effect = indicator;
effect_time = 0; effect_time = 0;
} }
@@ -119,7 +125,15 @@ void Indicator_Tick(void)
active_effect = STATUS_NONE; active_effect = STATUS_NONE;
} }
else if (effect_time % 100 == 0) led_on(); 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) { else if (active_effect == STATUS_WELCOME) {
if (effect_time == 0) led_on(); if (effect_time == 0) led_on();
+1
View File
@@ -16,6 +16,7 @@ enum GEX_StatusIndicator {
STATUS_NONE = 0, STATUS_NONE = 0,
STATUS_FAULT, STATUS_FAULT,
STATUS_DISK_BUSY, STATUS_DISK_BUSY,
STATUS_DISK_BUSY_SHORT,
STATUS_DISK_ATTACHED, STATUS_DISK_ATTACHED,
STATUS_DISK_REMOVED, STATUS_DISK_REMOVED,
STATUS_WELCOME, STATUS_WELCOME,
+57
View File
@@ -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();
}
+32
View File
@@ -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
+3
View File
@@ -4,6 +4,7 @@
#include "platform.h" #include "platform.h"
#include "platform/lock_jumper.h" #include "platform/lock_jumper.h"
#include "platform/watchdog.h"
#include "status_led.h" #include "status_led.h"
#include "utils/stacksmon.h" #include "utils/stacksmon.h"
#include "vfs/vfs_manager.h" #include "vfs/vfs_manager.h"
@@ -45,6 +46,8 @@ void TaskMain(void const * argument)
cnt++; cnt++;
Indicator_Heartbeat(); Indicator_Heartbeat();
wd_restart();
} }
// if no message and it just timed out, go wait some more... // if no message and it just timed out, go wait some more...
+3
View File
@@ -3,6 +3,7 @@
// //
#include "platform.h" #include "platform.h"
#include "platform/watchdog.h"
#include "comm/messages.h" #include "comm/messages.h"
#include "task_msg.h" #include "task_msg.h"
@@ -85,7 +86,9 @@ void TaskMsgJob(const void *argument)
#if CDC_LOOPBACK_TEST #if CDC_LOOPBACK_TEST
TF_WriteImpl(comm, slot.msg.data, slot.msg.len); TF_WriteImpl(comm, slot.msg.data, slot.msg.len);
#else #else
wd_suspend();
TF_Accept(comm, slot.msg.data, slot.msg.len); TF_Accept(comm, slot.msg.data, slot.msg.len);
wd_resume();
#endif #endif
} }
-12
View File
@@ -14,15 +14,6 @@ error_t OW_preInit(Unit *unit)
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv)); struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
if (priv == NULL) return E_OUT_OF_MEM; 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 // some defaults
priv->pin_number = 0; priv->pin_number = 0;
priv->port_name = 'A'; priv->port_name = 'A';
@@ -63,9 +54,6 @@ void OW_deInit(Unit *unit)
// Release all resources // Release all resources
rsc_teardown(unit); rsc_teardown(unit);
// Delete the software timer
assert_param(pdPASS == xTimerDelete(priv->busyWaitTimer, 1000));
// Free memory // Free memory
free_ck(unit->data); free_ck(unit->data);
} }
+1 -1
View File
@@ -64,5 +64,5 @@ void OW_writeIni(Unit *unit, IniWriter *iw)
iw_entry(iw, "pin", "%c%d", priv->port_name, priv->pin_number); iw_entry(iw, "pin", "%c%d", priv->port_name, priv->pin_number);
iw_comment(iw, "Parasitic (bus-powered) mode"); iw_comment(iw, "Parasitic (bus-powered) mode");
iw_entry(iw, "parasitic", str_yn(priv->parasitic)); iw_entry_s(iw, "parasitic", str_yn(priv->parasitic));
} }
+14 -11
View File
@@ -38,12 +38,13 @@ static void OW_TimerRespCb(Job *job)
* *
* @param xTimer * @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; struct priv *priv = unit->data;
assert_param(priv->busy); if(!priv->busy) {
dbg("ow tick should be disabled now!");
return;
}
if (priv->parasitic) { if (priv->parasitic) {
// this is the end of the 750ms measurement time // this is the end of the 750ms measurement time
@@ -56,7 +57,8 @@ void OW_TimerCb(TimerHandle_t xTimer)
uint32_t time = PTIM_GetTime(); uint32_t time = PTIM_GetTime();
if (time - priv->busyStart > 1000) { if (time - priv->busyStart > 1000) {
xTimerStop(xTimer, 100); unit->tick_interval = 0;
unit->_tick_cnt = 0;
Job j = { Job j = {
.unit = unit, .unit = unit,
@@ -69,7 +71,8 @@ void OW_TimerCb(TimerHandle_t xTimer)
return; return;
halt_ok: halt_ok:
xTimerStop(xTimer, 100); unit->tick_interval = 0;
unit->_tick_cnt = 0;
Job j = { Job j = {
.unit = unit, .unit = unit,
@@ -79,7 +82,6 @@ halt_ok:
scheduleJob(&j); scheduleJob(&j);
} }
enum PinCmd_ { enum PinCmd_ {
CMD_CHECK_PRESENCE = 0, // simply tests that any devices are attached 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 CMD_SEARCH_ADDR = 1, // perform a scan of the bus, retrieving all found device ROMs
@@ -120,13 +122,13 @@ static error_t OW_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Pay
*/ */
case CMD_POLL_FOR_1: case CMD_POLL_FOR_1:
// This can't be exposed via the UU API, due to being async // This can't be exposed via the UU API, due to being async
unit->_tick_cnt = 0;
unit->tick_interval = 750;
if (priv->parasitic) { if (priv->parasitic) {
assert_param(pdPASS == xTimerChangePeriod(priv->busyWaitTimer, 750, 100)); unit->tick_interval = 750;
} else { } else {
// every 10 ticks unit->tick_interval = 10;
assert_param(pdPASS == xTimerChangePeriod(priv->busyWaitTimer, 10, 100));
} }
assert_param(pdPASS == xTimerStart(priv->busyWaitTimer, 100));
priv->busy = true; priv->busy = true;
priv->busyStart = PTIM_GetTime(); priv->busyStart = PTIM_GetTime();
priv->busyRequestId = frame_id; priv->busyRequestId = frame_id;
@@ -242,4 +244,5 @@ const UnitDriver UNIT_1WIRE = {
.deInit = OW_deInit, .deInit = OW_deInit,
// Function // Function
.handleRequest = OW_handleRequest, .handleRequest = OW_handleRequest,
.updateTick = OW_tickHandler,
}; };
+9 -6
View File
@@ -40,7 +40,8 @@ static void UADC_JobSendBlockChunk(Job *job)
.len = (TF_LEN) (1 /*seq*/ + count * sizeof(uint16_t)), .len = (TF_LEN) (1 /*seq*/ + count * sizeof(uint16_t)),
.type = type, .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, &priv->stream_serial, 1);
TF_Multipart_Payload(comm, (uint8_t *) (priv->dma_buffer + start), count * sizeof(uint16_t)); TF_Multipart_Payload(comm, (uint8_t *) (priv->dma_buffer + start), count * sizeof(uint16_t));
TF_Multipart_Close(comm); 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; const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP;
if (ht) { if (ht) {
end = (priv->buf_itemcount / 2); end = (priv->buf_itemcount >> 1); // div2
} }
else { else {
end = priv->buf_itemcount; end = priv->buf_itemcount;
@@ -234,7 +235,7 @@ static void handle_httc(Unit *unit, bool tc)
priv->stream_startpos = 0; priv->stream_startpos = 0;
} }
else { 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_stream = priv->opmode == ADC_OPMODE_STREAM;
const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP; const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP;
if (m_trigd || m_stream || m_fixcpt) { 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) { if (ht && tc) {
// dual event interrupt - may happen if we missed both and they were pending after // 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) // 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; if (priv->opmode == ADC_OPMODE_UNINIT) return;
// Wait for the DMA to complete copying the last sample // Wait for the DMA to complete copying the last sample
uint32_t dmapos; uint32_t dmapos = DMA_POS(priv);
hw_wait_while((dmapos = DMA_POS(priv)) % priv->nb_channels != 0, 100); // XXX this could be changed to reading it from the DR instead 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; uint32_t sample_pos;
if (dmapos == 0) { if (dmapos == 0) {
+5 -5
View File
@@ -80,14 +80,14 @@ void UADC_writeIni(Unit *unit, IniWriter *iw)
iw_comment(iw, "Enabled channels, comma separated"); 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, " 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_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_cmt_newline(iw);
iw_comment(iw, "Sampling time (0-7)"); 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_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_cmt_newline(iw);
iw_comment(iw, "Sample buffer size"); 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, "- defines the maximum pre-trigger size (divide by # of channels)");
iw_comment(iw, "- captured data is sent in half-buffer chunks"); iw_comment(iw, "- captured data is sent in half-buffer chunks");
iw_comment(iw, "- buffer overrun aborts the data capture"); 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_cmt_newline(iw);
iw_comment(iw, "Exponential averaging coefficient (permil, range 0-1000 ~ 0.000-1.000)"); 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, "- used formula: y[t]=(1-k)*y[t-1]+k*u[t]");
iw_comment(iw, "- not available when a capture is running"); 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);
} }
+7 -7
View File
@@ -92,24 +92,24 @@ void DIn_writeIni(Unit *unit, IniWriter *iw)
iw_entry(iw, "port", "%c", priv->port_name); iw_entry(iw, "port", "%c", priv->port_name);
iw_comment(iw, "Pins (comma separated, supports ranges)"); 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_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_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_cmt_newline(iw);
iw_comment(iw, "Trigger pins activated by rising/falling edge"); 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_s(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-fall", cfg_pinmask_encode(priv->trig_fall, unit_tmp512, 0));
iw_comment(iw, "Trigger pins auto-armed by default"); 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_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 #if PLAT_NO_FLOATING_INPUTS
iw_comment(iw, "NOTE: Pins use pull-up by default.\r\n"); iw_comment(iw, "NOTE: Pins use pull-up by default.\r\n");
+3 -3
View File
@@ -72,11 +72,11 @@ void DOut_writeIni(Unit *unit, IniWriter *iw)
iw_entry(iw, "port", "%c", priv->port_name); iw_entry(iw, "port", "%c", priv->port_name);
iw_comment(iw, "Pins (comma separated, supports ranges)"); 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_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_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));
} }
+5 -5
View File
@@ -92,20 +92,20 @@ void UFCAP_writeIni(Unit *unit, IniWriter *iw)
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Active level or edge (0-low,falling; 1-high,rising)"); 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_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_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_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_cmt_newline(iw);
iw_comment(iw, "Mode on startup: N-none, I-indirect, D-direct, F-free count"); 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_IDLE, "N",
OPMODE_INDIRECT_CONT, "I", OPMODE_INDIRECT_CONT, "I",
OPMODE_DIRECT_CONT, "D", OPMODE_DIRECT_CONT, "D",
+5 -5
View File
@@ -74,7 +74,7 @@ void UI2C_writeIni(Unit *unit, IniWriter *iw)
struct priv *priv = unit->data; struct priv *priv = unit->data;
iw_comment(iw, "Peripheral number (I2Cx)"); 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)"); iw_comment(iw, "Pin mappings (SCL,SDA)");
#if GEX_PLAT_F072_DISCOVERY #if GEX_PLAT_F072_DISCOVERY
@@ -89,15 +89,15 @@ void UI2C_writeIni(Unit *unit, IniWriter *iw)
#else #else
#error "BAD PLATFORM!" #error "BAD PLATFORM!"
#endif #endif
iw_entry(iw, "remap", "%d", (int)priv->remap); iw_entry_d(iw, "remap", priv->remap);
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Speed: 1-Standard, 2-Fast, 3-Fast+"); 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_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_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);
} }
+2 -2
View File
@@ -54,8 +54,8 @@ void Npx_writeIni(Unit *unit, IniWriter *iw)
struct priv *priv = unit->data; struct priv *priv = unit->data;
iw_comment(iw, "Data pin"); 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_comment(iw, "Number of pixels");
iw_entry(iw, "pixels", "%d", priv->cfg.pixels); iw_entry_d(iw, "pixels", priv->cfg.pixels);
} }
+64
View File
@@ -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;
}
+170
View File
@@ -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);
}
+65
View File
@@ -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
+89
View File
@@ -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);
}
+69
View File
@@ -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,
};
+16
View File
@@ -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
+7 -7
View File
@@ -98,19 +98,19 @@ void USIPO_writeIni(Unit *unit, IniWriter *iw)
struct priv *priv = unit->data; struct priv *priv = unit->data;
iw_comment(iw, "Shift pin & its active edge (1-rising,0-falling)"); 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_s(iw, "shift-pin", cfg_pinrsc_encode(priv->cfg.pin_shift));
iw_entry(iw, "shift-pol", "%d", priv->cfg.shift_pol); iw_entry_d(iw, "shift-pol", priv->cfg.shift_pol);
iw_comment(iw, "Store pin & its active edge"); iw_comment(iw, "Store pin & its active edge");
iw_entry(iw, "store-pin", cfg_pinrsc_encode(priv->cfg.pin_store)); iw_entry_s(iw, "store-pin", cfg_pinrsc_encode(priv->cfg.pin_store));
iw_entry(iw, "store-pol", "%d", priv->cfg.store_pol); iw_entry_d(iw, "store-pol", priv->cfg.store_pol);
iw_comment(iw, "Clear pin & its active level"); iw_comment(iw, "Clear pin & its active level");
iw_entry(iw, "clear-pin", cfg_pinrsc_encode(priv->cfg.pin_clear)); iw_entry_s(iw, "clear-pin", cfg_pinrsc_encode(priv->cfg.pin_clear));
iw_entry(iw, "clear-pol", "%d", priv->cfg.clear_pol); iw_entry_d(iw, "clear-pol", priv->cfg.clear_pol);
iw_comment(iw, "Data port and pins"); iw_comment(iw, "Data port and pins");
iw_entry(iw, "data-port", "%c", priv->cfg.data_pname); 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));
} }
+8 -8
View File
@@ -98,7 +98,7 @@ void USPI_writeIni(Unit *unit, IniWriter *iw)
struct priv *priv = unit->data; struct priv *priv = unit->data;
iw_comment(iw, "Peripheral number (SPIx)"); 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 // TODO show a legend for peripherals and remaps
iw_comment(iw, "Pin mappings (SCK,MISO,MOSI)"); iw_comment(iw, "Pin mappings (SCK,MISO,MOSI)");
@@ -114,28 +114,28 @@ void USPI_writeIni(Unit *unit, IniWriter *iw)
#else #else
#error "BAD PLATFORM!" #error "BAD PLATFORM!"
#endif #endif
iw_entry(iw, "remap", "%d", (int)priv->remap); iw_entry_d(iw, "remap", priv->remap);
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Prescaller: 2,4,8,...,256"); 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_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_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_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_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_cmt_newline(iw);
iw_comment(iw, "SS port name"); iw_comment(iw, "SS port name");
iw_entry(iw, "port", "%c", priv->ssn_port_name); iw_entry(iw, "port", "%c", priv->ssn_port_name);
iw_comment(iw, "SS pins (comma separated, supports ranges)"); 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));
} }
+23
View File
@@ -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
+11
View File
@@ -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"
+217
View File
@@ -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;
}
+221
View File
@@ -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);
}
+95
View File
@@ -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
+187
View File
@@ -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));
}
}
+136
View File
@@ -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,
};
+16
View File
@@ -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
+19 -19
View File
@@ -156,7 +156,7 @@ void UUSART_writeIni(Unit *unit, IniWriter *iw)
struct priv *priv = unit->data; struct priv *priv = unit->data;
iw_comment(iw, "Peripheral number (UARTx 1-4)"); 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)"); iw_comment(iw, "Pin mappings (TX,RX,CK,CTS,RTS/DE)");
#if GEX_PLAT_F072_DISCOVERY #if GEX_PLAT_F072_DISCOVERY
@@ -173,41 +173,41 @@ void UUSART_writeIni(Unit *unit, IniWriter *iw)
#else #else
#error "BAD PLATFORM!" #error "BAD PLATFORM!"
#endif #endif
iw_entry(iw, "remap", "%d", (int)priv->remap); iw_entry_d(iw, "remap", priv->remap);
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Baud rate in bps (eg. 9600, 115200)"); // TODO examples/range iw_comment(iw, "Baud rate in bps (eg. 9600)");
iw_entry(iw, "baud-rate", "%d", (int)priv->baudrate); iw_entry_d(iw, "baud-rate", priv->baudrate);
iw_comment(iw, "Parity type (NONE, ODD, EVEN)"); 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", 0, "NONE",
1, "ODD", 1, "ODD",
2, "EVEN")); 2, "EVEN"));
iw_comment(iw, "Number of stop bits (0.5, 1, 1.5, 2)"); 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", 0, "0.5",
1, "1", 1, "1",
2, "1.5", 2, "1.5",
3, "2")); 3, "2"));
iw_comment(iw, "Bit order (LSB or MSB first)"); 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", 0, "MSB",
1, "LSB")); 1, "LSB"));
iw_comment(iw, "Word width (7,8,9) - including parity bit if used"); 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_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", 1, "RX",
2, "TX", 2, "TX",
3, "RXTX")); 3, "RXTX"));
iw_comment(iw, "Hardware flow control (NONE, RTS, CTS, FULL)"); 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", 0, "NONE",
1, "RTS", 1, "RTS",
2, "CTS", 2, "CTS",
@@ -215,19 +215,19 @@ void UUSART_writeIni(Unit *unit, IniWriter *iw)
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Generate serial clock (Y,N)"); iw_comment(iw, "Generate serial clock (Y,N)");
iw_entry(iw, "clock-output", str_yn(priv->clock_output)); iw_entry_s(iw, "clock-output", str_yn(priv->clock_output));
iw_comment(iw, "Output clock polarity: 0,1 (clock idle level)"); iw_comment(iw, "Clock polarity: 0,1");
iw_entry(iw, "cpol", "%d", (int)priv->cpol); iw_entry_d(iw, "cpol", priv->cpol);
iw_comment(iw, "Output clock phase: 0,1 (active edge, 0-first, 1-second)"); iw_comment(iw, "Clock phase: 0,1");
iw_entry(iw, "cpha", "%d", (int)priv->cpha); iw_entry_d(iw, "cpha", priv->cpha);
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Generate RS485 Driver Enable signal (Y,N) - uses RTS pin"); 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_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_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_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));
} }
+112 -503
View File
@@ -1,526 +1,135 @@
/* #line 1 "ini_parser.rl" */
/* Ragel constants block */
#include "ini_parser.h" #include "ini_parser.h"
// Ragel setup enum nini_state {
NINI_IDLE,
/* #line 10 "ini_parser.c" */ NINI_SECTION,
static const char _ini_actions[] = { NINI_KEY,
0, 1, 1, 1, 2, 1, 3, 1, NINI_VALUE,
4, 1, 5, 1, 6, 1, 7, 1, NINI_COMMENT,
8, 1, 9, 1, 10, 1, 11, 1,
13, 2, 0, 4, 2, 12, 4
}; };
static const char _ini_eof_actions[] = { static struct {
0, 23, 5, 5, 15, 15, 15, 15, uint8_t section_i;
19, 19, 0, 0, 0, 0, 0, 0, char section[INI_KEY_MAX];
0
};
static const int ini_start = 1; uint8_t key_i;
static const int ini_first_final = 12; char key[INI_KEY_MAX];
static const int ini_error = 0;
static const int ini_en_section = 2; uint8_t value_i;
static const int ini_en_keyvalue = 4; char value[INI_VALUE_MAX];
static const int ini_en_comment = 8; bool val_last_space;
static const int ini_en_discard2eol = 10;
static const int ini_en_main = 1;
IniParserCallback cb;
void *userdata;
enum nini_state state;
} nini;
/* #line 10 "ini_parser.rl" */ void ini_parse_begin(IniParserCallback callback, void *userData)
// 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)
{ {
buff_i = 0; ini_parse_reset();
value_quote = 0; nini.cb = callback;
value_nextesc = false; nini.userdata = userData;
} }
void void ini_parse(const char *data, size_t len)
ini_parse_reset(void)
{ {
ini_parse_reset_partial(); for (; len > 0; len--) {
keybuf[0] = secbuf[0] = valbuf[0] = 0; char c = *data++;
if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
/* #line 67 "ini_parser.c" */ if (nini.state != NINI_VALUE && nini.state != NINI_COMMENT)
{ continue;
cs = ini_start; }
}
/* #line 41 "ini_parser.rl" */ 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;
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 void *ini_parse_end(void)
ini_parser_error(const char* msg)
{ {
ini_error("Parser error: %s", msg); if (nini.state == NINI_VALUE) {
ini_parse_reset_partial(); 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_file(const char *text, size_t len, IniParserCallback callback, void *userData)
void
ini_parse_begin(IniParserCallback callback, void *userData)
{ {
keyCallback = callback; ini_parse_begin(callback, userData);
userdata = userData; ini_parse(text, len);
ini_parse_reset(); ini_parse_end();
} }
void ini_parse_reset(void)
void
*ini_parse_end(void)
{ {
ini_parse("\n", 1); nini.state = NINI_IDLE;
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" */
} }
+1 -9
View File
@@ -1,6 +1,5 @@
// //
// INI file parser with a FSM generated by Ragel. This was originally written for ESPTerm // INI file parser. Used to extract sections, keys and values from user-provided settings file
// Used to extract sections, keys and values from user-provided settings file
// //
#ifndef INIPARSE_STREAM_H #ifndef INIPARSE_STREAM_H
@@ -8,13 +7,6 @@
#include "platform.h" #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 // buffer sizes
//#define INI_KEY_MAX 20 //#define INI_KEY_MAX 20
//#define INI_VALUE_MAX 30 // moved to plat_compat.h //#define INI_VALUE_MAX 30 // moved to plat_compat.h
-284
View File
@@ -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;
#*/
}%%
}
+19
View File
@@ -119,6 +119,25 @@ void iw_entry(IniWriter *iw, const char *key, const char *format, ...)
iw_newline(iw); // one newline after entry 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) uint32_t iw_measure_total(void (*handler)(IniWriter *), uint32_t tag)
{ {
IniWriter iw = iw_init(NULL, 0xFFFFFFFF, 1); IniWriter iw = iw_init(NULL, 0xFFFFFFFF, 1);
+3
View File
@@ -126,6 +126,9 @@ __attribute__((format(printf,2,3)));
void iw_entry(IniWriter *iw, const char *key, const char *format, ...) void iw_entry(IniWriter *iw, const char *key, const char *format, ...)
__attribute__((format(printf,3,4))); __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 * Measure total ini writer length using a dummy write
* *
+10 -20
View File
@@ -1,3 +1,4 @@
#include <debug.h>
#include "payload_parser.h" #include "payload_parser.h"
#define pp_check_capacity(pp, needed) \ #define pp_check_capacity(pp, needed) \
@@ -58,32 +59,21 @@ uint32_t pp_u32(PayloadParser *pp)
uint64_t pp_u64(PayloadParser *pp) uint64_t pp_u64(PayloadParser *pp)
{ {
pp_check_capacity(pp, 4); pp_check_capacity(pp, 8);
if (!pp->ok) return 0; if (!pp->ok) return 0;
uint64_t x = 0; uint32_t x0, x1;
uint64_t x;
if (pp->bigendian) { if (pp->bigendian) {
x |= (uint64_t) ((uint64_t) *pp->current++ << 56); x1 = pp_u32(pp);
x |= (uint64_t) ((uint64_t) *pp->current++ << 48); x0 = pp_u32(pp);
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++;
} else { } else {
x |= *pp->current++; x0 = pp_u32(pp);
x |= (uint64_t) (*pp->current++ << 8); x1 = pp_u32(pp);
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);
} }
x = ((uint64_t)x1)<<32 | x0;
return x; return x;
} }
+1 -1
View File
@@ -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) void vfs_user_build_filesystem(void)
{ {
dbg("Rebuilding VFS..."); vfs_printf("Rebuilding VFS...");
// Setup the filesystem based on target parameters // Setup the filesystem based on target parameters
vfs_init(daplink_drive_name, 0/*unused "disk size"*/); vfs_init(daplink_drive_name, 0/*unused "disk size"*/);