1
0

Initial commit

This commit is contained in:
2023-11-28 14:19:36 +01:00
commit 2b9655cdce
262 changed files with 151100 additions and 0 deletions

101
src/app/factory.cpp Normal file
View File

@ -0,0 +1,101 @@
#include "mcu/mcu.h"
#include "xf/xf.h"
#include "factory.h"
#include "board/interface/buttonscontrollercallbackprovider.h"
extern "C" TIM_HandleTypeDef htim1; // Defined in main.c
extern "C" ADC_HandleTypeDef hadc3; // Defined in main.c
oscilloscope::Controller Factory::_oscilloscopeController;
oscilloscope::Gui Factory::_gui;
external::FrequencyGenerator Factory::_fgen;
oscilloscope::FreqGenController Factory::_fgenctrl;
ButtonsController Factory::_bc;
void Factory_initialize()
{
Factory::initialize();
}
void Factory_build()
{
Factory::build();
}
Factory::Factory()
{
}
// static
void Factory::initialize()
{
Trace::out("---------------------------------------------");
Trace::out("Initializing...");
// TODO: Uncomment code line below in order to call OscilloscopeController's initialize() method
// getOscilloscopeController().initialize(getGui(), adcValuesBuffer, ADC_VALUES_BUFFER_SIZE);
getFrequencyGenerator().initialize();
getFreqGenController().initialize(getGui());
#if (TOUCHGFX_BAREMETAL != 0)
getTouchGfxTask().initialize();
#endif // TOUCHGFX_BAREMETAL
}
// static
void Factory::build()
{
Trace::out("Building...");
HAL_ADC_Start_IT(&hadc3); // Start ADC conversion
HAL_TIM_OC_Start_IT(&htim1, TIM_CHANNEL_1); // Start TIM1 with trigger channel 1
getOscilloscopeController().start();
getGui().start();
getButtonsController().registerCallback(&getFreqGenController(),
(interface::ButtonsControllerCallbackProvider::CallbackMethod)&oscilloscope::FreqGenController::onButtonChanged);
getFreqGenController().start();
getButtonsController().start();
#if (TOUCHGFX_BAREMETAL != 0)
getTouchGfxTask().start();
#endif // TOUCHGFX_BAREMETAL
Trace::out("Running...");
}
oscilloscope::Controller & Factory::getOscilloscopeController()
{
return oscilloscope::Controller::getInstance();
}
//static
oscilloscope::Gui & Factory::getGui()
{
return _gui;
}
//static
ButtonsController& Factory::getButtonsController() {
return _bc;
}
//static
oscilloscope::FreqGenController& Factory::getFreqGenController() {
return _fgenctrl;
}
#if (TOUCHGFX_BAREMETAL != 0)
// static
TouchGfxTask & Factory::getTouchGfxTask()
{
static TouchGfxTask touchGfxTask;
return touchGfxTask;
}
#endif // TOUCHGFX_BAREMETAL
FrequencyGenerator& Factory::getFrequencyGenerator() {
return _fgen;
}

66
src/app/factory.h Normal file
View File

@ -0,0 +1,66 @@
#ifndef APP_FACTORY_H
#define APP_FACTORY_H
//
// What is seen only by the C++ compiler
//
#ifdef __cplusplus
#include "main.h"
#include "oscilloscopecontroller.h"
#include "gui.h"
#include "config/touchgfx-config.h"
#if (TOUCHGFX_BAREMETAL != 0)
#include "touchgfxtask.h"
#endif // TOUCHGFX_BAREMETAL
#include "mdw/ext-freqgen/frequencygenerator.h"
#include "app/freqgencontroller.h"
#include "board/buttonscontroller.h"
using external::FrequencyGenerator;
/**
* @brief Factory creating all objects/components and relations between them.
*/
class Factory
{
public:
Factory(); ///< Constructor
static void initialize(); ///< Initializes the factory
static void build(); ///< Creates components and initializes relations
#if (TOUCHGFX_BAREMETAL != 0)
static TouchGfxTask & getTouchGfxTask();
#endif // TOUCHGFX_BAREMETAL
static oscilloscope::Controller & getOscilloscopeController();
static oscilloscope::Gui & getGui();
static ButtonsController& getButtonsController();
static FrequencyGenerator& getFrequencyGenerator();
static oscilloscope::FreqGenController& getFreqGenController();
protected:
static oscilloscope::Controller _oscilloscopeController;
static oscilloscope::Gui _gui;
static external::FrequencyGenerator _fgen;
static oscilloscope::FreqGenController _fgenctrl;
static ButtonsController _bc;
};
#endif // __cplusplus
//
// What is seen by the C and C++ compiler
//
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
void Factory_initialize();
void Factory_build();
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // APP_FACTORY_H

View File

@ -0,0 +1,305 @@
#include "freqgencontroller.h"
#include "factory.h"
#include "trace/trace.h"
#include <assert.h>
#include "event/evButtonPressed.h"
#include "event/events.h"
namespace oscilloscope
{
FreqGenController* FreqGenController::_instance = nullptr;
FreqGenController::FreqGenController():
_pGui(nullptr)
{
assert (_instance==nullptr);
_instance = this;
if (EXTFREQGEN_START_FREQUENCY == HZ_50 ||
EXTFREQGEN_START_FREQUENCY == HZ_110 ||
EXTFREQGEN_START_FREQUENCY == HZ_240 ||
EXTFREQGEN_START_FREQUENCY == HZ_370 ||
EXTFREQGEN_START_FREQUENCY == HZ_500 ||
EXTFREQGEN_START_FREQUENCY == HZ_700 ||
EXTFREQGEN_START_FREQUENCY == HZ_1000 ||
EXTFREQGEN_START_FREQUENCY == HZ_5000 ||
EXTFREQGEN_START_FREQUENCY == HZ_10000)
{
_frequency = EXTFREQGEN_START_FREQUENCY;
}
else
{
_frequency = HZ_1000;
}
if (EXTFREQGEN_START_WAVEFORM == SINUS ||
EXTFREQGEN_START_WAVEFORM == TRIANGLE ||
EXTFREQGEN_START_WAVEFORM == SQUARE)
{
_mode = EXTFREQGEN_START_WAVEFORM;
}
else
{
_mode = SINUS;
}
change();
state = ST_INIT;
}
void FreqGenController::onButtonChanged(uint16_t buttonIndex, bool pressed) {
if (pressed)
{
GEN(evButtonPressed(buttonIndex));
}
}
FreqGenController* FreqGenController::getInstance() {
return _instance;
}
XFEventStatus FreqGenController::processEvent() {
XFEventStatus retVal = XFEventStatus::NotConsumed;
FCG_STATES oldState = state;
const XFEvent* ev = getCurrentEvent();
switch (state)
{
case ST_INIT:
if (ev->getEventType()==XFEvent::Initial)
{
state = ST_WAITBUTTON;
}
break;
case ST_WAITBUTTON:
if (ev->getEventType()==XFEvent::Event && ev->getId() == evButtonPressedId)
{
switch (((evButtonPressed*) ev)->buttonIndex())
{
case 1:
state = ST_CHANGEFREQDOWN;
break;
case 2:
state = ST_CHANGEFREQUP;
break;
case 3:
state = ST_CHANGEMODE;
break;
default:
break;
}
}
break;
case ST_CHANGEFREQUP:
case ST_CHANGEFREQDOWN:
case ST_CHANGEMODE:
if (ev->getEventType()==XFEvent::NullTransition )
{
state = ST_WAITBUTTON;
}
break;
default:
break;
}
if (oldState != state)
{
retVal = XFEventStatus::Consumed;
switch (state)
{
case ST_INIT:
break;
case ST_WAITBUTTON:
break;
case ST_CHANGEFREQUP:
frequencyUp();
change();
GEN(XFNullTransition());
break;
case ST_CHANGEFREQDOWN:
frequencyDown();
change();
GEN(XFNullTransition());
break;
case ST_CHANGEMODE:
shiftMode();
change();
GEN(XFNullTransition());
break;
default:
break;
}
}
return retVal;
}
void FreqGenController::start() {
startBehavior();
}
void FreqGenController::frequencyUp() {
//change the frequency up
switch (_frequency)
{
case HZ_50:
_frequency = HZ_110;
break;
case HZ_110:
_frequency = HZ_240;
break;
case HZ_240:
_frequency = HZ_370;
break;
case HZ_370:
_frequency = HZ_500;
break;
case HZ_500:
_frequency = HZ_700;
break;
case HZ_700:
_frequency = HZ_1000;
break;
case HZ_1000:
_frequency = HZ_5000;
break;
case HZ_5000:
_frequency = HZ_10000;
break;
case HZ_10000:
_frequency = HZ_50;
break;
default:
break;
}
Trace::out("Frequency up to %s", toString(_frequency).c_str());
// Update LCD display
gui().setFreqGenFrequencyText(toString(_frequency));
}
void FreqGenController::frequencyDown() {
//change the frequency down
switch (_frequency)
{
case HZ_50:
_frequency = HZ_10000;
break;
case HZ_110:
_frequency = HZ_50;
break;
case HZ_240:
_frequency = HZ_110;
break;
case HZ_370:
_frequency = HZ_240;
break;
case HZ_500:
_frequency = HZ_370;
break;
case HZ_700:
_frequency = HZ_500;
break;
case HZ_1000:
_frequency = HZ_700;
break;
case HZ_5000:
_frequency = HZ_1000;
break;
case HZ_10000:
_frequency = HZ_5000;
break;
default:
break;
}
Trace::out("Frequency down to %s", toString(_frequency).c_str());
// Update LCD display
gui().setFreqGenFrequencyText(toString(_frequency));
}
void FreqGenController::shiftMode() {
//change the waveform
switch (_mode)
{
case SINUS:
_mode = TRIANGLE;
if (EXTFREQGEN_NOTIFICATION_TRACE == 1)
{
Trace::out("Triangle\n");
gui().setFreqGenWaveformText("Tria -");
}
break;
case TRIANGLE :
_mode = SQUARE;
if (EXTFREQGEN_NOTIFICATION_TRACE == 1)
{
Trace::out("Square\n");
gui().setFreqGenWaveformText("Rect -");
}
break;
case SQUARE :
_mode = SINUS;
if (EXTFREQGEN_NOTIFICATION_TRACE == 1)
{
Trace::out("Sine\n");
gui().setFreqGenWaveformText("Sine -");
}
break;
default:
break;
}
}
void FreqGenController::initialize(oscilloscope::Gui & gui) {
_pGui = &gui;
Factory::getFrequencyGenerator().setFrequency(_frequency);
Factory::getFrequencyGenerator().setWaveForm(_mode);
}
void FreqGenController::change() {
Factory::getFrequencyGenerator().setWaveForm(_mode);
Factory::getFrequencyGenerator().setFrequency(_frequency);
}
//static
std::string FreqGenController::toString(const Frequency & frequency)
{
std::string freqString("n/a");
switch (frequency)
{
case HZ_50:
freqString = "50 Hz";
break;
case HZ_110:
freqString = "110 Hz";
break;
case HZ_240:
freqString = "240 Hz";
break;
case HZ_370:
freqString = "370 Hz";
break;
case HZ_500:
freqString = "500 Hz";
break;
case HZ_700:
freqString = "700 Hz";
break;
case HZ_1000:
freqString = "1 kHz";
break;
case HZ_5000:
freqString = "5 kHz";
break;
case HZ_10000:
freqString = "10 kHz";
break;
}
return freqString;
}
} /* namespace oscilloscope */

View File

@ -0,0 +1,81 @@
#ifndef APP_FREQGENCONTROLLER_H
#define APP_FREQGENCONTROLLER_H
#include <cassert>
#include <stdint.h>
#include "config/ext-freqgen-config.h"
#include "xf/behavior.h"
#include "board/interface/buttonscontrollercallbackprovider.h"
#include "ext-26pin/ext_26pin.h"
namespace oscilloscope
{
class Gui;
typedef enum _Frequency
{
HZ_50 = 50,
HZ_110 =110,
HZ_240 = 240,
HZ_370 = 370,
HZ_500 = 500,
HZ_700 = 700,
HZ_1000 = 1000,
HZ_5000 = 5000,
HZ_10000 = 10000
} Frequency;
/**
* @brief Frequency generator controller to drive external MinGen module with buttons.
*/
class FreqGenController : public interface::ButtonsControllerCallbackProvider,
public XFBehavior
{
//internal types
public:
typedef enum _FGC_STATES
{
ST_INIT,
ST_WAITBUTTON,
ST_CHANGEFREQUP,
ST_CHANGEFREQDOWN,
ST_CHANGEMODE
} FCG_STATES;
public:
FreqGenController();
static FreqGenController* getInstance();
//interface ButtonsControllerCallbackProvider
public:
void onButtonChanged(uint16_t buttonIndex, bool pressed);
//interface XFBehavior
public:
XFEventStatus processEvent();
void start();
void initialize(oscilloscope::Gui & gui);
protected:
inline oscilloscope::Gui & gui() const { assert(_pGui); return *_pGui; }
// internal methods
private:
void frequencyUp();
void frequencyDown();
void shiftMode();
void change();
static std::string toString(const Frequency & frequency);
private:
static FreqGenController* _instance;
oscilloscope::Gui * _pGui;
Frequency _frequency;
f_mode _mode;
FCG_STATES state;
};
} /* namespace oscilloscope */
#endif // APP_FREQGENCONTROLLER_H

105
src/app/gui.cpp Normal file
View File

@ -0,0 +1,105 @@
#include <cstring>
#include <cassert>
#include <cmath>
#include "trace/trace.h"
#include "gui.h"
#include "TouchGFX/gui/include/gui/mainview_screen/MainViewView.hpp"
#include "TouchGFX/gui/include/gui/model/Model.hpp"
#define TOUCH_THREAD_STACK_SIZE 2048
namespace oscilloscope {
Gui* Gui::_instance = nullptr;
Gui::Gui() :
_pGuiObserver(nullptr),
_redLedOn(false),
_xAxisPixelsPerField(roundf(460.0/8)) // Width of the chart graph divided by the number of divisions to show
{
if(_instance==nullptr){
_instance = this;
}
}
Gui* Gui::getInstance() {
return _instance;
}
bool Gui::registerObserver(interface::GuiObserver * pGuiObserver)
{
if (!_pGuiObserver and pGuiObserver)
{
_pGuiObserver = pGuiObserver;
return true;
}
return false;
}
void Gui::start()
{
}
void Gui::drawGraphPoints(uint16_t * values, uint16_t maxSize, float xScale /* = 1 */)
{
Model* model = Model::getInstance();
if(model!=nullptr){
model->setGraphPoints(values, maxSize, xScale);
}
}
bool Gui::isRedLedEnabled() const
{
return _redLedOn;
}
void Gui::setRedLed(bool enable)
{
_redLedOn = enable;
}
bool Gui::isOscilloscopePageEnabled() const
{
return true;
}
void Gui::setTimeDivisionText(std::string text)
{
Model* model = Model::getInstance();
if(model!=nullptr){
model->setDivTimLabel(text);
}
}
void Gui::setFreqGenWaveformText(std::string text)
{
Model* model = Model::getInstance();
if(model!=nullptr){
model->setModeSignal(text);
}
}
void Gui::setFreqGenFrequencyText(std::string text)
{
Model* model = Model::getInstance();
if(model!=nullptr){
model->setFreqSignal(text);
}
}
void Gui::onButtonTimePlusPressed()
{
_pGuiObserver->onButtonTimePlusPressed();
}
void Gui::onButtonTimeMinusPressed()
{
_pGuiObserver->onButtonTimeMinusPressed();
}
void Gui::onCheckBoxTriggerCheckState(bool checked)
{
_pGuiObserver->onCheckBoxTriggerCheckState(checked);
}
} // namespace oscilloscope

55
src/app/gui.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef APP_GUI_H
#define APP_GUI_H
#include "interface/guiobserver.h"
namespace oscilloscope {
/**
* @brief The GUI (Graphical User Interface) class is handling the oscilloscope view on the LCD.
*
* The GUI class uses a graphical library to show the oscilloscope view.
*
* Internally, all requests are forwarded to the TouchGFX generated classes.
*
* Note: Keep in mind that the internal graph element provides only a maximum of 460 data points!
*/
class Gui
{
public:
Gui();
static Gui* getInstance();
bool registerObserver(interface::GuiObserver * pGuiObserver);
void start();
void drawGraphPoints(uint16_t * values, uint16_t maxSize, float xScale = 1);
bool isRedLedEnabled() const;
void setRedLed(bool enable);
bool isOscilloscopePageEnabled() const;
void setTimeDivisionText(std::string text);
void setFreqGenWaveformText(std::string text);
void setFreqGenFrequencyText(std::string text);
inline float getXAxisPixelsPerField() const { return _xAxisPixelsPerField; }
void onButtonTimePlusPressed();
void onButtonTimeMinusPressed();
void onCheckBoxTriggerCheckState(bool checked);
protected:
inline interface::GuiObserver & observer() const { assert(_pGuiObserver); return *_pGuiObserver; }
protected:
static Gui* _instance;
interface::GuiObserver * _pGuiObserver; ///< GUI observer notified about GUI events.
bool _redLedOn;
float _xAxisPixelsPerField; ///< Number of pixels per field on the x-axis.
};
} // namespace oscilloscope
#endif // APP_GUI_H

View File

View File

@ -0,0 +1,22 @@
#ifndef INTERFACE_GUI_OBSERVER_H
#define INTERFACE_GUI_OBSERVER_H
namespace interface {
class GuiObserver
{
public:
virtual ~GuiObserver() {}
virtual void onButtonTimePlusPressed() = 0;
virtual void onButtonTimeMinusPressed() = 0;
virtual void onCheckBoxTriggerCheckState(bool checked) = 0;
virtual uint32_t getTDivCount() const = 0; // Returns the of x-axis grid count
protected:
GuiObserver() {}
};
} // namespace interface
#endif // INTERFACE_GUI_OBSERVER_H

View File

@ -0,0 +1,150 @@
#include <assert.h>
#include "trace/trace.h"
#include "xf/eventstatus.h"
#include "event/evcheckboxtrigger.h"
#include "main.h"
#include "gui.h"
#include "oscilloscopecontroller.h"
namespace oscilloscope {
Controller * Controller::_pInstance(nullptr);
const TDivOption Controller::_tdivOptions[] = {{TDIV_500us, "500 us / div"},
{TDIV_1ms, "1 ms / div"},
{TDIV_2ms, "2 ms / div"},
{TDIV_5ms, "5 ms / div"},
{TDIV_10ms, "10 ms / div"}};
Controller::Controller() :
_pGui(nullptr),
_adcValuesBuffer(nullptr),
_adcValuesBufferSize(0),
_tdivValue(TDIV_1ms)
{
assert(!_pInstance); // Only one instance of this class allowed!
_pInstance = this;
}
//static
Controller & Controller::getInstance()
{
assert(_pInstance); // Create first an instance!
return *_pInstance;
}
void Controller::initialize(Gui & gui, uint16_t * adcValuesBuffer, uint32_t adcValuesBufferSize)
{
_pGui = &gui;
_adcValuesBuffer = adcValuesBuffer;
_adcValuesBufferSize = adcValuesBufferSize;
gui.registerObserver(this); // Get notified about GUI events
}
void Controller::start()
{
startBehavior();
}
XFEventStatus Controller::processEvent()
{
if (!_adcValuesBuffer)
{
Trace::out("oscilloscope::Controller Error: Attribute '_adcValuesBuffer' not set!");
}
assert(_adcValuesBuffer);
assert(_adcValuesBufferSize > 0);
if (getCurrentEvent()->getEventType() == XFEvent::Initial)
{
scheduleTimeout(TIMEOUT_ID, TIMEOUT_INTERVAL);
doShowAnalogSignal();
}
if (getCurrentEvent()->getEventType() == XFEvent::Timeout &&
getCurrentTimeout()->getId() == TIMEOUT_ID)
{
scheduleTimeout(TIMEOUT_ID, TIMEOUT_INTERVAL);
doShowAnalogSignal();
}
if (getCurrentEvent()->getEventType() == XFEvent::Event &&
getCurrentEvent()->getId() == BTN_PLUS_ID)
{
doButtonTimePlusPressed();
}
if (getCurrentEvent()->getEventType() == XFEvent::Event &&
getCurrentEvent()->getId() == BTN_MINUS_ID)
{
doButtonTimeMinusPressed();
}
return XFEventStatus::Consumed;
}
void Controller::onButtonTimePlusPressed()
{
XFEvent* evButtonPlus =new XFEvent(XFEvent::Event, BTN_PLUS_ID, this);
pushEvent(evButtonPlus);
}
void Controller::onButtonTimeMinusPressed()
{
XFEvent* evButtonMinus =new XFEvent(XFEvent::Event, BTN_MINUS_ID, this);
pushEvent(evButtonMinus);
}
void Controller::onCheckBoxTriggerCheckState(bool checked)
{
Trace::out("Trigger checkbox: %s", (checked) ? "checked" : "unchecked");
GEN(evCheckBoxTrigger(checked, CHECK_BOX_TRIGGER_ID));
}
void Controller::doShowAnalogSignal()
{
// TODO: Call gui().drawGraphPoints() with the appropriate data.
}
void Controller::doButtonTimePlusPressed()
{
if (_tdivValue < (TDIV_MAX - 1))
{
_tdivValue = (TDivValue)(_tdivValue + 1);
gui().setTimeDivisionText(getText(_tdivValue));
}
}
void Controller::doButtonTimeMinusPressed()
{
if (_tdivValue > (TDIV_MIN + 1))
{
_tdivValue = (TDivValue)(_tdivValue - 1);
gui().setTimeDivisionText(getText(_tdivValue));
}
}
std::string Controller::getText(TDivValue tdivValue)
{
const uint32_t count = sizeof(_tdivOptions)/sizeof(_tdivOptions[0]);
for (uint32_t i = 0; i < count; i++)
{
if (_tdivOptions[i].tdivValue == tdivValue)
{
return _tdivOptions[i].text;
}
}
return "n/a";
}
} // namespace oscilloscope

View File

@ -0,0 +1,92 @@
#ifndef OSCILLOSCOPECONTROLLER_H
#define OSCILLOSCOPECONTROLLER_H
#include <assert.h>
#include <string>
#include "xf/behavior.h"
#include "interface/guiobserver.h"
namespace oscilloscope {
class Gui;
typedef enum
{
TDIV_MIN = 0,
TDIV_500us,
TDIV_1ms,
TDIV_2ms,
TDIV_5ms,
TDIV_10ms,
TDIV_MAX
} TDivValue;
typedef struct
{
TDivValue tdivValue;
std::string text;
} TDivOption;
/**
* @brief The Oscilloscope Controller
*
* Responsible to provide and update oscilloscope data. All input
* (touch screen, signal measurement data) comes to the controller
* and updates then the view(s) accordingly.
*/
class Controller : public XFBehavior,
public interface::GuiObserver
{
public:
Controller();
virtual ~Controller() {}
static Controller & getInstance();
void initialize(Gui & gui, uint16_t * adcValuesBuffer, uint32_t adcValuesBufferSize);
void start();
inline TDivValue getTDivValue() const { return _tdivValue; }
// XFReactive interface implementation
protected:
XFEventStatus processEvent() override;
// GuiObserver interface implementation
protected:
void onButtonTimePlusPressed() override;
void onButtonTimeMinusPressed() override;
void onCheckBoxTriggerCheckState(bool checked) override;
uint32_t getTDivCount() const override { return 8; };
protected:
void doShowAnalogSignal();
void doButtonTimePlusPressed();
void doButtonTimeMinusPressed();
inline Gui & gui() const { assert(_pGui); return *_pGui; }
std::string getText(TDivValue tdivValue);
protected:
static Controller * _pInstance;
Gui * _pGui;
uint16_t * _adcValuesBuffer;
uint32_t _adcValuesBufferSize;
const int TIMEOUT_ID = 0;
const int TIMEOUT_INTERVAL = 20;
enum {
BTN_PLUS_ID = 0,
BTN_MINUS_ID = 1,
CHECK_BOX_TRIGGER_ID = 2
} EventId;
TDivValue _tdivValue;
static const TDivOption _tdivOptions[];
};
} // namespace oscilloscope
#endif // OSCILLOSCOPECONTROLLER_H

50
src/app/touchgfxtask.cpp Normal file
View File

@ -0,0 +1,50 @@
#include "config/touchgfx-config.h"
#if (TOUCHGFX_BAREMETAL != 0)
#include "app_touchgfx.h"
#include "gui/common/FrontendHeap.hpp"
#include "touchgfxtask.h"
extern "C" void touchgfx_init();
extern "C" void touchgfx_taskEntry();
TouchGfxTask::TouchGfxTask():
interval_(20)
{
}
void TouchGfxTask::initialize()
{
touchgfx_init();
}
void TouchGfxTask::start()
{
startBehavior();
}
XFEventStatus TouchGfxTask::processEvent()
{
// Generate a timeout on startup. Want to call touchgfx_taskEntry()
// every x milliseconds
if (getCurrentEvent()->getEventType() == XFEvent::Initial)
{
scheduleTimeout(1, 20);
}
// Call touchgfx_taskEntry on timeout
if (getCurrentEvent()->getEventType() == XFEvent::Timeout and
getCurrentTimeout()->getId() == 1)
{
touchgfx_taskEntry();
scheduleTimeout(1, 20);
}
return XFEventStatus::Consumed;
}
#endif // TOUCHGFX_BAREMETAL

28
src/app/touchgfxtask.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef TOUCHGFXTASK_H
#define TOUCHGFXTASK_H
#include "config/touchgfx-config.h"
#if (TOUCHGFX_BAREMETAL != 0)
#include "xf/behavior.h"
/**
* @brief TouchGFX task used in IDF and/or bare-metal environments to drive LCD display.
*/
class TouchGfxTask : public XFBehavior
{
public:
TouchGfxTask();
void initialize();
void start();
protected:
XFEventStatus processEvent() override;
protected:
const int32_t interval_;
};
#endif // TOUCHGFX_BAREMETAL
#endif // TOUCHGFXTASK_H

View File

@ -0,0 +1,8 @@
#ifndef BOARD_BUTTONSCONTROLLER_CONFIG_H
#define BOARD_BUTTONSCONTROLLER_CONFIG_H
#define BUTTONSCONTROLLER_EXCLUDE_FROM_BUILD 0 /**< Default: 0; ButtonsController is needed in this project. */
#define BUTTONSCONTROLLER_DEBOUNCE_TIME 10 /**< Time in milliseconds to debounce buttons. */
#define TRACE_BUTTONSCONTROLLER_NOTIFICATIONS 0 /**< Enables trace notification messages. */
#endif // BOARD_BUTTONSCONTROLLER_CONFIG_H

View File

@ -0,0 +1,27 @@
/*
* ext-freqgen-config.h
*
* Created on: 24 Nov 2020
* Author: rim
*/
#ifndef EXT_FREQGEN_CONFIG_H_
#define EXT_FREQGEN_CONFIG_H_
#define EXTFREQGEN_NOTIFICATION_TRACE 1 // (0,1) default=1 trace out of waveform and frequency
#define EXTFREQGEN_START_FREQUENCY HZ_1000 // one of these:
// HZ_50 = 50,
// HZ_110 =110,
// HZ_240 = 240,
// HZ_370 = 370,
// HZ_500 = 500,
// HZ_700 = 700,
// HZ_1000 = 1000,
// HZ_5000 = 5000,
// HZ_10000 = 10000
#define EXTFREQGEN_START_WAVEFORM TRIANGLE // one of these:
// SINUS
// TRIANGLE
// SQUARE
#endif /* EXT_FREQGEN_CONFIG_H_ */

View File

@ -0,0 +1,10 @@
#ifndef TOUCHGFX_CONFIG_H
#define TOUCHGFX_CONFIG_H
/**
* Waring: Only one PORT define should be enabled at a time!
*/
#define TOUCHGFX_BAREMETAL 1
#define TOUCHGFX_FREERTOS 0
#endif // TOUCHGFX_CONFIG_H

18
src/config/trace-config.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef TRACE_CONFIG_H
#define TRACE_CONFIG_H
#include "stm32f7xx_hal.h" // "mcu/mcu.h" not working here!
extern "C" UART_HandleTypeDef huart1; // Defined in main.c
#define USE_PLATFORM_F7_DISCO_GCC_TRACE 1
#define TRACE_UART_NUMBER 0
#define TRACE_UART_HANDLE huart1
#define TRACE_UART_BAUD_RATE /* 115200, but given by STM32CubeMX tool configuration */
#define TRACE_UART_USE_TX_DMA false
#define TRACE_UART_CONSTRUCTOR_PARAMETERS TRACE_UART_NUMBER, &TRACE_UART_HANDLE, TRACE_UART_USE_TX_DMA
#define TRACE_ADD_CRLF_SEQU 0
#endif // TRACE_CONFIG_H

36
src/config/xf-config.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef XF_CONFIG_H
#define XF_CONFIG_H
#include "config/xf-port-config.h"
#if (PORT_IDF_STM32CUBE != 0)
#define USE_XF_DEFAULT_IMPLEMENTATION 1
#define USE_XF_DISPATCHER_DEFAULT_IMPLEMENTATION 1
#define USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION 1
#define USE_XF_RESOURCE_FACTORY_DEFAULT_IMPLEMENTATION 1
#define USE_XF_MUTEX_DEFAULT_IDF_IMPLEMENTATION 1
#define USE_XF_EVENT_QUEUE_DEFAULT_IDF_IMPLEMENTATION 1
#define USE_XF_PORT_IDF_STM32CUBE_PORT_FUNCTIONS_IMPLEMENTATION 1
#include "default-idf/eventqueue-default.h"
#ifdef __cplusplus
using XFEventQueue = XFEventQueueDefault;
#endif // __cplusplus
#endif // PORT_IDF_STM32CUBE
#if (PORT_STM32CUBE_CMSIS_FREERTOS != 0)
#define USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION 1
#define USE_XF_MUTEX_DEFAULT_CMSIS_OS_IMPLEMENTATION 1
#define USE_XF_THREAD_DEFAULT_CMSIS_OS_IMPLEMENTATION 1
#define USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_RESOURCE_FACTORY_IMPLEMENTATION 1
#define USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_TIMEOUTMANAGER_IMPLEMENTATION 1
#define USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_EVENT_QUEUE_IMPLEMENTATION 1
#define XFTHREAD_DEFAULT_STACK_SIZE 2048
#include "stm32cube-cmsis-freertos/eventqueue.h"
#ifdef __cplusplus
using XFEventQueue = XFEventQueuePort;
#endif // __cplusplus
#endif // PORT_STM32CUBE_CMSIS_FREERTOS
#endif // XF_CONFIG_H

View File

@ -0,0 +1,10 @@
#ifndef XF_PORT_CONFIG_H
#define XF_PORT_CONFIG_H
/**
* Waring: Only one PORT define should be enabled at a time!
*/
#define PORT_IDF_STM32CUBE 1
#define PORT_STM32CUBE_CMSIS_FREERTOS 0
#endif // XF_PORT_CONFIG_H

View File

@ -0,0 +1,8 @@
#include "events.h"
#include "evbuttonirq.h"
evButtonIrq::evButtonIrq() :
XFCustomEvent(evButtonIrqId)
{
setDeleteAfterConsume(false);
}

13
src/event/evbuttonirq.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef EVBUTTONIRQ_H
#define EVBUTTONIRQ_H
#include "xf/customevent.h"
#include "events.h"
class evButtonIrq : public XFCustomEvent
{
public:
evButtonIrq();
};
#endif // EVBUTTONIRQ_H

View File

@ -0,0 +1,12 @@
#include "events.h"
#include "evbuttonpressed.h"
evButtonPressed::evButtonPressed(int buttonIndex) :
XFCustomEvent(evButtonPressedId)
{
_buttonIndex = buttonIndex;
}
uint16_t evButtonPressed::buttonIndex() {
return _buttonIndex;
}

View File

@ -0,0 +1,18 @@
#ifndef EVBUTTONPRESSED_H
#define EVBUTTONPRESSED_H
#include "xf/customevent.h"
#include "events.h"
#include <stdint.h>
class evButtonPressed : public XFCustomEvent
{
public:
evButtonPressed(int buttonIndex);
uint16_t buttonIndex();
private:
uint16_t _buttonIndex;
};
#endif // EVBUTTONPRESSED_H

View File

@ -0,0 +1,8 @@
#include "events.h"
#include "event/evbuttonreleased.h"
evButtonReleased::evButtonReleased() :
XFCustomEvent(evButtonReleasedId)
{
}

View File

@ -0,0 +1,13 @@
#ifndef EVBUTTONRELEASED_H
#define EVBUTTONRELEASED_H
#include "xf/customevent.h"
#include "events.h"
class evButtonReleased : public XFCustomEvent
{
public:
evButtonReleased();
};
#endif // EVBUTTONRELEASED_H

View File

@ -0,0 +1,13 @@
#include "events.h"
#include "evcheckboxtrigger.h"
evCheckBoxTrigger::evCheckBoxTrigger(bool checked, int eventId) :
XFCustomEvent(eventId),
checked(checked)
{
}
bool evCheckBoxTrigger::isChecked() const {
return checked;
}

View File

@ -0,0 +1,17 @@
#ifndef EV_CHECK_BOX_TRIGGER_H
#define EV_CHECK_BOX_TRIGGER_H
#include "xf/customevent.h"
#include "events.h"
#include <stdint.h>
class evCheckBoxTrigger : public XFCustomEvent
{
public:
evCheckBoxTrigger(bool checked, int eventId);
bool isChecked() const;
private:
const bool checked;
};
#endif // EV_CHECK_BOX_TRIGGER_H

12
src/event/events.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef EVENTS_H
#define EVENTS_H
typedef enum
{
evButtonIrqId = 1,
evButtonPressedId,
evButtonReleasedId
} EventIds;
#endif // EVENTS_H

View File

@ -0,0 +1,53 @@
#include "frequencygenerator.h"
#include "trace/trace.h"
#include <assert.h>
namespace external
{
FrequencyGenerator* FrequencyGenerator::_instance = nullptr;
FrequencyGenerator::FrequencyGenerator()
{
assert (_instance==nullptr);
_instance = this;
_mode = SINUS;
_frequency = 500;
_initialized = false;
}
void FrequencyGenerator::initialize() {
if (Ext_FreqGen_Init() == 0)
{
_initialized = true;
}
}
void FrequencyGenerator::setWaveForm(f_mode mode) {
_mode = mode;
setGen();
}
void FrequencyGenerator::setFrequency(uint32_t frequency) {
_frequency = frequency;
setGen();
}
FrequencyGenerator* FrequencyGenerator::getInstance() {
return _instance;
}
void FrequencyGenerator::setGen() {
if (_initialized )
{
Ext_FreqGen_Set(_frequency, _mode);
}
else
{
trace_out("Frequency Generator not initialized\n");
}
}
} /* namespace external */

View File

@ -0,0 +1,34 @@
#ifndef EXT_FREQGEN_FREQUENCYGENERATOR_H
#define EXT_FREQGEN_FREQUENCYGENERATOR_H
#include "ext-26pin/ext_26pin.h"
namespace external
{
/**
* @brief FrequencyGenerator class providing access to external frequency generator "MiniGen" module.
*/
class FrequencyGenerator
{
public:
FrequencyGenerator();
void initialize();
void setWaveForm(f_mode mode);
void setFrequency(uint32_t frequency);
public: //singleton
static FrequencyGenerator* getInstance();
private: //methods
void setGen();
private:
uint32_t _frequency;
f_mode _mode;
bool _initialized;
static FrequencyGenerator* _instance;
};
} /* namespace external */
#endif // EXT_FREQGEN_FREQUENCYGENERATOR_H

View File

@ -0,0 +1,9 @@
# Changelog
## 0.1.1 - (2021-05-04)
- Added mutex lock methods to `Trace` class
## 0.1.0 - (2019-04-25)
- Moved project from SVN repository to GIT repository.
Took code from ButtonManager project.

7
src/mdw/trace/README.md Normal file
View File

@ -0,0 +1,7 @@
# trace
Trace package with interface definition.
The implementation of the Trace package is platform specific.
Every platform must provide its own implementation of the Trace package.

View File

@ -0,0 +1,19 @@
#ifndef TRACE_CONFIG_H
#define TRACE_CONFIG_H
/**
* Trace config example. Copy this file into the 'config' folder
* of your project and do your configuration there.
* Be sure to set up your include path such that the config file in
* your project is seen first.
*
* Do not perform changes in this file at this location. It may
* cause other projects to no more build!
*/
#warning "No project specific trace configuration found! Taking default configuration!"
#define USE_TRACE_EXAMPLE 0
#define TRACE_ADD_CRLF_SEQU 0
#endif // TRACE_CONFIG_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,39 @@
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<tagfile>
<compound kind="class">
<name>Trace</name>
<filename>class_trace.html</filename>
<member kind="function" static="yes">
<type>static void</type>
<name>initialize</name>
<anchorfile>class_trace.html</anchorfile>
<anchor>a6a42778d9401b9e90605475ecffeb8a2</anchor>
<arglist>()</arglist>
</member>
<member kind="function" static="yes">
<type>static void</type>
<name>out</name>
<anchorfile>class_trace.html</anchorfile>
<anchor>a602aec03cad6466d892034582794de33</anchor>
<arglist>(string str)</arglist>
</member>
<member kind="function" static="yes">
<type>static void</type>
<name>out</name>
<anchorfile>class_trace.html</anchorfile>
<anchor>a2c0dd29f5f94cfe01be01d414a2d18ba</anchor>
<arglist>(const char *format,...)</arglist>
</member>
</compound>
<compound kind="page">
<name>index</name>
<title>Trace</title>
<filename>index</filename>
<docanchor file="index" title="Introduction">sec_trace_intro</docanchor>
<docanchor file="index" title="Targets">sec_trace_targets</docanchor>
<docanchor file="index" title="Armebs4 Board">subsec_trace_armebs4</docanchor>
<docanchor file="index" title="Serial Configuration">subsubsec_trace_f7_disco_serial_config</docanchor>
<docanchor file="index" title="QT library">subsec_trace_qt</docanchor>
<docanchor file="index" title="Links to related Documentation">sec_trace_external_links</docanchor>
</compound>
</tagfile>

View File

@ -0,0 +1,15 @@
#include "config/trace-config.h"
#include "trace/trace.h"
#if (USE_TRACE_EXAMPLE != 0)
int main()
{
Trace::out("Hello World");
Trace::out("My name is %s and a am %d years old.", "Sarah Walker", 28);
return 0;
}
#endif // USE_TRACE_EXAMPLE

105
src/mdw/trace/trace.h Normal file
View File

@ -0,0 +1,105 @@
#ifndef TRACE_H
#define TRACE_H
#include <stddef.h>
#include <stdint.h>
#include <config/trace-config.h> // angle brackets important here!
#ifdef __cplusplus
extern "C" {
#endif
void trace_initialize();
void trace_out(const char * const format , ...);
#ifdef __cplusplus
} // extern "C"
#endif
#ifdef __cplusplus
#include <string>
using namespace std;
/** \mainpage Trace
*
* \section sec_trace_intro Introduction
*
* This small library is used to print debug information to an output.
* It serves as a general interface (LAL <b>L</b>ibrary <b>A</b>bstraction <b>L</b>ayer).
*
* The library consists of a single class named Trace. There is no need to make an instance
* of this class. Instead use the #Trace::out() methods to output the information needed.
*
* \section sec_trace_targets Targets
* \subsection subsec_trace_f7_disco F7-DISCO Board
* When working with the F7-DISCO board, Trace outputs the information using the USB-STLINK interface
* of the debugger USB cable to the Host. On Windows, the 'STLink Virtual COM' Port must be opened to
* see the trace output.
* During compilation time, the constant \a USE_PLATFORM_F7_DISCO_GCC_TRACE must be defined.
* \subsubsection subsubsec_trace_f7_disco_serial_config Serial Configuration
* - Baud: 115200
* - Data Bits: 8
* - Parity: none
* - Stop Bits: 1
* - Flow control: none
*
* \subsection subsec_trace_qt QT library
* When working with the QT library, Trace outputs the information to the debuggers output window.
* During compilation time, the constant \a TC_QTCREATOR must be defined.
*
* \section sec_trace_external_links Links to related Documentation
* \if DOC_WITH_TESTBENCH
* - <a href="../../../../../../test-bench/doxygen/output/html/index.html">Test Bench Documentation</a>
* \endif
* - <a href="../../../../../xf/doxygen/output/html/index.html">XF Documentation</a>
*/
/**
* \example trace-example01.cpp
*/
/**
* Prints debug information to a predefined output (output window).
*/
class Trace
{
public:
/**
* @brief Initializes trace functionality.
*
* Call this method prior to use trace functionality.
*/
static void initialize();
/**
* Outputs an STL string to the output window. The method will automatically add a new line, so
* the next string will be put automatically on the next line in the output window.
*
* \param str String to print to the output window.
*/
static void out(string str);
/**
* Outputs a sequence of data formatted as the fromat argument specifies.
* This method can be used the same way as the traditional printf.
* The method will automatically add a new line too.
*
* \param format The string that contains the text to be printed. It
* can optionally contain embedded format specifiers that
* are replaced by the values specified in subsequent additional
* arguments and formatted as requested.
*/
static void out(const char * format, ...);
public:
static void lock(); ///< Locks trace for other threads.
static void unlock(); ///< Unlocks trace so other threads can access trace.
protected:
Trace() {}
};
#endif // __cplusplus
#endif // TRACE_H

1
src/platform/f7-disco-gcc/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.DS_Store

View File

@ -0,0 +1,32 @@
# Changelog
## 0.2.7 - (2021-10-05)
- Added class comments
## 0.2.6 - (2021-08-25)
- Some minor bugfixes
## 0.2.5 - (2021-05-04)
- Moved XF definitions into .cpp file
## 0.2.4 - (2021-05-04)
- Added mutex to `Trace` and updated `TRACE_ADD_CRLF_SEQU` option
- Added `ext-26pin` package
## 0.2.3 - (2020-03-27)
- Added `main.h` file in different config files
## 0.2.2 - (2020-03-27)
- Fixed include bug
## 0.2.1 - (2019-04-25)
- Added BUTTONSCONTROLLER_EXCLUDE_FROM_BUILD define to exclude ButtonsController from build
## 0.2.0 - (2019-04-25)
- Added ButtonsController class (originally from ButtonManager project)
- Added C functions to trace package
## 0.1.0 - (2019-04-25)
- Moved project from SVN repository to GIT repository.
Took code from Realtime Oscilloscope project.

View File

@ -0,0 +1 @@
Project containing platform specific packages, based on the 32F746GDISCOVERY board

View File

@ -0,0 +1,185 @@
#include <string.h>
#include "mcu/mcu.h"
#include "trace/trace.h"
#include "buttonscontroller.h"
#include "main.h"
#if !defined(BUTTONSCONTROLLER_EXCLUDE_FROM_BUILD) || defined(BUTTONSCONTROLLER_EXCLUDE_FROM_BUILD) && (BUTTONSCONTROLLER_EXCLUDE_FROM_BUILD == 0)
#ifndef BUTTONSCONTROLLER_DEBOUNCE_TIME
#define BUTTONSCONTROLLER_DEBOUNCE_TIME 50 /* in milliseconds */
#endif
#include "event/evbuttonirq.h"
ButtonsController * ButtonsController::_pInstance(nullptr);
ButtonsController::ButtonsController()
{
assert(!_pInstance); // Singleton pattern. Only one instance allowed.
_pInstance = this; // Store 'this' to static pointer
_currentState = STATE_UNKOWN;
// Now the actual state of the buttons can be read
_currentButtonsValue = readButtonsValue();
_callbacksCount = 0;
}
ButtonsController::~ButtonsController()
{
}
void ButtonsController::onIrq()
{
static evButtonIrq evButtonIrq;
pushEvent(&evButtonIrq, true);
}
bool ButtonsController::registerCallback(interface::ButtonsControllerCallbackProvider * callbackProvider,
interface::ButtonsControllerCallbackProvider::CallbackMethod callbackMethod)
{
if (_callbacksCount < MAX_CALLBACKS)
{
for (uint8_t i = 0; i < MAX_CALLBACKS; i++)
{
if (_callbackProvider[i].first == nullptr)
{
_callbackProvider[i].first = callbackProvider;
_callbackProvider[i].second = callbackMethod;
_callbacksCount++;
break;
}
}
return true;
}
return false;
}
ButtonsController::tButtonsValue ButtonsController::readButtonsValue()
{
tButtonsValue value = 0;
// Button BTN0
value |= (HAL_GPIO_ReadPin(BUTTON0_GPIO_Port, BUTTON0_Pin) == GPIO_PIN_SET) ? 0x01 : 0x00;
// Button BTN1
value |= (HAL_GPIO_ReadPin(BUTTON1_GPIO_Port, BUTTON1_Pin) == GPIO_PIN_SET) ? 0x02 : 0x00;
// Button BTN2
value |= (HAL_GPIO_ReadPin(BUTTON2_GPIO_Port, BUTTON2_Pin) == GPIO_PIN_SET) ? 0x04 : 0x00;
// Button BTN3
value |= (HAL_GPIO_ReadPin(BUTTON3_GPIO_Port, BUTTON3_Pin) == GPIO_PIN_SET) ? 0x08 : 0x00;
return value;
}
XFEventStatus ButtonsController::processEvent()
{
eMainState newState = _currentState;
// Handle transition changes
switch (_currentState)
{
case STATE_UNKOWN:
// Decouple caller of startBehavior() with
// the transition from UNKNOWN to INITIAL.
if (getCurrentEvent()->getEventType() == XFEvent::Initial)
{
newState = STATE_INITIAL;
}
break;
case STATE_INITIAL:
if (getCurrentEvent()->getEventType() == XFEvent::NullTransition)
{
newState = STATE_CHECK_BUTTONS;
}
break;
case STATE_CHECK_BUTTONS:
if (getCurrentEvent()->getEventType() == XFEvent::Event &&
getCurrentEvent()->getId() == evButtonIrqId)
{
newState = STATE_DEBOUNCE;
}
break;
case STATE_DEBOUNCE:
if (getCurrentEvent()->getEventType() == XFEvent::Timeout &&
getCurrentTimeout()->getId() == Timeout_DEBOUNCE_id)
{
newState = STATE_CHECK_BUTTONS;
}
break;
}
// Handle transitions
if (_currentState != newState)
{
switch (newState)
{
case STATE_INITIAL:
GEN(XFNullTransition());
break;
case STATE_CHECK_BUTTONS:
doCheckButtons();
break;
case STATE_DEBOUNCE:
scheduleTimeout(Timeout_DEBOUNCE_id, BUTTONSCONTROLLER_DEBOUNCE_TIME);
break;
default:
break;
}
_currentState = newState;
}
return XFEventStatus::Consumed;
}
void ButtonsController::doCheckButtons()
{
tButtonsValue newButtonsValue = readButtonsValue();
uint8_t mask = 0x01;
if (_currentButtonsValue != newButtonsValue)
{
for (uint32_t i = 0; i < BUTTONS_COUNT; i++)
{
if ((_currentButtonsValue & mask) != (newButtonsValue & mask))
{
notifyButtonChange(i, !(newButtonsValue & mask));
}
mask <<= 0x01;
}
_currentButtonsValue = newButtonsValue;
}
}
void ButtonsController::notifyButtonChange(uint16_t buttonIndex, bool pressed)
{
#if (TRACE_BUTTONSCONTROLLER_NOTIFICATIONS != 0)
Trace::out("Button %d %s", buttonIndex, (pressed) ? "pressed" : "released");
#endif
for (uint8_t i = 0; i < MAX_CALLBACKS; i++)
{
if (_callbackProvider[i].first != nullptr)
{
(_callbackProvider[i].first->*_callbackProvider[i].second)(buttonIndex, pressed);
break;
}
else
{
break;
}
}
}
#endif // BUTTONSCONTROLLER_EXCLUDE_FROM_BUILD

View File

@ -0,0 +1,90 @@
#ifndef BOARD_BUTTONSCONTROLLER_H
#define BOARD_BUTTONSCONTROLLER_H
#include <stdint.h>
#include <assert.h>
#include <config/buttonscontroller-config.h>
#if !defined(BUTTONSCONTROLLER_EXCLUDE_FROM_BUILD) || defined(BUTTONSCONTROLLER_EXCLUDE_FROM_BUILD) && (BUTTONSCONTROLLER_EXCLUDE_FROM_BUILD == 0)
#include "interface/buttonirq.h"
#include "xf/behavior.h"
#include "interface/buttonscontrollercallbackcaller.h"
/**
* @brief ButtonsController handles/generates button pressed- and released pressed events.
*
* Use the registerCallback() method to get informed about button pressed- and released events.
*/
class ButtonsController : protected interface::ButtonIrq,
public interface::ButtonsControllerCallbackCaller,
protected XFBehavior
{
friend void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
public:
typedef uint8_t tButtonsValue; ///< Type used to store the state of buttons.
typedef std::pair<interface::ButtonsControllerCallbackProvider *,
interface::ButtonsControllerCallbackProvider::CallbackMethod> CallbackProvider;
ButtonsController();
virtual ~ButtonsController();
static ButtonsController & getInstance() { assert(_pInstance); return *_pInstance; } ///< Access to single instance
inline void start() { startBehavior(); }
tButtonsValue readButtonsValue(); ///< @brief Reads the actual state of the buttons.
protected:
void onIrq() override;
public:
bool registerCallback(interface::ButtonsControllerCallbackProvider * callbackProvider,
interface::ButtonsControllerCallbackProvider::CallbackMethod callbackMethod) override;
public:
XFEventStatus processEvent() override;
// Methods executed in state-machine
protected:
void doCheckButtons();
protected:
void notifyButtonChange(uint16_t buttonIndex, bool pressed);
protected:
/**
* Timeout identifier(s) for this state machine
*/
typedef enum
{
Timeout_DEBOUNCE_id = 1 ///< Timeout id for WAIT
} eTimeoutId;
/**
* Enumeration used to have a unique identifier for every
* state in the state machine.
*/
typedef enum
{
STATE_UNKOWN = 0, ///< Unknown state
STATE_INITIAL = 1, ///< Initial state
STATE_CHECK_BUTTONS = 2, ///< Check state of buttons
STATE_DEBOUNCE = 3 ///< Debounce state
} eMainState;
eMainState _currentState; ///< Attribute indicating currently active state.
public:
static constexpr const uint8_t BUTTONS_COUNT = 4; ///< Amount of buttons available.
protected:
static ButtonsController * _pInstance;
tButtonsValue _currentButtonsValue; ///< Last read buttons state.
static constexpr const uint8_t MAX_CALLBACKS = 8;
uint8_t _callbacksCount; ///< Stores how many callbacks are registered.
CallbackProvider _callbackProvider[MAX_CALLBACKS]; ///< Registered callback providers.
};
#endif // BUTTONSCONTROLLER_EXCLUDE_FROM_BUILD
#endif // BOARD_BUTTONSCONTROLLER_H

View File

@ -0,0 +1,27 @@
#ifndef INTERFACE_BUTTONIRQ_H
#define INTERFACE_BUTTONIRQ_H
namespace interface {
/**
* @brief Interface needed by the Interrupt Service Routine (ISR).
*
* This interface is needed by the ISR which reacts on button
* changes (level changes on GPIOs).
*
* Every time a level change on the buttons GPIOs is detected,
* the ISR calls this method.
*/
class ButtonIrq
{
protected:
virtual ~ButtonIrq() {}
virtual void onIrq() = 0; ///< @brief Called by the ISR.
protected:
ButtonIrq() {} ///< Not allowing to instantiate object of interface.
};
} // namespace interface
#endif // INTERFACE_BUTTONIRQ_H

View File

@ -0,0 +1,30 @@
#ifndef INTERFACE_BUTTONS_CONTROLLER_CALLBACK_CALLER_H
#define INTERFACE_BUTTONS_CONTROLLER_CALLBACK_CALLER_H
#include "buttonscontrollercallbackprovider.h"
namespace interface {
/**
* @brief Interface to be provided by the ButtonsController.
*
*/
class ButtonsControllerCallbackCaller
{
protected:
virtual ~ButtonsControllerCallbackCaller() {}
/**
* @brief Registers a callback method with its called pointer (callback provider).
*
* @return Returns true of the callback provider could be registered, otherwise false.
*/
virtual bool registerCallback(ButtonsControllerCallbackProvider * callbackProvider,
ButtonsControllerCallbackProvider::CallbackMethod callbackMethod) = 0;
protected:
ButtonsControllerCallbackCaller() {} ///< Not allowing to instantiate object of interface.
};
} // namespace interface
#endif // INTERFACE_BUTTONS_CONTROLLER_CALLBACK_CALLER_H

View File

@ -0,0 +1,31 @@
#ifndef INTERFACE_BUTTONS_CONTROLLER_CALLBACK_PROVIDER_H
#define INTERFACE_BUTTONS_CONTROLLER_CALLBACK_PROVIDER_H
#include <stdint.h>
namespace interface {
/**
* @brief Interface needed by the ButtonsController to notify a method callback provider.
*
*/
class ButtonsControllerCallbackProvider
{
public:
virtual ~ButtonsControllerCallbackProvider() {}
/**
* @brief The method prototype of the callback method to be provided by the class implementing the interface.
*
* Example implementation:
* // Called by ButtonsController to notify button pressed/released events.
* void onButtonChanged(uint16_t buttonIndex, bool pressed);
*
*/
typedef void (ButtonsControllerCallbackProvider::*CallbackMethod)(uint16_t buttonIndex, bool pressed);
protected:
ButtonsControllerCallbackProvider() {} ///< Not allowing to instantiate object of interface.
};
} // namespace interface
#endif // INTERFACE_BUTTONS_CONTROLLER_CALLBACK_H

View File

@ -0,0 +1,145 @@
#include "mcu/mcu.h"
#include "config/ledcontroller-config.h"
#if (LEDCONTROLLER_TRACE_ENABLE != 0)
#include "trace/trace.h"
#endif // LEDCONTROLLER_TRACE_ENABLE
#include "ledcontroller.h"
LedController * LedController::_pInstance = nullptr;
LedController::LedController()
{
assert(!_pInstance); // Only one instance of this class allowed!
_pInstance = this;
// Initialize the method array with the right methods.
_ledOperation[0] = &LedController::setLed0;
_ledOperation[1] = &LedController::setLed1;
_ledOperation[2] = &LedController::setLed2;
_ledOperation[3] = &LedController::setLed3;
/*
* F7-DISCO LED GPIOs (Extension Board):
* LED0: PA15
* LED1: PH6
* LED2: PA8
* LED3: PB4
*/
}
LedController::~LedController()
{
}
void LedController::setLed(uint8_t index, bool bOn)
{
setLeds(0x01 << index, bOn);
}
void LedController::setLeds(uint8_t ledMask, bool bOn)
{
uint8_t mask = 0x01;
for (uint8_t i = 0; i < ledCount(); i++, mask <<= 1)
{
if ((ledMask & mask) == mask && _ledOperation[i])
{
(this->*_ledOperation[i])(bOn);
}
}
}
void LedController::setLed0(bool bOn /* = true */)
{
if (bOn)
{
HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET);
}
#if (LEDCONTROLLER_TRACE_ENABLE != 0)
if (bOn)
{
// Not using "%s" here (bug in gcc c-library!)
Trace::out(" LED0: on");
}
else
{
Trace::out(" LED0: off");
}
#endif // LEDCONTROLLER_TRACE_ENABLE
}
void LedController::setLed1(bool bOn /* = true */)
{
if (bOn)
{
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
}
#if (LEDCONTROLLER_TRACE_ENABLE != 0)
if (bOn)
{
Trace::out(" LED1: on");
}
else
{
Trace::out(" LED1: off");
}
#endif // LEDCONTROLLER_TRACE_ENABLE
}
void LedController::setLed2(bool bOn /* = true */)
{
if (bOn)
{
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);
}
#if (LEDCONTROLLER_TRACE_ENABLE != 0)
if (bOn)
{
Trace::out(" LED2: on");
}
else
{
Trace::out(" LED2: off");
}
#endif // LEDCONTROLLER_TRACE_ENABLE
}
void LedController::setLed3(bool bOn /* = true */)
{
if (bOn)
{
HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET);
}
#if (LEDCONTROLLER_TRACE_ENABLE != 0)
if (bOn)
{
Trace::out(" LED3: on");
}
else
{
Trace::out(" LED3: off");
}
#endif // LEDCONTROLLER_TRACE_ENABLE
}

View File

@ -0,0 +1,40 @@
#ifndef BOARD_LEDCONTROLLER_H
#define BOARD_LEDCONTROLLER_H
#include <cassert>
#include <stdint.h>
/**
* @brief Used to command LEDs on the F7-DISCO extension board.
*/
class LedController
{
public:
#define LED_COUNT 4
public:
LedController();
virtual ~LedController();
inline static LedController & getInstance() { assert(_pInstance); return *_pInstance; }
void setLed(uint8_t index, bool bOn = true);
void setLeds(uint8_t ledMask, bool bOn = true);
inline uint8_t ledCount() const { return LED_COUNT; }
void setLed0(bool bOn = true);
void setLed1(bool bOn = true);
void setLed2(bool bOn = true);
void setLed3(bool bOn = true);
protected:
typedef void (LedController::*ledMethod)(bool bOn); ///< Function prototype to led operation. Used for fast access to LED operation.
protected:
static LedController * _pInstance;
ledMethod _ledOperation[LED_COUNT]; ///< Array of pointers to led functions.
};
#endif // BOARD_LEDCONTROLLER_H

View File

@ -0,0 +1,149 @@
#include <config/trace-config.h>
#if (USE_PLATFORM_F7_DISCO_GCC_TRACE != 0)
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "hal/uart.h"
#include "trace/trace.h" // Include the general trace.h file (common for many projects)
#include "xf/interface/resourcefactory.h"
#ifndef TRACE_ADD_CRLF_SEQU
#define TRACE_ADD_CRLF_SEQU 0
#endif
using interface::XFResourceFactory;
using interface::XFMutex;
static Uart traceUart(TRACE_UART_CONSTRUCTOR_PARAMETERS);
static char strTrace[255];
static int32_t checkStringEnding(char * str, uint32_t len);
static interface::XFMutex & traceMutex()
{
static XFMutex * mutex = XFResourceFactory::getInstance()->createMutex();
return *mutex;
}
static void traceMutexLock()
{
traceMutex().lock();
}
static void traceMutexUnlock()
{
traceMutex().unlock();
}
void trace_initialize()
{
Trace::initialize();
}
void trace_out(const char * const format , ...)
{
va_list args;
// Format string
va_start(args, format);
vsprintf(strTrace, format, args);
va_end(args);
checkStringEnding(strTrace, strlen(strTrace));
traceUart.write(strTrace);
}
//static
void Trace::initialize()
{
traceUart.initialize(TRACE_UART_BAUD_RATE);
}
static int32_t checkStringEnding(char * str, uint32_t len)
{
if (!len)
{
return 0;
}
if (str[len-1] != '\n')
{
#if (TRACE_ADD_CRLF_SEQU != 0)
// Add "\r\n" at the end of the string
str[len] = '\r';
str[len+1] = '\n';
str[len+2] = '\0';
#else
// Add "\n" at the end of the string
str[len] = '\n';
str[len+1] = '\0';
#endif // TRACE_ADD_CRLF_SEQU
}
#if (TRACE_ADD_CRLF_SEQU != 0)
// Check string finishing with "\r\n"
else if (str[len-1] == '\n')
{
// Check if second last char is an '\r'
if (len == 1 ||
(len >= 2 && str[len-2] != '\r'))
{
// Squeeze a '\r'
memmove(&str[len], &str[len-1], 2);
str[len-1] = '\r';
}
}
#endif // TRACE_ADD_CRLF_SEQU
return strlen(str);
}
void Trace::out(string str)
{
traceMutexLock();
if (str[str.length()-1] != '\n')
{
str += '\n';
}
#if defined(TRACE_ADD_CRLF_SEQU) && (TRACE_ADD_CRLF_SEQU != 0)
if(str[str.length()-2] != '\r'){
str.insert(str.length()-1, "\r");
}
#endif // TRACE_ADD_CRLF_SEQU
traceUart.write(str.data(), str.length());
traceMutexUnlock();
}
void Trace::out(const char * format, ...)
{
traceMutexLock();
va_list args;
// Format string
va_start(args, format);
vsprintf(strTrace, format, args);
va_end(args);
checkStringEnding(strTrace, strlen(strTrace));
traceUart.write(strTrace);
traceMutexUnlock();
}
//static
void Trace::lock()
{
traceMutexLock();
}
//static
void Trace::unlock()
{
traceMutexUnlock();
}
#endif // USE_PLATFORM_F7_DISCO_GCC_TRACE

View File

@ -0,0 +1,25 @@
#ifndef BOARD_BUTTONSCONTROLLER_CONFIG_H
#define BOARD_BUTTONSCONTROLLER_CONFIG_H
/**
* Do NOT edit this file!
*
* This is the default ButtonsController config file.
* You may provide your own implementation at project level.
*
* For this:
* - Copy/paste this file into a folder named 'config' in
* you projects include/source directory.
* - Add a compiler include path so that your file is seen
* before the default config file provided in the platform
* package.
* - Adjust the content of your config file to your needs.
* - Remove this comment in your config file.
*/
#include "main.h" // To get GPIO user labels (BUTTON0, BUTTON1, etc.)
#define BUTTONSCONTROLLER_EXCLUDE_FROM_BUILD 0 /* Default: 0 */
#define TRACE_BUTTONSCONTROLLER_NOTIFICATIONS 0
#endif // BOARD_BUTTONSCONTROLLER_CONFIG_H

View File

@ -0,0 +1,24 @@
#ifndef BOARD_LEDCONTROLLER_CONFIG_H
#define BOARD_LEDCONTROLLER_CONFIG_H
/**
* Do NOT edit this file!
*
* This is the default LedController config file.
* You may provide your own implementation at project level.
*
* For this:
* - Copy/paste this file into a folder named 'config' in
* you projects include/source directory.
* - Add a compiler include path so that your file is seen
* before the default config file provided in the platform
* package.
* - Adjust the content of your config file to your needs.
* - Remove this comment in your config file.
*/
#include "main.h" // To get GPIO user labels (LED0, LED1, etc.)
#define LEDCONTROLLER_TRACE_ENABLE 1
#endif // BOARD_LEDCONTROLLER_CONFIG_H

View File

@ -0,0 +1,34 @@
#ifndef TRACE_CONFIG_H
#define TRACE_CONFIG_H
/**
* Do NOT edit this file!
*
* This is the default TRACE config file.
* You may provide your own implementation at project level.
*
* For this:
* - Copy/paste this file into a folder named 'config' in
* you projects include/source directory.
* - Add a compiler include path so that your file is seen
* before the default config file provided in the platform
* package.
* - Adjust the content of your config file to your needs.
* - Remove this comment in your config file.
*/
#include "stm32f7xx_hal.h" // Do not use "mcu/mcu.h" here!
extern "C" UART_HandleTypeDef huart1; // Defined in main.c
#define USE_PLATFORM_F7_DISCO_GCC_TRACE 1
#define TRACE_UART_NUMBER 0
#define TRACE_UART_HANDLE huart1
#define TRACE_UART_BAUD_RATE /* 115200, but given by STM32CubeMX tool configuration */
#define TRACE_UART_USE_TX_DMA false
#define TRACE_UART_CONSTRUCTOR_PARAMETERS TRACE_UART_NUMBER, &TRACE_UART_HANDLE, TRACE_UART_USE_TX_DMA
#define TRACE_ADD_CRLF_SEQU 1
#endif // TRACE_CONFIG_H

View File

@ -0,0 +1,22 @@
#ifndef HAL_UART_CONFIG_H
#define HAL_UART_CONFIG_H
/**
* Do NOT edit this file!
*
* This is the default UART config file.
* You may provide your own implementation at project level.
*
* For this:
* - Copy/paste this file into a folder named 'config' in
* you projects include/source directory.
* - Add a compiler include path so that your file is seen
* before the default config file provided in the platform
* package.
* - Adjust the content of your config file to your needs.
* - Remove this comment in your config file.
*/
#include "mcu/mcu.h"
#endif // HAL_UART_CONFIG_H

View File

@ -0,0 +1,135 @@
#include "stm32f7xx_hal.h"
#include "ext_26pin.h"
extern SPI_HandleTypeDef hspi2;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
int32_t Ext_Debug_Init (void) {
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOF_CLK_ENABLE();
/* Configure GPIO pin: PF9 (GPIO_DEBUG) */
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
return 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
int32_t Ext_FreqGen_Init (void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOI_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(nCS_FREQ_GEN_GPIO_Port, nCS_FREQ_GEN_Pin, GPIO_PIN_SET);
/*Configure GPIO pin : nCS_FREQ_GEN_Pin */
GPIO_InitStruct.Pin = nCS_FREQ_GEN_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(nCS_FREQ_GEN_GPIO_Port, &GPIO_InitStruct);
__HAL_RCC_SPI2_CLK_ENABLE();
/**SPI2 GPIO Configuration
PI1 ------> SPI2_SCK
PB15 ------> SPI2_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* SPI2 parameter configuration*/
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 7;
hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
if (HAL_SPI_Init(&hspi2) != HAL_OK)
return -1;
Ext_FreqGen_Set(20,SQUARE);
Ext_FreqGen_Set(20,SQUARE);
return 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Ext_FreqGen_Set(uint32_t frequency,f_mode mode)
{
uint8_t data[2];
float calcDivisor;
uint32_t divisorInt;
calcDivisor = ((float)frequency * 268435456L) / 16000000L;
divisorInt = (uint32_t)calcDivisor - 1;
//----------------------------------------------------------------------------
// reset generator
data[0] = 0x21;
data[1] = 0x00;
HAL_GPIO_WritePin(nCS_FREQ_GEN_GPIO_Port, nCS_FREQ_GEN_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi2,data,2,10);
HAL_GPIO_WritePin(nCS_FREQ_GEN_GPIO_Port, nCS_FREQ_GEN_Pin, GPIO_PIN_SET);
//----------------------------------------------------------------------------
// set frequency LSB (14 bits)
data[0] = ((divisorInt & 0x3FFF) | 0x4000) >> 8;
data[1] = ((divisorInt & 0x3FFF) | 0x4000) >> 0;
HAL_GPIO_WritePin(nCS_FREQ_GEN_GPIO_Port, nCS_FREQ_GEN_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi2,data,2,10);
HAL_GPIO_WritePin(nCS_FREQ_GEN_GPIO_Port, nCS_FREQ_GEN_Pin, GPIO_PIN_SET);
//----------------------------------------------------------------------------
// set frequency MSB (14 bits)
data[0] = (((divisorInt>>14) & 0x3FFF) | 0x4000) >> 8;
data[1] = (((divisorInt>>14) & 0x3FFF) | 0x4000) >> 0;
HAL_GPIO_WritePin(nCS_FREQ_GEN_GPIO_Port, nCS_FREQ_GEN_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi2,data,2,10);
HAL_GPIO_WritePin(nCS_FREQ_GEN_GPIO_Port, nCS_FREQ_GEN_Pin, GPIO_PIN_SET);
//----------------------------------------------------------------------------
// set output signal
data[0] = 0x20; // unreset
switch(mode)
{
case SINUS:
data[1] = 0x00;
break;
case TRIANGLE:
data[1] = 0x02;
break;
case SQUARE:
data[1] = 0x28;
break;
}
HAL_GPIO_WritePin(nCS_FREQ_GEN_GPIO_Port, nCS_FREQ_GEN_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi2,data,2,10);
HAL_GPIO_WritePin(nCS_FREQ_GEN_GPIO_Port, nCS_FREQ_GEN_Pin, GPIO_PIN_SET);
}

View File

@ -0,0 +1,55 @@
/************************************************************************//**
* \file ext_keyboard.h
* \brief Function to use the extension keyboard
* \author pascal (dot) sartoretti (at) hevs (dot) ch
***************************************************************************/
#ifndef __EXT_26PIN_H
#define __EXT_26PIN_H
#include <stdint.h>
#include "stm32f7xx_hal.h"
#ifdef __cplusplus
extern "C" {
#endif
#define nCS_FREQ_GEN_Pin GPIO_PIN_6
#define nCS_FREQ_GEN_GPIO_Port GPIOF
typedef enum
{
SINUS,
TRIANGLE,
SQUARE
}f_mode;
/************************************************************************//**
* \brief Inits the Sparkfun frequency generator connected to SPI
* port on the 26 pin connector pins below:
* SCK = pin 3
* MOSI = pin 2
* nCS = pin 4
***************************************************************************/
int32_t Ext_FreqGen_Init (void);
/************************************************************************//**
* \brief Sets a frequency on Sparfun generator output
* \param frequency The frequency in hertz (below 20 Hz signal is bad)
* \param mode The signal mode (SINUS,TRIANGLE,SQUARE)
*
* The signal is centered at about 1.61 volt +/- 0.53 volts
***************************************************************************/
void Ext_FreqGen_Set(uint32_t frequency,f_mode mode);
/************************************************************************//**
* \brief Inits the debug pin PF9
***************************************************************************/
int32_t Ext_Debug_Init(void);
#ifdef __cplusplus
}
#endif
#endif /* __BOARD_LED_H */

View File

@ -0,0 +1,46 @@
#include "mcu/mcu.h"
#include "critical.h"
static volatile int inIsr_ = 0;
static volatile int enterCriticalNested_ = 0;
void critical_enter()
{
// Only disable interrupts when not calling from an ISR
if (!critical_inIsr())
{
if (!enterCriticalNested_)
{
// Turn off the priority configurable interrupts
__disable_irq();
}
enterCriticalNested_++;
}
}
void critical_exit()
{
// Only enable interrupts when not calling from an ISR
if (!critical_inIsr())
{
enterCriticalNested_--;
if (!enterCriticalNested_)
{
// Turn on the interrupts with configurable priority
__enable_irq();
}
}
}
int critical_inIsr()
{
// Variable must be put to TRUE in every ISR to indicate execution
// of an ISR and need to put back to FALSE before leaving ISR.
return inIsr_;
}
void critical_setInIsr(bool inIsr)
{
inIsr_ = inIsr;
}

View File

@ -0,0 +1,20 @@
#ifndef CRITICAL_H
#define CRITICAL_H
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
void critical_enter(); ///< Disables all interrupts.
void critical_exit(); ///< Enables all interrupts.
int critical_inIsr(); ///< Returns 1 if in an interrupt service routine (ISR), 0 otherwise.
void critical_setInIsr(bool inIsr); ///< Set or clear 'bInISR' variable.
#ifdef __cplusplus
}
#endif
#endif /* CRITICAL_H */

View File

@ -0,0 +1,93 @@
#include <string.h>
#include "mcu/mcu.h"
#include "uart.h"
#ifndef TRACE_UART_PREEMPTION_PRIO
#define TRACE_UART_PREEMPTION_PRIO 0
#endif
Uart * Uart::_sUart[Uart::UART_COUNT]; // Comment: Startup script should initialize pointers to zero (.bss section)
bool Uart::_sInitialized[Uart::UART_COUNT]; // Same for other arrays
Uart::Uart(const unsigned char uartNbr, UART_HandleTypeDef * uartHandle, bool bTxDMA /* = false */)
: _uartNbr(-1),
_pUartHandle(NULL),
_bTxDMA(bTxDMA)
{
assert(uartNbr < UART_COUNT);
if (uartNbr < UART_COUNT)
{
if (!_sUart[uartNbr])
{
// Register instance
_sUart[uartNbr] = this;
_uartNbr = uartNbr;
_pUartHandle = uartHandle;
}
else
{
assert(false); // Error: Instance for specified UART already exists.
}
}
}
Uart::~Uart()
{
}
bool Uart::initialize()
{
return true;
}
bool Uart::enable()
{
// Enable the USART
__HAL_UART_ENABLE(_pUartHandle);
return true;
}
bool Uart::disable()
{
// enable the USART
__HAL_UART_DISABLE(_pUartHandle);
return true;
}
void Uart::write(const char * str, unsigned int length /* = 0 */)
{
if (!length)
{
length = strlen(str);
}
if (!_bTxDMA)
{ // Transmit without DMA
// Send next character
HAL_UART_Transmit(_pUartHandle, (uint8_t *)str, length, 50);
}
else
{ // TX DMA enabled
writeUsingDMA((const uint8_t *)str, length);
}
}
void Uart::writeUsingDMA(const uint8_t * str, uint32_t length)
{
assert(length <= sizeof(_pTxDmaBuffer));
// Copy data to TX DMA buffer
::memcpy(_pTxDmaBuffer, str, length);
// Check that a Tx process is not already ongoing
// (should never happen, but who knows!)
while (_pUartHandle->gState != HAL_UART_STATE_READY)
{ continue; }
// Give data to TX DMA
HAL_UART_Transmit_DMA(_pUartHandle, _pTxDmaBuffer, length);
}

View File

@ -0,0 +1,66 @@
#ifndef HAL_UART_H
#define HAL_UART_H
#include "config/uart-config.h"
#include "cassert"
#ifndef UART_TX_DMA_BUFFER_SIZE
#define UART_TX_DMA_BUFFER_SIZE 128
#endif
/**
* @brief Provides general access to the microcontrollers UART peripheral.
*/
class Uart
{
friend class Factory;
public:
Uart(const unsigned char uartNbr, UART_HandleTypeDef * uartHandle, bool bTxDMA = false);
virtual ~Uart();
bool initialize();
bool enable();
bool disable();
void write(const char * str, unsigned int length = 0);
/**
* Static accessor to the instances of UART. Used by the factory.
* You should not use this method directly. Use the factory to
* access an UART instead.
*/
static inline Uart & uart(const unsigned char uartNbr)
{
assert(uartNbr < UART_COUNT);
return *_sUart[uartNbr];
}
/**
* Checks if UART is present and initialized
*/
static inline bool present(const unsigned char uartNbr)
{
return (uartNbr < UART_COUNT &&
_sInitialized[uartNbr]) ? true : false;
}
protected:
void writeUsingDMA(const uint8_t * str, uint32_t length);
protected:
static const unsigned char UART_COUNT = 3; ///< Constant indicating how many USART the MCU has
unsigned char _uartNbr; ///< Number of UART. Index starting at 0
UART_HandleTypeDef * _pUartHandle; ///< Reference to the USART structure
static Uart * _sUart[UART_COUNT]; ///< Array to check if USB device was created already
static bool _sInitialized[UART_COUNT]; ///< Indicates if the UART has been initialized
const bool _bTxDMA; ///< Use DMA for transmission
uint8_t _pTxDmaBuffer[UART_TX_DMA_BUFFER_SIZE]; ///< Buffer used by DMA for transmission
};
#endif // HAL_UART_H

View File

@ -0,0 +1,24 @@
#ifndef MCU_STM32F7_MCU_H
#define MCU_STM32F7_MCU_H
#include "stm32f7xx_hal.h"
#include "trace/trace.h"
/**
* @brief Static class representing the actual microcontroller (MCU).
*/
class Mcu
{
public:
inline static void msleep(uint32_t msecs) { HAL_Delay(msecs); }
inline static void wait() { for (uint32_t i = 1000000; i > 0; i--) continue; }
static void reset()
{
Trace::out("Mcu: Reset");
Trace::out("----------------------------------------------------");
wait();
NVIC_SystemReset();
}
};
#endif // MCU_STM32F7_MCU_H

10
src/xf/config/xf-config.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef XF_CONFIG_DEFAULT_H
#define XF_CONFIG_DEFAULT_H
#warning "You should provide your own 'xf-config.h' file in your project!"
// If you need some inspiration on what to provide in the 'xf-config.h' file
// please have a look onto the 'xf-config.h' files provided in the
// XF test-bench tests.
#endif // XF_CONFIG_DEFAULT_H

104
src/xf/core/behavior.cpp Normal file
View File

@ -0,0 +1,104 @@
#include <cassert>
#include "xf/xf.h"
#include "xf/interface/resourcefactory.h"
#include "xf/interface/dispatcher.h"
#include "xf/timeout.h"
#include "xf/initialevent.h"
#include "xf/behavior.h"
using interface::XFResourceFactory;
XFBehavior::XFBehavior(bool ownDispatcher /* = false */) :
pDispatcher_(nullptr),
hasOwnDispatcher_(ownDispatcher),
deleteOnTerminate_(false),
pCurrentEvent_(nullptr)
{
if (ownDispatcher)
{
pDispatcher_ = XFResourceFactory::getInstance()->createDispatcher();
}
else
{
pDispatcher_ = XFResourceFactory::getInstance()->getDefaultDispatcher();
}
// Force hasOwnDispatcher attribute to false in case actual
// dispatcher is the default dispatcher. This may happen
// if in an IDF an other dispatcher is requested, but
// only the default dispatcher is present.
if (pDispatcher_ == XFResourceFactory::getInstance()->getDefaultDispatcher())
{
hasOwnDispatcher_ = false;
}
}
XFBehavior::~XFBehavior()
{
}
void XFBehavior::startBehavior()
{
// Send initial event to state machine
GEN(XFInitialEvent());
// Start dispatcher if behavior has its own dispatcher
if (hasOwnDispatcher())
{
getDispatcher()->start();
}
}
void XFBehavior::pushEvent(XFEvent * pEvent, bool fromISR)
{
// Set owner
pEvent->setBehavior(this);
// Push to dispatchers event queue
getDispatcher()->pushEvent(pEvent, fromISR);
}
bool XFBehavior::deleteOnTerminate() const
{
return deleteOnTerminate_;
}
void XFBehavior::setDeleteOnTerminate(bool deleteBehaviour)
{
deleteOnTerminate_ = deleteBehaviour;
}
XFBehavior::TerminateBehavior XFBehavior::process(const XFEvent * pEvent)
{
XFEventStatus eventStatus;
setCurrentEvent(pEvent);
eventStatus = processEvent();
setCurrentEvent(nullptr);
return (eventStatus == XFEventStatus::Terminate);
}
interface::XFDispatcher * XFBehavior::getDispatcher()
{
return pDispatcher_;
}
void XFBehavior::setCurrentEvent(const XFEvent * pEvent)
{
pCurrentEvent_ = pEvent;
}
const XFEvent * XFBehavior::getCurrentEvent() const
{
return pCurrentEvent_;
}
const XFTimeout * XFBehavior::getCurrentTimeout()
{
assert(getCurrentEvent()->getEventType() == XFEvent::Timeout);
return static_cast<const XFTimeout *>(getCurrentEvent());
}

View File

@ -0,0 +1,8 @@
#include "xf/customevent.h"
XFCustomEvent::XFCustomEvent(int id, interface::XFReactive * pBehavior)
: XFEvent(XFEvent::Event, id, pBehavior),
bDeleteAfterConsume_(true)
{
}

View File

@ -0,0 +1,11 @@
#include "xf/initialevent.h"
XFInitialEvent::XFInitialEvent()
: XFEvent(XFEvent::Initial, 0, nullptr)
{
}
bool XFInitialEvent::deleteAfterConsume() const
{
return true;
}

View File

@ -0,0 +1,11 @@
#include "xf/nulltransition.h"
XFNullTransition::XFNullTransition(interface::XFReactive * pBehavior)
: XFEvent(XFEvent::NullTransition, 0, pBehavior)
{
}
bool XFNullTransition::deleteAfterConsume() const
{
return true;
}

19
src/xf/core/timeout.cpp Normal file
View File

@ -0,0 +1,19 @@
#include "xf/timeout.h"
XFTimeout::XFTimeout(int id, int interval, interface::XFReactive * pBehavior)
: XFEvent(XFEvent::Timeout, id, pBehavior),
interval_(interval),
relTicks_(interval)
{
}
bool XFTimeout::operator ==(const XFTimeout & timeout) const
{
// Check behavior and timeout id attributes, if there are equal
return (pBehavior_ == timeout.pBehavior_ && getId() == timeout.getId()) ? true : false;
}
bool XFTimeout::deleteAfterConsume() const
{
return true;
}

2515
src/xf/doxygen/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

1556
src/xf/doxygen/xf.tag Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,101 @@
#ifndef XF_BEHAVIOR_H
#define XF_BEHAVIOR_H
#include "xf/interface/reactive.h"
#include "xf/interface/dispatcher.h"
#include "xf/eventstatus.h"
#include "xf/initialevent.h"
#include "xf/nulltransition.h"
#include "xf/timeout.h"
class XFTimeout;
/** @ingroup xf_core
* @{
*/
/**
* @brief Base class for state machines, activities, process and data flows.
*
* Reactive class implementing a behavior. This class can be used to
* implement a state machine behavior or an activity behavior.
*
* Override the processEvent() operation in the inherited class to implement
* your state machine behavior. The processEvent() method gets automatically
* called every time an event or timeout arrives. The event (or timeout) can
* be accessed via the getCurrentEvent() method.
*/
class XFBehavior : public interface::XFReactive
{
public:
#define GEN(event) pushEvent(new event)
/**
* @brief Default constructor for the behavior.
*
* Per default the XFBehavior chooses the 'default dispatcher' for event processing. In
* case the ownDispatcher parameter is set to true, the XFBehavior creates internally
* a separate dispatcher.
*
* @param ownDispatcher Set to true to get dedicated dispatcher for this behavior.
*/
explicit XFBehavior(bool ownDispatcher = false);
~XFBehavior() override;
void startBehavior() override; ///< Starts the behavior, resp. the state machine.
void pushEvent(XFEvent * pEvent, bool fromISR=false) override;
bool deleteOnTerminate() const override;
void setDeleteOnTerminate(bool deleteBehaviour) override;
protected:
/**
* Executes the current event in its implemented behavior.
* This method needs to be overridden to implement the
* behavior (i.e. state machine) needed.
*/
virtual XFEventStatus processEvent() = 0;
const XFEvent * getCurrentEvent() const; ///< Returns the current event to be processed in processEvent().
interface::XFDispatcher * getDispatcher(); ///< Returns reference to #_pDispatcher.
inline bool hasOwnDispatcher() const { return hasOwnDispatcher_; } ///< True if behavior has its own dispatcher.
/** \brief Returns a reference to the actually processed timeout.
*
* Will work only if the current event is of type IXFEvent::Timeout.
*/
const XFTimeout * getCurrentTimeout();
inline void scheduleTimeout(int timeoutId, int interval) { getDispatcher()->scheduleTimeout(timeoutId, interval, this); } ///< @brief Schedules a timeout for this state machine.
inline void unscheduleTimeout(int timeoutId) { getDispatcher()->unscheduleTimeout(timeoutId, this); } ///< @brief Unschedules a timeout for this state machine.
private:
void setCurrentEvent(const XFEvent * pEvent); ///< Sets the current event to be processed in processEvent().
/**
* \brief Processes the given event.
*
* The dispatcher calls this method every time a new event
* or timeout arrives. The process method stores the actual
* event using the #_pCurrentEvent and then calls
* processEvent().
*
* In case you intend to call process() inside your state machine you
* are doing something wrong! Call GEN() or pushEvent() instead!
*
* \param pEvent The event to process.
*/
TerminateBehavior process(const XFEvent * pEvent) override;
protected:
interface::XFDispatcher * pDispatcher_; ///< Reference to dispatcher processing this behavior.
bool hasOwnDispatcher_; ///< True if behavior has its own dispatcher, False if the default dispatcher is used.
bool deleteOnTerminate_; ///< Indicates if the behavior can be deleted after reception of a 'terminate event'.
const XFEvent * pCurrentEvent_; ///< Reference to actually processed event.
};
/** @} */ // end of xf_core group
#endif // XF_BEHAVIOR_H

View File

@ -0,0 +1,51 @@
#ifndef XF_CUSTOMEVENT_H
#define XF_CUSTOMEVENT_H
#include "xf/xf.h"
#include "xf/event.h"
/** @ingroup xf_core
* @{
*/
/**
* @brief Base class for project related events.
*
* It is possible to create custom events by deriving new classes/events from
* this class.
* All custom events have `#Event` as event type. In the state machine the event
* can be uniquely identified with `getEventType() == Event` and the event id
* `getId()` given to the object at construction time.
*
* It is up to the devoper to handle the different event ids.
*/
class XFCustomEvent : public XFEvent
{
public:
/**
* Constructor for the class
*
* @param id Event identifier to identify the custom event (in the context of the behavior).
* @param pBehavior The behavior for which the event was constructed (will consume the event).
**/
XFCustomEvent(int id, interface::XFReactive * pBehavior = nullptr);
/**
* @brief Tells the XF if the event should be deleted after processing.
* @return True if the event should be deleted.
*/
bool deleteAfterConsume() const override { return bDeleteAfterConsume_; }
protected:
/**
* @brief Setter for #_bDeleteAfterConsume attribute.
* @param bDeleteAfterConsume Parameter to be assigned. Default: true.
*/
void setDeleteAfterConsume(bool bDeleteAfterConsume = true) { bDeleteAfterConsume_ = bDeleteAfterConsume; }
protected:
bool bDeleteAfterConsume_; ///< True if the XF should delete event after consumption/dispatching.
};
/** @} */ // end of xf_core group
#endif // XF_CUSTOMEVENT_H

74
src/xf/include/xf/event.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef XF_EVENT_H
#define XF_EVENT_H
namespace interface {
class XFReactive;
}
/** @ingroup xf_core
* @{
*/
/**
* @brief Base class for all types of events and timeouts.
*
* Requirements:
* - Needs to hold a property which allows to distinguish between different
* types of events (#_eventType).
* - Use an enumeration to define the type for the event type property (#XFEventType).
* - The event type property needs to be set at initialization time and cannot be
* changed afterwards.
*/
class XFEvent
{
public:
/**
* Defines the types of events
*/
typedef enum
{
Unknown = 0, ///< Unknown state (not initialized).
Initial = 1, ///< Initial pseudostate.
NullTransition = 2, ///< Event generated by the state machine to define a null transition.
Event = 3, ///< Custom event.
Timeout = 4, ///< Defines a timeout event.
Terminate = -1 ///< Defines a terminate state. Will end the state machine.
} XFEventType;
public :
/**
* Default class constructor
*/
XFEvent(XFEventType eventType, int id, interface::XFReactive * pBehavior) : eventType_(eventType), id_(id), pBehavior_(pBehavior) {}
virtual ~XFEvent() {} ///< Class destructor
/** \brief Returns the type of the event.
*
* Can be used to distinguish between an event or a timeout.
*/
inline XFEventType getEventType() const { return eventType_; }
/** \brief Returns pointer to behavioral class.
*
* Returns a pointer to the behavioral class processing the event (see #_pBehavior).
*/
inline interface::XFReactive * getBehavior() const { return pBehavior_; }
/** \brief Sets pointer to behavioral class (see #_pBehavior).
* Sets the behavior in which the event should be executed.
*/
inline void setBehavior(interface::XFReactive * pBehavior) { pBehavior_ = pBehavior; }
inline int getId() const { return id_; } ///< Returns #_id identifying the event in the behaviors context.
virtual bool deleteAfterConsume() const { return false; } ///< Tells the dispatcher if the event must be deleted or not.
protected:
const XFEventType eventType_; ///< Holds the type of the event.
int id_; ///< Event id
interface::XFReactive * pBehavior_; ///< Pointer to behavioral class processing the event.
};
/** @} */ // end of xf_core group
#endif // XF_EVENT_H

View File

@ -0,0 +1,75 @@
#ifndef XF_EVENTSTATUS_H
#define XF_EVENTSTATUS_H
/** @ingroup xf_core
* @{
*/
/**
* @brief Event status returned after event processing.
*
* The XFEventStatus is used after consumption of an event. It gives an
* information on how the event was consument and how the framework should
* react.
*/
class XFEventStatus
{
public:
/**
* Status values about the event processed.
*
* \see XFBehavior::process
*/
typedef enum
{
Unknown = 0,
Consumed = 0x0001, ///< Event consumed
NotConsumed = 0x0002, ///< Event not consumed
RegionFinished = 0x0004, ///< Composite state machine finished
Terminate = 0x0008 ///< Terminate state machine
} eEventStatus;
/**
* Constructor
*
* \param eventStatus Initial value of the event status.
*/
XFEventStatus(eEventStatus eventStatus = Unknown) : status_(eventStatus) {}
/**
* Checks if both variables contain the same event status.
*/
bool operator == (const XFEventStatus::eEventStatus & eventStatus) const
{
return (this->status_ == eventStatus);
}
/**
* @brief OR assignment.
*
* OR's the right event status with the left event status.
*/
void operator |= (const XFEventStatus & eventStatus)
{
unsigned int s1 = status_, s2 = eventStatus.status_;
s1 |= s2;
status_ = (eEventStatus)s1;
}
/**
* @brief Checks if the given event status (r-value) is present in the actual (l-value).
*/
bool is(const eEventStatus eventStatus) const
{
unsigned int mask = (unsigned int)eventStatus;
return ((((unsigned int)status_) & mask) == mask);
}
public:
eEventStatus status_; ///< Attribute containing the status of the event.
};
typedef XFEventStatus::eEventStatus eEventStatus;
/** @} */ // end of xf_core group
#endif // XF_EVENTSTATUS_H

View File

@ -0,0 +1,25 @@
#ifndef INITIALEVENT_H
#define INITIALEVENT_H
#include "xf/event.h"
/** @ingroup xf_core
* @{
*/
/**
* @brief Initial event to start a behavior.
*
* Represents for example the first transition executed
* in a state machine.
*/
class XFInitialEvent : public XFEvent
{
public:
XFInitialEvent();
bool deleteAfterConsume() const override;
};
/** @} */ // end of xf_core group
#endif // INITIALEVENT_H

View File

@ -0,0 +1,98 @@
#ifndef XF_INTERFACE_DISPATCHER_H
#define XF_INTERFACE_DISPATCHER_H
#include "xf/event.h"
class XF;
namespace interface {
class XFReactive;
class XFThread;
/**
* @brief Interface for the XF dispatcher providing the event processing loop.
*
* Depending on the implementation the dispatcher is executed by
* an internal thread. It is up to the port implementation how
* the class behaves.
*
* The dispatcher should at least provide a queue to hold events
* and an algorithm (typically in execute()) that dispatches the queued
* events to the associated behavior (eq. state machine, activity).
*
* There may exist multiple dispatchers. Each behavior needs to be
* bound to a dispatcher. One dispatcher may serve different behaviors.
*
* In an IDF the attribute _pThread is usually null.
*/
class XFDispatcher
{
friend class ::XF;
public:
virtual ~XFDispatcher() = default;
virtual bool isActive() const = 0; ///< True if dispatcher has its own thread.
virtual void start() = 0; ///< Starts the thread.
virtual void stop() = 0; ///< Stops the thread.
virtual void pushEvent(XFEvent * pEvent, bool fromISR=false) = 0; ///< Adds event to the events queue.
/**
* @brief Adds a new timeout to be handled.
*
* The Thread will forward the timeout information to the timeout
* manager which is responsible to handle all timeouts.
*/
virtual void scheduleTimeout(int timeoutId, int interval, interface::XFReactive * pReactive) = 0;
/**
* @brief Removes all timeouts corresponding the given parameters.
*/
virtual void unscheduleTimeout(int timeoutId, interface::XFReactive * pReactive) = 0;
protected:
/**
* Constructor is protected because only method createInstance()
* should be called to create Dispatcher instances
*/
XFDispatcher() = default;
/**
* @brief Returns pointer to thread executing the behavior.
*
* Within an IDF no threads are present and this method returns
* always null.
*/
virtual interface::XFThread * getThread() const { return nullptr; }
/**
* @brief Main loop of the dispatcher. Implements event loop processing.
*/
virtual int execute(const void * param = nullptr) = 0;
/**
* @brief Executes once the dispatcher.
*
* Usually, this method must not be called explicitly. The
* standard way to call the dispatcher is to call execute().
*
* This method can be called by the Thread (or main function) if it
* must perform concurrent (non-XF related) tasks in addition.
*
* When using this method start() must not be called.
*/
virtual int executeOnce() = 0;
/**
* @brief Dispatches the event to the corresponding behavioral part.
*
* For example the state machine which should process the event.
*
* \param pEvent The event to dispatch
*/
virtual void dispatchEvent(const XFEvent * pEvent) const = 0;
};
} // namespace interface
#endif // XF_INTERFACE_DISPATCHER_H

View File

@ -0,0 +1,27 @@
#ifndef XF_INTERFACE_EVENT_QUEUE_H
#define XF_INTERFACE_EVENT_QUEUE_H
class XFEvent;
namespace interface {
/**
* @brief Interface to be implemented by the event queue
*/
class XFEventQueue
{
public:
virtual ~XFEventQueue() = default;
virtual bool empty() const = 0; ///< Returns true if no event is in the queue.
virtual bool push(const XFEvent * pEvent, bool fromISR = false) = 0; ///< Pushes the given event onto the queue.
virtual const XFEvent * front() = 0; ///< Returns pointer to next event to pop.
virtual void pop() = 0; ///< Pops the next event from the queue.
virtual bool pend() = 0; ///< Wait for the next event to arrive. Returns true if an event is in the queue.
public:
XFEventQueue() = default;
};
} // namespace interface
#endif // XF_INTERFACE_EVENT_QUEUE_H

View File

@ -0,0 +1,56 @@
#ifndef XF_INTERFACE_MUTEX_H
#define XF_INTERFACE_MUTEX_H
#include <stdint.h>
namespace interface {
/**
* @brief Mutex interface needed by the XF to access a mutex.
*
* This interface only needs to be implemented for an XF port using
* an underlying OS. An IDF based XF does not need to provide a
* mutex.
*
* A non-recursive mutex needs to be implemented.
*/
class XFMutex
{
public:
virtual ~XFMutex() = default;
virtual void lock() = 0; ///< Blocks until the mutex becomes available.
virtual void unlock() = 0; ///< Releases the mutex so it can be taken by other threads.
/**
* @brief Tries to get the mutex.
*
* If timeout is 0 method will leave immediately and then the return parameter indicates it the
* mutex could be taken or not. Giving a negative value will block the thread until the mutex
* becomes available.
*/
virtual bool tryLock(int32_t timeout = 0) = 0;
/**
* @brief Creates and returns a new mutex instance.
* @return Pointer to the created mutex object.
*
* The implementation of this method needs to be provided by
* every XF port realizing a Mutex with this XFMutex interface.
* Best way is to implement this method in the mutex.cpp
* (or mutex-default.cpp) file of the XF port.
*
* Attention:
* Do not forget to create an object of the class realizing
* the interface and then return this object.
*
* You cannot instanciate an object of an abstract class!
*/
static XFMutex * create();
protected:
XFMutex() = default;
};
} // namespace interface
#endif // XF_INTERFACE_MUTEX_H

View File

@ -0,0 +1,53 @@
#ifndef XF_INTERFACE_REACTIVE_H
#define XF_INTERFACE_REACTIVE_H
#include <string>
#include "xf/event.h"
#include "xf/eventstatus.h"
class XFDispatcherDefault;
class XFDispatcherActiveDefault;
class XFDispatcherPort;
class XFDispatcherActivePort;
class XFDispatcher;
namespace interface {
/**
* @brief Interface to receive and process events.
*
* Interface that needs to be implemented by every class having a
* behavior. Interface methods are needed by the other parts of the XF.
*
* This interface is used by the dispatcher to process events.
*/
class XFReactive
{
// Only XFDispatchers should get access to the 'process' method
friend class ::XFDispatcherDefault;
friend class ::XFDispatcherActiveDefault;
friend class ::XFDispatcherPort;
friend class ::XFDispatcherActivePort;
friend class ::XFDispatcher;
public:
using TerminateBehavior = bool;
public:
virtual ~XFReactive() = default;
virtual void startBehavior() = 0; ///< Starts the behavior.
virtual void pushEvent(XFEvent * pEvent, bool fromISR = false) = 0; ///< Injects an event into the class.
virtual bool deleteOnTerminate() const = 0; ///< Tells XF to delete behavior when receiving terminate event.
virtual void setDeleteOnTerminate(bool deleteBehaviour) = 0; ///< Sets/Clears the 'delete on terminate' property.
protected:
virtual TerminateBehavior process(const XFEvent * pEvent) = 0; ///< Called by the dispatcher to process an event.
protected:
XFReactive() = default;
};
} // namespace interface
#endif // XF_INTERFACE_REACTIVE_H

View File

@ -0,0 +1,76 @@
#ifndef XF_INTERFACE_RESOURCE_FACTORY_H
#define XF_INTERFACE_RESOURCE_FACTORY_H
#include "xf/interface/dispatcher.h"
#include "xf/interface/thread.h"
#include "xf/interface/mutex.h"
namespace interface {
/**
* @brief Responsible to create and return XF resources.
*
* The XF resource factory provides instances of following classes
* - Dispatcher
* - Thread
* - Mutex
*
* The XFResourceFactory::getInstance() method needs to be implemented
* in the class realizing this interface.
*
*/
class XFResourceFactory
{
public:
static XFResourceFactory * getInstance(); ///< Returns a pointer to the unique instance of the XF resource factory.
/**
* @brief Returns the default dispatcher.
*
* In case a bahavior does not have a specific dispatcher the
* default dispatcher ist used.
*
* @return A pointer to the default dispatcher.
*/
virtual interface::XFDispatcher * getDefaultDispatcher() = 0;
/**
* @brief Creates a new dispatcher.
*
* Per default this method returns a new active dispatcher. In
* case there is no OS present (IDF) the default dispatcher may
* be returned.
*
* @return The new dispatcher
*/
virtual interface::XFDispatcher * createDispatcher() = 0;
/**
* @brief Creates a new Thread.
* @param pProvider The instance providing the entry method.
* @param entryMethod The method to by called by the new thread.
* @param threadName The name of the thread.
* @param stackSize The stack size of the thread.
* @return Pointer to new thread
*
* The method may return null in case there is no OS present.
*/
virtual interface::XFThread * createThread(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize = 0) = 0;
/**
* @brief Returns a new mutex.
* @return Pointer to new mutex.
*/
virtual interface::XFMutex * createMutex() = 0;
virtual ~XFResourceFactory() = default;
protected:
XFResourceFactory() = default;
};
} // namespace interface
#endif // XF_INTERFACE_RESOURCE_FACTORY_H

View File

@ -0,0 +1,60 @@
#ifndef XF_INTERFACE_THREAD_H
#define XF_INTERFACE_THREAD_H
#include "stdint.h"
typedef enum
{
XF_THREAD_PRIO_UNKNOWN = 0,
XF_THREAD_PRIO_LOW = 5,
XF_THREAD_PRIO_NORMAL = 10,
XF_THREAD_PRIO_HIGH = 15,
XF_THREAD_PRIO_MAX = 20
} XFThreadPriority;
namespace interface {
/**
* @brief Interface to be implemented by the class providing the thread entry method.
*/
class XFThreadEntryPointProvider
{
public:
virtual ~XFThreadEntryPointProvider() = default;
protected:
XFThreadEntryPointProvider() = default;
};
/**
* @brief Interface for a Thread.
*
* Thread interface representing the instance executing the behavior. In an OS less XF
* (hence an IDF), usually this class is not needed. In an XF interfacing an OS,
* multiple instances can be made, each interfacing the real OS thread.
*
* Thread instances can be created using the ResourceFactory instance.
*
* The XF assumes that the Thread is in suspend state after creation. Automatically
* starting the thread after creation may lead to unwanted behavior!
*/
class XFThread
{
public:
virtual ~XFThread() = default;
typedef void (XFThreadEntryPointProvider::*EntryMethodBody)(const void *); ///< Prototype of method to be executed by the thread.
virtual void start() = 0; ///< Starts the thread.
virtual void stop() = 0; ///< Requests the thread to stop execution.
virtual void setPriority(XFThreadPriority priority) = 0; ///< Set the thread priority.
virtual XFThreadPriority getPriority() const = 0; ///< Returns the thread priority.
virtual void delay(uint32_t milliseconds) = 0; ///< Causes the thread to sleep (for the given milliseconds).
protected:
XFThread() = default;
};
} // namespace interface
#endif // XF_INTERFACE_THREAD_H

View File

@ -0,0 +1,89 @@
#ifndef XF_INTERFACE_TIMEOUTMANAGER_H
#define XF_INTERFACE_TIMEOUTMANAGER_H
#include <stdint.h>
namespace interface {
class XFReactive;
}
class XFTimeout;
namespace interface {
/**
* @brief Interface for TimerManager classes (and some few 'tick' stuff already provided).
*
* The TimeoutManager is responsible to handle timeouts used
* in state machines. It decrements them accordingly and inject
* them back to the state machine when timeouted.
*
* <b>Requirements:</b>
* - Implements the Singleton pattern
* - Handle timeouts (hold, decrement, re-inject)
*/
class XFTimeoutManager
{
public:
virtual ~XFTimeoutManager() = default;
static XFTimeoutManager * getInstance(); ///< Returns a pointer to the single instance of TimeoutManager.
/**
* Sets the time interval in milliseconds in which the timeout manager
* should handle the timeouts.
*/
virtual void initialize(int32_t tickInterval)
{
tickInterval_ = tickInterval;
}
/**
* @brief Returns tick interval in milliseconds.
*/
virtual int32_t getTickInterval() const
{
return tickInterval_;
}
/**
* Starts the timeout manager.
*/
virtual void start() = 0;
/**
* Adds a timeout to the timeout manager.
*
* \param timeoutId The timeout id known by the reactive parameter. Is needed by the reactive part to uniquely identify the timeout.
* \param interval The time in milliseconds to wait until the timeout expires.
* \param pReactive The reactive instance where to inject the timeout when it timeouts.
*/
virtual void scheduleTimeout(int32_t timeoutId, int32_t interval, interface::XFReactive * pReactive) = 0;
/**
* Removes all timeouts corresponding the given parameters.
*/
virtual void unscheduleTimeout(int32_t timeoutId, interface::XFReactive * pReactive) = 0;
/** \brief Called periodically with a delay defined by TimeoutManager::_tickInterval.
*
* On each call to this method, TimeoutManager::_tickInterval will be removed from the
* timeouts.
* When a timeout expires it is pushed back to the dispatcher. To which
* dispatcher it must be given is known by the reactive instance to which the timeout
* belongs.
*/
virtual void tick() = 0;
protected:
XFTimeoutManager() :
tickInterval_(0)
{}
virtual void addTimeout(XFTimeout * pNewTimeout) = 0; ///< Adds the timeout to the list of timeouts.
protected:
int32_t tickInterval_; ///< Interval in milliseconds the TimeoutManager is decrementing the timeouts.
};
} // namespace interface
#endif // XF_INTERFACE_TIMEOUTMANAGER_H

View File

@ -0,0 +1,33 @@
#ifndef XF_NULLTRANSITION_H
#define XF_NULLTRANSITION_H
#include "xf.h"
#include "xf/event.h"
/** @ingroup xf_core
* @{
*/
/**
* @brief State machine transition without trigger.
*
* Represents a transition in a state machine having no trigger.
*
* In case one wants to directly transition from one state to
* an other (without a trigger) a null transition must be pushed.
*/
class XFNullTransition : public XFEvent
{
public:
/**
* Constructor
*
* \param pBehavior Behavior in which the null transition will be executed.
*/
XFNullTransition(interface::XFReactive * pBehavior = nullptr);
bool deleteAfterConsume() const override;
};
/** @} */ // end of xf_core group
#endif // XF_NULLTRANSITION_H

View File

@ -0,0 +1,59 @@
#ifndef XF_TIMEOUT_H
#define XF_TIMEOUT_H
#include "xf/event.h"
namespace interface {
class XFTimeoutManager;
}
/** @ingroup xf_core
* @{
*/
/**
* @brief Used by the TimeoutManager to create and handle a timeout.
*
* Timeouts are created automatically by the TimeoutManager when
* scheduling a timeout. After expiration they are queued to the event queue
* and afterwards dispatched to the corresonding behavior.
*
* A timeout can be identified by checking against #Timeout using
* the `getEventType()` method.
*
* XFTimeout is inheriting from XFEvent, so every timeout is
* also an event.
*/
class XFTimeout : public XFEvent
{
friend class interface::XFTimeoutManager;
public:
/**
* Constructor of the class.
* \param id The id given by the behavioral class to uniquely identifying the timeout
* \param interval The interval in milliseconds the timeout expires
* \param pBehavior Pointer to behavioral class to which the timeout belongs
*/
XFTimeout(int id, int interval, interface::XFReactive * pBehavior);
/**
* Operator checks if #_pBehavior and #_id are equal and returns
* true if so. All other attributes get no attention.
*/
bool operator ==(const XFTimeout & timeout) const;
bool deleteAfterConsume() const override; ///< Tells the dispatcher if the event must be deleted or not.
inline void setRelTicks(int relTicks) { relTicks_ = relTicks; } ///< Sets remaining ticks.
inline int getRelTicks() const { return relTicks_; } ///< Returns remaining ticks.
inline void substractFromRelTicks(int ticksToSubstract) { relTicks_ -= ticksToSubstract; } ///< Substracts `ticksToSubstract` from remaining ticks.
inline void addToRelTicks(int ticksToAdd) { relTicks_ += ticksToAdd; } ///< Adds `ticksToAdd` to remaining ticks.
protected:
int interval_; ///< Timeout interval
int relTicks_; ///< Used by the TimeoutManager to calculate remaining time. Can get negative!
};
/** @} */ // end of xf_core group
#endif // XF_TIMEOUT_H

View File

@ -0,0 +1,6 @@
/** @defgroup xf_core XF Core Classes
*
* XF core classes.
*
*/

171
src/xf/include/xf/xf.h Normal file
View File

@ -0,0 +1,171 @@
#ifndef XF_XF_H
#define XF_XF_H
#include "config/xf-config.h"
//
// What is seen only by the C++ compiler
//
#ifdef __cplusplus
#include "xf/interface/dispatcher.h"
/** \mainpage PTR Execution Framework Documentation
*
* \section sec_xf_intro Introduction
*
* This library implements an e<b>X</b>ecution <b>F</b>ramework (XF) to drive finite
* state machines. Using this framework, it is possible to drive multiple state machines
* in a concurrent manner (pseudo-parallel) without having an operating system.
*
* The XF defines an interface which gives the ability to reimplement parts of the XF to
* make changes to an other target/platform. It is also possible to let the XF run with an RTOS.
* This gives the possibility to run state machines in a OS like concurrent manner with
* threads provided by the underlying RTOS.
*
* \section sec_xf_comp XF Component Diagram
* The XF is split into two parts. One part is the XF core containing classes which
* never change across platforms. The other part is the XF port containing classes
* adjusted for a specific platform:
*
* \image html comp-xf.png "Component Class Diagram"
*
* The XF core together with a port forms a complete XF which can be integrated into
* a software project.
*
* \section sec_xf_cmd XF Class Diagram
*
* Following class diagram shows the basic relations between the most important classes
* in the PTR XF. It shall give you a basic understanding about the relations between
* these classes:
*
* \image html cmd-xf.png "XF Class Diagram"
*
* \section sec_xf_start Starting Point
*
* A good point to jump into the definitions of the classes is the `#XF` class. Other classes
* of interest are `interface::XFTimeoutManager`, `interface::XFDispatcher` and `interface::XFReactive`.
*
* \section sec_xf_external_links Links to related Documentation
* \if DOC_WITH_TESTBENCH
* - <a href="../../../../../test-bench/doxygen/output/html/index.html">Test Bench Documentation</a>
* \endif
* - <a href="../../../../../src/mdw/trace/doxygen/output/html/index.html">Trace Documentation</a>
*
* \if DOC_WITH_RELEASE_HISTORY
* \section sec_xf_releases XF Releases
* \subsection xf_v_4_0_1 XF Version: 4.0.1 (2021-08)
* - crc: Added parameter 'fromISR' for push() methods
* - sth: Added XF_isRunning() function to port-functions.h
* \subsection xf_v_4_0_0 XF Version: 4.0.0 (2021-05)
* - crc: Migration from IDE-STM / CubeMX to CubeIDE
* - crc: Changed CMSIS port from `CMSIS_RTOS_V1` to `CMSIS_RTOS_V2`
* \subsection xf_v_3_3_2 XF Version: 3.3.2 (2020-09)
* - sth: Added 'override' keywords to derived methods
* - sth: Removed attribute '_mainDispatcher' from XFResourceFactoryDefault
* \subsection xf_v_3_3_1 XF Version: 3.3.1 (2020-04)
* - sth: Added XF::isRunning() method
* \subsection xf_v_3_3_0 XF Version: 3.3.0 (2020-02)
* - sth: Introduced per platform default port implementations (port/default-qt, port/default-idf, etc.)
* - sth: Moved mutex and thread classes into the platform default port folders
* - sth: Added 'interface::XFReactive::deleteOnTerminate()' method
* \subsection xf_v_3_2_1 XF Version: 3.2.1 (2019-04)
* - sth: Made several bugfixes.
* \subsection xf_v_3_2 XF Version: 3.2 (2018-09)
* - sth: Updated XF interfaces.
* - sth: Added IDF_STM32CUBE, STM32CUBE_CMSIS_FREERTOS and ACTIVE_QT ports.
* - sth: Removed old ports IDF_STM32F4 and CMSIS_RTOS_FREERTOS.
* \subsection xf_v_3_1 XF Version: 3.1 (2017-11)
* - sth: Fixed bug in removeTimeouts() method of XFTimeoutManager. Thanks to Gregory Dumoulin.
* \subsection xf_v_3_0 XF Version: 3.0 (2017-10)
* - sth: The new XF is providing interfaces to support other OS's.
* - sth: Changed XF interfaces. Porting older applications to new XF need some adjustments.
* - sth: Added 'port' folder to allow extensions to other platforms.
* - sth: Added IDF_STM32F4, CMSIS_RTOS_FREERTOS and IDF_QT ports.
* \subsection xf_v_2_1 XF Version: 2.1 (2015-03-02)
* - sth: XFTimoutManager now returns timeouts with same value correctly.
* \subsection xf_v_2_0 XF Version: 2.0 (2014-04-28)
* - sth: Changed way how XFTimeoutManager handles timeouts which timeout at the same time.
* Now new timeouts get behind the timeouts with the same (timeout) time.
* \subsection xf_v_1_0 XF Version: 1.0 (2014-04-24)
* - sth: Renamed class XFEvent to XFCustomEvent
* - sth: Renamed IXFEvent to XFEvent (because it was never a real interface)
* \subsection xf_v_0_5 XF Version: 0.5 (2013-12-09)
* - sth: Now properly stopping and terminating MainThreadExec instance
* - sth: Added new literal to XFEventStatus to handle composite states
* \subsection xf_v_0_4 XF Version: 0.4 (2013-12-05)
* - sth: Added scheduleTimeout and unscheduleTimeout to XFBehavior class (helper operations)
* \subsection xf_v_0_3 XF Version: 0.3 (2013-09-19)
* - sth: Added handling for static events (IXFEvent::deleteAfterConsume())
* \subsection xf_v_0_2 XF Version: 0.2 (2011-08-14)
* - sth: Fixed bug in XFTimeoutManager::addTimeout method
* \subsection xf_v_0_1 XF Version: 0.1 (2010-11-26)
* - sth: First release
* \endif
*/
/** @ingroup xf_core
* @{
*/
/**
* @brief Static class grouping the basic methods for the XF together.
*/
class XF
{
public:
/**
* Initializes the e<b>X</b>ecution <b>F</b>ramework (XF). Call
* this method prior to initialize the other objects of the system.
*
* @param timeInterval The interval in milliseconds with which the TimeoutManager should run.
* @param argc Optional parameter to pass application argument number to XF.
* @param argv Optional parameter to pass application arguments to XF.
*/
static void initialize(int timeInterval = 10, int argc = 0, char * argv[] = nullptr);
/**
* Starts execution of the framework. This
* results in processing the events in main loop.
*
* This method is blocking.
*/
static int exec();
/**
* Executes once the dispatcher. To be called regularly in a while loop.
*
* This method is non-blocking.
*/
static int execOnce();
/**
* @brief Returns true in case the XF is initialized and running.
*/
static bool isRunning();
protected:
static bool isInitialized_; ///< Changes from false to true after calling method initialize(int). Used to handle multiple calls to init(int).
static bool isRunning_; ///< Tells if the XF is initialized and running.
};
#endif // __cplusplus
//
// What is seen by the C and C++ compiler
//
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
void XF_initialize(int timeInterval); ///< Initializes XF within C code
void XF_exec(); ///< Calls XF execution in C code (blocking call)
void XF_execOnce(); ///< Calls XF execution in C code (non-blocking call)
#ifdef __cplusplus
}
#endif // __cplusplus
/** @} */ // end of xf_core group
#endif // XF_XF_H

62
src/xf/port/README.md Normal file
View File

@ -0,0 +1,62 @@
# XF Ports
## Introduction
An XF (execution framework) consist of a view classes which some need to be adjusted
when used on another platform.
Following you will find a list of classes which may be adjusted/reimplemented when
changing to another platform/environment:
- `XF`
- `ResourceFactory`
- `TimeoutManager`
- `Dispatcher`
- `EventQueue`
- `Thread`
- `Mutex`
These classes are also named `port classes` because they can be ported to another
platform. All port classes can be found in the _port_ folder whereas every port is
located in a separate folder.
Every port may pick some default implementation classes from the _default_ folders
also located in the _port_ folder.
In case you are going to implement an OS-less XF (hence an IDF) usually, you do not
need to implement the classes `Thread` and `Mutex`.
## Default Port Classes
There are already some default port class implementations present. You can find
them in the `default` folder and may suit your needs for a first version
of your XF. These default port classes are platform independent and can be
used by any port implementation.
## Default Platform Classes
Some classes depent on external resources like for example an OS. These
classes are located in the _default-&lt;platform&gt;_ specific folders. Currently,
the following default platfroms are available:
| Platform | Folder | Description |
|--|--|--|
| CMSIS-OS | [default-cmsis-os](./default-cmsis-os) | CMSIS-OS abstraction layer |
| IDF | [default-idf](./default-idf) | Interrupt driven framework |
| QT | [default-qt](./default-qt) | Qt library |
## Port Folder Structure
In case you want to add support for another platform to the XF, you need to add a
subfolder to the _port_ folder and put the port class files in there. Best is to
take an already present port which is most similar to what you need, rename it and
start adaption of these files.
You may also mix-up you port with classes from the _default_, _default-&lt;platform&gt;_
folder and your custom folder (or even reference classes from other ports).
## Available Ports
Here is a list of currently available ports:
| Port Name | OS | Platform | Folder Name | Description |
|--|--|--|--|--|
| PORT_IDF_QT | Qt (IDF) | Qt library based implementation | idf-qt | XF support for OS X, Linux and Windows |
| PORT_IDF_STM32CUBE | Bare-Metal (IDF) | STM32CubeMX based port | idf-stm32cube | XF for ARM Cortex based microcontrollers from STMicroelectronics |
| PORT_STM32CUBE_CMSIS_FREERTOS | CMSIS OS (FreeRTOS) | Any platform supporting CMSIS OS | stm32cube-cmsis-freertos | FreeRTOS based port |
| PORT_ACTIVE_QT | Qt multi-thread | Qt library based implementation | active-qt | XF support for OS X, Linux and Windows (multi-thread) |

View File

@ -0,0 +1,38 @@
# XF Port - Active Qt
This port folder contains specific classes for the _Active Qt_
XF port.
# Classes used by the _Active Qt_ Port
| Class name | File location | Define to set |
|--|--|--|
| XFTimeoutManagerDefault | xf/port/default/timeoutmanager-default.cpp | USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION |
| XFDispatcherActiveDefault | xf/port/default/dispatcher-active.cpp | USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION |
| XF | xf/port/idf-qt/xf.cpp | USE_XF_PORT_IDF_QT_XF_IMPLEMENTATION |
| XFMutexPort | xf/port/default-qt/mutex-default.cpp | USE_XF_MUTEX_DEFAULT_QT_IMPLEMENTATION |
| XFThreadPort | xf/port/default-qt/thread-default.cpp | USE_XF_THREAD_DEFAULT_QT_IMPLEMENTATION |
| XFEventQueuePort | xf/port/idf-qt/eventqueue.cpp | USE_XF_PORT_IDF_QT_EVENT_QUEUE_IMPLEMENTATION |
| Port Functions | xf/port/idf-qt/port-functions.cpp | USE_XF_PORT_IDF_QT_PORT_FUNCTIONS_IMPLEMENTATION |
| XFResourceFactoryPort | xf/port/active-qt/resourcefactory.cpp | USE_XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_IMPLEMENTATION |
# Example _config/xf-config.h_ File
```c++
// Take all the port classes from the IDF_QT port expect...
#define USE_XF_PORT_IDF_QT_XF_IMPLEMENTATION 1
#define USE_XF_PORT_IDF_QT_EVENT_QUEUE_IMPLEMENTATION 1
#define USE_XF_PORT_IDF_QT_PORT_FUNCTIONS_IMPLEMENTATION 1
// ... the resource factory. Must provide active dispatchers!
#define USE_XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_IMPLEMENTATION 1
// ... mutexes and threads from the 'default-qt' port package
#define USE_XF_MUTEX_DEFAULT_QT_IMPLEMENTATION 1
#define USE_XF_THREAD_DEFAULT_QT_IMPLEMENTATION 1
// ... and the remaining classes from the default port package.
#define USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION 1
#define USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION 1
#include "idf-qt/eventqueue.h"
```

Binary file not shown.

View File

@ -0,0 +1,51 @@
#include <config/xf-config.h>
#if (USE_XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_IMPLEMENTATION != 0)
#include <QtGlobal>
#include "xf/interface/mutex.h"
#include "thread-default.h"
#include "default/dispatcher-active.h"
#include "resourcefactory.h"
using interface::XFMutex;
//static
interface::XFResourceFactory * interface::XFResourceFactory::getInstance()
{
return XFResourceFactoryPort::getInstance();
}
// static
interface::XFResourceFactory * XFResourceFactoryPort::getInstance()
{
static XFResourceFactoryPort theResourceFactory;
return &theResourceFactory;
}
interface::XFDispatcher * XFResourceFactoryPort::getDefaultDispatcher()
{
static XFDispatcherActiveDefault mainDispatcher;
return &mainDispatcher;
}
interface::XFDispatcher * XFResourceFactoryPort::createDispatcher()
{
// Create the new active dispatcher
return new XFDispatcherActiveDefault;
}
interface::XFThread * XFResourceFactoryPort::createThread(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize /* = 0 */)
{
return new XFThreadDefault(pProvider, entryMethod, threadName, stackSize);
}
interface::XFMutex * XFResourceFactoryPort::createMutex()
{
return XFMutex::create();
}
#endif // USE_XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_IMPLEMENTATION

View File

@ -0,0 +1,31 @@
#ifndef XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_H
#define XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_H
#include "config/xf-config.h"
#if (USE_XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_IMPLEMENTATION != 0)
#include "xf/interface/resourcefactory.h"
#include "xf/interface/dispatcher.h"
class XFResourceFactoryPort : public interface::XFResourceFactory
{
public:
~XFResourceFactoryPort() override {}
static interface::XFResourceFactory * getInstance();
interface::XFDispatcher * getDefaultDispatcher() override;
interface::XFDispatcher * createDispatcher() override;
interface::XFThread * createThread(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize = 0) override;
interface::XFMutex * createMutex() override;
protected:
XFResourceFactoryPort() {}
};
#endif // USE_XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_IMPLEMENTATION
#endif // XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_H

View File

@ -0,0 +1,8 @@
INCLUDEPATH += $$PWD/..
SOURCES += \
"$$PWD/resourcefactory.cpp"
HEADERS += \
"$$PWD/resourcefactory.h"

View File

@ -0,0 +1,24 @@
#
# This PRI file takes only the classes needed from the
# 'default' port.
#
INCLUDEPATH += $$PWD/..
# Path to default implementation of the XF port
DEFAULT_IMPL_PATH = $$PWD/../default
DEFAULT_IMPL_SOURCES += \
"$${DEFAULT_IMPL_PATH}/xf-default.cpp" \
"$${DEFAULT_IMPL_PATH}/timeoutmanager-default.cpp" \
"$${DEFAULT_IMPL_PATH}/dispatcher-active.cpp"
DEFAULT_IMPL_HEADERS += \
"$${DEFAULT_IMPL_PATH}/timeoutmanager-default.h" \
"$${DEFAULT_IMPL_PATH}/dispatcher-active.h"
SOURCES += \
$${DEFAULT_IMPL_SOURCES}$$
HEADERS += \
$${DEFAULT_IMPL_HEADERS}$$

View File

@ -0,0 +1,39 @@
# CMSIS-OS Platform Default Port
This folder provides a default implementation for CMSIS-OS platform
related XF classes. You can use these classes to construct a CMSIS-OS
based XF.
If these classes do not suit your needs, they can be reimplemented for
your platform. Create an additional folder in the 'port' folder and
implement there the classes you need for your platform.
# Available Default CMSIS-OS Port Classes
| Class name | File location | Define to set |
| -------------- | ------------------------------------- | --------------------------------------- |
| XFMutexDefault | xf/port/default-cmsis-os/mutex-default.cpp | USE_XF_MUTEX_DEFAULT_CMSIS_OS_IMPLEMENTATION |
| XFThreadDefault | xf/port/default-cmsis-os/thread-default.cpp | USE_XF_THREAD_DEFAULT_CMSIS_OS_IMPLEMENTATION |
If you need more information about the classes mentioned above, please
have a look into their header files and the doxygen comments in code.
# Example _config/xf-config.h_ File
Following you will find an example giving you a basic idea which define
to set in the application specific _config/xf-config.h_ file.
The _Stm32Cube CMSIS FreeRTOS_ port uses these classes:
```c++
// Defines to set to use the Stm32Cube CMSIS FreeRTOS port
#define USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION 1
#define USE_XF_MUTEX_DEFAULT_CMSIS_OS_IMPLEMENTATION 1
#define USE_XF_THREAD_DEFAULT_CMSIS_OS_IMPLEMENTATION 1
#define USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_RESOURCE_FACTORY_IMPLEMENTATION 1
#define USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_TIMEOUTMANAGER_IMPLEMENTATION 1
#define USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_EVENT_QUEUE_IMPLEMENTATION 1
#define USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_THREAD_IMPLEMENTATION 1
#include "stm32cube-cmsis-freertos/eventqueue.h"
```

Binary file not shown.

View File

@ -0,0 +1,51 @@
#include <cassert>
#include <cstring>
#include <config/xf-config.h>
#if (USE_XF_MUTEX_DEFAULT_CMSIS_OS_IMPLEMENTATION != 0)
#include "mutex-default.h"
/**
* @brief Implementation of interface::XFMutex::create method.
*/
interface::XFMutex * interface::XFMutex::create()
{
return new XFMutexDefault;
}
XFMutexDefault::XFMutexDefault() :
_mutexId(0)
{
memset(&_mutexDefinition,0,sizeof(_mutexDefinition));
_mutexId = osMutexNew(&_mutexDefinition);
assert(_mutexId);
}
XFMutexDefault::~XFMutexDefault()
{
}
void XFMutexDefault::lock()
{
assert(_mutexId);
osStatus status = osMutexWait(_mutexId, osWaitForever);
assert(status == osOK);
}
void XFMutexDefault::unlock()
{
osStatus status = osMutexRelease(_mutexId);
assert(status == osOK);
}
bool XFMutexDefault::tryLock(int32_t timeout /* = 0 */)
{
osStatus status = osMutexWait(_mutexId, timeout);
return (status == osOK) ? true : false;
}
#endif // USE_XF_MUTEX_DEFAULT_CMSIS_OS_IMPLEMENTATION

View File

@ -0,0 +1,38 @@
#ifndef XF_MUTEX_DEFAULT_CMSIS_OS_H
#define XF_MUTEX_DEFAULT_CMSIS_OS_H
#include <config/xf-config.h>
#if (USE_XF_MUTEX_DEFAULT_CMSIS_OS_IMPLEMENTATION != 0)
#include <stdint.h>
#include <cmsis_os.h>
#include "xf/interface/mutex.h"
/** @ingroup port_default_cmsis_os
* @{
*/
/**
* @brief Default CMSIS-OS imlementation XFMutex interface.
*
*/
class XFMutexDefault : public interface::XFMutex
{
public:
XFMutexDefault();
virtual ~XFMutexDefault();
virtual void lock();
virtual void unlock();
virtual bool tryLock(int32_t timeout = 0);
protected:
osMutexDef_t _mutexDefinition;
osMutexId _mutexId;
};
/** @} */ // end of port_default_cmsis_os group
#endif // USE_XF_MUTEX_DEFAULT_CMSIS_OS_IMPLEMENTATION
#endif // XF_MUTEX_DEFAULT_CMSIS_OS_H

View File

@ -0,0 +1,6 @@
/** @defgroup port_default_cmsis_os CMSIS-OS Platform Default Port Classes
*
* CMSIS-OS platform default port classes.
*
*/

View File

@ -0,0 +1,134 @@
#include <config/xf-config.h>
#if (USE_XF_THREAD_DEFAULT_CMSIS_OS_IMPLEMENTATION != 0)
#include <cassert>
#include <string.h>
#include "thread-default.h"
#if !defined(XFTHREAD_DEFAULT_STACK_SIZE)
# define XFTHREAD_DEFAULT_STACK_SIZE 512
#endif
//extern "C" const int uxTopUsedPriority;
//const int __attribute__((used)) uxTopUsedPriority = configMAX_PRIORITIES - 1;
/**
* Always keep threads after creation in suspended state.
* Threads must be explicitly started with start()!
*/
/// Attributes structure for thread.
/*
typedef struct {
const char *name; ///< name of the thread
uint32_t attr_bits; ///< attribute bits
void *cb_mem; ///< memory for control block
uint32_t cb_size; ///< size of provided memory for control block
void *stack_mem; ///< memory for stack
uint32_t stack_size; ///< size of stack
osPriority_t priority; ///< initial thread priority (default: osPriorityNormal)
TZ_ModuleId_t tz_module; ///< TrustZone module identifier
uint32_t reserved; ///< reserved (must be 0)
} osThreadAttr_t;*/
XFThreadDefault::XFThreadDefault(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize /* = 0 */)
{
uint32_t threadStackSize = stackSize;
_pEntryMethodProvider = pProvider;
_entryMethod = entryMethod;
strcpy(_threadName, threadName);
if (threadStackSize == 0)
{
threadStackSize = XFTHREAD_DEFAULT_STACK_SIZE;
}
::memset(&_threadAttr, 0, sizeof(_threadAttr));
_threadAttr.name = _threadName;
_threadAttr.priority = osPriorityNormal;
_threadAttr.stack_size = threadStackSize;
_threadFunc = &threadEntryPoint;
_threadId = osThreadNew(_threadFunc, this, &_threadAttr);
assert(_threadId); // Check if thread creation was successful
// Always keep threads after creation in suspended state.
// Must be explicitly started with start();
osThreadSuspend(_threadId);
}
//static
void XFThreadDefault::threadEntryPoint(void * param)
{
XFThreadDefault * pThis = (XFThreadDefault *)param;
(pThis->_pEntryMethodProvider->*pThis->_entryMethod)(param);
}
void XFThreadDefault::start()
{
assert(_threadId != 0); // Check if thread was created
osThreadResume(_threadId);
}
void XFThreadDefault::stop()
{
osThreadTerminate(_threadId);
}
void XFThreadDefault::setPriority(XFThreadPriority priority)
{
osPriority prio = osPriorityNormal;
switch (priority)
{
case XF_THREAD_PRIO_LOW:
prio = osPriorityLow;
break;
case XF_THREAD_PRIO_HIGH:
prio = osPriorityHigh;
break;
default:
break;
}
osThreadSetPriority(_threadId, prio);
}
XFThreadPriority XFThreadDefault::getPriority() const
{
const osPriority prio = osThreadGetPriority(_threadId);
XFThreadPriority priority = XF_THREAD_PRIO_UNKNOWN;
switch (prio)
{
case osPriorityLow:
priority = XF_THREAD_PRIO_LOW;
break;
case osPriorityNormal:
priority = XF_THREAD_PRIO_NORMAL;
break;
case osPriorityHigh:
priority = XF_THREAD_PRIO_HIGH;
break;
default:
break;
}
return priority;
}
void XFThreadDefault::delay(uint32_t milliseconds)
{
osDelay(milliseconds);
}
#endif // USE_XF_THREAD_DEFAULT_CMSIS_OS_IMPLEMENTATION

View File

@ -0,0 +1,45 @@
#ifndef XF_THREAD_DEFAULT_CMSIS_OS_H
#define XF_THREAD_DEFAULT_CMSIS_OS_H
#include <config/xf-config.h>
#if (USE_XF_THREAD_DEFAULT_CMSIS_OS_IMPLEMENTATION != 0)
#include <stdint.h>
#include <cmsis_os.h>
#include "xf/interface/thread.h"
class XFThreadDefault : public interface::XFThread
{
friend class XFResourceFactoryPort;
public:
virtual void start();
virtual void stop();
virtual void setPriority(XFThreadPriority priority);
virtual XFThreadPriority getPriority() const;
virtual void delay(uint32_t milliseconds);
protected:
XFThreadDefault(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize = 0);
static void threadEntryPoint(void * param);
protected:
interface::XFThreadEntryPointProvider * _pEntryMethodProvider;
interface::XFThread::EntryMethodBody _entryMethod;
osThreadAttr_t _threadAttr;
osThreadFunc_t _threadFunc;
char _threadName[32];
osThreadId _threadId;
};
#endif // USE_XF_THREAD_DEFAULT_CMSIS_OS_IMPLEMENTATION
#endif // XF_THREAD_DEFAULT_CMSIS_OS_H

View File

@ -0,0 +1,42 @@
# IDF (Interrupt Driven Framework) Platform Default Port
This folder provides a default implementation for IDF related XF classes.
You can use these classes to construct an IDF based XF.
If these classes do not suit your needs, they can be reimplemented for
your platform. Create an additional folder in the 'port' folder and
implement there the classes you need for your platform.
# Available Default IDF Port Classes
| Class name | File location | Define to set |
| -------------- | ------------------------------------- | --------------------------------------- |
| XFEventQueueDefault | xf/port/default-idf/eventqueue-default.cpp | USE_XF_EVENT_QUEUE_DEFAULT_IDF_IMPLEMENTATION |
| XFMutexDefault | xf/port/default-idf/mutex-default.cpp | USE_XF_MUTEX_DEFAULT_IDF_IMPLEMENTATION |
If you need more information about the classes mentioned above, please
have a look into their header files and the doxygen comments in code.
# Example _config/xf-config.h_ File
Following you will find an example giving you a basic idea which define
to set in the application specific _config/xf-config.h_ file.
The _IDF Stm32Cube_ port uses quite all default implementations:
```c++
// Defines to set to use the IDF Stm32Cube port
#define USE_XF_DEFAULT_IMPLEMENTATION 1
#define USE_XF_DISPATCHER_DEFAULT_IMPLEMENTATION 1
#define USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION 1
#define USE_XF_RESOURCE_FACTORY_DEFAULT_IMPLEMENTATION 1
#define USE_XF_MUTEX_DEFAULT_IDF_IMPLEMENTATION 1
#define USE_XF_EVENT_QUEUE_DEFAULT_IDF_IMPLEMENTATION 1
#define USE_XF_PORT_IDF_STM32CUBE_PORT_FUNCTIONS_IMPLEMENTATION 1
#include "default-idf/eventqueue-default.h"
#ifdef __cplusplus
using XFEventQueue = XFEventQueueDefault;
#endif // __cplusplus
```

Binary file not shown.

View File

@ -0,0 +1,61 @@
#include <config/xf-config.h>
#if (USE_XF_EVENT_QUEUE_DEFAULT_IDF_IMPLEMENTATION != 0)
#include <cassert>
#include "eventqueue-default.h"
XFEventQueueDefault::XFEventQueueDefault()
{
}
XFEventQueueDefault::~XFEventQueueDefault()
{
}
bool XFEventQueueDefault::empty() const
{
return _queue.empty();
}
bool XFEventQueueDefault::push(const XFEvent * pEvent, bool fromISR)
{
_mutex.lock();
{
_queue.push(pEvent);
}
_mutex.unlock();
return true;
}
const XFEvent * XFEventQueueDefault::front()
{
const XFEvent * event;
_mutex.lock();
{
event = _queue.front();
}
_mutex.unlock();
return event;
}
void XFEventQueueDefault::pop()
{
_mutex.lock();
{
_queue.pop();
}
_mutex.unlock();
}
bool XFEventQueueDefault::pend()
{
// Method cannot be used in an IDF! Waiting within
// this method would block the whole XF
return false;
}
#endif // USE_XF_EVENT_QUEUE_DEFAULT_IDF_IMPLEMENTATION

View File

@ -0,0 +1,51 @@
#ifndef XF_EVENT_QUEUE_DEFAULT_H
#define XF_EVENT_QUEUE_DEFAULT_H
#ifdef __cplusplus
#include "config/xf-config.h"
#if (USE_XF_EVENT_QUEUE_DEFAULT_IDF_IMPLEMENTATION != 0)
#include <stdint.h>
#include <queue>
#include "xf/interface/eventqueue.h"
#include "default-idf/mutex-default.h"
/** @ingroup port_default
* @{
*/
/**
* @brief Default implementation of the event queue using a `std::queue` as container.
*
* This class does not provide a blocking pend() method. This means that this class
* can be used in an IDF, but is not the right choice for a RTOS based XF.
*/
class XFEventQueueDefault : public interface::XFEventQueue
{
using Mutex = XFMutexDefault;
public:
XFEventQueueDefault();
virtual ~XFEventQueueDefault();
// XFEventQueue interface implementation
public:
virtual bool empty() const; ///< Returns true if no event is in the queue.
virtual bool push(const XFEvent * pEvent,
bool fromISR = false); ///< Pushes the given event onto the queue.
virtual const XFEvent * front(); ///< Returns pointer to next event to pop.
virtual void pop(); ///< Pops the next event from the queue.
///< Wait for the next event to arrive. Returns true if an event is in the queue.
virtual bool pend();
protected:
typedef std::queue<const XFEvent *> EventQueue; ///< Type of the event queue.
Mutex _mutex; ///< Mutex protecting access to _queue.
EventQueue _queue; ///< Internal queue holding the events.
};
/** @} */ // end of port_default group
#endif // USE_XF_EVENT_QUEUE_DEFAULT_IDF_IMPLEMENTATION
#endif // __cplusplus
#endif // XF_EVENT_QUEUE_DEFAULT_H

Some files were not shown because too many files have changed in this diff Show More