Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cafb54c102
|
||
|
|
7622cf0aaf
|
+1
-1
@@ -110,7 +110,7 @@ extern uint32_t SystemCoreClock;
|
|||||||
#define configCHECK_FOR_STACK_OVERFLOW 2
|
#define configCHECK_FOR_STACK_OVERFLOW 2
|
||||||
#define configENABLE_BACKWARD_COMPATIBILITY 0
|
#define configENABLE_BACKWARD_COMPATIBILITY 0
|
||||||
|
|
||||||
#define configUSE_TIMERS 0
|
#define configUSE_TIMERS 1
|
||||||
#define configTIMER_TASK_PRIORITY TSK_TIMERS_PRIO // above normal
|
#define configTIMER_TASK_PRIORITY TSK_TIMERS_PRIO // above normal
|
||||||
#define configTIMER_TASK_STACK_DEPTH TSK_STACK_TIMERS //128
|
#define configTIMER_TASK_STACK_DEPTH TSK_STACK_TIMERS //128
|
||||||
#define configTIMER_QUEUE_LENGTH 4
|
#define configTIMER_QUEUE_LENGTH 4
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include "task_main.h"
|
#include "task_main.h"
|
||||||
|
|
||||||
#include "USB/usbd_cdc_if.h"
|
#include "USB/usbd_cdc_if.h"
|
||||||
#include "USB/usb_device.h"
|
|
||||||
#include "TinyFrame.h"
|
#include "TinyFrame.h"
|
||||||
|
|
||||||
extern osSemaphoreId semVcomTxReadyHandle;
|
extern osSemaphoreId semVcomTxReadyHandle;
|
||||||
@@ -16,30 +15,6 @@ extern osMutexId mutTinyFrameTxHandle;
|
|||||||
|
|
||||||
void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
|
void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
|
||||||
{
|
{
|
||||||
#if 1
|
|
||||||
const uint32_t real_size = len;
|
|
||||||
|
|
||||||
// Padding to a multiple of 64 bytes - this is supposed to maximize the bulk transfer speed
|
|
||||||
if (len&0x3F) {
|
|
||||||
uint32_t pad = (64 - (len&0x3F));
|
|
||||||
memset((void *) (buff + len), 0, pad);
|
|
||||||
len += pad; // padding to a multiple of 64 (size of the endpoint)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We bypass the USBD driver library's overhead by using the HAL function directly
|
|
||||||
assert_param(HAL_OK == HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) buff, len));
|
|
||||||
|
|
||||||
// The buffer is the TF transmit buffer, we can't leave it to work asynchronously because
|
|
||||||
// the next call could modify it before it's been transmitted (in the case of a chunked / multi-part frame)
|
|
||||||
|
|
||||||
// the assumption here is that all until the last chunk use the full buffer capacity
|
|
||||||
if (real_size == TF_SENDBUF_LEN) {
|
|
||||||
if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 100)) {
|
|
||||||
TF_Error("Tx stalled in WriteImpl");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
(void) tf;
|
(void) tf;
|
||||||
#define CHUNK 64 // same as TF_SENDBUF_LEN, so we should always have only one run of the loop
|
#define CHUNK 64 // same as TF_SENDBUF_LEN, so we should always have only one run of the loop
|
||||||
int32_t total = (int32_t) len;
|
int32_t total = (int32_t) len;
|
||||||
@@ -51,36 +26,21 @@ void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const uint16_t chunksize = (uint16_t) MIN(total, CHUNK);
|
const uint16_t chunksize = (uint16_t) MIN(total, CHUNK);
|
||||||
|
assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, chunksize));
|
||||||
// this is an attempt to speed it up a little by removing a couple levels of indirection
|
|
||||||
assert_param(HAL_OK == HAL_PCD_EP_Transmit(hUsbDeviceFS.pData, CDC_IN_EP, (uint8_t *) buff, chunksize));
|
|
||||||
|
|
||||||
// USBD_LL_Transmit(&hUsbDeviceFS, CDC_IN_EP, (uint8_t *) buff, chunksize);
|
|
||||||
// assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, chunksize));
|
|
||||||
|
|
||||||
buff += chunksize;
|
buff += chunksize;
|
||||||
total -= chunksize;
|
total -= chunksize;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Claim the TX interface before composing and sending a frame */
|
/** Claim the TX interface before composing and sending a frame */
|
||||||
bool TF_ClaimTx(TinyFrame *tf)
|
bool TF_ClaimTx(TinyFrame *tf)
|
||||||
{
|
{
|
||||||
(void) tf;
|
(void) tf;
|
||||||
// assert_param(!inIRQ()); // useless delay
|
// assert_param(osThreadGetId() != tskMainHandle);
|
||||||
assert_param(pdTRUE == xSemaphoreTake(mutTinyFrameTxHandle, 5000)); // trips the wd
|
assert_param(!inIRQ());
|
||||||
|
|
||||||
// The last chunk from some previous frame may still be being transmitted,
|
|
||||||
// wait for it to finish (the semaphore is given in the CDC tx done handler)
|
|
||||||
if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 100)) {
|
|
||||||
TF_Error("Tx stalled in Claim");
|
|
||||||
|
|
||||||
// release the guarding mutex again
|
|
||||||
assert_param(pdTRUE == xSemaphoreGive(mutTinyFrameTxHandle));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
assert_param(osOK == osMutexWait(mutTinyFrameTxHandle, 5000));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +48,5 @@ bool TF_ClaimTx(TinyFrame *tf)
|
|||||||
void TF_ReleaseTx(TinyFrame *tf)
|
void TF_ReleaseTx(TinyFrame *tf)
|
||||||
{
|
{
|
||||||
(void) tf;
|
(void) tf;
|
||||||
assert_param(pdTRUE == xSemaphoreGive(mutTinyFrameTxHandle));
|
assert_param(osOK == osMutexRelease(mutTinyFrameTxHandle));
|
||||||
|
|
||||||
// the last payload is sent asynchronously
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -870,11 +870,7 @@ static inline uint32_t _TF_FN TF_ComposeTail(uint8_t *outbuff, TF_CKSUM *cksum)
|
|||||||
*/
|
*/
|
||||||
static bool _TF_FN TF_SendFrame_Begin(TinyFrame *tf, TF_Msg *msg, TF_Listener listener, TF_TICKS timeout)
|
static bool _TF_FN TF_SendFrame_Begin(TinyFrame *tf, TF_Msg *msg, TF_Listener listener, TF_TICKS timeout)
|
||||||
{
|
{
|
||||||
bool suc = TF_ClaimTx(tf);
|
TF_TRY(TF_ClaimTx(tf));
|
||||||
if (!suc) {
|
|
||||||
TF_Error("TF lock not free");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
tf->tx_pos = (uint32_t) TF_ComposeHead(tf, tf->sendbuf, msg); // frame ID is incremented here if it's not a response
|
tf->tx_pos = (uint32_t) TF_ComposeHead(tf, tf->sendbuf, msg); // frame ID is incremented here if it's not a response
|
||||||
tf->tx_len = msg->len;
|
tf->tx_len = msg->len;
|
||||||
@@ -1035,10 +1031,10 @@ bool _TF_FN TF_Query_Multipart(TinyFrame *tf, TF_Msg *msg, TF_Listener listener,
|
|||||||
return TF_Query(tf, msg, listener, timeout);
|
return TF_Query(tf, msg, listener, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _TF_FN TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg)
|
void _TF_FN TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg)
|
||||||
{
|
{
|
||||||
msg->data = NULL;
|
msg->data = NULL;
|
||||||
return TF_Respond(tf, msg);
|
TF_Respond(tf, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _TF_FN TF_Multipart_Payload(TinyFrame *tf, const uint8_t *buff, uint32_t length)
|
void _TF_FN TF_Multipart_Payload(TinyFrame *tf, const uint8_t *buff, uint32_t length)
|
||||||
|
|||||||
@@ -369,7 +369,7 @@ bool TF_Query_Multipart(TinyFrame *tf, TF_Msg *msg, TF_Listener listener, TF_TIC
|
|||||||
* TF_Respond() with multipart payload.
|
* TF_Respond() with multipart payload.
|
||||||
* msg.data is ignored and set to NULL
|
* msg.data is ignored and set to NULL
|
||||||
*/
|
*/
|
||||||
bool TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg);
|
void TF_Respond_Multipart(TinyFrame *tf, TF_Msg *msg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send the payload for a started multipart frame. This can be called multiple times
|
* Send the payload for a started multipart frame. This can be called multiple times
|
||||||
|
|||||||
@@ -0,0 +1,328 @@
|
|||||||
|
--- 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 )
|
||||||
|
{
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
--- 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
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
--- 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
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
--- 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)))) + \
|
#define SWAPBYTE(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \
|
||||||
(((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8))
|
(((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8))
|
||||||
|
|
||||||
#define LOBYTE(x) ((uint8_t)((x) & 0x00FF))
|
#define LOBYTE(x) ((uint8_t)(x & 0x00FF))
|
||||||
#define HIBYTE(x) ((uint8_t)(((x) & 0xFF00) >>8))
|
#define HIBYTE(x) ((uint8_t)((x & 0xFF00) >>8))
|
||||||
|
|
||||||
#ifndef MIN
|
#ifndef MIN
|
||||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
--- 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__ )
|
||||||
@@ -66,7 +66,6 @@ PCD_HandleTypeDef hpcd_USB_FS;
|
|||||||
/* init function */
|
/* init function */
|
||||||
void MX_USB_DEVICE_Init(void)
|
void MX_USB_DEVICE_Init(void)
|
||||||
{
|
{
|
||||||
dbg("USB device init ...");
|
|
||||||
/* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */
|
/* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */
|
||||||
|
|
||||||
/* USER CODE END USB_DEVICE_Init_PreTreatment */
|
/* USER CODE END USB_DEVICE_Init_PreTreatment */
|
||||||
|
|||||||
+1
-1
@@ -314,7 +314,7 @@ void USBD_CDC_TransmitDone(USBD_HandleTypeDef *pdev)
|
|||||||
assert_param(inIRQ());
|
assert_param(inIRQ());
|
||||||
|
|
||||||
portBASE_TYPE taskWoken = pdFALSE;
|
portBASE_TYPE taskWoken = pdFALSE;
|
||||||
assert_param(pdTRUE == xSemaphoreGiveFromISR(semVcomTxReadyHandle, &taskWoken));
|
assert_param(xSemaphoreGiveFromISR(semVcomTxReadyHandle, &taskWoken) == pdTRUE);
|
||||||
portYIELD_FROM_ISR(taskWoken);
|
portYIELD_FROM_ISR(taskWoken);
|
||||||
}
|
}
|
||||||
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
|
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
|
||||||
|
|||||||
+5
-11
@@ -2,7 +2,6 @@
|
|||||||
// Created by MightyPork on 2017/11/21.
|
// Created by MightyPork on 2017/11/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <platform/status_led.h>
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "framework/settings.h"
|
#include "framework/settings.h"
|
||||||
#include "utils/ini_parser.h"
|
#include "utils/ini_parser.h"
|
||||||
@@ -65,14 +64,13 @@ static void settings_bulkread_cb(BulkRead *bulk, uint32_t chunk, uint8_t *buffer
|
|||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
free_ck(bulk);
|
free_ck(bulk);
|
||||||
iw_end();
|
iw_end();
|
||||||
// dbg("INI read complete.");
|
dbg("INI read complete.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bulk->offset == 0) iw_begin();
|
if (bulk->offset == 0) iw_begin();
|
||||||
|
|
||||||
IniWriter iw = iw_init((char *)buffer, bulk->offset, chunk);
|
IniWriter iw = iw_init((char *)buffer, bulk->offset, chunk);
|
||||||
iw.tag = 1;
|
|
||||||
settings_build_units_ini(&iw);
|
settings_build_units_ini(&iw);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,18 +79,17 @@ static void settings_bulkread_cb(BulkRead *bulk, uint32_t chunk, uint8_t *buffer
|
|||||||
*/
|
*/
|
||||||
static TF_Result lst_ini_export(TinyFrame *tf, TF_Msg *msg)
|
static TF_Result lst_ini_export(TinyFrame *tf, TF_Msg *msg)
|
||||||
{
|
{
|
||||||
// dbg("Bulk read INI file");
|
dbg("Bulk read INI file");
|
||||||
|
|
||||||
BulkRead *bulk = malloc_ck(sizeof(BulkRead));
|
BulkRead *bulk = malloc_ck(sizeof(BulkRead));
|
||||||
assert_param(bulk != NULL);
|
assert_param(bulk != NULL);
|
||||||
|
|
||||||
bulk->frame_id = msg->frame_id;
|
bulk->frame_id = msg->frame_id;
|
||||||
bulk->len = iw_measure_total(settings_build_units_ini, 1);
|
bulk->len = iw_measure_total(settings_build_units_ini);
|
||||||
bulk->read = settings_bulkread_cb;
|
bulk->read = settings_bulkread_cb;
|
||||||
bulk->userdata = NULL;
|
bulk->userdata = NULL;
|
||||||
|
|
||||||
bulkread_start(tf, bulk);
|
bulkread_start(tf, bulk);
|
||||||
Indicator_Effect(STATUS_DISK_BUSY_SHORT);
|
|
||||||
|
|
||||||
return TF_STAY;
|
return TF_STAY;
|
||||||
}
|
}
|
||||||
@@ -114,7 +111,7 @@ static void settings_bulkwrite_cb(BulkWrite *bulk, const uint8_t *chunk, uint32_
|
|||||||
|
|
||||||
if (bulk->offset > 0) {
|
if (bulk->offset > 0) {
|
||||||
settings_load_ini_end();
|
settings_load_ini_end();
|
||||||
// dbg("INI write complete");
|
dbg("INI write complete");
|
||||||
} else {
|
} else {
|
||||||
dbg("INI write failed");
|
dbg("INI write failed");
|
||||||
}
|
}
|
||||||
@@ -131,7 +128,7 @@ static void settings_bulkwrite_cb(BulkWrite *bulk, const uint8_t *chunk, uint32_
|
|||||||
*/
|
*/
|
||||||
static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg)
|
static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg)
|
||||||
{
|
{
|
||||||
// dbg("Bulk write INI file");
|
dbg("Bulk write INI file");
|
||||||
|
|
||||||
BulkWrite *bulk = malloc_ck(sizeof(BulkWrite));
|
BulkWrite *bulk = malloc_ck(sizeof(BulkWrite));
|
||||||
assert_param(bulk);
|
assert_param(bulk);
|
||||||
@@ -154,8 +151,6 @@ static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg)
|
|||||||
|
|
||||||
bulkwrite_start(tf, bulk);
|
bulkwrite_start(tf, bulk);
|
||||||
|
|
||||||
Indicator_Effect(STATUS_DISK_BUSY);
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
return TF_STAY;
|
return TF_STAY;
|
||||||
}
|
}
|
||||||
@@ -165,7 +160,6 @@ done:
|
|||||||
/** Listener: Save settings to Flash */
|
/** Listener: Save settings to Flash */
|
||||||
static TF_Result lst_persist_cfg(TinyFrame *tf, TF_Msg *msg)
|
static TF_Result lst_persist_cfg(TinyFrame *tf, TF_Msg *msg)
|
||||||
{
|
{
|
||||||
Indicator_Effect(STATUS_DISK_REMOVED);
|
|
||||||
settings_save();
|
settings_save();
|
||||||
return TF_STAY;
|
return TF_STAY;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-4
@@ -13,10 +13,8 @@
|
|||||||
|
|
||||||
void SysTick_Handler(void)
|
void SysTick_Handler(void)
|
||||||
{
|
{
|
||||||
// OS first, avoids jitter
|
|
||||||
osSystickHandler();
|
|
||||||
// GEX periodic updates
|
|
||||||
GEX_MsTick();
|
GEX_MsTick();
|
||||||
|
osSystickHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -36,7 +34,7 @@ void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName)
|
|||||||
|
|
||||||
// && (__CORTEX_M >= 3)
|
// && (__CORTEX_M >= 3)
|
||||||
#if VERBOSE_HARDFAULT
|
#if VERBOSE_HARDFAULT
|
||||||
void __attribute__((used)) HardFault_DumpRegisters(const uint32_t *origStack, uint32_t lr_value)
|
void __attribute__((used)) HardFault_DumpRegisters( uint32_t *origStack, uint32_t lr_value)
|
||||||
{
|
{
|
||||||
/* These are volatile to try and prevent the compiler/linker optimising them
|
/* 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
|
away as the variables never actually get used. If the debugger won't show the
|
||||||
|
|||||||
+27
-43
@@ -6,7 +6,6 @@
|
|||||||
#include "unit.h"
|
#include "unit.h"
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
#include "hw_utils.h"
|
#include "hw_utils.h"
|
||||||
#include "cfg_utils.h"
|
|
||||||
#include "unit_registry.h"
|
#include "unit_registry.h"
|
||||||
|
|
||||||
static bool rsc_initialized = false;
|
static bool rsc_initialized = false;
|
||||||
@@ -22,8 +21,10 @@ const char *const rsc_names[] = {
|
|||||||
#undef X
|
#undef X
|
||||||
};
|
};
|
||||||
|
|
||||||
COMPILER_ASSERT(R_PF15 < R_EXTI0);
|
// Check that EXTI have higher values than GPIOs in the enum
|
||||||
COMPILER_ASSERT(R_PA0 == 0);
|
// (determines the logic in the name generation code below)
|
||||||
|
COMPILER_ASSERT(R_EXTI0 > R_PA0);
|
||||||
|
|
||||||
|
|
||||||
const char * rsc_get_name(Resource rsc)
|
const char * rsc_get_name(Resource rsc)
|
||||||
{
|
{
|
||||||
@@ -33,46 +34,24 @@ const char * rsc_get_name(Resource rsc)
|
|||||||
// we assume the returned value is not stored anywhere
|
// we assume the returned value is not stored anywhere
|
||||||
// and is directly used in a sprintf call, hence a static buffer is OK to use
|
// and is directly used in a sprintf call, hence a static buffer is OK to use
|
||||||
|
|
||||||
// R_PA0 is 0
|
if (rsc >= R_EXTI0) {
|
||||||
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;
|
uint8_t index = rsc - R_EXTI0;
|
||||||
SNPRINTF(gpionamebuf, 8, "EXTI%d", index);
|
SNPRINTF(gpionamebuf, 8, "EXTI%d", index);
|
||||||
return gpionamebuf;
|
return gpionamebuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rsc_names[rsc - R_EXTI15 - 1];
|
if (rsc >= R_PA0) {
|
||||||
}
|
// we assume the returned value is not stored anywhere
|
||||||
|
// and is directly used in a sprintf call.
|
||||||
/** Convert a pin to resource handle */
|
uint8_t index = rsc - R_PA0;
|
||||||
Resource rsc_portpin2rsc(char port_name, uint8_t pin_number, bool *suc)
|
SNPRINTF(gpionamebuf, 8, "P%c%d", 'A'+(index/16), index%16);
|
||||||
{
|
return gpionamebuf;
|
||||||
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) {
|
return rsc_names[rsc];
|
||||||
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)
|
const char * rsc_get_owner_name(Resource rsc)
|
||||||
{
|
{
|
||||||
assert_param(rsc < RESOURCE_COUNT);
|
assert_param(rsc < RESOURCE_COUNT);
|
||||||
@@ -85,12 +64,11 @@ const char * rsc_get_owner_name(Resource rsc)
|
|||||||
|
|
||||||
void rsc_init_registry(void)
|
void rsc_init_registry(void)
|
||||||
{
|
{
|
||||||
memset(UNIT_PLATFORM.resources, 0xFF, RSCMAP_LEN);
|
for(uint32_t i = 0; i < RSCMAP_LEN; i++) {
|
||||||
memset(global_rscmap, 0xFF, RSCMAP_LEN);
|
UNIT_PLATFORM.resources[i] = global_rscmap[i] = 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
rsc_initialized = true;
|
rsc_initialized = true;
|
||||||
|
|
||||||
rsc_dbg("Total %d hw resources, bitmap has %d bytes.", RESOURCE_COUNT, RSCMAP_LEN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -143,11 +121,17 @@ error_t rsc_claim_range(Unit *unit, Resource rsc0, Resource rsc1)
|
|||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins)
|
error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins)
|
||||||
{
|
{
|
||||||
|
bool suc = true;
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
if (pins & (1 << i)) {
|
if (pins & (1 << i)) {
|
||||||
TRY(rsc_claim_pin(unit, port_name, (uint8_t)i));
|
Resource rsc = hw_pin2resource(port_name, (uint8_t) i, &suc);
|
||||||
|
if (!suc) return E_BAD_CONFIG;
|
||||||
|
|
||||||
|
TRY(rsc_claim(unit, rsc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
@@ -157,7 +141,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)
|
error_t rsc_claim_pin(Unit *unit, char port_name, uint8_t pin)
|
||||||
{
|
{
|
||||||
bool suc = true;
|
bool suc = true;
|
||||||
Resource rsc = rsc_portpin2rsc(port_name, pin, &suc);
|
Resource rsc = hw_pin2resource(port_name, pin, &suc);
|
||||||
if (!suc) return E_BAD_CONFIG;
|
if (!suc) return E_BAD_CONFIG;
|
||||||
TRY(rsc_claim(unit, rsc));
|
TRY(rsc_claim(unit, rsc));
|
||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
@@ -238,7 +222,7 @@ void rsc_print_all_available(IniWriter *iw)
|
|||||||
|
|
||||||
uint32_t count0 = (iw->count + iw->skip);
|
uint32_t count0 = (iw->count + iw->skip);
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (uint32_t rsc = R_EXTI15+1; rsc < R_NONE; rsc++) {
|
for (uint32_t rsc = 0; rsc < R_PA0; rsc++) {
|
||||||
if (RSC_IS_HELD(scratchmap, (Resource)rsc)) continue;
|
if (RSC_IS_HELD(scratchmap, (Resource)rsc)) continue;
|
||||||
if (!first) iw_string(iw, ", ");
|
if (!first) iw_string(iw, ", ");
|
||||||
|
|
||||||
@@ -258,7 +242,7 @@ void rsc_print_all_available(IniWriter *iw)
|
|||||||
if (i%16 == 0) {
|
if (i%16 == 0) {
|
||||||
// here we print the previous port
|
// here we print the previous port
|
||||||
if (bitmap != 0) {
|
if (bitmap != 0) {
|
||||||
iw_string(iw, cfg_pinmask_encode(bitmap, iwbuffer, 0));
|
iw_string(iw, pinmask2str(bitmap, iwbuffer));
|
||||||
bitmap = 0;
|
bitmap = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +257,7 @@ void rsc_print_all_available(IniWriter *iw)
|
|||||||
}
|
}
|
||||||
// the last one
|
// the last one
|
||||||
if (bitmap != 0) {
|
if (bitmap != 0) {
|
||||||
iw_string(iw, cfg_pinmask_encode(bitmap, iwbuffer, 0));
|
iw_string(iw, pinmask2str(bitmap, iwbuffer));
|
||||||
}
|
}
|
||||||
iw_newline(iw);
|
iw_newline(iw);
|
||||||
iw_newline(iw);
|
iw_newline(iw);
|
||||||
|
|||||||
@@ -94,16 +94,6 @@ void rsc_free(Unit *unit, Resource rsc);
|
|||||||
*/
|
*/
|
||||||
void rsc_free_range(Unit *unit, Resource rsc0, Resource rsc1);
|
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.
|
* Get name of a resource by the Resource enum.
|
||||||
* Uses a static buffer, DO NOT store the returned pointer.
|
* Uses a static buffer, DO NOT store the returned pointer.
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
X(I2C1) X(I2C2) X(I2C3) \
|
X(I2C1) X(I2C2) X(I2C3) \
|
||||||
X(ADC1) X(ADC2) X(ADC3) X(ADC4) \
|
X(ADC1) X(ADC2) X(ADC3) X(ADC4) \
|
||||||
X(DAC1) X(DAC2) \
|
X(DAC1) X(DAC2) \
|
||||||
X(TSC) \
|
|
||||||
X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \
|
X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \
|
||||||
X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \
|
X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \
|
||||||
X(TIM6) X(TIM7) X(TIM8) X(TIM9) X(TIM10) X(TIM11) X(TIM12) X(TIM13) X(TIM14) \
|
X(TIM6) X(TIM7) X(TIM8) X(TIM9) X(TIM10) X(TIM11) X(TIM12) X(TIM13) X(TIM14) \
|
||||||
@@ -25,6 +24,7 @@
|
|||||||
// X(I2S1) X(I2S2) X(I2S3)
|
// X(I2S1) X(I2S2) X(I2S3)
|
||||||
// X(OPAMP1) X(OPAMP2) X(OPAMP3) X(OPAMP4)
|
// X(OPAMP1) X(OPAMP2) X(OPAMP3) X(OPAMP4)
|
||||||
// X(CAN1) X(CAN2)
|
// X(CAN1) X(CAN2)
|
||||||
|
// X(TSC)
|
||||||
// X(DCMI)
|
// X(DCMI)
|
||||||
// X(ETH)
|
// X(ETH)
|
||||||
// X(FSMC)
|
// X(FSMC)
|
||||||
@@ -59,13 +59,9 @@ typedef enum hw_resource Resource;
|
|||||||
/** Enum of all resources */
|
/** Enum of all resources */
|
||||||
enum hw_resource {
|
enum hw_resource {
|
||||||
#define X(res_name) R_##res_name,
|
#define X(res_name) R_##res_name,
|
||||||
// GPIO are at the beginning, because some units use the constants in their config to represent
|
|
||||||
// selected pins and those must not change with adding more stuff to the main list
|
|
||||||
XX_RESOURCES_GPIO
|
|
||||||
// EXTIs (same like GPIOs) have dynamically generated labels to save rom space. Must be contiguous.
|
|
||||||
XX_RESOURCES_EXTI
|
|
||||||
// All the rest ...
|
|
||||||
XX_RESOURCES
|
XX_RESOURCES
|
||||||
|
XX_RESOURCES_GPIO
|
||||||
|
XX_RESOURCES_EXTI
|
||||||
#undef X
|
#undef X
|
||||||
R_NONE,
|
R_NONE,
|
||||||
RESOURCE_COUNT = R_NONE,
|
RESOURCE_COUNT = R_NONE,
|
||||||
|
|||||||
+9
-11
@@ -2,6 +2,7 @@
|
|||||||
// Created by MightyPork on 2017/11/26.
|
// Created by MightyPork on 2017/11/26.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "utils/avrlibc.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "utils/hexdump.h"
|
#include "utils/hexdump.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
@@ -9,7 +10,6 @@
|
|||||||
#include "system_settings.h"
|
#include "system_settings.h"
|
||||||
#include "utils/str_utils.h"
|
#include "utils/str_utils.h"
|
||||||
#include "unit_base.h"
|
#include "unit_base.h"
|
||||||
#include "utils/avrlibc.h"
|
|
||||||
|
|
||||||
// pre-declarations
|
// pre-declarations
|
||||||
static void savebuf_flush(PayloadBuilder *pb, bool final);
|
static void savebuf_flush(PayloadBuilder *pb, bool final);
|
||||||
@@ -229,6 +229,7 @@ static void gex_file_preamble(IniWriter *iw, const char *filename)
|
|||||||
iw_hdr_comment(iw, filename);
|
iw_hdr_comment(iw, filename);
|
||||||
iw_hdr_comment(iw, "GEX v%s on %s", GEX_VERSION, GEX_PLATFORM);
|
iw_hdr_comment(iw, "GEX v%s on %s", GEX_VERSION, GEX_PLATFORM);
|
||||||
iw_hdr_comment(iw, "built %s at %s", __DATE__, __TIME__);
|
iw_hdr_comment(iw, "built %s at %s", __DATE__, __TIME__);
|
||||||
|
iw_cmt_newline(iw);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Generate a config file header (write instructions) */
|
/** Generate a config file header (write instructions) */
|
||||||
@@ -236,15 +237,12 @@ static void ini_preamble(IniWriter *iw, const char *filename)
|
|||||||
{
|
{
|
||||||
gex_file_preamble(iw, filename);
|
gex_file_preamble(iw, filename);
|
||||||
|
|
||||||
if (iw->tag == 0) { // tag 1 is set when exporting via the API
|
iw_comment(iw, "Overwrite this file to change settings.");
|
||||||
iw_cmt_newline(iw);
|
#if PLAT_LOCK_BTN
|
||||||
iw_comment(iw, "Overwrite this file to change settings.");
|
iw_comment(iw, "Press the LOCK button to save them to Flash.");
|
||||||
#if PLAT_LOCK_BTN
|
#else
|
||||||
iw_comment(iw, "Press the LOCK button to save them to Flash.");
|
iw_comment(iw, "Close the LOCK jumper to save them to Flash.");
|
||||||
#else
|
#endif
|
||||||
iw_comment(iw, "Close the LOCK jumper to save them to Flash.");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- UNITS.INI ---
|
// --- UNITS.INI ---
|
||||||
@@ -286,7 +284,7 @@ extern void plat_print_system_pinout(IniWriter *iw);
|
|||||||
void settings_build_pinout_txt(IniWriter *iw)
|
void settings_build_pinout_txt(IniWriter *iw)
|
||||||
{
|
{
|
||||||
gex_file_preamble(iw, "PINOUT.TXT");
|
gex_file_preamble(iw, "PINOUT.TXT");
|
||||||
iw_cmt_newline(iw);
|
|
||||||
rsc_print_all_available(iw);
|
rsc_print_all_available(iw);
|
||||||
ureg_print_unit_resources(iw);
|
ureg_print_unit_resources(iw);
|
||||||
plat_print_system_pinout(iw);
|
plat_print_system_pinout(iw);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include "system_settings.h"
|
#include "system_settings.h"
|
||||||
#include "utils/str_utils.h"
|
#include "utils/str_utils.h"
|
||||||
#include "platform/lock_jumper.h"
|
#include "platform/lock_jumper.h"
|
||||||
#include "cfg_utils.h"
|
|
||||||
|
|
||||||
struct system_settings SystemSettings;
|
struct system_settings SystemSettings;
|
||||||
|
|
||||||
@@ -78,12 +77,12 @@ bool systemsettings_load_ini(const char *restrict key, const char *restrict valu
|
|||||||
{
|
{
|
||||||
bool suc = true;
|
bool suc = true;
|
||||||
if (streq(key, "expose_vcom")) {
|
if (streq(key, "expose_vcom")) {
|
||||||
bool yn = cfg_bool_parse(value, &suc);
|
bool yn = str_parse_yn(value, &suc);
|
||||||
if (suc) SystemSettings.visible_vcom = yn;
|
if (suc) SystemSettings.visible_vcom = yn;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streq(key, "ini_comments")) {
|
if (streq(key, "ini_comments")) {
|
||||||
bool yn = cfg_bool_parse(value, &suc);
|
bool yn = str_parse_yn(value, &suc);
|
||||||
if (suc) SystemSettings.ini_comments = yn;
|
if (suc) SystemSettings.ini_comments = yn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "unit.h"
|
#include "unit.h"
|
||||||
#include "hw_utils.h"
|
#include "hw_utils.h"
|
||||||
#include "cfg_utils.h"
|
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
#include "utils/str_utils.h"
|
#include "utils/str_utils.h"
|
||||||
#include "utils/malloc_safe.h"
|
#include "utils/malloc_safe.h"
|
||||||
|
|||||||
+11
-19
@@ -340,27 +340,19 @@ bool ureg_finalize_all_init(void)
|
|||||||
} else {
|
} else {
|
||||||
pUnit->status = pUnit->driver->init(pUnit);
|
pUnit->status = pUnit->driver->init(pUnit);
|
||||||
if (pUnit->status != E_SUCCESS) {
|
if (pUnit->status != E_SUCCESS) {
|
||||||
dbg("!!! error initing unit %s: %s", pUnit->name, error_get_message(pUnit->status));
|
dbg("!!! error initing unit %s: %s", pUnit->name,
|
||||||
|
error_get_message(pUnit->status));
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to assign unique callsigns
|
// try to assign unique callsigns
|
||||||
|
// FIXME this is wrong, sometimes leads to duplicate CS
|
||||||
if (pUnit->callsign == 0) {
|
if (pUnit->callsign == 0) {
|
||||||
// this is very inefficient but should be reliable
|
pUnit->callsign = callsign++;
|
||||||
bool change;
|
}
|
||||||
do {
|
else {
|
||||||
change = false;
|
if (pUnit->callsign >= callsign) {
|
||||||
UlistEntry *xli = ulist_head;
|
callsign = (uint8_t) (pUnit->callsign + 1);
|
||||||
while (xli != NULL) {
|
}
|
||||||
if (xli->unit.callsign != 0) {
|
|
||||||
if (xli->unit.callsign == callsign) {
|
|
||||||
change = true;
|
|
||||||
callsign++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xli = xli->next;
|
|
||||||
}
|
|
||||||
} while (change && callsign < 255);
|
|
||||||
pUnit->callsign = callsign;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,9 +398,8 @@ void ureg_build_ini(IniWriter *iw)
|
|||||||
|
|
||||||
// Unit list
|
// Unit list
|
||||||
iw_section(iw, "UNITS");
|
iw_section(iw, "UNITS");
|
||||||
iw_comment(iw, "Create units by adding their names next to a type (e.g. DO=A,B),");
|
iw_comment(iw, "Create units by adding their names next to a type (e.g. PIN=A,B),");
|
||||||
iw_comment(iw, "remove the same way. Reload to update the unit sections below.");
|
iw_comment(iw, "remove the same way. Reload to update the unit sections below.");
|
||||||
iw_cmt_newline(iw);
|
|
||||||
|
|
||||||
// This could certainly be done in some more efficient way ...
|
// This could certainly be done in some more efficient way ...
|
||||||
re = ureg_head;
|
re = ureg_head;
|
||||||
@@ -421,6 +412,7 @@ void ureg_build_ini(IniWriter *iw)
|
|||||||
|
|
||||||
const UnitDriver *const pDriver = re->driver;
|
const UnitDriver *const pDriver = re->driver;
|
||||||
|
|
||||||
|
iw_cmt_newline(iw);
|
||||||
iw_comment(iw, pDriver->description);
|
iw_comment(iw, pDriver->description);
|
||||||
iw_string(iw, pDriver->name);
|
iw_string(iw, pDriver->name);
|
||||||
iw_string(iw, "=");
|
iw_string(iw, "=");
|
||||||
|
|||||||
+1
-1
@@ -147,7 +147,7 @@ void MX_FREERTOS_Init(void) {
|
|||||||
stackmon_register("Main", mainTaskStack, sizeof(mainTaskStack));
|
stackmon_register("Main", mainTaskStack, sizeof(mainTaskStack));
|
||||||
stackmon_register("Job+Msg", msgJobQueTaskStack, sizeof(msgJobQueTaskStack));
|
stackmon_register("Job+Msg", msgJobQueTaskStack, sizeof(msgJobQueTaskStack));
|
||||||
stackmon_register("Idle", xIdleStack, sizeof(xIdleStack));
|
stackmon_register("Idle", xIdleStack, sizeof(xIdleStack));
|
||||||
// stackmon_register("Timers", xTimersStack, sizeof(xTimersStack));
|
stackmon_register("Timers", xTimersStack, sizeof(xTimersStack));
|
||||||
/* USER CODE END Init */
|
/* USER CODE END Init */
|
||||||
|
|
||||||
/* Create the mutex(es) */
|
/* Create the mutex(es) */
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ GEX_SRC_DIR = \
|
|||||||
User/units/i2c \
|
User/units/i2c \
|
||||||
User/units/spi \
|
User/units/spi \
|
||||||
User/units/adc \
|
User/units/adc \
|
||||||
User/units/sipo \
|
|
||||||
User/units/fcap \
|
|
||||||
User/units/touch \
|
|
||||||
User/units/simple_pwm \
|
|
||||||
User/TinyFrame \
|
User/TinyFrame \
|
||||||
User/CWPack \
|
User/CWPack \
|
||||||
User/tasks
|
User/tasks
|
||||||
|
|||||||
-12
@@ -43,18 +43,6 @@ void GEX_PreInit(void)
|
|||||||
dbg("\r\n\033[37;1m*** GEX "GEX_VERSION" on "GEX_PLATFORM" ***\033[m");
|
dbg("\r\n\033[37;1m*** GEX "GEX_VERSION" on "GEX_PLATFORM" ***\033[m");
|
||||||
dbg("Build "__DATE__" "__TIME__);
|
dbg("Build "__DATE__" "__TIME__);
|
||||||
|
|
||||||
PRINTF("Reset cause:");
|
|
||||||
if (LL_RCC_IsActiveFlag_LPWRRST()) PRINTF(" LPWR");
|
|
||||||
if (LL_RCC_IsActiveFlag_WWDGRST()) PRINTF(" WWDG");
|
|
||||||
if (LL_RCC_IsActiveFlag_IWDGRST()) PRINTF(" IWDG");
|
|
||||||
if (LL_RCC_IsActiveFlag_SFTRST()) PRINTF(" SFT");
|
|
||||||
if (LL_RCC_IsActiveFlag_PORRST()) PRINTF(" POR");
|
|
||||||
if (LL_RCC_IsActiveFlag_PINRST()) PRINTF(" PIN");
|
|
||||||
if (LL_RCC_IsActiveFlag_OBLRST()) PRINTF(" OBL");
|
|
||||||
if (LL_RCC_IsActiveFlag_V18PWRRST()) PRINTF(" V18PWR");
|
|
||||||
PUTNL();
|
|
||||||
LL_RCC_ClearResetFlags();
|
|
||||||
|
|
||||||
plat_init();
|
plat_init();
|
||||||
|
|
||||||
MX_USB_DEVICE_Init();
|
MX_USB_DEVICE_Init();
|
||||||
|
|||||||
@@ -1,299 +0,0 @@
|
|||||||
//
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
+219
-52
@@ -3,8 +3,10 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
#include "utils/avrlibc.h"
|
||||||
#include "hw_utils.h"
|
#include "hw_utils.h"
|
||||||
|
|
||||||
|
|
||||||
/** Convert pin number to LL bitfield */
|
/** Convert pin number to LL bitfield */
|
||||||
uint32_t hw_pin2ll(uint8_t pin_number, bool *suc)
|
uint32_t hw_pin2ll(uint8_t pin_number, bool *suc)
|
||||||
{
|
{
|
||||||
@@ -34,21 +36,210 @@ GPIO_TypeDef *hw_port2periph(char port_name, bool *suc)
|
|||||||
return GPIO_PERIPHS[num];
|
return GPIO_PERIPHS[num];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Convert a pin resource to it's LL lib values */
|
/** Convert a pin to resource handle */
|
||||||
bool hw_pinrsc2ll(Resource rsc, GPIO_TypeDef **port, uint32_t *llpin)
|
Resource hw_pin2resource(char port_name, uint8_t pin_number, bool *suc)
|
||||||
{
|
{
|
||||||
if (rsc > R_PF15) return false;
|
assert_param(suc != NULL);
|
||||||
uint32_t index = rsc - R_PA0;
|
|
||||||
uint32_t pname = (index/16);
|
if(port_name < 'A' || port_name >= ('A'+PORTS_COUNT)) {
|
||||||
uint8_t pnum = (uint8_t) (index % 16);
|
dbg("Bad port: %c", port_name); // TODO proper report
|
||||||
if (pname >= PORTS_COUNT) return false;
|
*suc = false;
|
||||||
*port = GPIO_PERIPHS[pname];
|
return R_NONE;
|
||||||
*llpin = LL_GPIO_PINS[pnum];
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma GCC push_options
|
/** Parse port name */
|
||||||
#pragma GCC optimize ("O2")
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/** spread a packed pinfield using a mask */
|
/** spread a packed pinfield using a mask */
|
||||||
uint32_t pinmask_spread_32(uint32_t packed, uint32_t mask)
|
uint32_t pinmask_spread_32(uint32_t packed, uint32_t mask)
|
||||||
{
|
{
|
||||||
@@ -56,7 +247,7 @@ uint32_t pinmask_spread_32(uint32_t packed, uint32_t mask)
|
|||||||
uint32_t poke = 1;
|
uint32_t poke = 1;
|
||||||
if(packed == 0) return 0;
|
if(packed == 0) return 0;
|
||||||
|
|
||||||
for (int i = 0; i < 32; i++) {
|
for (int i = 0; i<32; i++) {
|
||||||
if (mask & 1) {
|
if (mask & 1) {
|
||||||
if (packed & poke) {
|
if (packed & poke) {
|
||||||
result |= 1<<i;
|
result |= 1<<i;
|
||||||
@@ -92,13 +283,24 @@ uint32_t pinmask_pack_32(uint32_t spread, uint32_t mask)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma GCC pop_options
|
/** 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;
|
||||||
|
}
|
||||||
|
|
||||||
/** Configure unit pins as analog (part of unit teardown) */
|
/** Configure unit pins as analog (part of unit teardown) */
|
||||||
void hw_deinit_unit_pins(Unit *unit)
|
void hw_deinit_unit_pins(Unit *unit)
|
||||||
{
|
{
|
||||||
for (uint32_t rsc = R_PA0; rsc <= R_PF15; rsc++) {
|
for (uint32_t rsc = R_PA0; rsc <= R_PF15; rsc++) {
|
||||||
if (RSC_IS_HELD(unit->resources, (Resource)rsc)) {
|
if (RSC_IS_HELD(unit->resources, rsc)) {
|
||||||
rsc_dbg("Freeing pin %s", rsc_get_name((Resource)rsc));
|
rsc_dbg("Freeing pin %s", rsc_get_name((Resource)rsc));
|
||||||
GPIO_TypeDef *port = GPIO_PERIPHS[(rsc-R_PA0) / 16];
|
GPIO_TypeDef *port = GPIO_PERIPHS[(rsc-R_PA0) / 16];
|
||||||
uint32_t ll_pin = LL_GPIO_PINS[(rsc-R_PA0)%16];
|
uint32_t ll_pin = LL_GPIO_PINS[(rsc-R_PA0)%16];
|
||||||
@@ -130,30 +332,6 @@ error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af)
|
|||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Configure a pin to alternate function */
|
|
||||||
error_t hw_configure_gpiorsc_af(Resource rsc, uint32_t ll_af)
|
|
||||||
{
|
|
||||||
#if PLAT_NO_AFNUM
|
|
||||||
trap("Illegal call to hw_configure_gpio_af() on this platform");
|
|
||||||
#else
|
|
||||||
|
|
||||||
bool suc = true;
|
|
||||||
GPIO_TypeDef *port;
|
|
||||||
uint32_t ll_pin;
|
|
||||||
suc = hw_pinrsc2ll(rsc, &port, &ll_pin);
|
|
||||||
if (!suc) return E_BAD_CONFIG;
|
|
||||||
|
|
||||||
if (ll_pin & 0xFF)
|
|
||||||
LL_GPIO_SetAFPin_0_7(port, ll_pin, ll_af);
|
|
||||||
else
|
|
||||||
LL_GPIO_SetAFPin_8_15(port, ll_pin, ll_af);
|
|
||||||
|
|
||||||
LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ALTERNATE);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Configure pins using sparse map */
|
/** Configure pins using sparse map */
|
||||||
error_t hw_configure_sparse_pins(char port_name, uint16_t mask, GPIO_TypeDef **port_dest,
|
error_t hw_configure_sparse_pins(char port_name, uint16_t mask, GPIO_TypeDef **port_dest,
|
||||||
uint32_t ll_mode, uint32_t ll_otype)
|
uint32_t ll_mode, uint32_t ll_otype)
|
||||||
@@ -179,8 +357,8 @@ error_t hw_configure_sparse_pins(char port_name, uint16_t mask, GPIO_TypeDef **p
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Solve a timer/counter's count and prescaller value */
|
/** Solve a timer/counter's count and prescaller value */
|
||||||
bool hw_solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
|
bool solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
|
||||||
uint16_t *presc, uint32_t *count, float *real_freq)
|
uint16_t *presc, uint32_t *count, float *real_freq)
|
||||||
{
|
{
|
||||||
if (required_freq == 0) return false;
|
if (required_freq == 0) return false;
|
||||||
|
|
||||||
@@ -213,6 +391,7 @@ bool hw_solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void hw_periph_clock_enable(void *periph)
|
void hw_periph_clock_enable(void *periph)
|
||||||
{
|
{
|
||||||
// GPIOs are enabled by default on start-up
|
// GPIOs are enabled by default on start-up
|
||||||
@@ -311,12 +490,6 @@ void hw_periph_clock_enable(void *periph)
|
|||||||
#ifdef DAC2
|
#ifdef DAC2
|
||||||
else if (periph == DAC2) __HAL_RCC_DAC2_CLK_ENABLE();
|
else if (periph == DAC2) __HAL_RCC_DAC2_CLK_ENABLE();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// --- TSC ---
|
|
||||||
#ifdef TSC
|
|
||||||
else if (periph == TSC) __HAL_RCC_TSC_CLK_ENABLE();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
else {
|
else {
|
||||||
dbg("Periph 0x%p missing in hw clock enable func", periph);
|
dbg("Periph 0x%p missing in hw clock enable func", periph);
|
||||||
trap("BUG");
|
trap("BUG");
|
||||||
@@ -422,12 +595,6 @@ void hw_periph_clock_disable(void *periph)
|
|||||||
#ifdef DAC2
|
#ifdef DAC2
|
||||||
else if (periph == DAC2) __HAL_RCC_DAC2_CLK_DISABLE();
|
else if (periph == DAC2) __HAL_RCC_DAC2_CLK_DISABLE();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// --- TSC ---
|
|
||||||
#ifdef TSC
|
|
||||||
else if (periph == TSC) __HAL_RCC_TSC_CLK_DISABLE();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
else {
|
else {
|
||||||
dbg("Periph 0x%p missing in hw clock disable func", periph);
|
dbg("Periph 0x%p missing in hw clock disable func", periph);
|
||||||
trap("BUG");
|
trap("BUG");
|
||||||
|
|||||||
+65
-12
@@ -21,6 +21,16 @@
|
|||||||
*/
|
*/
|
||||||
uint32_t hw_pin2ll(uint8_t pin_number, bool *suc);
|
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
|
* Convert port name to peripheral instance
|
||||||
*
|
*
|
||||||
@@ -31,14 +41,55 @@ uint32_t hw_pin2ll(uint8_t pin_number, bool *suc);
|
|||||||
GPIO_TypeDef *hw_port2periph(char port_name, bool *suc);
|
GPIO_TypeDef *hw_port2periph(char port_name, bool *suc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a pin resource to it's LL lib values
|
* Parse a pin name (e.g. PA0 or A0) to port name and pin number
|
||||||
*
|
*
|
||||||
* @param[in] rsc - resource to process
|
* @param str - source string
|
||||||
* @param[out] port - output port
|
* @param targetName - output: port name (one character)
|
||||||
* @param[out] llpin - output LL pin mask
|
* @param targetNumber - output: pin number 0-15
|
||||||
* @return success
|
* @return success
|
||||||
*/
|
*/
|
||||||
bool hw_pinrsc2ll(Resource rsc, GPIO_TypeDef **port, uint32_t *llpin) __attribute__((warn_unused_result));
|
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spread packed port pins using a mask
|
* Spread packed port pins using a mask
|
||||||
@@ -49,7 +100,6 @@ bool hw_pinrsc2ll(Resource rsc, GPIO_TypeDef **port, uint32_t *llpin) __attribut
|
|||||||
*/
|
*/
|
||||||
uint32_t pinmask_spread_32(uint32_t packed, uint32_t mask);
|
uint32_t pinmask_spread_32(uint32_t packed, uint32_t mask);
|
||||||
|
|
||||||
/** Spread packed port pins using a mask - 16-bit version */
|
|
||||||
static inline uint16_t pinmask_spread(uint16_t packed, uint16_t mask)
|
static inline uint16_t pinmask_spread(uint16_t packed, uint16_t mask)
|
||||||
{
|
{
|
||||||
return (uint16_t) pinmask_spread_32(packed, mask);
|
return (uint16_t) pinmask_spread_32(packed, mask);
|
||||||
@@ -64,12 +114,18 @@ static inline uint16_t pinmask_spread(uint16_t packed, uint16_t mask)
|
|||||||
*/
|
*/
|
||||||
uint32_t pinmask_pack_32(uint32_t spread, uint32_t mask);
|
uint32_t pinmask_pack_32(uint32_t spread, uint32_t mask);
|
||||||
|
|
||||||
/** Pack spread port pins using a mask - 16-bit version */
|
|
||||||
static inline uint16_t pinmask_pack(uint32_t spread, uint32_t mask)
|
static inline uint16_t pinmask_pack(uint32_t spread, uint32_t mask)
|
||||||
{
|
{
|
||||||
return (uint16_t) pinmask_pack_32(spread, 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.
|
* Set all GPIO resources held by unit to analog.
|
||||||
* This is a part of unit teardown.
|
* This is a part of unit teardown.
|
||||||
@@ -88,9 +144,6 @@ void hw_deinit_unit_pins(Unit *unit);
|
|||||||
*/
|
*/
|
||||||
error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af) __attribute__((warn_unused_result));
|
error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af) __attribute__((warn_unused_result));
|
||||||
|
|
||||||
/** Configure a pin to alternate function via rsc */
|
|
||||||
error_t hw_configure_gpiorsc_af(Resource rsc, uint32_t ll_af) __attribute__((warn_unused_result));
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure multiple pins using the bitmap pattern
|
* Configure multiple pins using the bitmap pattern
|
||||||
*
|
*
|
||||||
@@ -137,8 +190,8 @@ void hw_periph_clock_disable(void *periph);
|
|||||||
* @param[out] real_freq - field for storing the computed real frequency
|
* @param[out] real_freq - field for storing the computed real frequency
|
||||||
* @return true on success
|
* @return true on success
|
||||||
*/
|
*/
|
||||||
bool hw_solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
|
bool 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));
|
uint16_t *presc, uint32_t *count, float *real_freq);
|
||||||
|
|
||||||
#define hw_wait_while(call, timeout) \
|
#define hw_wait_while(call, timeout) \
|
||||||
do { \
|
do { \
|
||||||
|
|||||||
@@ -61,15 +61,11 @@ static struct callbacks_ {
|
|||||||
struct cbslot dma2_7;
|
struct cbslot dma2_7;
|
||||||
struct cbslot dma2_8;
|
struct cbslot dma2_8;
|
||||||
|
|
||||||
struct cbslot tim2;
|
|
||||||
struct cbslot tim6;
|
struct cbslot tim6;
|
||||||
struct cbslot tim7;
|
struct cbslot tim7;
|
||||||
struct cbslot tim14;
|
|
||||||
struct cbslot tim15;
|
struct cbslot tim15;
|
||||||
struct cbslot tim16;
|
|
||||||
|
|
||||||
struct cbslot adc1;
|
struct cbslot adc1;
|
||||||
struct cbslot tsc;
|
|
||||||
|
|
||||||
// XXX add more callbacks here when needed
|
// XXX add more callbacks here when needed
|
||||||
} callbacks;
|
} callbacks;
|
||||||
@@ -93,8 +89,7 @@ void irqd_init(void)
|
|||||||
HAL_NVIC_SetPriority(EXTI2_3_IRQn, 2, 0);
|
HAL_NVIC_SetPriority(EXTI2_3_IRQn, 2, 0);
|
||||||
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 2, 0);
|
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 2, 0);
|
||||||
|
|
||||||
NVIC_EnableIRQ(TSC_IRQn); /*!< Touch Sensing Controller Interrupts */
|
// NVIC_EnableIRQ(TSC_IRQn); /*!< Touch Sensing Controller Interrupts */
|
||||||
HAL_NVIC_SetPriority(TSC_IRQn, 2, 0);
|
|
||||||
|
|
||||||
NVIC_EnableIRQ(DMA1_Channel1_IRQn); /*!< DMA1 Channel 1 Interrupt */
|
NVIC_EnableIRQ(DMA1_Channel1_IRQn); /*!< DMA1 Channel 1 Interrupt */
|
||||||
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); /*!< DMA1 Channel 2 and Channel 3 Interrupt */
|
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); /*!< DMA1 Channel 2 and Channel 3 Interrupt */
|
||||||
@@ -107,32 +102,24 @@ void irqd_init(void)
|
|||||||
HAL_NVIC_SetPriority(ADC1_COMP_IRQn, 1, 0); // ADC group completion - higher prio than DMA to let it handle the last halfword first
|
HAL_NVIC_SetPriority(ADC1_COMP_IRQn, 1, 0); // ADC group completion - higher prio than DMA to let it handle the last halfword first
|
||||||
|
|
||||||
// NVIC_EnableIRQ(TIM1_IRQn); /*!< TIM1 global Interrupt */
|
// NVIC_EnableIRQ(TIM1_IRQn); /*!< TIM1 global Interrupt */
|
||||||
NVIC_EnableIRQ(TIM2_IRQn); /*!< TIM2 global Interrupt */
|
// NVIC_EnableIRQ(TIM2_IRQn); /*!< TIM2 global Interrupt */
|
||||||
HAL_NVIC_SetPriority(TIM2_IRQn, 2, 0); // Used by FCAP
|
|
||||||
|
|
||||||
// NVIC_EnableIRQ(TIM3_IRQn); /*!< TIM3 global Interrupt */
|
// NVIC_EnableIRQ(TIM3_IRQn); /*!< TIM3 global Interrupt */
|
||||||
|
|
||||||
NVIC_EnableIRQ(TIM6_DAC_IRQn); /*!< TIM6 global and DAC channel underrun error Interrupt */
|
NVIC_EnableIRQ(TIM6_DAC_IRQn); /*!< TIM6 global and DAC channel underrun error Interrupt */
|
||||||
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0); // Used for DAC timing
|
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0); // Used for DAC timing
|
||||||
|
|
||||||
NVIC_EnableIRQ(TIM7_IRQn); /*!< TIM7 global Interrupt */
|
NVIC_EnableIRQ(TIM7_IRQn); /*!< TIM7 global Interrupt */
|
||||||
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0);// this will be for dac (?)
|
HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0);
|
||||||
|
|
||||||
NVIC_EnableIRQ(TIM14_IRQn); /*used by fcap as a time reference for direct capture */ /*!< TIM14 global Interrupt */
|
/* Tim14 is used for HAL timebase, because SysTick is used to time FreeRTOS and has the lowest priority. */
|
||||||
HAL_NVIC_SetPriority(TIM14_IRQn, 2, 0);
|
/* Tim14's priority is set to 0 in the init routine, which runs early in the startup sequence */
|
||||||
|
// NVIC_EnableIRQ(TIM14_IRQn); /*!< TIM14 global Interrupt */
|
||||||
|
|
||||||
NVIC_EnableIRQ(TIM15_IRQn); /*!< TIM15 global Interrupt */
|
NVIC_EnableIRQ(TIM15_IRQn); /*!< TIM15 global Interrupt */
|
||||||
HAL_NVIC_SetPriority(TIM15_IRQn, 2, 0); // Used by ADC
|
HAL_NVIC_SetPriority(TIM15_IRQn, 2, 0);
|
||||||
|
|
||||||
NVIC_EnableIRQ(TIM16_IRQn); /*!< TIM16 global Interrupt */
|
// NVIC_EnableIRQ(TIM16_IRQn); /*!< TIM16 global Interrupt */
|
||||||
HAL_NVIC_SetPriority(TIM16_IRQn, 2, 0);
|
|
||||||
|
|
||||||
|
|
||||||
/* Tim17 is used for HAL timebase, because SysTick is used to time FreeRTOS and has the lowest priority. */
|
|
||||||
/* Tim17's priority is set to 0 in the init routine, which runs early in the startup sequence */
|
|
||||||
// NVIC_EnableIRQ(TIM17_IRQn); /*!< TIM17 global Interrupt */
|
// NVIC_EnableIRQ(TIM17_IRQn); /*!< TIM17 global Interrupt */
|
||||||
|
|
||||||
|
|
||||||
// NVIC_EnableIRQ(I2C1_IRQn); /*!< I2C1 Event Interrupt & EXTI Line23 Interrupt (I2C1 wakeup) */
|
// NVIC_EnableIRQ(I2C1_IRQn); /*!< I2C1 Event Interrupt & EXTI Line23 Interrupt (I2C1 wakeup) */
|
||||||
// NVIC_EnableIRQ(I2C2_IRQn); /*!< I2C2 Event Interrupt */
|
// NVIC_EnableIRQ(I2C2_IRQn); /*!< I2C2 Event Interrupt */
|
||||||
// NVIC_EnableIRQ(SPI1_IRQn); /*!< SPI1 global Interrupt */
|
// NVIC_EnableIRQ(SPI1_IRQn); /*!< SPI1 global Interrupt */
|
||||||
@@ -172,15 +159,9 @@ static struct cbslot *get_slot_for_periph(void *periph)
|
|||||||
else if (periph == USART5) slot = &callbacks.usart5;
|
else if (periph == USART5) slot = &callbacks.usart5;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
else if (periph == TIM2) slot = &callbacks.tim2;
|
|
||||||
else if (periph == TIM6) slot = &callbacks.tim6;
|
else if (periph == TIM6) slot = &callbacks.tim6;
|
||||||
else if (periph == TIM7) slot = &callbacks.tim7;
|
else if (periph == TIM7) slot = &callbacks.tim7;
|
||||||
else if (periph == TIM14) slot = &callbacks.tim14;
|
|
||||||
else if (periph == TIM15) slot = &callbacks.tim15;
|
else if (periph == TIM15) slot = &callbacks.tim15;
|
||||||
else if (periph == TIM16) slot = &callbacks.tim16;
|
|
||||||
// 17 - used by timebase
|
|
||||||
|
|
||||||
else if (periph == TSC) slot = &callbacks.tsc;
|
|
||||||
|
|
||||||
else if (periph == ADC1) slot = &callbacks.adc1;
|
else if (periph == ADC1) slot = &callbacks.adc1;
|
||||||
|
|
||||||
@@ -321,10 +302,7 @@ void EXTI4_15_IRQHandler(void)
|
|||||||
|
|
||||||
// ------------ INTERRUPTS -------------
|
// ------------ INTERRUPTS -------------
|
||||||
|
|
||||||
void TIM2_IRQHandler(void)
|
// TIM14 is used to generate HAL timebase and its handler is in the file "timebase.c"
|
||||||
{
|
|
||||||
CALL_IRQ_HANDLER(callbacks.tim2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TIM6_DAC_IRQHandler(void)
|
void TIM6_DAC_IRQHandler(void)
|
||||||
{
|
{
|
||||||
@@ -336,31 +314,16 @@ void TIM7_IRQHandler(void)
|
|||||||
CALL_IRQ_HANDLER(callbacks.tim7);
|
CALL_IRQ_HANDLER(callbacks.tim7);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TIM14_IRQHandler(void)
|
|
||||||
{
|
|
||||||
CALL_IRQ_HANDLER(callbacks.tim14);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TIM15_IRQHandler(void)
|
void TIM15_IRQHandler(void)
|
||||||
{
|
{
|
||||||
CALL_IRQ_HANDLER(callbacks.tim15);
|
CALL_IRQ_HANDLER(callbacks.tim15);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TIM16_IRQHandler(void)
|
|
||||||
{
|
|
||||||
CALL_IRQ_HANDLER(callbacks.tim16);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ADC1_COMP_IRQHandler(void)
|
void ADC1_COMP_IRQHandler(void)
|
||||||
{
|
{
|
||||||
CALL_IRQ_HANDLER(callbacks.adc1);
|
CALL_IRQ_HANDLER(callbacks.adc1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TSC_IRQHandler(void)
|
|
||||||
{
|
|
||||||
CALL_IRQ_HANDLER(callbacks.tsc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// other ISRs...
|
// other ISRs...
|
||||||
|
|
||||||
|
|||||||
@@ -5,44 +5,6 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "ll_extension.h"
|
#include "ll_extension.h"
|
||||||
|
|
||||||
const uint32_t LL_TIM_IC_FILTERS[] = {
|
|
||||||
LL_TIM_IC_FILTER_FDIV1,
|
|
||||||
LL_TIM_IC_FILTER_FDIV1_N2,
|
|
||||||
LL_TIM_IC_FILTER_FDIV1_N4,
|
|
||||||
LL_TIM_IC_FILTER_FDIV1_N8,
|
|
||||||
LL_TIM_IC_FILTER_FDIV2_N6,
|
|
||||||
LL_TIM_IC_FILTER_FDIV2_N8,
|
|
||||||
LL_TIM_IC_FILTER_FDIV4_N6,
|
|
||||||
LL_TIM_IC_FILTER_FDIV4_N8,
|
|
||||||
LL_TIM_IC_FILTER_FDIV8_N6,
|
|
||||||
LL_TIM_IC_FILTER_FDIV8_N8,
|
|
||||||
LL_TIM_IC_FILTER_FDIV16_N5,
|
|
||||||
LL_TIM_IC_FILTER_FDIV16_N6,
|
|
||||||
LL_TIM_IC_FILTER_FDIV16_N8,
|
|
||||||
LL_TIM_IC_FILTER_FDIV32_N5,
|
|
||||||
LL_TIM_IC_FILTER_FDIV32_N6,
|
|
||||||
LL_TIM_IC_FILTER_FDIV32_N8,
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint32_t LL_TIM_ETR_FILTERS[] = {
|
|
||||||
LL_TIM_ETR_FILTER_FDIV1,
|
|
||||||
LL_TIM_ETR_FILTER_FDIV1_N2,
|
|
||||||
LL_TIM_ETR_FILTER_FDIV1_N4,
|
|
||||||
LL_TIM_ETR_FILTER_FDIV1_N8,
|
|
||||||
LL_TIM_ETR_FILTER_FDIV2_N6,
|
|
||||||
LL_TIM_ETR_FILTER_FDIV2_N8,
|
|
||||||
LL_TIM_ETR_FILTER_FDIV4_N6,
|
|
||||||
LL_TIM_ETR_FILTER_FDIV4_N8,
|
|
||||||
LL_TIM_ETR_FILTER_FDIV8_N6,
|
|
||||||
LL_TIM_ETR_FILTER_FDIV8_N8,
|
|
||||||
LL_TIM_ETR_FILTER_FDIV16_N5,
|
|
||||||
LL_TIM_ETR_FILTER_FDIV16_N6,
|
|
||||||
LL_TIM_ETR_FILTER_FDIV16_N8,
|
|
||||||
LL_TIM_ETR_FILTER_FDIV32_N5,
|
|
||||||
LL_TIM_ETR_FILTER_FDIV32_N6,
|
|
||||||
LL_TIM_ETR_FILTER_FDIV32_N8,
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint32_t LL_SYSCFG_EXTI_PORTS[PORTS_COUNT] = {
|
const uint32_t LL_SYSCFG_EXTI_PORTS[PORTS_COUNT] = {
|
||||||
LL_SYSCFG_EXTI_PORTA,
|
LL_SYSCFG_EXTI_PORTA,
|
||||||
LL_SYSCFG_EXTI_PORTB,
|
LL_SYSCFG_EXTI_PORTB,
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ extern GPIO_TypeDef * const GPIO_PERIPHS[PORTS_COUNT];
|
|||||||
extern const uint32_t LL_GPIO_PINS[16];
|
extern const uint32_t LL_GPIO_PINS[16];
|
||||||
extern const uint32_t LL_EXTI_LINES[16];
|
extern const uint32_t LL_EXTI_LINES[16];
|
||||||
extern const uint32_t LL_ADC_SAMPLETIMES[8];
|
extern const uint32_t LL_ADC_SAMPLETIMES[8];
|
||||||
extern const uint32_t LL_TIM_IC_FILTERS[16];
|
|
||||||
extern const uint32_t LL_TIM_ETR_FILTERS[16];
|
|
||||||
|
|
||||||
static inline bool LL_DMA_IsActiveFlag_G(uint32_t isr_snapshot, uint8_t channel)
|
static inline bool LL_DMA_IsActiveFlag_G(uint32_t isr_snapshot, uint8_t channel)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,11 +26,16 @@ void LockJumper_Init(void)
|
|||||||
{
|
{
|
||||||
bool suc = true;
|
bool suc = true;
|
||||||
|
|
||||||
Resource pinrsc = rsc_portpin2rsc(LOCK_JUMPER_PORT, LOCK_JUMPER_PIN, &suc);
|
// Resolve and claim resource
|
||||||
|
Resource rsc = hw_pin2resource(LOCK_JUMPER_PORT, LOCK_JUMPER_PIN, &suc);
|
||||||
assert_param(suc);
|
assert_param(suc);
|
||||||
|
|
||||||
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, pinrsc));
|
assert_param(E_SUCCESS == rsc_claim(&UNIT_SYSTEM, rsc));
|
||||||
assert_param(hw_pinrsc2ll(pinrsc, &lock_periph, &lock_llpin));
|
|
||||||
|
// Resolve pin
|
||||||
|
lock_periph = hw_port2periph(LOCK_JUMPER_PORT, &suc);
|
||||||
|
lock_llpin = hw_pin2ll(LOCK_JUMPER_PIN, &suc);
|
||||||
|
assert_param(suc);
|
||||||
|
|
||||||
// Configure for input
|
// Configure for input
|
||||||
LL_GPIO_SetPinMode(lock_periph, lock_llpin, LL_GPIO_MODE_INPUT);
|
LL_GPIO_SetPinMode(lock_periph, lock_llpin, LL_GPIO_MODE_INPUT);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// 180 is normally enough if not doing extensive debug logging
|
// 180 is normally enough if not doing extensive debug logging
|
||||||
#define TSK_STACK_MSG 220 // TF message handler task stack size (all unit commands run on this thread)
|
#define TSK_STACK_MSG 200 // TF message handler task stack size (all unit commands run on this thread)
|
||||||
#define TSK_STACK_IDLE 64 //configMINIMAL_STACK_SIZE
|
#define TSK_STACK_IDLE 64 //configMINIMAL_STACK_SIZE
|
||||||
#define TSK_STACK_TIMERS 64 //configTIMER_TASK_STACK_DEPTH
|
#define TSK_STACK_TIMERS 64 //configTIMER_TASK_STACK_DEPTH
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define BULK_READ_BUF_LEN 256 // Buffer for TF bulk reads
|
#define BULK_READ_BUF_LEN 256 // Buffer for TF bulk reads
|
||||||
#define UNIT_TMP_LEN 256 // Buffer for internal unit operations
|
#define UNIT_TMP_LEN 512 // Buffer for internal unit operations
|
||||||
|
|
||||||
#define FLASH_SAVE_BUF_LEN 128 // Malloc'd buffer for saving to flash
|
#define FLASH_SAVE_BUF_LEN 128 // Malloc'd buffer for saving to flash
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
#define RX_QUE_CAPACITY 16 // TinyFrame rx queue size (64 bytes each)
|
#define RX_QUE_CAPACITY 16 // TinyFrame rx queue size (64 bytes each)
|
||||||
|
|
||||||
#define TF_MAX_PAYLOAD_RX 512 // TF max Rx payload
|
#define TF_MAX_PAYLOAD_RX 512 // TF max Rx payload
|
||||||
#define TF_SENDBUF_LEN 512 // TF transmit buffer (can be less than a full frame)
|
#define TF_SENDBUF_LEN 64 // TF transmit buffer (can be less than a full frame)
|
||||||
|
|
||||||
#define TF_MAX_ID_LST 4 // Frame ID listener count
|
#define TF_MAX_ID_LST 4 // Frame ID listener count
|
||||||
#define TF_MAX_TYPE_LST 6 // Frame Type listener count
|
#define TF_MAX_TYPE_LST 6 // Frame Type listener count
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
#define INI_VALUE_MAX 30 // Ini parser value buffer
|
#define INI_VALUE_MAX 30 // Ini parser value buffer
|
||||||
|
|
||||||
// -------- Stack buffers ----------
|
// -------- Stack buffers ----------
|
||||||
#define DBG_BUF_LEN 100 // Size of the snprintf buffer for debug messages
|
#define DBG_BUF_LEN 80 // Size of the snprintf buffer for debug messages
|
||||||
#define ERR_MSG_STR_LEN 64 // Error message buffer size
|
#define ERR_MSG_STR_LEN 64 // Error message buffer size
|
||||||
#define IWBUFFER_LEN 80 // Ini writer buffer for sprintf
|
#define IWBUFFER_LEN 80 // Ini writer buffer for sprintf
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
#include "debug_uart.h"
|
#include "debug_uart.h"
|
||||||
#include "irq_dispatcher.h"
|
#include "irq_dispatcher.h"
|
||||||
#include "timebase.h"
|
#include "timebase.h"
|
||||||
#include "watchdog.h"
|
|
||||||
|
|
||||||
void plat_init(void)
|
void plat_init(void)
|
||||||
{
|
{
|
||||||
@@ -40,6 +39,4 @@ void plat_init(void)
|
|||||||
settings_load(); // XXX maybe this should be moved to the main task
|
settings_load(); // XXX maybe this should be moved to the main task
|
||||||
|
|
||||||
comm_init();
|
comm_init();
|
||||||
|
|
||||||
wd_init();
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-10
@@ -17,10 +17,6 @@
|
|||||||
#include "units/test/unit_test.h"
|
#include "units/test/unit_test.h"
|
||||||
#include "units/usart/unit_usart.h"
|
#include "units/usart/unit_usart.h"
|
||||||
#include "units/spi/unit_spi.h"
|
#include "units/spi/unit_spi.h"
|
||||||
#include "units/sipo/unit_sipo.h"
|
|
||||||
#include "units/fcap/unit_fcap.h"
|
|
||||||
#include "units/touch/unit_touch.h"
|
|
||||||
#include "units/simple_pwm/unit_pwmdim.h"
|
|
||||||
#include "hw_utils.h"
|
#include "hw_utils.h"
|
||||||
|
|
||||||
void plat_init_resources(void)
|
void plat_init_resources(void)
|
||||||
@@ -90,10 +86,6 @@ void plat_init_resources(void)
|
|||||||
ureg_add_type(&UNIT_USART);
|
ureg_add_type(&UNIT_USART);
|
||||||
ureg_add_type(&UNIT_1WIRE);
|
ureg_add_type(&UNIT_1WIRE);
|
||||||
ureg_add_type(&UNIT_ADC);
|
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
|
// Free all present resources
|
||||||
{
|
{
|
||||||
@@ -102,7 +94,7 @@ void plat_init_resources(void)
|
|||||||
// rsc_free_range(NULL, R_COMP1, R_COMP2);
|
// rsc_free_range(NULL, R_COMP1, R_COMP2);
|
||||||
rsc_free(NULL, R_DAC1);
|
rsc_free(NULL, R_DAC1);
|
||||||
// rsc_free(NULL, R_HDMI_CEC);
|
// rsc_free(NULL, R_HDMI_CEC);
|
||||||
rsc_free(NULL, R_TSC);
|
// rsc_free(NULL, R_TSC);
|
||||||
rsc_free_range(NULL, R_I2C1, R_I2C2);
|
rsc_free_range(NULL, R_I2C1, R_I2C2);
|
||||||
// rsc_free_range(NULL, R_I2S1, R_I2S2);
|
// rsc_free_range(NULL, R_I2S1, R_I2S2);
|
||||||
rsc_free_range(NULL, R_SPI1, R_SPI2);
|
rsc_free_range(NULL, R_SPI1, R_SPI2);
|
||||||
@@ -158,7 +150,7 @@ void plat_init_resources(void)
|
|||||||
rsc_free_range(NULL, R_TIM1, R_TIM4);
|
rsc_free_range(NULL, R_TIM1, R_TIM4);
|
||||||
rsc_free_range(NULL, R_TIM6, R_TIM8);
|
rsc_free_range(NULL, R_TIM6, R_TIM8);
|
||||||
rsc_free_range(NULL, R_TIM15, R_TIM17);
|
rsc_free_range(NULL, R_TIM15, R_TIM17);
|
||||||
rsc_free(NULL, R_TSC);
|
// rsc_free(NULL, R_TSC);
|
||||||
rsc_free_range(NULL, R_USART1, R_USART5);
|
rsc_free_range(NULL, R_USART1, R_USART5);
|
||||||
|
|
||||||
rsc_free_range(NULL, R_PA0, R_PA15);
|
rsc_free_range(NULL, R_PA0, R_PA15);
|
||||||
|
|||||||
+8
-16
@@ -50,7 +50,13 @@ static inline void led_off(void)
|
|||||||
/** Set up the LED */
|
/** Set up the LED */
|
||||||
void Indicator_Init(void)
|
void Indicator_Init(void)
|
||||||
{
|
{
|
||||||
assert_param(E_SUCCESS == rsc_claim_pin(&UNIT_SYSTEM, STATUS_LED_PORT, STATUS_LED_PIN));
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set indicator ON */
|
/** Set indicator ON */
|
||||||
@@ -61,12 +67,6 @@ void Indicator_Effect(enum GEX_StatusIndicator indicator)
|
|||||||
led_on();
|
led_on();
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent the two disk ops interfering (happens in write-reload)
|
|
||||||
if (indicator == STATUS_DISK_BUSY && active_effect == STATUS_DISK_BUSY_SHORT) return;
|
|
||||||
if (indicator == STATUS_DISK_BUSY_SHORT && active_effect == STATUS_DISK_BUSY) return;
|
|
||||||
|
|
||||||
// TODO add some better protection against effect overlap?
|
|
||||||
|
|
||||||
active_effect = indicator;
|
active_effect = indicator;
|
||||||
effect_time = 0;
|
effect_time = 0;
|
||||||
}
|
}
|
||||||
@@ -125,15 +125,7 @@ void Indicator_Tick(void)
|
|||||||
active_effect = STATUS_NONE;
|
active_effect = STATUS_NONE;
|
||||||
}
|
}
|
||||||
else if (effect_time % 100 == 0) led_on();
|
else if (effect_time % 100 == 0) led_on();
|
||||||
else if (effect_time % 100 == 20) led_off();
|
else if (effect_time % 100 == 50) led_off();
|
||||||
}
|
|
||||||
else if (active_effect == STATUS_DISK_BUSY_SHORT) {
|
|
||||||
if (effect_time >= 200) {
|
|
||||||
led_off();
|
|
||||||
active_effect = STATUS_NONE;
|
|
||||||
}
|
|
||||||
else if (effect_time % 100 == 0) led_on();
|
|
||||||
else if (effect_time % 100 == 20) led_off();
|
|
||||||
}
|
}
|
||||||
else if (active_effect == STATUS_WELCOME) {
|
else if (active_effect == STATUS_WELCOME) {
|
||||||
if (effect_time == 0) led_on();
|
if (effect_time == 0) led_on();
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ enum GEX_StatusIndicator {
|
|||||||
STATUS_NONE = 0,
|
STATUS_NONE = 0,
|
||||||
STATUS_FAULT,
|
STATUS_FAULT,
|
||||||
STATUS_DISK_BUSY,
|
STATUS_DISK_BUSY,
|
||||||
STATUS_DISK_BUSY_SHORT,
|
|
||||||
STATUS_DISK_ATTACHED,
|
STATUS_DISK_ATTACHED,
|
||||||
STATUS_DISK_REMOVED,
|
STATUS_DISK_REMOVED,
|
||||||
STATUS_WELCOME,
|
STATUS_WELCOME,
|
||||||
|
|||||||
+7
-9
@@ -7,12 +7,10 @@
|
|||||||
|
|
||||||
// ---------------------------- HAL TIMEBASE -----------------------------
|
// ---------------------------- HAL TIMEBASE -----------------------------
|
||||||
|
|
||||||
#define TIMEBASE_TIMER TIM17
|
#define TIMEBASE_TIMER TIM14
|
||||||
|
|
||||||
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
|
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
|
||||||
{
|
{
|
||||||
// EDIT - used 17 instead because 14 was needed for fcap
|
|
||||||
|
|
||||||
// TIM14 is a simple 16-bit timer timer with no special features.
|
// TIM14 is a simple 16-bit timer timer with no special features.
|
||||||
// This makes it a good choice for the timebase generation. We set it to generate
|
// This makes it a good choice for the timebase generation. We set it to generate
|
||||||
// an interrupt every 1 ms
|
// an interrupt every 1 ms
|
||||||
@@ -21,9 +19,9 @@ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
|
|||||||
|
|
||||||
// - TIM14 is always up-counting
|
// - TIM14 is always up-counting
|
||||||
// - using APB1 clock
|
// - using APB1 clock
|
||||||
__HAL_RCC_TIM17_CLK_ENABLE();
|
__HAL_RCC_TIM14_CLK_ENABLE();
|
||||||
NVIC_SetPriority(TIM17_IRQn, TickPriority); // highest possible priority
|
NVIC_SetPriority(TIM14_IRQn, TickPriority); // highest possible priority
|
||||||
NVIC_EnableIRQ(TIM17_IRQn);
|
NVIC_EnableIRQ(TIM14_IRQn);
|
||||||
|
|
||||||
/* Compute TIM1 clock */
|
/* Compute TIM1 clock */
|
||||||
uint32_t uwTimclock = HAL_RCC_GetPCLK1Freq();
|
uint32_t uwTimclock = HAL_RCC_GetPCLK1Freq();
|
||||||
@@ -47,7 +45,7 @@ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
|
|||||||
static volatile uint32_t uwUptimeMs = 0;
|
static volatile uint32_t uwUptimeMs = 0;
|
||||||
|
|
||||||
/* TIMEBASE TIMER ISR */
|
/* TIMEBASE TIMER ISR */
|
||||||
void TIM17_IRQHandler(void)
|
void TIM14_IRQHandler(void)
|
||||||
{
|
{
|
||||||
uwUptimeMs++;
|
uwUptimeMs++;
|
||||||
LL_TIM_ClearFlag_UPDATE(TIMEBASE_TIMER);
|
LL_TIM_ClearFlag_UPDATE(TIMEBASE_TIMER);
|
||||||
@@ -91,10 +89,10 @@ uint64_t PTIM_GetMicrotime(void)
|
|||||||
uwMicros = TIMEBASE_TIMER->CNT;
|
uwMicros = TIMEBASE_TIMER->CNT;
|
||||||
uwMillis = uwUptimeMs;
|
uwMillis = uwUptimeMs;
|
||||||
|
|
||||||
if (LL_TIM_IsActiveFlag_UPDATE(TIMEBASE_TIMER)) {
|
if (LL_TIM_IsActiveFlag_UPDATE(TIM14)) {
|
||||||
// This means the timer has overflown after we disabled IRQ
|
// This means the timer has overflown after we disabled IRQ
|
||||||
// Use the last CNT value before the overflow
|
// Use the last CNT value before the overflow
|
||||||
uwMicros = TIMEBASE_TIMER->ARR; // this is 999us
|
uwMicros = TIM14->ARR; // this is 999us
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vPortExitCritical();
|
vPortExitCritical();
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
//
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
+2
-3
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "platform/lock_jumper.h"
|
#include "platform/lock_jumper.h"
|
||||||
#include "platform/watchdog.h"
|
|
||||||
#include "status_led.h"
|
#include "status_led.h"
|
||||||
#include "utils/stacksmon.h"
|
#include "utils/stacksmon.h"
|
||||||
#include "vfs/vfs_manager.h"
|
#include "vfs/vfs_manager.h"
|
||||||
@@ -13,6 +12,8 @@
|
|||||||
#include "usbd_msc.h"
|
#include "usbd_msc.h"
|
||||||
#include "task_main.h"
|
#include "task_main.h"
|
||||||
|
|
||||||
|
extern void plat_init(void);
|
||||||
|
|
||||||
/* TaskUsbEvent function */
|
/* TaskUsbEvent function */
|
||||||
void TaskMain(void const * argument)
|
void TaskMain(void const * argument)
|
||||||
{
|
{
|
||||||
@@ -46,8 +47,6 @@ void TaskMain(void const * argument)
|
|||||||
|
|
||||||
cnt++;
|
cnt++;
|
||||||
Indicator_Heartbeat();
|
Indicator_Heartbeat();
|
||||||
|
|
||||||
wd_restart();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if no message and it just timed out, go wait some more...
|
// if no message and it just timed out, go wait some more...
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "platform/watchdog.h"
|
|
||||||
#include "comm/messages.h"
|
#include "comm/messages.h"
|
||||||
#include "task_msg.h"
|
#include "task_msg.h"
|
||||||
|
|
||||||
@@ -86,9 +85,7 @@ void TaskMsgJob(const void *argument)
|
|||||||
#if CDC_LOOPBACK_TEST
|
#if CDC_LOOPBACK_TEST
|
||||||
TF_WriteImpl(comm, slot.msg.data, slot.msg.len);
|
TF_WriteImpl(comm, slot.msg.data, slot.msg.len);
|
||||||
#else
|
#else
|
||||||
wd_suspend();
|
|
||||||
TF_Accept(comm, slot.msg.data, slot.msg.len);
|
TF_Accept(comm, slot.msg.data, slot.msg.len);
|
||||||
wd_resume();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-1
@@ -14,6 +14,15 @@ error_t OW_preInit(Unit *unit)
|
|||||||
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
|
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
|
||||||
if (priv == NULL) return E_OUT_OF_MEM;
|
if (priv == NULL) return E_OUT_OF_MEM;
|
||||||
|
|
||||||
|
// the timer is not started until needed
|
||||||
|
priv->busyWaitTimer = xTimerCreate("1w_tim", // name
|
||||||
|
750, // interval (will be changed when starting it)
|
||||||
|
true, // periodic (we use this only for the polling variant, the one-shot will stop the timer in the CB)
|
||||||
|
unit, // user data
|
||||||
|
OW_TimerCb); // callback
|
||||||
|
|
||||||
|
if (priv->busyWaitTimer == NULL) return E_OUT_OF_MEM;
|
||||||
|
|
||||||
// some defaults
|
// some defaults
|
||||||
priv->pin_number = 0;
|
priv->pin_number = 0;
|
||||||
priv->port_name = 'A';
|
priv->port_name = 'A';
|
||||||
@@ -31,7 +40,7 @@ error_t OW_init(Unit *unit)
|
|||||||
// --- Parse config ---
|
// --- Parse config ---
|
||||||
priv->ll_pin = hw_pin2ll(priv->pin_number, &suc);
|
priv->ll_pin = hw_pin2ll(priv->pin_number, &suc);
|
||||||
priv->port = hw_port2periph(priv->port_name, &suc);
|
priv->port = hw_port2periph(priv->port_name, &suc);
|
||||||
Resource rsc = rsc_portpin2rsc(priv->port_name, priv->pin_number, &suc);
|
Resource rsc = hw_pin2resource(priv->port_name, priv->pin_number, &suc);
|
||||||
if (!suc) return E_BAD_CONFIG;
|
if (!suc) return E_BAD_CONFIG;
|
||||||
|
|
||||||
// --- Claim resources ---
|
// --- Claim resources ---
|
||||||
@@ -54,6 +63,9 @@ void OW_deInit(Unit *unit)
|
|||||||
// Release all resources
|
// Release all resources
|
||||||
rsc_teardown(unit);
|
rsc_teardown(unit);
|
||||||
|
|
||||||
|
// Delete the software timer
|
||||||
|
assert_param(pdPASS == xTimerDelete(priv->busyWaitTimer, 1000));
|
||||||
|
|
||||||
// Free memory
|
// Free memory
|
||||||
free_ck(unit->data);
|
free_ck(unit->data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ void OW_loadBinary(Unit *unit, PayloadParser *pp)
|
|||||||
|
|
||||||
priv->port_name = pp_char(pp);
|
priv->port_name = pp_char(pp);
|
||||||
priv->pin_number = pp_u8(pp);
|
priv->pin_number = pp_u8(pp);
|
||||||
priv->parasitic = pp_bool(pp);
|
if (version >= 1) {
|
||||||
|
priv->parasitic = pp_bool(pp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Write to a binary buffer for storing in Flash */
|
/** Write to a binary buffer for storing in Flash */
|
||||||
@@ -26,7 +28,7 @@ void OW_writeBinary(Unit *unit, PayloadBuilder *pb)
|
|||||||
{
|
{
|
||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
pb_u8(pb, 0); // version
|
pb_u8(pb, 1); // version
|
||||||
|
|
||||||
pb_char(pb, priv->port_name);
|
pb_char(pb, priv->port_name);
|
||||||
pb_u8(pb, priv->pin_number);
|
pb_u8(pb, priv->pin_number);
|
||||||
@@ -42,10 +44,10 @@ error_t OW_loadIni(Unit *unit, const char *key, const char *value)
|
|||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
if (streq(key, "pin")) {
|
if (streq(key, "pin")) {
|
||||||
suc = cfg_portpin_parse(value, &priv->port_name, &priv->pin_number);
|
suc = parse_pin(value, &priv->port_name, &priv->pin_number);
|
||||||
}
|
}
|
||||||
else if (streq(key, "parasitic")) {
|
else if (streq(key, "parasitic")) {
|
||||||
priv->parasitic = cfg_bool_parse(value, &suc);
|
priv->parasitic = str_parse_yn(value, &suc);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return E_BAD_KEY;
|
return E_BAD_KEY;
|
||||||
@@ -64,5 +66,5 @@ void OW_writeIni(Unit *unit, IniWriter *iw)
|
|||||||
iw_entry(iw, "pin", "%c%d", priv->port_name, priv->pin_number);
|
iw_entry(iw, "pin", "%c%d", priv->port_name, priv->pin_number);
|
||||||
|
|
||||||
iw_comment(iw, "Parasitic (bus-powered) mode");
|
iw_comment(iw, "Parasitic (bus-powered) mode");
|
||||||
iw_entry_s(iw, "parasitic", str_yn(priv->parasitic));
|
iw_entry(iw, "parasitic", str_yn(priv->parasitic));
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-14
@@ -38,13 +38,12 @@ static void OW_TimerRespCb(Job *job)
|
|||||||
*
|
*
|
||||||
* @param xTimer
|
* @param xTimer
|
||||||
*/
|
*/
|
||||||
void OW_tickHandler(Unit *unit)
|
void OW_TimerCb(TimerHandle_t xTimer)
|
||||||
{
|
{
|
||||||
|
Unit *unit = pvTimerGetTimerID(xTimer);
|
||||||
|
assert_param(unit);
|
||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
if(!priv->busy) {
|
assert_param(priv->busy);
|
||||||
dbg("ow tick should be disabled now!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->parasitic) {
|
if (priv->parasitic) {
|
||||||
// this is the end of the 750ms measurement time
|
// this is the end of the 750ms measurement time
|
||||||
@@ -57,8 +56,7 @@ void OW_tickHandler(Unit *unit)
|
|||||||
|
|
||||||
uint32_t time = PTIM_GetTime();
|
uint32_t time = PTIM_GetTime();
|
||||||
if (time - priv->busyStart > 1000) {
|
if (time - priv->busyStart > 1000) {
|
||||||
unit->tick_interval = 0;
|
xTimerStop(xTimer, 100);
|
||||||
unit->_tick_cnt = 0;
|
|
||||||
|
|
||||||
Job j = {
|
Job j = {
|
||||||
.unit = unit,
|
.unit = unit,
|
||||||
@@ -71,8 +69,7 @@ void OW_tickHandler(Unit *unit)
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
halt_ok:
|
halt_ok:
|
||||||
unit->tick_interval = 0;
|
xTimerStop(xTimer, 100);
|
||||||
unit->_tick_cnt = 0;
|
|
||||||
|
|
||||||
Job j = {
|
Job j = {
|
||||||
.unit = unit,
|
.unit = unit,
|
||||||
@@ -82,6 +79,7 @@ halt_ok:
|
|||||||
scheduleJob(&j);
|
scheduleJob(&j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
enum PinCmd_ {
|
enum PinCmd_ {
|
||||||
CMD_CHECK_PRESENCE = 0, // simply tests that any devices are attached
|
CMD_CHECK_PRESENCE = 0, // simply tests that any devices are attached
|
||||||
CMD_SEARCH_ADDR = 1, // perform a scan of the bus, retrieving all found device ROMs
|
CMD_SEARCH_ADDR = 1, // perform a scan of the bus, retrieving all found device ROMs
|
||||||
@@ -122,13 +120,13 @@ static error_t OW_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Pay
|
|||||||
*/
|
*/
|
||||||
case CMD_POLL_FOR_1:
|
case CMD_POLL_FOR_1:
|
||||||
// This can't be exposed via the UU API, due to being async
|
// This can't be exposed via the UU API, due to being async
|
||||||
unit->_tick_cnt = 0;
|
|
||||||
unit->tick_interval = 750;
|
|
||||||
if (priv->parasitic) {
|
if (priv->parasitic) {
|
||||||
unit->tick_interval = 750;
|
assert_param(pdPASS == xTimerChangePeriod(priv->busyWaitTimer, 750, 100));
|
||||||
} else {
|
} else {
|
||||||
unit->tick_interval = 10;
|
// every 10 ticks
|
||||||
|
assert_param(pdPASS == xTimerChangePeriod(priv->busyWaitTimer, 10, 100));
|
||||||
}
|
}
|
||||||
|
assert_param(pdPASS == xTimerStart(priv->busyWaitTimer, 100));
|
||||||
priv->busy = true;
|
priv->busy = true;
|
||||||
priv->busyStart = PTIM_GetTime();
|
priv->busyStart = PTIM_GetTime();
|
||||||
priv->busyRequestId = frame_id;
|
priv->busyRequestId = frame_id;
|
||||||
@@ -244,5 +242,4 @@ const UnitDriver UNIT_1WIRE = {
|
|||||||
.deInit = OW_deInit,
|
.deInit = OW_deInit,
|
||||||
// Function
|
// Function
|
||||||
.handleRequest = OW_handleRequest,
|
.handleRequest = OW_handleRequest,
|
||||||
.updateTick = OW_tickHandler,
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,8 +40,7 @@ static void UADC_JobSendBlockChunk(Job *job)
|
|||||||
.len = (TF_LEN) (1 /*seq*/ + count * sizeof(uint16_t)),
|
.len = (TF_LEN) (1 /*seq*/ + count * sizeof(uint16_t)),
|
||||||
.type = type,
|
.type = type,
|
||||||
};
|
};
|
||||||
|
TF_Respond_Multipart(comm, &msg);
|
||||||
assert_param(true == TF_Respond_Multipart(comm, &msg));
|
|
||||||
TF_Multipart_Payload(comm, &priv->stream_serial, 1);
|
TF_Multipart_Payload(comm, &priv->stream_serial, 1);
|
||||||
TF_Multipart_Payload(comm, (uint8_t *) (priv->dma_buffer + start), count * sizeof(uint16_t));
|
TF_Multipart_Payload(comm, (uint8_t *) (priv->dma_buffer + start), count * sizeof(uint16_t));
|
||||||
TF_Multipart_Close(comm);
|
TF_Multipart_Close(comm);
|
||||||
@@ -172,7 +171,7 @@ static void handle_httc(Unit *unit, bool tc)
|
|||||||
const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP;
|
const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP;
|
||||||
|
|
||||||
if (ht) {
|
if (ht) {
|
||||||
end = (priv->buf_itemcount >> 1); // div2
|
end = (priv->buf_itemcount / 2);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
end = priv->buf_itemcount;
|
end = priv->buf_itemcount;
|
||||||
@@ -235,7 +234,7 @@ static void handle_httc(Unit *unit, bool tc)
|
|||||||
priv->stream_startpos = 0;
|
priv->stream_startpos = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
priv->stream_startpos = priv->buf_itemcount >> 1; // div2
|
priv->stream_startpos = priv->buf_itemcount / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,7 +289,7 @@ void UADC_DMA_Handler(void *arg)
|
|||||||
const bool m_stream = priv->opmode == ADC_OPMODE_STREAM;
|
const bool m_stream = priv->opmode == ADC_OPMODE_STREAM;
|
||||||
const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP;
|
const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP;
|
||||||
if (m_trigd || m_stream || m_fixcpt) {
|
if (m_trigd || m_stream || m_fixcpt) {
|
||||||
const uint32_t half = (uint32_t) (priv->buf_itemcount >> 1); // div2
|
const uint32_t half = (uint32_t) (priv->buf_itemcount / 2);
|
||||||
if (ht && tc) {
|
if (ht && tc) {
|
||||||
// dual event interrupt - may happen if we missed both and they were pending after
|
// dual event interrupt - may happen if we missed both and they were pending after
|
||||||
// interrupts became enabled again (this can happen due to the EOS or other higher prio irq's)
|
// interrupts became enabled again (this can happen due to the EOS or other higher prio irq's)
|
||||||
@@ -337,10 +336,8 @@ void UADC_ADC_EOS_Handler(void *arg)
|
|||||||
if (priv->opmode == ADC_OPMODE_UNINIT) return;
|
if (priv->opmode == ADC_OPMODE_UNINIT) return;
|
||||||
|
|
||||||
// Wait for the DMA to complete copying the last sample
|
// Wait for the DMA to complete copying the last sample
|
||||||
uint32_t dmapos = DMA_POS(priv);
|
uint32_t dmapos;
|
||||||
if ((DMA_POS(priv) % priv->nb_channels) != 0) {
|
hw_wait_while((dmapos = DMA_POS(priv)) % priv->nb_channels != 0, 100); // XXX this could be changed to reading it from the DR instead
|
||||||
hw_wait_while((dmapos = DMA_POS(priv)) % priv->nb_channels != 0, 100); // XXX this could be changed to reading it from the DR instead
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t sample_pos;
|
uint32_t sample_pos;
|
||||||
if (dmapos == 0) {
|
if (dmapos == 0) {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ error_t UADC_SetSampleRate(Unit *unit, uint32_t hertz)
|
|||||||
|
|
||||||
uint16_t presc;
|
uint16_t presc;
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
if (!hw_solve_timer(PLAT_APB1_HZ, hertz, true, &presc, &count, &priv->real_frequency)) {
|
if (!solve_timer(PLAT_APB1_HZ, hertz, true, &presc, &count, &priv->real_frequency)) {
|
||||||
dbg("Failed to resolve timer params.");
|
dbg("Failed to resolve timer params.");
|
||||||
return E_BAD_VALUE;
|
return E_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -48,20 +48,20 @@ error_t UADC_loadIni(Unit *unit, const char *key, const char *value)
|
|||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
if (streq(key, "channels")) {
|
if (streq(key, "channels")) {
|
||||||
priv->cfg.channels = cfg_pinmask_parse_32(value, &suc);
|
priv->cfg.channels = parse_pinmask(value, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "sample_time")) {
|
else if (streq(key, "sample_time")) {
|
||||||
priv->cfg.sample_time = cfg_u8_parse(value, &suc);
|
priv->cfg.sample_time = (uint8_t) avr_atoi(value);
|
||||||
if (priv->cfg.sample_time > 7) return E_BAD_VALUE;
|
if (priv->cfg.sample_time > 7) return E_BAD_VALUE;
|
||||||
}
|
}
|
||||||
else if (streq(key, "frequency")) {
|
else if (streq(key, "frequency")) {
|
||||||
priv->cfg.frequency = cfg_u32_parse(value, &suc);
|
priv->cfg.frequency = (uint32_t) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "buffer_size")) {
|
else if (streq(key, "buffer_size")) {
|
||||||
priv->cfg.buffer_size = cfg_u32_parse(value, &suc);
|
priv->cfg.buffer_size = (uint32_t) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "avg_factor")) {
|
else if (streq(key, "avg_factor")) {
|
||||||
priv->cfg.averaging_factor = cfg_u16_parse(value, &suc);
|
priv->cfg.averaging_factor = (uint16_t) avr_atoi(value);
|
||||||
if (priv->cfg.averaging_factor > 1000) return E_BAD_VALUE;
|
if (priv->cfg.averaging_factor > 1000) return E_BAD_VALUE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -80,14 +80,14 @@ void UADC_writeIni(Unit *unit, IniWriter *iw)
|
|||||||
iw_comment(iw, "Enabled channels, comma separated");
|
iw_comment(iw, "Enabled channels, comma separated");
|
||||||
iw_comment(iw, " 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17");
|
iw_comment(iw, " 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17");
|
||||||
iw_comment(iw, "A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 C0 C1 C2 C3 C4 C5 Tsens Vref");
|
iw_comment(iw, "A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 C0 C1 C2 C3 C4 C5 Tsens Vref");
|
||||||
iw_entry_s(iw, "channels", cfg_pinmask_encode(priv->cfg.channels, unit_tmp512, true));
|
iw_entry(iw, "channels", "%s", pinmask2str_up(priv->cfg.channels, unit_tmp512));
|
||||||
|
|
||||||
iw_cmt_newline(iw);
|
iw_cmt_newline(iw);
|
||||||
iw_comment(iw, "Sampling time (0-7)");
|
iw_comment(iw, "Sampling time (0-7)");
|
||||||
iw_entry_d(iw, "sample_time", priv->cfg.sample_time);
|
iw_entry(iw, "sample_time", "%d", (int)priv->cfg.sample_time);
|
||||||
|
|
||||||
iw_comment(iw, "Sampling frequency (Hz)");
|
iw_comment(iw, "Sampling frequency (Hz)");
|
||||||
iw_entry_d(iw, "frequency", priv->cfg.frequency);
|
iw_entry(iw, "frequency", "%d", (int)priv->cfg.frequency);
|
||||||
|
|
||||||
iw_cmt_newline(iw);
|
iw_cmt_newline(iw);
|
||||||
iw_comment(iw, "Sample buffer size");
|
iw_comment(iw, "Sample buffer size");
|
||||||
@@ -95,12 +95,12 @@ void UADC_writeIni(Unit *unit, IniWriter *iw)
|
|||||||
iw_comment(iw, "- defines the maximum pre-trigger size (divide by # of channels)");
|
iw_comment(iw, "- defines the maximum pre-trigger size (divide by # of channels)");
|
||||||
iw_comment(iw, "- captured data is sent in half-buffer chunks");
|
iw_comment(iw, "- captured data is sent in half-buffer chunks");
|
||||||
iw_comment(iw, "- buffer overrun aborts the data capture");
|
iw_comment(iw, "- buffer overrun aborts the data capture");
|
||||||
iw_entry_d(iw, "buffer_size", priv->cfg.buffer_size);
|
iw_entry(iw, "buffer_size", "%d", (int)priv->cfg.buffer_size);
|
||||||
|
|
||||||
iw_cmt_newline(iw);
|
iw_cmt_newline(iw);
|
||||||
iw_comment(iw, "Exponential averaging coefficient (permil, range 0-1000 ~ 0.000-1.000)");
|
iw_comment(iw, "Exponential averaging coefficient (permil, range 0-1000 ~ 0.000-1.000)");
|
||||||
iw_comment(iw, "- used formula: y[t]=(1-k)*y[t-1]+k*u[t]");
|
iw_comment(iw, "- used formula: y[t]=(1-k)*y[t-1]+k*u[t]");
|
||||||
iw_comment(iw, "- not available when a capture is running");
|
iw_comment(iw, "- not available when a capture is running");
|
||||||
iw_entry_d(iw, "avg_factor", priv->cfg.averaging_factor);
|
iw_entry(iw, "avg_factor", "%d", priv->cfg.averaging_factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,10 +20,15 @@ void DIn_loadBinary(Unit *unit, PayloadParser *pp)
|
|||||||
priv->pins = pp_u16(pp);
|
priv->pins = pp_u16(pp);
|
||||||
priv->pulldown = pp_u16(pp);
|
priv->pulldown = pp_u16(pp);
|
||||||
priv->pullup = pp_u16(pp);
|
priv->pullup = pp_u16(pp);
|
||||||
priv->trig_rise = pp_u16(pp);
|
|
||||||
priv->trig_fall = pp_u16(pp);
|
if (version >= 1) {
|
||||||
priv->trig_holdoff = pp_u16(pp);
|
priv->trig_rise = pp_u16(pp);
|
||||||
priv->def_auto = 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 */
|
/** Write to a binary buffer for storing in Flash */
|
||||||
@@ -31,7 +36,7 @@ void DIn_writeBinary(Unit *unit, PayloadBuilder *pb)
|
|||||||
{
|
{
|
||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
pb_u8(pb, 0); // version
|
pb_u8(pb, 2); // version
|
||||||
|
|
||||||
pb_char(pb, priv->port_name);
|
pb_char(pb, priv->port_name);
|
||||||
pb_u16(pb, priv->pins);
|
pb_u16(pb, priv->pins);
|
||||||
@@ -52,28 +57,28 @@ error_t DIn_loadIni(Unit *unit, const char *key, const char *value)
|
|||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
if (streq(key, "port")) {
|
if (streq(key, "port")) {
|
||||||
suc = cfg_port_parse(value, &priv->port_name);
|
suc = parse_port_name(value, &priv->port_name);
|
||||||
}
|
}
|
||||||
else if (streq(key, "pins")) {
|
else if (streq(key, "pins")) {
|
||||||
priv->pins = cfg_pinmask_parse(value, &suc);
|
priv->pins = parse_pinmask(value, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "pull-up")) {
|
else if (streq(key, "pull-up")) {
|
||||||
priv->pullup = cfg_pinmask_parse(value, &suc);
|
priv->pullup = parse_pinmask(value, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "pull-down")) {
|
else if (streq(key, "pull-down")) {
|
||||||
priv->pulldown = cfg_pinmask_parse(value, &suc);
|
priv->pulldown = parse_pinmask(value, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "trig-rise")) {
|
else if (streq(key, "trig-rise")) {
|
||||||
priv->trig_rise = cfg_pinmask_parse(value, &suc);
|
priv->trig_rise = parse_pinmask(value, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "trig-fall")) {
|
else if (streq(key, "trig-fall")) {
|
||||||
priv->trig_fall = cfg_pinmask_parse(value, &suc);
|
priv->trig_fall = parse_pinmask(value, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "auto-trigger")) {
|
else if (streq(key, "auto-trigger")) {
|
||||||
priv->def_auto = cfg_pinmask_parse(value, &suc);
|
priv->def_auto = parse_pinmask(value, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "hold-off")) {
|
else if (streq(key, "hold-off")) {
|
||||||
priv->trig_holdoff = cfg_u16_parse(value, &suc);
|
priv->trig_holdoff = (uint16_t) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return E_BAD_KEY;
|
return E_BAD_KEY;
|
||||||
@@ -92,24 +97,24 @@ void DIn_writeIni(Unit *unit, IniWriter *iw)
|
|||||||
iw_entry(iw, "port", "%c", priv->port_name);
|
iw_entry(iw, "port", "%c", priv->port_name);
|
||||||
|
|
||||||
iw_comment(iw, "Pins (comma separated, supports ranges)");
|
iw_comment(iw, "Pins (comma separated, supports ranges)");
|
||||||
iw_entry_s(iw, "pins", cfg_pinmask_encode(priv->pins, unit_tmp512, 0));
|
iw_entry(iw, "pins", "%s", pinmask2str(priv->pins, unit_tmp512));
|
||||||
|
|
||||||
iw_comment(iw, "Pins with pull-up");
|
iw_comment(iw, "Pins with pull-up");
|
||||||
iw_entry_s(iw, "pull-up", cfg_pinmask_encode(priv->pullup, unit_tmp512, 0));
|
iw_entry(iw, "pull-up", "%s", pinmask2str(priv->pullup, unit_tmp512));
|
||||||
|
|
||||||
iw_comment(iw, "Pins with pull-down");
|
iw_comment(iw, "Pins with pull-down");
|
||||||
iw_entry_s(iw, "pull-down", cfg_pinmask_encode(priv->pulldown, unit_tmp512, 0));
|
iw_entry(iw, "pull-down", "%s", pinmask2str(priv->pulldown, unit_tmp512));
|
||||||
|
|
||||||
iw_cmt_newline(iw);
|
iw_cmt_newline(iw);
|
||||||
iw_comment(iw, "Trigger pins activated by rising/falling edge");
|
iw_comment(iw, "Trigger pins activated by rising/falling edge");
|
||||||
iw_entry_s(iw, "trig-rise", cfg_pinmask_encode(priv->trig_rise, unit_tmp512, 0));
|
iw_entry(iw, "trig-rise", "%s", pinmask2str(priv->trig_rise, unit_tmp512));
|
||||||
iw_entry_s(iw, "trig-fall", cfg_pinmask_encode(priv->trig_fall, unit_tmp512, 0));
|
iw_entry(iw, "trig-fall", "%s", pinmask2str(priv->trig_fall, unit_tmp512));
|
||||||
|
|
||||||
iw_comment(iw, "Trigger pins auto-armed by default");
|
iw_comment(iw, "Trigger pins auto-armed by default");
|
||||||
iw_entry_s(iw, "auto-trigger", cfg_pinmask_encode(priv->def_auto, unit_tmp512, 0));
|
iw_entry(iw, "auto-trigger", "%s", pinmask2str(priv->def_auto, unit_tmp512));
|
||||||
|
|
||||||
iw_comment(iw, "Triggers hold-off time (ms)");
|
iw_comment(iw, "Triggers hold-off time (ms)");
|
||||||
iw_entry_d(iw, "hold-off", priv->trig_holdoff);
|
iw_entry(iw, "hold-off", "%d", (int)priv->trig_holdoff);
|
||||||
|
|
||||||
#if PLAT_NO_FLOATING_INPUTS
|
#if PLAT_NO_FLOATING_INPUTS
|
||||||
iw_comment(iw, "NOTE: Pins use pull-up by default.\r\n");
|
iw_comment(iw, "NOTE: Pins use pull-up by default.\r\n");
|
||||||
|
|||||||
@@ -9,56 +9,80 @@
|
|||||||
#define DOUT_INTERNAL
|
#define DOUT_INTERNAL
|
||||||
#include "_dout_internal.h"
|
#include "_dout_internal.h"
|
||||||
|
|
||||||
error_t UU_DOut_Write(Unit *unit, uint16_t packed)
|
error_t UU_DOut_Spread(Unit *unit, uint16_t packed, uint16_t *spread_out)
|
||||||
{
|
{
|
||||||
CHECK_TYPE(unit, &UNIT_DOUT);
|
CHECK_TYPE(unit, &UNIT_DOUT);
|
||||||
|
*spread_out = UU_DOut_Spread_HS(unit, packed);
|
||||||
|
return E_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t UU_DOut_Spread_HS(Unit *unit, uint16_t packed)
|
||||||
|
{
|
||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
uint16_t mask = priv->pins;
|
uint16_t mask = priv->pins;
|
||||||
uint16_t spread = pinmask_spread(packed, mask);
|
return pinmask_spread(packed, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UU_DOut_Write_HS(Unit *unit, uint16_t spread)
|
||||||
|
{
|
||||||
|
struct priv *priv = unit->data;
|
||||||
|
uint16_t mask = priv->pins;
|
||||||
uint16_t set = spread;
|
uint16_t set = spread;
|
||||||
uint16_t reset = ((~spread) & mask);
|
uint16_t reset = ((~spread) & mask);
|
||||||
priv->port->BSRR = set | (reset << 16);
|
priv->port->BSRR = set | (reset << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UU_DOut_Set_HS(Unit *unit, uint16_t spread)
|
||||||
|
{
|
||||||
|
struct priv *priv = unit->data;
|
||||||
|
priv->port->BSRR = spread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UU_DOut_Clear_HS(Unit *unit, uint16_t spread)
|
||||||
|
{
|
||||||
|
struct priv *priv = unit->data;
|
||||||
|
priv->port->BSRR = (spread<<16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UU_DOut_Toggle_HS(Unit *unit, uint16_t spread)
|
||||||
|
{
|
||||||
|
struct priv *priv = unit->data;
|
||||||
|
uint16_t mask = priv->pins;
|
||||||
|
uint16_t flipped = (uint16_t) (~priv->port->ODR) & mask;
|
||||||
|
uint16_t set = flipped & spread;
|
||||||
|
uint16_t reset = ((~flipped) & mask) & spread;
|
||||||
|
priv->port->BSRR = set | (reset<<16);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t UU_DOut_Write(Unit *unit, uint16_t packed)
|
||||||
|
{
|
||||||
|
CHECK_TYPE(unit, &UNIT_DOUT);
|
||||||
|
const uint16_t spread = UU_DOut_Spread_HS(unit, packed);
|
||||||
|
UU_DOut_Write_HS(unit, spread);
|
||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t UU_DOut_Set(Unit *unit, uint16_t packed)
|
error_t UU_DOut_Set(Unit *unit, uint16_t packed)
|
||||||
{
|
{
|
||||||
CHECK_TYPE(unit, &UNIT_DOUT);
|
CHECK_TYPE(unit, &UNIT_DOUT);
|
||||||
|
const uint16_t spread = UU_DOut_Spread_HS(unit, packed);
|
||||||
struct priv *priv = unit->data;
|
UU_DOut_Set_HS(unit, spread);
|
||||||
uint16_t mask = priv->pins;
|
|
||||||
uint16_t spread = pinmask_spread(packed, mask);
|
|
||||||
|
|
||||||
priv->port->BSRR = spread;
|
|
||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t UU_DOut_Clear(Unit *unit, uint16_t packed)
|
error_t UU_DOut_Clear(Unit *unit, uint16_t packed)
|
||||||
{
|
{
|
||||||
CHECK_TYPE(unit, &UNIT_DOUT);
|
CHECK_TYPE(unit, &UNIT_DOUT);
|
||||||
|
const uint16_t spread = UU_DOut_Spread_HS(unit, packed);
|
||||||
struct priv *priv = unit->data;
|
UU_DOut_Clear_HS(unit, spread);
|
||||||
uint16_t mask = priv->pins;
|
|
||||||
uint16_t spread = pinmask_spread(packed, mask);
|
|
||||||
|
|
||||||
priv->port->BSRR = (spread<<16);
|
|
||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t UU_DOut_Toggle(Unit *unit, uint16_t packed)
|
error_t UU_DOut_Toggle(Unit *unit, uint16_t packed)
|
||||||
{
|
{
|
||||||
CHECK_TYPE(unit, &UNIT_DOUT);
|
CHECK_TYPE(unit, &UNIT_DOUT);
|
||||||
|
const uint16_t spread = UU_DOut_Spread_HS(unit, packed);
|
||||||
struct priv *priv = unit->data;
|
UU_DOut_Toggle_HS(unit, spread);
|
||||||
uint16_t mask = priv->pins;
|
|
||||||
uint16_t spread = pinmask_spread(packed, mask);
|
|
||||||
|
|
||||||
uint16_t flipped = (uint16_t) (~priv->port->ODR) & mask;
|
|
||||||
uint16_t set = flipped & spread;
|
|
||||||
uint16_t reset = ((~flipped) & mask) & spread;
|
|
||||||
priv->port->BSRR = set | (reset<<16);
|
|
||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,16 +44,16 @@ error_t DOut_loadIni(Unit *unit, const char *key, const char *value)
|
|||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
if (streq(key, "port")) {
|
if (streq(key, "port")) {
|
||||||
suc = cfg_port_parse(value, &priv->port_name);
|
suc = parse_port_name(value, &priv->port_name);
|
||||||
}
|
}
|
||||||
else if (streq(key, "pins")) {
|
else if (streq(key, "pins")) {
|
||||||
priv->pins = cfg_pinmask_parse(value, &suc);
|
priv->pins = parse_pinmask(value, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "initial")) {
|
else if (streq(key, "initial")) {
|
||||||
priv->initial = cfg_pinmask_parse(value, &suc);
|
priv->initial = parse_pinmask(value, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "open-drain")) {
|
else if (streq(key, "open-drain")) {
|
||||||
priv->open_drain = cfg_pinmask_parse(value, &suc);
|
priv->open_drain = parse_pinmask(value, &suc);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return E_BAD_KEY;
|
return E_BAD_KEY;
|
||||||
@@ -72,11 +72,11 @@ void DOut_writeIni(Unit *unit, IniWriter *iw)
|
|||||||
iw_entry(iw, "port", "%c", priv->port_name);
|
iw_entry(iw, "port", "%c", priv->port_name);
|
||||||
|
|
||||||
iw_comment(iw, "Pins (comma separated, supports ranges)");
|
iw_comment(iw, "Pins (comma separated, supports ranges)");
|
||||||
iw_entry_s(iw, "pins", cfg_pinmask_encode(priv->pins, unit_tmp512, 0));
|
iw_entry(iw, "pins", "%s", pinmask2str(priv->pins, unit_tmp512));
|
||||||
|
|
||||||
iw_comment(iw, "Initially high pins");
|
iw_comment(iw, "Initially high pins");
|
||||||
iw_entry_s(iw, "initial", cfg_pinmask_encode(priv->initial, unit_tmp512, 0));
|
iw_entry(iw, "initial", "%s", pinmask2str(priv->initial, unit_tmp512));
|
||||||
|
|
||||||
iw_comment(iw, "Open-drain pins");
|
iw_comment(iw, "Open-drain pins");
|
||||||
iw_entry_s(iw, "open-drain", cfg_pinmask_encode(priv->open_drain, unit_tmp512, 0));
|
iw_entry(iw, "open-drain", "%s", pinmask2str(priv->open_drain, unit_tmp512));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,4 +56,17 @@ error_t UU_DOut_Toggle(Unit *unit, uint16_t packed);
|
|||||||
*/
|
*/
|
||||||
error_t UU_DOut_GetPinCount(Unit *unit, uint8_t *count);
|
error_t UU_DOut_GetPinCount(Unit *unit, uint8_t *count);
|
||||||
|
|
||||||
|
// --- high-speed variants, without type checking and spreading ---
|
||||||
|
|
||||||
|
/** Spread a packed word */
|
||||||
|
error_t UU_DOut_Spread(Unit *unit, uint16_t packed, uint16_t *spread_out);
|
||||||
|
|
||||||
|
// those are like the normal functions, but without driver checking and other verification (where applicable)
|
||||||
|
// also the argument must be already spread, which saves time if the same value is used repeatedly
|
||||||
|
uint16_t UU_DOut_Spread_HS(Unit *unit, uint16_t packed);
|
||||||
|
void UU_DOut_Write_HS(Unit *unit, uint16_t spread);
|
||||||
|
void UU_DOut_Set_HS(Unit *unit, uint16_t spread);
|
||||||
|
void UU_DOut_Clear_HS(Unit *unit, uint16_t spread);
|
||||||
|
void UU_DOut_Toggle_HS(Unit *unit, uint16_t spread);
|
||||||
|
|
||||||
#endif //U_DOUT_H
|
#endif //U_DOUT_H
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
#include "unit_fcap.h"
|
|
||||||
|
|
||||||
#define FCAP_INTERNAL
|
|
||||||
#include "_fcap_internal.h"
|
|
||||||
|
|
||||||
@@ -1,462 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/20.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <stm32f072xb.h>
|
|
||||||
#include "platform.h"
|
|
||||||
|
|
||||||
#define FCAP_INTERNAL
|
|
||||||
#include "_fcap_internal.h"
|
|
||||||
|
|
||||||
static void UFCAP_StopMeasurement(Unit *unit);
|
|
||||||
static void UFCAP_ConfigureForIndirectCapture(Unit *unit);
|
|
||||||
static void UFCAP_ConfigureForDirectCapture(Unit *unit, uint16_t msec);
|
|
||||||
static void UFCAP_ConfigureForFreeCapture(Unit *unit);
|
|
||||||
|
|
||||||
uint32_t UFCAP_GetFreeCounterValue(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv * const priv = unit->data;
|
|
||||||
TIM_TypeDef * const TIMx = priv->TIMx;
|
|
||||||
return TIMx->CNT;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t UFCAP_FreeCounterClear(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv * const priv = unit->data;
|
|
||||||
TIM_TypeDef * const TIMx = priv->TIMx;
|
|
||||||
|
|
||||||
// this isn't perfect, we can miss one clock
|
|
||||||
// but it's probably the best we can do here ...
|
|
||||||
vPortEnterCritical();
|
|
||||||
uint32_t val = TIMx->CNT;
|
|
||||||
TIMx->CNT = 0;
|
|
||||||
vPortExitCritical();
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void UFCAP_IndirectBurstReportJob(Job *job)
|
|
||||||
{
|
|
||||||
Unit *unit = job->unit;
|
|
||||||
struct priv * const priv = unit->data;
|
|
||||||
|
|
||||||
uint8_t buf[20];
|
|
||||||
PayloadBuilder pb = pb_start(buf, 20, NULL);
|
|
||||||
|
|
||||||
pb_u16(&pb, PLAT_AHB_MHZ);
|
|
||||||
pb_u16(&pb, priv->ind_burst.n_count);
|
|
||||||
pb_u64(&pb, priv->ind_burst.period_acu);
|
|
||||||
pb_u64(&pb, priv->ind_burst.ontime_acu);
|
|
||||||
|
|
||||||
assert_param(pb.ok);
|
|
||||||
|
|
||||||
com_respond_pb(priv->request_id, MSG_SUCCESS, &pb);
|
|
||||||
|
|
||||||
// timer is already stopped, now in OPMODE_BUSY
|
|
||||||
priv->opmode = OPMODE_IDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void UFCAP_SinglePulseReportJob(Job *job)
|
|
||||||
{
|
|
||||||
Unit *unit = job->unit;
|
|
||||||
struct priv * const priv = unit->data;
|
|
||||||
|
|
||||||
uint8_t buf[6];
|
|
||||||
PayloadBuilder pb = pb_start(buf, 6, NULL);
|
|
||||||
|
|
||||||
pb_u16(&pb, PLAT_AHB_MHZ);
|
|
||||||
pb_u32(&pb, job->data1);
|
|
||||||
assert_param(pb.ok);
|
|
||||||
|
|
||||||
com_respond_pb(priv->request_id, MSG_SUCCESS, &pb);
|
|
||||||
|
|
||||||
// timer is already stopped, now in OPMODE_BUSY
|
|
||||||
priv->opmode = OPMODE_IDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Count is passed in data1
|
|
||||||
* @param job
|
|
||||||
*/
|
|
||||||
static void UFCAP_DirectBurstReportJob(Job *job)
|
|
||||||
{
|
|
||||||
Unit *unit = job->unit;
|
|
||||||
struct priv * const priv = unit->data;
|
|
||||||
|
|
||||||
uint8_t buf[8];
|
|
||||||
PayloadBuilder pb = pb_start(buf, 8, NULL);
|
|
||||||
|
|
||||||
pb_u8(&pb, priv->direct_presc);
|
|
||||||
pb_u16(&pb, priv->dir_burst.msec);
|
|
||||||
pb_u32(&pb, job->data1);
|
|
||||||
|
|
||||||
assert_param(pb.ok);
|
|
||||||
|
|
||||||
com_respond_pb(priv->request_id, MSG_SUCCESS, &pb);
|
|
||||||
|
|
||||||
// timer is already stopped, now in OPMODE_BUSY
|
|
||||||
priv->opmode = OPMODE_IDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UFCAP_TIMxHandler(void *arg)
|
|
||||||
{
|
|
||||||
Unit *unit = arg;
|
|
||||||
assert_param(unit);
|
|
||||||
struct priv * const priv = unit->data;
|
|
||||||
assert_param(priv);
|
|
||||||
|
|
||||||
TIM_TypeDef * const TIMx = priv->TIMx;
|
|
||||||
|
|
||||||
if (priv->opmode == OPMODE_INDIRECT_CONT) {
|
|
||||||
if (LL_TIM_IsActiveFlag_CC1(TIMx)) {
|
|
||||||
if (priv->n_skip > 0) {
|
|
||||||
priv->n_skip--;
|
|
||||||
} else {
|
|
||||||
priv->ind_cont.last_period = LL_TIM_IC_GetCaptureCH1(TIMx);
|
|
||||||
priv->ind_cont.last_ontime = priv->ind_cont.ontime;
|
|
||||||
}
|
|
||||||
LL_TIM_ClearFlag_CC1(TIMx);
|
|
||||||
LL_TIM_ClearFlag_CC1OVR(TIMx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LL_TIM_IsActiveFlag_CC2(TIMx)) {
|
|
||||||
priv->ind_cont.ontime = LL_TIM_IC_GetCaptureCH2(TIMx);
|
|
||||||
LL_TIM_ClearFlag_CC2(TIMx);
|
|
||||||
LL_TIM_ClearFlag_CC2OVR(TIMx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (priv->opmode == OPMODE_SINGLE_PULSE) {
|
|
||||||
if (LL_TIM_IsActiveFlag_CC2(TIMx)) {
|
|
||||||
// single pulse - does not wait for the second edge
|
|
||||||
uint32_t len = LL_TIM_IC_GetCaptureCH2(TIMx);
|
|
||||||
|
|
||||||
priv->opmode = OPMODE_BUSY;
|
|
||||||
UFCAP_StopMeasurement(unit);
|
|
||||||
|
|
||||||
Job j = {
|
|
||||||
.cb = UFCAP_SinglePulseReportJob,
|
|
||||||
.unit = unit,
|
|
||||||
.data1 = len,
|
|
||||||
};
|
|
||||||
scheduleJob(&j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (priv->opmode == OPMODE_INDIRECT_BURST) {
|
|
||||||
if (LL_TIM_IsActiveFlag_CC1(TIMx)) {
|
|
||||||
const uint32_t period = LL_TIM_IC_GetCaptureCH1(TIMx);
|
|
||||||
const uint32_t ontime = priv->ind_burst.ontime;
|
|
||||||
|
|
||||||
if (priv->n_skip > 0) {
|
|
||||||
priv->n_skip--;
|
|
||||||
} else {
|
|
||||||
priv->ind_burst.ontime_acu += ontime;
|
|
||||||
priv->ind_burst.period_acu += period;
|
|
||||||
if (++priv->ind_burst.n_count == priv->ind_burst.n_target) {
|
|
||||||
priv->opmode = OPMODE_BUSY;
|
|
||||||
UFCAP_StopMeasurement(unit);
|
|
||||||
|
|
||||||
Job j = {
|
|
||||||
.cb = UFCAP_IndirectBurstReportJob,
|
|
||||||
.unit = unit,
|
|
||||||
};
|
|
||||||
scheduleJob(&j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LL_TIM_ClearFlag_CC1(TIMx);
|
|
||||||
LL_TIM_ClearFlag_CC1OVR(TIMx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LL_TIM_IsActiveFlag_CC2(TIMx)) {
|
|
||||||
priv->ind_burst.ontime = LL_TIM_IC_GetCaptureCH2(TIMx);
|
|
||||||
LL_TIM_ClearFlag_CC2(TIMx);
|
|
||||||
LL_TIM_ClearFlag_CC2OVR(TIMx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (priv->opmode == OPMODE_IDLE) {
|
|
||||||
// clear everything - in idle it would cycle in the handler forever
|
|
||||||
TIMx->SR = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
trap("Unhandled fcap TIMx irq");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UFCAP_TIMyHandler(void *arg)
|
|
||||||
{
|
|
||||||
Unit *unit = arg;
|
|
||||||
assert_param(unit);
|
|
||||||
struct priv *const priv = unit->data;
|
|
||||||
assert_param(priv);
|
|
||||||
|
|
||||||
TIM_TypeDef * const TIMx = priv->TIMx;
|
|
||||||
TIM_TypeDef * const TIMy = priv->TIMy;
|
|
||||||
uint32_t cnt = TIMx->CNT; // TIMx should be stopped now
|
|
||||||
|
|
||||||
// dbg("> TIMy Handler, TIMx cntr is %d", cnt);
|
|
||||||
priv->dir_cont.last_count = cnt;
|
|
||||||
|
|
||||||
if (priv->opmode == OPMODE_DIRECT_CONT) {
|
|
||||||
LL_TIM_DisableCounter(TIMx);
|
|
||||||
LL_TIM_DisableCounter(TIMy);
|
|
||||||
LL_TIM_SetCounter(TIMx, 0);
|
|
||||||
LL_TIM_SetCounter(TIMy, 0);
|
|
||||||
LL_TIM_EnableCounter(TIMy); // next loop
|
|
||||||
LL_TIM_EnableCounter(TIMx);
|
|
||||||
}
|
|
||||||
else if (priv->opmode == OPMODE_DIRECT_BURST) {
|
|
||||||
priv->opmode = OPMODE_BUSY;
|
|
||||||
UFCAP_StopMeasurement(unit);
|
|
||||||
|
|
||||||
Job j = {
|
|
||||||
.cb = UFCAP_DirectBurstReportJob,
|
|
||||||
.unit = unit,
|
|
||||||
.data1 = cnt,
|
|
||||||
};
|
|
||||||
scheduleJob(&j);
|
|
||||||
}
|
|
||||||
else if (priv->opmode == OPMODE_IDLE) {
|
|
||||||
// clear everything - in idle it would cycle in the handler forever
|
|
||||||
TIMy->SR = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
trap("Unhandled fcap TIMy irq");
|
|
||||||
}
|
|
||||||
|
|
||||||
LL_TIM_ClearFlag_UPDATE(TIMy);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void UFCAP_ClearTimerConfig(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv * const priv = unit->data;
|
|
||||||
TIM_TypeDef * const TIMx = priv->TIMx;
|
|
||||||
|
|
||||||
// CLEAR CURRENT STATE, STOP
|
|
||||||
UFCAP_StopMeasurement(unit);
|
|
||||||
|
|
||||||
// CONFIGURE TIMER BASIC PARAMS
|
|
||||||
LL_TIM_SetPrescaler(TIMx, 0);
|
|
||||||
LL_TIM_SetAutoReload(TIMx, 0xFFFFFFFF);
|
|
||||||
LL_TIM_EnableARRPreload(TIMx);
|
|
||||||
LL_TIM_GenerateEvent_UPDATE(TIMx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset all timer registers
|
|
||||||
*
|
|
||||||
* @param unit
|
|
||||||
*/
|
|
||||||
static void UFCAP_StopMeasurement(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv * const priv = unit->data;
|
|
||||||
|
|
||||||
LL_TIM_DeInit(priv->TIMx); // clear all flags and settings
|
|
||||||
LL_TIM_DeInit(priv->TIMy); // clear all flags and settings
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Switch the FCAP module opmode
|
|
||||||
*
|
|
||||||
* @param unit
|
|
||||||
* @param opmode
|
|
||||||
*/
|
|
||||||
void UFCAP_SwitchMode(Unit *unit, enum fcap_opmode opmode)
|
|
||||||
{
|
|
||||||
struct priv * const priv = unit->data;
|
|
||||||
|
|
||||||
if (opmode == priv->opmode) return;
|
|
||||||
|
|
||||||
priv->opmode = opmode;
|
|
||||||
|
|
||||||
switch (opmode) {
|
|
||||||
case OPMODE_IDLE:
|
|
||||||
// XXX maybe we should report the abort to the PC-side listener
|
|
||||||
UFCAP_StopMeasurement(unit);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPMODE_INDIRECT_CONT:
|
|
||||||
priv->ind_cont.last_ontime = 0;
|
|
||||||
priv->ind_cont.last_period = 0;
|
|
||||||
priv->ind_cont.ontime = 0;
|
|
||||||
priv->n_skip = 1; // discard the first cycle (will be incomplete)
|
|
||||||
UFCAP_ConfigureForIndirectCapture(unit); // is also stopped and restarted
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPMODE_INDIRECT_BURST:
|
|
||||||
priv->ind_burst.ontime = 0;
|
|
||||||
priv->ind_burst.n_count = 0;
|
|
||||||
priv->ind_burst.period_acu = 0;
|
|
||||||
priv->ind_burst.ontime_acu = 0;
|
|
||||||
priv->n_skip = 1; // discard the first cycle (will be incomplete)
|
|
||||||
UFCAP_ConfigureForIndirectCapture(unit); // is also stopped and restarted
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPMODE_SINGLE_PULSE:
|
|
||||||
priv->n_skip = 0;
|
|
||||||
UFCAP_ConfigureForIndirectCapture(unit); // is also stopped and restarted
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPMODE_DIRECT_CONT:
|
|
||||||
// msec is set by caller
|
|
||||||
priv->dir_cont.last_count = 0;
|
|
||||||
priv->n_skip = 1; // discard the first cycle (will be incomplete)
|
|
||||||
UFCAP_ConfigureForDirectCapture(unit, priv->direct_msec);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPMODE_DIRECT_BURST:
|
|
||||||
// msec is set by caller
|
|
||||||
priv->n_skip = 0; // no skip here (if there was any)
|
|
||||||
UFCAP_ConfigureForDirectCapture(unit, (uint16_t) priv->dir_burst.msec);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPMODE_FREE_COUNTER:
|
|
||||||
UFCAP_ConfigureForFreeCapture(unit);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
trap("Unhandled opmode %d", (int)opmode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure peripherals for an indirect capture (PWM measurement) - continuous or burst
|
|
||||||
* @param unit
|
|
||||||
*/
|
|
||||||
static void UFCAP_ConfigureForIndirectCapture(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv * const priv = unit->data;
|
|
||||||
TIM_TypeDef * const TIMx = priv->TIMx;
|
|
||||||
const uint32_t ll_ch_a = priv->ll_ch_a;
|
|
||||||
const uint32_t ll_ch_b = priv->ll_ch_b;
|
|
||||||
|
|
||||||
UFCAP_ClearTimerConfig(unit);
|
|
||||||
|
|
||||||
// Enable channels and select mapping to TIx signals
|
|
||||||
|
|
||||||
// A - will be used to measure period
|
|
||||||
// B - will be used to measure the duty cycle
|
|
||||||
|
|
||||||
// _________ ______
|
|
||||||
// _______| |________________|
|
|
||||||
// A B A
|
|
||||||
// irq irq,cap irq
|
|
||||||
// reset
|
|
||||||
|
|
||||||
// B irq may be used if we want to measure a pulse width
|
|
||||||
|
|
||||||
// Normally TI1 = CH1, TI2 = CH2.
|
|
||||||
// It's possible to select the other channel, which we use to connect both TIx to the shame CHx.
|
|
||||||
LL_TIM_IC_SetActiveInput(TIMx, ll_ch_a, priv->a_direct ? LL_TIM_ACTIVEINPUT_DIRECTTI : LL_TIM_ACTIVEINPUT_INDIRECTTI);
|
|
||||||
LL_TIM_IC_SetActiveInput(TIMx, ll_ch_b, priv->a_direct ? LL_TIM_ACTIVEINPUT_INDIRECTTI : LL_TIM_ACTIVEINPUT_DIRECTTI);
|
|
||||||
LL_TIM_IC_SetPolarity(TIMx, ll_ch_a, priv->active_level ? LL_TIM_IC_POLARITY_RISING : LL_TIM_IC_POLARITY_FALLING);
|
|
||||||
LL_TIM_IC_SetPolarity(TIMx, ll_ch_b, priv->active_level ? LL_TIM_IC_POLARITY_FALLING : LL_TIM_IC_POLARITY_RISING);
|
|
||||||
|
|
||||||
if (priv->dfilter > 15) priv->dfilter = 15;
|
|
||||||
uint32_t filter = LL_TIM_IC_FILTERS[priv->dfilter];
|
|
||||||
LL_TIM_IC_SetFilter(TIMx, ll_ch_a, filter);
|
|
||||||
LL_TIM_IC_SetFilter(TIMx, ll_ch_b, filter);
|
|
||||||
|
|
||||||
LL_TIM_CC_EnableChannel(TIMx, ll_ch_a | ll_ch_b);
|
|
||||||
|
|
||||||
LL_TIM_SetSlaveMode(TIMx, LL_TIM_SLAVEMODE_RESET);
|
|
||||||
LL_TIM_SetTriggerInput(TIMx, LL_TIM_TS_TI1FP1); // Use Filtered Input 1 (TI1)
|
|
||||||
|
|
||||||
LL_TIM_EnableMasterSlaveMode(TIMx);
|
|
||||||
|
|
||||||
LL_TIM_ClearFlag_CC1(TIMx);
|
|
||||||
LL_TIM_ClearFlag_CC1OVR(TIMx);
|
|
||||||
LL_TIM_ClearFlag_CC2(TIMx);
|
|
||||||
LL_TIM_ClearFlag_CC2OVR(TIMx);
|
|
||||||
|
|
||||||
LL_TIM_EnableIT_CC1(TIMx);
|
|
||||||
LL_TIM_EnableIT_CC2(TIMx);
|
|
||||||
LL_TIM_EnableCounter(TIMx);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure peripherals for an indirect capture (PWM measurement) - continuous or burst
|
|
||||||
* @param unit
|
|
||||||
*/
|
|
||||||
static void UFCAP_ConfigureForDirectCapture(Unit *unit, uint16_t msec)
|
|
||||||
{
|
|
||||||
struct priv * const priv = unit->data;
|
|
||||||
|
|
||||||
// dbg("Configuring Direct capture...");
|
|
||||||
|
|
||||||
UFCAP_ClearTimerConfig(unit);
|
|
||||||
|
|
||||||
{
|
|
||||||
TIM_TypeDef *const TIMy = priv->TIMy;
|
|
||||||
assert_param(PLAT_AHB_MHZ<=65);
|
|
||||||
uint16_t presc = PLAT_AHB_MHZ*1000;
|
|
||||||
uint32_t count = msec+1; // it's one tick longer because we generate OCREF on the exact msec count - it must be at least 1 tick long
|
|
||||||
|
|
||||||
LL_TIM_SetPrescaler(TIMy, (uint32_t) (presc - 1));
|
|
||||||
LL_TIM_SetAutoReload(TIMy, count - 1);
|
|
||||||
LL_TIM_EnableARRPreload(TIMy);
|
|
||||||
LL_TIM_GenerateEvent_UPDATE(TIMy);
|
|
||||||
LL_TIM_SetOnePulseMode(TIMy, LL_TIM_ONEPULSEMODE_SINGLE);
|
|
||||||
LL_TIM_OC_EnableFast(TIMy, LL_TIM_CHANNEL_CH1);
|
|
||||||
|
|
||||||
// dbg("TIMy presc %d, count %d", (int) presc, (int) count);
|
|
||||||
|
|
||||||
LL_TIM_SetTriggerOutput(TIMy, LL_TIM_TRGO_OC1REF);
|
|
||||||
LL_TIM_OC_SetMode(TIMy, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM1); // 1 until CC, then 0
|
|
||||||
LL_TIM_OC_SetCompareCH1(TIMy, count-1);
|
|
||||||
LL_TIM_CC_EnableChannel(TIMy, LL_TIM_CHANNEL_CH1); // enable the output channel that produces a trigger
|
|
||||||
|
|
||||||
LL_TIM_ClearFlag_UPDATE(TIMy);
|
|
||||||
LL_TIM_EnableIT_UPDATE(TIMy);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// TIMx - the slave
|
|
||||||
TIM_TypeDef *const TIMx = priv->TIMx;
|
|
||||||
LL_TIM_SetSlaveMode(TIMx, LL_TIM_SLAVEMODE_GATED);
|
|
||||||
LL_TIM_SetTriggerInput(TIMx, LL_TIM_TS_ITR3); // ITR3 is TIM14 which we use as TIMy
|
|
||||||
LL_TIM_EnableMasterSlaveMode(TIMx);
|
|
||||||
|
|
||||||
uint32_t presc = LL_TIM_ETR_PRESCALER_DIV1;
|
|
||||||
switch (priv->direct_presc) {
|
|
||||||
case 1: presc = LL_TIM_ETR_PRESCALER_DIV1; break;
|
|
||||||
case 2: presc = LL_TIM_ETR_PRESCALER_DIV2; break;
|
|
||||||
case 4: presc = LL_TIM_ETR_PRESCALER_DIV4; break;
|
|
||||||
case 8: presc = LL_TIM_ETR_PRESCALER_DIV8; break;
|
|
||||||
default:
|
|
||||||
priv->direct_presc = 1; // will be sent with the response
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->dfilter > 15) priv->dfilter = 15;
|
|
||||||
uint32_t filter = LL_TIM_ETR_FILTERS[priv->dfilter];
|
|
||||||
|
|
||||||
LL_TIM_ConfigETR(TIMx,
|
|
||||||
priv->active_level ? LL_TIM_ETR_POLARITY_NONINVERTED : LL_TIM_ETR_POLARITY_INVERTED,
|
|
||||||
presc,
|
|
||||||
filter);
|
|
||||||
|
|
||||||
LL_TIM_EnableExternalClock(TIMx); // TODO must check and deny this mode if the pin is not on CH1 = external trigger input
|
|
||||||
|
|
||||||
LL_TIM_SetCounter(TIMx, 0);
|
|
||||||
LL_TIM_EnableCounter(TIMx);
|
|
||||||
}
|
|
||||||
|
|
||||||
LL_TIM_EnableCounter(priv->TIMy); // XXX this will start the first pulse (maybe)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Freerunning capture (counting pulses - geiger)
|
|
||||||
* @param unit
|
|
||||||
*/
|
|
||||||
static void UFCAP_ConfigureForFreeCapture(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv * const priv = unit->data;
|
|
||||||
|
|
||||||
UFCAP_ClearTimerConfig(unit);
|
|
||||||
|
|
||||||
TIM_TypeDef *const TIMx = priv->TIMx;
|
|
||||||
LL_TIM_EnableExternalClock(TIMx);
|
|
||||||
LL_TIM_SetCounter(TIMx, 0);
|
|
||||||
LL_TIM_EnableCounter(TIMx);
|
|
||||||
}
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
|
|
||||||
#define FCAP_INTERNAL
|
|
||||||
#include "_fcap_internal.h"
|
|
||||||
|
|
||||||
/** Allocate data structure and set defaults */
|
|
||||||
error_t UFCAP_preInit(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
|
|
||||||
if (priv == NULL) return E_OUT_OF_MEM;
|
|
||||||
|
|
||||||
priv->conf.signal_pname = 'A';
|
|
||||||
priv->conf.signal_pnum = 0;
|
|
||||||
|
|
||||||
priv->conf.active_level = 1;
|
|
||||||
priv->conf.direct_presc = 1;
|
|
||||||
priv->conf.dfilter = 0;
|
|
||||||
priv->conf.direct_msec = 1000;
|
|
||||||
priv->conf.startmode = OPMODE_IDLE;
|
|
||||||
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Finalize unit set-up */
|
|
||||||
error_t UFCAP_init(Unit *unit)
|
|
||||||
{
|
|
||||||
bool suc = true;
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
// ---- Resolve what to configure ----
|
|
||||||
|
|
||||||
TIM_TypeDef * const TIMx = TIM2;
|
|
||||||
Resource timRsc = R_TIM2;
|
|
||||||
|
|
||||||
TIM_TypeDef * const TIMy = TIM14;
|
|
||||||
Resource tim2Rsc = R_TIM14;
|
|
||||||
|
|
||||||
uint32_t ll_ch_a = 0;
|
|
||||||
uint32_t ll_ch_b = 0;
|
|
||||||
|
|
||||||
switch (priv->conf.signal_pname) {
|
|
||||||
case 'A':
|
|
||||||
switch (priv->conf.signal_pnum) {
|
|
||||||
case 5:
|
|
||||||
case 15:
|
|
||||||
case 0: ll_ch_a = LL_TIM_CHANNEL_CH1; break;
|
|
||||||
case 1: ll_ch_a = LL_TIM_CHANNEL_CH2; break;
|
|
||||||
default:
|
|
||||||
dbg("Bad signal pin!");
|
|
||||||
return E_BAD_CONFIG;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'B':
|
|
||||||
switch (priv->conf.signal_pnum) {
|
|
||||||
case 3: ll_ch_a = LL_TIM_CHANNEL_CH2; break;
|
|
||||||
default:
|
|
||||||
dbg("Bad signal pin!");
|
|
||||||
return E_BAD_CONFIG;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
dbg("Bad signal pin port!");
|
|
||||||
return E_BAD_CONFIG;
|
|
||||||
}
|
|
||||||
const uint32_t ll_timpin_af = LL_GPIO_AF_2;
|
|
||||||
|
|
||||||
bool a_direct = true;
|
|
||||||
switch (ll_ch_a) {
|
|
||||||
case LL_TIM_CHANNEL_CH1:
|
|
||||||
ll_ch_b = LL_TIM_CHANNEL_CH2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LL_TIM_CHANNEL_CH2:
|
|
||||||
ll_ch_b = LL_TIM_CHANNEL_CH1;
|
|
||||||
a_direct = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- CLAIM ----
|
|
||||||
|
|
||||||
TRY(rsc_claim_pin(unit, priv->conf.signal_pname, priv->conf.signal_pnum));
|
|
||||||
TRY(rsc_claim(unit, timRsc));
|
|
||||||
TRY(rsc_claim(unit, tim2Rsc));
|
|
||||||
|
|
||||||
// ---- INIT ----
|
|
||||||
assert_param(ll_ch_a != ll_ch_b);
|
|
||||||
|
|
||||||
priv->TIMx = TIMx;
|
|
||||||
priv->TIMy = TIMy;
|
|
||||||
priv->ll_ch_a = ll_ch_a;
|
|
||||||
priv->ll_ch_b = ll_ch_b;
|
|
||||||
priv->a_direct = a_direct;
|
|
||||||
|
|
||||||
// Load defaults
|
|
||||||
priv->active_level = priv->conf.active_level;
|
|
||||||
priv->direct_presc = priv->conf.direct_presc;
|
|
||||||
priv->dfilter = priv->conf.dfilter;
|
|
||||||
priv->direct_msec = priv->conf.direct_msec;
|
|
||||||
priv->opmode = priv->conf.startmode;
|
|
||||||
|
|
||||||
TRY(hw_configure_gpio_af(priv->conf.signal_pname, priv->conf.signal_pnum, ll_timpin_af));
|
|
||||||
|
|
||||||
GPIO_TypeDef *gpio = hw_port2periph(priv->conf.signal_pname, &suc);
|
|
||||||
uint32_t ll_pin = hw_pin2ll(priv->conf.signal_pnum, &suc);
|
|
||||||
LL_GPIO_SetPinPull(gpio, ll_pin, LL_GPIO_PULL_DOWN); // XXX change to pull-up if the polarity is inverted
|
|
||||||
|
|
||||||
hw_periph_clock_enable(TIMx);
|
|
||||||
hw_periph_clock_enable(TIMy);
|
|
||||||
irqd_attach(TIMx, UFCAP_TIMxHandler, unit);
|
|
||||||
irqd_attach(TIMy, UFCAP_TIMyHandler, unit);
|
|
||||||
|
|
||||||
UFCAP_SwitchMode(unit, priv->opmode); // switch to the default opmode
|
|
||||||
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Tear down the unit */
|
|
||||||
void UFCAP_deInit(Unit *unit)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
// de-init peripherals
|
|
||||||
if (unit->status == E_SUCCESS ) {
|
|
||||||
UFCAP_SwitchMode(unit, OPMODE_IDLE);
|
|
||||||
|
|
||||||
TIM_TypeDef *TIMx = priv->TIMx;
|
|
||||||
TIM_TypeDef *TIMy = priv->TIMy;
|
|
||||||
LL_TIM_DeInit(TIMx);
|
|
||||||
LL_TIM_DeInit(TIMy);
|
|
||||||
irqd_detach(TIMx, UFCAP_TIMxHandler);
|
|
||||||
irqd_detach(TIMy, UFCAP_TIMyHandler);
|
|
||||||
hw_periph_clock_disable(TIMx);
|
|
||||||
hw_periph_clock_disable(TIMy);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release all resources, deinit pins
|
|
||||||
rsc_teardown(unit);
|
|
||||||
|
|
||||||
// Free memory
|
|
||||||
free_ck(unit->data);
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef GEX_F072_FCAP_INTERNAL_H
|
|
||||||
#define GEX_F072_FCAP_INTERNAL_H
|
|
||||||
|
|
||||||
#ifndef FCAP_INTERNAL
|
|
||||||
#error bad include!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "unit_base.h"
|
|
||||||
|
|
||||||
enum fcap_opmode {
|
|
||||||
OPMODE_IDLE = 0,
|
|
||||||
OPMODE_BUSY = 1, // used after capture is done, before it's reported
|
|
||||||
OPMODE_INDIRECT_CONT = 2,
|
|
||||||
OPMODE_INDIRECT_BURST = 3, // averaging
|
|
||||||
OPMODE_DIRECT_CONT = 4,
|
|
||||||
OPMODE_DIRECT_BURST = 5,
|
|
||||||
OPMODE_FREE_COUNTER = 6,
|
|
||||||
OPMODE_SINGLE_PULSE = 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Private data structure */
|
|
||||||
struct priv {
|
|
||||||
// settings
|
|
||||||
struct {
|
|
||||||
char signal_pname; // the input pin - one of TIM2 channels
|
|
||||||
uint8_t signal_pnum;
|
|
||||||
|
|
||||||
bool active_level;
|
|
||||||
uint8_t direct_presc;
|
|
||||||
uint8_t dfilter;
|
|
||||||
uint16_t direct_msec;
|
|
||||||
|
|
||||||
enum fcap_opmode startmode;
|
|
||||||
} conf;
|
|
||||||
|
|
||||||
// internal state
|
|
||||||
TIM_TypeDef *TIMx;
|
|
||||||
TIM_TypeDef *TIMy; // used as a timebase source for TIMx in direct mode
|
|
||||||
uint32_t ll_ch_b;
|
|
||||||
uint32_t ll_ch_a;
|
|
||||||
bool a_direct;
|
|
||||||
|
|
||||||
enum fcap_opmode opmode;
|
|
||||||
|
|
||||||
TF_ID request_id;
|
|
||||||
uint8_t n_skip; //!< Periods to skip before starting the real capture
|
|
||||||
|
|
||||||
bool active_level; // in PWM mode, the first part that is measured. (if 1, HHHLLL, else LLLHHH). In direct mode, clock polarity
|
|
||||||
uint8_t direct_presc;
|
|
||||||
uint16_t direct_msec;
|
|
||||||
uint8_t dfilter;
|
|
||||||
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
uint32_t ontime; // length of the captured positive pulse in the current interval
|
|
||||||
uint32_t last_period; //!< length of the captured interval between two rising edges
|
|
||||||
uint32_t last_ontime; //!< length of the last captured ontime
|
|
||||||
} ind_cont;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
uint32_t ontime; // length of the captured positive pulse in the current interval
|
|
||||||
uint64_t period_acu; //!< length of the captured interval between two rising edges, sum
|
|
||||||
uint64_t ontime_acu; //!< length of the last captured ontime, sum
|
|
||||||
uint16_t n_count; //!< Periods captured
|
|
||||||
uint16_t n_target; //!< Periods captured - requested count
|
|
||||||
} ind_burst;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
uint32_t last_count; //!< Pulse count in the last capture window
|
|
||||||
} dir_cont;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
uint16_t msec; // capture window length (used in the report callback) - different from the cont time, which is a semi-persistent config
|
|
||||||
} dir_burst;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Allocate data structure and set defaults */
|
|
||||||
error_t UFCAP_preInit(Unit *unit);
|
|
||||||
|
|
||||||
/** Load from a binary buffer stored in Flash */
|
|
||||||
void UFCAP_loadBinary(Unit *unit, PayloadParser *pp);
|
|
||||||
|
|
||||||
/** Write to a binary buffer for storing in Flash */
|
|
||||||
void UFCAP_writeBinary(Unit *unit, PayloadBuilder *pb);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Parse a key-value pair from the INI file */
|
|
||||||
error_t UFCAP_loadIni(Unit *unit, const char *key, const char *value);
|
|
||||||
|
|
||||||
/** Generate INI file section for the unit */
|
|
||||||
void UFCAP_writeIni(Unit *unit, IniWriter *iw);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Finalize unit set-up */
|
|
||||||
error_t UFCAP_init(Unit *unit);
|
|
||||||
|
|
||||||
/** Tear down the unit */
|
|
||||||
void UFCAP_deInit(Unit *unit);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void UFCAP_SwitchMode(Unit *unit, enum fcap_opmode opmode);
|
|
||||||
|
|
||||||
void UFCAP_TIMxHandler(void *arg);
|
|
||||||
void UFCAP_TIMyHandler(void *arg);
|
|
||||||
|
|
||||||
uint32_t UFCAP_GetFreeCounterValue(Unit *unit);
|
|
||||||
uint32_t UFCAP_FreeCounterClear(Unit *unit);
|
|
||||||
|
|
||||||
#endif //GEX_F072_FCAP_INTERNAL_H
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
|
|
||||||
#define FCAP_INTERNAL
|
|
||||||
#include "_fcap_internal.h"
|
|
||||||
|
|
||||||
/** Load from a binary buffer stored in Flash */
|
|
||||||
void UFCAP_loadBinary(Unit *unit, PayloadParser *pp)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
uint8_t version = pp_u8(pp);
|
|
||||||
(void)version;
|
|
||||||
|
|
||||||
priv->conf.signal_pname = pp_char(pp);
|
|
||||||
priv->conf.signal_pnum = pp_u8(pp);
|
|
||||||
priv->conf.active_level = pp_bool(pp);
|
|
||||||
priv->conf.dfilter = pp_u8(pp);
|
|
||||||
priv->conf.direct_presc = pp_u8(pp);
|
|
||||||
priv->conf.direct_msec = pp_u16(pp);
|
|
||||||
priv->conf.startmode = (enum fcap_opmode) pp_u8(pp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Write to a binary buffer for storing in Flash */
|
|
||||||
void UFCAP_writeBinary(Unit *unit, PayloadBuilder *pb)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
pb_u8(pb, 0); // version
|
|
||||||
|
|
||||||
pb_char(pb, priv->conf.signal_pname);
|
|
||||||
pb_u8(pb, priv->conf.signal_pnum);
|
|
||||||
pb_bool(pb, priv->conf.active_level);
|
|
||||||
pb_u8(pb, priv->conf.dfilter);
|
|
||||||
pb_u8(pb, priv->conf.direct_presc);
|
|
||||||
pb_u16(pb, priv->conf.direct_msec);
|
|
||||||
pb_u8(pb, priv->conf.startmode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Parse a key-value pair from the INI file */
|
|
||||||
error_t UFCAP_loadIni(Unit *unit, const char *key, const char *value)
|
|
||||||
{
|
|
||||||
bool suc = true;
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
if (streq(key, "pin")) {
|
|
||||||
suc = cfg_portpin_parse(value, &priv->conf.signal_pname, &priv->conf.signal_pnum);
|
|
||||||
}
|
|
||||||
else if (streq(key, "active-level")) {
|
|
||||||
priv->conf.active_level = cfg_bool_parse(value, &suc);
|
|
||||||
}
|
|
||||||
else if (streq(key, "input-filter")) {
|
|
||||||
priv->conf.dfilter = cfg_u8_parse(value, &suc);
|
|
||||||
}
|
|
||||||
else if (streq(key, "direct-presc")) {
|
|
||||||
priv->conf.direct_presc = cfg_u8_parse(value, &suc);
|
|
||||||
}
|
|
||||||
else if (streq(key, "direct-time")) {
|
|
||||||
priv->conf.direct_msec = cfg_u16_parse(value, &suc);
|
|
||||||
}
|
|
||||||
else if (streq(key, "initial-mode")) {
|
|
||||||
priv->conf.startmode = (enum fcap_opmode) cfg_enum4_parse(value,
|
|
||||||
"N", OPMODE_IDLE,
|
|
||||||
"I", OPMODE_INDIRECT_CONT,
|
|
||||||
"D", OPMODE_DIRECT_CONT,
|
|
||||||
"F", OPMODE_FREE_COUNTER,
|
|
||||||
&suc);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
return E_BAD_KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!suc) return E_BAD_VALUE;
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Generate INI file section for the unit */
|
|
||||||
void UFCAP_writeIni(Unit *unit, IniWriter *iw)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
iw_comment(iw, "Signal input pin - one of:");
|
|
||||||
iw_comment(iw, " Full support: A0, A5, A15");
|
|
||||||
iw_comment(iw, " Indirect only: A1, B3");
|
|
||||||
iw_entry(iw, "pin", "%c%d", priv->conf.signal_pname, priv->conf.signal_pnum);
|
|
||||||
iw_cmt_newline(iw);
|
|
||||||
|
|
||||||
iw_comment(iw, "Active level or edge (0-low,falling; 1-high,rising)");
|
|
||||||
iw_entry_d(iw, "active-level", priv->conf.active_level);
|
|
||||||
|
|
||||||
iw_comment(iw, "Input filtering (0-15)");
|
|
||||||
iw_entry_d(iw, "input-filter", priv->conf.dfilter);
|
|
||||||
|
|
||||||
iw_comment(iw, "Pulse counter pre-divider (1,2,4,8)");
|
|
||||||
iw_entry_d(iw, "direct-presc", priv->conf.direct_presc);
|
|
||||||
|
|
||||||
iw_comment(iw, "Pulse counting interval (ms)");
|
|
||||||
iw_entry_d(iw, "direct-time", priv->conf.direct_msec);
|
|
||||||
iw_cmt_newline(iw);
|
|
||||||
|
|
||||||
iw_comment(iw, "Mode on startup: N-none, I-indirect, D-direct, F-free count");
|
|
||||||
iw_entry_s(iw, "initial-mode", cfg_enum4_encode(priv->conf.startmode,
|
|
||||||
OPMODE_IDLE, "N",
|
|
||||||
OPMODE_INDIRECT_CONT, "I",
|
|
||||||
OPMODE_DIRECT_CONT, "D",
|
|
||||||
OPMODE_FREE_COUNTER, "F"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,322 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2017/11/25.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "unit_base.h"
|
|
||||||
#include "unit_fcap.h"
|
|
||||||
|
|
||||||
#define FCAP_INTERNAL
|
|
||||||
#include "_fcap_internal.h"
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
enum FcapCmd_ {
|
|
||||||
CMD_STOP = 0,
|
|
||||||
|
|
||||||
// Measuring a waveform
|
|
||||||
CMD_INDIRECT_CONT_START = 1, // keep measuring, read on demand
|
|
||||||
CMD_INDIRECT_BURST_START = 2, // wait and reply
|
|
||||||
|
|
||||||
// Counting pulses
|
|
||||||
CMD_DIRECT_CONT_START = 3, // keep measuring, read on demand
|
|
||||||
CMD_DIRECT_BURST_START = 4, // wait and reply
|
|
||||||
CMD_FREECOUNT_START = 5, // keep counting pulses until stopped, read on reply
|
|
||||||
|
|
||||||
CMD_MEASURE_SINGLE_PULSE = 6, // measure the first incoming pulse of the right polarity. NOTE: can glitch if the signal starts in the active level
|
|
||||||
CMD_FREECOUNT_CLEAR = 7, // clear the free counter, return last value
|
|
||||||
|
|
||||||
// Results readout for continuous modes
|
|
||||||
CMD_INDIRECT_CONT_READ = 10,
|
|
||||||
CMD_DIRECT_CONT_READ = 11,
|
|
||||||
CMD_FREECOUNT_READ = 12,
|
|
||||||
|
|
||||||
// configs
|
|
||||||
CMD_SET_POLARITY = 20,
|
|
||||||
CMD_SET_DIR_PRESC = 21,
|
|
||||||
CMD_SET_INPUT_FILTER = 22,
|
|
||||||
CMD_SET_DIR_MSEC = 23,
|
|
||||||
|
|
||||||
// go back to the configured settings
|
|
||||||
CMD_RESTORE_DEFAULTS = 30,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Handle a request message */
|
|
||||||
static error_t UFCAP_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
|
|
||||||
{
|
|
||||||
uint8_t presc;
|
|
||||||
uint16_t msec;
|
|
||||||
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL);
|
|
||||||
const char* msg_denied_on_pin = "Not available on the selected pin!";
|
|
||||||
|
|
||||||
switch (command) {
|
|
||||||
/**
|
|
||||||
* Stop any ongoing measurement and return to base state.
|
|
||||||
*/
|
|
||||||
case CMD_STOP:
|
|
||||||
UFCAP_SwitchMode(unit, OPMODE_IDLE);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
// ----------------------- CONFIG --------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the active polarity, or triggering edge (for direct)
|
|
||||||
*
|
|
||||||
* pld: pol:u8 (0,1)
|
|
||||||
*/
|
|
||||||
case CMD_SET_POLARITY:
|
|
||||||
{
|
|
||||||
priv->active_level = pp_bool(pp);
|
|
||||||
}
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the direct measurement prescaller 1,2,4,8
|
|
||||||
*
|
|
||||||
* pld: presc:u8
|
|
||||||
*/
|
|
||||||
case CMD_SET_DIR_PRESC:
|
|
||||||
{
|
|
||||||
presc = pp_u8(pp);
|
|
||||||
if (presc != 1 && presc != 2 && presc != 4 && presc != 8) return E_BAD_VALUE;
|
|
||||||
priv->direct_presc = presc;
|
|
||||||
}
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the input filter for all modes
|
|
||||||
*
|
|
||||||
* pld: filter:u8 (0-15)
|
|
||||||
*/
|
|
||||||
case CMD_SET_INPUT_FILTER:
|
|
||||||
{
|
|
||||||
uint8_t input_filter = pp_u8(pp);
|
|
||||||
if (input_filter >= 16) return E_BAD_VALUE;
|
|
||||||
priv->dfilter = input_filter;
|
|
||||||
}
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the direct sampling time.
|
|
||||||
*
|
|
||||||
* pld: msec:u16
|
|
||||||
*/
|
|
||||||
case CMD_SET_DIR_MSEC:
|
|
||||||
{
|
|
||||||
msec = pp_u16(pp);
|
|
||||||
priv->direct_msec = msec;
|
|
||||||
}
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset all SET* settings to their default values, stop any ongoing measure.
|
|
||||||
*/
|
|
||||||
case CMD_RESTORE_DEFAULTS:
|
|
||||||
UFCAP_SwitchMode(unit, OPMODE_IDLE);
|
|
||||||
|
|
||||||
priv->active_level = priv->conf.active_level;
|
|
||||||
priv->direct_presc = priv->conf.direct_presc;
|
|
||||||
priv->direct_msec = priv->conf.direct_msec;
|
|
||||||
priv->dfilter = priv->conf.dfilter;
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
// ------------------ COMMANDS ------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start indirect continuous measurement.
|
|
||||||
*/
|
|
||||||
case CMD_INDIRECT_CONT_START:
|
|
||||||
if (priv->opmode == OPMODE_INDIRECT_CONT) return E_SUCCESS; // no-op
|
|
||||||
if (priv->opmode != OPMODE_IDLE) return E_BUSY;
|
|
||||||
|
|
||||||
UFCAP_SwitchMode(unit, OPMODE_INDIRECT_CONT);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a continuous direct measurement (counting pulses in fixed time intervals)
|
|
||||||
*
|
|
||||||
* - meas_time_ms 0 = no change
|
|
||||||
* - prescaller 0 = no change
|
|
||||||
*
|
|
||||||
* pld: meas_time_ms:u16, prescaller:u8
|
|
||||||
* - prescaller is 1,2,4,8; 0 = no change
|
|
||||||
*/
|
|
||||||
case CMD_DIRECT_CONT_START:
|
|
||||||
if (!priv->a_direct) {
|
|
||||||
// This works only if we use the ETR pin. TIM2 shares CH1 with ETR.
|
|
||||||
// If CH2 is selected as input, ETR is not available.
|
|
||||||
com_respond_str(MSG_ERROR, frame_id, msg_denied_on_pin);
|
|
||||||
return E_FAILURE;
|
|
||||||
}
|
|
||||||
if (priv->opmode == OPMODE_DIRECT_CONT) return E_SUCCESS; // no-op
|
|
||||||
if (priv->opmode != OPMODE_IDLE) return E_BUSY;
|
|
||||||
|
|
||||||
msec = pp_u16(pp);
|
|
||||||
presc = pp_u8(pp);
|
|
||||||
if (msec != 0) priv->direct_msec = msec;
|
|
||||||
if (presc != 0) priv->direct_presc = presc;
|
|
||||||
|
|
||||||
UFCAP_SwitchMode(unit, OPMODE_DIRECT_CONT);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a burst of direct measurements with averaging.
|
|
||||||
* The measurement is performed on N consecutive pulses.
|
|
||||||
*
|
|
||||||
* pld: count:u16
|
|
||||||
*
|
|
||||||
* resp: core_mhz:u16, count:u16, period_sum:u64, ontime_sum:u64
|
|
||||||
*/
|
|
||||||
case CMD_INDIRECT_BURST_START:
|
|
||||||
if (priv->opmode != OPMODE_IDLE) return E_BAD_MODE;
|
|
||||||
|
|
||||||
priv->ind_burst.n_target = pp_u16(pp);
|
|
||||||
priv->request_id = frame_id;
|
|
||||||
UFCAP_SwitchMode(unit, OPMODE_INDIRECT_BURST);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a single direct measurement of the given length (pulses in time period)
|
|
||||||
* If 'prescaller' is not 0, it is changed via the param field.
|
|
||||||
*
|
|
||||||
* pld: meas_time_ms:u16, prescaller:u8
|
|
||||||
* - prescaller is 1,2,4,8; 0 = no change
|
|
||||||
*
|
|
||||||
* resp: prescaller:u8, meas_time_ms:u16, pulse_count:u32
|
|
||||||
*/
|
|
||||||
case CMD_DIRECT_BURST_START:
|
|
||||||
if (priv->opmode != OPMODE_IDLE) return E_BAD_MODE;
|
|
||||||
|
|
||||||
priv->dir_burst.msec = pp_u16(pp);
|
|
||||||
|
|
||||||
presc = pp_u8(pp);
|
|
||||||
if (presc != 0) priv->direct_presc = presc;
|
|
||||||
|
|
||||||
priv->request_id = frame_id;
|
|
||||||
UFCAP_SwitchMode(unit, OPMODE_DIRECT_BURST);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Measure a single pulse length of the given polarity.
|
|
||||||
* Measures time from a rising to a falling edge (or falling to rising, if polarity is 0)
|
|
||||||
*
|
|
||||||
* resp: core_mhz:u16, ontime:u32
|
|
||||||
*/
|
|
||||||
case CMD_MEASURE_SINGLE_PULSE:
|
|
||||||
if (priv->opmode != OPMODE_IDLE) return E_BAD_MODE;
|
|
||||||
priv->request_id = frame_id;
|
|
||||||
UFCAP_SwitchMode(unit, OPMODE_SINGLE_PULSE);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a free-running pulse counter.
|
|
||||||
*
|
|
||||||
* pld: prescaller:u8
|
|
||||||
* - prescaller is 1,2,4,8; 0 = no change
|
|
||||||
*/
|
|
||||||
case CMD_FREECOUNT_START:
|
|
||||||
if (priv->opmode != OPMODE_IDLE) return E_BAD_MODE;
|
|
||||||
|
|
||||||
presc = pp_u8(pp);
|
|
||||||
if (presc != 0) priv->direct_presc = presc;
|
|
||||||
|
|
||||||
UFCAP_SwitchMode(unit, OPMODE_FREE_COUNTER);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the free-running pulse counter.
|
|
||||||
*
|
|
||||||
* resp: last_val:u32
|
|
||||||
*/
|
|
||||||
case CMD_FREECOUNT_CLEAR:
|
|
||||||
if (priv->opmode != OPMODE_FREE_COUNTER) {
|
|
||||||
return E_BAD_MODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
pb_u32(&pb, UFCAP_FreeCounterClear(unit));
|
|
||||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
// ------------------ READING ---------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the most recent pulse measurement during continuous indirect measure.
|
|
||||||
*
|
|
||||||
* resp: core_mhz:u16, period:u32, ontime:u32
|
|
||||||
*/
|
|
||||||
case CMD_INDIRECT_CONT_READ:
|
|
||||||
if (priv->opmode != OPMODE_INDIRECT_CONT) {
|
|
||||||
return E_BAD_MODE;
|
|
||||||
}
|
|
||||||
if (priv->ind_cont.last_period == 0) {
|
|
||||||
return E_BUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
pb_u16(&pb, PLAT_AHB_MHZ);
|
|
||||||
pb_u32(&pb, priv->ind_cont.last_period);
|
|
||||||
pb_u32(&pb, priv->ind_cont.last_ontime);
|
|
||||||
|
|
||||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the most recent result of a continuous direct measurement.
|
|
||||||
*
|
|
||||||
* resp: prescaller:u8, meas_time_ms:u16, pulse_count:u32
|
|
||||||
*/
|
|
||||||
case CMD_DIRECT_CONT_READ:
|
|
||||||
if (!priv->a_direct) { // see above
|
|
||||||
com_respond_str(MSG_ERROR, frame_id, msg_denied_on_pin);
|
|
||||||
return E_FAILURE;
|
|
||||||
}
|
|
||||||
if (priv->opmode != OPMODE_DIRECT_CONT) return E_BAD_MODE;
|
|
||||||
if (priv->dir_cont.last_count == 0) return E_BUSY;
|
|
||||||
|
|
||||||
pb_u8(&pb, priv->direct_presc);
|
|
||||||
pb_u16(&pb, priv->direct_msec);
|
|
||||||
pb_u32(&pb, priv->dir_cont.last_count);
|
|
||||||
|
|
||||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the current value of the free-running pulse counter.
|
|
||||||
*
|
|
||||||
* The timing may have a significant jitter, this function is practically useful only for
|
|
||||||
* slow pulse sources (like a geiger counter, item counting etc)
|
|
||||||
*
|
|
||||||
* resp: count:u32
|
|
||||||
*/
|
|
||||||
case CMD_FREECOUNT_READ:
|
|
||||||
if (priv->opmode != OPMODE_FREE_COUNTER) {
|
|
||||||
return E_BAD_MODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
pb_u32(&pb, UFCAP_GetFreeCounterValue(unit));
|
|
||||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return E_UNKNOWN_COMMAND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Frequency capture */
|
|
||||||
const UnitDriver UNIT_FCAP = {
|
|
||||||
.name = "FCAP",
|
|
||||||
.description = "Frequency and pulse measurement",
|
|
||||||
// Settings
|
|
||||||
.preInit = UFCAP_preInit,
|
|
||||||
.cfgLoadBinary = UFCAP_loadBinary,
|
|
||||||
.cfgWriteBinary = UFCAP_writeBinary,
|
|
||||||
.cfgLoadIni = UFCAP_loadIni,
|
|
||||||
.cfgWriteIni = UFCAP_writeIni,
|
|
||||||
// Init
|
|
||||||
.init = UFCAP_init,
|
|
||||||
.deInit = UFCAP_deInit,
|
|
||||||
// Function
|
|
||||||
.handleRequest = UFCAP_handleRequest,
|
|
||||||
};
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2017/11/25.
|
|
||||||
//
|
|
||||||
// Digital input unit; single or multiple pin read access on one port (A-F)
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef U_FCAP_H
|
|
||||||
#define U_FCAP_H
|
|
||||||
|
|
||||||
#include "unit.h"
|
|
||||||
|
|
||||||
extern const UnitDriver UNIT_FCAP;
|
|
||||||
|
|
||||||
// UU_ prototypes
|
|
||||||
|
|
||||||
#endif //U_FCAP_H
|
|
||||||
+15
-12
@@ -20,7 +20,10 @@ void UI2C_loadBinary(Unit *unit, PayloadParser *pp)
|
|||||||
priv->anf = pp_bool(pp);
|
priv->anf = pp_bool(pp);
|
||||||
priv->dnf = pp_u8(pp);
|
priv->dnf = pp_u8(pp);
|
||||||
priv->speed = pp_u8(pp);
|
priv->speed = pp_u8(pp);
|
||||||
priv->remap = pp_u8(pp);
|
|
||||||
|
if (version >= 1) {
|
||||||
|
priv->remap = pp_u8(pp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Write to a binary buffer for storing in Flash */
|
/** Write to a binary buffer for storing in Flash */
|
||||||
@@ -28,7 +31,7 @@ void UI2C_writeBinary(Unit *unit, PayloadBuilder *pb)
|
|||||||
{
|
{
|
||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
pb_u8(pb, 0); // version
|
pb_u8(pb, 1); // version
|
||||||
|
|
||||||
pb_u8(pb, priv->periph_num);
|
pb_u8(pb, priv->periph_num);
|
||||||
pb_bool(pb, priv->anf);
|
pb_bool(pb, priv->anf);
|
||||||
@@ -46,19 +49,19 @@ error_t UI2C_loadIni(Unit *unit, const char *key, const char *value)
|
|||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
if (streq(key, "device")) {
|
if (streq(key, "device")) {
|
||||||
priv->periph_num = cfg_u8_parse(value, &suc);
|
priv->periph_num = (uint8_t) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "remap")) {
|
else if (streq(key, "remap")) {
|
||||||
priv->remap = cfg_u8_parse(value, &suc);
|
priv->remap = (uint8_t) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "analog-filter")) {
|
else if (streq(key, "analog-filter")) {
|
||||||
priv->anf = cfg_bool_parse(value, &suc);
|
priv->anf = str_parse_yn(value, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "digital-filter")) {
|
else if (streq(key, "digital-filter")) {
|
||||||
priv->dnf = cfg_u8_parse(value, &suc);
|
priv->dnf = (uint8_t) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "speed")) {
|
else if (streq(key, "speed")) {
|
||||||
priv->speed = cfg_u8_parse(value, &suc);
|
priv->speed = (uint8_t) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return E_BAD_KEY;
|
return E_BAD_KEY;
|
||||||
@@ -74,7 +77,7 @@ void UI2C_writeIni(Unit *unit, IniWriter *iw)
|
|||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
iw_comment(iw, "Peripheral number (I2Cx)");
|
iw_comment(iw, "Peripheral number (I2Cx)");
|
||||||
iw_entry_d(iw, "device", priv->periph_num);
|
iw_entry(iw, "device", "%d", (int)priv->periph_num);
|
||||||
|
|
||||||
iw_comment(iw, "Pin mappings (SCL,SDA)");
|
iw_comment(iw, "Pin mappings (SCL,SDA)");
|
||||||
#if GEX_PLAT_F072_DISCOVERY
|
#if GEX_PLAT_F072_DISCOVERY
|
||||||
@@ -89,15 +92,15 @@ void UI2C_writeIni(Unit *unit, IniWriter *iw)
|
|||||||
#else
|
#else
|
||||||
#error "BAD PLATFORM!"
|
#error "BAD PLATFORM!"
|
||||||
#endif
|
#endif
|
||||||
iw_entry_d(iw, "remap", priv->remap);
|
iw_entry(iw, "remap", "%d", (int)priv->remap);
|
||||||
|
|
||||||
iw_cmt_newline(iw);
|
iw_cmt_newline(iw);
|
||||||
iw_comment(iw, "Speed: 1-Standard, 2-Fast, 3-Fast+");
|
iw_comment(iw, "Speed: 1-Standard, 2-Fast, 3-Fast+");
|
||||||
iw_entry_d(iw, "speed", priv->speed);
|
iw_entry(iw, "speed", "%d", (int)priv->speed);
|
||||||
|
|
||||||
iw_comment(iw, "Analog noise filter enable (Y,N)");
|
iw_comment(iw, "Analog noise filter enable (Y,N)");
|
||||||
iw_entry_s(iw, "analog-filter", str_yn(priv->anf));
|
iw_entry(iw, "analog-filter", "%s", str_yn(priv->anf));
|
||||||
|
|
||||||
iw_comment(iw, "Digital noise filter bandwidth (0-15)");
|
iw_comment(iw, "Digital noise filter bandwidth (0-15)");
|
||||||
iw_entry_d(iw, "digital-filter", priv->dnf);
|
iw_entry(iw, "digital-filter", "%d", (int)priv->dnf);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ error_t UU_Npx_Clear(Unit *unit)
|
|||||||
CHECK_TYPE(unit, &UNIT_NEOPIXEL);
|
CHECK_TYPE(unit, &UNIT_NEOPIXEL);
|
||||||
|
|
||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
ws2812_clear(priv->port, priv->ll_pin, priv->cfg.pixels);
|
ws2812_clear(priv->port, priv->ll_pin, priv->pixels);
|
||||||
return E_SUCCESS;
|
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);
|
CHECK_TYPE(unit, &UNIT_NEOPIXEL);
|
||||||
|
|
||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
if (nbytes != 3*priv->cfg.pixels) return E_BAD_COUNT;
|
if (nbytes != 3*priv->pixels) return E_BAD_COUNT;
|
||||||
ws2812_load_raw(priv->port, priv->ll_pin, packed_rgb, priv->cfg.pixels);
|
ws2812_load_raw(priv->port, priv->ll_pin, packed_rgb, priv->pixels);
|
||||||
return E_SUCCESS;
|
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);
|
CHECK_TYPE(unit, &UNIT_NEOPIXEL);
|
||||||
|
|
||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
if (nbytes != 4*priv->cfg.pixels) return E_BAD_COUNT;
|
if (nbytes != 4*priv->pixels) return E_BAD_COUNT;
|
||||||
ws2812_load_sparse(priv->port, priv->ll_pin, bytes, priv->cfg.pixels, bige);
|
ws2812_load_sparse(priv->port, priv->ll_pin, bytes, priv->pixels, bige);
|
||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +60,6 @@ error_t UU_Npx_GetCount(Unit *unit, uint16_t *count)
|
|||||||
CHECK_TYPE(unit, &UNIT_NEOPIXEL);
|
CHECK_TYPE(unit, &UNIT_NEOPIXEL);
|
||||||
|
|
||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
*count = priv->cfg.pixels;
|
*count = priv->pixels;
|
||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ error_t Npx_preInit(Unit *unit)
|
|||||||
if (priv == NULL) return E_OUT_OF_MEM;
|
if (priv == NULL) return E_OUT_OF_MEM;
|
||||||
|
|
||||||
// some defaults
|
// some defaults
|
||||||
priv->cfg.pin = R_PA0;
|
priv->pin_number = 0;
|
||||||
priv->cfg.pixels = 1;
|
priv->port_name = 'A';
|
||||||
|
priv->pixels = 1;
|
||||||
|
|
||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -29,9 +30,13 @@ error_t Npx_init(Unit *unit)
|
|||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
// --- Parse config ---
|
// --- Parse config ---
|
||||||
suc = hw_pinrsc2ll(priv->cfg.pin, &priv->port, &priv->ll_pin);
|
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);
|
||||||
if (!suc) return E_BAD_CONFIG;
|
if (!suc) return E_BAD_CONFIG;
|
||||||
TRY(rsc_claim(unit, priv->cfg.pin));
|
|
||||||
|
// --- Claim resources ---
|
||||||
|
TRY(rsc_claim(unit, rsc));
|
||||||
|
|
||||||
// --- Init hardware ---
|
// --- Init hardware ---
|
||||||
LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT);
|
LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT);
|
||||||
@@ -40,7 +45,7 @@ error_t Npx_init(Unit *unit)
|
|||||||
|
|
||||||
// clear strip
|
// clear strip
|
||||||
|
|
||||||
ws2812_clear(priv->port, priv->ll_pin, priv->cfg.pixels);
|
ws2812_clear(priv->port, priv->ll_pin, priv->pixels);
|
||||||
|
|
||||||
return E_SUCCESS;
|
return E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,9 @@
|
|||||||
|
|
||||||
/** Private data structure */
|
/** Private data structure */
|
||||||
struct priv {
|
struct priv {
|
||||||
struct {
|
char port_name;
|
||||||
Resource pin;
|
uint8_t pin_number;
|
||||||
uint16_t pixels;
|
uint16_t pixels;
|
||||||
} cfg;
|
|
||||||
|
|
||||||
uint32_t ll_pin;
|
uint32_t ll_pin;
|
||||||
GPIO_TypeDef *port;
|
GPIO_TypeDef *port;
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ void Npx_loadBinary(Unit *unit, PayloadParser *pp)
|
|||||||
{
|
{
|
||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
priv->cfg.pin = (Resource) pp_u8(pp);
|
priv->port_name = pp_char(pp);
|
||||||
priv->cfg.pixels = pp_u16(pp);
|
priv->pin_number = pp_u8(pp);
|
||||||
|
priv->pixels = pp_u16(pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Write to a binary buffer for storing in Flash */
|
/** Write to a binary buffer for storing in Flash */
|
||||||
@@ -22,8 +23,9 @@ void Npx_writeBinary(Unit *unit, PayloadBuilder *pb)
|
|||||||
{
|
{
|
||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
pb_u8(pb, priv->cfg.pin);
|
pb_char(pb, priv->port_name);
|
||||||
pb_u16(pb, priv->cfg.pixels);
|
pb_u8(pb, priv->pin_number);
|
||||||
|
pb_u16(pb, priv->pixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
@@ -35,10 +37,10 @@ error_t Npx_loadIni(Unit *unit, const char *key, const char *value)
|
|||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
if (streq(key, "pin")) {
|
if (streq(key, "pin")) {
|
||||||
priv->cfg.pin = cfg_pinrsc_parse(value, &suc);
|
suc = parse_pin(value, &priv->port_name, &priv->pin_number);
|
||||||
}
|
}
|
||||||
else if (streq(key, "pixels")) {
|
else if (streq(key, "pixels")) {
|
||||||
priv->cfg.pixels = cfg_u16_parse(value, &suc);
|
priv->pixels = (uint16_t) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return E_BAD_KEY;
|
return E_BAD_KEY;
|
||||||
@@ -54,8 +56,8 @@ void Npx_writeIni(Unit *unit, IniWriter *iw)
|
|||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
iw_comment(iw, "Data pin");
|
iw_comment(iw, "Data pin");
|
||||||
iw_entry_s(iw, "pin", cfg_pinrsc_encode(priv->cfg.pin));
|
iw_entry(iw, "pin", "%c%d", priv->port_name, priv->pin_number);
|
||||||
|
|
||||||
iw_comment(iw, "Number of pixels");
|
iw_comment(iw, "Number of pixels");
|
||||||
iw_entry_d(iw, "pixels", priv->cfg.pixels);
|
iw_entry(iw, "pixels", "%d", priv->pixels);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
//
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
//
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
//
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
//
|
|
||||||
// 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,
|
|
||||||
};
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
#include "unit_sipo.h"
|
|
||||||
|
|
||||||
#define SIPO_INTERNAL
|
|
||||||
#include "_sipo_internal.h"
|
|
||||||
|
|
||||||
static void send_pulse(bool pol, GPIO_TypeDef *port, uint32_t ll)
|
|
||||||
{
|
|
||||||
if (pol) {
|
|
||||||
LL_GPIO_SetOutputPin(port, ll);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LL_GPIO_ResetOutputPin(port, ll);
|
|
||||||
}
|
|
||||||
|
|
||||||
__asm_loop(2);
|
|
||||||
|
|
||||||
if (pol) {
|
|
||||||
LL_GPIO_ResetOutputPin(port, ll);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LL_GPIO_SetOutputPin(port, ll);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma GCC push_options
|
|
||||||
#pragma GCC optimize ("O2")
|
|
||||||
error_t UU_SIPO_Write(Unit *unit, const uint8_t *buffer, uint16_t buflen, uint16_t terminal_data)
|
|
||||||
{
|
|
||||||
CHECK_TYPE(unit, &UNIT_SIPO);
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
if (buflen % priv->data_width != 0) {
|
|
||||||
dbg("Buflen %d vs width %d", (int)buflen, (int)priv->data_width);
|
|
||||||
return E_BAD_COUNT; // must be a multiple of the channel count
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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->cfg.data_pins;
|
|
||||||
|
|
||||||
uint8_t offsets[16];
|
|
||||||
for (int i=0; i<16; i++) offsets[i] = (uint8_t) (bytelen * i);
|
|
||||||
|
|
||||||
for (int32_t bn = bytelen - 1; bn >= 0; bn--) {
|
|
||||||
// send the byte
|
|
||||||
for (int32_t i = 0; i < 8; i++) {
|
|
||||||
uint16_t packed = 0;
|
|
||||||
for (int32_t j = data_width - 1; j >= 0; j--) {
|
|
||||||
packed |= (buffer[bn + offsets[j]] >> i) & 1;
|
|
||||||
if (j > 0) packed <<= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t spread = pinmask_spread(packed, mask);
|
|
||||||
priv->data_port->BSRR = spread | (((~spread) & mask) << 16);
|
|
||||||
|
|
||||||
// Shift clock pulse
|
|
||||||
send_pulse(priv->cfg.shift_pol, priv->shift_port, priv->shift_ll);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// load the final data - this may be used by some other circuitry or
|
|
||||||
// simply to rest the lines at a defined known level
|
|
||||||
uint16_t spread = pinmask_spread(terminal_data, mask);
|
|
||||||
priv->data_port->BSRR = spread | (((~spread) & mask) << 16);
|
|
||||||
|
|
||||||
send_pulse(priv->cfg.store_pol, priv->store_port, priv->store_ll);
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
#pragma GCC pop_options
|
|
||||||
|
|
||||||
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->cfg.data_pins);
|
|
||||||
priv->data_port->BSRR = spread | (((~spread) & priv->cfg.data_pins) << 16);
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
error_t UU_SIPO_DirectClear(Unit *unit)
|
|
||||||
{
|
|
||||||
CHECK_TYPE(unit, &UNIT_SIPO);
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
send_pulse(priv->cfg.clear_pol, priv->clear_port, priv->clear_ll);
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
error_t UU_SIPO_DirectShift(Unit *unit)
|
|
||||||
{
|
|
||||||
CHECK_TYPE(unit, &UNIT_SIPO);
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
send_pulse(priv->cfg.shift_pol, priv->shift_port, priv->shift_ll);
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
error_t UU_SIPO_DirectStore(Unit *unit)
|
|
||||||
{
|
|
||||||
CHECK_TYPE(unit, &UNIT_SIPO);
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
send_pulse(priv->cfg.store_pol, priv->store_port, priv->store_ll);
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
|
|
||||||
#define SIPO_INTERNAL
|
|
||||||
#include "_sipo_internal.h"
|
|
||||||
|
|
||||||
/** Allocate data structure and set defaults */
|
|
||||||
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->cfg.pin_store = R_PA0;
|
|
||||||
priv->cfg.store_pol = true;
|
|
||||||
|
|
||||||
priv->cfg.pin_shift = R_PA1;
|
|
||||||
priv->cfg.shift_pol = true;
|
|
||||||
|
|
||||||
priv->cfg.pin_clear = R_PA2;
|
|
||||||
priv->cfg.clear_pol = false;
|
|
||||||
|
|
||||||
priv->cfg.data_pname = 'A';
|
|
||||||
priv->cfg.data_pins = (1<<3);
|
|
||||||
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Finalize unit set-up */
|
|
||||||
error_t USIPO_init(Unit *unit)
|
|
||||||
{
|
|
||||||
bool suc = true;
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
// --- Parse config ---
|
|
||||||
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, 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->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->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);
|
|
||||||
LL_GPIO_SetPinSpeed(priv->data_port, ll_pin, LL_GPIO_SPEED_FREQ_HIGH);
|
|
||||||
priv->data_width++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the initial state - zeros
|
|
||||||
priv->data_port->ODR &= ~priv->cfg.data_pins;
|
|
||||||
|
|
||||||
|
|
||||||
// STORE
|
|
||||||
LL_GPIO_SetPinMode(priv->store_port, priv->store_ll, LL_GPIO_MODE_OUTPUT);
|
|
||||||
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->cfg.store_pol)
|
|
||||||
LL_GPIO_ResetOutputPin(priv->store_port, priv->store_ll);
|
|
||||||
else
|
|
||||||
LL_GPIO_SetOutputPin(priv->store_port, priv->store_ll);
|
|
||||||
|
|
||||||
// SHIFT
|
|
||||||
LL_GPIO_SetPinMode(priv->shift_port, priv->shift_ll, LL_GPIO_MODE_OUTPUT);
|
|
||||||
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->cfg.shift_pol)
|
|
||||||
LL_GPIO_ResetOutputPin(priv->shift_port, priv->shift_ll);
|
|
||||||
else
|
|
||||||
LL_GPIO_SetOutputPin(priv->shift_port, priv->shift_ll);
|
|
||||||
|
|
||||||
// CLEAR
|
|
||||||
LL_GPIO_SetPinMode(priv->clear_port, priv->clear_ll, LL_GPIO_MODE_OUTPUT);
|
|
||||||
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->cfg.clear_pol)
|
|
||||||
LL_GPIO_ResetOutputPin(priv->clear_port, priv->clear_ll);
|
|
||||||
else
|
|
||||||
LL_GPIO_SetOutputPin(priv->clear_port, priv->clear_ll);
|
|
||||||
|
|
||||||
// initial clear
|
|
||||||
UU_SIPO_DirectClear(unit);
|
|
||||||
|
|
||||||
return E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Tear down the unit */
|
|
||||||
void USIPO_deInit(Unit *unit)
|
|
||||||
{
|
|
||||||
// Release all resources, deinit pins
|
|
||||||
rsc_teardown(unit);
|
|
||||||
|
|
||||||
// Free memory
|
|
||||||
free_ck(unit->data);
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef GEX_F072_SIPO_INTERNAL_H
|
|
||||||
#define GEX_F072_SIPO_INTERNAL_H
|
|
||||||
|
|
||||||
#ifndef SIPO_INTERNAL
|
|
||||||
#error bad include!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "unit_base.h"
|
|
||||||
|
|
||||||
/** Private data structure */
|
|
||||||
struct priv {
|
|
||||||
struct {
|
|
||||||
// settings
|
|
||||||
Resource pin_store;
|
|
||||||
bool store_pol; //!< Store pulse active edge
|
|
||||||
|
|
||||||
Resource pin_shift;
|
|
||||||
bool shift_pol; //!< Shift clock active edge
|
|
||||||
|
|
||||||
Resource pin_clear;
|
|
||||||
bool clear_pol; //!< Clear signal active level
|
|
||||||
|
|
||||||
char data_pname;
|
|
||||||
uint16_t data_pins;
|
|
||||||
} cfg;
|
|
||||||
|
|
||||||
// live fields
|
|
||||||
uint32_t store_ll;
|
|
||||||
uint32_t shift_ll;
|
|
||||||
uint32_t clear_ll;
|
|
||||||
|
|
||||||
GPIO_TypeDef *store_port;
|
|
||||||
GPIO_TypeDef *shift_port;
|
|
||||||
GPIO_TypeDef *clear_port;
|
|
||||||
GPIO_TypeDef *data_port;
|
|
||||||
|
|
||||||
uint8_t data_width;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Allocate data structure and set defaults */
|
|
||||||
error_t USIPO_preInit(Unit *unit);
|
|
||||||
|
|
||||||
/** Load from a binary buffer stored in Flash */
|
|
||||||
void USIPO_loadBinary(Unit *unit, PayloadParser *pp);
|
|
||||||
|
|
||||||
/** Write to a binary buffer for storing in Flash */
|
|
||||||
void USIPO_writeBinary(Unit *unit, PayloadBuilder *pb);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Parse a key-value pair from the INI file */
|
|
||||||
error_t USIPO_loadIni(Unit *unit, const char *key, const char *value);
|
|
||||||
|
|
||||||
/** Generate INI file section for the unit */
|
|
||||||
void USIPO_writeIni(Unit *unit, IniWriter *iw);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Finalize unit set-up */
|
|
||||||
error_t USIPO_init(Unit *unit);
|
|
||||||
|
|
||||||
/** Tear down the unit */
|
|
||||||
void USIPO_deInit(Unit *unit);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a buffer to the pins.
|
|
||||||
* Buffer contains data for the individual channels, sequentially (AAAAAA BBBBBB CCCCCC ...)
|
|
||||||
* The bytes are sent LSB first, from the last byte (e.g. 1,2,3 - 3 is sent first, LSB-first).
|
|
||||||
*
|
|
||||||
* The chunks order is from the lowest to the highest bit
|
|
||||||
*
|
|
||||||
* @param unit
|
|
||||||
* @param buffer - buffer of data to send
|
|
||||||
* @param buflen - number of bytes in the buffer
|
|
||||||
* @param terminal_data - data to set before sending the store pulse (final data lines state, will not appear in the SIPOs)
|
|
||||||
* @return success
|
|
||||||
*/
|
|
||||||
error_t UU_SIPO_Write(Unit *unit, const uint8_t *buffer, uint16_t buflen, uint16_t terminal_data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Direct access to the output data pins (may be useful for debugging, or circuits that use them
|
|
||||||
* for something else when not loading a new value).
|
|
||||||
*
|
|
||||||
* @param unit
|
|
||||||
* @param data_packed - packed data to set on the output (right-aligned, highest to lowest pin)
|
|
||||||
* @return success
|
|
||||||
*/
|
|
||||||
error_t UU_SIPO_DirectData(Unit *unit, uint16_t data_packed);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a clear pulse.
|
|
||||||
*
|
|
||||||
* @param unit
|
|
||||||
* @return success
|
|
||||||
*/
|
|
||||||
error_t UU_SIPO_DirectClear(Unit *unit);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a shift pulse.
|
|
||||||
*
|
|
||||||
* @param unit
|
|
||||||
* @return success
|
|
||||||
*/
|
|
||||||
error_t UU_SIPO_DirectShift(Unit *unit);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a store pulse.
|
|
||||||
*
|
|
||||||
* @param unit
|
|
||||||
* @return success
|
|
||||||
*/
|
|
||||||
error_t UU_SIPO_DirectStore(Unit *unit);
|
|
||||||
|
|
||||||
#endif //GEX_F072_SIPO_INTERNAL_H
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/03.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "unit_base.h"
|
|
||||||
|
|
||||||
#define SIPO_INTERNAL
|
|
||||||
#include "_sipo_internal.h"
|
|
||||||
|
|
||||||
/** Load from a binary buffer stored in Flash */
|
|
||||||
void USIPO_loadBinary(Unit *unit, PayloadParser *pp)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
uint8_t version = pp_u8(pp);
|
|
||||||
(void)version;
|
|
||||||
|
|
||||||
priv->cfg.pin_store = (Resource) pp_u8(pp);
|
|
||||||
priv->cfg.store_pol = pp_bool(pp);
|
|
||||||
|
|
||||||
priv->cfg.pin_shift = (Resource) pp_u8(pp);
|
|
||||||
priv->cfg.shift_pol = pp_bool(pp);
|
|
||||||
|
|
||||||
priv->cfg.pin_clear = (Resource) pp_u8(pp);
|
|
||||||
priv->cfg.clear_pol = pp_bool(pp);
|
|
||||||
|
|
||||||
priv->cfg.data_pname = pp_char(pp);
|
|
||||||
priv->cfg.data_pins = pp_u16(pp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Write to a binary buffer for storing in Flash */
|
|
||||||
void USIPO_writeBinary(Unit *unit, PayloadBuilder *pb)
|
|
||||||
{
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
pb_u8(pb, 0); // version
|
|
||||||
|
|
||||||
pb_u8(pb, priv->cfg.pin_store);
|
|
||||||
pb_bool(pb, priv->cfg.store_pol);
|
|
||||||
|
|
||||||
pb_u8(pb, priv->cfg.pin_shift);
|
|
||||||
pb_bool(pb, priv->cfg.shift_pol);
|
|
||||||
|
|
||||||
pb_u8(pb, priv->cfg.pin_clear);
|
|
||||||
pb_bool(pb, priv->cfg.clear_pol);
|
|
||||||
|
|
||||||
pb_char(pb, priv->cfg.data_pname);
|
|
||||||
pb_u16(pb, priv->cfg.data_pins);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Parse a key-value pair from the INI file */
|
|
||||||
error_t USIPO_loadIni(Unit *unit, const char *key, const char *value)
|
|
||||||
{
|
|
||||||
bool suc = true;
|
|
||||||
struct priv *priv = unit->data;
|
|
||||||
|
|
||||||
if (streq(key, "store-pin")) {
|
|
||||||
priv->cfg.pin_store = cfg_pinrsc_parse(value, &suc);
|
|
||||||
}
|
|
||||||
else if (streq(key, "shift-pin")) {
|
|
||||||
priv->cfg.pin_shift = cfg_pinrsc_parse(value, &suc);
|
|
||||||
}
|
|
||||||
else if (streq(key, "clear-pin")) {
|
|
||||||
priv->cfg.pin_clear = cfg_pinrsc_parse(value, &suc);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (streq(key, "store-pol")) {
|
|
||||||
priv->cfg.store_pol = cfg_bool_parse(value, &suc);
|
|
||||||
}
|
|
||||||
else if (streq(key, "shift-pol")) {
|
|
||||||
priv->cfg.shift_pol = cfg_bool_parse(value, &suc);
|
|
||||||
}
|
|
||||||
else if (streq(key, "clear-pol")) {
|
|
||||||
priv->cfg.clear_pol = cfg_bool_parse(value, &suc);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (streq(key, "data-port")) {
|
|
||||||
suc = cfg_port_parse(value, &priv->cfg.data_pname);
|
|
||||||
}
|
|
||||||
else if (streq(key, "data-pins")) {
|
|
||||||
priv->cfg.data_pins = cfg_pinmask_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 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_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_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_s(iw, "clear-pin", cfg_pinrsc_encode(priv->cfg.pin_clear));
|
|
||||||
iw_entry_d(iw, "clear-pol", priv->cfg.clear_pol);
|
|
||||||
|
|
||||||
iw_comment(iw, "Data port and pins");
|
|
||||||
iw_entry(iw, "data-port", "%c", priv->cfg.data_pname);
|
|
||||||
iw_entry_s(iw, "data-pins", cfg_pinmask_encode(priv->cfg.data_pins, unit_tmp512, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2017/11/25.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "unit_base.h"
|
|
||||||
#include "unit_sipo.h"
|
|
||||||
|
|
||||||
#define SIPO_INTERNAL
|
|
||||||
|
|
||||||
#include "_sipo_internal.h"
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
enum SipoCmd_ {
|
|
||||||
CMD_WRITE = 0,
|
|
||||||
CMD_DIRECT_DATA = 1,
|
|
||||||
CMD_DIRECT_SHIFT = 2,
|
|
||||||
CMD_DIRECT_CLEAR = 3,
|
|
||||||
CMD_DIRECT_STORE = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Handle a request message */
|
|
||||||
static error_t USIPO_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
|
|
||||||
{
|
|
||||||
switch (command) {
|
|
||||||
case CMD_WRITE:
|
|
||||||
{
|
|
||||||
uint32_t len;
|
|
||||||
uint16_t terminal_packed = pp_u16(pp);
|
|
||||||
const uint8_t *tail = pp_tail(pp, &len);
|
|
||||||
TRY(UU_SIPO_Write(unit, (uint8_t *) tail, (uint16_t) len, terminal_packed));
|
|
||||||
}
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
case CMD_DIRECT_DATA:
|
|
||||||
TRY(UU_SIPO_DirectData(unit, pp_u16(pp)));
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
case CMD_DIRECT_CLEAR:
|
|
||||||
TRY(UU_SIPO_DirectClear(unit));
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
case CMD_DIRECT_SHIFT:
|
|
||||||
TRY(UU_SIPO_DirectShift(unit));
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
case CMD_DIRECT_STORE:
|
|
||||||
TRY(UU_SIPO_DirectStore(unit));
|
|
||||||
return E_SUCCESS;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return E_UNKNOWN_COMMAND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Unit template */
|
|
||||||
const UnitDriver UNIT_SIPO = {
|
|
||||||
.name = "SIPO",
|
|
||||||
.description = "Shift register driver (595, 4094)",
|
|
||||||
// Settings
|
|
||||||
.preInit = USIPO_preInit,
|
|
||||||
.cfgLoadBinary = USIPO_loadBinary,
|
|
||||||
.cfgWriteBinary = USIPO_writeBinary,
|
|
||||||
.cfgLoadIni = USIPO_loadIni,
|
|
||||||
.cfgWriteIni = USIPO_writeIni,
|
|
||||||
// Init
|
|
||||||
.init = USIPO_init,
|
|
||||||
.deInit = USIPO_deInit,
|
|
||||||
// Function
|
|
||||||
.handleRequest = USIPO_handleRequest,
|
|
||||||
};
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2017/11/25.
|
|
||||||
//
|
|
||||||
// Digital input unit; single or multiple pin read access on one port (A-F)
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef U_SIPO_H
|
|
||||||
#define U_SIPO_H
|
|
||||||
|
|
||||||
#include "unit.h"
|
|
||||||
|
|
||||||
extern const UnitDriver UNIT_SIPO;
|
|
||||||
|
|
||||||
// UU_ prototypes
|
|
||||||
|
|
||||||
#endif //U_SIPO_H
|
|
||||||
+19
-17
@@ -58,31 +58,31 @@ error_t USPI_loadIni(Unit *unit, const char *key, const char *value)
|
|||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
if (streq(key, "device")) {
|
if (streq(key, "device")) {
|
||||||
priv->periph_num = cfg_u8_parse(value, &suc);
|
priv->periph_num = (uint8_t) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "remap")) {
|
else if (streq(key, "remap")) {
|
||||||
priv->remap = cfg_u8_parse(value, &suc);
|
priv->remap = (uint8_t) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "prescaller")) {
|
else if (streq(key, "prescaller")) {
|
||||||
priv->prescaller = cfg_u16_parse(value, &suc);
|
priv->prescaller = (uint16_t ) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "cpol")) {
|
else if (streq(key, "cpol")) {
|
||||||
priv->cpol = cfg_bool_parse(value, &suc);
|
priv->cpol = (bool) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "cpha")) {
|
else if (streq(key, "cpha")) {
|
||||||
priv->cpha = cfg_bool_parse(value, &suc);
|
priv->cpha = (bool) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "tx-only")) {
|
else if (streq(key, "tx-only")) {
|
||||||
priv->tx_only = cfg_bool_parse(value, &suc);
|
priv->tx_only = str_parse_yn(value, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "first-bit")) {
|
else if (streq(key, "first-bit")) {
|
||||||
priv->lsb_first = (bool) cfg_enum2_parse(value, "MSB", 0, "LSB", 1, &suc);
|
priv->lsb_first = (bool)str_parse_2(value, "MSB", 0, "LSB", 1, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "port")) {
|
else if (streq(key, "port")) {
|
||||||
suc = cfg_port_parse(value, &priv->ssn_port_name);
|
suc = parse_port_name(value, &priv->ssn_port_name);
|
||||||
}
|
}
|
||||||
else if (streq(key, "pins")) {
|
else if (streq(key, "pins")) {
|
||||||
priv->ssn_pins = cfg_pinmask_parse(value, &suc);
|
priv->ssn_pins = parse_pinmask(value, &suc);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return E_BAD_KEY;
|
return E_BAD_KEY;
|
||||||
@@ -98,7 +98,7 @@ void USPI_writeIni(Unit *unit, IniWriter *iw)
|
|||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
iw_comment(iw, "Peripheral number (SPIx)");
|
iw_comment(iw, "Peripheral number (SPIx)");
|
||||||
iw_entry_d(iw, "device", priv->periph_num);
|
iw_entry(iw, "device", "%d", (int)priv->periph_num);
|
||||||
|
|
||||||
// TODO show a legend for peripherals and remaps
|
// TODO show a legend for peripherals and remaps
|
||||||
iw_comment(iw, "Pin mappings (SCK,MISO,MOSI)");
|
iw_comment(iw, "Pin mappings (SCK,MISO,MOSI)");
|
||||||
@@ -114,28 +114,30 @@ void USPI_writeIni(Unit *unit, IniWriter *iw)
|
|||||||
#else
|
#else
|
||||||
#error "BAD PLATFORM!"
|
#error "BAD PLATFORM!"
|
||||||
#endif
|
#endif
|
||||||
iw_entry_d(iw, "remap", priv->remap);
|
iw_entry(iw, "remap", "%d", (int)priv->remap);
|
||||||
|
|
||||||
iw_cmt_newline(iw);
|
iw_cmt_newline(iw);
|
||||||
iw_comment(iw, "Prescaller: 2,4,8,...,256");
|
iw_comment(iw, "Prescaller: 2,4,8,...,256");
|
||||||
iw_entry_d(iw, "prescaller", priv->prescaller);
|
iw_entry(iw, "prescaller", "%d", (int)priv->prescaller);
|
||||||
|
|
||||||
iw_comment(iw, "Clock polarity: 0,1 (clock idle level)");
|
iw_comment(iw, "Clock polarity: 0,1 (clock idle level)");
|
||||||
iw_entry_d(iw, "cpol", priv->cpol);
|
iw_entry(iw, "cpol", "%d", (int)priv->cpol);
|
||||||
|
|
||||||
iw_comment(iw, "Clock phase: 0,1 (active edge, 0-first, 1-second)");
|
iw_comment(iw, "Clock phase: 0,1 (active edge, 0-first, 1-second)");
|
||||||
iw_entry_d(iw, "cpha", priv->cpha);
|
iw_entry(iw, "cpha", "%d", (int)priv->cpha);
|
||||||
|
|
||||||
iw_comment(iw, "Transmit only, disable MISO");
|
iw_comment(iw, "Transmit only, disable MISO");
|
||||||
iw_entry_s(iw, "tx-only", str_yn(priv->tx_only));
|
iw_entry(iw, "tx-only", str_yn(priv->tx_only));
|
||||||
|
|
||||||
iw_comment(iw, "Bit order (LSB or MSB first)");
|
iw_comment(iw, "Bit order (LSB or MSB first)");
|
||||||
iw_entry_s(iw, "first-bit", cfg_enum2_encode((uint32_t) priv->lsb_first, 0, "MSB", 1, "LSB"));
|
iw_entry(iw, "first-bit", str_2((uint32_t)priv->lsb_first,
|
||||||
|
0, "MSB",
|
||||||
|
1, "LSB"));
|
||||||
|
|
||||||
iw_cmt_newline(iw);
|
iw_cmt_newline(iw);
|
||||||
iw_comment(iw, "SS port name");
|
iw_comment(iw, "SS port name");
|
||||||
iw_entry(iw, "port", "%c", priv->ssn_port_name);
|
iw_entry(iw, "port", "%c", priv->ssn_port_name);
|
||||||
|
|
||||||
iw_comment(iw, "SS pins (comma separated, supports ranges)");
|
iw_comment(iw, "SS pins (comma separated, supports ranges)");
|
||||||
iw_entry_s(iw, "pins", cfg_pinmask_encode(priv->ssn_pins, unit_tmp512, 0));
|
iw_entry(iw, "pins", "%s", pinmask2str(priv->ssn_pins, unit_tmp512));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
#!/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
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
//
|
|
||||||
// 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"
|
|
||||||
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
//
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
@@ -1,221 +0,0 @@
|
|||||||
//
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
//
|
|
||||||
// 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
//
|
|
||||||
// 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,
|
|
||||||
};
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
@@ -81,66 +81,66 @@ error_t UUSART_loadIni(Unit *unit, const char *key, const char *value)
|
|||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
if (streq(key, "device")) {
|
if (streq(key, "device")) {
|
||||||
priv->periph_num = cfg_u8_parse(value, &suc);
|
priv->periph_num = (uint8_t) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "remap")) {
|
else if (streq(key, "remap")) {
|
||||||
priv->remap = cfg_u8_parse(value, &suc);
|
priv->remap = (uint8_t) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "baud-rate")) {
|
else if (streq(key, "baud-rate")) {
|
||||||
priv->baudrate = cfg_u32_parse(value, &suc);
|
priv->baudrate = (uint32_t ) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "parity")) {
|
else if (streq(key, "parity")) {
|
||||||
priv->parity = (uint8_t) cfg_enum3_parse(value,
|
priv->parity = (uint8_t) str_parse_3(value,
|
||||||
"NONE", 0,
|
"NONE", 0,
|
||||||
"ODD", 1,
|
"ODD", 1,
|
||||||
"EVEN", 2, &suc);
|
"EVEN", 2, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "stop-bits")) {
|
else if (streq(key, "stop-bits")) {
|
||||||
priv->stopbits = (uint8_t) cfg_enum4_parse(value,
|
priv->stopbits = (uint8_t) str_parse_4(value,
|
||||||
"0.5", 0,
|
"0.5", 0,
|
||||||
"1", 1,
|
"1", 1,
|
||||||
"1.5", 2,
|
"1.5", 2,
|
||||||
"2", 3, &suc);
|
"2", 3, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "direction")) {
|
else if (streq(key, "direction")) {
|
||||||
priv->direction = (uint8_t) cfg_enum3_parse(value,
|
priv->direction = (uint8_t) str_parse_3(value,
|
||||||
"RX", UUSART_DIRECTION_RX,
|
"RX", UUSART_DIRECTION_RX,
|
||||||
"TX", UUSART_DIRECTION_TX,
|
"TX", UUSART_DIRECTION_TX,
|
||||||
"RXTX", UUSART_DIRECTION_RXTX, &suc);
|
"RXTX", UUSART_DIRECTION_RXTX, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "hw-flow-control")) {
|
else if (streq(key, "hw-flow-control")) {
|
||||||
priv->hw_flow_control = (uint8_t) cfg_enum4_parse(value,
|
priv->hw_flow_control = (uint8_t) str_parse_4(value,
|
||||||
"NONE", 0,
|
"NONE", 0,
|
||||||
"RTS", 1,
|
"RTS", 1,
|
||||||
"CTS", 2,
|
"CTS", 2,
|
||||||
"FULL", 3, &suc);
|
"FULL", 3, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "word-width")) {
|
else if (streq(key, "word-width")) {
|
||||||
priv->width = cfg_u8_parse(value, &suc);
|
priv->width = (uint8_t ) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "first-bit")) {
|
else if (streq(key, "first-bit")) {
|
||||||
priv->lsb_first = (bool) cfg_enum2_parse(value, "MSB", 0, "LSB", 1, &suc);
|
priv->lsb_first = (bool)str_parse_2(value, "MSB", 0, "LSB", 1, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "clock-output")) {
|
else if (streq(key, "clock-output")) {
|
||||||
priv->clock_output = cfg_bool_parse(value, &suc);
|
priv->clock_output = str_parse_yn(value, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "cpol")) {
|
else if (streq(key, "cpol")) {
|
||||||
priv->cpol = cfg_bool_parse(value, &suc);
|
priv->cpol = (bool) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "cpha")) {
|
else if (streq(key, "cpha")) {
|
||||||
priv->cpha = cfg_bool_parse(value, &suc);
|
priv->cpha = (bool) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "de-output")) {
|
else if (streq(key, "de-output")) {
|
||||||
priv->de_output = cfg_bool_parse(value, &suc);
|
priv->de_output = str_parse_yn(value, &suc);
|
||||||
}
|
}
|
||||||
else if (streq(key, "de-polarity")) {
|
else if (streq(key, "de-polarity")) {
|
||||||
priv->de_polarity = cfg_bool_parse(value, &suc);
|
priv->de_polarity = (bool) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "de-assert-time")) {
|
else if (streq(key, "de-assert-time")) {
|
||||||
priv->de_assert_time = cfg_u8_parse(value, &suc);
|
priv->de_assert_time = (uint8_t) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else if (streq(key, "de-clear-time")) {
|
else if (streq(key, "de-clear-time")) {
|
||||||
priv->de_clear_time = cfg_u8_parse(value, &suc);
|
priv->de_clear_time = (uint8_t) avr_atoi(value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return E_BAD_KEY;
|
return E_BAD_KEY;
|
||||||
@@ -156,7 +156,7 @@ void UUSART_writeIni(Unit *unit, IniWriter *iw)
|
|||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
|
|
||||||
iw_comment(iw, "Peripheral number (UARTx 1-4)");
|
iw_comment(iw, "Peripheral number (UARTx 1-4)");
|
||||||
iw_entry_d(iw, "device", priv->periph_num);
|
iw_entry(iw, "device", "%d", (int)priv->periph_num);
|
||||||
|
|
||||||
iw_comment(iw, "Pin mappings (TX,RX,CK,CTS,RTS/DE)");
|
iw_comment(iw, "Pin mappings (TX,RX,CK,CTS,RTS/DE)");
|
||||||
#if GEX_PLAT_F072_DISCOVERY
|
#if GEX_PLAT_F072_DISCOVERY
|
||||||
@@ -173,61 +173,61 @@ void UUSART_writeIni(Unit *unit, IniWriter *iw)
|
|||||||
#else
|
#else
|
||||||
#error "BAD PLATFORM!"
|
#error "BAD PLATFORM!"
|
||||||
#endif
|
#endif
|
||||||
iw_entry_d(iw, "remap", priv->remap);
|
iw_entry(iw, "remap", "%d", (int)priv->remap);
|
||||||
|
|
||||||
iw_cmt_newline(iw);
|
iw_cmt_newline(iw);
|
||||||
iw_comment(iw, "Baud rate in bps (eg. 9600)");
|
iw_comment(iw, "Baud rate in bps (eg. 9600, 115200)"); // TODO examples/range
|
||||||
iw_entry_d(iw, "baud-rate", priv->baudrate);
|
iw_entry(iw, "baud-rate", "%d", (int)priv->baudrate);
|
||||||
|
|
||||||
iw_comment(iw, "Parity type (NONE, ODD, EVEN)");
|
iw_comment(iw, "Parity type (NONE, ODD, EVEN)");
|
||||||
iw_entry_s(iw, "parity", cfg_enum3_encode(priv->parity,
|
iw_entry(iw, "parity", "%s", str_3(priv->parity,
|
||||||
0, "NONE",
|
0, "NONE",
|
||||||
1, "ODD",
|
1, "ODD",
|
||||||
2, "EVEN"));
|
2, "EVEN"));
|
||||||
|
|
||||||
iw_comment(iw, "Number of stop bits (0.5, 1, 1.5, 2)");
|
iw_comment(iw, "Number of stop bits (0.5, 1, 1.5, 2)");
|
||||||
iw_entry_s(iw, "stop-bits", cfg_enum4_encode(priv->stopbits,
|
iw_entry(iw, "stop-bits", "%s", str_4(priv->stopbits,
|
||||||
0, "0.5",
|
0, "0.5",
|
||||||
1, "1",
|
1, "1",
|
||||||
2, "1.5",
|
2, "1.5",
|
||||||
3, "2"));
|
3, "2"));
|
||||||
|
|
||||||
iw_comment(iw, "Bit order (LSB or MSB first)");
|
iw_comment(iw, "Bit order (LSB or MSB first)");
|
||||||
iw_entry_s(iw, "first-bit", cfg_enum2_encode((uint32_t) priv->lsb_first,
|
iw_entry(iw, "first-bit", str_2((uint32_t)priv->lsb_first,
|
||||||
0, "MSB",
|
0, "MSB",
|
||||||
1, "LSB"));
|
1, "LSB"));
|
||||||
|
|
||||||
iw_comment(iw, "Word width (7,8,9) - including parity bit if used");
|
iw_comment(iw, "Word width (7,8,9) - including parity bit if used");
|
||||||
iw_entry_d(iw, "word-width", (int)priv->width);
|
iw_entry(iw, "word-width", "%d", (int)priv->width);
|
||||||
|
|
||||||
iw_comment(iw, "Enabled lines (RX,TX,RXTX)");
|
iw_comment(iw, "Enabled lines (RX,TX,RXTX)");
|
||||||
iw_entry_s(iw, "direction", cfg_enum3_encode(priv->direction,
|
iw_entry(iw, "direction", str_3(priv->direction,
|
||||||
1, "RX",
|
1, "RX",
|
||||||
2, "TX",
|
2, "TX",
|
||||||
3, "RXTX"));
|
3, "RXTX"));
|
||||||
|
|
||||||
iw_comment(iw, "Hardware flow control (NONE, RTS, CTS, FULL)");
|
iw_comment(iw, "Hardware flow control (NONE, RTS, CTS, FULL)");
|
||||||
iw_entry_s(iw, "hw-flow-control", cfg_enum4_encode(priv->hw_flow_control,
|
iw_entry(iw, "hw-flow-control", "%s", str_4(priv->hw_flow_control,
|
||||||
0, "NONE",
|
0, "NONE",
|
||||||
1, "RTS",
|
1, "RTS",
|
||||||
2, "CTS",
|
2, "CTS",
|
||||||
3, "FULL"));
|
3, "FULL"));
|
||||||
|
|
||||||
iw_cmt_newline(iw);
|
iw_cmt_newline(iw);
|
||||||
iw_comment(iw, "Generate serial clock (Y,N)");
|
iw_comment(iw, "Generate serial clock (Y,N)");
|
||||||
iw_entry_s(iw, "clock-output", str_yn(priv->clock_output));
|
iw_entry(iw, "clock-output", str_yn(priv->clock_output));
|
||||||
iw_comment(iw, "Clock polarity: 0,1");
|
iw_comment(iw, "Output clock polarity: 0,1 (clock idle level)");
|
||||||
iw_entry_d(iw, "cpol", priv->cpol);
|
iw_entry(iw, "cpol", "%d", (int)priv->cpol);
|
||||||
iw_comment(iw, "Clock phase: 0,1");
|
iw_comment(iw, "Output clock phase: 0,1 (active edge, 0-first, 1-second)");
|
||||||
iw_entry_d(iw, "cpha", priv->cpha);
|
iw_entry(iw, "cpha", "%d", (int)priv->cpha);
|
||||||
|
|
||||||
iw_cmt_newline(iw);
|
iw_cmt_newline(iw);
|
||||||
iw_comment(iw, "Generate RS485 Driver Enable signal (Y,N) - uses RTS pin");
|
iw_comment(iw, "Generate RS485 Driver Enable signal (Y,N) - uses RTS pin");
|
||||||
iw_entry_s(iw, "de-output", str_yn(priv->de_output));
|
iw_entry(iw, "de-output", str_yn(priv->de_output));
|
||||||
iw_comment(iw, "DE active level: 0,1");
|
iw_comment(iw, "DE active level: 0,1");
|
||||||
iw_entry_d(iw, "de-polarity", (priv->de_polarity));
|
iw_entry(iw, "de-polarity", "%d", (int)(priv->de_polarity));
|
||||||
iw_comment(iw, "DE assert time (0-31)");
|
iw_comment(iw, "DE assert time (0-31)");
|
||||||
iw_entry_d(iw, "de-assert-time", (priv->de_assert_time));
|
iw_entry(iw, "de-assert-time", "%d", (int)(priv->de_assert_time));
|
||||||
iw_comment(iw, "DE clear time (0-31)");
|
iw_comment(iw, "DE clear time (0-31)");
|
||||||
iw_entry_d(iw, "de-clear-time", (priv->de_clear_time));
|
iw_entry(iw, "de-clear-time", "%d", (int)(priv->de_clear_time));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/* 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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/* 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);
|
||||||
|
}
|
||||||
+11
-11
@@ -37,10 +37,10 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "avrlibc.h"
|
#include "avrlibc.h"
|
||||||
|
|
||||||
/* Only GCC 4.2 calls the library function to convert an uint32_t
|
/* Only GCC 4.2 calls the library function to convert an unsigned long
|
||||||
to float. Other GCC-es (including 4.3) use a signed long to float
|
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. */
|
conversion along with a large inline code to correct the result. */
|
||||||
extern double __floatunsisf (uint32_t);
|
extern double __floatunsisf (unsigned long);
|
||||||
|
|
||||||
static const float pwr_p10 [6] = {
|
static const float pwr_p10 [6] = {
|
||||||
1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32
|
1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32
|
||||||
@@ -84,13 +84,13 @@ double
|
|||||||
avr_strtod (const char * nptr, char ** endptr)
|
avr_strtod (const char * nptr, char ** endptr)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
uint32_t u32;
|
unsigned long u32;
|
||||||
float flt;
|
float flt;
|
||||||
} x;
|
} x;
|
||||||
char c;
|
unsigned char c;
|
||||||
int32_t exp;
|
int exp;
|
||||||
|
|
||||||
uint8_t flag;
|
unsigned char flag;
|
||||||
#define FL_MINUS 0x01 /* number is negative */
|
#define FL_MINUS 0x01 /* number is negative */
|
||||||
#define FL_ANY 0x02 /* any digit was readed */
|
#define FL_ANY 0x02 /* any digit was readed */
|
||||||
#define FL_OVFL 0x04 /* overflow was */
|
#define FL_OVFL 0x04 /* overflow was */
|
||||||
@@ -178,7 +178,7 @@ avr_strtod (const char * nptr, char ** endptr)
|
|||||||
do {
|
do {
|
||||||
if (i < 3200)
|
if (i < 3200)
|
||||||
i = (((i << 2) + i) << 1) + c; /* i = 10*i + c */
|
i = (((i << 2) + i) << 1) + c; /* i = 10*i + c */
|
||||||
c = (char) (*nptr++ - '0');
|
c = *nptr++ - '0';
|
||||||
} while (c <= 9);
|
} while (c <= 9);
|
||||||
if (flag & FL_MEXP)
|
if (flag & FL_MEXP)
|
||||||
i = -i;
|
i = -i;
|
||||||
@@ -189,7 +189,7 @@ avr_strtod (const char * nptr, char ** endptr)
|
|||||||
if ((flag & FL_ANY) && endptr)
|
if ((flag & FL_ANY) && endptr)
|
||||||
*endptr = (char *)nptr - 1;
|
*endptr = (char *)nptr - 1;
|
||||||
|
|
||||||
x.flt = (float) __floatunsisf (x.u32); /* manually */
|
x.flt = __floatunsisf (x.u32); /* manually */
|
||||||
if ((flag & FL_MINUS) && (flag & FL_ANY))
|
if ((flag & FL_MINUS) && (flag & FL_ANY))
|
||||||
x.flt = -x.flt;
|
x.flt = -x.flt;
|
||||||
|
|
||||||
@@ -204,7 +204,7 @@ avr_strtod (const char * nptr, char ** endptr)
|
|||||||
for (pwr = 32; pwr; pwr >>= 1) {
|
for (pwr = 32; pwr; pwr >>= 1) {
|
||||||
for (; exp >= pwr; exp -= pwr) {
|
for (; exp >= pwr; exp -= pwr) {
|
||||||
union {
|
union {
|
||||||
uint32_t u32;
|
unsigned long u32;
|
||||||
float flt;
|
float flt;
|
||||||
} y;
|
} y;
|
||||||
y.u32 = (uint32_t) *((float *)nptr);
|
y.u32 = (uint32_t) *((float *)nptr);
|
||||||
@@ -213,7 +213,7 @@ avr_strtod (const char * nptr, char ** endptr)
|
|||||||
nptr -= sizeof(float);
|
nptr -= sizeof(float);
|
||||||
}
|
}
|
||||||
if (!isfinite(x.flt) || x.flt == 0)
|
if (!isfinite(x.flt) || x.flt == 0)
|
||||||
avrlibc_errno = ERANGE;
|
errno = ERANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return x.flt;
|
return x.flt;
|
||||||
|
|||||||
+18
-19
@@ -32,7 +32,6 @@
|
|||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "avrlibc.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert a string to a long integer.
|
* Convert a string to a long integer.
|
||||||
@@ -40,14 +39,14 @@
|
|||||||
* Ignores `locale' stuff. Assumes that the upper and lower case
|
* Ignores `locale' stuff. Assumes that the upper and lower case
|
||||||
* alphabets and digits are each contiguous.
|
* alphabets and digits are each contiguous.
|
||||||
*/
|
*/
|
||||||
int32_t
|
long
|
||||||
avr_strtol(const char *nptr, char **endptr, register int32_t base)
|
avr_strtol(const char *nptr, char **endptr, register int base)
|
||||||
{
|
{
|
||||||
register uint32_t acc;
|
register unsigned long acc;
|
||||||
register char c;
|
register unsigned char c;
|
||||||
register uint32_t cutoff;
|
register unsigned long cutoff;
|
||||||
register int8_t any;
|
register signed char any;
|
||||||
uint8_t flag = 0;
|
unsigned char flag = 0;
|
||||||
#define FL_NEG 0x01 /* number is negative */
|
#define FL_NEG 0x01 /* number is negative */
|
||||||
#define FL_0X 0x02 /* number has a 0x prefix */
|
#define FL_0X 0x02 /* number has a 0x prefix */
|
||||||
|
|
||||||
@@ -106,24 +105,24 @@ avr_strtol(const char *nptr, char **endptr, register int32_t base)
|
|||||||
* Set any if any `digits' consumed; make it negative to indicate
|
* Set any if any `digits' consumed; make it negative to indicate
|
||||||
* overflow.
|
* overflow.
|
||||||
*/
|
*/
|
||||||
#if INT32_MIN != -INT32_MAX - 1
|
#if LONG_MIN != -LONG_MAX - 1
|
||||||
# error "This implementation of strtol() does not work on this platform."
|
# error "This implementation of strtol() does not work on this platform."
|
||||||
#endif
|
#endif
|
||||||
switch (base) {
|
switch (base) {
|
||||||
case 10:
|
case 10:
|
||||||
cutoff = ((uint32_t)INT32_MAX + 1) / 10;
|
cutoff = ((unsigned long)LONG_MAX + 1) / 10;
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
cutoff = ((uint32_t)INT32_MAX + 1) / 16;
|
cutoff = ((unsigned long)LONG_MAX + 1) / 16;
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
cutoff = ((uint32_t)INT32_MAX + 1) / 8;
|
cutoff = ((unsigned long)LONG_MAX + 1) / 8;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
cutoff = ((uint32_t)INT32_MAX + 1) / 2;
|
cutoff = ((unsigned long)LONG_MAX + 1) / 2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cutoff = ((uint32_t)INT32_MAX + 1) / base;
|
cutoff = ((unsigned long)LONG_MAX + 1) / base;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (acc = 0, any = 0;; c = *nptr++) {
|
for (acc = 0, any = 0;; c = *nptr++) {
|
||||||
@@ -144,7 +143,7 @@ avr_strtol(const char *nptr, char **endptr, register int32_t base)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
acc = acc * base + c;
|
acc = acc * base + c;
|
||||||
if (acc > (uint32_t)INT32_MAX + 1)
|
if (acc > (unsigned long)LONG_MAX + 1)
|
||||||
any = -1;
|
any = -1;
|
||||||
else
|
else
|
||||||
any = 1;
|
any = 1;
|
||||||
@@ -156,13 +155,13 @@ avr_strtol(const char *nptr, char **endptr, register int32_t base)
|
|||||||
*endptr = (char *)nptr - 2;
|
*endptr = (char *)nptr - 2;
|
||||||
}
|
}
|
||||||
if (any < 0) {
|
if (any < 0) {
|
||||||
acc = (flag & FL_NEG) ? INT32_MIN : INT32_MAX;
|
acc = (flag & FL_NEG) ? LONG_MIN : LONG_MAX;
|
||||||
avrlibc_errno = ERANGE;
|
errno = ERANGE;
|
||||||
} else if (flag & FL_NEG) {
|
} else if (flag & FL_NEG) {
|
||||||
acc = -acc;
|
acc = -acc;
|
||||||
} else if ((signed long)acc < 0) {
|
} else if ((signed long)acc < 0) {
|
||||||
acc = INT32_MAX;
|
acc = LONG_MAX;
|
||||||
avrlibc_errno = ERANGE;
|
errno = ERANGE;
|
||||||
}
|
}
|
||||||
return (acc);
|
return (acc);
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-15
@@ -35,18 +35,18 @@
|
|||||||
#include "avrlibc.h"
|
#include "avrlibc.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert a string to an uint32_t integer.
|
* Convert a string to an unsigned long integer.
|
||||||
*
|
*
|
||||||
* Ignores `locale' stuff. Assumes that the upper and lower case
|
* Ignores `locale' stuff. Assumes that the upper and lower case
|
||||||
* alphabets and digits are each contiguous.
|
* alphabets and digits are each contiguous.
|
||||||
*/
|
*/
|
||||||
uint32_t
|
unsigned long
|
||||||
avr_strtoul(const char *nptr, char **endptr, register int32_t base)
|
avr_strtoul(const char *nptr, char **endptr, register int base)
|
||||||
{
|
{
|
||||||
register uint32_t acc;
|
register unsigned long acc;
|
||||||
register char c;
|
register unsigned char c;
|
||||||
register uint32_t cutoff;
|
register unsigned long cutoff;
|
||||||
register int8_t any;
|
register signed char any;
|
||||||
unsigned char flag = 0;
|
unsigned char flag = 0;
|
||||||
#define FL_NEG 0x01 /* number is negative */
|
#define FL_NEG 0x01 /* number is negative */
|
||||||
#define FL_0X 0x02 /* number has a 0x prefix */
|
#define FL_0X 0x02 /* number has a 0x prefix */
|
||||||
@@ -102,10 +102,10 @@ avr_strtoul(const char *nptr, char **endptr, register int32_t base)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
switch (base) {
|
switch (base) {
|
||||||
case 16: cutoff = UINT32_MAX / 16; break;
|
case 16: cutoff = ULONG_MAX / 16; break;
|
||||||
case 10: cutoff = UINT32_MAX / 10; break;
|
case 10: cutoff = ULONG_MAX / 10; break;
|
||||||
case 8: cutoff = UINT32_MAX / 8; break;
|
case 8: cutoff = ULONG_MAX / 8; break;
|
||||||
default: cutoff = UINT32_MAX / base;
|
default: cutoff = ULONG_MAX / base;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (acc = 0, any = 0;; c = *nptr++) {
|
for (acc = 0, any = 0;; c = *nptr++) {
|
||||||
@@ -126,7 +126,7 @@ avr_strtoul(const char *nptr, char **endptr, register int32_t base)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
acc = acc * base + c;
|
acc = acc * base + c;
|
||||||
any = (int8_t) ((c > acc) ? -1 : 1);
|
any = (c > acc) ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endptr) {
|
if (endptr) {
|
||||||
@@ -138,8 +138,8 @@ avr_strtoul(const char *nptr, char **endptr, register int32_t base)
|
|||||||
if (flag & FL_NEG)
|
if (flag & FL_NEG)
|
||||||
acc = -acc;
|
acc = -acc;
|
||||||
if (any < 0) {
|
if (any < 0) {
|
||||||
acc = UINT32_MAX;
|
acc = ULONG_MAX;
|
||||||
avrlibc_errno = ERANGE;
|
errno = ERANGE;
|
||||||
}
|
}
|
||||||
return (uint32_t) (acc);
|
return (acc);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by MightyPork on 2018/02/23.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
volatile int32_t avrlibc_errno = 0;
|
|
||||||
+25
-36
@@ -8,10 +8,21 @@
|
|||||||
#ifndef GEX_AVRLIBC_H_H
|
#ifndef GEX_AVRLIBC_H_H
|
||||||
#define GEX_AVRLIBC_H_H
|
#define GEX_AVRLIBC_H_H
|
||||||
|
|
||||||
#include <stdint.h>
|
/**
|
||||||
#include <stddef.h>
|
* atoi() - parse decimal int from ASCII
|
||||||
|
*
|
||||||
|
* @param p - string
|
||||||
|
* @return int, 0 on failure
|
||||||
|
*/
|
||||||
|
int avr_atoi(const char *p);
|
||||||
|
|
||||||
extern volatile int32_t avrlibc_errno;
|
/**
|
||||||
|
* atol() - parse decimal long int from ASCII
|
||||||
|
*
|
||||||
|
* @param p - string
|
||||||
|
* @return int, 0 on failure
|
||||||
|
*/
|
||||||
|
long avr_atol(const char *p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* strtol() - parse integer number form string.
|
* strtol() - parse integer number form string.
|
||||||
@@ -24,39 +35,7 @@ extern volatile int32_t avrlibc_errno;
|
|||||||
* @param base - base 2, 10, 16.... 0 for auto
|
* @param base - base 2, 10, 16.... 0 for auto
|
||||||
* @return the number
|
* @return the number
|
||||||
*/
|
*/
|
||||||
int32_t avr_strtol(const char *nptr, char **endptr, register int32_t base);
|
long avr_strtol(const char *nptr, char **endptr, register int 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
|
* Parse double from ASCII
|
||||||
@@ -67,4 +46,14 @@ static inline int32_t avr_atoi(const char *p)
|
|||||||
*/
|
*/
|
||||||
double avr_strtod (const char * nptr, char ** endptr);
|
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
|
#endif //GEX_AVRLIBC_H_H
|
||||||
|
|||||||
@@ -28,7 +28,6 @@
|
|||||||
X(CHECKSUM_MISMATCH, NULL) /* bus checksum failed */ \
|
X(CHECKSUM_MISMATCH, NULL) /* bus checksum failed */ \
|
||||||
X(PROTOCOL_BREACH, NULL) /* eating with the wrong spoon */ \
|
X(PROTOCOL_BREACH, NULL) /* eating with the wrong spoon */ \
|
||||||
X(BUSY, NULL) /* Unit is busy */ \
|
X(BUSY, NULL) /* Unit is busy */ \
|
||||||
X(BAD_MODE, NULL) /* Command not permissible in current opmode */ \
|
|
||||||
\
|
\
|
||||||
/* VFS user errors (those are meant to be shown to user) */ \
|
/* VFS user errors (those are meant to be shown to user) */ \
|
||||||
X(VFS_ERROR_DURING_TRANSFER, "Error during transfer") \
|
X(VFS_ERROR_DURING_TRANSFER, "Error during transfer") \
|
||||||
|
|||||||
+502
-111
@@ -1,135 +1,526 @@
|
|||||||
|
|
||||||
|
/* #line 1 "ini_parser.rl" */
|
||||||
|
|
||||||
|
/* Ragel constants block */
|
||||||
#include "ini_parser.h"
|
#include "ini_parser.h"
|
||||||
|
|
||||||
enum nini_state {
|
// Ragel setup
|
||||||
NINI_IDLE,
|
|
||||||
NINI_SECTION,
|
/* #line 10 "ini_parser.c" */
|
||||||
NINI_KEY,
|
static const char _ini_actions[] = {
|
||||||
NINI_VALUE,
|
0, 1, 1, 1, 2, 1, 3, 1,
|
||||||
NINI_COMMENT,
|
4, 1, 5, 1, 6, 1, 7, 1,
|
||||||
|
8, 1, 9, 1, 10, 1, 11, 1,
|
||||||
|
13, 2, 0, 4, 2, 12, 4
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct {
|
static const char _ini_eof_actions[] = {
|
||||||
uint8_t section_i;
|
0, 23, 5, 5, 15, 15, 15, 15,
|
||||||
char section[INI_KEY_MAX];
|
19, 19, 0, 0, 0, 0, 0, 0,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
uint8_t key_i;
|
static const int ini_start = 1;
|
||||||
char key[INI_KEY_MAX];
|
static const int ini_first_final = 12;
|
||||||
|
static const int ini_error = 0;
|
||||||
|
|
||||||
uint8_t value_i;
|
static const int ini_en_section = 2;
|
||||||
char value[INI_VALUE_MAX];
|
static const int ini_en_keyvalue = 4;
|
||||||
bool val_last_space;
|
static const int ini_en_comment = 8;
|
||||||
|
static const int ini_en_discard2eol = 10;
|
||||||
|
static const int ini_en_main = 1;
|
||||||
|
|
||||||
IniParserCallback cb;
|
|
||||||
void *userdata;
|
|
||||||
enum nini_state state;
|
|
||||||
} nini;
|
|
||||||
|
|
||||||
void ini_parse_begin(IniParserCallback callback, void *userData)
|
/* #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)
|
||||||
{
|
{
|
||||||
ini_parse_reset();
|
buff_i = 0;
|
||||||
nini.cb = callback;
|
value_quote = 0;
|
||||||
nini.userdata = userData;
|
value_nextesc = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ini_parse(const char *data, size_t len)
|
void
|
||||||
|
ini_parse_reset(void)
|
||||||
{
|
{
|
||||||
for (; len > 0; len--) {
|
ini_parse_reset_partial();
|
||||||
char c = *data++;
|
keybuf[0] = secbuf[0] = valbuf[0] = 0;
|
||||||
if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
|
|
||||||
if (nini.state != NINI_VALUE && nini.state != NINI_COMMENT)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (nini.state) {
|
/* #line 67 "ini_parser.c" */
|
||||||
case NINI_IDLE:
|
{
|
||||||
if (c == '[') {
|
cs = ini_start;
|
||||||
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:
|
/* #line 41 "ini_parser.rl" */
|
||||||
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)
|
void
|
||||||
|
ini_parser_error(const char* msg)
|
||||||
{
|
{
|
||||||
if (nini.state == NINI_VALUE) {
|
ini_error("Parser error: %s", msg);
|
||||||
nini.value[nini.value_i] = 0;
|
ini_parse_reset_partial();
|
||||||
nini.state = NINI_IDLE;
|
|
||||||
nini.cb(nini.section, nini.key, nini.value, nini.userdata);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nini.userdata;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData)
|
|
||||||
|
void
|
||||||
|
ini_parse_begin(IniParserCallback callback, void *userData)
|
||||||
{
|
{
|
||||||
ini_parse_begin(callback, userData);
|
keyCallback = callback;
|
||||||
ini_parse(text, len);
|
userdata = userData;
|
||||||
ini_parse_end();
|
ini_parse_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ini_parse_reset(void)
|
|
||||||
|
void
|
||||||
|
*ini_parse_end(void)
|
||||||
{
|
{
|
||||||
nini.state = NINI_IDLE;
|
ini_parse("\n", 1);
|
||||||
|
if (keyCallback) {
|
||||||
|
keyCallback = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ud = userdata;
|
||||||
|
userdata = NULL;
|
||||||
|
return ud;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ini_parse_file(const char *text, size_t len, IniParserCallback callback, void *userData)
|
||||||
|
{
|
||||||
|
ini_parse_begin(callback, userData);
|
||||||
|
ini_parse(text, len);
|
||||||
|
ini_parse_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rtrim_buf(char *buf, int32_t end)
|
||||||
|
{
|
||||||
|
if (end > 0) {
|
||||||
|
while ((uint8_t)buf[--end] < 33);
|
||||||
|
end++; // go past the last character
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[end] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ini_parse(const char *newstr, size_t len)
|
||||||
|
{
|
||||||
|
int32_t i;
|
||||||
|
char c;
|
||||||
|
bool isnl;
|
||||||
|
bool isquot;
|
||||||
|
|
||||||
|
// Load new data to Ragel vars
|
||||||
|
const uint8_t *p;
|
||||||
|
const uint8_t *eof;
|
||||||
|
const uint8_t *pe;
|
||||||
|
|
||||||
|
if (len == 0) while(newstr[++len] != 0); // alternative to strlen
|
||||||
|
|
||||||
|
p = (const uint8_t *) newstr;
|
||||||
|
eof = NULL;
|
||||||
|
pe = (const uint8_t *) (newstr + len);
|
||||||
|
|
||||||
|
// Init Ragel on the first run
|
||||||
|
if (cs == -1) {
|
||||||
|
ini_parse_reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The parser
|
||||||
|
|
||||||
|
/* #line 152 "ini_parser.c" */
|
||||||
|
{
|
||||||
|
const char *_acts;
|
||||||
|
unsigned int _nacts;
|
||||||
|
|
||||||
|
if ( p == pe )
|
||||||
|
goto _test_eof;
|
||||||
|
if ( cs == 0 )
|
||||||
|
goto _out;
|
||||||
|
_resume:
|
||||||
|
switch ( cs ) {
|
||||||
|
case 1:
|
||||||
|
switch( (*p) ) {
|
||||||
|
case 32u: goto tr1;
|
||||||
|
case 35u: goto tr3;
|
||||||
|
case 58u: goto tr0;
|
||||||
|
case 59u: goto tr3;
|
||||||
|
case 61u: goto tr0;
|
||||||
|
case 91u: goto tr4;
|
||||||
|
}
|
||||||
|
if ( (*p) < 9u ) {
|
||||||
|
if ( (*p) <= 8u )
|
||||||
|
goto tr0;
|
||||||
|
} else if ( (*p) > 13u ) {
|
||||||
|
if ( 14u <= (*p) && (*p) <= 31u )
|
||||||
|
goto tr0;
|
||||||
|
} else
|
||||||
|
goto tr1;
|
||||||
|
goto tr2;
|
||||||
|
case 0:
|
||||||
|
goto _out;
|
||||||
|
case 12:
|
||||||
|
goto tr0;
|
||||||
|
case 2:
|
||||||
|
switch( (*p) ) {
|
||||||
|
case 9u: goto tr6;
|
||||||
|
case 32u: goto tr6;
|
||||||
|
case 93u: goto tr5;
|
||||||
|
}
|
||||||
|
if ( (*p) <= 31u )
|
||||||
|
goto tr5;
|
||||||
|
goto tr7;
|
||||||
|
case 3:
|
||||||
|
if ( (*p) == 93u )
|
||||||
|
goto tr8;
|
||||||
|
if ( (*p) > 8u ) {
|
||||||
|
if ( 10u <= (*p) && (*p) <= 31u )
|
||||||
|
goto tr5;
|
||||||
|
} else
|
||||||
|
goto tr5;
|
||||||
|
goto tr7;
|
||||||
|
case 13:
|
||||||
|
goto tr5;
|
||||||
|
case 4:
|
||||||
|
switch( (*p) ) {
|
||||||
|
case 10u: goto tr10;
|
||||||
|
case 58u: goto tr11;
|
||||||
|
case 61u: goto tr11;
|
||||||
|
}
|
||||||
|
goto tr9;
|
||||||
|
case 5:
|
||||||
|
switch( (*p) ) {
|
||||||
|
case 9u: goto tr13;
|
||||||
|
case 10u: goto tr14;
|
||||||
|
case 13u: goto tr15;
|
||||||
|
case 32u: goto tr13;
|
||||||
|
}
|
||||||
|
goto tr12;
|
||||||
|
case 6:
|
||||||
|
switch( (*p) ) {
|
||||||
|
case 10u: goto tr14;
|
||||||
|
case 13u: goto tr15;
|
||||||
|
}
|
||||||
|
goto tr12;
|
||||||
|
case 14:
|
||||||
|
goto tr10;
|
||||||
|
case 7:
|
||||||
|
if ( (*p) == 10u )
|
||||||
|
goto tr14;
|
||||||
|
goto tr10;
|
||||||
|
case 8:
|
||||||
|
switch( (*p) ) {
|
||||||
|
case 10u: goto tr17;
|
||||||
|
case 13u: goto tr18;
|
||||||
|
}
|
||||||
|
goto tr16;
|
||||||
|
case 15:
|
||||||
|
goto tr19;
|
||||||
|
case 9:
|
||||||
|
if ( (*p) == 10u )
|
||||||
|
goto tr17;
|
||||||
|
goto tr19;
|
||||||
|
case 10:
|
||||||
|
switch( (*p) ) {
|
||||||
|
case 10u: goto tr21;
|
||||||
|
case 13u: goto tr22;
|
||||||
|
}
|
||||||
|
goto tr20;
|
||||||
|
case 16:
|
||||||
|
goto tr23;
|
||||||
|
case 11:
|
||||||
|
if ( (*p) == 10u )
|
||||||
|
goto tr21;
|
||||||
|
goto tr23;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr23: cs = 0; goto _again;
|
||||||
|
tr0: cs = 0; goto f0;
|
||||||
|
tr5: cs = 0; goto f4;
|
||||||
|
tr10: cs = 0; goto f7;
|
||||||
|
tr19: cs = 0; goto f11;
|
||||||
|
tr1: cs = 1; goto _again;
|
||||||
|
tr6: cs = 2; goto _again;
|
||||||
|
tr7: cs = 3; goto f5;
|
||||||
|
tr9: cs = 4; goto f8;
|
||||||
|
tr13: cs = 5; goto _again;
|
||||||
|
tr11: cs = 5; goto f9;
|
||||||
|
tr12: cs = 6; goto f10;
|
||||||
|
tr15: cs = 7; goto _again;
|
||||||
|
tr16: cs = 8; goto _again;
|
||||||
|
tr18: cs = 9; goto _again;
|
||||||
|
tr20: cs = 10; goto _again;
|
||||||
|
tr22: cs = 11; goto _again;
|
||||||
|
tr2: cs = 12; goto f1;
|
||||||
|
tr3: cs = 12; goto f2;
|
||||||
|
tr4: cs = 12; goto f3;
|
||||||
|
tr8: cs = 13; goto f6;
|
||||||
|
tr14: cs = 14; goto f10;
|
||||||
|
tr17: cs = 15; goto f12;
|
||||||
|
tr21: cs = 16; goto f13;
|
||||||
|
|
||||||
|
f5: _acts = _ini_actions + 1; goto execFuncs;
|
||||||
|
f6: _acts = _ini_actions + 3; goto execFuncs;
|
||||||
|
f4: _acts = _ini_actions + 5; goto execFuncs;
|
||||||
|
f1: _acts = _ini_actions + 7; goto execFuncs;
|
||||||
|
f8: _acts = _ini_actions + 9; goto execFuncs;
|
||||||
|
f9: _acts = _ini_actions + 11; goto execFuncs;
|
||||||
|
f10: _acts = _ini_actions + 13; goto execFuncs;
|
||||||
|
f7: _acts = _ini_actions + 15; goto execFuncs;
|
||||||
|
f12: _acts = _ini_actions + 17; goto execFuncs;
|
||||||
|
f11: _acts = _ini_actions + 19; goto execFuncs;
|
||||||
|
f13: _acts = _ini_actions + 21; goto execFuncs;
|
||||||
|
f0: _acts = _ini_actions + 23; goto execFuncs;
|
||||||
|
f3: _acts = _ini_actions + 25; goto execFuncs;
|
||||||
|
f2: _acts = _ini_actions + 28; goto execFuncs;
|
||||||
|
|
||||||
|
execFuncs:
|
||||||
|
_nacts = *_acts++;
|
||||||
|
while ( _nacts-- > 0 ) {
|
||||||
|
switch ( *_acts++ ) {
|
||||||
|
case 0:
|
||||||
|
/* #line 130 "ini_parser.rl" */
|
||||||
|
{
|
||||||
|
buff_i = 0;
|
||||||
|
{cs = 2;goto _again;}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
/* #line 135 "ini_parser.rl" */
|
||||||
|
{
|
||||||
|
if (buff_i >= INI_KEY_MAX) {
|
||||||
|
ini_parser_error("Section name too long");
|
||||||
|
{cs = 10;goto _again;}
|
||||||
|
}
|
||||||
|
keybuf[buff_i++] = (*p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
/* #line 143 "ini_parser.rl" */
|
||||||
|
{
|
||||||
|
// we need a separate buffer for the result, otherwise a failed
|
||||||
|
// partial parse would corrupt the section string
|
||||||
|
rtrim_buf(keybuf, buff_i);
|
||||||
|
for (i = 0; (c = keybuf[i]) != 0; i++) secbuf[i] = c;
|
||||||
|
secbuf[i] = 0;
|
||||||
|
{cs = 1;goto _again;}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
/* #line 155 "ini_parser.rl" */
|
||||||
|
{
|
||||||
|
ini_parser_error("Syntax error in [section]");
|
||||||
|
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
/* #line 162 "ini_parser.rl" */
|
||||||
|
{
|
||||||
|
buff_i = 0;
|
||||||
|
keybuf[buff_i++] = (*p); // add the first char
|
||||||
|
{cs = 4;goto _again;}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
/* #line 168 "ini_parser.rl" */
|
||||||
|
{
|
||||||
|
if (buff_i >= INI_KEY_MAX) {
|
||||||
|
ini_parser_error("Key too long");
|
||||||
|
{cs = 10;goto _again;}
|
||||||
|
}
|
||||||
|
keybuf[buff_i++] = (*p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
/* #line 176 "ini_parser.rl" */
|
||||||
|
{
|
||||||
|
rtrim_buf(keybuf, buff_i);
|
||||||
|
|
||||||
|
// --- Value begin ---
|
||||||
|
buff_i = 0;
|
||||||
|
value_quote = 0;
|
||||||
|
value_nextesc = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
/* #line 185 "ini_parser.rl" */
|
||||||
|
{
|
||||||
|
isnl = ((*p) == '\r' || (*p) == '\n');
|
||||||
|
isquot = ((*p) == '\'' || (*p) == '"');
|
||||||
|
|
||||||
|
// detect our starting quote
|
||||||
|
if (isquot && !value_nextesc && buff_i == 0 && value_quote == 0) {
|
||||||
|
value_quote = (*p);
|
||||||
|
goto valueCharDone;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buff_i >= INI_VALUE_MAX) {
|
||||||
|
ini_parser_error("Value too long");
|
||||||
|
{cs = 10;goto _again;}
|
||||||
|
}
|
||||||
|
|
||||||
|
// end of string - clean up and report
|
||||||
|
if ((!value_nextesc && (*p) == value_quote) || isnl) {
|
||||||
|
if (isnl && value_quote) {
|
||||||
|
ini_parser_error("Unterminated string");
|
||||||
|
{cs = 1;goto _again;}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unquoted: trim from the end
|
||||||
|
if (!value_quote) {
|
||||||
|
rtrim_buf(valbuf, buff_i);
|
||||||
|
} else {
|
||||||
|
valbuf[buff_i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyCallback) {
|
||||||
|
keyCallback(secbuf, keybuf, valbuf, userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we don't want to discard to eol if the string was terminated by eol
|
||||||
|
// - would delete the next line
|
||||||
|
|
||||||
|
if (isnl) {cs = 1;goto _again;} else {cs = 10;goto _again;}
|
||||||
|
}
|
||||||
|
|
||||||
|
c = (*p);
|
||||||
|
// escape...
|
||||||
|
if (value_nextesc) {
|
||||||
|
if ((*p) == 'n') c = '\n';
|
||||||
|
else if ((*p) == 'r') c = '\r';
|
||||||
|
else if ((*p) == 't') c = '\t';
|
||||||
|
else if ((*p) == 'e') c = '\033';
|
||||||
|
}
|
||||||
|
|
||||||
|
// collecting characters...
|
||||||
|
if (value_nextesc || (*p) != '\\') { // is quoted, or is not a quoting backslash - literal character
|
||||||
|
valbuf[buff_i++] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_nextesc = (!value_nextesc && (*p) == '\\');
|
||||||
|
valueCharDone:;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
/* #line 247 "ini_parser.rl" */
|
||||||
|
{
|
||||||
|
ini_parser_error("Syntax error in key=value");
|
||||||
|
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
/* #line 257 "ini_parser.rl" */
|
||||||
|
{ {cs = 1;goto _again;} }
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
/* #line 258 "ini_parser.rl" */
|
||||||
|
{
|
||||||
|
ini_parser_error("Syntax error in comment");
|
||||||
|
if((*p) == '\n') {cs = 1;goto _again;} else {cs = 10;goto _again;}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
/* #line 265 "ini_parser.rl" */
|
||||||
|
{ {cs = 1;goto _again;} }
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
/* #line 273 "ini_parser.rl" */
|
||||||
|
{ {cs = 8;goto _again;} }
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
/* #line 276 "ini_parser.rl" */
|
||||||
|
{
|
||||||
|
ini_parser_error("Syntax error in root");
|
||||||
|
{cs = 10;goto _again;}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
/* #line 458 "ini_parser.c" */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goto _again;
|
||||||
|
|
||||||
|
_again:
|
||||||
|
if ( cs == 0 )
|
||||||
|
goto _out;
|
||||||
|
if ( ++p != pe )
|
||||||
|
goto _resume;
|
||||||
|
_test_eof: {}
|
||||||
|
if ( p == eof )
|
||||||
|
{
|
||||||
|
const char *__acts = _ini_actions + _ini_eof_actions[cs];
|
||||||
|
unsigned int __nacts = (unsigned int) *__acts++;
|
||||||
|
while ( __nacts-- > 0 ) {
|
||||||
|
switch ( *__acts++ ) {
|
||||||
|
case 3:
|
||||||
|
/* #line 155 "ini_parser.rl" */
|
||||||
|
{
|
||||||
|
ini_parser_error("Syntax error in [section]");
|
||||||
|
if((*p) == '\n') {cs = 1; if ( p == pe )
|
||||||
|
goto _test_eof;
|
||||||
|
goto _again;} else {cs = 10; if ( p == pe )
|
||||||
|
goto _test_eof;
|
||||||
|
goto _again;}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
/* #line 247 "ini_parser.rl" */
|
||||||
|
{
|
||||||
|
ini_parser_error("Syntax error in key=value");
|
||||||
|
if((*p) == '\n') {cs = 1; if ( p == pe )
|
||||||
|
goto _test_eof;
|
||||||
|
goto _again;} else {cs = 10; if ( p == pe )
|
||||||
|
goto _test_eof;
|
||||||
|
goto _again;}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
/* #line 258 "ini_parser.rl" */
|
||||||
|
{
|
||||||
|
ini_parser_error("Syntax error in comment");
|
||||||
|
if((*p) == '\n') {cs = 1; if ( p == pe )
|
||||||
|
goto _test_eof;
|
||||||
|
goto _again;} else {cs = 10; if ( p == pe )
|
||||||
|
goto _test_eof;
|
||||||
|
goto _again;}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
/* #line 276 "ini_parser.rl" */
|
||||||
|
{
|
||||||
|
ini_parser_error("Syntax error in root");
|
||||||
|
{cs = 10; if ( p == pe )
|
||||||
|
goto _test_eof;
|
||||||
|
goto _again;}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
/* #line 517 "ini_parser.c" */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_out: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #line 283 "ini_parser.rl" */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -1,5 +1,6 @@
|
|||||||
//
|
//
|
||||||
// INI file parser. Used to extract sections, keys and values from user-provided settings file
|
// 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
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef INIPARSE_STREAM_H
|
#ifndef INIPARSE_STREAM_H
|
||||||
@@ -7,6 +8,13 @@
|
|||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
|
// toggleable logging func
|
||||||
|
#ifdef DEBUG_INI
|
||||||
|
#define ini_error(fmt, ...) dbg("! INI err: "#fmt, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define ini_error(fmt, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
// buffer sizes
|
// buffer sizes
|
||||||
//#define INI_KEY_MAX 20
|
//#define INI_KEY_MAX 20
|
||||||
//#define INI_VALUE_MAX 30 // moved to plat_compat.h
|
//#define INI_VALUE_MAX 30 // moved to plat_compat.h
|
||||||
|
|||||||
@@ -0,0 +1,284 @@
|
|||||||
|
|
||||||
|
/* 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;
|
||||||
|
#*/
|
||||||
|
}%%
|
||||||
|
}
|
||||||
+1
-21
@@ -119,29 +119,9 @@ void iw_entry(IniWriter *iw, const char *key, const char *format, ...)
|
|||||||
iw_newline(iw); // one newline after entry
|
iw_newline(iw); // one newline after entry
|
||||||
}
|
}
|
||||||
|
|
||||||
void iw_entry_s(IniWriter *iw, const char *key, const char *value)
|
uint32_t iw_measure_total(void (*handler)(IniWriter *))
|
||||||
{
|
|
||||||
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);
|
IniWriter iw = iw_init(NULL, 0xFFFFFFFF, 1);
|
||||||
iw.tag = tag;
|
|
||||||
iw_begin();
|
iw_begin();
|
||||||
handler(&iw);
|
handler(&iw);
|
||||||
iw_end();
|
iw_end();
|
||||||
|
|||||||
+2
-6
@@ -18,7 +18,6 @@ typedef struct iniwriter_ {
|
|||||||
char *ptr;
|
char *ptr;
|
||||||
uint32_t skip;
|
uint32_t skip;
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
uint32_t tag; // general purpose field (used to identify for which purpose is the file being read)
|
|
||||||
} IniWriter;
|
} IniWriter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,7 +43,7 @@ void iw_end(void);
|
|||||||
* @param count - number of bytes to write, truncate rest
|
* @param count - number of bytes to write, truncate rest
|
||||||
* @return structure initializer
|
* @return structure initializer
|
||||||
*/
|
*/
|
||||||
#define iw_init(xbuffer, xskip, xcount) (IniWriter){.ptr=(xbuffer), .skip=(xskip), .count=(xcount)}
|
#define iw_init(buffer, skip, count) (IniWriter){buffer, skip, count}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to write a buffer to the file
|
* Try to write a buffer to the file
|
||||||
@@ -126,15 +125,12 @@ __attribute__((format(printf,2,3)));
|
|||||||
void iw_entry(IniWriter *iw, const char *key, const char *format, ...)
|
void iw_entry(IniWriter *iw, const char *key, const char *format, ...)
|
||||||
__attribute__((format(printf,3,4)));
|
__attribute__((format(printf,3,4)));
|
||||||
|
|
||||||
void iw_entry_s(IniWriter *iw, const char *key, const char *value);
|
|
||||||
void iw_entry_d(IniWriter *iw, const char *key, int32_t value);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Measure total ini writer length using a dummy write
|
* Measure total ini writer length using a dummy write
|
||||||
*
|
*
|
||||||
* @param handler - function that normally writes to the writer
|
* @param handler - function that normally writes to the writer
|
||||||
* @return byte count
|
* @return byte count
|
||||||
*/
|
*/
|
||||||
uint32_t iw_measure_total(void (*handler)(IniWriter *), uint32_t tag);
|
uint32_t iw_measure_total(void (*handler)(IniWriter *));
|
||||||
|
|
||||||
#endif //INIWRITER_H
|
#endif //INIWRITER_H
|
||||||
|
|||||||
+21
-11
@@ -1,4 +1,3 @@
|
|||||||
#include <debug.h>
|
|
||||||
#include "payload_parser.h"
|
#include "payload_parser.h"
|
||||||
|
|
||||||
#define pp_check_capacity(pp, needed) \
|
#define pp_check_capacity(pp, needed) \
|
||||||
@@ -59,21 +58,32 @@ uint32_t pp_u32(PayloadParser *pp)
|
|||||||
|
|
||||||
uint64_t pp_u64(PayloadParser *pp)
|
uint64_t pp_u64(PayloadParser *pp)
|
||||||
{
|
{
|
||||||
pp_check_capacity(pp, 8);
|
pp_check_capacity(pp, 4);
|
||||||
if (!pp->ok) return 0;
|
if (!pp->ok) return 0;
|
||||||
|
|
||||||
uint32_t x0, x1;
|
uint64_t x = 0;
|
||||||
uint64_t x;
|
|
||||||
|
|
||||||
if (pp->bigendian) {
|
if (pp->bigendian) {
|
||||||
x1 = pp_u32(pp);
|
x |= (uint64_t) ((uint64_t) *pp->current++ << 56);
|
||||||
x0 = pp_u32(pp);
|
x |= (uint64_t) ((uint64_t) *pp->current++ << 48);
|
||||||
} else {
|
x |= (uint64_t) ((uint64_t) *pp->current++ << 40);
|
||||||
x0 = pp_u32(pp);
|
x |= (uint64_t) ((uint64_t) *pp->current++ << 32);
|
||||||
x1 = pp_u32(pp);
|
|
||||||
}
|
|
||||||
x = ((uint64_t)x1)<<32 | x0;
|
|
||||||
|
|
||||||
|
x |= (uint64_t) (*pp->current++ << 24);
|
||||||
|
x |= (uint64_t) (*pp->current++ << 16);
|
||||||
|
x |= (uint64_t) (*pp->current++ << 8);
|
||||||
|
x |= *pp->current++;
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user