WIP
This commit is contained in:
parent
90d89c7fbe
commit
49383b1b32
68 changed files with 3385 additions and 610 deletions
190
components/f4ll_cpp/crcscheduler.cpp
Normal file
190
components/f4ll_cpp/crcscheduler.cpp
Normal file
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* interrupt.c
|
||||
*
|
||||
* Created on: Aug 29, 2019
|
||||
* Author: abody
|
||||
*/
|
||||
#include <f4ll_cpp/crcscheduler.h>
|
||||
#include <string.h>
|
||||
#if defined(HAVE_DIAG)
|
||||
#include "diag.h"
|
||||
#endif
|
||||
#include "f4ll_cpp/dmahelper.h"
|
||||
|
||||
#ifndef DIAG_CRC_CALC_START
|
||||
# define DIAG_CRC_CALC_START()
|
||||
#endif
|
||||
|
||||
#ifndef DIAG_CRC_CALC_END
|
||||
# define DIAG_CRC_CALC_END()
|
||||
#endif
|
||||
|
||||
#ifndef DIAG_INTERRUPT_IN
|
||||
# define DIAG_INTERRUPT_IN()
|
||||
#endif
|
||||
|
||||
#ifndef DIAG_INTERRUPT_OUT
|
||||
# define DIAG_INTERRUPT_OUT()
|
||||
#endif
|
||||
|
||||
void Crc_StartNextTask(struct crcstatus_t *status);
|
||||
|
||||
|
||||
CrcScheduler::CrcScheduler(CRC_TypeDef *crcUnit, DMA_TypeDef *dma, uint32_t stream) :
|
||||
m_dma(dma, stream),
|
||||
m_activeSlot(nullptr),
|
||||
m_firstSlot(nullptr)
|
||||
{
|
||||
m_crcUnit = crcUnit;
|
||||
LL_DMA_EnableIT_TC(dma, stream);
|
||||
LL_DMA_EnableIT_TE(dma, stream);
|
||||
LL_DMA_SetM2MDstAddress(dma, stream, (uint32_t)&crcUnit->DR);
|
||||
}
|
||||
|
||||
|
||||
void CrcScheduler::AttachTasks(struct crcslot_t *slot, struct crctask_t *tasks, uint8_t taskCount)
|
||||
{
|
||||
slot->count = taskCount;
|
||||
slot->tasks = tasks;
|
||||
memset(tasks, 0, sizeof(*tasks)*taskCount);
|
||||
|
||||
uint32_t prim = __get_PRIMASK();
|
||||
__disable_irq();
|
||||
slot->next = m_firstSlot;
|
||||
m_firstSlot = slot;
|
||||
__set_PRIMASK(prim);
|
||||
}
|
||||
|
||||
|
||||
uint8_t CrcScheduler::GetActiveTask(struct crcslot_t **slot_out)
|
||||
{
|
||||
uint8_t ret;
|
||||
|
||||
uint32_t prim = __get_PRIMASK();
|
||||
|
||||
__disable_irq();
|
||||
ret = m_activeTask;
|
||||
if(slot_out)
|
||||
*slot_out = (struct crcslot_t *) m_activeSlot;
|
||||
__set_PRIMASK(prim);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool CrcScheduler::IsTaskQueued(struct crcslot_t *slot, uint8_t task) {
|
||||
return ((struct crctask_t volatile)slot->tasks[task]).address != NULL;
|
||||
}
|
||||
|
||||
|
||||
bool CrcScheduler::IsTaskBusy(struct crcslot_t *slot, uint8_t task) {
|
||||
struct crctask_t volatile *taskPtr = &slot->tasks[task];
|
||||
return taskPtr->callback != NULL || taskPtr->callbackParam != NULL;
|
||||
}
|
||||
|
||||
|
||||
void CrcScheduler::WaitResults(struct crcslot_t *slot, uint8_t task) {
|
||||
while(IsTaskBusy(slot, task));
|
||||
}
|
||||
|
||||
|
||||
uint8_t CrcScheduler::Enqueue(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len,
|
||||
ICrcCallback* callback, void* callbackParam)
|
||||
{
|
||||
uint32_t prim = __get_PRIMASK();
|
||||
bool need_start;
|
||||
//struct crcstatus_t volatile *st = status;
|
||||
|
||||
while(IsTaskBusy(slot, task));
|
||||
__disable_irq();
|
||||
need_start = (m_activeSlot == nullptr);
|
||||
slot->tasks[task].address = need_start ? NULL : address;
|
||||
slot->tasks[task].wordCount = (len+3)/4;
|
||||
slot->tasks[task].callback = callback;
|
||||
slot->tasks[task].callbackParam = callbackParam;
|
||||
if(need_start) {
|
||||
m_activeSlot = slot;
|
||||
m_activeTask = task;
|
||||
}
|
||||
__set_PRIMASK(prim);
|
||||
|
||||
if(need_start) {
|
||||
DIAG_CRC_CALC_START();
|
||||
m_crcUnit->CR = 1;
|
||||
LL_DMA_SetM2MSrcAddress(m_dma.GetDma(), m_dma.GetStream(), (uint32_t)address);
|
||||
LL_DMA_SetDataLength(m_dma.GetDma(), m_dma.GetStream(), (len+3)/4);
|
||||
DIAG_CRC_CALC_START();
|
||||
LL_DMA_EnableStream(m_dma.GetDma(), m_dma.GetStream());
|
||||
}
|
||||
return need_start;
|
||||
}
|
||||
|
||||
|
||||
uint32_t CrcScheduler::Compute(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len)
|
||||
{
|
||||
uint32_t result;
|
||||
Enqueue(slot, task, address, len, NULL, &result);
|
||||
while((struct crcslot_t volatile *)slot->tasks[task].callbackParam);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// only called from ISR context
|
||||
void CrcScheduler::StartNextTask()
|
||||
{
|
||||
char moreTasks;
|
||||
uint8_t index = 0;
|
||||
|
||||
do {
|
||||
struct crcslot_t *slot = m_firstSlot;
|
||||
moreTasks = 0;
|
||||
while(slot) {
|
||||
if(index < slot->count) {
|
||||
if(slot->tasks[index].address) {
|
||||
DIAG_CRC_CALC_START();
|
||||
m_activeSlot = slot;
|
||||
m_activeTask = index;
|
||||
m_crcUnit->CR = 1;
|
||||
LL_DMA_SetM2MSrcAddress(m_dma.GetDma(), m_dma.GetStream(), (uint32_t)slot->tasks[index].address);
|
||||
LL_DMA_SetDataLength(m_dma.GetDma(), m_dma.GetStream(), slot->tasks[index].wordCount);
|
||||
LL_DMA_EnableStream(m_dma.GetDma(), m_dma.GetStream());
|
||||
slot->tasks[index].address = nullptr; // marking as started
|
||||
return;
|
||||
}
|
||||
if(index + 1 < slot->count)
|
||||
moreTasks = 1;
|
||||
}
|
||||
slot = slot->next;
|
||||
}
|
||||
++index;
|
||||
} while(moreTasks);
|
||||
m_activeSlot = nullptr;
|
||||
}
|
||||
|
||||
|
||||
// !!!PORTABILITY WARNING!!! using registers and bits directly. should be reviewed extremely when porting to a different MCU
|
||||
void CrcScheduler::_HandleDmaIrq()
|
||||
{
|
||||
uint8_t success = 1;
|
||||
|
||||
DIAG_INTERRUPT_IN();
|
||||
if((*m_dma.GetIsReg() & m_dma.GetTcMask()) ||
|
||||
(*m_dma.GetIsReg() & m_dma.GetTeMask())) {
|
||||
if(*m_dma.GetIsReg() & m_dma.GetTeMask())
|
||||
success = 0;
|
||||
*m_dma.GetIfcReg() = *m_dma.GetIsReg() & (m_dma.GetTcMask() | m_dma.GetTeMask());
|
||||
LL_DMA_DisableStream(m_dma.GetDma(), m_dma.GetStream());
|
||||
if(m_activeSlot) {
|
||||
crctask_t *tsk = &m_activeSlot->tasks[m_activeTask];
|
||||
if(tsk->callback)
|
||||
tsk->callback->CrcCalculationCompleted(tsk->callbackParam, m_crcUnit->DR, success);
|
||||
else if(tsk->callbackParam)
|
||||
*(uint32_t*)tsk->callbackParam = success ? m_crcUnit->DR : 0xffffffff;
|
||||
tsk->callback = nullptr;
|
||||
tsk->callbackParam = nullptr; // marking as inactive
|
||||
DIAG_CRC_CALC_END();
|
||||
StartNextTask();
|
||||
}
|
||||
}
|
||||
DIAG_INTERRUPT_OUT();
|
||||
}
|
||||
|
68
components/f4ll_cpp/crcscheduler.h
Normal file
68
components/f4ll_cpp/crcscheduler.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* interrupt.h
|
||||
*
|
||||
* Created on: Aug 29, 2019
|
||||
* Author: abody
|
||||
*/
|
||||
|
||||
#ifndef CRC_HANDLER_H_
|
||||
#define CRC_HANDLER_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef HAVE_CONFIG
|
||||
#include "config.h"
|
||||
#endif // HAVE_CONFIG
|
||||
|
||||
#include <platform/crc_ll.h>
|
||||
#include <f4ll_cpp/dmahelper.h>
|
||||
|
||||
class CrcScheduler {
|
||||
public:
|
||||
struct ICrcCallback {
|
||||
virtual void CrcCalculationCompleted(void*, uint32_t, uint8_t) = 0;
|
||||
};
|
||||
|
||||
struct crctask_t {
|
||||
void * volatile address;
|
||||
uint16_t wordCount;
|
||||
ICrcCallback* callback;
|
||||
void *callbackParam;
|
||||
};
|
||||
|
||||
struct crcslot_t {
|
||||
uint16_t count;
|
||||
struct crcslot_t *next;
|
||||
struct crctask_t *tasks;
|
||||
};
|
||||
|
||||
CrcScheduler(CRC_TypeDef *crcUnit, DMA_TypeDef *dma, uint32_t stream);
|
||||
|
||||
uint8_t GetActiveTask(struct crcslot_t **slot_out);
|
||||
bool IsTaskQueued(struct crcslot_t *slot, uint8_t task);
|
||||
bool IsTaskBusy(struct crcslot_t *slot, uint8_t task);
|
||||
|
||||
void WaitResults(struct crcslot_t *slot, uint8_t task);
|
||||
|
||||
void AttachTasks(struct crcslot_t *slot, struct crctask_t *tasks, uint8_t taskCount);
|
||||
|
||||
uint8_t Enqueue(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len,
|
||||
ICrcCallback* callback, void* callbackParam);
|
||||
uint32_t Compute(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len);
|
||||
static void HandleDmaIrq(void *param) { reinterpret_cast<CrcScheduler*>(param)->_HandleDmaIrq(); }
|
||||
void _HandleDmaIrq();
|
||||
|
||||
private:
|
||||
void StartNextTask();
|
||||
|
||||
CRC_TypeDef *m_crcUnit;
|
||||
DmaHelper m_dma;
|
||||
|
||||
volatile crcslot_t *m_activeSlot;
|
||||
volatile uint8_t m_activeTask;
|
||||
|
||||
crcslot_t *m_firstSlot;
|
||||
};
|
||||
|
||||
|
||||
#endif /* CRC_HANDLER_H_ */
|
|
@ -13,16 +13,16 @@ DmaHelper::DmaHelper(DMA_TypeDef *dma, uint32_t stream)
|
|||
{
|
||||
m_dma = dma;
|
||||
m_stream = stream;
|
||||
m_isReg = GetIsReg(dma, stream);
|
||||
m_ifcReg = GetIfcReg(dma, stream);
|
||||
m_feMask = GetFeMask(stream);
|
||||
m_dmeMask = GetDmeMask(stream);
|
||||
m_teMask = GetTeMask(stream);
|
||||
m_htMask = GetHtMask(stream);
|
||||
m_tcMask = GetTcMask(stream);
|
||||
m_isReg = _GetIsReg(dma, stream);
|
||||
m_ifcReg = _GetIfcReg(dma, stream);
|
||||
m_feMask = _GetFeMask(stream);
|
||||
m_dmeMask = _GetDmeMask(stream);
|
||||
m_teMask = _GetTeMask(stream);
|
||||
m_htMask = _GetHtMask(stream);
|
||||
m_tcMask = _GetTcMask(stream);
|
||||
}
|
||||
|
||||
volatile uint32_t* DmaHelper::GetIsReg(DMA_TypeDef *dma, uint32_t stream)
|
||||
volatile uint32_t* DmaHelper::_GetIsReg(DMA_TypeDef *dma, uint32_t stream)
|
||||
{
|
||||
if(dma == DMA1)
|
||||
return (stream < LL_DMA_STREAM_4) ? &DMA1->LISR : &DMA1->HISR;
|
||||
|
@ -31,7 +31,7 @@ volatile uint32_t* DmaHelper::GetIsReg(DMA_TypeDef *dma, uint32_t stream)
|
|||
}
|
||||
|
||||
|
||||
volatile uint32_t* DmaHelper::GetIfcReg(DMA_TypeDef *dma, uint32_t stream)
|
||||
volatile uint32_t* DmaHelper::_GetIfcReg(DMA_TypeDef *dma, uint32_t stream)
|
||||
{
|
||||
if(dma == DMA1)
|
||||
return (stream < LL_DMA_STREAM_4) ? &DMA1->LIFCR : &DMA1->HIFCR;
|
||||
|
@ -39,7 +39,7 @@ volatile uint32_t* DmaHelper::GetIfcReg(DMA_TypeDef *dma, uint32_t stream)
|
|||
return (stream < LL_DMA_STREAM_4) ? &DMA2->LIFCR : &DMA2->HIFCR;
|
||||
}
|
||||
|
||||
uint32_t DmaHelper::GetFeMask(uint32_t stream)
|
||||
uint32_t DmaHelper::_GetFeMask(uint32_t stream)
|
||||
{
|
||||
static const uint32_t feMasks[8] = {
|
||||
DMA_LISR_FEIF0, DMA_LISR_FEIF1, DMA_LISR_FEIF2, DMA_LISR_FEIF3, DMA_HISR_FEIF4, DMA_HISR_FEIF5, DMA_HISR_FEIF6, DMA_HISR_FEIF7
|
||||
|
@ -47,7 +47,7 @@ uint32_t DmaHelper::GetFeMask(uint32_t stream)
|
|||
return feMasks[stream];
|
||||
}
|
||||
|
||||
uint32_t DmaHelper::GetDmeMask(uint32_t stream)
|
||||
uint32_t DmaHelper::_GetDmeMask(uint32_t stream)
|
||||
{
|
||||
static const uint32_t dmeMasks[8] = {
|
||||
DMA_LISR_DMEIF0, DMA_LISR_DMEIF1, DMA_LISR_DMEIF2, DMA_LISR_DMEIF3, DMA_HISR_DMEIF4, DMA_HISR_DMEIF5, DMA_HISR_DMEIF6, DMA_HISR_DMEIF7
|
||||
|
@ -55,7 +55,7 @@ uint32_t DmaHelper::GetDmeMask(uint32_t stream)
|
|||
return dmeMasks[stream];
|
||||
}
|
||||
|
||||
uint32_t DmaHelper::GetTeMask(uint32_t stream)
|
||||
uint32_t DmaHelper::_GetTeMask(uint32_t stream)
|
||||
{
|
||||
static const uint32_t teMasks[8] = {
|
||||
DMA_LISR_TEIF0, DMA_LISR_TEIF1, DMA_LISR_TEIF2, DMA_LISR_TEIF3, DMA_HISR_TEIF4, DMA_HISR_TEIF5, DMA_HISR_TEIF6, DMA_HISR_TEIF7
|
||||
|
@ -63,7 +63,7 @@ uint32_t DmaHelper::GetTeMask(uint32_t stream)
|
|||
return teMasks[stream];
|
||||
}
|
||||
|
||||
uint32_t DmaHelper::GetHtMask(uint32_t stream)
|
||||
uint32_t DmaHelper::_GetHtMask(uint32_t stream)
|
||||
{
|
||||
static const uint32_t htMasks[8] = {
|
||||
DMA_LISR_HTIF0, DMA_LISR_HTIF1, DMA_LISR_HTIF2, DMA_LISR_HTIF3, DMA_HISR_HTIF4, DMA_HISR_HTIF5, DMA_HISR_HTIF6, DMA_HISR_HTIF7
|
||||
|
@ -71,7 +71,7 @@ uint32_t DmaHelper::GetHtMask(uint32_t stream)
|
|||
return htMasks[stream];
|
||||
}
|
||||
|
||||
uint32_t DmaHelper::GetTcMask(uint32_t stream)
|
||||
uint32_t DmaHelper::_GetTcMask(uint32_t stream)
|
||||
{
|
||||
static const uint32_t tcMasks[8] = {
|
||||
DMA_LISR_TCIF0, DMA_LISR_TCIF1, DMA_LISR_TCIF2, DMA_LISR_TCIF3, DMA_HISR_TCIF4, DMA_HISR_TCIF5, DMA_HISR_TCIF6, DMA_HISR_TCIF7
|
||||
|
|
|
@ -17,13 +17,25 @@
|
|||
class DmaHelper {
|
||||
public:
|
||||
DmaHelper(DMA_TypeDef *dma, uint32_t stream);
|
||||
volatile uint32_t* GetIsReg(DMA_TypeDef *dma, uint32_t stream);
|
||||
volatile uint32_t* GetIfcReg(DMA_TypeDef *dma, uint32_t stream);
|
||||
uint32_t GetDmeMask(uint32_t stream);
|
||||
uint32_t GetTeMask(uint32_t stream);
|
||||
uint32_t GetHtMask(uint32_t stream);
|
||||
uint32_t GetTcMask(uint32_t stream);
|
||||
uint32_t GetFeMask(uint32_t stream);
|
||||
|
||||
DMA_TypeDef* GetDma() { return m_dma; }
|
||||
uint32_t GetStream() { return m_stream; }
|
||||
volatile uint32_t* GetIsReg() { return m_isReg; }
|
||||
volatile uint32_t* GetIfcReg() { return m_ifcReg; }
|
||||
uint32_t GetDmeMask() { return m_dmeMask; }
|
||||
uint32_t GetTeMask() { return m_teMask; }
|
||||
uint32_t GetHtMask() { return m_htMask; }
|
||||
uint32_t GetTcMask() { return m_tcMask; }
|
||||
uint32_t GetFeMask() { return m_feMask; }
|
||||
|
||||
private:
|
||||
static volatile uint32_t* _GetIsReg(DMA_TypeDef *dma, uint32_t stream);
|
||||
static volatile uint32_t* _GetIfcReg(DMA_TypeDef *dma, uint32_t stream);
|
||||
static uint32_t _GetDmeMask(uint32_t stream);
|
||||
static uint32_t _GetTeMask(uint32_t stream);
|
||||
static uint32_t _GetHtMask(uint32_t stream);
|
||||
static uint32_t _GetTcMask(uint32_t stream);
|
||||
static uint32_t _GetFeMask(uint32_t stream);
|
||||
|
||||
private:
|
||||
DMA_TypeDef *m_dma;
|
||||
|
|
35
components/f4ll_cpp/memcpydma.cpp
Normal file
35
components/f4ll_cpp/memcpydma.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* memcpy_dma.c
|
||||
*
|
||||
* Created on: Oct 1, 2019
|
||||
* Author: abody
|
||||
*/
|
||||
#include <f4ll_cpp/dmahelper.h>
|
||||
#include <f4ll_cpp/memcpydma.h>
|
||||
|
||||
MemcpyDma::MemcpyDma(DMA_TypeDef *dma, uint32_t stream) :
|
||||
DmaHelper(dma, stream),
|
||||
m_busy(false)
|
||||
{
|
||||
LL_DMA_EnableIT_TC(dma, stream);
|
||||
}
|
||||
|
||||
void* MemcpyDma::Copy(void *dst, void const *src, size_t length)
|
||||
{
|
||||
while(m_busy);
|
||||
LL_DMA_SetM2MSrcAddress(GetDma(), GetStream(), (uint32_t)src);
|
||||
LL_DMA_SetM2MDstAddress(GetDma(), GetStream(), (uint32_t)dst);
|
||||
LL_DMA_SetDataLength(GetDma(), GetStream(), (length+3)/4 );
|
||||
m_busy = true;
|
||||
LL_DMA_EnableStream(GetDma(), GetStream());
|
||||
return dst;
|
||||
}
|
||||
|
||||
void MemcpyDma::HandleDmaIrq(void)
|
||||
{
|
||||
if(*GetIsReg() & GetTcMask()) { // DMA transfer complete
|
||||
*GetIfcReg() = GetTcMask();
|
||||
LL_DMA_DisableStream(GetDma(), GetStream());
|
||||
m_busy = false;
|
||||
}
|
||||
}
|
30
components/f4ll_cpp/memcpydma.h
Normal file
30
components/f4ll_cpp/memcpydma.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* memcpy_dma.h
|
||||
*
|
||||
* Created on: Oct 1, 2019
|
||||
* Author: abody
|
||||
*/
|
||||
|
||||
#ifndef MEMCPY_DMA_H_
|
||||
#define MEMCPY_DMA_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <platform/dma_ll.h>
|
||||
#include <f4ll_cpp/dmahelper.h>
|
||||
#include <f4ll_cpp/singleton.h>
|
||||
|
||||
|
||||
class MemcpyDma : public DmaHelper, public Singleton<MemcpyDma>
|
||||
{
|
||||
public:
|
||||
MemcpyDma(DMA_TypeDef *dma, uint32_t stream);
|
||||
void* Copy(void *dst, void const *src, size_t length);
|
||||
static inline void HandleDmaIrq(void *param) { reinterpret_cast<MemcpyDma*>(param)->HandleDmaIrq(); }
|
||||
|
||||
private:
|
||||
void HandleDmaIrq();
|
||||
volatile bool m_busy;
|
||||
};
|
||||
|
||||
|
||||
#endif /* MEMCPY_DMA_H_ */
|
282
components/f4ll_cpp/packetuart.cpp
Normal file
282
components/f4ll_cpp/packetuart.cpp
Normal file
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* usart_handler.c
|
||||
*
|
||||
* Created on: Sep 16, 2019
|
||||
* Author: abody
|
||||
*/
|
||||
|
||||
#include <f4ll_cpp/memcpydma.h>
|
||||
#include "f4ll_cpp/crcscheduler.h"
|
||||
#include <f4ll_cpp/packetuart.h>
|
||||
#include <string.h>
|
||||
#include <platform/usart_ll.h>
|
||||
#if defined(HAVE_DIAG)
|
||||
#include "diag.h"
|
||||
#endif
|
||||
|
||||
#ifndef MOCKABLE
|
||||
#define MOCKABLE(x) x
|
||||
#endif
|
||||
|
||||
#ifndef DIAG_RX_BUFFER_SWITCH
|
||||
# define DIAG_RX_BUFFER_SWITCH(x)
|
||||
#endif
|
||||
#ifndef DIAG_INTERRUPT_IN
|
||||
# define DIAG_INTERRUPT_IN()
|
||||
#endif
|
||||
#ifndef DIAG_INTERRUPT_OUT
|
||||
# define DIAG_INTERRUPT_OUT()
|
||||
#endif
|
||||
|
||||
#define STARTMARKER 0x95
|
||||
|
||||
static inline uint32_t RoundUpTo4(uint32_t inp)
|
||||
{
|
||||
return (inp + 3) & 0xfffc;
|
||||
}
|
||||
|
||||
#ifndef USART_STATS_DISABLED
|
||||
static inline void StatsIncOverrun(struct usart_stats *s) {
|
||||
++s->overrun;
|
||||
}
|
||||
static inline void StatsIncHdrError(struct usart_stats *s, uint32_t hdr) {
|
||||
++s->hdrError;
|
||||
s->lastErrHdr = hdr;
|
||||
}
|
||||
static inline void StatsIncPayloadError(struct usart_stats *s, uint32_t pep1, uint32_t pep2) {
|
||||
++s->payloadErrror;
|
||||
s->pep1 = pep1;
|
||||
s->pep2 = pep2;
|
||||
}
|
||||
static inline void StatsIncDmaError(struct usart_stats *s) {
|
||||
++s->dmaError;
|
||||
}
|
||||
static inline void StatsIncRcvd(struct usart_stats *s) {
|
||||
++s->rcvd;
|
||||
}
|
||||
static inline void StatsIncPremature_hdr(struct usart_stats *s) {
|
||||
++s->premature_hdr;
|
||||
}
|
||||
static inline void StatsIncPremature_payload(struct usart_stats *s) {
|
||||
++s->premature_payload;
|
||||
}
|
||||
static inline void StatsIncSent(struct usart_stats *s) {
|
||||
++s->sent;
|
||||
}
|
||||
static inline void StatsAddSkiped(struct usart_stats *s, uint8_t cnt) {
|
||||
s->skiped += s->rcvd > 2 ? cnt : 0;
|
||||
}
|
||||
|
||||
#else // USART_STATS_DISABLED
|
||||
#define StatsIncOverrun(x)
|
||||
#define StatsIncHdrError(x,y)
|
||||
#define StatsIncPayloadError(x,y,z)
|
||||
#define StatsIncDmaError(x)
|
||||
#define StatsIncRcvd(x)
|
||||
#define StatsIncPremature_hdr(x)
|
||||
#define StatsIncPremature_payload(x)
|
||||
#define StatsIncSent(x)
|
||||
#define StatsAddSkiped(x,y)
|
||||
#endif // USART_STATS_DISABLED
|
||||
|
||||
PacketUart::PacketUart(
|
||||
USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx, CrcScheduler *crcScheduler,
|
||||
PacketUart::pku_packetreceivedcallback_t packetReceivedCallback, void * packetReceivedCallbackParam)
|
||||
: UartBase(uart, dma, stream_rx, stream_tx)
|
||||
, m_crcScheduler(crcScheduler)
|
||||
{
|
||||
uint32_t status = uart->SR;
|
||||
volatile uint32_t tmpreg = uart->DR; // clearing some of the error/status bits in the USART
|
||||
(void) tmpreg;
|
||||
(void) status;
|
||||
|
||||
txBuffer.busy = 0;
|
||||
txBuffer.error = 0;
|
||||
txBuffer.requestedLength = 0;
|
||||
rxBuffers[0].busy = 0;
|
||||
rxBuffers[1].busy = 0;
|
||||
rxBuffers[0].error = 0;
|
||||
rxBuffers[1].error = 0;
|
||||
rxBuffers[0].requestedLength = 0;
|
||||
rxBuffers[1].requestedLength = 0;
|
||||
packetReceivedCallback = packetReceivedCallback;
|
||||
packetReceivedCallbackParam = packetReceivedCallbackParam;
|
||||
rxSerial = -1;
|
||||
txSerial = 0;
|
||||
activeRxBuf = 0;
|
||||
m_crcScheduler->AttachTasks( &crcSlot, crcTasks, 2);
|
||||
#ifndef USART_STATS_DISABLED
|
||||
memset(&st->stats, 0, sizeof(st->stats));
|
||||
#endif
|
||||
|
||||
LL_USART_EnableIT_IDLE(uart);
|
||||
}
|
||||
|
||||
|
||||
uint8_t* PacketUart::GetTxBuffer()
|
||||
{
|
||||
return txBuffer.packet.payload;
|
||||
}
|
||||
|
||||
|
||||
uint8_t PacketUart::CheckHeader(Packet *packet)
|
||||
{
|
||||
return packet->header.startByte == STARTMARKER && (packet->header.startByte ^ packet->header.serial ^ packet->header.payloadLength) == packet->header.hash;
|
||||
}
|
||||
|
||||
|
||||
uint8_t PacketUart::Post(uint8_t const *payload, uint8_t length, uint8_t waitForCrcQueue)
|
||||
{
|
||||
struct Buffer *buffer = &txBuffer;
|
||||
uint8_t hash = STARTMARKER;
|
||||
buffer->packet.header.startByte = STARTMARKER;
|
||||
buffer->packet.header.serial = txSerial;
|
||||
hash ^= txSerial++;
|
||||
buffer->packet.header.payloadLength = length;
|
||||
hash ^= length;
|
||||
buffer->packet.header.hash = hash;
|
||||
|
||||
uint16_t payloadLength = RoundUpTo4(length);
|
||||
if(payload)
|
||||
memcpy(txBuffer.packet.payload, payload, length);
|
||||
txBuffer.requestedLength = sizeof(struct Header) + payloadLength + sizeof(uint32_t); // +4 for the hash
|
||||
txBuffer.busy = 1;
|
||||
txBuffer.error = 0;
|
||||
m_crcScheduler->Enqueue(&crcSlot, 0, &txBuffer.packet, sizeof(txBuffer.packet.header) + payloadLength,
|
||||
NULL, (uint32_t*)(txBuffer.packet.payload + payloadLength));
|
||||
while(waitForCrcQueue && m_crcScheduler->IsTaskQueued(&crcSlot, 0));
|
||||
SetupTransmit(&txBuffer.packet, txBuffer.requestedLength);
|
||||
|
||||
StatsIncSent(&status->stats);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void PacketUart::SetupReceive()
|
||||
{
|
||||
uint8_t packetIndex = activeRxBuf;
|
||||
rxBuffers[packetIndex].requestedLength = sizeof(rxBuffers[packetIndex].packet);
|
||||
UartBase::SetupReceive(&rxBuffers[packetIndex], sizeof(rxBuffers[packetIndex].packet));
|
||||
}
|
||||
|
||||
|
||||
void PacketUart::ConsumePacket(uint8_t packetIndex)
|
||||
{
|
||||
Buffer *buffer = &rxBuffers[packetIndex];
|
||||
if(buffer->busy) {
|
||||
if(buffer->error)
|
||||
StatsIncPayloadError(&status->stats, Buffer->errorInfo, *(uint32_t*) (Buffer->packet.payload + RoundUpTo4(Buffer->packet.header.payloadLength)));
|
||||
else {
|
||||
uint8_t diff = buffer->packet.header.serial - rxSerial;
|
||||
if(diff > 1)
|
||||
StatsAddSkiped(&status->stats, diff - 1);
|
||||
rxSerial = buffer->packet.header.serial;
|
||||
}
|
||||
}
|
||||
|
||||
buffer->busy = buffer->error = 0;
|
||||
}
|
||||
|
||||
|
||||
void PacketUart::HandleRxDmaIrq()
|
||||
{
|
||||
DIAG_INTERRUPT_IN();
|
||||
StatsIncRcvd(&status->stats);
|
||||
if(*m_rxDma.GetIsReg() & m_rxDma.GetTcMask()) {
|
||||
*m_rxDma.GetIfcReg() = m_rxDma.GetTcMask();
|
||||
if(CheckHeader(&rxBuffers[activeRxBuf].packet)) {
|
||||
m_crcScheduler->Enqueue(&crcSlot, 1, &rxBuffers[activeRxBuf].packet,
|
||||
RoundUpTo4(rxBuffers[activeRxBuf].packet.header.payloadLength) + sizeof(struct Header),
|
||||
this, &rxBuffers[activeRxBuf]);
|
||||
} else {
|
||||
StatsIncHdrError(&status->stats, *(uint32_t*)&status->rxBuffers[status->activeRxBuf].packet.header);
|
||||
rxBuffers[activeRxBuf].error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(*m_rxDma.GetIsReg() & m_rxDma.GetTeMask()) {
|
||||
*m_rxDma.GetIfcReg() = m_rxDma.GetTeMask();
|
||||
rxBuffers[activeRxBuf].error = 1;
|
||||
}
|
||||
|
||||
activeRxBuf ^= 1;
|
||||
|
||||
DIAG_RX_BUFFER_SWITCH(status->activeRxBuf);
|
||||
if(rxBuffers[activeRxBuf].busy)
|
||||
StatsIncOverrun(&status->stats);
|
||||
SetupReceive();
|
||||
DIAG_INTERRUPT_OUT();
|
||||
}
|
||||
|
||||
|
||||
void PacketUart::CrcCalculationCompleted(void *callbackParm, uint32_t calculatedCrc, uint8_t success)
|
||||
{
|
||||
struct Buffer *ub = (struct Buffer*) callbackParm;
|
||||
if(!success)
|
||||
ub->error = 1;
|
||||
else if(*(uint32_t*) (ub->packet.payload + RoundUpTo4(ub->packet.header.payloadLength)) == calculatedCrc)
|
||||
ub->busy = 1;
|
||||
else {
|
||||
ub->error = ub->busy = 1;
|
||||
ub->errorInfo = calculatedCrc;
|
||||
}
|
||||
if(packetReceivedCallback)
|
||||
packetReceivedCallback(packetReceivedCallbackParam, ub);
|
||||
}
|
||||
|
||||
|
||||
void PacketUart::HandleTxDmaIrq()
|
||||
{
|
||||
DIAG_INTERRUPT_IN();
|
||||
if(*m_txDma.GetIsReg() & m_txDma.GetTcMask()) { // DMA transfer complete
|
||||
*m_txDma.GetIfcReg() = m_txDma.GetTcMask();
|
||||
LL_USART_EnableIT_TC(m_uart);
|
||||
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
|
||||
}
|
||||
if(*m_txDma.GetIsReg() & m_txDma.GetTeMask()) {
|
||||
*m_txDma.GetIfcReg() = m_txDma.GetTeMask();
|
||||
txBuffer.error = 1;
|
||||
LL_USART_EnableIT_TC(m_uart);
|
||||
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
|
||||
StatsIncDmaError(&status->stats);
|
||||
}
|
||||
if(*m_txDma.GetIsReg() & m_txDma.GetFeMask())
|
||||
*m_txDma.GetIfcReg() = m_txDma.GetFeMask();
|
||||
if(*m_txDma.GetIsReg() & m_txDma.GetHtMask())
|
||||
*m_txDma.GetIfcReg() = m_txDma.GetHtMask();
|
||||
if(*m_txDma.GetIsReg() & m_txDma.GetDmeMask())
|
||||
*m_txDma.GetIfcReg() = m_txDma.GetDmeMask();
|
||||
DIAG_INTERRUPT_OUT();
|
||||
}
|
||||
|
||||
|
||||
void PacketUart::HandleUsartIrq()
|
||||
{
|
||||
DIAG_INTERRUPT_IN();
|
||||
if(LL_USART_IsActiveFlag_IDLE(m_uart) && LL_USART_IsEnabledIT_IDLE(m_uart)) { // receiver idle
|
||||
LL_USART_ClearFlag_IDLE(m_uart);
|
||||
uint16_t rcvdLen = rxBuffers[activeRxBuf].requestedLength - LL_DMA_GetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream());
|
||||
if(rcvdLen >= sizeof(struct Header)) {
|
||||
if(CheckHeader(&rxBuffers[activeRxBuf].packet)) {
|
||||
if(rcvdLen >= sizeof(struct Header) + RoundUpTo4(rxBuffers[activeRxBuf].packet.header.payloadLength) + sizeof(uint32_t))
|
||||
LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
|
||||
else
|
||||
StatsIncPremature_payload(&stats);
|
||||
} else {
|
||||
rxBuffers[activeRxBuf].error = 1;
|
||||
rxBuffers[activeRxBuf].busy = 1;
|
||||
LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
|
||||
}
|
||||
} else
|
||||
StatsIncPremature_hdr(&status->stats);
|
||||
}
|
||||
|
||||
if(LL_USART_IsActiveFlag_TC(m_uart) && LL_USART_IsEnabledIT_TC(m_uart)) { // transmission complete
|
||||
LL_USART_DisableIT_TC(m_uart);
|
||||
LL_USART_DisableDirectionTx(m_uart); // enforcing an idle frame
|
||||
LL_USART_EnableDirectionTx(m_uart);
|
||||
txBuffer.busy = 0;
|
||||
}
|
||||
DIAG_INTERRUPT_OUT();
|
||||
}
|
||||
|
103
components/f4ll_cpp/packetuart.h
Normal file
103
components/f4ll_cpp/packetuart.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* usart_handler.h
|
||||
*
|
||||
* Created on: Sep 16, 2019
|
||||
* Author: abody
|
||||
*/
|
||||
|
||||
#ifndef USART_HANDLER_H_
|
||||
#define USART_HANDLER_H_
|
||||
#include <inttypes.h>
|
||||
#include <platform/usart_ll.h>
|
||||
#include <f4ll_cpp/uartbase.h>
|
||||
|
||||
#define USART_STATS_DISABLED
|
||||
|
||||
class PacketUart : public UartBase, public CrcScheduler::ICrcCallback
|
||||
{
|
||||
public:
|
||||
struct Buffer;
|
||||
|
||||
struct IPacketUsartCallback {
|
||||
virtual void PacketReceived(void *userParam, Buffer *buffer) = 0;
|
||||
};
|
||||
|
||||
struct Stats {
|
||||
uint32_t overrun;
|
||||
uint32_t hdrError;
|
||||
uint32_t lastErrHdr;
|
||||
uint32_t payloadErrror;
|
||||
uint32_t pep1, pep2;
|
||||
uint32_t dmaError;
|
||||
uint32_t rcvd;
|
||||
uint32_t premature_hdr;
|
||||
uint32_t premature_payload;
|
||||
uint32_t sent;
|
||||
uint32_t skiped;
|
||||
};
|
||||
|
||||
struct Header {
|
||||
uint8_t startByte;
|
||||
uint8_t serial;
|
||||
uint8_t payloadLength;
|
||||
uint8_t hash;
|
||||
};
|
||||
|
||||
struct Packet {
|
||||
struct Header header;
|
||||
//!!! should start on word offset !!!
|
||||
uint8_t payload[256+sizeof(uint32_t)]; // extra room for crc32
|
||||
} __attribute__((aligned));
|
||||
|
||||
struct Buffer {
|
||||
Packet packet;
|
||||
//transfer area ends here
|
||||
volatile uint8_t busy;
|
||||
volatile uint8_t error;
|
||||
uint16_t requestedLength;
|
||||
uint32_t errorInfo;
|
||||
};
|
||||
|
||||
|
||||
typedef void (*pku_packetreceivedcallback_t)(void *userParam, Buffer *Buffer);
|
||||
|
||||
PacketUart(
|
||||
USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx, CrcScheduler *crcScheduler,
|
||||
PacketUart::pku_packetreceivedcallback_t packetReceivedCallback, void * packetReceivedCallbackParam);
|
||||
|
||||
uint8_t* GetTxBuffer();
|
||||
|
||||
uint8_t Post(uint8_t const *payload, uint8_t length, uint8_t waitForCrcQueue);
|
||||
void SetupReceive();
|
||||
void ConsumePacket(uint8_t packetIndex);
|
||||
|
||||
static void HandleRxDmaIrq(void* param) { reinterpret_cast<PacketUart*>(param)->HandleRxDmaIrq(); }
|
||||
static void HandleTxDmaIrq(void* param) { reinterpret_cast<PacketUart*>(param)->HandleTxDmaIrq(); }
|
||||
static void HandleUsartIrq(void* param) { reinterpret_cast<PacketUart*>(param)->HandleUsartIrq(); }
|
||||
|
||||
uint8_t CheckHeader(struct Packet *packet);
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
void HandleRxDmaIrq();
|
||||
void HandleTxDmaIrq();
|
||||
void HandleUsartIrq();
|
||||
|
||||
virtual void CrcCalculationCompleted(void*, uint32_t, uint8_t);
|
||||
|
||||
CrcScheduler *m_crcScheduler;
|
||||
CrcScheduler::crcslot_t crcSlot;
|
||||
CrcScheduler::crctask_t crcTasks[2];
|
||||
|
||||
uint8_t rxSerial;
|
||||
uint8_t txSerial;
|
||||
Stats stats;
|
||||
uint8_t activeRxBuf;
|
||||
pku_packetreceivedcallback_t packetReceivedCallback;
|
||||
void *packetReceivedCallbackParam;
|
||||
Buffer txBuffer;
|
||||
Buffer rxBuffers[2];
|
||||
};
|
||||
|
||||
#endif /* UART_HANDLER_H_ */
|
161
components/f4ll_cpp/serialconsole.h
Normal file
161
components/f4ll_cpp/serialconsole.h
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* interrupt.h
|
||||
*
|
||||
* Created on: Aug 29, 2019
|
||||
* Author: abody
|
||||
*/
|
||||
|
||||
#ifndef CONSOLEHANDLER_H_
|
||||
#define CONSOLEHANDLER_H_
|
||||
|
||||
#include <cstring>
|
||||
#include "usart.h"
|
||||
#include <f4ll_cpp/dmahelper.h>
|
||||
#include <f4ll_cpp/uartbase.h>
|
||||
|
||||
|
||||
template<unsigned int bufSize> class SerialConsole : protected UartBase
|
||||
{
|
||||
public:
|
||||
struct Buffer {
|
||||
volatile bool busy = false;
|
||||
volatile bool error = false;
|
||||
uint8_t len;
|
||||
char buffer[bufSize];
|
||||
};
|
||||
|
||||
struct ISerialConsoleCallback {
|
||||
virtual void LineReceived(void *userParam, Buffer *buffer) = 0;
|
||||
virtual void TransmissionComplete(void *userParam, Buffer *buffer) = 0;
|
||||
};
|
||||
|
||||
SerialConsole(USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx,
|
||||
ISerialConsoleCallback *callback, void *callbackUserParam);
|
||||
|
||||
void Send(char const *buffer, uint8_t length = 0);
|
||||
void SendLine(char const *buffer, uint8_t length = 0);
|
||||
|
||||
void HandleRxDmaIrq();
|
||||
void HandleTxDmaIrq();
|
||||
void HandleUsartIrq();
|
||||
|
||||
private:
|
||||
bool m_activeRxBuffer = false;
|
||||
Buffer m_rxBuffers[2];
|
||||
Buffer m_txBuffer;
|
||||
|
||||
ISerialConsoleCallback *m_callback;
|
||||
void *m_callbackUserParam;
|
||||
};
|
||||
|
||||
template<unsigned int bufSize> SerialConsole<bufSize>::SerialConsole(
|
||||
USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx,
|
||||
ISerialConsoleCallback *callback, void *callbackUserParam
|
||||
)
|
||||
: UartBase(uart, dma, stream_rx, stream_tx)
|
||||
, m_callback(callback), m_callbackUserParam(callbackUserParam)
|
||||
{
|
||||
LL_USART_EnableIT_IDLE(uart);
|
||||
SetupReceive(m_rxBuffers[m_activeRxBuffer].buffer, bufSize);
|
||||
}
|
||||
|
||||
template<unsigned int bufSize> void SerialConsole<bufSize>::HandleRxDmaIrq()
|
||||
{
|
||||
if(*m_rxDma.GetIsReg() & m_rxDma.GetTcMask()) {
|
||||
*m_rxDma.GetIfcReg() = m_rxDma.GetTcMask();
|
||||
m_rxBuffers[m_activeRxBuffer].busy = true;
|
||||
if(m_callback)
|
||||
m_callback->LineReceived(m_callbackUserParam, &m_rxBuffers[m_activeRxBuffer]);
|
||||
}
|
||||
|
||||
if(*m_rxDma.GetIsReg() & m_rxDma.GetTeMask()) {
|
||||
*m_rxDma.GetIfcReg() = m_rxDma.GetTeMask();
|
||||
}
|
||||
|
||||
m_activeRxBuffer = !m_activeRxBuffer;
|
||||
|
||||
SetupReceive(m_rxBuffers[m_activeRxBuffer].buffer, bufSize);
|
||||
}
|
||||
|
||||
template<unsigned int bufSize> void SerialConsole<bufSize>::HandleTxDmaIrq()
|
||||
{
|
||||
if(*m_txDma.GetIsReg() & m_txDma.GetTcMask()) { // DMA transfer complete
|
||||
*m_txDma.GetIfcReg() = m_txDma.GetTcMask();
|
||||
LL_USART_EnableIT_TC(m_uart);
|
||||
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
|
||||
}
|
||||
if(*m_txDma.GetIsReg() & m_txDma.GetTeMask()) {
|
||||
*m_txDma.GetIfcReg() = m_txDma.GetTeMask();
|
||||
m_txBuffer.error = true;
|
||||
LL_USART_EnableIT_TC(m_uart);
|
||||
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned int bufSize> void SerialConsole<bufSize>::HandleUsartIrq()
|
||||
{
|
||||
if(LL_USART_IsActiveFlag_IDLE(m_uart) && LL_USART_IsEnabledIT_IDLE(m_uart)) { // receiver idle
|
||||
// we assume that new line marker will arrive without an idle cycle even if it is CRLF
|
||||
LL_USART_ClearFlag_IDLE(m_uart);
|
||||
uint16_t rcvdLen = bufSize - LL_DMA_GetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream());
|
||||
if(rcvdLen ) {
|
||||
bool newLine = false;;
|
||||
do {
|
||||
auto lastChar = m_rxBuffers[m_activeRxBuffer].buffer[rcvdLen-1];
|
||||
if( lastChar == '\r' || lastChar == '\n')
|
||||
newLine = true;
|
||||
else
|
||||
break;
|
||||
} while(--rcvdLen);
|
||||
|
||||
if(newLine) {
|
||||
m_rxBuffers[m_activeRxBuffer].buffer[rcvdLen] = 0;
|
||||
m_rxBuffers[m_activeRxBuffer].len = rcvdLen;
|
||||
LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(LL_USART_IsActiveFlag_TC(m_uart) && LL_USART_IsEnabledIT_TC(m_uart)) { // transmission complete
|
||||
LL_USART_DisableIT_TC(m_uart);
|
||||
LL_USART_DisableDirectionTx(m_uart); // enforcing an idle frame
|
||||
LL_USART_EnableDirectionTx(m_uart);
|
||||
m_txBuffer.busy = false;
|
||||
if(m_callback)
|
||||
m_callback->TransmissionComplete(m_callbackUserParam, &m_txBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned int bufSize> void SerialConsole<bufSize>::Send(char const *buffer, uint8_t length)
|
||||
{
|
||||
if(!length) {
|
||||
auto computedLength = strlen(buffer);
|
||||
if(computedLength <= (uint8_t)-1)
|
||||
length = computedLength;
|
||||
}
|
||||
if(length) {
|
||||
while( m_txBuffer.busy );
|
||||
memcpy(m_txBuffer.buffer, buffer, length);
|
||||
SetupTransmit(m_txBuffer.buffer, length);
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned int bufSize> void SerialConsole<bufSize>::SendLine(char const *buffer, uint8_t length)
|
||||
{
|
||||
if(!length) {
|
||||
auto computedLength = strlen(buffer);
|
||||
if(computedLength <= (uint8_t)-1)
|
||||
length = computedLength;
|
||||
}
|
||||
if(length) {
|
||||
while( m_txBuffer.busy );
|
||||
memcpy(m_txBuffer.buffer, buffer, length);
|
||||
if(m_txBuffer.buffer[length-1 != '\n']) {
|
||||
m_txBuffer.buffer[length++] = '\r';
|
||||
m_txBuffer.buffer[length++] = '\n';
|
||||
}
|
||||
SetupTransmit(m_txBuffer.buffer, length);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONSOLEHANDLER_H_ */
|
35
components/f4ll_cpp/singleton.h
Normal file
35
components/f4ll_cpp/singleton.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* singleton.h
|
||||
*
|
||||
* Created on: Sep 11, 2019
|
||||
* Author: compi
|
||||
*/
|
||||
|
||||
#ifndef SINGLETON_H_
|
||||
#define SINGLETON_H_
|
||||
|
||||
#include <utility>
|
||||
|
||||
template<typename T> class Singleton {
|
||||
public:
|
||||
static T &Instance() { return *m_instance; }
|
||||
template<typename ... Args>
|
||||
static T &Init(Args &&... args)
|
||||
{
|
||||
static T instance{ std::forward<Args>(args)... };
|
||||
if(!m_instance)
|
||||
m_instance = &instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
protected:
|
||||
Singleton() = default;
|
||||
Singleton(const Singleton &) = delete;
|
||||
Singleton &operator=(const Singleton &) = delete;
|
||||
virtual ~Singleton() = default;
|
||||
static T *m_instance;
|
||||
};
|
||||
|
||||
template<typename T> T* Singleton<T>::m_instance = nullptr;
|
||||
|
||||
#endif /* SINGLETON_H_ */
|
110
components/f4ll_cpp/strutil.c
Normal file
110
components/f4ll_cpp/strutil.c
Normal file
|
@ -0,0 +1,110 @@
|
|||
#include <stdint.h>
|
||||
#include <f4ll_cpp/strutil.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
size_t strcpy_ex(char *dst, char const *src)
|
||||
{
|
||||
size_t ret = 0;
|
||||
do {
|
||||
*dst++ = *src;
|
||||
++ret;
|
||||
} while(*src++);
|
||||
return ret - 1;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
void strrev(char *first, char *last)
|
||||
{
|
||||
char tmp;
|
||||
while(last > first) {
|
||||
tmp = *first;
|
||||
*first++ = *last;
|
||||
*last-- = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
char tochr(const uint8_t in, const uint8_t upper)
|
||||
{
|
||||
return in + ((in < 10) ? '0' : (upper ? 'A' : 'a') - 10);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
size_t uitodec(char* buffer, uint32_t data)
|
||||
{
|
||||
char *b2 = buffer;
|
||||
if(!data) {
|
||||
*b2++ = '0';
|
||||
*b2 = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
while(data) {
|
||||
*b2++ = (data % 10) + '0';
|
||||
data /= 10;
|
||||
}
|
||||
size_t ret = b2 - buffer;
|
||||
|
||||
*b2-- = 0;
|
||||
|
||||
strrev(buffer, b2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
size_t uitohex(char* buffer, uint32_t data, uint8_t chars)
|
||||
{
|
||||
char *b2 = buffer;
|
||||
size_t ret = 0;
|
||||
|
||||
if(chars == 0xff || !chars)
|
||||
{
|
||||
if(!data) {
|
||||
*b2++ = '0';
|
||||
*b2 = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
while(data) {
|
||||
uint8_t curval = data & 0x0f;
|
||||
*b2++ = tochr(curval, 1);
|
||||
data >>= 4;
|
||||
}
|
||||
ret = b2 - buffer;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = chars;
|
||||
for(uint8_t pos = 0; pos < (uint8_t)ret; ++pos) {
|
||||
*b2++ = tochr(data & 0x0f, 1);
|
||||
data >>= 4;
|
||||
}
|
||||
|
||||
}
|
||||
*b2-- = 0;
|
||||
strrev(buffer, b2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
size_t itodec(char* buffer, int data)
|
||||
{
|
||||
if(data < 0) {
|
||||
*buffer++ = '-';
|
||||
return uitodec(buffer, -data) + 1;
|
||||
}
|
||||
|
||||
return uitodec(buffer, data);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
size_t itohex(char* buffer, int data)
|
||||
{
|
||||
if(data < 0) {
|
||||
*buffer++ = '-';
|
||||
return uitohex(buffer, -data, 0) + 1;
|
||||
}
|
||||
return uitohex(buffer, data, 0);
|
||||
}
|
31
components/f4ll_cpp/strutil.h
Normal file
31
components/f4ll_cpp/strutil.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* strutil.h
|
||||
*
|
||||
* Created on: Feb 11, 2017
|
||||
* Author: compi
|
||||
*/
|
||||
|
||||
#ifndef _STM32PLUS_STRUTIL_H_
|
||||
#define _STM32PLUS_STRUTIL_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
size_t strcpy_ex(char *dst, char const *src);
|
||||
size_t uitodec(char* buffer, uint32_t data);
|
||||
size_t uitohex(char* buffer, uint32_t data, uint8_t chars);
|
||||
size_t itodec(char* buffer, int data);
|
||||
size_t itohex(char* buffer, int data);
|
||||
void strrev(char *first, char *last);
|
||||
char tochr(const uint8_t in, const uint8_t upper);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _STM32PLUS_STRUTIL_H_ */
|
46
components/f4ll_cpp/uartbase.cpp
Normal file
46
components/f4ll_cpp/uartbase.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* UartBase.cpp
|
||||
*
|
||||
* Created on: Feb 4, 2020
|
||||
* Author: abody
|
||||
*/
|
||||
|
||||
#include <f4ll_cpp/uartbase.h>
|
||||
|
||||
UartBase::UartBase(USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx)
|
||||
: m_uart(uart)
|
||||
, m_rxDma(dma, stream_rx)
|
||||
, m_txDma(dma, stream_tx)
|
||||
{
|
||||
*m_rxDma.GetIfcReg() =
|
||||
m_rxDma.GetTcMask() | m_rxDma.GetHtMask() |
|
||||
m_rxDma.GetTeMask() | m_rxDma.GetFeMask() | m_rxDma.GetDmeMask();
|
||||
*m_txDma.GetIfcReg() =
|
||||
m_txDma.GetTcMask() | m_txDma.GetHtMask() |
|
||||
m_txDma.GetTeMask() | m_txDma.GetFeMask() | m_txDma.GetDmeMask();
|
||||
|
||||
LL_DMA_EnableIT_TC(dma, stream_rx);
|
||||
LL_DMA_EnableIT_TE(dma, stream_rx);
|
||||
LL_DMA_EnableIT_TC(dma, stream_tx);
|
||||
LL_DMA_EnableIT_TE(dma, stream_tx);
|
||||
}
|
||||
|
||||
void UartBase::SetupReceive(void *buffer, uint16_t length)
|
||||
{
|
||||
LL_DMA_ConfigAddresses(m_rxDma.GetDma(), m_rxDma.GetStream(), LL_USART_DMA_GetRegAddr(m_uart),
|
||||
(uint32_t)buffer, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
|
||||
LL_DMA_SetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream(), length); // payload already have extra room for hash
|
||||
LL_USART_EnableDMAReq_RX(m_uart);
|
||||
LL_USART_ClearFlag_ORE(m_uart);
|
||||
LL_DMA_EnableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
|
||||
}
|
||||
|
||||
|
||||
void UartBase::SetupTransmit(void *buffer, uint16_t length)
|
||||
{
|
||||
LL_DMA_ConfigAddresses(m_txDma.GetDma(), m_txDma.GetStream(), (uint32_t)buffer, LL_USART_DMA_GetRegAddr(m_uart), LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
|
||||
LL_DMA_SetDataLength(m_txDma.GetDma(), m_txDma.GetStream(), length);
|
||||
LL_USART_EnableDMAReq_TX(m_uart);
|
||||
LL_DMA_EnableStream(m_txDma.GetDma(), m_txDma.GetStream());
|
||||
}
|
||||
|
27
components/f4ll_cpp/uartbase.h
Normal file
27
components/f4ll_cpp/uartbase.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* UartBase.h
|
||||
*
|
||||
* Created on: Feb 4, 2020
|
||||
* Author: abody
|
||||
*/
|
||||
#ifndef F4LL_CPP_UARTBASE_H_
|
||||
#define F4LL_CPP_UARTBASE_H_
|
||||
|
||||
#include <platform/usart_ll.h>
|
||||
#include <f4ll_cpp/dmahelper.h>
|
||||
|
||||
class UartBase
|
||||
{
|
||||
public:
|
||||
UartBase() = delete;
|
||||
protected:
|
||||
UartBase(USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx);
|
||||
void SetupTransmit(void *buffer, uint16_t length);
|
||||
void SetupReceive(void *buffer, uint16_t length);
|
||||
|
||||
USART_TypeDef *m_uart;
|
||||
DmaHelper m_rxDma;
|
||||
DmaHelper m_txDma;
|
||||
};
|
||||
|
||||
#endif /* F4LL_CPP_UARTBASE_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue