Unclear how to build a C++ class for a UART GPS receiver that uses HAL DMA library calls
I'm in a fair ways over my head here. I figured out how to build a STM32F413 program that interfaces with a uBlox GPS receiver over a UART serial port. Now I'm trying to build that code into a C++ class that gets instantiated in my main application. My main app is a fairly standard "Gang of Four" state machine and I'm trying to make all my methods non-blocking to the greatest extent reasonable. So, commands are sent to the GPS receiver using DMA and messages from the GPS receiver are also handled with DMA and the idle line detect IRQ since I don't always know how many bytes are in the message. Eventually there will be 7 or 8 different UART devices but I'm hoping to make them all look like this GPS device.
In order to make the HAL_UART_RXIdleCallback work I had to declare it static in the .hpp file. It all works until I try to call a method from another object (like my msgQ object) in the HAL_UART_RXIdleCallback method. Then I get the error "Invalid use of member msgQ in static member function".
I've tried a few work arounds but I can't get past the issue that HAL_UART_RXIdleCallback needs to be static as far as I can tell. Another issue is I'm just not knowledgeable enough yet to dump the HAL library and write my own low level drivers. I understand this is a pretty complicated question but if anyone has any suggestions, I'd be happy to hear them.
Here's the GPS class header file. The msgQ is instantiated at line 35 below.
#pragma once
#include <stm32f4xx_hal.h>
#include <string>
using namespace std;
#include "FIFOQueue.hpp"
static UART_HandleTypeDef hUART7 = UART_HandleTypeDef();
static DMA_HandleTypeDef hDMA_RX = DMA_HandleTypeDef();
static DMA_HandleTypeDef hDMA_TX = DMA_HandleTypeDef();
const uint32_t RXBufferLength = 512;
static uint8_t RXBuffer[RXBufferLength];
//TODO probably should make this inheritable by future uartUBloxGPS and i2cUBloxGPS
class ubloxGPS
{
public:
ubloxGPS(string qid)
{
configUART();
qID = qid;
}
static void HAL_UART_RXIdleCallback(UART_HandleTypeDef *huart);
void getPosition();
int32_t checkMsgQ(FIFOQueue::QRecord qRecord);
private:
uint8_t GPSMessage[256];
uint16_t GPSMessageIndex = 0;
string qID;
//TODO might want to add a cmdQ sometime in the future
FIFOQueue msgQ {4, 256, "ubloxGPSMsgQ"};
void configUART();
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
};and here the implementation. I get the error at line 41 below
#include <stm32f4xx_hal.h>
#include <iostream>
#include <string.h>
using namespace std;
#include "ubloxGPS.hpp"
#include "FIFOQueue.hpp"
const uint8_t PUBX00cmd[] = "$PUBX,00*33\r\n";
void ubloxGPS::getPosition()
{
HAL_UART_Transmit_DMA(&hUART7, (uint8_t *)PUBX00cmd, sizeof(PUBX00cmd));
HAL_UART_Receive_DMA(&hUART7, RXBuffer, RXBufferLength);
}
//TODO Figure out why certain methods are extern "C" and why some aren't
extern "C" void UART7_IRQHandler()
{
//cout << "hit LPUART1_IRQHandler" << endl;
HAL_UART_IRQHandler(&hUART7);
if (__HAL_UART_GET_FLAG(&hUART7, UART_FLAG_IDLE))
{
ubloxGPS::HAL_UART_RXIdleCallback(&hUART7);
__HAL_UART_CLEAR_IDLEFLAG(&hUART7);
}
}
void ubloxGPS::HAL_UART_RXIdleCallback(UART_HandleTypeDef *huart)
{
HAL_UART_DMAStop(&hUART7);
cout << "hit HAL_UART_RXIdleCallback" << endl;
cout << "RX GPS Message: " << RXBuffer << endl;
memset(RXBuffer, 0, RXBufferLength);
HAL_UART_Receive_DMA(&hUART7, RXBuffer, RXBufferLength);
msgQ.enqueue()
}
extern "C" void DMA1_Stream1_IRQHandler()
{
cout << "hit DMA1_Stream1_IRQHandler (TX)" << endl;
HAL_DMA_IRQHandler(&hDMA_TX);
}
extern "C" void DMA1_Stream3_IRQHandler()
{
cout << "hit DMA1_Stream3_IRQHandler (RX)" << endl;
HAL_DMA_IRQHandler(&hDMA_RX);
}
void ubloxGPS::HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
cout << "Hit HAL_UART_RxCpltCallback" << endl;
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
cout << "UART TX Complete" << endl;
}
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
{
cout << "UART TX Half Complete" << endl;
}
void ubloxGPS::configUART()
{
/**UART7 GPIO Configuration
PF6 ------> UART7_RX
PF7 ------> UART7_TX
*/
__USART7_CLK_ENABLE();
__GPIOF_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = GPIO_PIN_7;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Alternate = GPIO_AF8_UART7;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_InitStructure.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOF, &GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_6;
GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
HAL_GPIO_Init(GPIOF, &GPIO_InitStructure);
hUART7.Instance = UART7;
hUART7.Init.BaudRate = 9600;
hUART7.Init.WordLength = UART_WORDLENGTH_8B;
hUART7.Init.StopBits = UART_STOPBITS_1;
hUART7.Init.Parity = UART_PARITY_NONE;
hUART7.Init.HwFlowCtl = UART_HWCONTROL_NONE;
hUART7.Init.Mode = UART_MODE_TX_RX;
if (HAL_UART_Init(&hUART7) != HAL_OK)
{
cout << "Error in UART_Init" << endl;
while (1) {}
}
NVIC_EnableIRQ(UART7_IRQn);
__HAL_UART_ENABLE_IT(&hUART7, UART_IT_IDLE);
//Setup UART TX DMA
__DMA1_CLK_ENABLE();
hDMA_TX.Instance = DMA1_Stream1;
hDMA_TX.Init.Channel = DMA_CHANNEL_5;
hDMA_TX.Init.Direction = DMA_MEMORY_TO_PERIPH;
hDMA_TX.Init.PeriphInc = DMA_PINC_DISABLE;
hDMA_TX.Init.MemInc = DMA_MINC_ENABLE;
//hDMA.Init.Mode = DMA_CIRCULAR;
hDMA_TX.Init.Mode = DMA_NORMAL;
//hDMA.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hDMA_TX.Init.Priority = DMA_PRIORITY_LOW;
hDMA_TX.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hDMA_TX.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
if (HAL_DMA_Init(&hDMA_TX) != HAL_OK)
asm("bkpt 255");
__HAL_LINKDMA(&hUART7, hdmatx, hDMA_TX);
NVIC_EnableIRQ(DMA1_Stream1_IRQn);
//Setup UART RX DMA
hDMA_RX.Instance = DMA1_Stream3;
hDMA_RX.Init.Channel = DMA_CHANNEL_5;
hDMA_RX.Init.Direction = DMA_PERIPH_TO_MEMORY;
hDMA_RX.Init.PeriphInc = DMA_PINC_DISABLE;
hDMA_RX.Init.MemInc = DMA_MINC_ENABLE;
//hDMA.Init.Mode = DMA_CIRCULAR;
hDMA_RX.Init.Mode = DMA_NORMAL;
//hDMA.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hDMA_RX.Init.Priority = DMA_PRIORITY_HIGH;
hDMA_RX.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hDMA_RX.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
if (HAL_DMA_Init(&hDMA_RX) != HAL_OK)
asm("bkpt 255");
__HAL_LINKDMA(&hUART7, hdmarx, hDMA_RX);
NVIC_EnableIRQ(DMA1_Stream3_IRQn);
}