30 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
MightyPork 1a888366af fixes, and use the new rsc parsing for some unit pins 2018-02-23 11:24:10 +01:00
MightyPork a60b736834 massive utils refactoring, renames, avr libc utils cleaning 2018-02-23 10:55:49 +01:00
MightyPork 8dcdaf9236 provisions for representing pins via resources in settings 2018-02-22 23:33:11 +01:00
MightyPork f8181a10d1 fix a bug in fcap conf 2018-02-22 13:46:21 +01:00
MightyPork b678a8f2b7 fcap cleaning, added new features and reorganized the unit 2018-02-22 13:42:42 +01:00
MightyPork 805e47594a direct measurement (need more testing) 2018-02-21 23:11:06 +01:00
MightyPork 75efa12338 wip direct, unfinished config 2018-02-20 22:58:24 +01:00
MightyPork 20dfa7e158 mod fcap to always fully deinit the timer when IDLE 2018-02-20 15:58:20 +01:00
MightyPork 1a6dd4b5ae indirect frequency measurement 2018-02-20 13:24:35 +01:00
MightyPork 6d8aa4d31d fixed broken new unit callsign assign algo 2018-02-18 09:15:44 +01:00
100 changed files with 3951 additions and 2316 deletions
+1 -1
View File
@@ -110,7 +110,7 @@ extern uint32_t SystemCoreClock;
#define configCHECK_FOR_STACK_OVERFLOW 2
#define configENABLE_BACKWARD_COMPATIBILITY 0
#define configUSE_TIMERS 1
#define configUSE_TIMERS 0
#define configTIMER_TASK_PRIORITY TSK_TIMERS_PRIO // above normal
#define configTIMER_TASK_STACK_DEPTH TSK_STACK_TIMERS //128
#define configTIMER_QUEUE_LENGTH 4
+47 -5
View File
@@ -8,6 +8,7 @@
#include "task_main.h"
#include "USB/usbd_cdc_if.h"
#include "USB/usb_device.h"
#include "TinyFrame.h"
extern osSemaphoreId semVcomTxReadyHandle;
@@ -15,6 +16,30 @@ extern osMutexId mutTinyFrameTxHandle;
void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
{
#if 1
const uint32_t real_size = len;
// Padding to a multiple of 64 bytes - this is supposed to maximize the bulk transfer speed
if (len&0x3F) {
uint32_t pad = (64 - (len&0x3F));
memset((void *) (buff + len), 0, pad);
len += pad; // padding to a multiple of 64 (size of the endpoint)
}
// We bypass the USBD driver library's overhead by using the HAL function directly
assert_param(HAL_OK == HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) buff, len));
// The buffer is the TF transmit buffer, we can't leave it to work asynchronously because
// the next call could modify it before it's been transmitted (in the case of a chunked / multi-part frame)
// the assumption here is that all until the last chunk use the full buffer capacity
if (real_size == TF_SENDBUF_LEN) {
if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 100)) {
TF_Error("Tx stalled in WriteImpl");
return;
}
}
#else
(void) tf;
#define CHUNK 64 // same as TF_SENDBUF_LEN, so we should always have only one run of the loop
int32_t total = (int32_t) len;
@@ -26,21 +51,36 @@ void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
}
const uint16_t chunksize = (uint16_t) MIN(total, CHUNK);
assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, chunksize));
// this is an attempt to speed it up a little by removing a couple levels of indirection
assert_param(HAL_OK == HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) buff, chunksize));
// USBD_LL_Transmit(&hUsbDeviceFS, CDC_IN_EP, (uint8_t *) buff, chunksize);
// assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, chunksize));
buff += chunksize;
total -= chunksize;
}
#endif
}
/** Claim the TX interface before composing and sending a frame */
bool TF_ClaimTx(TinyFrame *tf)
{
(void) tf;
// assert_param(osThreadGetId() != tskMainHandle);
assert_param(!inIRQ());
// assert_param(!inIRQ()); // useless delay
assert_param(pdTRUE == xSemaphoreTake(mutTinyFrameTxHandle, 5000)); // trips the wd
// The last chunk from some previous frame may still be being transmitted,
// wait for it to finish (the semaphore is given in the CDC tx done handler)
if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 100)) {
TF_Error("Tx stalled in Claim");
// release the guarding mutex again
assert_param(pdTRUE == xSemaphoreGive(mutTinyFrameTxHandle));
return false;
}
assert_param(osOK == osMutexWait(mutTinyFrameTxHandle, 5000));
return true;
}
@@ -48,5 +88,7 @@ bool TF_ClaimTx(TinyFrame *tf)
void TF_ReleaseTx(TinyFrame *tf)
{
(void) tf;
assert_param(osOK == osMutexRelease(mutTinyFrameTxHandle));
assert_param(pdTRUE == xSemaphoreGive(mutTinyFrameTxHandle));
// the last payload is sent asynchronously
}
+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)
{
TF_TRY(TF_ClaimTx(tf));
bool suc = TF_ClaimTx(tf);
if (!suc) {
TF_Error("TF lock not free");
return false;
}
tf->tx_pos = (uint32_t) TF_ComposeHead(tf, tf->sendbuf, msg); // frame ID is incremented here if it's not a response
tf->tx_len = msg->len;
@@ -1031,10 +1035,10 @@ bool _TF_FN TF_Query_Multipart(TinyFrame *tf, TF_Msg *msg, TF_Listener listener,
return TF_Query(tf, msg, listener, timeout);
}
void _TF_FN TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg)
bool _TF_FN TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg)
{
msg->data = NULL;
TF_Respond(tf, msg);
return TF_Respond(tf, msg);
}
void _TF_FN TF_Multipart_Payload(TinyFrame *tf, const uint8_t *buff, uint32_t length)
+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.
* 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
@@ -1,328 +0,0 @@
--- Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c (date 1511202099000)
+++ Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c (revision )
@@ -59,6 +59,7 @@
*/
/* Includes ------------------------------------------------------------------*/
+#include "usbd_msc.h" // for rejecting bad control messages
#include "usbd_cdc.h"
#include "usbd_desc.h"
#include "usbd_ctlreq.h"
@@ -103,34 +104,7 @@
* @{
*/
-
-static uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev,
- uint8_t cfgidx);
-
-static uint8_t USBD_CDC_DeInit (USBD_HandleTypeDef *pdev,
- uint8_t cfgidx);
-
-static uint8_t USBD_CDC_Setup (USBD_HandleTypeDef *pdev,
- USBD_SetupReqTypedef *req);
-
-static uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev,
- uint8_t epnum);
-
-static uint8_t USBD_CDC_DataOut (USBD_HandleTypeDef *pdev,
- uint8_t epnum);
-
-static uint8_t USBD_CDC_EP0_RxReady (USBD_HandleTypeDef *pdev);
-
-static uint8_t *USBD_CDC_GetFSCfgDesc (uint16_t *length);
-
-static uint8_t *USBD_CDC_GetHSCfgDesc (uint16_t *length);
-
-static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc (uint16_t *length);
-
-static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc (uint16_t *length);
-
-uint8_t *USBD_CDC_GetDeviceQualifierDescriptor (uint16_t *length);
-
+#ifndef CDC_COMPOSITE
/* USB Standard Device Descriptor */
__ALIGN_BEGIN static uint8_t USBD_CDC_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
{
@@ -156,7 +130,7 @@
/* CDC interface class callbacks structure */
-USBD_ClassTypeDef USBD_CDC =
+USBD_ClassTypeDef USBD_CDC =
{
USBD_CDC_Init,
USBD_CDC_DeInit,
@@ -172,6 +146,7 @@
USBD_CDC_GetFSCfgDesc,
USBD_CDC_GetOtherSpeedCfgDesc,
USBD_CDC_GetDeviceQualifierDescriptor,
+ NULL
};
/* USB CDC device Configuration Descriptor */
@@ -456,6 +431,7 @@
0x00,
0x00 /* bInterval */
};
+#endif
/**
* @}
@@ -463,7 +439,7 @@
/** @defgroup USBD_CDC_Private_Functions
* @{
- */
+ */
/**
* @brief USBD_CDC_Init
@@ -472,7 +448,7 @@
* @param cfgidx: Configuration index
* @retval status
*/
-static uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev,
+uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev,
uint8_t cfgidx)
{
uint8_t ret = 0;
@@ -514,18 +490,18 @@
CDC_CMD_PACKET_SIZE);
- pdev->pClassData = USBD_malloc(sizeof (USBD_CDC_HandleTypeDef));
+ pdev->pClassData2 = USBD_malloc(sizeof (USBD_CDC_HandleTypeDef));
- if(pdev->pClassData == NULL)
+ if(pdev->pClassData2 == NULL)
{
ret = 1;
}
else
{
- hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
/* Init physical Interface components */
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Init();
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->Init();
/* Init Xfer states */
hcdc->TxState =0;
@@ -560,7 +536,7 @@
* @param cfgidx: Configuration index
* @retval status
*/
-static uint8_t USBD_CDC_DeInit (USBD_HandleTypeDef *pdev,
+uint8_t USBD_CDC_DeInit (USBD_HandleTypeDef *pdev,
uint8_t cfgidx)
{
uint8_t ret = 0;
@@ -579,11 +555,11 @@
/* DeInit physical Interface components */
- if(pdev->pClassData != NULL)
+ if(pdev->pClassData2 != NULL)
{
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->DeInit();
- USBD_free(pdev->pClassData);
- pdev->pClassData = NULL;
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->DeInit();
+ USBD_free(pdev->pClassData2);
+ pdev->pClassData2 = NULL;
}
return ret;
@@ -596,20 +572,23 @@
* @param req: usb requests
* @retval status
*/
-static uint8_t USBD_CDC_Setup (USBD_HandleTypeDef *pdev,
+uint8_t USBD_CDC_Setup (USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req)
{
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
static uint8_t ifalt = 0;
switch (req->bmRequest & USB_REQ_TYPE_MASK)
{
case USB_REQ_TYPE_CLASS :
+ if (req->bRequest == BOT_GET_MAX_LUN) break; // Not ours!
+ if (req->bRequest == BOT_RESET) break; // Not ours!
+
if (req->wLength)
{
if (req->bmRequest & 0x80)
{
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Control(req->bRequest,
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->Control(req->bRequest,
(uint8_t *)hcdc->data,
req->wLength);
USBD_CtlSendData (pdev,
@@ -629,7 +608,7 @@
}
else
{
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Control(req->bRequest,
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->Control(req->bRequest,
(uint8_t*)req,
0);
}
@@ -661,14 +640,15 @@
* @param epnum: endpoint number
* @retval status
*/
-static uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)
+uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)
{
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
- if(pdev->pClassData != NULL)
+ if(pdev->pClassData2 != NULL)
{
hcdc->TxState = 0;
+ USBD_CDC_TransmitDone(pdev);
return USBD_OK;
}
@@ -685,18 +665,18 @@
* @param epnum: endpoint number
* @retval status
*/
-static uint8_t USBD_CDC_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
+uint8_t USBD_CDC_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
{
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
/* Get the received data length */
hcdc->RxLength = USBD_LL_GetRxDataSize (pdev, epnum);
/* USB data will be immediately processed, this allow next USB traffic being
NAKed till the end of the application Xfer */
- if(pdev->pClassData != NULL)
+ if(pdev->pClassData2 != NULL)
{
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Receive(hcdc->RxBuffer, &hcdc->RxLength);
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->Receive(hcdc->RxBuffer, &hcdc->RxLength);
return USBD_OK;
}
@@ -715,13 +695,13 @@
* @param epnum: endpoint number
* @retval status
*/
-static uint8_t USBD_CDC_EP0_RxReady (USBD_HandleTypeDef *pdev)
+uint8_t USBD_CDC_EP0_RxReady (USBD_HandleTypeDef *pdev)
{
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
- if((pdev->pUserData != NULL) && (hcdc->CmdOpCode != 0xFF))
+ if((pdev->pUserData2 != NULL) && (hcdc->CmdOpCode != 0xFF))
{
- ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Control(hcdc->CmdOpCode,
+ ((USBD_CDC_ItfTypeDef *)pdev->pUserData2)->Control(hcdc->CmdOpCode,
(uint8_t *)hcdc->data,
hcdc->CmdLength);
hcdc->CmdOpCode = 0xFF;
@@ -730,6 +710,7 @@
return USBD_OK;
}
+#ifndef CDC_COMPOSITE
/**
* @brief USBD_CDC_GetFSCfgDesc
* Return configuration descriptor
@@ -737,7 +718,7 @@
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
-static uint8_t *USBD_CDC_GetFSCfgDesc (uint16_t *length)
+uint8_t *USBD_CDC_GetFSCfgDesc (uint16_t *length)
{
*length = sizeof (USBD_CDC_CfgFSDesc);
return USBD_CDC_CfgFSDesc;
@@ -750,7 +731,7 @@
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
-static uint8_t *USBD_CDC_GetHSCfgDesc (uint16_t *length)
+uint8_t *USBD_CDC_GetHSCfgDesc (uint16_t *length)
{
*length = sizeof (USBD_CDC_CfgHSDesc);
return USBD_CDC_CfgHSDesc;
@@ -763,7 +744,7 @@
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
-static uint8_t *USBD_CDC_GetOtherSpeedCfgDesc (uint16_t *length)
+uint8_t *USBD_CDC_GetOtherSpeedCfgDesc (uint16_t *length)
{
*length = sizeof (USBD_CDC_OtherSpeedCfgDesc);
return USBD_CDC_OtherSpeedCfgDesc;
@@ -780,6 +761,7 @@
*length = sizeof (USBD_CDC_DeviceQualifierDesc);
return USBD_CDC_DeviceQualifierDesc;
}
+#endif
/**
* @brief USBD_CDC_RegisterInterface
@@ -794,7 +776,7 @@
if(fops != NULL)
{
- pdev->pUserData= fops;
+ pdev->pUserData2= fops;
ret = USBD_OK;
}
@@ -811,7 +793,7 @@
uint8_t *pbuff,
uint16_t length)
{
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
hcdc->TxBuffer = pbuff;
hcdc->TxLength = length;
@@ -829,7 +811,7 @@
uint8_t USBD_CDC_SetRxBuffer (USBD_HandleTypeDef *pdev,
uint8_t *pbuff)
{
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
hcdc->RxBuffer = pbuff;
@@ -845,9 +827,9 @@
*/
uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)
{
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
- if(pdev->pClassData != NULL)
+ if(pdev->pClassData2 != NULL)
{
if(hcdc->TxState == 0)
{
@@ -882,10 +864,10 @@
*/
uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev)
{
- USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
+ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData2;
/* Suspend or Resume USB Out process */
- if(pdev->pClassData != NULL)
+ if(pdev->pClassData2 != NULL)
{
if(pdev->dev_speed == USBD_SPEED_HIGH )
{
@@ -1,60 +0,0 @@
--- Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc.h (date 1511202099000)
+++ Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc.h (revision )
@@ -58,9 +58,10 @@
#define BOT_RESET 0xFF
#define USB_MSC_CONFIG_DESC_SIZ 32
-
+#ifndef MSC_CUSTOM_EPS
#define MSC_EPIN_ADDR 0x81
-#define MSC_EPOUT_ADDR 0x01
+#define MSC_EPOUT_ADDR 0x01
+#endif
/**
* @}
@@ -107,7 +108,7 @@
USBD_MSC_BOT_HandleTypeDef;
/* Structure for MSC process */
-extern USBD_ClassTypeDef USBD_MSC;
+extern USBD_ClassTypeDef USBD_MSC;
#define USBD_MSC_CLASS &USBD_MSC
uint8_t USBD_MSC_RegisterStorage (USBD_HandleTypeDef *pdev,
@@ -118,8 +119,34 @@
/**
* @}
- */
+ */
+// XXX "static" moved here for use in composite driver
+
+uint8_t USBD_MSC_Init (USBD_HandleTypeDef *pdev,
+ uint8_t cfgidx);
+
+uint8_t USBD_MSC_DeInit (USBD_HandleTypeDef *pdev,
+ uint8_t cfgidx);
+
+uint8_t USBD_MSC_Setup (USBD_HandleTypeDef *pdev,
+ USBD_SetupReqTypedef *req);
+
+uint8_t USBD_MSC_DataIn (USBD_HandleTypeDef *pdev,
+ uint8_t epnum);
+
+
+uint8_t USBD_MSC_DataOut (USBD_HandleTypeDef *pdev,
+ uint8_t epnum);
+
+uint8_t *USBD_MSC_GetHSCfgDesc (uint16_t *length);
+
+uint8_t *USBD_MSC_GetFSCfgDesc (uint16_t *length);
+
+uint8_t *USBD_MSC_GetOtherSpeedCfgDesc (uint16_t *length);
+
+uint8_t *USBD_MSC_GetDeviceQualifierDescriptor (uint16_t *length);
+
#ifdef __cplusplus
}
#endif
@@ -1,35 +0,0 @@
--- Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc.c (date 1511202099000)
+++ Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc.c (revision )
@@ -116,7 +116,7 @@
* @{
*/
-
+#ifndef MSC_COMPOSITE
USBD_ClassTypeDef USBD_MSC =
{
USBD_MSC_Init,
@@ -279,6 +279,7 @@
0x01,
0x00,
};
+#endif
/**
* @}
*/
@@ -530,6 +531,7 @@
return 0;
}
+#ifndef MSC_COMPOSITE
/**
* @brief USBD_MSC_GetHSCfgDesc
* return configuration descriptor
@@ -576,6 +578,7 @@
*length = sizeof (USBD_MSC_DeviceQualifierDesc);
return USBD_MSC_DeviceQualifierDesc;
}
+#endif
/**
* @brief USBD_MSC_RegisterStorage
@@ -1,37 +0,0 @@
--- Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c (date 1511202099000)
+++ Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c (revision )
@@ -190,14 +190,27 @@
INVALID_CDB);
return -1;
}
-
- if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
+
+ // XXX THIS SECTION IS MODIFIED FOR NOTIFY!
+ // https://www.microchip.com/forums/m401735.aspx
+ int8_t changeStatus = ((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun);
+ if(changeStatus != 0)
{
- SCSI_SenseCode(pdev,
- lun,
- NOT_READY,
- MEDIUM_NOT_PRESENT);
-
+ if (changeStatus == -1)
+ {
+ SCSI_SenseCode(pdev,
+ lun,
+ UNIT_ATTENTION,
+ MEDIUM_HAVE_CHANGED);
+ }
+ else
+ {
+ SCSI_SenseCode(pdev,
+ lun,
+ NOT_READY,
+ MEDIUM_NOT_PRESENT);
+ }
+
hmsc->bot_state = USBD_BOT_NO_DATA;
return -1;
}
@@ -265,8 +265,8 @@ typedef struct _USBD_HandleTypeDef
#define SWAPBYTE(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \
(((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8))
#define LOBYTE(x) ((uint8_t)(x & 0x00FF))
#define HIBYTE(x) ((uint8_t)((x & 0xFF00) >>8))
#define LOBYTE(x) ((uint8_t)((x) & 0x00FF))
#define HIBYTE(x) ((uint8_t)(((x) & 0xFF00) >>8))
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
@@ -1,62 +0,0 @@
--- Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h (date 1511202099000)
+++ Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h (revision )
@@ -99,6 +99,7 @@
#define USB_DESC_TYPE_ENDPOINT 5
#define USB_DESC_TYPE_DEVICE_QUALIFIER 6
#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 7
+#define USB_DESC_TYPE_IFACE_ASSOCIATION 11
#define USB_DESC_TYPE_BOS 0x0F
#define USB_CONFIG_REMOTE_WAKEUP 2
@@ -147,7 +148,7 @@
typedef struct usb_setup_req
{
-
+
uint8_t bmRequest;
uint8_t bRequest;
uint16_t wValue;
@@ -230,7 +231,7 @@
uint32_t dev_config_status;
USBD_SpeedTypeDef dev_speed;
USBD_EndpointTypeDef ep_in[15];
- USBD_EndpointTypeDef ep_out[15];
+ USBD_EndpointTypeDef ep_out[15];
uint32_t ep0_state;
uint32_t ep0_data_len;
uint8_t dev_state;
@@ -242,10 +243,14 @@
USBD_SetupReqTypedef request;
USBD_DescriptorsTypeDef *pDesc;
- USBD_ClassTypeDef *pClass;
- void *pClassData;
- void *pUserData;
- void *pData;
+ USBD_ClassTypeDef *pClass; // the composite class
+ void *pClassData;
+ void *pUserData;
+ void *pClassData2; // used for secondary class
+ void *pUserData2; // used for secondary class
+ void *pClassData3; // used for tertiary class
+ void *pUserData3; // used for tertiary class
+ void *pData; // this is a pointer to the low level registers struct
} USBD_HandleTypeDef;
/**
@@ -262,8 +267,14 @@
#define LOBYTE(x) ((uint8_t)(x & 0x00FF))
#define HIBYTE(x) ((uint8_t)((x & 0xFF00) >>8))
+
+#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
#if defined ( __GNUC__ )
+1
View File
@@ -66,6 +66,7 @@ PCD_HandleTypeDef hpcd_USB_FS;
/* init function */
void MX_USB_DEVICE_Init(void)
{
dbg("USB device init ...");
/* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */
/* USER CODE END USB_DEVICE_Init_PreTreatment */
+1 -1
View File
@@ -314,7 +314,7 @@ void USBD_CDC_TransmitDone(USBD_HandleTypeDef *pdev)
assert_param(inIRQ());
portBASE_TYPE taskWoken = pdFALSE;
assert_param(xSemaphoreGiveFromISR(semVcomTxReadyHandle, &taskWoken) == pdTRUE);
assert_param(pdTRUE == xSemaphoreGiveFromISR(semVcomTxReadyHandle, &taskWoken));
portYIELD_FROM_ISR(taskWoken);
}
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
+9 -4
View File
@@ -2,6 +2,7 @@
// Created by MightyPork on 2017/11/21.
//
#include <platform/status_led.h>
#include "platform.h"
#include "framework/settings.h"
#include "utils/ini_parser.h"
@@ -64,7 +65,7 @@ static void settings_bulkread_cb(BulkRead *bulk, uint32_t chunk, uint8_t *buffer
if (buffer == NULL) {
free_ck(bulk);
iw_end();
dbg("INI read complete.");
// dbg("INI read complete.");
return;
}
@@ -80,7 +81,7 @@ static void settings_bulkread_cb(BulkRead *bulk, uint32_t chunk, uint8_t *buffer
*/
static TF_Result lst_ini_export(TinyFrame *tf, TF_Msg *msg)
{
dbg("Bulk read INI file");
// dbg("Bulk read INI file");
BulkRead *bulk = malloc_ck(sizeof(BulkRead));
assert_param(bulk != NULL);
@@ -91,6 +92,7 @@ static TF_Result lst_ini_export(TinyFrame *tf, TF_Msg *msg)
bulk->userdata = NULL;
bulkread_start(tf, bulk);
Indicator_Effect(STATUS_DISK_BUSY_SHORT);
return TF_STAY;
}
@@ -112,7 +114,7 @@ static void settings_bulkwrite_cb(BulkWrite *bulk, const uint8_t *chunk, uint32_
if (bulk->offset > 0) {
settings_load_ini_end();
dbg("INI write complete");
// dbg("INI write complete");
} else {
dbg("INI write failed");
}
@@ -129,7 +131,7 @@ static void settings_bulkwrite_cb(BulkWrite *bulk, const uint8_t *chunk, uint32_
*/
static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg)
{
dbg("Bulk write INI file");
// dbg("Bulk write INI file");
BulkWrite *bulk = malloc_ck(sizeof(BulkWrite));
assert_param(bulk);
@@ -152,6 +154,8 @@ static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg)
bulkwrite_start(tf, bulk);
Indicator_Effect(STATUS_DISK_BUSY);
done:
return TF_STAY;
}
@@ -161,6 +165,7 @@ done:
/** Listener: Save settings to Flash */
static TF_Result lst_persist_cfg(TinyFrame *tf, TF_Msg *msg)
{
Indicator_Effect(STATUS_DISK_REMOVED);
settings_save();
return TF_STAY;
}
+4 -2
View File
@@ -13,8 +13,10 @@
void SysTick_Handler(void)
{
GEX_MsTick();
// OS first, avoids jitter
osSystickHandler();
// GEX periodic updates
GEX_MsTick();
}
@@ -34,7 +36,7 @@ void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName)
// && (__CORTEX_M >= 3)
#if VERBOSE_HARDFAULT
void __attribute__((used)) HardFault_DumpRegisters( uint32_t *origStack, uint32_t lr_value)
void __attribute__((used)) HardFault_DumpRegisters(const uint32_t *origStack, uint32_t lr_value)
{
/* These are volatile to try and prevent the compiler/linker optimising them
away as the variables never actually get used. If the debugger won't show the
+42 -26
View File
@@ -6,6 +6,7 @@
#include "unit.h"
#include "resources.h"
#include "hw_utils.h"
#include "cfg_utils.h"
#include "unit_registry.h"
static bool rsc_initialized = false;
@@ -21,10 +22,8 @@ const char *const rsc_names[] = {
#undef X
};
// Check that EXTI have higher values than GPIOs in the enum
// (determines the logic in the name generation code below)
COMPILER_ASSERT(R_EXTI0 > R_PA0);
COMPILER_ASSERT(R_PF15 < R_EXTI0);
COMPILER_ASSERT(R_PA0 == 0);
const char * rsc_get_name(Resource rsc)
{
@@ -34,23 +33,45 @@ const char * rsc_get_name(Resource rsc)
// we assume the returned value is not stored anywhere
// and is directly used in a sprintf call, hence a static buffer is OK to use
if (rsc >= R_EXTI0) {
// R_PA0 is 0
if (rsc <= R_PF15) {
// we assume the returned value is not stored anywhere
// and is directly used in a sprintf call.
uint8_t index = rsc;
SNPRINTF(gpionamebuf, 8, "P%c%d", 'A'+(index/16), index%16);
return gpionamebuf;
}
if (rsc >= R_EXTI0 && rsc <= R_EXTI15) {
uint8_t index = rsc - R_EXTI0;
SNPRINTF(gpionamebuf, 8, "EXTI%d", index);
return gpionamebuf;
}
if (rsc >= R_PA0) {
// we assume the returned value is not stored anywhere
// and is directly used in a sprintf call.
uint8_t index = rsc - R_PA0;
SNPRINTF(gpionamebuf, 8, "P%c%d", 'A'+(index/16), index%16);
return gpionamebuf;
return rsc_names[rsc - R_EXTI15 - 1];
}
return rsc_names[rsc];
/** Convert a pin to resource handle */
Resource rsc_portpin2rsc(char port_name, uint8_t pin_number, bool *suc)
{
assert_param(suc != NULL);
if(port_name < 'A' || port_name >= ('A'+PORTS_COUNT)) {
dbg("Bad port: %c", port_name); // TODO proper report
*suc = false;
return R_NONE;
}
if(pin_number > 15) {
dbg("Bad pin: %d", pin_number); // TODO proper report
*suc = false;
return R_NONE;
}
uint8_t num = (uint8_t) (port_name - 'A');
return R_PA0 + num*16 + pin_number;
}
const char * rsc_get_owner_name(Resource rsc)
{
@@ -64,11 +85,12 @@ const char * rsc_get_owner_name(Resource rsc)
void rsc_init_registry(void)
{
for(uint32_t i = 0; i < RSCMAP_LEN; i++) {
UNIT_PLATFORM.resources[i] = global_rscmap[i] = 0xFF;
}
memset(UNIT_PLATFORM.resources, 0xFF, RSCMAP_LEN);
memset(global_rscmap, 0xFF, RSCMAP_LEN);
rsc_initialized = true;
rsc_dbg("Total %d hw resources, bitmap has %d bytes.", RESOURCE_COUNT, RSCMAP_LEN);
}
@@ -121,17 +143,11 @@ error_t rsc_claim_range(Unit *unit, Resource rsc0, Resource rsc1)
return E_SUCCESS;
}
error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins)
{
bool suc = true;
for (int i = 0; i < 16; i++) {
if (pins & (1 << i)) {
Resource rsc = hw_pin2resource(port_name, (uint8_t) i, &suc);
if (!suc) return E_BAD_CONFIG;
TRY(rsc_claim(unit, rsc));
TRY(rsc_claim_pin(unit, port_name, (uint8_t)i));
}
}
return E_SUCCESS;
@@ -141,7 +157,7 @@ error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins)
error_t rsc_claim_pin(Unit *unit, char port_name, uint8_t pin)
{
bool suc = true;
Resource rsc = hw_pin2resource(port_name, pin, &suc);
Resource rsc = rsc_portpin2rsc(port_name, pin, &suc);
if (!suc) return E_BAD_CONFIG;
TRY(rsc_claim(unit, rsc));
return E_SUCCESS;
@@ -222,7 +238,7 @@ void rsc_print_all_available(IniWriter *iw)
uint32_t count0 = (iw->count + iw->skip);
bool first = true;
for (uint32_t rsc = 0; rsc < R_PA0; rsc++) {
for (uint32_t rsc = R_EXTI15+1; rsc < R_NONE; rsc++) {
if (RSC_IS_HELD(scratchmap, (Resource)rsc)) continue;
if (!first) iw_string(iw, ", ");
@@ -242,7 +258,7 @@ void rsc_print_all_available(IniWriter *iw)
if (i%16 == 0) {
// here we print the previous port
if (bitmap != 0) {
iw_string(iw, pinmask2str(bitmap, iwbuffer));
iw_string(iw, cfg_pinmask_encode(bitmap, iwbuffer, 0));
bitmap = 0;
}
@@ -257,7 +273,7 @@ void rsc_print_all_available(IniWriter *iw)
}
// the last one
if (bitmap != 0) {
iw_string(iw, pinmask2str(bitmap, iwbuffer));
iw_string(iw, cfg_pinmask_encode(bitmap, iwbuffer, 0));
}
iw_newline(iw);
iw_newline(iw);
+10
View File
@@ -94,6 +94,16 @@ void rsc_free(Unit *unit, Resource rsc);
*/
void rsc_free_range(Unit *unit, Resource rsc0, Resource rsc1);
/**
* Convert pin name and number to a resource enum
*
* @param port_name - char 'A'..'Z'
* @param pin_number - number 0..15
* @param suc - set to false on failure, left unchanged on success
* @return the resource, or R_NONE
*/
Resource rsc_portpin2rsc(char port_name, uint8_t pin_number, bool *suc);
/**
* Get name of a resource by the Resource enum.
* Uses a static buffer, DO NOT store the returned pointer.
+6 -2
View File
@@ -13,6 +13,7 @@
X(I2C1) X(I2C2) X(I2C3) \
X(ADC1) X(ADC2) X(ADC3) X(ADC4) \
X(DAC1) X(DAC2) \
X(TSC) \
X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \
X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \
X(TIM6) X(TIM7) X(TIM8) X(TIM9) X(TIM10) X(TIM11) X(TIM12) X(TIM13) X(TIM14) \
@@ -24,7 +25,6 @@
// X(I2S1) X(I2S2) X(I2S3)
// X(OPAMP1) X(OPAMP2) X(OPAMP3) X(OPAMP4)
// X(CAN1) X(CAN2)
// X(TSC)
// X(DCMI)
// X(ETH)
// X(FSMC)
@@ -59,9 +59,13 @@ typedef enum hw_resource Resource;
/** Enum of all resources */
enum hw_resource {
#define X(res_name) R_##res_name,
XX_RESOURCES
// GPIO are at the beginning, because some units use the constants in their config to represent
// selected pins and those must not change with adding more stuff to the main list
XX_RESOURCES_GPIO
// EXTIs (same like GPIOs) have dynamically generated labels to save rom space. Must be contiguous.
XX_RESOURCES_EXTI
// All the rest ...
XX_RESOURCES
#undef X
R_NONE,
RESOURCE_COUNT = R_NONE,
+1 -1
View File
@@ -2,7 +2,6 @@
// Created by MightyPork on 2017/11/26.
//
#include "utils/avrlibc.h"
#include "platform.h"
#include "utils/hexdump.h"
#include "settings.h"
@@ -10,6 +9,7 @@
#include "system_settings.h"
#include "utils/str_utils.h"
#include "unit_base.h"
#include "utils/avrlibc.h"
// pre-declarations
static void savebuf_flush(PayloadBuilder *pb, bool final);
+3 -2
View File
@@ -6,6 +6,7 @@
#include "system_settings.h"
#include "utils/str_utils.h"
#include "platform/lock_jumper.h"
#include "cfg_utils.h"
struct system_settings SystemSettings;
@@ -77,12 +78,12 @@ bool systemsettings_load_ini(const char *restrict key, const char *restrict valu
{
bool suc = true;
if (streq(key, "expose_vcom")) {
bool yn = str_parse_yn(value, &suc);
bool yn = cfg_bool_parse(value, &suc);
if (suc) SystemSettings.visible_vcom = yn;
}
if (streq(key, "ini_comments")) {
bool yn = str_parse_yn(value, &suc);
bool yn = cfg_bool_parse(value, &suc);
if (suc) SystemSettings.ini_comments = yn;
}
+1
View File
@@ -8,6 +8,7 @@
#include "platform.h"
#include "unit.h"
#include "hw_utils.h"
#include "cfg_utils.h"
#include "resources.h"
#include "utils/str_utils.h"
#include "utils/malloc_safe.h"
+2 -1
View File
@@ -346,8 +346,9 @@ bool ureg_finalize_all_init(void)
// try to assign unique callsigns
if (pUnit->callsign == 0) {
// this is very inefficient but should be reliable
bool change = false;
bool change;
do {
change = false;
UlistEntry *xli = ulist_head;
while (xli != NULL) {
if (xli->unit.callsign != 0) {
+1 -1
View File
@@ -147,7 +147,7 @@ void MX_FREERTOS_Init(void) {
stackmon_register("Main", mainTaskStack, sizeof(mainTaskStack));
stackmon_register("Job+Msg", msgJobQueTaskStack, sizeof(msgJobQueTaskStack));
stackmon_register("Idle", xIdleStack, sizeof(xIdleStack));
stackmon_register("Timers", xTimersStack, sizeof(xTimersStack));
// stackmon_register("Timers", xTimersStack, sizeof(xTimersStack));
/* USER CODE END Init */
/* Create the mutex(es) */
+3
View File
@@ -15,6 +15,9 @@ GEX_SRC_DIR = \
User/units/spi \
User/units/adc \
User/units/sipo \
User/units/fcap \
User/units/touch \
User/units/simple_pwm \
User/TinyFrame \
User/CWPack \
User/tasks
+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("Build "__DATE__" "__TIME__);
PRINTF("Reset cause:");
if (LL_RCC_IsActiveFlag_LPWRRST()) PRINTF(" LPWR");
if (LL_RCC_IsActiveFlag_WWDGRST()) PRINTF(" WWDG");
if (LL_RCC_IsActiveFlag_IWDGRST()) PRINTF(" IWDG");
if (LL_RCC_IsActiveFlag_SFTRST()) PRINTF(" SFT");
if (LL_RCC_IsActiveFlag_PORRST()) PRINTF(" POR");
if (LL_RCC_IsActiveFlag_PINRST()) PRINTF(" PIN");
if (LL_RCC_IsActiveFlag_OBLRST()) PRINTF(" OBL");
if (LL_RCC_IsActiveFlag_V18PWRRST()) PRINTF(" V18PWR");
PUTNL();
LL_RCC_ClearResetFlags();
plat_init();
MX_USB_DEVICE_Init();
+299
View File
@@ -0,0 +1,299 @@
//
// Created by MightyPork on 2018/02/23.
//
#include "cfg_utils.h"
#include "hw_utils.h"
#include "utils/avrlibc.h"
#include "utils/str_utils.h"
/** Parse a string representation of a pin directly to a resource constant */
Resource cfg_pinrsc_parse(const char *str, bool *suc)
{
char pname;
uint8_t pnum;
if (!cfg_portpin_parse(str, &pname, &pnum)) {
*suc = false;
return R_NONE;
}
return rsc_portpin2rsc(pname, pnum, suc);
}
/** Convert a resource to a pin name - uses a static buffer, result must not be stored! */
char *cfg_pinrsc_encode(Resource rsc)
{
static char buf[4];
uint32_t index = rsc - R_PA0;
uint32_t portnum = (index/16);
uint8_t pinnum = (uint8_t) (index % 16);
if (portnum >= PORTS_COUNT) return "";
buf[0] = (char) ('A' + portnum);
if (pinnum>9) {
buf[1] = '1';
buf[2] = (char) ('0' + (pinnum - 10));
buf[3] = 0;
} else {
buf[1] = (char) ('0' + pinnum);
buf[2] = 0;
}
return buf;
}
/** Parse single pin */
bool cfg_portpin_parse(const char *value, char *targetName, uint8_t *targetNumber)
{
// discard leading 'P'
if (value[0] == 'P') {
value++;
}
size_t len = strlen(value);
if (len<2||len>3) return false;
*targetName = (uint8_t) value[0];
if (!(*targetName >= 'A' && *targetName <= 'H')) return false;
// lets just hope it's OK
*targetNumber = (uint8_t) avr_atoi(value + 1);
return true;
}
/** Parse port name */
bool cfg_port_parse(const char *value, char *targetName)
{
*targetName = (uint8_t) value[0];
if (!(*targetName >= 'A' && *targetName < 'A' + PORTS_COUNT)) return false;
return true;
}
/** Parse a list of pin numbers with ranges and commans/semicolons to a bitmask */
uint32_t cfg_pinmask_parse_32(const char *value, bool *suc)
{
uint32_t bits = 0;
uint32_t acu = 0;
bool inrange = false;
uint32_t rangestart = 0;
// shortcut if none are set
if (value[0] == 0) return 0;
char c;
do {
c = *value++;
if (c == ' ' || c == '\t') {
// skip
}
else if (c >= '0' && c <= '9') {
acu = acu*10 + (c-'0');
}
else if (c == ',' || c == ';' || c == 0) {
// end of number or range
if (!inrange) rangestart = acu;
// swap them if they're in the wrong order
if (acu < rangestart) {
uint32_t swp = acu;
acu = rangestart;
rangestart = swp;
}
if (rangestart > 31) rangestart = 31;
if (acu > 31) acu = 31;
for(uint32_t i=rangestart; i <= acu; i++) {
bits |= 1<<i;
}
inrange = false;
rangestart = 0;
acu = 0;
}
else if (c == '-' || c == ':') {
rangestart = acu;
inrange = true;
acu=0;
} else {
*suc = false;
}
} while (c != 0);
return bits;
}
/** Convert a pin bitmask to the ASCII format understood by str_parse_pinmask() */
char *cfg_pinmask_encode(uint32_t pins, char *buffer, bool ascending)
{
char *b = buffer;
uint32_t start = 0;
bool on = false;
bool first = true;
bool bit;
// shortcut if none are set
if (pins == 0) {
buffer[0] = 0;
return buffer;
}
if (ascending) {
for (int32_t i = 0; i <= 32; i++) {
if (i == 32) {
bit = false;
} else {
bit = 0 != (pins & 1);
pins >>= 1;
}
if (bit) {
if (!on) {
start = (uint32_t) i;
on = true;
}
} else {
if (on) {
if (!first) {
b += SPRINTF(b, ", ");
}
if (start == (uint32_t)(i - 1)) {
b += SPRINTF(b, "%"PRIu32, start);
} else {
b += SPRINTF(b, "%"PRIu32"-%"PRIu32, start, i - 1);
}
first = false;
on = false;
}
}
}
} else {
for (int32_t i = 31; i >= -1; i--) {
if (i == -1) {
bit = false;
} else {
bit = 0 != (pins & 0x80000000);
pins <<= 1;
}
if (bit) {
if (!on) {
start = (uint32_t) i;
on = true;
}
} else {
if (on) {
if (!first) {
b += SPRINTF(b, ", ");
}
if (start == (uint32_t) (i + 1)) {
b += SPRINTF(b, "%"PRIu32, start);
} else {
b += SPRINTF(b, "%"PRIu32"-%"PRIu32, start, i + 1);
}
first = false;
on = false;
}
}
}
}
return buffer;
}
bool cfg_bool_parse(const char *str, bool *suc)
{
// TODO implement strcasecmp without the locale crap from newlib and use it here
if (streq(str, "Y")) return true;
if (streq(str, "N")) return false;
if (streq(str, "1")) return true;
if (streq(str, "0")) return false;
if (streq(str, "H")) return true;
if (streq(str, "L")) return false;
if (streq(str, "YES")) return true;
if (streq(str, "NO")) return false;
if (streq(str, "ON")) return true;
if (streq(str, "OFF")) return false;
*suc = false;
return false;
}
/** Convert number to one of 2 options */
const char *cfg_enum2_encode(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b)
{
if (n == nb) return b;
return a;
}
/** Convert number to one of 3 options */
const char *cfg_enum3_encode(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b,
uint32_t nc, const char *c)
{
if (n == nb) return b;
if (n == nc) return c;
return a;
}
/** Convert number to one of 4 options */
const char *cfg_enum4_encode(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b,
uint32_t nc, const char *c,
uint32_t nd, const char *d)
{
if (n == nb) return b;
if (n == nc) return c;
if (n == nd) return d;
return a;
}
uint32_t cfg_enum2_parse(const char *value,
const char *a, uint32_t na,
const char *b, uint32_t nb,
bool *suc)
{
if (streq(value, a)) return na;
if (streq(value, b)) return nb;
*suc = false;
return na;
}
uint32_t cfg_enum3_parse(const char *value,
const char *a, uint32_t na,
const char *b, uint32_t nb,
const char *c, uint32_t nc,
bool *suc)
{
if (streq(value, a)) return na;
if (streq(value, b)) return nb;
if (streq(value, c)) return nc;
*suc = false;
return na;
}
uint32_t cfg_enum4_parse(const char *value,
const char *a, uint32_t na,
const char *b, uint32_t nb,
const char *c, uint32_t nc,
const char *d, uint32_t nd,
bool *suc)
{
if (streq(value, a)) return na;
if (streq(value, b)) return nb;
if (streq(value, c)) return nc;
if (streq(value, d)) return nd;
*suc = false;
return na;
}
+153
View File
@@ -0,0 +1,153 @@
//
// Created by MightyPork on 2018/02/23.
//
#ifndef GEX_F072_CFG_UTILS_H
#define GEX_F072_CFG_UTILS_H
#include "platform.h"
#include "rsc_enum.h"
#include "utils/avrlibc.h"
/**
* Parse a pin name (e.g. PA0 or A0) to port name and pin number
*
* @param str - source string
* @param targetName - output: port name (one character)
* @param targetNumber - output: pin number 0-15
* @return success
*/
bool cfg_portpin_parse(const char *str, char *targetName, uint8_t *targetNumber);
/**
* Parse a string representation of a pin directly to a resource constant
*
* @param[in] str - source string - e.g. PA0 or A0
* @param[out] suc - written to false on failure
* @return the parsed resource
*/
Resource cfg_pinrsc_parse(const char *str, bool *suc);
/**
* Convert a resource to a pin name - uses a static buffer, result must not be stored!
*
* @param[in] rsc - resource to print
* @return a pointer to a static buffer used for exporting the names
*/
char *cfg_pinrsc_encode(Resource rsc);
/**
* Parse a port name (one character) - validates that it's within range
*
* @param value - source string
* @param targetName - output: port name (one character)
* @return success
*/
bool cfg_port_parse(const char *value, char *targetName);
/**
* Parse a list of pin numbers with ranges and commands/semicolons to a bitmask.
* Supported syntax:
* - comma separated numbers
* - numbers connected by dash or colon form a range (can be in any order)
*
* @param value - source string
* @param suc - set to False if parsing failed
* @return the resulting bitmap
*/
uint32_t cfg_pinmask_parse_32(const char *value, bool *suc);
/** same as cfg_pinmask_parse_32(), but with a cast to u16 */
static inline uint16_t cfg_pinmask_parse(const char *value, bool *suc)
{
return (uint16_t) cfg_pinmask_parse_32(value, suc);
}
/**
* Convert a pin bitmap to the ASCII format understood by str_parse_pinmask()
*
* @param[in] pins - sparse pin map
* @param[out] buffer - output string buffer
* @param[in] ascending - use ordering 0..31 rather than 31..0
* @return the output buffer
*/
char *cfg_pinmask_encode(uint32_t pins, char *buffer, bool ascending);
/** Parse Y/N to bool */
bool cfg_bool_parse(const char *str, bool *suc);
/** Convert number to one of 4 options */
const char *cfg_enum2_encode(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b);
/** Convert number to one of 4 options */
const char *cfg_enum3_encode(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b,
uint32_t nc, const char *c);
/** Convert number to one of 4 options */
const char *cfg_enum4_encode(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b,
uint32_t nc, const char *c,
uint32_t nd, const char *d);
/** Convert string to one of two numeric options */
uint32_t cfg_enum2_parse(const char *tpl,
const char *a, uint32_t na,
const char *b, uint32_t nb,
bool *suc);
/** Convert string to one of three numeric options */
uint32_t cfg_enum3_parse(const char *tpl,
const char *a, uint32_t na,
const char *b, uint32_t nb,
const char *c, uint32_t nc,
bool *suc);
/** Convert string to one of four numeric options */
uint32_t cfg_enum4_parse(const char *tpl,
const char *a, uint32_t na,
const char *b, uint32_t nb,
const char *c, uint32_t nc,
const char *d, uint32_t nd,
bool *suc);
/** Convert bool to a Y or N constant string */
#define str_yn(cond) ((cond) ? ("Y") : ("N"))
static inline uint8_t cfg_u8_parse(const char *value, bool *suc)
{
return (uint8_t) avr_atoi(value);
}
static inline int8_t cfg_i8_parse(const char *value, bool *suc)
{
return (int8_t) avr_atoi(value);
}
static inline uint16_t cfg_u16_parse(const char *value, bool *suc)
{
return (uint16_t) avr_atoi(value);
}
static inline int16_t cfg_i16_parse(const char *value, bool *suc)
{
return (int16_t) avr_atoi(value);
}
static inline uint32_t cfg_u32_parse(const char *value, bool *suc)
{
return (uint32_t) avr_atoi(value);
}
static inline int32_t cfg_i32_parse(const char *value, bool *suc)
{
return (int32_t) avr_atoi(value);
}
#endif //GEX_F072_CFG_UTILS_H
+47 -217
View File
@@ -3,10 +3,8 @@
//
#include "platform.h"
#include "utils/avrlibc.h"
#include "hw_utils.h"
/** Convert pin number to LL bitfield */
uint32_t hw_pin2ll(uint8_t pin_number, bool *suc)
{
@@ -36,210 +34,19 @@ GPIO_TypeDef *hw_port2periph(char port_name, bool *suc)
return GPIO_PERIPHS[num];
}
/** Convert a pin to resource handle */
Resource hw_pin2resource(char port_name, uint8_t pin_number, bool *suc)
/** Convert a pin resource to it's LL lib values */
bool hw_pinrsc2ll(Resource rsc, GPIO_TypeDef **port, uint32_t *llpin)
{
assert_param(suc != NULL);
if(port_name < 'A' || port_name >= ('A'+PORTS_COUNT)) {
dbg("Bad port: %c", port_name); // TODO proper report
*suc = false;
return R_NONE;
}
if(pin_number > 15) {
dbg("Bad pin: %d", pin_number); // TODO proper report
*suc = false;
return R_NONE;
}
uint8_t num = (uint8_t) (port_name - 'A');
return R_PA0 + num*16 + pin_number;
}
/** Parse single pin */
bool parse_pin(const char *value, char *targetName, uint8_t *targetNumber)
{
// discard leading 'P'
if (value[0] == 'P') {
value++;
}
size_t len = strlen(value);
if (len<2||len>3) return false;
*targetName = (uint8_t) value[0];
if (!(*targetName >= 'A' && *targetName <= 'H')) return false;
// lets just hope it's OK
*targetNumber = (uint8_t) avr_atoi(value + 1);
if (rsc > R_PF15) return false;
uint32_t index = rsc - R_PA0;
uint32_t pname = (index/16);
uint8_t pnum = (uint8_t) (index % 16);
if (pname >= PORTS_COUNT) return false;
*port = GPIO_PERIPHS[pname];
*llpin = LL_GPIO_PINS[pnum];
return true;
}
/** Parse port name */
bool parse_port_name(const char *value, char *targetName)
{
*targetName = (uint8_t) value[0];
if (!(*targetName >= 'A' && *targetName < 'A' + PORTS_COUNT)) return false;
return true;
}
/** Parse a list of pin numbers with ranges and commans/semicolons to a bitmask */
uint32_t parse_pinmask(const char *value, bool *suc)
{
uint32_t bits = 0;
uint32_t acu = 0;
bool inrange = false;
uint32_t rangestart = 0;
// shortcut if none are set
if (value[0] == 0) return 0;
char c;
do {
c = *value++;
if (c == ' ' || c == '\t') {
// skip
}
else if (c >= '0' && c <= '9') {
acu = acu*10 + (c-'0');
}
else if (c == ',' || c == ';' || c == 0) {
// end of number or range
if (!inrange) rangestart = acu;
// swap them if they're in the wrong order
if (acu < rangestart) {
uint32_t swp = acu;
acu = rangestart;
rangestart = swp;
}
if (rangestart > 31) rangestart = 31;
if (acu > 31) acu = 31;
for(uint32_t i=rangestart; i <= acu; i++) {
bits |= 1<<i;
}
inrange = false;
rangestart = 0;
acu = 0;
}
else if (c == '-' || c == ':') {
rangestart = acu;
inrange = true;
acu=0;
} else {
*suc = false;
}
} while (c != 0);
return bits;
}
/** Convert a pin bitmask to the ASCII format understood by str_parse_pinmask() */
char * pinmask2str(uint32_t pins, char *buffer)
{
char *b = buffer;
uint32_t start = 0;
bool on = false;
bool first = true;
// shortcut if none are set
if (pins == 0) {
buffer[0] = 0;
return buffer;
}
for (int32_t i = 31; i >= -1; i--) {
bool bit;
if (i == -1) {
bit = false;
} else {
bit = 0 != (pins & 0x80000000);
pins <<= 1;
}
if (bit) {
if (!on) {
start = (uint32_t) i;
on = true;
}
} else {
if (on) {
if (!first) {
b += SPRINTF(b, ", ");
}
if (start == (uint32_t)(i+1)) {
b += SPRINTF(b, "%"PRIu32, start);
}
else {
b += SPRINTF(b, "%"PRIu32"-%"PRIu32, start, i + 1);
}
first = false;
on = false;
}
}
}
return buffer;
}
char * pinmask2str_up(uint32_t pins, char *buffer)
{
char *b = buffer;
uint32_t start = 0;
bool on = false;
bool first = true;
// shortcut if none are set
if (pins == 0) {
buffer[0] = 0;
return buffer;
}
for (int32_t i = 0; i <= 32; i++) {
bool bit;
if (i == 32) {
bit = false;
} else {
bit = 0 != (pins & 1);
pins >>= 1;
}
if (bit) {
if (!on) {
start = (uint32_t) i;
on = true;
}
} else {
if (on) {
if (!first) {
b += SPRINTF(b, ", ");
}
if (start == (uint32_t)(i-1)) {
b += SPRINTF(b, "%"PRIu32, start);
}
else {
b += SPRINTF(b, "%"PRIu32"-%"PRIu32, start, i - 1);
}
first = false;
on = false;
}
}
}
return buffer;
}
#pragma GCC push_options
#pragma GCC optimize ("O2")
/** spread a packed pinfield using a mask */
@@ -285,25 +92,13 @@ uint32_t pinmask_pack_32(uint32_t spread, uint32_t mask)
return result;
}
/** Convert spread port pin number to a packed index using a mask */
uint8_t pinmask_translate(uint32_t mask, uint8_t index)
{
int cnt = 0;
for (int i = 0; i<32; i++) {
if (mask & (1<<i)) {
if (i == index) return (uint8_t) cnt;
cnt++;
}
}
return 0;
}
#pragma GCC pop_options
/** Configure unit pins as analog (part of unit teardown) */
void hw_deinit_unit_pins(Unit *unit)
{
for (uint32_t rsc = R_PA0; rsc <= R_PF15; rsc++) {
if (RSC_IS_HELD(unit->resources, rsc)) {
if (RSC_IS_HELD(unit->resources, (Resource)rsc)) {
rsc_dbg("Freeing pin %s", rsc_get_name((Resource)rsc));
GPIO_TypeDef *port = GPIO_PERIPHS[(rsc-R_PA0) / 16];
uint32_t ll_pin = LL_GPIO_PINS[(rsc-R_PA0)%16];
@@ -335,6 +130,30 @@ error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af)
return E_SUCCESS;
}
/** Configure a pin to alternate function */
error_t hw_configure_gpiorsc_af(Resource rsc, uint32_t ll_af)
{
#if PLAT_NO_AFNUM
trap("Illegal call to hw_configure_gpio_af() on this platform");
#else
bool suc = true;
GPIO_TypeDef *port;
uint32_t ll_pin;
suc = hw_pinrsc2ll(rsc, &port, &ll_pin);
if (!suc) return E_BAD_CONFIG;
if (ll_pin & 0xFF)
LL_GPIO_SetAFPin_0_7(port, ll_pin, ll_af);
else
LL_GPIO_SetAFPin_8_15(port, ll_pin, ll_af);
LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ALTERNATE);
#endif
return E_SUCCESS;
}
/** Configure pins using sparse map */
error_t hw_configure_sparse_pins(char port_name, uint16_t mask, GPIO_TypeDef **port_dest,
uint32_t ll_mode, uint32_t ll_otype)
@@ -360,7 +179,7 @@ error_t hw_configure_sparse_pins(char port_name, uint16_t mask, GPIO_TypeDef **p
}
/** Solve a timer/counter's count and prescaller value */
bool solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
bool hw_solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
uint16_t *presc, uint32_t *count, float *real_freq)
{
if (required_freq == 0) return false;
@@ -394,7 +213,6 @@ bool solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
return true;
}
void hw_periph_clock_enable(void *periph)
{
// GPIOs are enabled by default on start-up
@@ -493,6 +311,12 @@ void hw_periph_clock_enable(void *periph)
#ifdef DAC2
else if (periph == DAC2) __HAL_RCC_DAC2_CLK_ENABLE();
#endif
// --- TSC ---
#ifdef TSC
else if (periph == TSC) __HAL_RCC_TSC_CLK_ENABLE();
#endif
else {
dbg("Periph 0x%p missing in hw clock enable func", periph);
trap("BUG");
@@ -598,6 +422,12 @@ void hw_periph_clock_disable(void *periph)
#ifdef DAC2
else if (periph == DAC2) __HAL_RCC_DAC2_CLK_DISABLE();
#endif
// --- TSC ---
#ifdef TSC
else if (periph == TSC) __HAL_RCC_TSC_CLK_DISABLE();
#endif
else {
dbg("Periph 0x%p missing in hw clock disable func", periph);
trap("BUG");
+10 -65
View File
@@ -21,16 +21,6 @@
*/
uint32_t hw_pin2ll(uint8_t pin_number, bool *suc);
/**
* Convert pin name and number to a resource enum
*
* @param port_name - char 'A'..'Z'
* @param pin_number - number 0..15
* @param suc - set to false on failure, left unchanged on success
* @return the resource, or R_NONE
*/
Resource hw_pin2resource(char port_name, uint8_t pin_number, bool *suc);
/**
* Convert port name to peripheral instance
*
@@ -41,55 +31,14 @@ Resource hw_pin2resource(char port_name, uint8_t pin_number, bool *suc);
GPIO_TypeDef *hw_port2periph(char port_name, bool *suc);
/**
* Parse a pin name (e.g. PA0 or A0) to port name and pin number
* Convert a pin resource to it's LL lib values
*
* @param str - source string
* @param targetName - output: port name (one character)
* @param targetNumber - output: pin number 0-15
* @param[in] rsc - resource to process
* @param[out] port - output port
* @param[out] llpin - output LL pin mask
* @return success
*/
bool parse_pin(const char *str, char *targetName, uint8_t *targetNumber);
/**
* Parse a port name (one character) - validates that it's within range
*
* @param value - source string
* @param targetName - output: port name (one character)
* @return success
*/
bool parse_port_name(const char *value, char *targetName);
/**
* Parse a list of pin numbers with ranges and commands/semicolons to a bitmask.
* Supported syntax:
* - comma separated numbers
* - numbers connected by dash or colon form a range (can be in any order)
*
* @param value - source string
* @param suc - set to False if parsing failed
* @return the resulting bitmap
*/
uint32_t parse_pinmask(const char *value, bool *suc);
/**
* Convert a pin bitmap to the ASCII format understood by str_parse_pinmask()
* This is the downto variant (15..0)
*
* @param pins - sparse pin map
* @param buffer - output string buffer
* @return the output buffer
*/
char * pinmask2str(uint32_t pins, char *buffer);
/**
* Convert a pin bitmap to the ASCII format understood by str_parse_pinmask()
* This is the ascending variant (0..15)
*
* @param pins - sparse pin map
* @param buffer - output string buffer
* @return the output buffer
*/
char * pinmask2str_up(uint32_t pins, char *buffer);
bool hw_pinrsc2ll(Resource rsc, GPIO_TypeDef **port, uint32_t *llpin) __attribute__((warn_unused_result));
/**
* Spread packed port pins using a mask
@@ -121,13 +70,6 @@ static inline uint16_t pinmask_pack(uint32_t spread, uint32_t mask)
return (uint16_t) pinmask_pack_32(spread, mask);
}
/**
* Convert spread port pin number to a packed index using a mask
*
* eg. with a mask 0b1010 and index 3, the result is 1 (bit 1 of the packed - 0bX0)
*/
uint8_t pinmask_translate(uint32_t mask, uint8_t index);
/**
* Set all GPIO resources held by unit to analog.
* This is a part of unit teardown.
@@ -146,6 +88,9 @@ void hw_deinit_unit_pins(Unit *unit);
*/
error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af) __attribute__((warn_unused_result));
/** Configure a pin to alternate function via rsc */
error_t hw_configure_gpiorsc_af(Resource rsc, uint32_t ll_af) __attribute__((warn_unused_result));
/**
* Configure multiple pins using the bitmap pattern
*
@@ -192,8 +137,8 @@ void hw_periph_clock_disable(void *periph);
* @param[out] real_freq - field for storing the computed real frequency
* @return true on success
*/
bool solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
uint16_t *presc, uint32_t *count, float *real_freq);
bool hw_solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
uint16_t *presc, uint32_t *count, float *real_freq) __attribute__((warn_unused_result));
#define hw_wait_while(call, timeout) \
do { \
+46 -9
View File
@@ -61,11 +61,15 @@ static struct callbacks_ {
struct cbslot dma2_7;
struct cbslot dma2_8;
struct cbslot tim2;
struct cbslot tim6;
struct cbslot tim7;
struct cbslot tim14;
struct cbslot tim15;
struct cbslot tim16;
struct cbslot adc1;
struct cbslot tsc;
// XXX add more callbacks here when needed
} callbacks;
@@ -89,7 +93,8 @@ void irqd_init(void)
HAL_NVIC_SetPriority(EXTI2_3_IRQn, 2, 0);
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 2, 0);
// NVIC_EnableIRQ(TSC_IRQn); /*!< Touch Sensing Controller Interrupts */
NVIC_EnableIRQ(TSC_IRQn); /*!< Touch Sensing Controller Interrupts */
HAL_NVIC_SetPriority(TSC_IRQn, 2, 0);
NVIC_EnableIRQ(DMA1_Channel1_IRQn); /*!< DMA1 Channel 1 Interrupt */
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); /*!< DMA1 Channel 2 and Channel 3 Interrupt */
@@ -102,24 +107,32 @@ void irqd_init(void)
HAL_NVIC_SetPriority(ADC1_COMP_IRQn, 1, 0); // ADC group completion - higher prio than DMA to let it handle the last halfword first
// NVIC_EnableIRQ(TIM1_IRQn); /*!< TIM1 global Interrupt */
// NVIC_EnableIRQ(TIM2_IRQn); /*!< TIM2 global Interrupt */
NVIC_EnableIRQ(TIM2_IRQn); /*!< TIM2 global Interrupt */
HAL_NVIC_SetPriority(TIM2_IRQn, 2, 0); // Used by FCAP
// NVIC_EnableIRQ(TIM3_IRQn); /*!< TIM3 global Interrupt */
NVIC_EnableIRQ(TIM6_DAC_IRQn); /*!< TIM6 global and DAC channel underrun error Interrupt */
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0); // Used for DAC timing
NVIC_EnableIRQ(TIM7_IRQn); /*!< TIM7 global Interrupt */
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0);
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0);// this will be for dac (?)
/* Tim14 is used for HAL timebase, because SysTick is used to time FreeRTOS and has the lowest priority. */
/* Tim14's priority is set to 0 in the init routine, which runs early in the startup sequence */
// NVIC_EnableIRQ(TIM14_IRQn); /*!< TIM14 global Interrupt */
NVIC_EnableIRQ(TIM14_IRQn); /*used by fcap as a time reference for direct capture */ /*!< TIM14 global Interrupt */
HAL_NVIC_SetPriority(TIM14_IRQn, 2, 0);
NVIC_EnableIRQ(TIM15_IRQn); /*!< TIM15 global Interrupt */
HAL_NVIC_SetPriority(TIM15_IRQn, 2, 0);
HAL_NVIC_SetPriority(TIM15_IRQn, 2, 0); // Used by ADC
// NVIC_EnableIRQ(TIM16_IRQn); /*!< TIM16 global Interrupt */
NVIC_EnableIRQ(TIM16_IRQn); /*!< TIM16 global Interrupt */
HAL_NVIC_SetPriority(TIM16_IRQn, 2, 0);
/* Tim17 is used for HAL timebase, because SysTick is used to time FreeRTOS and has the lowest priority. */
/* Tim17's priority is set to 0 in the init routine, which runs early in the startup sequence */
// NVIC_EnableIRQ(TIM17_IRQn); /*!< TIM17 global Interrupt */
// NVIC_EnableIRQ(I2C1_IRQn); /*!< I2C1 Event Interrupt & EXTI Line23 Interrupt (I2C1 wakeup) */
// NVIC_EnableIRQ(I2C2_IRQn); /*!< I2C2 Event Interrupt */
// NVIC_EnableIRQ(SPI1_IRQn); /*!< SPI1 global Interrupt */
@@ -159,9 +172,15 @@ static struct cbslot *get_slot_for_periph(void *periph)
else if (periph == USART5) slot = &callbacks.usart5;
#endif
else if (periph == TIM2) slot = &callbacks.tim2;
else if (periph == TIM6) slot = &callbacks.tim6;
else if (periph == TIM7) slot = &callbacks.tim7;
else if (periph == TIM14) slot = &callbacks.tim14;
else if (periph == TIM15) slot = &callbacks.tim15;
else if (periph == TIM16) slot = &callbacks.tim16;
// 17 - used by timebase
else if (periph == TSC) slot = &callbacks.tsc;
else if (periph == ADC1) slot = &callbacks.adc1;
@@ -302,7 +321,10 @@ void EXTI4_15_IRQHandler(void)
// ------------ INTERRUPTS -------------
// TIM14 is used to generate HAL timebase and its handler is in the file "timebase.c"
void TIM2_IRQHandler(void)
{
CALL_IRQ_HANDLER(callbacks.tim2);
}
void TIM6_DAC_IRQHandler(void)
{
@@ -314,16 +336,31 @@ void TIM7_IRQHandler(void)
CALL_IRQ_HANDLER(callbacks.tim7);
}
void TIM14_IRQHandler(void)
{
CALL_IRQ_HANDLER(callbacks.tim14);
}
void TIM15_IRQHandler(void)
{
CALL_IRQ_HANDLER(callbacks.tim15);
}
void TIM16_IRQHandler(void)
{
CALL_IRQ_HANDLER(callbacks.tim16);
}
void ADC1_COMP_IRQHandler(void)
{
CALL_IRQ_HANDLER(callbacks.adc1);
}
void TSC_IRQHandler(void)
{
CALL_IRQ_HANDLER(callbacks.tsc);
}
// other ISRs...
+38
View File
@@ -5,6 +5,44 @@
#include "platform.h"
#include "ll_extension.h"
const uint32_t LL_TIM_IC_FILTERS[] = {
LL_TIM_IC_FILTER_FDIV1,
LL_TIM_IC_FILTER_FDIV1_N2,
LL_TIM_IC_FILTER_FDIV1_N4,
LL_TIM_IC_FILTER_FDIV1_N8,
LL_TIM_IC_FILTER_FDIV2_N6,
LL_TIM_IC_FILTER_FDIV2_N8,
LL_TIM_IC_FILTER_FDIV4_N6,
LL_TIM_IC_FILTER_FDIV4_N8,
LL_TIM_IC_FILTER_FDIV8_N6,
LL_TIM_IC_FILTER_FDIV8_N8,
LL_TIM_IC_FILTER_FDIV16_N5,
LL_TIM_IC_FILTER_FDIV16_N6,
LL_TIM_IC_FILTER_FDIV16_N8,
LL_TIM_IC_FILTER_FDIV32_N5,
LL_TIM_IC_FILTER_FDIV32_N6,
LL_TIM_IC_FILTER_FDIV32_N8,
};
const uint32_t LL_TIM_ETR_FILTERS[] = {
LL_TIM_ETR_FILTER_FDIV1,
LL_TIM_ETR_FILTER_FDIV1_N2,
LL_TIM_ETR_FILTER_FDIV1_N4,
LL_TIM_ETR_FILTER_FDIV1_N8,
LL_TIM_ETR_FILTER_FDIV2_N6,
LL_TIM_ETR_FILTER_FDIV2_N8,
LL_TIM_ETR_FILTER_FDIV4_N6,
LL_TIM_ETR_FILTER_FDIV4_N8,
LL_TIM_ETR_FILTER_FDIV8_N6,
LL_TIM_ETR_FILTER_FDIV8_N8,
LL_TIM_ETR_FILTER_FDIV16_N5,
LL_TIM_ETR_FILTER_FDIV16_N6,
LL_TIM_ETR_FILTER_FDIV16_N8,
LL_TIM_ETR_FILTER_FDIV32_N5,
LL_TIM_ETR_FILTER_FDIV32_N6,
LL_TIM_ETR_FILTER_FDIV32_N8,
};
const uint32_t LL_SYSCFG_EXTI_PORTS[PORTS_COUNT] = {
LL_SYSCFG_EXTI_PORTA,
LL_SYSCFG_EXTI_PORTB,
+2 -1
View File
@@ -13,7 +13,8 @@ extern GPIO_TypeDef * const GPIO_PERIPHS[PORTS_COUNT];
extern const uint32_t LL_GPIO_PINS[16];
extern const uint32_t LL_EXTI_LINES[16];
extern const uint32_t LL_ADC_SAMPLETIMES[8];
extern const uint32_t LL_TIM_IC_FILTERS[16];
extern const uint32_t LL_TIM_ETR_FILTERS[16];
static inline bool LL_DMA_IsActiveFlag_G(uint32_t isr_snapshot, uint8_t channel)
{
+3 -8
View File
@@ -26,16 +26,11 @@ void LockJumper_Init(void)
{
bool suc = true;
// Resolve and claim resource
Resource rsc = hw_pin2resource(LOCK_JUMPER_PORT, LOCK_JUMPER_PIN, &suc);
Resource pinrsc = rsc_portpin2rsc(LOCK_JUMPER_PORT, LOCK_JUMPER_PIN, &suc);
assert_param(suc);
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, rsc));
// Resolve pin
lock_periph = hw_port2periph(LOCK_JUMPER_PORT, &suc);
lock_llpin = hw_pin2ll(LOCK_JUMPER_PIN, &suc);
assert_param(suc);
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, pinrsc));
assert_param(hw_pinrsc2ll(pinrsc, &lock_periph, &lock_llpin));
// Configure for input
LL_GPIO_SetPinMode(lock_periph, lock_llpin, LL_GPIO_MODE_INPUT);
+4 -4
View File
@@ -21,7 +21,7 @@
#endif
// 180 is normally enough if not doing extensive debug logging
#define TSK_STACK_MSG 200 // TF message handler task stack size (all unit commands run on this thread)
#define TSK_STACK_MSG 220 // TF message handler task stack size (all unit commands run on this thread)
#define TSK_STACK_IDLE 64 //configMINIMAL_STACK_SIZE
#define TSK_STACK_TIMERS 64 //configTIMER_TASK_STACK_DEPTH
@@ -30,7 +30,7 @@
#define BULK_READ_BUF_LEN 256 // Buffer for TF bulk reads
#define UNIT_TMP_LEN 512 // Buffer for internal unit operations
#define UNIT_TMP_LEN 256 // Buffer for internal unit operations
#define FLASH_SAVE_BUF_LEN 128 // Malloc'd buffer for saving to flash
@@ -38,7 +38,7 @@
#define RX_QUE_CAPACITY 16 // TinyFrame rx queue size (64 bytes each)
#define TF_MAX_PAYLOAD_RX 512 // TF max Rx payload
#define TF_SENDBUF_LEN 64 // TF transmit buffer (can be less than a full frame)
#define TF_SENDBUF_LEN 512 // TF transmit buffer (can be less than a full frame)
#define TF_MAX_ID_LST 4 // Frame ID listener count
#define TF_MAX_TYPE_LST 6 // Frame Type listener count
@@ -51,7 +51,7 @@
#define INI_VALUE_MAX 30 // Ini parser value buffer
// -------- Stack buffers ----------
#define DBG_BUF_LEN 80 // Size of the snprintf buffer for debug messages
#define DBG_BUF_LEN 100 // Size of the snprintf buffer for debug messages
#define ERR_MSG_STR_LEN 64 // Error message buffer size
#define IWBUFFER_LEN 80 // Ini writer buffer for sprintf
+3
View File
@@ -15,6 +15,7 @@
#include "debug_uart.h"
#include "irq_dispatcher.h"
#include "timebase.h"
#include "watchdog.h"
void plat_init(void)
{
@@ -39,4 +40,6 @@ void plat_init(void)
settings_load(); // XXX maybe this should be moved to the main task
comm_init();
wd_init();
}
+8 -2
View File
@@ -18,6 +18,9 @@
#include "units/usart/unit_usart.h"
#include "units/spi/unit_spi.h"
#include "units/sipo/unit_sipo.h"
#include "units/fcap/unit_fcap.h"
#include "units/touch/unit_touch.h"
#include "units/simple_pwm/unit_pwmdim.h"
#include "hw_utils.h"
void plat_init_resources(void)
@@ -88,6 +91,9 @@ void plat_init_resources(void)
ureg_add_type(&UNIT_1WIRE);
ureg_add_type(&UNIT_ADC);
ureg_add_type(&UNIT_SIPO);
ureg_add_type(&UNIT_FCAP);
ureg_add_type(&UNIT_TOUCH);
ureg_add_type(&UNIT_PWMDIM);
// Free all present resources
{
@@ -96,7 +102,7 @@ void plat_init_resources(void)
// rsc_free_range(NULL, R_COMP1, R_COMP2);
rsc_free(NULL, R_DAC1);
// rsc_free(NULL, R_HDMI_CEC);
// rsc_free(NULL, R_TSC);
rsc_free(NULL, R_TSC);
rsc_free_range(NULL, R_I2C1, R_I2C2);
// rsc_free_range(NULL, R_I2S1, R_I2S2);
rsc_free_range(NULL, R_SPI1, R_SPI2);
@@ -152,7 +158,7 @@ void plat_init_resources(void)
rsc_free_range(NULL, R_TIM1, R_TIM4);
rsc_free_range(NULL, R_TIM6, R_TIM8);
rsc_free_range(NULL, R_TIM15, R_TIM17);
// rsc_free(NULL, R_TSC);
rsc_free(NULL, R_TSC);
rsc_free_range(NULL, R_USART1, R_USART5);
rsc_free_range(NULL, R_PA0, R_PA15);
+16 -8
View File
@@ -50,13 +50,7 @@ static inline void led_off(void)
/** Set up the LED */
void Indicator_Init(void)
{
bool suc = true;
// Resolve and claim resource
Resource rsc = hw_pin2resource(STATUS_LED_PORT, STATUS_LED_PIN, &suc);
assert_param(suc);
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, rsc));
assert_param(E_SUCCESS == rsc_claim_pin(&UNIT_SYSTEM, STATUS_LED_PORT, STATUS_LED_PIN));
}
/** Set indicator ON */
@@ -67,6 +61,12 @@ void Indicator_Effect(enum GEX_StatusIndicator indicator)
led_on();
}
// prevent the two disk ops interfering (happens in write-reload)
if (indicator == STATUS_DISK_BUSY && active_effect == STATUS_DISK_BUSY_SHORT) return;
if (indicator == STATUS_DISK_BUSY_SHORT && active_effect == STATUS_DISK_BUSY) return;
// TODO add some better protection against effect overlap?
active_effect = indicator;
effect_time = 0;
}
@@ -125,7 +125,15 @@ void Indicator_Tick(void)
active_effect = STATUS_NONE;
}
else if (effect_time % 100 == 0) led_on();
else if (effect_time % 100 == 50) led_off();
else if (effect_time % 100 == 20) led_off();
}
else if (active_effect == STATUS_DISK_BUSY_SHORT) {
if (effect_time >= 200) {
led_off();
active_effect = STATUS_NONE;
}
else if (effect_time % 100 == 0) led_on();
else if (effect_time % 100 == 20) led_off();
}
else if (active_effect == STATUS_WELCOME) {
if (effect_time == 0) led_on();
+1
View File
@@ -16,6 +16,7 @@ enum GEX_StatusIndicator {
STATUS_NONE = 0,
STATUS_FAULT,
STATUS_DISK_BUSY,
STATUS_DISK_BUSY_SHORT,
STATUS_DISK_ATTACHED,
STATUS_DISK_REMOVED,
STATUS_WELCOME,
+9 -7
View File
@@ -7,10 +7,12 @@
// ---------------------------- HAL TIMEBASE -----------------------------
#define TIMEBASE_TIMER TIM14
#define TIMEBASE_TIMER TIM17
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
// EDIT - used 17 instead because 14 was needed for fcap
// TIM14 is a simple 16-bit timer timer with no special features.
// This makes it a good choice for the timebase generation. We set it to generate
// an interrupt every 1 ms
@@ -19,9 +21,9 @@ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
// - TIM14 is always up-counting
// - using APB1 clock
__HAL_RCC_TIM14_CLK_ENABLE();
NVIC_SetPriority(TIM14_IRQn, TickPriority); // highest possible priority
NVIC_EnableIRQ(TIM14_IRQn);
__HAL_RCC_TIM17_CLK_ENABLE();
NVIC_SetPriority(TIM17_IRQn, TickPriority); // highest possible priority
NVIC_EnableIRQ(TIM17_IRQn);
/* Compute TIM1 clock */
uint32_t uwTimclock = HAL_RCC_GetPCLK1Freq();
@@ -45,7 +47,7 @@ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
static volatile uint32_t uwUptimeMs = 0;
/* TIMEBASE TIMER ISR */
void TIM14_IRQHandler(void)
void TIM17_IRQHandler(void)
{
uwUptimeMs++;
LL_TIM_ClearFlag_UPDATE(TIMEBASE_TIMER);
@@ -89,10 +91,10 @@ uint64_t PTIM_GetMicrotime(void)
uwMicros = TIMEBASE_TIMER->CNT;
uwMillis = uwUptimeMs;
if (LL_TIM_IsActiveFlag_UPDATE(TIM14)) {
if (LL_TIM_IsActiveFlag_UPDATE(TIMEBASE_TIMER)) {
// This means the timer has overflown after we disabled IRQ
// Use the last CNT value before the overflow
uwMicros = TIM14->ARR; // this is 999us
uwMicros = TIMEBASE_TIMER->ARR; // this is 999us
}
}
vPortExitCritical();
+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 -2
View File
@@ -4,6 +4,7 @@
#include "platform.h"
#include "platform/lock_jumper.h"
#include "platform/watchdog.h"
#include "status_led.h"
#include "utils/stacksmon.h"
#include "vfs/vfs_manager.h"
@@ -12,8 +13,6 @@
#include "usbd_msc.h"
#include "task_main.h"
extern void plat_init(void);
/* TaskUsbEvent function */
void TaskMain(void const * argument)
{
@@ -47,6 +46,8 @@ void TaskMain(void const * argument)
cnt++;
Indicator_Heartbeat();
wd_restart();
}
// if no message and it just timed out, go wait some more...
+3
View File
@@ -3,6 +3,7 @@
//
#include "platform.h"
#include "platform/watchdog.h"
#include "comm/messages.h"
#include "task_msg.h"
@@ -85,7 +86,9 @@ void TaskMsgJob(const void *argument)
#if CDC_LOOPBACK_TEST
TF_WriteImpl(comm, slot.msg.data, slot.msg.len);
#else
wd_suspend();
TF_Accept(comm, slot.msg.data, slot.msg.len);
wd_resume();
#endif
}
+1 -13
View File
@@ -14,15 +14,6 @@ error_t OW_preInit(Unit *unit)
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
if (priv == NULL) return E_OUT_OF_MEM;
// the timer is not started until needed
priv->busyWaitTimer = xTimerCreate("1w_tim", // name
750, // interval (will be changed when starting it)
true, // periodic (we use this only for the polling variant, the one-shot will stop the timer in the CB)
unit, // user data
OW_TimerCb); // callback
if (priv->busyWaitTimer == NULL) return E_OUT_OF_MEM;
// some defaults
priv->pin_number = 0;
priv->port_name = 'A';
@@ -40,7 +31,7 @@ error_t OW_init(Unit *unit)
// --- Parse config ---
priv->ll_pin = hw_pin2ll(priv->pin_number, &suc);
priv->port = hw_port2periph(priv->port_name, &suc);
Resource rsc = hw_pin2resource(priv->port_name, priv->pin_number, &suc);
Resource rsc = rsc_portpin2rsc(priv->port_name, priv->pin_number, &suc);
if (!suc) return E_BAD_CONFIG;
// --- Claim resources ---
@@ -63,9 +54,6 @@ void OW_deInit(Unit *unit)
// Release all resources
rsc_teardown(unit);
// Delete the software timer
assert_param(pdPASS == xTimerDelete(priv->busyWaitTimer, 1000));
// Free memory
free_ck(unit->data);
}
+4 -6
View File
@@ -18,17 +18,15 @@ void OW_loadBinary(Unit *unit, PayloadParser *pp)
priv->port_name = pp_char(pp);
priv->pin_number = pp_u8(pp);
if (version >= 1) {
priv->parasitic = pp_bool(pp);
}
}
/** Write to a binary buffer for storing in Flash */
void OW_writeBinary(Unit *unit, PayloadBuilder *pb)
{
struct priv *priv = unit->data;
pb_u8(pb, 1); // version
pb_u8(pb, 0); // version
pb_char(pb, priv->port_name);
pb_u8(pb, priv->pin_number);
@@ -44,10 +42,10 @@ error_t OW_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data;
if (streq(key, "pin")) {
suc = parse_pin(value, &priv->port_name, &priv->pin_number);
suc = cfg_portpin_parse(value, &priv->port_name, &priv->pin_number);
}
else if (streq(key, "parasitic")) {
priv->parasitic = str_parse_yn(value, &suc);
priv->parasitic = cfg_bool_parse(value, &suc);
}
else {
return E_BAD_KEY;
@@ -66,5 +64,5 @@ void OW_writeIni(Unit *unit, IniWriter *iw)
iw_entry(iw, "pin", "%c%d", priv->port_name, priv->pin_number);
iw_comment(iw, "Parasitic (bus-powered) mode");
iw_entry(iw, "parasitic", str_yn(priv->parasitic));
iw_entry_s(iw, "parasitic", str_yn(priv->parasitic));
}
+14 -11
View File
@@ -38,12 +38,13 @@ static void OW_TimerRespCb(Job *job)
*
* @param xTimer
*/
void OW_TimerCb(TimerHandle_t xTimer)
void OW_tickHandler(Unit *unit)
{
Unit *unit = pvTimerGetTimerID(xTimer);
assert_param(unit);
struct priv *priv = unit->data;
assert_param(priv->busy);
if(!priv->busy) {
dbg("ow tick should be disabled now!");
return;
}
if (priv->parasitic) {
// this is the end of the 750ms measurement time
@@ -56,7 +57,8 @@ void OW_TimerCb(TimerHandle_t xTimer)
uint32_t time = PTIM_GetTime();
if (time - priv->busyStart > 1000) {
xTimerStop(xTimer, 100);
unit->tick_interval = 0;
unit->_tick_cnt = 0;
Job j = {
.unit = unit,
@@ -69,7 +71,8 @@ void OW_TimerCb(TimerHandle_t xTimer)
return;
halt_ok:
xTimerStop(xTimer, 100);
unit->tick_interval = 0;
unit->_tick_cnt = 0;
Job j = {
.unit = unit,
@@ -79,7 +82,6 @@ halt_ok:
scheduleJob(&j);
}
enum PinCmd_ {
CMD_CHECK_PRESENCE = 0, // simply tests that any devices are attached
CMD_SEARCH_ADDR = 1, // perform a scan of the bus, retrieving all found device ROMs
@@ -120,13 +122,13 @@ static error_t OW_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Pay
*/
case CMD_POLL_FOR_1:
// This can't be exposed via the UU API, due to being async
unit->_tick_cnt = 0;
unit->tick_interval = 750;
if (priv->parasitic) {
assert_param(pdPASS == xTimerChangePeriod(priv->busyWaitTimer, 750, 100));
unit->tick_interval = 750;
} else {
// every 10 ticks
assert_param(pdPASS == xTimerChangePeriod(priv->busyWaitTimer, 10, 100));
unit->tick_interval = 10;
}
assert_param(pdPASS == xTimerStart(priv->busyWaitTimer, 100));
priv->busy = true;
priv->busyStart = PTIM_GetTime();
priv->busyRequestId = frame_id;
@@ -242,4 +244,5 @@ const UnitDriver UNIT_1WIRE = {
.deInit = OW_deInit,
// Function
.handleRequest = OW_handleRequest,
.updateTick = OW_tickHandler,
};
+8 -5
View File
@@ -40,7 +40,8 @@ static void UADC_JobSendBlockChunk(Job *job)
.len = (TF_LEN) (1 /*seq*/ + count * sizeof(uint16_t)),
.type = type,
};
TF_Respond_Multipart(comm, &msg);
assert_param(true == TF_Respond_Multipart(comm, &msg));
TF_Multipart_Payload(comm, &priv->stream_serial, 1);
TF_Multipart_Payload(comm, (uint8_t *) (priv->dma_buffer + start), count * sizeof(uint16_t));
TF_Multipart_Close(comm);
@@ -171,7 +172,7 @@ static void handle_httc(Unit *unit, bool tc)
const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP;
if (ht) {
end = (priv->buf_itemcount / 2);
end = (priv->buf_itemcount >> 1); // div2
}
else {
end = priv->buf_itemcount;
@@ -234,7 +235,7 @@ static void handle_httc(Unit *unit, bool tc)
priv->stream_startpos = 0;
}
else {
priv->stream_startpos = priv->buf_itemcount / 2;
priv->stream_startpos = priv->buf_itemcount >> 1; // div2
}
}
@@ -289,7 +290,7 @@ void UADC_DMA_Handler(void *arg)
const bool m_stream = priv->opmode == ADC_OPMODE_STREAM;
const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP;
if (m_trigd || m_stream || m_fixcpt) {
const uint32_t half = (uint32_t) (priv->buf_itemcount / 2);
const uint32_t half = (uint32_t) (priv->buf_itemcount >> 1); // div2
if (ht && tc) {
// dual event interrupt - may happen if we missed both and they were pending after
// interrupts became enabled again (this can happen due to the EOS or other higher prio irq's)
@@ -336,8 +337,10 @@ void UADC_ADC_EOS_Handler(void *arg)
if (priv->opmode == ADC_OPMODE_UNINIT) return;
// Wait for the DMA to complete copying the last sample
uint32_t dmapos;
uint32_t dmapos = DMA_POS(priv);
if ((DMA_POS(priv) % priv->nb_channels) != 0) {
hw_wait_while((dmapos = DMA_POS(priv)) % priv->nb_channels != 0, 100); // XXX this could be changed to reading it from the DR instead
}
uint32_t sample_pos;
if (dmapos == 0) {
+1 -1
View File
@@ -35,7 +35,7 @@ error_t UADC_SetSampleRate(Unit *unit, uint32_t hertz)
uint16_t presc;
uint32_t count;
if (!solve_timer(PLAT_APB1_HZ, hertz, true, &presc, &count, &priv->real_frequency)) {
if (!hw_solve_timer(PLAT_APB1_HZ, hertz, true, &presc, &count, &priv->real_frequency)) {
dbg("Failed to resolve timer params.");
return E_BAD_VALUE;
}
+10 -10
View File
@@ -48,20 +48,20 @@ error_t UADC_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data;
if (streq(key, "channels")) {
priv->cfg.channels = parse_pinmask(value, &suc);
priv->cfg.channels = cfg_pinmask_parse_32(value, &suc);
}
else if (streq(key, "sample_time")) {
priv->cfg.sample_time = (uint8_t) avr_atoi(value);
priv->cfg.sample_time = cfg_u8_parse(value, &suc);
if (priv->cfg.sample_time > 7) return E_BAD_VALUE;
}
else if (streq(key, "frequency")) {
priv->cfg.frequency = (uint32_t) avr_atoi(value);
priv->cfg.frequency = cfg_u32_parse(value, &suc);
}
else if (streq(key, "buffer_size")) {
priv->cfg.buffer_size = (uint32_t) avr_atoi(value);
priv->cfg.buffer_size = cfg_u32_parse(value, &suc);
}
else if (streq(key, "avg_factor")) {
priv->cfg.averaging_factor = (uint16_t) avr_atoi(value);
priv->cfg.averaging_factor = cfg_u16_parse(value, &suc);
if (priv->cfg.averaging_factor > 1000) return E_BAD_VALUE;
}
else {
@@ -80,14 +80,14 @@ void UADC_writeIni(Unit *unit, IniWriter *iw)
iw_comment(iw, "Enabled channels, comma separated");
iw_comment(iw, " 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17");
iw_comment(iw, "A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 C0 C1 C2 C3 C4 C5 Tsens Vref");
iw_entry(iw, "channels", "%s", pinmask2str_up(priv->cfg.channels, unit_tmp512));
iw_entry_s(iw, "channels", cfg_pinmask_encode(priv->cfg.channels, unit_tmp512, true));
iw_cmt_newline(iw);
iw_comment(iw, "Sampling time (0-7)");
iw_entry(iw, "sample_time", "%d", (int)priv->cfg.sample_time);
iw_entry_d(iw, "sample_time", priv->cfg.sample_time);
iw_comment(iw, "Sampling frequency (Hz)");
iw_entry(iw, "frequency", "%d", (int)priv->cfg.frequency);
iw_entry_d(iw, "frequency", priv->cfg.frequency);
iw_cmt_newline(iw);
iw_comment(iw, "Sample buffer size");
@@ -95,12 +95,12 @@ void UADC_writeIni(Unit *unit, IniWriter *iw)
iw_comment(iw, "- defines the maximum pre-trigger size (divide by # of channels)");
iw_comment(iw, "- captured data is sent in half-buffer chunks");
iw_comment(iw, "- buffer overrun aborts the data capture");
iw_entry(iw, "buffer_size", "%d", (int)priv->cfg.buffer_size);
iw_entry_d(iw, "buffer_size", priv->cfg.buffer_size);
iw_cmt_newline(iw);
iw_comment(iw, "Exponential averaging coefficient (permil, range 0-1000 ~ 0.000-1.000)");
iw_comment(iw, "- used formula: y[t]=(1-k)*y[t-1]+k*u[t]");
iw_comment(iw, "- not available when a capture is running");
iw_entry(iw, "avg_factor", "%d", priv->cfg.averaging_factor);
iw_entry_d(iw, "avg_factor", priv->cfg.averaging_factor);
}
+16 -21
View File
@@ -20,23 +20,18 @@ void DIn_loadBinary(Unit *unit, PayloadParser *pp)
priv->pins = pp_u16(pp);
priv->pulldown = pp_u16(pp);
priv->pullup = pp_u16(pp);
if (version >= 1) {
priv->trig_rise = pp_u16(pp);
priv->trig_fall = pp_u16(pp);
priv->trig_holdoff = pp_u16(pp);
}
if (version >= 2) {
priv->def_auto = pp_u16(pp);
}
}
/** Write to a binary buffer for storing in Flash */
void DIn_writeBinary(Unit *unit, PayloadBuilder *pb)
{
struct priv *priv = unit->data;
pb_u8(pb, 2); // version
pb_u8(pb, 0); // version
pb_char(pb, priv->port_name);
pb_u16(pb, priv->pins);
@@ -57,28 +52,28 @@ error_t DIn_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data;
if (streq(key, "port")) {
suc = parse_port_name(value, &priv->port_name);
suc = cfg_port_parse(value, &priv->port_name);
}
else if (streq(key, "pins")) {
priv->pins = parse_pinmask(value, &suc);
priv->pins = cfg_pinmask_parse(value, &suc);
}
else if (streq(key, "pull-up")) {
priv->pullup = parse_pinmask(value, &suc);
priv->pullup = cfg_pinmask_parse(value, &suc);
}
else if (streq(key, "pull-down")) {
priv->pulldown = parse_pinmask(value, &suc);
priv->pulldown = cfg_pinmask_parse(value, &suc);
}
else if (streq(key, "trig-rise")) {
priv->trig_rise = parse_pinmask(value, &suc);
priv->trig_rise = cfg_pinmask_parse(value, &suc);
}
else if (streq(key, "trig-fall")) {
priv->trig_fall = parse_pinmask(value, &suc);
priv->trig_fall = cfg_pinmask_parse(value, &suc);
}
else if (streq(key, "auto-trigger")) {
priv->def_auto = parse_pinmask(value, &suc);
priv->def_auto = cfg_pinmask_parse(value, &suc);
}
else if (streq(key, "hold-off")) {
priv->trig_holdoff = (uint16_t) avr_atoi(value);
priv->trig_holdoff = cfg_u16_parse(value, &suc);
}
else {
return E_BAD_KEY;
@@ -97,24 +92,24 @@ void DIn_writeIni(Unit *unit, IniWriter *iw)
iw_entry(iw, "port", "%c", priv->port_name);
iw_comment(iw, "Pins (comma separated, supports ranges)");
iw_entry(iw, "pins", "%s", pinmask2str(priv->pins, unit_tmp512));
iw_entry_s(iw, "pins", cfg_pinmask_encode(priv->pins, unit_tmp512, 0));
iw_comment(iw, "Pins with pull-up");
iw_entry(iw, "pull-up", "%s", pinmask2str(priv->pullup, unit_tmp512));
iw_entry_s(iw, "pull-up", cfg_pinmask_encode(priv->pullup, unit_tmp512, 0));
iw_comment(iw, "Pins with pull-down");
iw_entry(iw, "pull-down", "%s", pinmask2str(priv->pulldown, unit_tmp512));
iw_entry_s(iw, "pull-down", cfg_pinmask_encode(priv->pulldown, unit_tmp512, 0));
iw_cmt_newline(iw);
iw_comment(iw, "Trigger pins activated by rising/falling edge");
iw_entry(iw, "trig-rise", "%s", pinmask2str(priv->trig_rise, unit_tmp512));
iw_entry(iw, "trig-fall", "%s", pinmask2str(priv->trig_fall, unit_tmp512));
iw_entry_s(iw, "trig-rise", cfg_pinmask_encode(priv->trig_rise, unit_tmp512, 0));
iw_entry_s(iw, "trig-fall", cfg_pinmask_encode(priv->trig_fall, unit_tmp512, 0));
iw_comment(iw, "Trigger pins auto-armed by default");
iw_entry(iw, "auto-trigger", "%s", pinmask2str(priv->def_auto, unit_tmp512));
iw_entry_s(iw, "auto-trigger", cfg_pinmask_encode(priv->def_auto, unit_tmp512, 0));
iw_comment(iw, "Triggers hold-off time (ms)");
iw_entry(iw, "hold-off", "%d", (int)priv->trig_holdoff);
iw_entry_d(iw, "hold-off", priv->trig_holdoff);
#if PLAT_NO_FLOATING_INPUTS
iw_comment(iw, "NOTE: Pins use pull-up by default.\r\n");
+7 -7
View File
@@ -44,16 +44,16 @@ error_t DOut_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data;
if (streq(key, "port")) {
suc = parse_port_name(value, &priv->port_name);
suc = cfg_port_parse(value, &priv->port_name);
}
else if (streq(key, "pins")) {
priv->pins = (uint16_t) parse_pinmask(value, &suc);
priv->pins = cfg_pinmask_parse(value, &suc);
}
else if (streq(key, "initial")) {
priv->initial = (uint16_t) parse_pinmask(value, &suc);
priv->initial = cfg_pinmask_parse(value, &suc);
}
else if (streq(key, "open-drain")) {
priv->open_drain = (uint16_t) parse_pinmask(value, &suc);
priv->open_drain = cfg_pinmask_parse(value, &suc);
}
else {
return E_BAD_KEY;
@@ -72,11 +72,11 @@ void DOut_writeIni(Unit *unit, IniWriter *iw)
iw_entry(iw, "port", "%c", priv->port_name);
iw_comment(iw, "Pins (comma separated, supports ranges)");
iw_entry(iw, "pins", "%s", pinmask2str(priv->pins, unit_tmp512));
iw_entry_s(iw, "pins", cfg_pinmask_encode(priv->pins, unit_tmp512, 0));
iw_comment(iw, "Initially high pins");
iw_entry(iw, "initial", "%s", pinmask2str(priv->initial, unit_tmp512));
iw_entry_s(iw, "initial", cfg_pinmask_encode(priv->initial, unit_tmp512, 0));
iw_comment(iw, "Open-drain pins");
iw_entry(iw, "open-drain", "%s", pinmask2str(priv->open_drain, unit_tmp512));
iw_entry_s(iw, "open-drain", cfg_pinmask_encode(priv->open_drain, unit_tmp512, 0));
}
+11
View File
@@ -0,0 +1,11 @@
//
// Created by MightyPork on 2018/02/03.
//
#include "platform.h"
#include "unit_base.h"
#include "unit_fcap.h"
#define FCAP_INTERNAL
#include "_fcap_internal.h"
+462
View File
@@ -0,0 +1,462 @@
//
// Created by MightyPork on 2018/02/20.
//
#include <stm32f072xb.h>
#include "platform.h"
#define FCAP_INTERNAL
#include "_fcap_internal.h"
static void UFCAP_StopMeasurement(Unit *unit);
static void UFCAP_ConfigureForIndirectCapture(Unit *unit);
static void UFCAP_ConfigureForDirectCapture(Unit *unit, uint16_t msec);
static void UFCAP_ConfigureForFreeCapture(Unit *unit);
uint32_t UFCAP_GetFreeCounterValue(Unit *unit)
{
struct priv * const priv = unit->data;
TIM_TypeDef * const TIMx = priv->TIMx;
return TIMx->CNT;
}
uint32_t UFCAP_FreeCounterClear(Unit *unit)
{
struct priv * const priv = unit->data;
TIM_TypeDef * const TIMx = priv->TIMx;
// this isn't perfect, we can miss one clock
// but it's probably the best we can do here ...
vPortEnterCritical();
uint32_t val = TIMx->CNT;
TIMx->CNT = 0;
vPortExitCritical();
return val;
}
static void UFCAP_IndirectBurstReportJob(Job *job)
{
Unit *unit = job->unit;
struct priv * const priv = unit->data;
uint8_t buf[20];
PayloadBuilder pb = pb_start(buf, 20, NULL);
pb_u16(&pb, PLAT_AHB_MHZ);
pb_u16(&pb, priv->ind_burst.n_count);
pb_u64(&pb, priv->ind_burst.period_acu);
pb_u64(&pb, priv->ind_burst.ontime_acu);
assert_param(pb.ok);
com_respond_pb(priv->request_id, MSG_SUCCESS, &pb);
// timer is already stopped, now in OPMODE_BUSY
priv->opmode = OPMODE_IDLE;
}
static void UFCAP_SinglePulseReportJob(Job *job)
{
Unit *unit = job->unit;
struct priv * const priv = unit->data;
uint8_t buf[6];
PayloadBuilder pb = pb_start(buf, 6, NULL);
pb_u16(&pb, PLAT_AHB_MHZ);
pb_u32(&pb, job->data1);
assert_param(pb.ok);
com_respond_pb(priv->request_id, MSG_SUCCESS, &pb);
// timer is already stopped, now in OPMODE_BUSY
priv->opmode = OPMODE_IDLE;
}
/**
* Count is passed in data1
* @param job
*/
static void UFCAP_DirectBurstReportJob(Job *job)
{
Unit *unit = job->unit;
struct priv * const priv = unit->data;
uint8_t buf[8];
PayloadBuilder pb = pb_start(buf, 8, NULL);
pb_u8(&pb, priv->direct_presc);
pb_u16(&pb, priv->dir_burst.msec);
pb_u32(&pb, job->data1);
assert_param(pb.ok);
com_respond_pb(priv->request_id, MSG_SUCCESS, &pb);
// timer is already stopped, now in OPMODE_BUSY
priv->opmode = OPMODE_IDLE;
}
void UFCAP_TIMxHandler(void *arg)
{
Unit *unit = arg;
assert_param(unit);
struct priv * const priv = unit->data;
assert_param(priv);
TIM_TypeDef * const TIMx = priv->TIMx;
if (priv->opmode == OPMODE_INDIRECT_CONT) {
if (LL_TIM_IsActiveFlag_CC1(TIMx)) {
if (priv->n_skip > 0) {
priv->n_skip--;
} else {
priv->ind_cont.last_period = LL_TIM_IC_GetCaptureCH1(TIMx);
priv->ind_cont.last_ontime = priv->ind_cont.ontime;
}
LL_TIM_ClearFlag_CC1(TIMx);
LL_TIM_ClearFlag_CC1OVR(TIMx);
}
if (LL_TIM_IsActiveFlag_CC2(TIMx)) {
priv->ind_cont.ontime = LL_TIM_IC_GetCaptureCH2(TIMx);
LL_TIM_ClearFlag_CC2(TIMx);
LL_TIM_ClearFlag_CC2OVR(TIMx);
}
}
else if (priv->opmode == OPMODE_SINGLE_PULSE) {
if (LL_TIM_IsActiveFlag_CC2(TIMx)) {
// single pulse - does not wait for the second edge
uint32_t len = LL_TIM_IC_GetCaptureCH2(TIMx);
priv->opmode = OPMODE_BUSY;
UFCAP_StopMeasurement(unit);
Job j = {
.cb = UFCAP_SinglePulseReportJob,
.unit = unit,
.data1 = len,
};
scheduleJob(&j);
}
}
else if (priv->opmode == OPMODE_INDIRECT_BURST) {
if (LL_TIM_IsActiveFlag_CC1(TIMx)) {
const uint32_t period = LL_TIM_IC_GetCaptureCH1(TIMx);
const uint32_t ontime = priv->ind_burst.ontime;
if (priv->n_skip > 0) {
priv->n_skip--;
} else {
priv->ind_burst.ontime_acu += ontime;
priv->ind_burst.period_acu += period;
if (++priv->ind_burst.n_count == priv->ind_burst.n_target) {
priv->opmode = OPMODE_BUSY;
UFCAP_StopMeasurement(unit);
Job j = {
.cb = UFCAP_IndirectBurstReportJob,
.unit = unit,
};
scheduleJob(&j);
}
}
LL_TIM_ClearFlag_CC1(TIMx);
LL_TIM_ClearFlag_CC1OVR(TIMx);
}
if (LL_TIM_IsActiveFlag_CC2(TIMx)) {
priv->ind_burst.ontime = LL_TIM_IC_GetCaptureCH2(TIMx);
LL_TIM_ClearFlag_CC2(TIMx);
LL_TIM_ClearFlag_CC2OVR(TIMx);
}
}
else if (priv->opmode == OPMODE_IDLE) {
// clear everything - in idle it would cycle in the handler forever
TIMx->SR = 0;
}
else {
trap("Unhandled fcap TIMx irq");
}
}
void UFCAP_TIMyHandler(void *arg)
{
Unit *unit = arg;
assert_param(unit);
struct priv *const priv = unit->data;
assert_param(priv);
TIM_TypeDef * const TIMx = priv->TIMx;
TIM_TypeDef * const TIMy = priv->TIMy;
uint32_t cnt = TIMx->CNT; // TIMx should be stopped now
// dbg("> TIMy Handler, TIMx cntr is %d", cnt);
priv->dir_cont.last_count = cnt;
if (priv->opmode == OPMODE_DIRECT_CONT) {
LL_TIM_DisableCounter(TIMx);
LL_TIM_DisableCounter(TIMy);
LL_TIM_SetCounter(TIMx, 0);
LL_TIM_SetCounter(TIMy, 0);
LL_TIM_EnableCounter(TIMy); // next loop
LL_TIM_EnableCounter(TIMx);
}
else if (priv->opmode == OPMODE_DIRECT_BURST) {
priv->opmode = OPMODE_BUSY;
UFCAP_StopMeasurement(unit);
Job j = {
.cb = UFCAP_DirectBurstReportJob,
.unit = unit,
.data1 = cnt,
};
scheduleJob(&j);
}
else if (priv->opmode == OPMODE_IDLE) {
// clear everything - in idle it would cycle in the handler forever
TIMy->SR = 0;
}
else {
trap("Unhandled fcap TIMy irq");
}
LL_TIM_ClearFlag_UPDATE(TIMy);
}
static void UFCAP_ClearTimerConfig(Unit *unit)
{
struct priv * const priv = unit->data;
TIM_TypeDef * const TIMx = priv->TIMx;
// CLEAR CURRENT STATE, STOP
UFCAP_StopMeasurement(unit);
// CONFIGURE TIMER BASIC PARAMS
LL_TIM_SetPrescaler(TIMx, 0);
LL_TIM_SetAutoReload(TIMx, 0xFFFFFFFF);
LL_TIM_EnableARRPreload(TIMx);
LL_TIM_GenerateEvent_UPDATE(TIMx);
}
/**
* Reset all timer registers
*
* @param unit
*/
static void UFCAP_StopMeasurement(Unit *unit)
{
struct priv * const priv = unit->data;
LL_TIM_DeInit(priv->TIMx); // clear all flags and settings
LL_TIM_DeInit(priv->TIMy); // clear all flags and settings
}
/**
* Switch the FCAP module opmode
*
* @param unit
* @param opmode
*/
void UFCAP_SwitchMode(Unit *unit, enum fcap_opmode opmode)
{
struct priv * const priv = unit->data;
if (opmode == priv->opmode) return;
priv->opmode = opmode;
switch (opmode) {
case OPMODE_IDLE:
// XXX maybe we should report the abort to the PC-side listener
UFCAP_StopMeasurement(unit);
break;
case OPMODE_INDIRECT_CONT:
priv->ind_cont.last_ontime = 0;
priv->ind_cont.last_period = 0;
priv->ind_cont.ontime = 0;
priv->n_skip = 1; // discard the first cycle (will be incomplete)
UFCAP_ConfigureForIndirectCapture(unit); // is also stopped and restarted
break;
case OPMODE_INDIRECT_BURST:
priv->ind_burst.ontime = 0;
priv->ind_burst.n_count = 0;
priv->ind_burst.period_acu = 0;
priv->ind_burst.ontime_acu = 0;
priv->n_skip = 1; // discard the first cycle (will be incomplete)
UFCAP_ConfigureForIndirectCapture(unit); // is also stopped and restarted
break;
case OPMODE_SINGLE_PULSE:
priv->n_skip = 0;
UFCAP_ConfigureForIndirectCapture(unit); // is also stopped and restarted
break;
case OPMODE_DIRECT_CONT:
// msec is set by caller
priv->dir_cont.last_count = 0;
priv->n_skip = 1; // discard the first cycle (will be incomplete)
UFCAP_ConfigureForDirectCapture(unit, priv->direct_msec);
break;
case OPMODE_DIRECT_BURST:
// msec is set by caller
priv->n_skip = 0; // no skip here (if there was any)
UFCAP_ConfigureForDirectCapture(unit, (uint16_t) priv->dir_burst.msec);
break;
case OPMODE_FREE_COUNTER:
UFCAP_ConfigureForFreeCapture(unit);
break;
default:
trap("Unhandled opmode %d", (int)opmode);
}
}
/**
* Configure peripherals for an indirect capture (PWM measurement) - continuous or burst
* @param unit
*/
static void UFCAP_ConfigureForIndirectCapture(Unit *unit)
{
struct priv * const priv = unit->data;
TIM_TypeDef * const TIMx = priv->TIMx;
const uint32_t ll_ch_a = priv->ll_ch_a;
const uint32_t ll_ch_b = priv->ll_ch_b;
UFCAP_ClearTimerConfig(unit);
// Enable channels and select mapping to TIx signals
// A - will be used to measure period
// B - will be used to measure the duty cycle
// _________ ______
// _______| |________________|
// A B A
// irq irq,cap irq
// reset
// B irq may be used if we want to measure a pulse width
// Normally TI1 = CH1, TI2 = CH2.
// It's possible to select the other channel, which we use to connect both TIx to the shame CHx.
LL_TIM_IC_SetActiveInput(TIMx, ll_ch_a, priv->a_direct ? LL_TIM_ACTIVEINPUT_DIRECTTI : LL_TIM_ACTIVEINPUT_INDIRECTTI);
LL_TIM_IC_SetActiveInput(TIMx, ll_ch_b, priv->a_direct ? LL_TIM_ACTIVEINPUT_INDIRECTTI : LL_TIM_ACTIVEINPUT_DIRECTTI);
LL_TIM_IC_SetPolarity(TIMx, ll_ch_a, priv->active_level ? LL_TIM_IC_POLARITY_RISING : LL_TIM_IC_POLARITY_FALLING);
LL_TIM_IC_SetPolarity(TIMx, ll_ch_b, priv->active_level ? LL_TIM_IC_POLARITY_FALLING : LL_TIM_IC_POLARITY_RISING);
if (priv->dfilter > 15) priv->dfilter = 15;
uint32_t filter = LL_TIM_IC_FILTERS[priv->dfilter];
LL_TIM_IC_SetFilter(TIMx, ll_ch_a, filter);
LL_TIM_IC_SetFilter(TIMx, ll_ch_b, filter);
LL_TIM_CC_EnableChannel(TIMx, ll_ch_a | ll_ch_b);
LL_TIM_SetSlaveMode(TIMx, LL_TIM_SLAVEMODE_RESET);
LL_TIM_SetTriggerInput(TIMx, LL_TIM_TS_TI1FP1); // Use Filtered Input 1 (TI1)
LL_TIM_EnableMasterSlaveMode(TIMx);
LL_TIM_ClearFlag_CC1(TIMx);
LL_TIM_ClearFlag_CC1OVR(TIMx);
LL_TIM_ClearFlag_CC2(TIMx);
LL_TIM_ClearFlag_CC2OVR(TIMx);
LL_TIM_EnableIT_CC1(TIMx);
LL_TIM_EnableIT_CC2(TIMx);
LL_TIM_EnableCounter(TIMx);
}
/**
* Configure peripherals for an indirect capture (PWM measurement) - continuous or burst
* @param unit
*/
static void UFCAP_ConfigureForDirectCapture(Unit *unit, uint16_t msec)
{
struct priv * const priv = unit->data;
// dbg("Configuring Direct capture...");
UFCAP_ClearTimerConfig(unit);
{
TIM_TypeDef *const TIMy = priv->TIMy;
assert_param(PLAT_AHB_MHZ<=65);
uint16_t presc = PLAT_AHB_MHZ*1000;
uint32_t count = msec+1; // it's one tick longer because we generate OCREF on the exact msec count - it must be at least 1 tick long
LL_TIM_SetPrescaler(TIMy, (uint32_t) (presc - 1));
LL_TIM_SetAutoReload(TIMy, count - 1);
LL_TIM_EnableARRPreload(TIMy);
LL_TIM_GenerateEvent_UPDATE(TIMy);
LL_TIM_SetOnePulseMode(TIMy, LL_TIM_ONEPULSEMODE_SINGLE);
LL_TIM_OC_EnableFast(TIMy, LL_TIM_CHANNEL_CH1);
// dbg("TIMy presc %d, count %d", (int) presc, (int) count);
LL_TIM_SetTriggerOutput(TIMy, LL_TIM_TRGO_OC1REF);
LL_TIM_OC_SetMode(TIMy, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM1); // 1 until CC, then 0
LL_TIM_OC_SetCompareCH1(TIMy, count-1);
LL_TIM_CC_EnableChannel(TIMy, LL_TIM_CHANNEL_CH1); // enable the output channel that produces a trigger
LL_TIM_ClearFlag_UPDATE(TIMy);
LL_TIM_EnableIT_UPDATE(TIMy);
}
{
// TIMx - the slave
TIM_TypeDef *const TIMx = priv->TIMx;
LL_TIM_SetSlaveMode(TIMx, LL_TIM_SLAVEMODE_GATED);
LL_TIM_SetTriggerInput(TIMx, LL_TIM_TS_ITR3); // ITR3 is TIM14 which we use as TIMy
LL_TIM_EnableMasterSlaveMode(TIMx);
uint32_t presc = LL_TIM_ETR_PRESCALER_DIV1;
switch (priv->direct_presc) {
case 1: presc = LL_TIM_ETR_PRESCALER_DIV1; break;
case 2: presc = LL_TIM_ETR_PRESCALER_DIV2; break;
case 4: presc = LL_TIM_ETR_PRESCALER_DIV4; break;
case 8: presc = LL_TIM_ETR_PRESCALER_DIV8; break;
default:
priv->direct_presc = 1; // will be sent with the response
}
if (priv->dfilter > 15) priv->dfilter = 15;
uint32_t filter = LL_TIM_ETR_FILTERS[priv->dfilter];
LL_TIM_ConfigETR(TIMx,
priv->active_level ? LL_TIM_ETR_POLARITY_NONINVERTED : LL_TIM_ETR_POLARITY_INVERTED,
presc,
filter);
LL_TIM_EnableExternalClock(TIMx); // TODO must check and deny this mode if the pin is not on CH1 = external trigger input
LL_TIM_SetCounter(TIMx, 0);
LL_TIM_EnableCounter(TIMx);
}
LL_TIM_EnableCounter(priv->TIMy); // XXX this will start the first pulse (maybe)
}
/**
* Freerunning capture (counting pulses - geiger)
* @param unit
*/
static void UFCAP_ConfigureForFreeCapture(Unit *unit)
{
struct priv * const priv = unit->data;
UFCAP_ClearTimerConfig(unit);
TIM_TypeDef *const TIMx = priv->TIMx;
LL_TIM_EnableExternalClock(TIMx);
LL_TIM_SetCounter(TIMx, 0);
LL_TIM_EnableCounter(TIMx);
}
+147
View File
@@ -0,0 +1,147 @@
//
// Created by MightyPork on 2018/02/03.
//
#include "platform.h"
#include "unit_base.h"
#define FCAP_INTERNAL
#include "_fcap_internal.h"
/** Allocate data structure and set defaults */
error_t UFCAP_preInit(Unit *unit)
{
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
if (priv == NULL) return E_OUT_OF_MEM;
priv->conf.signal_pname = 'A';
priv->conf.signal_pnum = 0;
priv->conf.active_level = 1;
priv->conf.direct_presc = 1;
priv->conf.dfilter = 0;
priv->conf.direct_msec = 1000;
priv->conf.startmode = OPMODE_IDLE;
return E_SUCCESS;
}
/** Finalize unit set-up */
error_t UFCAP_init(Unit *unit)
{
bool suc = true;
struct priv *priv = unit->data;
// ---- Resolve what to configure ----
TIM_TypeDef * const TIMx = TIM2;
Resource timRsc = R_TIM2;
TIM_TypeDef * const TIMy = TIM14;
Resource tim2Rsc = R_TIM14;
uint32_t ll_ch_a = 0;
uint32_t ll_ch_b = 0;
switch (priv->conf.signal_pname) {
case 'A':
switch (priv->conf.signal_pnum) {
case 5:
case 15:
case 0: ll_ch_a = LL_TIM_CHANNEL_CH1; break;
case 1: ll_ch_a = LL_TIM_CHANNEL_CH2; break;
default:
dbg("Bad signal pin!");
return E_BAD_CONFIG;
}
break;
case 'B':
switch (priv->conf.signal_pnum) {
case 3: ll_ch_a = LL_TIM_CHANNEL_CH2; break;
default:
dbg("Bad signal pin!");
return E_BAD_CONFIG;
}
break;
default:
dbg("Bad signal pin port!");
return E_BAD_CONFIG;
}
const uint32_t ll_timpin_af = LL_GPIO_AF_2;
bool a_direct = true;
switch (ll_ch_a) {
case LL_TIM_CHANNEL_CH1:
ll_ch_b = LL_TIM_CHANNEL_CH2;
break;
case LL_TIM_CHANNEL_CH2:
ll_ch_b = LL_TIM_CHANNEL_CH1;
a_direct = false;
break;
}
// ---- CLAIM ----
TRY(rsc_claim_pin(unit, priv->conf.signal_pname, priv->conf.signal_pnum));
TRY(rsc_claim(unit, timRsc));
TRY(rsc_claim(unit, tim2Rsc));
// ---- INIT ----
assert_param(ll_ch_a != ll_ch_b);
priv->TIMx = TIMx;
priv->TIMy = TIMy;
priv->ll_ch_a = ll_ch_a;
priv->ll_ch_b = ll_ch_b;
priv->a_direct = a_direct;
// Load defaults
priv->active_level = priv->conf.active_level;
priv->direct_presc = priv->conf.direct_presc;
priv->dfilter = priv->conf.dfilter;
priv->direct_msec = priv->conf.direct_msec;
priv->opmode = priv->conf.startmode;
TRY(hw_configure_gpio_af(priv->conf.signal_pname, priv->conf.signal_pnum, ll_timpin_af));
GPIO_TypeDef *gpio = hw_port2periph(priv->conf.signal_pname, &suc);
uint32_t ll_pin = hw_pin2ll(priv->conf.signal_pnum, &suc);
LL_GPIO_SetPinPull(gpio, ll_pin, LL_GPIO_PULL_DOWN); // XXX change to pull-up if the polarity is inverted
hw_periph_clock_enable(TIMx);
hw_periph_clock_enable(TIMy);
irqd_attach(TIMx, UFCAP_TIMxHandler, unit);
irqd_attach(TIMy, UFCAP_TIMyHandler, unit);
UFCAP_SwitchMode(unit, priv->opmode); // switch to the default opmode
return E_SUCCESS;
}
/** Tear down the unit */
void UFCAP_deInit(Unit *unit)
{
struct priv *priv = unit->data;
// de-init peripherals
if (unit->status == E_SUCCESS ) {
UFCAP_SwitchMode(unit, OPMODE_IDLE);
TIM_TypeDef *TIMx = priv->TIMx;
TIM_TypeDef *TIMy = priv->TIMy;
LL_TIM_DeInit(TIMx);
LL_TIM_DeInit(TIMy);
irqd_detach(TIMx, UFCAP_TIMxHandler);
irqd_detach(TIMy, UFCAP_TIMyHandler);
hw_periph_clock_disable(TIMx);
hw_periph_clock_disable(TIMy);
}
// Release all resources, deinit pins
rsc_teardown(unit);
// Free memory
free_ck(unit->data);
}
+117
View File
@@ -0,0 +1,117 @@
//
// Created by MightyPork on 2018/02/03.
//
#ifndef GEX_F072_FCAP_INTERNAL_H
#define GEX_F072_FCAP_INTERNAL_H
#ifndef FCAP_INTERNAL
#error bad include!
#endif
#include "unit_base.h"
enum fcap_opmode {
OPMODE_IDLE = 0,
OPMODE_BUSY = 1, // used after capture is done, before it's reported
OPMODE_INDIRECT_CONT = 2,
OPMODE_INDIRECT_BURST = 3, // averaging
OPMODE_DIRECT_CONT = 4,
OPMODE_DIRECT_BURST = 5,
OPMODE_FREE_COUNTER = 6,
OPMODE_SINGLE_PULSE = 7,
};
/** Private data structure */
struct priv {
// settings
struct {
char signal_pname; // the input pin - one of TIM2 channels
uint8_t signal_pnum;
bool active_level;
uint8_t direct_presc;
uint8_t dfilter;
uint16_t direct_msec;
enum fcap_opmode startmode;
} conf;
// internal state
TIM_TypeDef *TIMx;
TIM_TypeDef *TIMy; // used as a timebase source for TIMx in direct mode
uint32_t ll_ch_b;
uint32_t ll_ch_a;
bool a_direct;
enum fcap_opmode opmode;
TF_ID request_id;
uint8_t n_skip; //!< Periods to skip before starting the real capture
bool active_level; // in PWM mode, the first part that is measured. (if 1, HHHLLL, else LLLHHH). In direct mode, clock polarity
uint8_t direct_presc;
uint16_t direct_msec;
uint8_t dfilter;
union {
struct {
uint32_t ontime; // length of the captured positive pulse in the current interval
uint32_t last_period; //!< length of the captured interval between two rising edges
uint32_t last_ontime; //!< length of the last captured ontime
} ind_cont;
struct {
uint32_t ontime; // length of the captured positive pulse in the current interval
uint64_t period_acu; //!< length of the captured interval between two rising edges, sum
uint64_t ontime_acu; //!< length of the last captured ontime, sum
uint16_t n_count; //!< Periods captured
uint16_t n_target; //!< Periods captured - requested count
} ind_burst;
struct {
uint32_t last_count; //!< Pulse count in the last capture window
} dir_cont;
struct {
uint16_t msec; // capture window length (used in the report callback) - different from the cont time, which is a semi-persistent config
} dir_burst;
};
};
/** Allocate data structure and set defaults */
error_t UFCAP_preInit(Unit *unit);
/** Load from a binary buffer stored in Flash */
void UFCAP_loadBinary(Unit *unit, PayloadParser *pp);
/** Write to a binary buffer for storing in Flash */
void UFCAP_writeBinary(Unit *unit, PayloadBuilder *pb);
// ------------------------------------------------------------------------
/** Parse a key-value pair from the INI file */
error_t UFCAP_loadIni(Unit *unit, const char *key, const char *value);
/** Generate INI file section for the unit */
void UFCAP_writeIni(Unit *unit, IniWriter *iw);
// ------------------------------------------------------------------------
/** Finalize unit set-up */
error_t UFCAP_init(Unit *unit);
/** Tear down the unit */
void UFCAP_deInit(Unit *unit);
// ------------------------------------------------------------------------
void UFCAP_SwitchMode(Unit *unit, enum fcap_opmode opmode);
void UFCAP_TIMxHandler(void *arg);
void UFCAP_TIMyHandler(void *arg);
uint32_t UFCAP_GetFreeCounterValue(Unit *unit);
uint32_t UFCAP_FreeCounterClear(Unit *unit);
#endif //GEX_F072_FCAP_INTERNAL_H
+114
View File
@@ -0,0 +1,114 @@
//
// Created by MightyPork on 2018/02/03.
//
#include "platform.h"
#include "unit_base.h"
#define FCAP_INTERNAL
#include "_fcap_internal.h"
/** Load from a binary buffer stored in Flash */
void UFCAP_loadBinary(Unit *unit, PayloadParser *pp)
{
struct priv *priv = unit->data;
uint8_t version = pp_u8(pp);
(void)version;
priv->conf.signal_pname = pp_char(pp);
priv->conf.signal_pnum = pp_u8(pp);
priv->conf.active_level = pp_bool(pp);
priv->conf.dfilter = pp_u8(pp);
priv->conf.direct_presc = pp_u8(pp);
priv->conf.direct_msec = pp_u16(pp);
priv->conf.startmode = (enum fcap_opmode) pp_u8(pp);
}
/** Write to a binary buffer for storing in Flash */
void UFCAP_writeBinary(Unit *unit, PayloadBuilder *pb)
{
struct priv *priv = unit->data;
pb_u8(pb, 0); // version
pb_char(pb, priv->conf.signal_pname);
pb_u8(pb, priv->conf.signal_pnum);
pb_bool(pb, priv->conf.active_level);
pb_u8(pb, priv->conf.dfilter);
pb_u8(pb, priv->conf.direct_presc);
pb_u16(pb, priv->conf.direct_msec);
pb_u8(pb, priv->conf.startmode);
}
// ------------------------------------------------------------------------
/** Parse a key-value pair from the INI file */
error_t UFCAP_loadIni(Unit *unit, const char *key, const char *value)
{
bool suc = true;
struct priv *priv = unit->data;
if (streq(key, "pin")) {
suc = cfg_portpin_parse(value, &priv->conf.signal_pname, &priv->conf.signal_pnum);
}
else if (streq(key, "active-level")) {
priv->conf.active_level = cfg_bool_parse(value, &suc);
}
else if (streq(key, "input-filter")) {
priv->conf.dfilter = cfg_u8_parse(value, &suc);
}
else if (streq(key, "direct-presc")) {
priv->conf.direct_presc = cfg_u8_parse(value, &suc);
}
else if (streq(key, "direct-time")) {
priv->conf.direct_msec = cfg_u16_parse(value, &suc);
}
else if (streq(key, "initial-mode")) {
priv->conf.startmode = (enum fcap_opmode) cfg_enum4_parse(value,
"N", OPMODE_IDLE,
"I", OPMODE_INDIRECT_CONT,
"D", OPMODE_DIRECT_CONT,
"F", OPMODE_FREE_COUNTER,
&suc);
}
else{
return E_BAD_KEY;
}
if (!suc) return E_BAD_VALUE;
return E_SUCCESS;
}
/** Generate INI file section for the unit */
void UFCAP_writeIni(Unit *unit, IniWriter *iw)
{
struct priv *priv = unit->data;
iw_comment(iw, "Signal input pin - one of:");
iw_comment(iw, " Full support: A0, A5, A15");
iw_comment(iw, " Indirect only: A1, B3");
iw_entry(iw, "pin", "%c%d", priv->conf.signal_pname, priv->conf.signal_pnum);
iw_cmt_newline(iw);
iw_comment(iw, "Active level or edge (0-low,falling; 1-high,rising)");
iw_entry_d(iw, "active-level", priv->conf.active_level);
iw_comment(iw, "Input filtering (0-15)");
iw_entry_d(iw, "input-filter", priv->conf.dfilter);
iw_comment(iw, "Pulse counter pre-divider (1,2,4,8)");
iw_entry_d(iw, "direct-presc", priv->conf.direct_presc);
iw_comment(iw, "Pulse counting interval (ms)");
iw_entry_d(iw, "direct-time", priv->conf.direct_msec);
iw_cmt_newline(iw);
iw_comment(iw, "Mode on startup: N-none, I-indirect, D-direct, F-free count");
iw_entry_s(iw, "initial-mode", cfg_enum4_encode(priv->conf.startmode,
OPMODE_IDLE, "N",
OPMODE_INDIRECT_CONT, "I",
OPMODE_DIRECT_CONT, "D",
OPMODE_FREE_COUNTER, "F"));
}
+322
View File
@@ -0,0 +1,322 @@
//
// Created by MightyPork on 2017/11/25.
//
#include "unit_base.h"
#include "unit_fcap.h"
#define FCAP_INTERNAL
#include "_fcap_internal.h"
// ------------------------------------------------------------------------
enum FcapCmd_ {
CMD_STOP = 0,
// Measuring a waveform
CMD_INDIRECT_CONT_START = 1, // keep measuring, read on demand
CMD_INDIRECT_BURST_START = 2, // wait and reply
// Counting pulses
CMD_DIRECT_CONT_START = 3, // keep measuring, read on demand
CMD_DIRECT_BURST_START = 4, // wait and reply
CMD_FREECOUNT_START = 5, // keep counting pulses until stopped, read on reply
CMD_MEASURE_SINGLE_PULSE = 6, // measure the first incoming pulse of the right polarity. NOTE: can glitch if the signal starts in the active level
CMD_FREECOUNT_CLEAR = 7, // clear the free counter, return last value
// Results readout for continuous modes
CMD_INDIRECT_CONT_READ = 10,
CMD_DIRECT_CONT_READ = 11,
CMD_FREECOUNT_READ = 12,
// configs
CMD_SET_POLARITY = 20,
CMD_SET_DIR_PRESC = 21,
CMD_SET_INPUT_FILTER = 22,
CMD_SET_DIR_MSEC = 23,
// go back to the configured settings
CMD_RESTORE_DEFAULTS = 30,
};
/** Handle a request message */
static error_t UFCAP_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
{
uint8_t presc;
uint16_t msec;
struct priv *priv = unit->data;
PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL);
const char* msg_denied_on_pin = "Not available on the selected pin!";
switch (command) {
/**
* Stop any ongoing measurement and return to base state.
*/
case CMD_STOP:
UFCAP_SwitchMode(unit, OPMODE_IDLE);
return E_SUCCESS;
// ----------------------- CONFIG --------------------------
/**
* Set the active polarity, or triggering edge (for direct)
*
* pld: pol:u8 (0,1)
*/
case CMD_SET_POLARITY:
{
priv->active_level = pp_bool(pp);
}
return E_SUCCESS;
/**
* Set the direct measurement prescaller 1,2,4,8
*
* pld: presc:u8
*/
case CMD_SET_DIR_PRESC:
{
presc = pp_u8(pp);
if (presc != 1 && presc != 2 && presc != 4 && presc != 8) return E_BAD_VALUE;
priv->direct_presc = presc;
}
return E_SUCCESS;
/**
* Set the input filter for all modes
*
* pld: filter:u8 (0-15)
*/
case CMD_SET_INPUT_FILTER:
{
uint8_t input_filter = pp_u8(pp);
if (input_filter >= 16) return E_BAD_VALUE;
priv->dfilter = input_filter;
}
return E_SUCCESS;
/**
* Set the direct sampling time.
*
* pld: msec:u16
*/
case CMD_SET_DIR_MSEC:
{
msec = pp_u16(pp);
priv->direct_msec = msec;
}
return E_SUCCESS;
/**
* Reset all SET* settings to their default values, stop any ongoing measure.
*/
case CMD_RESTORE_DEFAULTS:
UFCAP_SwitchMode(unit, OPMODE_IDLE);
priv->active_level = priv->conf.active_level;
priv->direct_presc = priv->conf.direct_presc;
priv->direct_msec = priv->conf.direct_msec;
priv->dfilter = priv->conf.dfilter;
return E_SUCCESS;
// ------------------ COMMANDS ------------------------
/**
* Start indirect continuous measurement.
*/
case CMD_INDIRECT_CONT_START:
if (priv->opmode == OPMODE_INDIRECT_CONT) return E_SUCCESS; // no-op
if (priv->opmode != OPMODE_IDLE) return E_BUSY;
UFCAP_SwitchMode(unit, OPMODE_INDIRECT_CONT);
return E_SUCCESS;
/**
* Start a continuous direct measurement (counting pulses in fixed time intervals)
*
* - meas_time_ms 0 = no change
* - prescaller 0 = no change
*
* pld: meas_time_ms:u16, prescaller:u8
* - prescaller is 1,2,4,8; 0 = no change
*/
case CMD_DIRECT_CONT_START:
if (!priv->a_direct) {
// This works only if we use the ETR pin. TIM2 shares CH1 with ETR.
// If CH2 is selected as input, ETR is not available.
com_respond_str(MSG_ERROR, frame_id, msg_denied_on_pin);
return E_FAILURE;
}
if (priv->opmode == OPMODE_DIRECT_CONT) return E_SUCCESS; // no-op
if (priv->opmode != OPMODE_IDLE) return E_BUSY;
msec = pp_u16(pp);
presc = pp_u8(pp);
if (msec != 0) priv->direct_msec = msec;
if (presc != 0) priv->direct_presc = presc;
UFCAP_SwitchMode(unit, OPMODE_DIRECT_CONT);
return E_SUCCESS;
/**
* Start a burst of direct measurements with averaging.
* The measurement is performed on N consecutive pulses.
*
* pld: count:u16
*
* resp: core_mhz:u16, count:u16, period_sum:u64, ontime_sum:u64
*/
case CMD_INDIRECT_BURST_START:
if (priv->opmode != OPMODE_IDLE) return E_BAD_MODE;
priv->ind_burst.n_target = pp_u16(pp);
priv->request_id = frame_id;
UFCAP_SwitchMode(unit, OPMODE_INDIRECT_BURST);
return E_SUCCESS;
/**
* Start a single direct measurement of the given length (pulses in time period)
* If 'prescaller' is not 0, it is changed via the param field.
*
* pld: meas_time_ms:u16, prescaller:u8
* - prescaller is 1,2,4,8; 0 = no change
*
* resp: prescaller:u8, meas_time_ms:u16, pulse_count:u32
*/
case CMD_DIRECT_BURST_START:
if (priv->opmode != OPMODE_IDLE) return E_BAD_MODE;
priv->dir_burst.msec = pp_u16(pp);
presc = pp_u8(pp);
if (presc != 0) priv->direct_presc = presc;
priv->request_id = frame_id;
UFCAP_SwitchMode(unit, OPMODE_DIRECT_BURST);
return E_SUCCESS;
/**
* Measure a single pulse length of the given polarity.
* Measures time from a rising to a falling edge (or falling to rising, if polarity is 0)
*
* resp: core_mhz:u16, ontime:u32
*/
case CMD_MEASURE_SINGLE_PULSE:
if (priv->opmode != OPMODE_IDLE) return E_BAD_MODE;
priv->request_id = frame_id;
UFCAP_SwitchMode(unit, OPMODE_SINGLE_PULSE);
return E_SUCCESS;
/**
* Start a free-running pulse counter.
*
* pld: prescaller:u8
* - prescaller is 1,2,4,8; 0 = no change
*/
case CMD_FREECOUNT_START:
if (priv->opmode != OPMODE_IDLE) return E_BAD_MODE;
presc = pp_u8(pp);
if (presc != 0) priv->direct_presc = presc;
UFCAP_SwitchMode(unit, OPMODE_FREE_COUNTER);
return E_SUCCESS;
/**
* Reset the free-running pulse counter.
*
* resp: last_val:u32
*/
case CMD_FREECOUNT_CLEAR:
if (priv->opmode != OPMODE_FREE_COUNTER) {
return E_BAD_MODE;
}
pb_u32(&pb, UFCAP_FreeCounterClear(unit));
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
return E_SUCCESS;
// ------------------ READING ---------------------
/**
* Read the most recent pulse measurement during continuous indirect measure.
*
* resp: core_mhz:u16, period:u32, ontime:u32
*/
case CMD_INDIRECT_CONT_READ:
if (priv->opmode != OPMODE_INDIRECT_CONT) {
return E_BAD_MODE;
}
if (priv->ind_cont.last_period == 0) {
return E_BUSY;
}
pb_u16(&pb, PLAT_AHB_MHZ);
pb_u32(&pb, priv->ind_cont.last_period);
pb_u32(&pb, priv->ind_cont.last_ontime);
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
return E_SUCCESS;
/**
* Read the most recent result of a continuous direct measurement.
*
* resp: prescaller:u8, meas_time_ms:u16, pulse_count:u32
*/
case CMD_DIRECT_CONT_READ:
if (!priv->a_direct) { // see above
com_respond_str(MSG_ERROR, frame_id, msg_denied_on_pin);
return E_FAILURE;
}
if (priv->opmode != OPMODE_DIRECT_CONT) return E_BAD_MODE;
if (priv->dir_cont.last_count == 0) return E_BUSY;
pb_u8(&pb, priv->direct_presc);
pb_u16(&pb, priv->direct_msec);
pb_u32(&pb, priv->dir_cont.last_count);
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
return E_SUCCESS;
/**
* Read the current value of the free-running pulse counter.
*
* The timing may have a significant jitter, this function is practically useful only for
* slow pulse sources (like a geiger counter, item counting etc)
*
* resp: count:u32
*/
case CMD_FREECOUNT_READ:
if (priv->opmode != OPMODE_FREE_COUNTER) {
return E_BAD_MODE;
}
pb_u32(&pb, UFCAP_GetFreeCounterValue(unit));
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
return E_SUCCESS;
default:
return E_UNKNOWN_COMMAND;
}
}
// ------------------------------------------------------------------------
/** Frequency capture */
const UnitDriver UNIT_FCAP = {
.name = "FCAP",
.description = "Frequency and pulse measurement",
// Settings
.preInit = UFCAP_preInit,
.cfgLoadBinary = UFCAP_loadBinary,
.cfgWriteBinary = UFCAP_writeBinary,
.cfgLoadIni = UFCAP_loadIni,
.cfgWriteIni = UFCAP_writeIni,
// Init
.init = UFCAP_init,
.deInit = UFCAP_deInit,
// Function
.handleRequest = UFCAP_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_FCAP_H
#define U_FCAP_H
#include "unit.h"
extern const UnitDriver UNIT_FCAP;
// UU_ prototypes
#endif //U_FCAP_H
+11 -14
View File
@@ -20,18 +20,15 @@ void UI2C_loadBinary(Unit *unit, PayloadParser *pp)
priv->anf = pp_bool(pp);
priv->dnf = pp_u8(pp);
priv->speed = pp_u8(pp);
if (version >= 1) {
priv->remap = pp_u8(pp);
}
}
/** Write to a binary buffer for storing in Flash */
void UI2C_writeBinary(Unit *unit, PayloadBuilder *pb)
{
struct priv *priv = unit->data;
pb_u8(pb, 1); // version
pb_u8(pb, 0); // version
pb_u8(pb, priv->periph_num);
pb_bool(pb, priv->anf);
@@ -49,19 +46,19 @@ error_t UI2C_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data;
if (streq(key, "device")) {
priv->periph_num = (uint8_t) avr_atoi(value);
priv->periph_num = cfg_u8_parse(value, &suc);
}
else if (streq(key, "remap")) {
priv->remap = (uint8_t) avr_atoi(value);
priv->remap = cfg_u8_parse(value, &suc);
}
else if (streq(key, "analog-filter")) {
priv->anf = str_parse_yn(value, &suc);
priv->anf = cfg_bool_parse(value, &suc);
}
else if (streq(key, "digital-filter")) {
priv->dnf = (uint8_t) avr_atoi(value);
priv->dnf = cfg_u8_parse(value, &suc);
}
else if (streq(key, "speed")) {
priv->speed = (uint8_t) avr_atoi(value);
priv->speed = cfg_u8_parse(value, &suc);
}
else {
return E_BAD_KEY;
@@ -77,7 +74,7 @@ void UI2C_writeIni(Unit *unit, IniWriter *iw)
struct priv *priv = unit->data;
iw_comment(iw, "Peripheral number (I2Cx)");
iw_entry(iw, "device", "%d", (int)priv->periph_num);
iw_entry_d(iw, "device", priv->periph_num);
iw_comment(iw, "Pin mappings (SCL,SDA)");
#if GEX_PLAT_F072_DISCOVERY
@@ -92,15 +89,15 @@ void UI2C_writeIni(Unit *unit, IniWriter *iw)
#else
#error "BAD PLATFORM!"
#endif
iw_entry(iw, "remap", "%d", (int)priv->remap);
iw_entry_d(iw, "remap", priv->remap);
iw_cmt_newline(iw);
iw_comment(iw, "Speed: 1-Standard, 2-Fast, 3-Fast+");
iw_entry(iw, "speed", "%d", (int)priv->speed);
iw_entry_d(iw, "speed", priv->speed);
iw_comment(iw, "Analog noise filter enable (Y,N)");
iw_entry(iw, "analog-filter", "%s", str_yn(priv->anf));
iw_entry_s(iw, "analog-filter", str_yn(priv->anf));
iw_comment(iw, "Digital noise filter bandwidth (0-15)");
iw_entry(iw, "digital-filter", "%d", (int)priv->dnf);
iw_entry_d(iw, "digital-filter", priv->dnf);
}
+6 -6
View File
@@ -16,7 +16,7 @@ error_t UU_Npx_Clear(Unit *unit)
CHECK_TYPE(unit, &UNIT_NEOPIXEL);
struct priv *priv = unit->data;
ws2812_clear(priv->port, priv->ll_pin, priv->pixels);
ws2812_clear(priv->port, priv->ll_pin, priv->cfg.pixels);
return E_SUCCESS;
}
@@ -26,8 +26,8 @@ error_t UU_Npx_Load(Unit *unit, const uint8_t *packed_rgb, uint32_t nbytes)
CHECK_TYPE(unit, &UNIT_NEOPIXEL);
struct priv *priv = unit->data;
if (nbytes != 3*priv->pixels) return E_BAD_COUNT;
ws2812_load_raw(priv->port, priv->ll_pin, packed_rgb, priv->pixels);
if (nbytes != 3*priv->cfg.pixels) return E_BAD_COUNT;
ws2812_load_raw(priv->port, priv->ll_pin, packed_rgb, priv->cfg.pixels);
return E_SUCCESS;
}
@@ -37,8 +37,8 @@ static error_t load_u32(Unit *unit, const uint8_t *bytes, uint32_t nbytes, bool
CHECK_TYPE(unit, &UNIT_NEOPIXEL);
struct priv *priv = unit->data;
if (nbytes != 4*priv->pixels) return E_BAD_COUNT;
ws2812_load_sparse(priv->port, priv->ll_pin, bytes, priv->pixels, bige);
if (nbytes != 4*priv->cfg.pixels) return E_BAD_COUNT;
ws2812_load_sparse(priv->port, priv->ll_pin, bytes, priv->cfg.pixels, bige);
return E_SUCCESS;
}
@@ -60,6 +60,6 @@ error_t UU_Npx_GetCount(Unit *unit, uint16_t *count)
CHECK_TYPE(unit, &UNIT_NEOPIXEL);
struct priv *priv = unit->data;
*count = priv->pixels;
*count = priv->cfg.pixels;
return E_SUCCESS;
}
+5 -10
View File
@@ -16,9 +16,8 @@ error_t Npx_preInit(Unit *unit)
if (priv == NULL) return E_OUT_OF_MEM;
// some defaults
priv->pin_number = 0;
priv->port_name = 'A';
priv->pixels = 1;
priv->cfg.pin = R_PA0;
priv->cfg.pixels = 1;
return E_SUCCESS;
}
@@ -30,13 +29,9 @@ error_t Npx_init(Unit *unit)
struct priv *priv = unit->data;
// --- Parse config ---
priv->ll_pin = hw_pin2ll(priv->pin_number, &suc);
priv->port = hw_port2periph(priv->port_name, &suc);
Resource rsc = hw_pin2resource(priv->port_name, priv->pin_number, &suc);
suc = hw_pinrsc2ll(priv->cfg.pin, &priv->port, &priv->ll_pin);
if (!suc) return E_BAD_CONFIG;
// --- Claim resources ---
TRY(rsc_claim(unit, rsc));
TRY(rsc_claim(unit, priv->cfg.pin));
// --- Init hardware ---
LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT);
@@ -45,7 +40,7 @@ error_t Npx_init(Unit *unit)
// clear strip
ws2812_clear(priv->port, priv->ll_pin, priv->pixels);
ws2812_clear(priv->port, priv->ll_pin, priv->cfg.pixels);
return E_SUCCESS;
}
+3 -2
View File
@@ -13,9 +13,10 @@
/** Private data structure */
struct priv {
char port_name;
uint8_t pin_number;
struct {
Resource pin;
uint16_t pixels;
} cfg;
uint32_t ll_pin;
GPIO_TypeDef *port;
+8 -10
View File
@@ -13,9 +13,8 @@ void Npx_loadBinary(Unit *unit, PayloadParser *pp)
{
struct priv *priv = unit->data;
priv->port_name = pp_char(pp);
priv->pin_number = pp_u8(pp);
priv->pixels = pp_u16(pp);
priv->cfg.pin = (Resource) pp_u8(pp);
priv->cfg.pixels = pp_u16(pp);
}
/** Write to a binary buffer for storing in Flash */
@@ -23,9 +22,8 @@ void Npx_writeBinary(Unit *unit, PayloadBuilder *pb)
{
struct priv *priv = unit->data;
pb_char(pb, priv->port_name);
pb_u8(pb, priv->pin_number);
pb_u16(pb, priv->pixels);
pb_u8(pb, priv->cfg.pin);
pb_u16(pb, priv->cfg.pixels);
}
// ------------------------------------------------------------------------
@@ -37,10 +35,10 @@ error_t Npx_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data;
if (streq(key, "pin")) {
suc = parse_pin(value, &priv->port_name, &priv->pin_number);
priv->cfg.pin = cfg_pinrsc_parse(value, &suc);
}
else if (streq(key, "pixels")) {
priv->pixels = (uint16_t) avr_atoi(value);
priv->cfg.pixels = cfg_u16_parse(value, &suc);
}
else {
return E_BAD_KEY;
@@ -56,8 +54,8 @@ void Npx_writeIni(Unit *unit, IniWriter *iw)
struct priv *priv = unit->data;
iw_comment(iw, "Data pin");
iw_entry(iw, "pin", "%c%d", priv->port_name, priv->pin_number);
iw_entry_s(iw, "pin", cfg_pinrsc_encode(priv->cfg.pin));
iw_comment(iw, "Number of pixels");
iw_entry(iw, "pixels", "%d", priv->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
+8 -8
View File
@@ -43,7 +43,7 @@ error_t UU_SIPO_Write(Unit *unit, const uint8_t *buffer, uint16_t buflen, uint16
// buffer contains data for the individual data pins, back to back as AAA BBB CCC (whole bytes)
const uint8_t data_width = priv->data_width;
const uint16_t bytelen = buflen / data_width;
const uint16_t mask = priv->data_pins;
const uint16_t mask = priv->cfg.data_pins;
uint8_t offsets[16];
for (int i=0; i<16; i++) offsets[i] = (uint8_t) (bytelen * i);
@@ -61,7 +61,7 @@ error_t UU_SIPO_Write(Unit *unit, const uint8_t *buffer, uint16_t buflen, uint16
priv->data_port->BSRR = spread | (((~spread) & mask) << 16);
// Shift clock pulse
send_pulse(priv->shift_pol, priv->shift_port, priv->shift_ll);
send_pulse(priv->cfg.shift_pol, priv->shift_port, priv->shift_ll);
}
}
@@ -70,7 +70,7 @@ error_t UU_SIPO_Write(Unit *unit, const uint8_t *buffer, uint16_t buflen, uint16
uint16_t spread = pinmask_spread(terminal_data, mask);
priv->data_port->BSRR = spread | (((~spread) & mask) << 16);
send_pulse(priv->store_pol, priv->store_port, priv->store_ll);
send_pulse(priv->cfg.store_pol, priv->store_port, priv->store_ll);
return E_SUCCESS;
}
#pragma GCC pop_options
@@ -80,8 +80,8 @@ error_t UU_SIPO_DirectData(Unit *unit, uint16_t data_packed)
CHECK_TYPE(unit, &UNIT_SIPO);
struct priv *priv = unit->data;
uint16_t spread = pinmask_spread(data_packed, priv->data_pins);
priv->data_port->BSRR = spread | (((~spread) & priv->data_pins) << 16);
uint16_t spread = pinmask_spread(data_packed, priv->cfg.data_pins);
priv->data_port->BSRR = spread | (((~spread) & priv->cfg.data_pins) << 16);
return E_SUCCESS;
}
@@ -89,7 +89,7 @@ error_t UU_SIPO_DirectClear(Unit *unit)
{
CHECK_TYPE(unit, &UNIT_SIPO);
struct priv *priv = unit->data;
send_pulse(priv->clear_pol, priv->clear_port, priv->clear_ll);
send_pulse(priv->cfg.clear_pol, priv->clear_port, priv->clear_ll);
return E_SUCCESS;
}
@@ -97,7 +97,7 @@ error_t UU_SIPO_DirectShift(Unit *unit)
{
CHECK_TYPE(unit, &UNIT_SIPO);
struct priv *priv = unit->data;
send_pulse(priv->shift_pol, priv->shift_port, priv->shift_ll);
send_pulse(priv->cfg.shift_pol, priv->shift_port, priv->shift_ll);
return E_SUCCESS;
}
@@ -105,6 +105,6 @@ error_t UU_SIPO_DirectStore(Unit *unit)
{
CHECK_TYPE(unit, &UNIT_SIPO);
struct priv *priv = unit->data;
send_pulse(priv->store_pol, priv->store_port, priv->store_ll);
send_pulse(priv->cfg.store_pol, priv->store_port, priv->store_ll);
return E_SUCCESS;
}
+21 -34
View File
@@ -14,20 +14,17 @@ error_t USIPO_preInit(Unit *unit)
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
if (priv == NULL) return E_OUT_OF_MEM;
priv->store_pname = 'A';
priv->store_pnum = 0;
priv->store_pol = true;
priv->cfg.pin_store = R_PA0;
priv->cfg.store_pol = true;
priv->shift_pname = 'A';
priv->shift_pnum = 1;
priv->shift_pol = true;
priv->cfg.pin_shift = R_PA1;
priv->cfg.shift_pol = true;
priv->clear_pname = 'A';
priv->clear_pnum = 2;
priv->clear_pol = false;
priv->cfg.pin_clear = R_PA2;
priv->cfg.clear_pol = false;
priv->data_pname = 'A';
priv->data_pins = (1<<3);
priv->cfg.data_pname = 'A';
priv->cfg.data_pins = (1<<3);
return E_SUCCESS;
}
@@ -39,33 +36,23 @@ error_t USIPO_init(Unit *unit)
struct priv *priv = unit->data;
// --- Parse config ---
priv->store_ll = hw_pin2ll(priv->store_pnum, &suc);
priv->store_port = hw_port2periph(priv->store_pname, &suc);
Resource store_rsc = hw_pin2resource(priv->store_pname, priv->store_pnum, &suc);
suc &= hw_pinrsc2ll(priv->cfg.pin_store, &priv->store_port, &priv->store_ll);
suc &= hw_pinrsc2ll(priv->cfg.pin_shift, &priv->shift_port, &priv->shift_ll);
suc &= hw_pinrsc2ll(priv->cfg.pin_clear, &priv->clear_port, &priv->clear_ll);
if (!suc) return E_BAD_CONFIG;
TRY(rsc_claim(unit, store_rsc));
priv->shift_ll = hw_pin2ll(priv->shift_pnum, &suc);
priv->shift_port = hw_port2periph(priv->shift_pname, &suc);
Resource shift_rsc = hw_pin2resource(priv->shift_pname, priv->shift_pnum, &suc);
if (!suc) return E_BAD_CONFIG;
TRY(rsc_claim(unit, shift_rsc));
priv->clear_ll = hw_pin2ll(priv->clear_pnum, &suc);
priv->clear_port = hw_port2periph(priv->clear_pname, &suc);
Resource clear_rsc = hw_pin2resource(priv->clear_pname, priv->clear_pnum, &suc);
if (!suc) return E_BAD_CONFIG;
TRY(rsc_claim(unit, clear_rsc));
TRY(rsc_claim(unit, priv->cfg.pin_store));
TRY(rsc_claim(unit, priv->cfg.pin_shift));
TRY(rsc_claim(unit, priv->cfg.pin_clear));
// Claim all needed pins
TRY(rsc_claim_gpios(unit, priv->data_pname, priv->data_pins));
priv->data_port = hw_port2periph(priv->data_pname, &suc);
TRY(rsc_claim_gpios(unit, priv->cfg.data_pname, priv->cfg.data_pins));
priv->data_port = hw_port2periph(priv->cfg.data_pname, &suc);
// --- Init hardware ---
priv->data_width = 0;
for (int i = 0; i < 16; i++) {
if (priv->data_pins & (1 << i)) {
if (priv->cfg.data_pins & (1 << i)) {
uint32_t ll_pin = hw_pin2ll((uint8_t) i, &suc);
LL_GPIO_SetPinMode(priv->data_port, ll_pin, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinOutputType(priv->data_port, ll_pin, LL_GPIO_OUTPUT_PUSHPULL);
@@ -75,7 +62,7 @@ error_t USIPO_init(Unit *unit)
}
// Set the initial state - zeros
priv->data_port->ODR &= ~priv->data_pins;
priv->data_port->ODR &= ~priv->cfg.data_pins;
// STORE
@@ -83,7 +70,7 @@ error_t USIPO_init(Unit *unit)
LL_GPIO_SetPinOutputType(priv->store_port, priv->store_ll, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinSpeed(priv->store_port, priv->store_ll, LL_GPIO_SPEED_FREQ_HIGH);
if (priv->store_pol)
if (priv->cfg.store_pol)
LL_GPIO_ResetOutputPin(priv->store_port, priv->store_ll);
else
LL_GPIO_SetOutputPin(priv->store_port, priv->store_ll);
@@ -93,7 +80,7 @@ error_t USIPO_init(Unit *unit)
LL_GPIO_SetPinOutputType(priv->shift_port, priv->shift_ll, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinSpeed(priv->shift_port, priv->shift_ll, LL_GPIO_SPEED_FREQ_HIGH);
if (priv->shift_pol)
if (priv->cfg.shift_pol)
LL_GPIO_ResetOutputPin(priv->shift_port, priv->shift_ll);
else
LL_GPIO_SetOutputPin(priv->shift_port, priv->shift_ll);
@@ -103,7 +90,7 @@ error_t USIPO_init(Unit *unit)
LL_GPIO_SetPinOutputType(priv->clear_port, priv->clear_ll, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinSpeed(priv->clear_port, priv->clear_ll, LL_GPIO_SPEED_FREQ_HIGH);
if (priv->clear_pol)
if (priv->cfg.clear_pol)
LL_GPIO_ResetOutputPin(priv->clear_port, priv->clear_ll);
else
LL_GPIO_SetOutputPin(priv->clear_port, priv->clear_ll);
+5 -6
View File
@@ -13,21 +13,20 @@
/** Private data structure */
struct priv {
struct {
// settings
char store_pname;
uint8_t store_pnum;
Resource pin_store;
bool store_pol; //!< Store pulse active edge
char shift_pname;
uint8_t shift_pnum;
Resource pin_shift;
bool shift_pol; //!< Shift clock active edge
char clear_pname;
uint8_t clear_pnum;
Resource pin_clear;
bool clear_pol; //!< Clear signal active level
char data_pname;
uint16_t data_pins;
} cfg;
// live fields
uint32_t store_ll;
+32 -38
View File
@@ -16,20 +16,17 @@ void USIPO_loadBinary(Unit *unit, PayloadParser *pp)
uint8_t version = pp_u8(pp);
(void)version;
priv->store_pname = pp_char(pp);
priv->store_pnum = pp_u8(pp);
priv->store_pol = pp_bool(pp);
priv->cfg.pin_store = (Resource) pp_u8(pp);
priv->cfg.store_pol = pp_bool(pp);
priv->shift_pname = pp_char(pp);
priv->shift_pnum = pp_u8(pp);
priv->shift_pol = pp_bool(pp);
priv->cfg.pin_shift = (Resource) pp_u8(pp);
priv->cfg.shift_pol = pp_bool(pp);
priv->clear_pname = pp_char(pp);
priv->clear_pnum = pp_u8(pp);
priv->clear_pol = pp_bool(pp);
priv->cfg.pin_clear = (Resource) pp_u8(pp);
priv->cfg.clear_pol = pp_bool(pp);
priv->data_pname = pp_char(pp);
priv->data_pins = pp_u16(pp);
priv->cfg.data_pname = pp_char(pp);
priv->cfg.data_pins = pp_u16(pp);
}
/** Write to a binary buffer for storing in Flash */
@@ -39,20 +36,17 @@ void USIPO_writeBinary(Unit *unit, PayloadBuilder *pb)
pb_u8(pb, 0); // version
pb_char(pb, priv->store_pname);
pb_u8(pb, priv->store_pnum);
pb_bool(pb, priv->store_pol);
pb_u8(pb, priv->cfg.pin_store);
pb_bool(pb, priv->cfg.store_pol);
pb_char(pb, priv->shift_pname);
pb_u8(pb, priv->shift_pnum);
pb_bool(pb, priv->shift_pol);
pb_u8(pb, priv->cfg.pin_shift);
pb_bool(pb, priv->cfg.shift_pol);
pb_char(pb, priv->clear_pname);
pb_u8(pb, priv->clear_pnum);
pb_bool(pb, priv->clear_pol);
pb_u8(pb, priv->cfg.pin_clear);
pb_bool(pb, priv->cfg.clear_pol);
pb_char(pb, priv->data_pname);
pb_u16(pb, priv->data_pins);
pb_char(pb, priv->cfg.data_pname);
pb_u16(pb, priv->cfg.data_pins);
}
// ------------------------------------------------------------------------
@@ -64,30 +58,30 @@ error_t USIPO_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data;
if (streq(key, "store-pin")) {
suc = parse_pin(value, &priv->store_pname, &priv->store_pnum);
priv->cfg.pin_store = cfg_pinrsc_parse(value, &suc);
}
else if (streq(key, "shift-pin")) {
suc = parse_pin(value, &priv->shift_pname, &priv->shift_pnum);
priv->cfg.pin_shift = cfg_pinrsc_parse(value, &suc);
}
else if (streq(key, "clear-pin")) {
suc = parse_pin(value, &priv->clear_pname, &priv->clear_pnum);
priv->cfg.pin_clear = cfg_pinrsc_parse(value, &suc);
}
else if (streq(key, "store-pol")) {
priv->store_pol = (bool) avr_atoi(value);
priv->cfg.store_pol = cfg_bool_parse(value, &suc);
}
else if (streq(key, "shift-pol")) {
priv->shift_pol = (bool) avr_atoi(value);
priv->cfg.shift_pol = cfg_bool_parse(value, &suc);
}
else if (streq(key, "clear-pol")) {
priv->clear_pol = (bool) avr_atoi(value);
priv->cfg.clear_pol = cfg_bool_parse(value, &suc);
}
else if (streq(key, "data-port")) {
suc = parse_port_name(value, &priv->data_pname);
suc = cfg_port_parse(value, &priv->cfg.data_pname);
}
else if (streq(key, "data-pins")) {
priv->data_pins = (uint16_t) parse_pinmask(value, &suc);
priv->cfg.data_pins = cfg_pinmask_parse(value, &suc);
}
else {
@@ -104,19 +98,19 @@ void USIPO_writeIni(Unit *unit, IniWriter *iw)
struct priv *priv = unit->data;
iw_comment(iw, "Shift pin & its active edge (1-rising,0-falling)");
iw_entry(iw, "shift-pin", "%c%d", priv->shift_pname, priv->shift_pnum);
iw_entry(iw, "shift-pol", "%d", priv->shift_pol);
iw_entry_s(iw, "shift-pin", cfg_pinrsc_encode(priv->cfg.pin_shift));
iw_entry_d(iw, "shift-pol", priv->cfg.shift_pol);
iw_comment(iw, "Store pin & its active edge");
iw_entry(iw, "store-pin", "%c%d", priv->store_pname, priv->store_pnum);
iw_entry(iw, "store-pol", "%d", priv->store_pol);
iw_entry_s(iw, "store-pin", cfg_pinrsc_encode(priv->cfg.pin_store));
iw_entry_d(iw, "store-pol", priv->cfg.store_pol);
iw_comment(iw, "Clear pin & its active level");
iw_entry(iw, "clear-pin", "%c%d", priv->clear_pname, priv->clear_pnum);
iw_entry(iw, "clear-pol", "%d", priv->clear_pol);
iw_entry_s(iw, "clear-pin", cfg_pinrsc_encode(priv->cfg.pin_clear));
iw_entry_d(iw, "clear-pol", priv->cfg.clear_pol);
iw_comment(iw, "Data port and pins");
iw_entry(iw, "data-port", "%c", priv->data_pname);
iw_entry(iw, "data-pins", "%s", pinmask2str_up(priv->data_pins, unit_tmp512));
iw_entry(iw, "data-port", "%c", priv->cfg.data_pname);
iw_entry_s(iw, "data-pins", cfg_pinmask_encode(priv->cfg.data_pins, unit_tmp512, true));
}
+17 -19
View File
@@ -58,31 +58,31 @@ error_t USPI_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data;
if (streq(key, "device")) {
priv->periph_num = (uint8_t) avr_atoi(value);
priv->periph_num = cfg_u8_parse(value, &suc);
}
else if (streq(key, "remap")) {
priv->remap = (uint8_t) avr_atoi(value);
priv->remap = cfg_u8_parse(value, &suc);
}
else if (streq(key, "prescaller")) {
priv->prescaller = (uint16_t ) avr_atoi(value);
priv->prescaller = cfg_u16_parse(value, &suc);
}
else if (streq(key, "cpol")) {
priv->cpol = (bool) avr_atoi(value);
priv->cpol = cfg_bool_parse(value, &suc);
}
else if (streq(key, "cpha")) {
priv->cpha = (bool) avr_atoi(value);
priv->cpha = cfg_bool_parse(value, &suc);
}
else if (streq(key, "tx-only")) {
priv->tx_only = str_parse_yn(value, &suc);
priv->tx_only = cfg_bool_parse(value, &suc);
}
else if (streq(key, "first-bit")) {
priv->lsb_first = (bool)str_parse_2(value, "MSB", 0, "LSB", 1, &suc);
priv->lsb_first = (bool) cfg_enum2_parse(value, "MSB", 0, "LSB", 1, &suc);
}
else if (streq(key, "port")) {
suc = parse_port_name(value, &priv->ssn_port_name);
suc = cfg_port_parse(value, &priv->ssn_port_name);
}
else if (streq(key, "pins")) {
priv->ssn_pins = parse_pinmask(value, &suc);
priv->ssn_pins = cfg_pinmask_parse(value, &suc);
}
else {
return E_BAD_KEY;
@@ -98,7 +98,7 @@ void USPI_writeIni(Unit *unit, IniWriter *iw)
struct priv *priv = unit->data;
iw_comment(iw, "Peripheral number (SPIx)");
iw_entry(iw, "device", "%d", (int)priv->periph_num);
iw_entry_d(iw, "device", priv->periph_num);
// TODO show a legend for peripherals and remaps
iw_comment(iw, "Pin mappings (SCK,MISO,MOSI)");
@@ -114,30 +114,28 @@ void USPI_writeIni(Unit *unit, IniWriter *iw)
#else
#error "BAD PLATFORM!"
#endif
iw_entry(iw, "remap", "%d", (int)priv->remap);
iw_entry_d(iw, "remap", priv->remap);
iw_cmt_newline(iw);
iw_comment(iw, "Prescaller: 2,4,8,...,256");
iw_entry(iw, "prescaller", "%d", (int)priv->prescaller);
iw_entry_d(iw, "prescaller", priv->prescaller);
iw_comment(iw, "Clock polarity: 0,1 (clock idle level)");
iw_entry(iw, "cpol", "%d", (int)priv->cpol);
iw_entry_d(iw, "cpol", priv->cpol);
iw_comment(iw, "Clock phase: 0,1 (active edge, 0-first, 1-second)");
iw_entry(iw, "cpha", "%d", (int)priv->cpha);
iw_entry_d(iw, "cpha", priv->cpha);
iw_comment(iw, "Transmit only, disable MISO");
iw_entry(iw, "tx-only", str_yn(priv->tx_only));
iw_entry_s(iw, "tx-only", str_yn(priv->tx_only));
iw_comment(iw, "Bit order (LSB or MSB first)");
iw_entry(iw, "first-bit", str_2((uint32_t)priv->lsb_first,
0, "MSB",
1, "LSB"));
iw_entry_s(iw, "first-bit", cfg_enum2_encode((uint32_t) priv->lsb_first, 0, "MSB", 1, "LSB"));
iw_cmt_newline(iw);
iw_comment(iw, "SS port name");
iw_entry(iw, "port", "%c", priv->ssn_port_name);
iw_comment(iw, "SS pins (comma separated, supports ranges)");
iw_entry(iw, "pins", "%s", pinmask2str(priv->ssn_pins, unit_tmp512));
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
+35 -35
View File
@@ -81,66 +81,66 @@ error_t UUSART_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data;
if (streq(key, "device")) {
priv->periph_num = (uint8_t) avr_atoi(value);
priv->periph_num = cfg_u8_parse(value, &suc);
}
else if (streq(key, "remap")) {
priv->remap = (uint8_t) avr_atoi(value);
priv->remap = cfg_u8_parse(value, &suc);
}
else if (streq(key, "baud-rate")) {
priv->baudrate = (uint32_t ) avr_atoi(value);
priv->baudrate = cfg_u32_parse(value, &suc);
}
else if (streq(key, "parity")) {
priv->parity = (uint8_t) str_parse_3(value,
priv->parity = (uint8_t) cfg_enum3_parse(value,
"NONE", 0,
"ODD", 1,
"EVEN", 2, &suc);
}
else if (streq(key, "stop-bits")) {
priv->stopbits = (uint8_t) str_parse_4(value,
priv->stopbits = (uint8_t) cfg_enum4_parse(value,
"0.5", 0,
"1", 1,
"1.5", 2,
"2", 3, &suc);
}
else if (streq(key, "direction")) {
priv->direction = (uint8_t) str_parse_3(value,
priv->direction = (uint8_t) cfg_enum3_parse(value,
"RX", UUSART_DIRECTION_RX,
"TX", UUSART_DIRECTION_TX,
"RXTX", UUSART_DIRECTION_RXTX, &suc);
}
else if (streq(key, "hw-flow-control")) {
priv->hw_flow_control = (uint8_t) str_parse_4(value,
priv->hw_flow_control = (uint8_t) cfg_enum4_parse(value,
"NONE", 0,
"RTS", 1,
"CTS", 2,
"FULL", 3, &suc);
}
else if (streq(key, "word-width")) {
priv->width = (uint8_t ) avr_atoi(value);
priv->width = cfg_u8_parse(value, &suc);
}
else if (streq(key, "first-bit")) {
priv->lsb_first = (bool)str_parse_2(value, "MSB", 0, "LSB", 1, &suc);
priv->lsb_first = (bool) cfg_enum2_parse(value, "MSB", 0, "LSB", 1, &suc);
}
else if (streq(key, "clock-output")) {
priv->clock_output = str_parse_yn(value, &suc);
priv->clock_output = cfg_bool_parse(value, &suc);
}
else if (streq(key, "cpol")) {
priv->cpol = (bool) avr_atoi(value);
priv->cpol = cfg_bool_parse(value, &suc);
}
else if (streq(key, "cpha")) {
priv->cpha = (bool) avr_atoi(value);
priv->cpha = cfg_bool_parse(value, &suc);
}
else if (streq(key, "de-output")) {
priv->de_output = str_parse_yn(value, &suc);
priv->de_output = cfg_bool_parse(value, &suc);
}
else if (streq(key, "de-polarity")) {
priv->de_polarity = (bool) avr_atoi(value);
priv->de_polarity = cfg_bool_parse(value, &suc);
}
else if (streq(key, "de-assert-time")) {
priv->de_assert_time = (uint8_t) avr_atoi(value);
priv->de_assert_time = cfg_u8_parse(value, &suc);
}
else if (streq(key, "de-clear-time")) {
priv->de_clear_time = (uint8_t) avr_atoi(value);
priv->de_clear_time = cfg_u8_parse(value, &suc);
}
else {
return E_BAD_KEY;
@@ -156,7 +156,7 @@ void UUSART_writeIni(Unit *unit, IniWriter *iw)
struct priv *priv = unit->data;
iw_comment(iw, "Peripheral number (UARTx 1-4)");
iw_entry(iw, "device", "%d", (int)priv->periph_num);
iw_entry_d(iw, "device", priv->periph_num);
iw_comment(iw, "Pin mappings (TX,RX,CK,CTS,RTS/DE)");
#if GEX_PLAT_F072_DISCOVERY
@@ -173,41 +173,41 @@ void UUSART_writeIni(Unit *unit, IniWriter *iw)
#else
#error "BAD PLATFORM!"
#endif
iw_entry(iw, "remap", "%d", (int)priv->remap);
iw_entry_d(iw, "remap", priv->remap);
iw_cmt_newline(iw);
iw_comment(iw, "Baud rate in bps (eg. 9600, 115200)"); // TODO examples/range
iw_entry(iw, "baud-rate", "%d", (int)priv->baudrate);
iw_comment(iw, "Baud rate in bps (eg. 9600)");
iw_entry_d(iw, "baud-rate", priv->baudrate);
iw_comment(iw, "Parity type (NONE, ODD, EVEN)");
iw_entry(iw, "parity", "%s", str_3(priv->parity,
iw_entry_s(iw, "parity", cfg_enum3_encode(priv->parity,
0, "NONE",
1, "ODD",
2, "EVEN"));
iw_comment(iw, "Number of stop bits (0.5, 1, 1.5, 2)");
iw_entry(iw, "stop-bits", "%s", str_4(priv->stopbits,
iw_entry_s(iw, "stop-bits", cfg_enum4_encode(priv->stopbits,
0, "0.5",
1, "1",
2, "1.5",
3, "2"));
iw_comment(iw, "Bit order (LSB or MSB first)");
iw_entry(iw, "first-bit", str_2((uint32_t)priv->lsb_first,
iw_entry_s(iw, "first-bit", cfg_enum2_encode((uint32_t) priv->lsb_first,
0, "MSB",
1, "LSB"));
iw_comment(iw, "Word width (7,8,9) - including parity bit if used");
iw_entry(iw, "word-width", "%d", (int)priv->width);
iw_entry_d(iw, "word-width", (int)priv->width);
iw_comment(iw, "Enabled lines (RX,TX,RXTX)");
iw_entry(iw, "direction", str_3(priv->direction,
iw_entry_s(iw, "direction", cfg_enum3_encode(priv->direction,
1, "RX",
2, "TX",
3, "RXTX"));
iw_comment(iw, "Hardware flow control (NONE, RTS, CTS, FULL)");
iw_entry(iw, "hw-flow-control", "%s", str_4(priv->hw_flow_control,
iw_entry_s(iw, "hw-flow-control", cfg_enum4_encode(priv->hw_flow_control,
0, "NONE",
1, "RTS",
2, "CTS",
@@ -215,19 +215,19 @@ void UUSART_writeIni(Unit *unit, IniWriter *iw)
iw_cmt_newline(iw);
iw_comment(iw, "Generate serial clock (Y,N)");
iw_entry(iw, "clock-output", str_yn(priv->clock_output));
iw_comment(iw, "Output clock polarity: 0,1 (clock idle level)");
iw_entry(iw, "cpol", "%d", (int)priv->cpol);
iw_comment(iw, "Output clock phase: 0,1 (active edge, 0-first, 1-second)");
iw_entry(iw, "cpha", "%d", (int)priv->cpha);
iw_entry_s(iw, "clock-output", str_yn(priv->clock_output));
iw_comment(iw, "Clock polarity: 0,1");
iw_entry_d(iw, "cpol", priv->cpol);
iw_comment(iw, "Clock phase: 0,1");
iw_entry_d(iw, "cpha", priv->cpha);
iw_cmt_newline(iw);
iw_comment(iw, "Generate RS485 Driver Enable signal (Y,N) - uses RTS pin");
iw_entry(iw, "de-output", str_yn(priv->de_output));
iw_entry_s(iw, "de-output", str_yn(priv->de_output));
iw_comment(iw, "DE active level: 0,1");
iw_entry(iw, "de-polarity", "%d", (int)(priv->de_polarity));
iw_entry_d(iw, "de-polarity", (priv->de_polarity));
iw_comment(iw, "DE assert time (0-31)");
iw_entry(iw, "de-assert-time", "%d", (int)(priv->de_assert_time));
iw_entry_d(iw, "de-assert-time", (priv->de_assert_time));
iw_comment(iw, "DE clear time (0-31)");
iw_entry(iw, "de-clear-time", "%d", (int)(priv->de_clear_time));
iw_entry_d(iw, "de-clear-time", (priv->de_clear_time));
}
-35
View File
@@ -1,35 +0,0 @@
/* Copyright (c) 2002, Marek Michalkiewicz
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include "avrlibc.h"
int
avr_atoi(const char *p)
{
return (int) avr_atol(p);
}
-36
View File
@@ -1,36 +0,0 @@
/* Copyright (c) 2002, Marek Michalkiewicz
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include <stdlib.h>
#include "avrlibc.h"
long
avr_atol(const char *p)
{
return avr_strtol(p, (char **) NULL, 10);
}
+10 -10
View File
@@ -37,10 +37,10 @@
#include <stdint.h>
#include "avrlibc.h"
/* Only GCC 4.2 calls the library function to convert an unsigned long
/* Only GCC 4.2 calls the library function to convert an uint32_t
to float. Other GCC-es (including 4.3) use a signed long to float
conversion along with a large inline code to correct the result. */
extern double __floatunsisf (unsigned long);
extern double __floatunsisf (uint32_t);
static const float pwr_p10 [6] = {
1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32
@@ -84,13 +84,13 @@ double
avr_strtod (const char * nptr, char ** endptr)
{
union {
unsigned long u32;
uint32_t u32;
float flt;
} x;
unsigned char c;
int exp;
char c;
int32_t exp;
unsigned char flag;
uint8_t flag;
#define FL_MINUS 0x01 /* number is negative */
#define FL_ANY 0x02 /* any digit was readed */
#define FL_OVFL 0x04 /* overflow was */
@@ -178,7 +178,7 @@ avr_strtod (const char * nptr, char ** endptr)
do {
if (i < 3200)
i = (((i << 2) + i) << 1) + c; /* i = 10*i + c */
c = *nptr++ - '0';
c = (char) (*nptr++ - '0');
} while (c <= 9);
if (flag & FL_MEXP)
i = -i;
@@ -189,7 +189,7 @@ avr_strtod (const char * nptr, char ** endptr)
if ((flag & FL_ANY) && endptr)
*endptr = (char *)nptr - 1;
x.flt = __floatunsisf (x.u32); /* manually */
x.flt = (float) __floatunsisf (x.u32); /* manually */
if ((flag & FL_MINUS) && (flag & FL_ANY))
x.flt = -x.flt;
@@ -204,7 +204,7 @@ avr_strtod (const char * nptr, char ** endptr)
for (pwr = 32; pwr; pwr >>= 1) {
for (; exp >= pwr; exp -= pwr) {
union {
unsigned long u32;
uint32_t u32;
float flt;
} y;
y.u32 = (uint32_t) *((float *)nptr);
@@ -213,7 +213,7 @@ avr_strtod (const char * nptr, char ** endptr)
nptr -= sizeof(float);
}
if (!isfinite(x.flt) || x.flt == 0)
errno = ERANGE;
avrlibc_errno = ERANGE;
}
return x.flt;
+19 -18
View File
@@ -32,6 +32,7 @@
#include <limits.h>
#include <errno.h>
#include "avrlibc.h"
/*
* Convert a string to a long integer.
@@ -39,14 +40,14 @@
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
long
avr_strtol(const char *nptr, char **endptr, register int base)
int32_t
avr_strtol(const char *nptr, char **endptr, register int32_t base)
{
register unsigned long acc;
register unsigned char c;
register unsigned long cutoff;
register signed char any;
unsigned char flag = 0;
register uint32_t acc;
register char c;
register uint32_t cutoff;
register int8_t any;
uint8_t flag = 0;
#define FL_NEG 0x01 /* number is negative */
#define FL_0X 0x02 /* number has a 0x prefix */
@@ -105,24 +106,24 @@ avr_strtol(const char *nptr, char **endptr, register int base)
* Set any if any `digits' consumed; make it negative to indicate
* overflow.
*/
#if LONG_MIN != -LONG_MAX - 1
#if INT32_MIN != -INT32_MAX - 1
# error "This implementation of strtol() does not work on this platform."
#endif
switch (base) {
case 10:
cutoff = ((unsigned long)LONG_MAX + 1) / 10;
cutoff = ((uint32_t)INT32_MAX + 1) / 10;
break;
case 16:
cutoff = ((unsigned long)LONG_MAX + 1) / 16;
cutoff = ((uint32_t)INT32_MAX + 1) / 16;
break;
case 8:
cutoff = ((unsigned long)LONG_MAX + 1) / 8;
cutoff = ((uint32_t)INT32_MAX + 1) / 8;
break;
case 2:
cutoff = ((unsigned long)LONG_MAX + 1) / 2;
cutoff = ((uint32_t)INT32_MAX + 1) / 2;
break;
default:
cutoff = ((unsigned long)LONG_MAX + 1) / base;
cutoff = ((uint32_t)INT32_MAX + 1) / base;
}
for (acc = 0, any = 0;; c = *nptr++) {
@@ -143,7 +144,7 @@ avr_strtol(const char *nptr, char **endptr, register int base)
continue;
}
acc = acc * base + c;
if (acc > (unsigned long)LONG_MAX + 1)
if (acc > (uint32_t)INT32_MAX + 1)
any = -1;
else
any = 1;
@@ -155,13 +156,13 @@ avr_strtol(const char *nptr, char **endptr, register int base)
*endptr = (char *)nptr - 2;
}
if (any < 0) {
acc = (flag & FL_NEG) ? LONG_MIN : LONG_MAX;
errno = ERANGE;
acc = (flag & FL_NEG) ? INT32_MIN : INT32_MAX;
avrlibc_errno = ERANGE;
} else if (flag & FL_NEG) {
acc = -acc;
} else if ((signed long)acc < 0) {
acc = LONG_MAX;
errno = ERANGE;
acc = INT32_MAX;
avrlibc_errno = ERANGE;
}
return (acc);
}
+15 -15
View File
@@ -35,18 +35,18 @@
#include "avrlibc.h"
/*
* Convert a string to an unsigned long integer.
* Convert a string to an uint32_t integer.
*
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
unsigned long
avr_strtoul(const char *nptr, char **endptr, register int base)
uint32_t
avr_strtoul(const char *nptr, char **endptr, register int32_t base)
{
register unsigned long acc;
register unsigned char c;
register unsigned long cutoff;
register signed char any;
register uint32_t acc;
register char c;
register uint32_t cutoff;
register int8_t any;
unsigned char flag = 0;
#define FL_NEG 0x01 /* number is negative */
#define FL_0X 0x02 /* number has a 0x prefix */
@@ -102,10 +102,10 @@ avr_strtoul(const char *nptr, char **endptr, register int base)
*
*/
switch (base) {
case 16: cutoff = ULONG_MAX / 16; break;
case 10: cutoff = ULONG_MAX / 10; break;
case 8: cutoff = ULONG_MAX / 8; break;
default: cutoff = ULONG_MAX / base;
case 16: cutoff = UINT32_MAX / 16; break;
case 10: cutoff = UINT32_MAX / 10; break;
case 8: cutoff = UINT32_MAX / 8; break;
default: cutoff = UINT32_MAX / base;
}
for (acc = 0, any = 0;; c = *nptr++) {
@@ -126,7 +126,7 @@ avr_strtoul(const char *nptr, char **endptr, register int base)
continue;
}
acc = acc * base + c;
any = (c > acc) ? -1 : 1;
any = (int8_t) ((c > acc) ? -1 : 1);
}
if (endptr) {
@@ -138,8 +138,8 @@ avr_strtoul(const char *nptr, char **endptr, register int base)
if (flag & FL_NEG)
acc = -acc;
if (any < 0) {
acc = ULONG_MAX;
errno = ERANGE;
acc = UINT32_MAX;
avrlibc_errno = ERANGE;
}
return (acc);
return (uint32_t) (acc);
}
+7
View File
@@ -0,0 +1,7 @@
//
// Created by MightyPork on 2018/02/23.
//
#include <stdint.h>
volatile int32_t avrlibc_errno = 0;
+36 -25
View File
@@ -8,21 +8,10 @@
#ifndef GEX_AVRLIBC_H_H
#define GEX_AVRLIBC_H_H
/**
* atoi() - parse decimal int from ASCII
*
* @param p - string
* @return int, 0 on failure
*/
int avr_atoi(const char *p);
#include <stdint.h>
#include <stddef.h>
/**
* atol() - parse decimal long int from ASCII
*
* @param p - string
* @return int, 0 on failure
*/
long avr_atol(const char *p);
extern volatile int32_t avrlibc_errno;
/**
* strtol() - parse integer number form string.
@@ -35,7 +24,39 @@ long avr_atol(const char *p);
* @param base - base 2, 10, 16.... 0 for auto
* @return the number
*/
long avr_strtol(const char *nptr, char **endptr, register int base);
int32_t avr_strtol(const char *nptr, char **endptr, register int32_t base);
/**
* like strtol(), but unsigned (and hence higher max value)
*
* @param nptr - string to parse
* @param endptr - NULL or pointer to string where the end will be stored (first bad char)
* @param base - base 2, 10, 16.... 0 for auto
* @return the number
*/
uint32_t avr_strtoul(const char *nptr, char **endptr, register int32_t base);
/**
* atol() - parse decimal long int from ASCII
*
* @param p - string
* @return int, 0 on failure
*/
static inline int32_t avr_atol(const char *p)
{
return avr_strtol(p, (char **) NULL, 10);
}
/**
* atoi() - parse decimal int from ASCII
*
* @param p - string
* @return int, 0 on failure
*/
static inline int32_t avr_atoi(const char *p)
{
return avr_atol(p);
}
/**
* Parse double from ASCII
@@ -46,14 +67,4 @@ long avr_strtol(const char *nptr, char **endptr, register int base);
*/
double avr_strtod (const char * nptr, char ** endptr);
/**
* like strtol(), but unsigned (and hence higher max value)
*
* @param nptr - string to parse
* @param endptr - NULL or pointer to string where the end will be stored (first bad char)
* @param base - base 2, 10, 16.... 0 for auto
* @return the number
*/
unsigned long avr_strtoul(const char *nptr, char **endptr, register int base);
#endif //GEX_AVRLIBC_H_H
+1
View File
@@ -28,6 +28,7 @@
X(CHECKSUM_MISMATCH, NULL) /* bus checksum failed */ \
X(PROTOCOL_BREACH, NULL) /* eating with the wrong spoon */ \
X(BUSY, NULL) /* Unit is busy */ \
X(BAD_MODE, NULL) /* Command not permissible in current opmode */ \
\
/* VFS user errors (those are meant to be shown to user) */ \
X(VFS_ERROR_DURING_TRANSFER, "Error during transfer") \
+109 -500
View File
@@ -1,526 +1,135 @@
/* #line 1 "ini_parser.rl" */
/* Ragel constants block */
#include "ini_parser.h"
// Ragel setup
/* #line 10 "ini_parser.c" */
static const char _ini_actions[] = {
0, 1, 1, 1, 2, 1, 3, 1,
4, 1, 5, 1, 6, 1, 7, 1,
8, 1, 9, 1, 10, 1, 11, 1,
13, 2, 0, 4, 2, 12, 4
enum nini_state {
NINI_IDLE,
NINI_SECTION,
NINI_KEY,
NINI_VALUE,
NINI_COMMENT,
};
static const char _ini_eof_actions[] = {
0, 23, 5, 5, 15, 15, 15, 15,
19, 19, 0, 0, 0, 0, 0, 0,
0
};
static struct {
uint8_t section_i;
char section[INI_KEY_MAX];
static const int ini_start = 1;
static const int ini_first_final = 12;
static const int ini_error = 0;
uint8_t key_i;
char key[INI_KEY_MAX];
static const int ini_en_section = 2;
static const int ini_en_keyvalue = 4;
static const int ini_en_comment = 8;
static const int ini_en_discard2eol = 10;
static const int ini_en_main = 1;
uint8_t value_i;
char value[INI_VALUE_MAX];
bool val_last_space;
IniParserCallback cb;
void *userdata;
enum nini_state state;
} nini;
/* #line 10 "ini_parser.rl" */
// Persistent state
static int8_t cs = -1; //!< Ragel's Current State variable
static uint32_t buff_i = 0; //!< Write pointer for the buffers
static char value_quote = 0; //!< Quote character of the currently collected value
static bool value_nextesc = false; //!< Next character is escaped, trated specially, and if quote, as literal quote character
static IniParserCallback keyCallback = NULL; //!< Currently assigned callback
static void *userdata = NULL; //!< Currently assigned user data for the callback
// Buffers
static char keybuf[INI_KEY_MAX];
static char secbuf[INI_KEY_MAX+10];
static char valbuf[INI_VALUE_MAX];
// See header for doxygen!
void
ini_parse_reset_partial(void)
void ini_parse_begin(IniParserCallback callback, void *userData)
{
buff_i = 0;
value_quote = 0;
value_nextesc = false;
}
void
ini_parse_reset(void)
{
ini_parse_reset_partial();
keybuf[0] = secbuf[0] = valbuf[0] = 0;
/* #line 67 "ini_parser.c" */
{
cs = ini_start;
}
/* #line 41 "ini_parser.rl" */
}
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();
nini.cb = callback;
nini.userdata = userData;
}
void
*ini_parse_end(void)
void ini_parse(const char *data, size_t len)
{
ini_parse("\n", 1);
if (keyCallback) {
keyCallback = NULL;
for (; len > 0; len--) {
char c = *data++;
if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
if (nini.state != NINI_VALUE && nini.state != NINI_COMMENT)
continue;
}
void *ud = userdata;
userdata = NULL;
return ud;
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
ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData)
void *ini_parse_end(void)
{
if (nini.state == NINI_VALUE) {
nini.value[nini.value_i] = 0;
nini.state = NINI_IDLE;
nini.cb(nini.section, nini.key, nini.value, nini.userdata);
}
return nini.userdata;
}
void ini_parse_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)
void ini_parse_reset(void)
{
if (end > 0) {
while ((uint8_t)buf[--end] < 33);
end++; // go past the last character
}
buf[end] = 0;
}
void
ini_parse(const char *newstr, size_t len)
{
int32_t i;
char c;
bool isnl;
bool isquot;
// Load new data to Ragel vars
const uint8_t *p;
const uint8_t *eof;
const uint8_t *pe;
if (len == 0) while(newstr[++len] != 0); // alternative to strlen
p = (const uint8_t *) newstr;
eof = NULL;
pe = (const uint8_t *) (newstr + len);
// Init Ragel on the first run
if (cs == -1) {
ini_parse_reset();
}
// The parser
/* #line 152 "ini_parser.c" */
{
const char *_acts;
unsigned int _nacts;
if ( p == pe )
goto _test_eof;
if ( cs == 0 )
goto _out;
_resume:
switch ( cs ) {
case 1:
switch( (*p) ) {
case 32u: goto tr1;
case 35u: goto tr3;
case 58u: goto tr0;
case 59u: goto tr3;
case 61u: goto tr0;
case 91u: goto tr4;
}
if ( (*p) < 9u ) {
if ( (*p) <= 8u )
goto tr0;
} else if ( (*p) > 13u ) {
if ( 14u <= (*p) && (*p) <= 31u )
goto tr0;
} else
goto tr1;
goto tr2;
case 0:
goto _out;
case 12:
goto tr0;
case 2:
switch( (*p) ) {
case 9u: goto tr6;
case 32u: goto tr6;
case 93u: goto tr5;
}
if ( (*p) <= 31u )
goto tr5;
goto tr7;
case 3:
if ( (*p) == 93u )
goto tr8;
if ( (*p) > 8u ) {
if ( 10u <= (*p) && (*p) <= 31u )
goto tr5;
} else
goto tr5;
goto tr7;
case 13:
goto tr5;
case 4:
switch( (*p) ) {
case 10u: goto tr10;
case 58u: goto tr11;
case 61u: goto tr11;
}
goto tr9;
case 5:
switch( (*p) ) {
case 9u: goto tr13;
case 10u: goto tr14;
case 13u: goto tr15;
case 32u: goto tr13;
}
goto tr12;
case 6:
switch( (*p) ) {
case 10u: goto tr14;
case 13u: goto tr15;
}
goto tr12;
case 14:
goto tr10;
case 7:
if ( (*p) == 10u )
goto tr14;
goto tr10;
case 8:
switch( (*p) ) {
case 10u: goto tr17;
case 13u: goto tr18;
}
goto tr16;
case 15:
goto tr19;
case 9:
if ( (*p) == 10u )
goto tr17;
goto tr19;
case 10:
switch( (*p) ) {
case 10u: goto tr21;
case 13u: goto tr22;
}
goto tr20;
case 16:
goto tr23;
case 11:
if ( (*p) == 10u )
goto tr21;
goto tr23;
}
tr23: cs = 0; goto _again;
tr0: cs = 0; goto f0;
tr5: cs = 0; goto f4;
tr10: cs = 0; goto f7;
tr19: cs = 0; goto f11;
tr1: cs = 1; goto _again;
tr6: cs = 2; goto _again;
tr7: cs = 3; goto f5;
tr9: cs = 4; goto f8;
tr13: cs = 5; goto _again;
tr11: cs = 5; goto f9;
tr12: cs = 6; goto f10;
tr15: cs = 7; goto _again;
tr16: cs = 8; goto _again;
tr18: cs = 9; goto _again;
tr20: cs = 10; goto _again;
tr22: cs = 11; goto _again;
tr2: cs = 12; goto f1;
tr3: cs = 12; goto f2;
tr4: cs = 12; goto f3;
tr8: cs = 13; goto f6;
tr14: cs = 14; goto f10;
tr17: cs = 15; goto f12;
tr21: cs = 16; goto f13;
f5: _acts = _ini_actions + 1; goto execFuncs;
f6: _acts = _ini_actions + 3; goto execFuncs;
f4: _acts = _ini_actions + 5; goto execFuncs;
f1: _acts = _ini_actions + 7; goto execFuncs;
f8: _acts = _ini_actions + 9; goto execFuncs;
f9: _acts = _ini_actions + 11; goto execFuncs;
f10: _acts = _ini_actions + 13; goto execFuncs;
f7: _acts = _ini_actions + 15; goto execFuncs;
f12: _acts = _ini_actions + 17; goto execFuncs;
f11: _acts = _ini_actions + 19; goto execFuncs;
f13: _acts = _ini_actions + 21; goto execFuncs;
f0: _acts = _ini_actions + 23; goto execFuncs;
f3: _acts = _ini_actions + 25; goto execFuncs;
f2: _acts = _ini_actions + 28; goto execFuncs;
execFuncs:
_nacts = *_acts++;
while ( _nacts-- > 0 ) {
switch ( *_acts++ ) {
case 0:
/* #line 130 "ini_parser.rl" */
{
buff_i = 0;
{cs = 2;goto _again;}
}
break;
case 1:
/* #line 135 "ini_parser.rl" */
{
if (buff_i >= INI_KEY_MAX) {
ini_parser_error("Section name too long");
{cs = 10;goto _again;}
}
keybuf[buff_i++] = (*p);
}
break;
case 2:
/* #line 143 "ini_parser.rl" */
{
// we need a separate buffer for the result, otherwise a failed
// partial parse would corrupt the section string
rtrim_buf(keybuf, buff_i);
for (i = 0; (c = keybuf[i]) != 0; i++) secbuf[i] = c;
secbuf[i] = 0;
{cs = 1;goto _again;}
}
break;
case 3:
/* #line 155 "ini_parser.rl" */
{
ini_parser_error("Syntax error in [section]");
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
}
break;
case 4:
/* #line 162 "ini_parser.rl" */
{
buff_i = 0;
keybuf[buff_i++] = (*p); // add the first char
{cs = 4;goto _again;}
}
break;
case 5:
/* #line 168 "ini_parser.rl" */
{
if (buff_i >= INI_KEY_MAX) {
ini_parser_error("Key too long");
{cs = 10;goto _again;}
}
keybuf[buff_i++] = (*p);
}
break;
case 6:
/* #line 176 "ini_parser.rl" */
{
rtrim_buf(keybuf, buff_i);
// --- Value begin ---
buff_i = 0;
value_quote = 0;
value_nextesc = false;
}
break;
case 7:
/* #line 185 "ini_parser.rl" */
{
isnl = ((*p) == '\r' || (*p) == '\n');
isquot = ((*p) == '\'' || (*p) == '"');
// detect our starting quote
if (isquot && !value_nextesc && buff_i == 0 && value_quote == 0) {
value_quote = (*p);
goto valueCharDone;
}
if (buff_i >= INI_VALUE_MAX) {
ini_parser_error("Value too long");
{cs = 10;goto _again;}
}
// end of string - clean up and report
if ((!value_nextesc && (*p) == value_quote) || isnl) {
if (isnl && value_quote) {
ini_parser_error("Unterminated string");
{cs = 1;goto _again;}
}
// unquoted: trim from the end
if (!value_quote) {
rtrim_buf(valbuf, buff_i);
} else {
valbuf[buff_i] = 0;
}
if (keyCallback) {
keyCallback(secbuf, keybuf, valbuf, userdata);
}
// we don't want to discard to eol if the string was terminated by eol
// - would delete the next line
if (isnl) {cs = 1;goto _again;} else {cs = 10;goto _again;}
}
c = (*p);
// escape...
if (value_nextesc) {
if ((*p) == 'n') c = '\n';
else if ((*p) == 'r') c = '\r';
else if ((*p) == 't') c = '\t';
else if ((*p) == 'e') c = '\033';
}
// collecting characters...
if (value_nextesc || (*p) != '\\') { // is quoted, or is not a quoting backslash - literal character
valbuf[buff_i++] = c;
}
value_nextesc = (!value_nextesc && (*p) == '\\');
valueCharDone:;
}
break;
case 8:
/* #line 247 "ini_parser.rl" */
{
ini_parser_error("Syntax error in key=value");
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
}
break;
case 9:
/* #line 257 "ini_parser.rl" */
{ {cs = 1;goto _again;} }
break;
case 10:
/* #line 258 "ini_parser.rl" */
{
ini_parser_error("Syntax error in comment");
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
}
break;
case 11:
/* #line 265 "ini_parser.rl" */
{ {cs = 1;goto _again;} }
break;
case 12:
/* #line 273 "ini_parser.rl" */
{ {cs = 8;goto _again;} }
break;
case 13:
/* #line 276 "ini_parser.rl" */
{
ini_parser_error("Syntax error in root");
{cs = 10;goto _again;}
}
break;
/* #line 458 "ini_parser.c" */
}
}
goto _again;
_again:
if ( cs == 0 )
goto _out;
if ( ++p != pe )
goto _resume;
_test_eof: {}
if ( p == eof )
{
const char *__acts = _ini_actions + _ini_eof_actions[cs];
unsigned int __nacts = (unsigned int) *__acts++;
while ( __nacts-- > 0 ) {
switch ( *__acts++ ) {
case 3:
/* #line 155 "ini_parser.rl" */
{
ini_parser_error("Syntax error in [section]");
if((*p) == '\n') {cs = 1; if ( p == pe )
goto _test_eof;
goto _again;} else {cs = 10; if ( p == pe )
goto _test_eof;
goto _again;}
}
break;
case 8:
/* #line 247 "ini_parser.rl" */
{
ini_parser_error("Syntax error in key=value");
if((*p) == '\n') {cs = 1; if ( p == pe )
goto _test_eof;
goto _again;} else {cs = 10; if ( p == pe )
goto _test_eof;
goto _again;}
}
break;
case 10:
/* #line 258 "ini_parser.rl" */
{
ini_parser_error("Syntax error in comment");
if((*p) == '\n') {cs = 1; if ( p == pe )
goto _test_eof;
goto _again;} else {cs = 10; if ( p == pe )
goto _test_eof;
goto _again;}
}
break;
case 13:
/* #line 276 "ini_parser.rl" */
{
ini_parser_error("Syntax error in root");
{cs = 10; if ( p == pe )
goto _test_eof;
goto _again;}
}
break;
/* #line 517 "ini_parser.c" */
}
}
}
_out: {}
}
/* #line 283 "ini_parser.rl" */
nini.state = NINI_IDLE;
}
+1 -9
View File
@@ -1,6 +1,5 @@
//
// INI file parser with a FSM generated by Ragel. This was originally written for ESPTerm
// Used to extract sections, keys and values from user-provided settings file
// INI file parser. Used to extract sections, keys and values from user-provided settings file
//
#ifndef INIPARSE_STREAM_H
@@ -8,13 +7,6 @@
#include "platform.h"
// toggleable logging func
#ifdef DEBUG_INI
#define ini_error(fmt, ...) dbg("! INI err: "#fmt, ##__VA_ARGS__)
#else
#define ini_error(fmt, ...)
#endif
// buffer sizes
//#define INI_KEY_MAX 20
//#define INI_VALUE_MAX 30 // moved to plat_compat.h
-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
}
void iw_entry_s(IniWriter *iw, const char *key, const char *value)
{
if (iw->count == 0) return;
iw_string(iw, key);
iw_string(iw, "=");
iw_string(iw, value);
iw_newline(iw);
}
void iw_entry_d(IniWriter *iw, const char *key, int32_t value)
{
if (iw->count == 0) return;
iw_string(iw, key);
iw_string(iw, "=");
uint32_t len = (int)fixup_snprintf(&iwbuffer[0], IWBUFFER_LEN, "%d", value);
iw_buff(iw, (uint8_t *) iwbuffer, len);
iw_newline(iw);
}
uint32_t iw_measure_total(void (*handler)(IniWriter *), uint32_t tag)
{
IniWriter iw = iw_init(NULL, 0xFFFFFFFF, 1);
+3
View File
@@ -126,6 +126,9 @@ __attribute__((format(printf,2,3)));
void iw_entry(IniWriter *iw, const char *key, const char *format, ...)
__attribute__((format(printf,3,4)));
void iw_entry_s(IniWriter *iw, const char *key, const char *value);
void iw_entry_d(IniWriter *iw, const char *key, int32_t value);
/**
* Measure total ini writer length using a dummy write
*
+10 -20
View File
@@ -1,3 +1,4 @@
#include <debug.h>
#include "payload_parser.h"
#define pp_check_capacity(pp, needed) \
@@ -58,32 +59,21 @@ uint32_t pp_u32(PayloadParser *pp)
uint64_t pp_u64(PayloadParser *pp)
{
pp_check_capacity(pp, 4);
pp_check_capacity(pp, 8);
if (!pp->ok) return 0;
uint64_t x = 0;
uint32_t x0, x1;
uint64_t x;
if (pp->bigendian) {
x |= (uint64_t) ((uint64_t) *pp->current++ << 56);
x |= (uint64_t) ((uint64_t) *pp->current++ << 48);
x |= (uint64_t) ((uint64_t) *pp->current++ << 40);
x |= (uint64_t) ((uint64_t) *pp->current++ << 32);
x |= (uint64_t) (*pp->current++ << 24);
x |= (uint64_t) (*pp->current++ << 16);
x |= (uint64_t) (*pp->current++ << 8);
x |= *pp->current++;
x1 = pp_u32(pp);
x0 = pp_u32(pp);
} else {
x |= *pp->current++;
x |= (uint64_t) (*pp->current++ << 8);
x |= (uint64_t) (*pp->current++ << 16);
x |= (uint64_t) (*pp->current++ << 24);
x |= (uint64_t) ((uint64_t) *pp->current++ << 32);
x |= (uint64_t) ((uint64_t) *pp->current++ << 40);
x |= (uint64_t) ((uint64_t) *pp->current++ << 48);
x |= (uint64_t) ((uint64_t) *pp->current++ << 56);
x0 = pp_u32(pp);
x1 = pp_u32(pp);
}
x = ((uint64_t)x1)<<32 | x0;
return x;
}
+1 -1
View File
@@ -190,7 +190,7 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
{
char ch;
LLONG value;
LDOUBLE fvalue;
LDOUBLE fvalue = 0;
char *strvalue;
int min;
int max;
-107
View File
@@ -5,110 +5,3 @@
#include "str_utils.h"
#include "platform.h"
#include "avrlibc.h"
bool str_parse_yn(const char *str, bool *suc)
{
// TODO implement strcasecmp without the locale crap from newlib and use it here
if (streq(str, "Y")) return true;
if (streq(str, "N")) return false;
if (streq(str, "1")) return true;
if (streq(str, "0")) return false;
if (streq(str, "YES")) return true;
if (streq(str, "NO")) return false;
*suc = false;
return false;
}
uint8_t str_parse_01(const char *str, const char *a, const char *b, bool *suc)
{
if (streq(str, a)) return 0;
if (streq(str, b)) return 1;
*suc = false;
return 0;
}
uint8_t str_parse_012(const char *str, const char *a, const char *b, const char *c, bool *suc)
{
if (streq(str, a)) return 0;
if (streq(str, b)) return 1;
if (streq(str, c)) return 2;
*suc = false;
return 0;
}
/** Convert number to one of 2 options */
const char *str_2(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b)
{
if (n == nb) return b;
return a;
}
/** Convert number to one of 3 options */
const char *str_3(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b,
uint32_t nc, const char *c)
{
if (n == nb) return b;
if (n == nc) return c;
return a;
}
/** Convert number to one of 4 options */
const char *str_4(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b,
uint32_t nc, const char *c,
uint32_t nd, const char *d)
{
if (n == nb) return b;
if (n == nc) return c;
if (n == nd) return d;
return a;
}
uint32_t str_parse_2(const char *tpl,
const char *a, uint32_t na,
const char *b, uint32_t nb,
bool *suc)
{
if (streq(tpl, a)) return na;
if (streq(tpl, b)) return nb;
*suc = false;
return na;
}
uint32_t str_parse_3(const char *tpl,
const char *a, uint32_t na,
const char *b, uint32_t nb,
const char *c, uint32_t nc,
bool *suc)
{
if (streq(tpl, a)) return na;
if (streq(tpl, b)) return nb;
if (streq(tpl, c)) return nc;
*suc = false;
return na;
}
uint32_t str_parse_4(const char *tpl,
const char *a, uint32_t na,
const char *b, uint32_t nb,
const char *c, uint32_t nc,
const char *d, uint32_t nd,
bool *suc)
{
if (streq(tpl, a)) return na;
if (streq(tpl, b)) return nb;
if (streq(tpl, c)) return nc;
if (streq(tpl, d)) return nd;
*suc = false;
return na;
}
-51
View File
@@ -103,55 +103,4 @@ last_char(const char *str)
return str[strlen(str) - 1];
}
/** Parse Y/N to bool */
bool str_parse_yn(const char *str, bool *suc);
/** Compare string with two options */
uint8_t str_parse_01(const char *str, const char *a, const char *b, bool *suc);
/** Compare string with three options */
uint8_t str_parse_012(const char *str, const char *a, const char *b, const char *c, bool *suc);
/** Convert number to one of 4 options */
const char *str_2(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b);
/** Convert number to one of 4 options */
const char *str_3(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b,
uint32_t nc, const char *c);
/** Convert number to one of 4 options */
const char *str_4(uint32_t n,
uint32_t na, const char *a,
uint32_t nb, const char *b,
uint32_t nc, const char *c,
uint32_t nd, const char *d);
/** Convert string to one of two numeric options */
uint32_t str_parse_2(const char *tpl,
const char *a, uint32_t na,
const char *b, uint32_t nb,
bool *suc);
/** Convert string to one of three numeric options */
uint32_t str_parse_3(const char *tpl,
const char *a, uint32_t na,
const char *b, uint32_t nb,
const char *c, uint32_t nc,
bool *suc);
/** Convert string to one of four numeric options */
uint32_t str_parse_4(const char *tpl,
const char *a, uint32_t na,
const char *b, uint32_t nb,
const char *c, uint32_t nc,
const char *d, uint32_t nd,
bool *suc);
/** Convert bool to a Y or N constant string */
#define str_yn(cond) ((cond) ? ("Y") : ("N"))
#endif
+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)
{
dbg("Rebuilding VFS...");
vfs_printf("Rebuilding VFS...");
// Setup the filesystem based on target parameters
vfs_init(daplink_drive_name, 0/*unused "disk size"*/);