22 Commits
Author SHA1 Message Date
MightyPork e5a2b2ed45 everything is bad 2018-03-04 21:56:36 +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
88 changed files with 2662 additions and 2314 deletions
+2 -1
View File
@@ -109,8 +109,9 @@ extern uint32_t SystemCoreClock;
#define configQUEUE_REGISTRY_SIZE 0
#define configCHECK_FOR_STACK_OVERFLOW 2
#define configENABLE_BACKWARD_COMPATIBILITY 0
#define configUSE_COUNTING_SEMAPHORES 1
#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
+9 -1
View File
@@ -4,6 +4,7 @@
// TinyFrame integration
//
#include <USB/usb_device.h>
#include "platform.h"
#include "task_main.h"
@@ -26,7 +27,14 @@ 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));
HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) "AAAAHELLODOLLY123", 17);
// 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;
@@ -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 */
+2
View File
@@ -313,6 +313,8 @@ void USBD_CDC_TransmitDone(USBD_HandleTypeDef *pdev)
assert_param(semVcomTxReadyHandle != NULL);
assert_param(inIRQ());
// if (uxSemaphoreGetCount(semVcomTxReadyHandle) == 2) return;
portBASE_TYPE taskWoken = pdFALSE;
assert_param(xSemaphoreGiveFromISR(semVcomTxReadyHandle, &taskWoken) == pdTRUE);
portYIELD_FROM_ISR(taskWoken);
+22 -3
View File
@@ -47,12 +47,13 @@
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <utils/malloc_safe.h>
#include <platform/hw_utils.h>
#include "platform.h"
#include "usbd_def.h"
#include "usbd_core.h"
#include "usbd_msc.h"
#include "usbd_cdc.h"
#include "utils/malloc_safe.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
@@ -335,6 +336,9 @@ void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd)
* @param pdev: Device handle
* @retval USBD Status
*/
extern void PCD_WritePMA(USB_TypeDef *USBx, uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes);
USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev)
{
#if PLAT_USB_OTGFS
@@ -397,12 +401,27 @@ USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev)
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , MSC_EPOUT_ADDR , PCD_SNG_BUF, ptr += 64); // 64
// CDC endpoints, EP2 two-way and EP3 in-only
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP , PCD_SNG_BUF, ptr += 64); // 64
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_OUT_EP , PCD_SNG_BUF, ptr += 64); // 64
uint32_t buf1addr, buf2addr;
buf1addr = (ptr += 64);
buf2addr = (ptr += 64);
uint32_t addr_begin = buf1addr;
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP , PCD_DBL_BUF, buf1addr | (buf2addr << 16)); // 64
buf1addr = (ptr += 64);
buf2addr = (ptr += 64);
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_OUT_EP , PCD_DBL_BUF, buf1addr | (buf2addr << 16)); // 64
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_CMD_EP , PCD_SNG_BUF, ptr += 16); // 16
(void)ptr;
#endif
const uint8_t buf[256] = {};
PCD_WritePMA(((PCD_HandleTypeDef*)pdev->pData)->Instance, (uint8_t *) &buf[0], (uint16_t) addr_begin, 256);
hw_configure_sparse_pins('B', 0b111, NULL, LL_GPIO_MODE_OUTPUT, LL_GPIO_OUTPUT_PUSHPULL);
return USBD_OK;
}
+1 -1
View File
@@ -99,7 +99,7 @@
#define CDC_CUSTOM_EPS
#define CDC_IN_EP 0x82 /* EP1 for data IN */
#define CDC_OUT_EP 0x02 /* EP1 for data OUT */
#define CDC_OUT_EP 0x04 /* EP1 for data OUT */
#define CDC_CMD_EP 0x83 /* EP2 for CDC commands */
/** @defgroup USBD_Exported_Macros
+5
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"
@@ -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;
}
@@ -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
+44 -28
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];
return rsc_names[rsc - R_EXTI15 - 1];
}
/** 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 -2
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) */
@@ -169,7 +169,7 @@ void MX_FREERTOS_Init(void) {
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
xSemaphoreGive(semVcomTxReadyHandle);
assert_param(pdTRUE == xSemaphoreGive(semVcomTxReadyHandle));
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
+2
View File
@@ -16,6 +16,8 @@ GEX_SRC_DIR = \
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 { \
+10 -1
View File
@@ -69,6 +69,7 @@ static struct callbacks_ {
struct cbslot tim16;
struct cbslot adc1;
struct cbslot tsc;
// XXX add more callbacks here when needed
} callbacks;
@@ -92,7 +93,8 @@ void irqd_init(void)
HAL_NVIC_SetPriority(EXTI2_3_IRQn, 2, 0);
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 2, 0);
// NVIC_EnableIRQ(TSC_IRQn); /*!< Touch Sensing Controller Interrupts */
NVIC_EnableIRQ(TSC_IRQn); /*!< Touch Sensing Controller Interrupts */
HAL_NVIC_SetPriority(TSC_IRQn, 2, 0);
NVIC_EnableIRQ(DMA1_Channel1_IRQn); /*!< DMA1 Channel 1 Interrupt */
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); /*!< DMA1 Channel 2 and Channel 3 Interrupt */
@@ -178,6 +180,8 @@ static struct cbslot *get_slot_for_periph(void *periph)
else if (periph == TIM16) slot = &callbacks.tim16;
// 17 - used by timebase
else if (periph == TSC) slot = &callbacks.tsc;
else if (periph == ADC1) slot = &callbacks.adc1;
else if (periph >= EXTIS[0] && periph <= EXTIS[15]) {
@@ -352,6 +356,11 @@ void ADC1_COMP_IRQHandler(void)
CALL_IRQ_HANDLER(callbacks.adc1);
}
void TSC_IRQHandler(void)
{
CALL_IRQ_HANDLER(callbacks.tsc);
}
// other ISRs...
+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);
+1 -1
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 260 // 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
+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();
}
+7 -3
View File
@@ -2,7 +2,6 @@
// Created by MightyPork on 2017/11/26.
//
#include <units/fcap/unit_fcap.h>
#include "platform.h"
#include "usbd_core.h"
#include "USB/usb_device.h"
@@ -19,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)
@@ -90,6 +92,8 @@ void plat_init_resources(void)
ureg_add_type(&UNIT_ADC);
ureg_add_type(&UNIT_SIPO);
ureg_add_type(&UNIT_FCAP);
ureg_add_type(&UNIT_TOUCH);
ureg_add_type(&UNIT_PWMDIM);
// Free all present resources
{
@@ -98,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);
@@ -154,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,
+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,9 +18,7 @@ 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 */
@@ -28,7 +26,7 @@ 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,
};
+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,15 +20,10 @@ 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 */
@@ -36,7 +31,7 @@ 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));
}
+12 -17
View File
@@ -18,14 +18,11 @@ void UFCAP_loadBinary(Unit *unit, PayloadParser *pp)
priv->conf.signal_pname = pp_char(pp);
priv->conf.signal_pnum = pp_u8(pp);
if (version >= 1) {
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 */
@@ -33,12 +30,10 @@ void UFCAP_writeBinary(Unit *unit, PayloadBuilder *pb)
{
struct priv *priv = unit->data;
pb_u8(pb, 1); // version
pb_u8(pb, 0); // version
pb_char(pb, priv->conf.signal_pname);
pb_u8(pb, priv->conf.signal_pnum);
// V1
pb_bool(pb, priv->conf.active_level);
pb_u8(pb, priv->conf.dfilter);
pb_u8(pb, priv->conf.direct_presc);
@@ -55,22 +50,22 @@ error_t UFCAP_loadIni(Unit *unit, const char *key, const char *value)
struct priv *priv = unit->data;
if (streq(key, "pin")) {
suc = parse_pin(value, &priv->conf.signal_pname, &priv->conf.signal_pnum);
suc = cfg_portpin_parse(value, &priv->conf.signal_pname, &priv->conf.signal_pnum);
}
else if (streq(key, "active-level")) {
priv->conf.active_level = (bool) avr_atoi(value);
priv->conf.active_level = cfg_bool_parse(value, &suc);
}
else if (streq(key, "input-filter")) {
priv->conf.dfilter = (uint8_t) avr_atoi(value);
priv->conf.dfilter = cfg_u8_parse(value, &suc);
}
else if (streq(key, "direct-presc")) {
priv->conf.direct_presc = (uint8_t) avr_atoi(value);
priv->conf.direct_presc = cfg_u8_parse(value, &suc);
}
else if (streq(key, "direct-time")) {
priv->conf.direct_msec = (uint16_t) avr_atoi(value);
priv->conf.direct_msec = cfg_u16_parse(value, &suc);
}
else if (streq(key, "initial-mode")) {
priv->conf.startmode = (enum fcap_opmode) str_parse_4(value,
priv->conf.startmode = (enum fcap_opmode) cfg_enum4_parse(value,
"N", OPMODE_IDLE,
"I", OPMODE_INDIRECT_CONT,
"D", OPMODE_DIRECT_CONT,
@@ -97,20 +92,20 @@ void UFCAP_writeIni(Unit *unit, IniWriter *iw)
iw_cmt_newline(iw);
iw_comment(iw, "Active level or edge (0-low,falling; 1-high,rising)");
iw_entry(iw, "active-level", "%d", (int)priv->conf.active_level);
iw_entry_d(iw, "active-level", priv->conf.active_level);
iw_comment(iw, "Input filtering (0-15)");
iw_entry(iw, "input-filter", "%d", (int)priv->conf.dfilter);
iw_entry_d(iw, "input-filter", priv->conf.dfilter);
iw_comment(iw, "Pulse counter pre-divider (1,2,4,8)");
iw_entry(iw, "direct-presc", "%d", (int)priv->conf.direct_presc);
iw_entry_d(iw, "direct-presc", priv->conf.direct_presc);
iw_comment(iw, "Pulse counting interval (ms)");
iw_entry(iw, "direct-time", "%d", (int)priv->conf.direct_msec);
iw_entry_d(iw, "direct-time", priv->conf.direct_msec);
iw_cmt_newline(iw);
iw_comment(iw, "Mode on startup: N-none, I-indirect, D-direct, F-free count");
iw_entry(iw, "initial-mode", "%s", str_4(priv->conf.startmode,
iw_entry_s(iw, "initial-mode", cfg_enum4_encode(priv->conf.startmode,
OPMODE_IDLE, "N",
OPMODE_INDIRECT_CONT, "I",
OPMODE_DIRECT_CONT, "D",
+11 -14
View File
@@ -20,10 +20,7 @@ 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 */
@@ -31,7 +28,7 @@ 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
+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_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);
}
void
ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *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 *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 str_parse_3(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 str_parse_4(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;
}
-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"*/);