Fixed ISerialBus interface and added device and register address fields so that future i2c and SPI devices can be addressed, to. Added i2c HAL. Tested, working.
The update on the interface required FunctionStatus and the logger to be updated, too
This commit is contained in:
@@ -5,13 +5,12 @@ idf_component_register(
|
||||
SRCS # list the source files of this component
|
||||
"main.cpp"
|
||||
# "old/src/bmp280.cpp"
|
||||
"hal/src/i2c.cpp"
|
||||
"hal/src/gpio.cpp"
|
||||
"hal/src/uart.cpp"
|
||||
|
||||
"platform/src/logger.cpp"
|
||||
# "old/src/i2c.cpp"
|
||||
# "old/src/wifi.cpp"
|
||||
# "old/src/logger.cpp"
|
||||
# "old/src/led_strip_encoder.c"
|
||||
# "old/src/ledmatrix.cpp"
|
||||
# "old/src/clock.cpp"
|
||||
|
||||
@@ -58,6 +58,7 @@ typedef enum
|
||||
//!< instance is already initialized
|
||||
FUNCTION_STATUS_UNDEFINED_VALUE = 4, //!< The function failed because an undefined value was used
|
||||
//!< This most probably happened when checking an enum
|
||||
FUNCTION_STATUS_NOT_IMPLEMENTED = 5, //!< The required functionality is not (yet) implemented
|
||||
// Interfaces/Busses
|
||||
FUNCTION_STATUS_NOT_OPEN = 10, //!< The Interface cannot be used because it has not been opened
|
||||
FUNCTION_STATUS_ALREADY_OPEN = 11, //!< The interface cannot be opened because it is already open
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
// Constant and macro definitions
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#define NO_DEVICE_ADDRESS (255)
|
||||
#define NO_REGISTER_ADDRESS (255)
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Type definitions.
|
||||
@@ -70,9 +72,9 @@ class ISerialBus
|
||||
|
||||
FunctionStatus close() {status = CLOSED; return FUNCTION_STATUS_OK;}
|
||||
|
||||
virtual FunctionStatus read(T* buffer, uint32_t length, uint32_t* actualLength) = 0;
|
||||
virtual FunctionStatus read(T deviceAddress, T registerAddress, T* buffer, uint32_t length, uint32_t* actualLength) = 0;
|
||||
|
||||
virtual FunctionStatus write(T* buffer, uint32_t length) = 0;
|
||||
virtual FunctionStatus write(T deviceAddress, T registerAddress, T* buffer, uint32_t length) = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
/// \file gpio.h
|
||||
/// \file i2c.h
|
||||
/// \brief File description
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
@@ -13,8 +13,18 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef MAIN_INC_GPIO_H_
|
||||
#define MAIN_INC_GPIO_H_
|
||||
#ifndef MAIN_HAL_INC_I2C_H_
|
||||
#define MAIN_HAL_INC_I2C_H_
|
||||
|
||||
/**
|
||||
* i2c implementation
|
||||
* \defgroup i2c
|
||||
* \brief {group_description}
|
||||
* \addtogroup {Layer}
|
||||
*
|
||||
* Detailed description
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -29,55 +39,58 @@
|
||||
|
||||
// ProjectIncludes
|
||||
// All include files that are provided by the project
|
||||
#include "ISerialBus.h"
|
||||
|
||||
#include "driver/i2c.h"
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Constant and macro definitions
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Type definitions.
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GPIO_DIRECTION_INPUT = 0,
|
||||
GPIO_DIRECTION_OUTPUT = 1
|
||||
} GPIO_Direction_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GPIO_VALUE_LOW = 0,
|
||||
GPIO_VALUE_HIGH = 1
|
||||
} GPIO_Value_t;
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Function declarations
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
class GPIO
|
||||
class i2c : public ISerialBus<uint8_t>
|
||||
{
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Public Section
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
public:
|
||||
// Class Constructor
|
||||
i2c(i2c_port_t* port);
|
||||
~i2c();
|
||||
|
||||
GPIO(int number, GPIO_Direction_t direction);
|
||||
FunctionStatus read(uint8_t deviceAddress, uint8_t registerAddress, uint8_t* buffer, uint32_t length, uint32_t* actualLength);
|
||||
|
||||
bool SetOutput(GPIO_Value_t value);
|
||||
FunctionStatus write(uint8_t deviceAddress, uint8_t registerAddress, uint8_t* buffer, uint32_t length);
|
||||
|
||||
GPIO_Value_t GetInput(void);
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Protected Section
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
protected:
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Private Section
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
private:
|
||||
|
||||
int number;
|
||||
void intWrite(uint8_t slaveAddress, uint8_t registerAddress, uint8_t* data, uint8_t length);
|
||||
void intRead(uint8_t slaveAddress, uint8_t registerAddress, uint8_t* data, uint8_t length);
|
||||
|
||||
GPIO_Direction_t direction;
|
||||
i2c_port_t* port;
|
||||
|
||||
GPIO_Value_t value = GPIO_VALUE_LOW;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* MAIN_INC_GPIO_H_ */
|
||||
|
||||
#endif /* MAIN_HAL_INC_I2C_H_ */
|
||||
@@ -67,9 +67,9 @@ class uart : public ISerialBus<uint8_t>
|
||||
uart(uart_port_t* uartPort);
|
||||
~uart();
|
||||
|
||||
FunctionStatus read(uint8_t* buffer, uint32_t length, uint32_t* actualLength);
|
||||
FunctionStatus read(uint8_t deviceAddress, uint8_t registerAddress, uint8_t* buffer, uint32_t length, uint32_t* actualLength);
|
||||
|
||||
FunctionStatus write(uint8_t* buffer, uint32_t length);
|
||||
FunctionStatus write(uint8_t deviceAddress, uint8_t registerAddress, uint8_t* buffer, uint32_t length);
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Protected Section
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
/// \file gpio.cpp
|
||||
/// \file i2c.cpp
|
||||
/// \brief Description
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
@@ -17,16 +17,13 @@
|
||||
// Include files
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include <gpio.h>
|
||||
#include "driver/gpio.h"
|
||||
|
||||
|
||||
#include <i2c.h>
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Constant and macro definitions
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#define I2C_MASTER_TIMEOUT_MS 1000
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Type definitions
|
||||
@@ -49,58 +46,68 @@
|
||||
// Function definitions
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
GPIO::GPIO(int number, GPIO_Direction_t direction)
|
||||
{
|
||||
this->number = number;
|
||||
this->direction = direction;
|
||||
|
||||
//zero-initialize the config structure.
|
||||
gpio_config_t io_conf = {};
|
||||
//disable interrupt
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
//set as output mode
|
||||
io_conf.mode = (this->direction == GPIO_DIRECTION_OUTPUT) ? GPIO_MODE_OUTPUT : GPIO_MODE_INPUT;
|
||||
//bit mask of the pins that you want to set
|
||||
io_conf.pin_bit_mask = (1ULL << this->number);
|
||||
//disable pull-down mode
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
//disable pull-up mode
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
//configure GPIO with the given settings
|
||||
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
||||
i2c::i2c(i2c_port_t* port) : port {port}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
i2c::~i2c()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool GPIO::SetOutput(GPIO_Value_t value)
|
||||
FunctionStatus i2c::write(uint8_t deviceAddress, uint8_t registerAddress, uint8_t* buffer, uint32_t length)
|
||||
{
|
||||
bool returnValue = false;
|
||||
FunctionStatus returnValue = FUNCTION_STATUS_OK;
|
||||
|
||||
if (this->direction == GPIO_DIRECTION_OUTPUT)
|
||||
if (status == OPEN)
|
||||
{
|
||||
ESP_ERROR_CHECK(gpio_set_level((gpio_num_t)this->number, (uint32_t)value));
|
||||
this->value = value;
|
||||
returnValue = true;
|
||||
intWrite(deviceAddress, registerAddress, buffer, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
returnValue = false;
|
||||
returnValue = FUNCTION_STATUS_NOT_OPEN;
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
GPIO_Value_t GPIO::GetInput(void)
|
||||
|
||||
FunctionStatus i2c::read(uint8_t deviceAddress, uint8_t registerAddress, uint8_t* buffer, uint32_t length, uint32_t* actualLength)
|
||||
{
|
||||
if (gpio_get_level((gpio_num_t)this->number))
|
||||
FunctionStatus returnValue = FUNCTION_STATUS_OK;
|
||||
|
||||
if (status == OPEN)
|
||||
{
|
||||
this->value = GPIO_VALUE_HIGH;
|
||||
intRead(deviceAddress, registerAddress, buffer, length);
|
||||
*actualLength = length;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->value = GPIO_VALUE_LOW;
|
||||
returnValue = FUNCTION_STATUS_NOT_OPEN;
|
||||
}
|
||||
|
||||
return this->value;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
|
||||
void i2c::intWrite(uint8_t slaveAddress, uint8_t registerAddress, uint8_t* data, uint8_t length)
|
||||
{
|
||||
uint8_t buffer[length + 1];
|
||||
|
||||
buffer[0] = registerAddress;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
buffer[i+1] = data[i];
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(i2c_master_write_to_device(*port, slaveAddress, buffer, sizeof(buffer), I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS));
|
||||
}
|
||||
|
||||
|
||||
void i2c::intRead(uint8_t slaveAddress, uint8_t registerAddress, uint8_t* data, uint8_t length)
|
||||
{
|
||||
ESP_ERROR_CHECK(i2c_master_write_read_device(*port, slaveAddress, ®isterAddress, 1, data, length, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS));
|
||||
}
|
||||
@@ -57,15 +57,25 @@ uart::~uart()
|
||||
|
||||
}
|
||||
|
||||
FunctionStatus uart::write(uint8_t* buffer, uint32_t length)
|
||||
FunctionStatus uart::write(uint8_t deviceAddress, uint8_t registerAddress, uint8_t* buffer, uint32_t length)
|
||||
{
|
||||
FunctionStatus returnValue = FUNCTION_STATUS_OK;
|
||||
|
||||
if (status == OPEN)
|
||||
{
|
||||
// For UART devices it is allowed to ignore the device or register address if it is requested as such
|
||||
// The common case is that both addresses are ignorable since UARTs are mostly not used this way, so this
|
||||
// implementation contains a shortcut and will immediatly write the buffer to the bus
|
||||
if ((deviceAddress == NO_DEVICE_ADDRESS) && (registerAddress == NO_REGISTER_ADDRESS))
|
||||
{
|
||||
uart_write_bytes(*this->port, (const void*)buffer, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
returnValue = FUNCTION_STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
returnValue = FUNCTION_STATUS_NOT_OPEN;
|
||||
}
|
||||
@@ -73,7 +83,7 @@ FunctionStatus uart::write(uint8_t* buffer, uint32_t length)
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
FunctionStatus uart::read(uint8_t* buffer, uint32_t length, uint32_t* actualLength)
|
||||
FunctionStatus uart::read(uint8_t deviceAddress, uint8_t registerAddress, uint8_t* buffer, uint32_t length, uint32_t* actualLength)
|
||||
{
|
||||
FunctionStatus returnValue = FUNCTION_STATUS_OK;
|
||||
|
||||
|
||||
+34
-9
@@ -29,6 +29,7 @@
|
||||
|
||||
// HAL includes
|
||||
#include "gpio.h"
|
||||
#include "i2c.h"
|
||||
#include "uart.h"
|
||||
|
||||
// Platform includes
|
||||
@@ -47,8 +48,6 @@
|
||||
// File-scope variables
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
static uart_port_t uartPort = UART_NUM_0;
|
||||
|
||||
static TaskHandle_t loggerTaskHandle;
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Function declarations
|
||||
@@ -72,10 +71,10 @@ extern "C" void app_main(void)
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
|
||||
//--------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// UART
|
||||
//
|
||||
const uart_config_t uartConfig =
|
||||
uart_config_t uartConfig =
|
||||
{
|
||||
.baud_rate = 115200,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
@@ -85,16 +84,17 @@ extern "C" void app_main(void)
|
||||
.rx_flow_ctrl_thresh = 0,
|
||||
.source_clk = UART_SCLK_DEFAULT
|
||||
};
|
||||
static uart_port_t debugUart = UART_NUM_0;
|
||||
ESP_ERROR_CHECK(uart_param_config(debugUart, &uartConfig));
|
||||
ESP_ERROR_CHECK(uart_set_pin(debugUart, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
ESP_ERROR_CHECK(uart_driver_install(debugUart, 1024, 1024, 0, NULL, 0));
|
||||
|
||||
ESP_ERROR_CHECK(uart_param_config(uartPort, &uartConfig));
|
||||
ESP_ERROR_CHECK(uart_set_pin(uartPort, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
ESP_ERROR_CHECK(uart_driver_install(uartPort, 1024, 1024, 0, NULL, 0));
|
||||
|
||||
uart uartDebug = uart(&uartPort);
|
||||
uart uartDebug = uart(&debugUart);
|
||||
uartDebug.open();
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// System-wide Debug Logger
|
||||
//
|
||||
|
||||
logger debugLogger = logger(16, uartDebug);
|
||||
// Call the logger executable within a dedicated task and forget about it afterwards
|
||||
@@ -107,6 +107,31 @@ extern "C" void app_main(void)
|
||||
LOGGER_PRINT("Release: %d.%d \n\r", MAJORRELEASE, MINORRELEASE);
|
||||
LOGGER_PRINT("Compiled on %s at %s\n\r\n\r\n\r", __DATE__, __TIME__);
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// I2C Masterbus for sensoring peripherals
|
||||
//
|
||||
i2c_port_t i2c_master_port = I2C_NUM_0;
|
||||
|
||||
i2c_config_t i2cConfig = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = (int)4,
|
||||
.scl_io_num = (int)5,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master = 400000,
|
||||
.clk_flags = 0
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(i2c_param_config(i2c_master_port, &i2cConfig));
|
||||
ESP_ERROR_CHECK(i2c_driver_install(i2c_master_port, i2cConfig.mode, 0, 0, 0));
|
||||
|
||||
i2c i2cSensor = i2c(&i2c_master_port);
|
||||
i2cSensor.open();
|
||||
uint8_t i2cData[2] = {0x12, 0x34};
|
||||
i2cSensor.write(0x40, 0x00, i2cData, 2);
|
||||
|
||||
|
||||
|
||||
gpio debugIO = gpio(2, gpio::Direction_t::GPIO_DIRECTION_OUTPUT, gpio::Value_t::GPIO_VALUE_LOW);
|
||||
|
||||
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
/// \file logger.h
|
||||
/// \brief File description
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// vbchaos software design
|
||||
//
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
/// $Revision: $
|
||||
/// $Author: $
|
||||
/// $Date: $
|
||||
// (c) 2023 vbchaos
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef MAIN_INC_LOGGER_H_
|
||||
#define MAIN_INC_LOGGER_H_
|
||||
|
||||
/**
|
||||
* Logger implementation
|
||||
* \defgroup Logger
|
||||
* \brief Implementation of a non-blocking logger for debug purpose
|
||||
* \ingroup Platform
|
||||
*
|
||||
* A non-blocking logger that implements its own task with very low (unimportant)
|
||||
* priority
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Include files
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// CompilerIncludes
|
||||
// All include files that are provided by the compiler directly
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// ProjectIncludes
|
||||
// All include files that are provided by the project
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "driver/uart_select.h"
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Constant and macro definitions
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Logs an error
|
||||
* \memberof Logger
|
||||
*/
|
||||
#define LOGGER_ERROR(...) \
|
||||
Logger::Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_ERROR, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Logs a success
|
||||
* \memberof Logger
|
||||
*/
|
||||
#define LOGGER_SUCCESS(...) \
|
||||
Logger::Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_SUCCESS, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Logs an error
|
||||
* \memberof Logger
|
||||
*/
|
||||
#define LOGGER_WARNING(...) \
|
||||
Logger::Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_WARNING, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Logs an error
|
||||
* \memberof Logger
|
||||
*/
|
||||
#define LOGGER_INFO(...) \
|
||||
Logger::Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_INFO, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Logs an error
|
||||
* \memberof Logger
|
||||
*/
|
||||
#define LOGGER_DEBUG(...) \
|
||||
Logger::Logger_log(__FILE__, __func__, __LINE__, LOGTYPE_DEBUG, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Logs an error
|
||||
* \memberof Logger
|
||||
*/
|
||||
#define LOGGER_PRINT(...) \
|
||||
Logger::Logger_log("", "", 0, LOGTYPE_PRINT, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Logs an error
|
||||
* \memberof Logger
|
||||
*/
|
||||
#define LOGGER_ERROR_ISR(...) \
|
||||
Logger::Logger_logISR(__FILE__, __func__, __LINE__, LOGTYPE_ERROR, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Logs a success
|
||||
* \memberof Logger
|
||||
*/
|
||||
#define LOGGER_SUCCESS_ISR(...) \
|
||||
Logger::Logger_logISR(__FILE__, __func__, __LINE__, LOGTYPE_ERROR, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Logs an error
|
||||
* \memberof Logger
|
||||
*/
|
||||
#define LOGGER_WARNING_ISR(...) \
|
||||
Logger::Logger_logISR(__FILE__, __func__, __LINE__, LOGTYPE_WARNING, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Logs an error
|
||||
* \memberof Logger
|
||||
*/
|
||||
#define LOGGER_INFO_ISR(...) \
|
||||
Logger::Logger_logISR(__FILE__, __func__, __LINE__, LOGTYPE_INFO, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Logs an error
|
||||
* \memberof Logger
|
||||
*/
|
||||
#define LOGGER_DEBUG_ISR(a, ...) \
|
||||
Logger::Logger_logISR(a, __FILE__, __func__, __LINE__, LOGTYPE_DEBUG, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Logs an error
|
||||
* \memberof Logger
|
||||
*/
|
||||
#define LOGGER_PRINT_ISR(a, ...) \
|
||||
Logger::Logger_logISR(a, "", "", 0, LOGTYPE_PRINT, ##__VA_ARGS__)
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Type definitions.
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LOGTYPE_PRINT, /**< Raw print */
|
||||
LOGTYPE_DEBUG, /**< Debug information only; will not be stored on SD-card */
|
||||
LOGTYPE_INFO, /**< Informational messages of important events */
|
||||
LOGTYPE_WARNING, /**< Recoverable fault */
|
||||
LOGTYPE_SUCCESS, /**< A specific success message */
|
||||
LOGTYPE_ERROR /**< Unrecoverable fault */
|
||||
} LogType;
|
||||
|
||||
|
||||
struct LogQueueItem
|
||||
{
|
||||
char fileName[32];
|
||||
char functionName[32];
|
||||
char context[128];
|
||||
int lineNumber;
|
||||
LogType logType;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Function declarations
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
static uart_port_t uartPort;
|
||||
static int queuesize;
|
||||
static QueueHandle_t logQueue;
|
||||
|
||||
Logger(int queuesize, uart_port_t uartPort);
|
||||
|
||||
static void Logger_log(const char* fileName, const char* functionName, int lineNumber, LogType logType, const char* format, ...);
|
||||
|
||||
static void Logger_logISR(struct Logger* self, const char* fileName, const char* functionName, int lineNumber, LogType logType, const char* context);
|
||||
|
||||
private:
|
||||
static TaskHandle_t logTaskHandle;
|
||||
|
||||
static void loggerTask(void* parameters);
|
||||
|
||||
static void composeLogQueueItem(struct LogQueueItem* logQueueItem, const char* fileName, const char* functionName,
|
||||
int lineNumber, LogType logType, const char* context);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* MAIN_INC_LOGGER_H_ */
|
||||
@@ -1,254 +0,0 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
/// \file logger.cpp
|
||||
/// \brief Description
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// vbchaos software design
|
||||
//
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
/// $Revision: $
|
||||
/// $Author: $
|
||||
/// $Date: $
|
||||
// (c) 2023 vbchaos
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Include files
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Constant and macro definitions
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#define ENABLE_SERIAL_LOGGING
|
||||
//#undef ENABLE_SERIAL_LOGGING
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Type definitions
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// File-scope variables
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Function declarations
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Function definitions
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
TaskHandle_t Logger::logTaskHandle = NULL;
|
||||
uart_port_t Logger::uartPort = 0;
|
||||
QueueHandle_t Logger::logQueue = NULL;
|
||||
int Logger::queuesize = 0;
|
||||
|
||||
Logger::Logger(int queuesize, uart_port_t uartPort)
|
||||
{
|
||||
Logger::uartPort = uartPort;
|
||||
Logger::queuesize = queuesize;
|
||||
logQueue = xQueueCreate(queuesize, sizeof(struct LogQueueItem));
|
||||
|
||||
xTaskCreate(loggerTask, (const char*)"loggerTask", 3072, NULL, 3, &logTaskHandle);
|
||||
|
||||
}
|
||||
|
||||
void Logger::Logger_log(const char* fileName, const char* functionName, int lineNumber, LogType logType, const char* format, ...)
|
||||
{
|
||||
#if defined(ENABLE_SERIAL_LOGGING)
|
||||
static int nrLostMessages = 0;
|
||||
static bool overflowRecovery = false;
|
||||
int nrOfMessages;
|
||||
struct LogQueueItem logQueueItem;
|
||||
va_list ap;
|
||||
|
||||
nrOfMessages = uxQueueMessagesWaiting(Logger::logQueue);
|
||||
|
||||
if((nrOfMessages == queuesize - 1) && !overflowRecovery)
|
||||
{
|
||||
// Queue almost full, only one entry left. Log a warning instead
|
||||
composeLogQueueItem(&logQueueItem, __FILE__, __func__, __LINE__, LOGTYPE_WARNING, "Log queue overflow");
|
||||
(void)xQueueSend(logQueue, &logQueueItem, 0);
|
||||
|
||||
overflowRecovery = true;
|
||||
nrLostMessages = 1;
|
||||
}
|
||||
else if((nrOfMessages == 0) && overflowRecovery)
|
||||
{
|
||||
// Queue empty again after an overflow
|
||||
char str[128];
|
||||
snprintf(str, sizeof(str) / sizeof(str[0]), "%d messages lost", nrLostMessages);
|
||||
composeLogQueueItem(&logQueueItem, __FILE__, __func__, __LINE__, LOGTYPE_WARNING, str);
|
||||
(void)xQueueSend(logQueue, &logQueueItem, 0);
|
||||
|
||||
overflowRecovery = false;
|
||||
}
|
||||
else if(!overflowRecovery)
|
||||
{
|
||||
// Normal behaviour, queue not full
|
||||
char str[128];
|
||||
va_start(ap, format);
|
||||
vsnprintf(str, sizeof(str) / sizeof(str[0]), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
composeLogQueueItem(&logQueueItem, fileName, functionName, lineNumber, logType, str);
|
||||
(void)xQueueSend(logQueue, &logQueueItem, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Count number of lost messages
|
||||
++nrLostMessages;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Logger_logISR(struct Logger* self, const char* fileName, const char* functionName, int lineNumber, LogType logType, const char* context)
|
||||
{
|
||||
#if defined(ENABLE_LOGGING)
|
||||
if (self->initialized)
|
||||
{
|
||||
struct LogQueueItem logQueueItem;
|
||||
portBASE_TYPE higherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
composeLogQueueItem(&logQueueItem, fileName, functionName, lineNumber, logType, context);
|
||||
|
||||
if(xQueueSendFromISR(self->logQueue, &logQueueItem, &higherPriorityTaskWoken) != pdTRUE)
|
||||
{
|
||||
// Queue failed
|
||||
}
|
||||
|
||||
portEND_SWITCHING_ISR(higherPriorityTaskWoken);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined(ENABLE_SERIAL_LOGGING)
|
||||
void Logger::composeLogQueueItem(struct LogQueueItem* logQueueItem, const char* fileName, const char* functionName,
|
||||
int lineNumber, LogType logType, const char* context)
|
||||
{
|
||||
const size_t fileNameSize = sizeof(logQueueItem->fileName) / sizeof(logQueueItem->fileName[0]);
|
||||
const size_t functionNameSize = sizeof(logQueueItem->functionName) / sizeof(logQueueItem->functionName[0]);
|
||||
const size_t contextSize = sizeof(logQueueItem->context) / sizeof(logQueueItem->context[0]);
|
||||
|
||||
logQueueItem->logType = logType;
|
||||
strncpy(&(logQueueItem->context[0]), context, contextSize);
|
||||
logQueueItem->context[contextSize - 1] = '\0';
|
||||
|
||||
if(logType != LOGTYPE_PRINT)
|
||||
{
|
||||
int fileNameIndex = 0;
|
||||
|
||||
// If filename starts with "src/", strip this part
|
||||
if((fileName[0] == 's') &&
|
||||
(fileName[1] == 'r') &&
|
||||
(fileName[2] == 'c') &&
|
||||
(fileName[3] == '/'))
|
||||
{
|
||||
fileNameIndex = 4;
|
||||
}
|
||||
|
||||
// It is known that the strncpy use can potentially truncate the source string, meaning
|
||||
// that the target string size is smaller then the original string
|
||||
// This is not a problem in this particular case, so the compiler warning is disabled
|
||||
// for this situation
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstringop-truncation"
|
||||
// All logtypes except LOGTYPE_PRINT need filename, functionname and linenumber.
|
||||
strncpy(&(logQueueItem->fileName[0]), &fileName[fileNameIndex], fileNameSize);
|
||||
strncpy(&(logQueueItem->functionName[0]), functionName, functionNameSize);
|
||||
#pragma GCC diagnostic pop
|
||||
logQueueItem->lineNumber = lineNumber;
|
||||
|
||||
// Fix terminating null byte in strncpy in case string to be copied is too long
|
||||
logQueueItem->fileName[fileNameSize - 1] = '\0';
|
||||
logQueueItem->functionName[functionNameSize - 1] = '\0';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void Logger::loggerTask(void* parameters)
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
struct LogQueueItem logQueueItem;
|
||||
|
||||
xQueueReceive(logQueue, &logQueueItem, portMAX_DELAY);
|
||||
|
||||
if(logQueueItem.logType == LOGTYPE_PRINT)
|
||||
{
|
||||
// Raw print
|
||||
#if defined(ENABLE_SERIAL_LOGGING)
|
||||
uart_write_bytes(uartPort, logQueueItem.context, strlen(logQueueItem.context));
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(ENABLE_SERIAL_LOGGING)
|
||||
char str[256];
|
||||
char* vt100Prefix = "";
|
||||
const char* vt100Postfix = "\033[0m";
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_SERIAL_LOGGING)
|
||||
if(logQueueItem.logType == LOGTYPE_INFO)
|
||||
{
|
||||
vt100Prefix = "\033[33m";
|
||||
}
|
||||
else if(logQueueItem.logType == LOGTYPE_WARNING)
|
||||
{
|
||||
vt100Prefix = "\033[35m";
|
||||
}
|
||||
else if(logQueueItem.logType == LOGTYPE_ERROR)
|
||||
{
|
||||
vt100Prefix = "\033[31m";
|
||||
}
|
||||
else if(logQueueItem.logType == LOGTYPE_SUCCESS)
|
||||
{
|
||||
vt100Prefix = "\033[32m";
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int seconds = 0;
|
||||
|
||||
#if defined(ENABLE_SERIAL_LOGGING)
|
||||
// Formatted print
|
||||
snprintf(str, sizeof(str) / sizeof(str[0]), "%s[%s] %09d %s, %s, %d: %s%s\n\r",
|
||||
vt100Prefix,
|
||||
(logQueueItem.logType == LOGTYPE_DEBUG) ? "DBG" :
|
||||
(logQueueItem.logType == LOGTYPE_INFO) ? "INF" :
|
||||
(logQueueItem.logType == LOGTYPE_SUCCESS) ? "SCS" :
|
||||
(logQueueItem.logType == LOGTYPE_WARNING) ? "WRN" : "ERR",
|
||||
seconds,
|
||||
logQueueItem.fileName,
|
||||
logQueueItem.functionName,
|
||||
logQueueItem.lineNumber,
|
||||
logQueueItem.context,
|
||||
vt100Postfix);
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_SERIAL_LOGGING)
|
||||
uart_write_bytes(uartPort, str, strlen(str));
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
@@ -194,7 +194,7 @@ void logger::task()
|
||||
// Raw print
|
||||
#if defined(ENABLE_SERIAL_LOGGING)
|
||||
|
||||
port.write((uint8_t*)logQueueItem.context.c_str(), logQueueItem.context.length() + 1);
|
||||
port.write(NO_DEVICE_ADDRESS, NO_REGISTER_ADDRESS, (uint8_t*)logQueueItem.context.c_str(), logQueueItem.context.length() + 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -217,7 +217,7 @@ void logger::task()
|
||||
+ logQueueItem.context + " "
|
||||
+ it->vt100Postfix;
|
||||
|
||||
port.write((uint8_t*)outputString.c_str(), outputString.length() + 1);
|
||||
port.write(NO_DEVICE_ADDRESS, NO_REGISTER_ADDRESS, (uint8_t*)outputString.c_str(), outputString.length() + 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user