Base task system
This commit is contained in:
+14
-5
@@ -7,7 +7,11 @@
|
|||||||
|
|
||||||
#include "SSD1306.h"
|
#include "SSD1306.h"
|
||||||
|
|
||||||
Display::Display(/* args */) : Task("Display", 128, 250, 1), counter(0)
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Display
|
||||||
|
{
|
||||||
|
Display::Display(/* args */) : Task("Display", 1024, 250, 1, 1), counter(0), data(0), data_counter(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,16 +19,21 @@ Display::~Display()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::setup(void *args)
|
void Display::setup()
|
||||||
{
|
{
|
||||||
ssd1306 = std::make_unique<SSD1306>(15, 14, 128, 32, 100000, false, i2c1);
|
ssd1306 = std::make_unique<SSD1306>(PIN_SCL, PIN_SDA, WIDTH, HEIGHT, 100000, false, i2c1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::loop(void *args)
|
void Display::loop()
|
||||||
{
|
{
|
||||||
ssd1306->clear();
|
ssd1306->clear();
|
||||||
ssd1306->print(0, 0, (uint8_t *)std::to_string(counter).c_str());
|
ssd1306->print(0, 0, (uint8_t *)std::to_string(counter).c_str());
|
||||||
ssd1306->print(0, 12, &counter);
|
ssd1306->print(0, 9, &counter);
|
||||||
|
data_counter += receive(data);
|
||||||
|
ssd1306->print(0, 18, (uint8_t *)std::to_string(data).c_str());
|
||||||
|
ssd1306->print(40, 18, (uint8_t *)std::to_string(data_counter).c_str());
|
||||||
ssd1306->show();
|
ssd1306->show();
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
|
} // namespace Display
|
||||||
|
} // namespace es
|
||||||
|
|||||||
+21
-5
@@ -1,22 +1,38 @@
|
|||||||
#ifndef DISPLAY_DISPLAY_H_GUARD
|
#ifndef ES_DISPLAY_DISPLAY_H_GUARD
|
||||||
#define DISPLAY_DISPLAY_H_GUARD
|
#define ES_DISPLAY_DISPLAY_H_GUARD
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "Task.h"
|
#include "Task.h"
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Display
|
||||||
|
{
|
||||||
|
constexpr int PIN_SCL = 15;
|
||||||
|
constexpr int PIN_SDA = 14;
|
||||||
|
|
||||||
|
constexpr int WIDTH = 128;
|
||||||
|
constexpr int HEIGHT = 32;
|
||||||
|
constexpr int PAGES = HEIGHT / 8; // 4
|
||||||
|
|
||||||
class SSD1306;
|
class SSD1306;
|
||||||
class Display : public Task
|
class Display : public es::Task::Task<uint8_t>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
uint8_t framebuffer[WIDTH * PAGES]; // 128 * 4 = 512
|
||||||
std::unique_ptr<SSD1306> ssd1306;
|
std::unique_ptr<SSD1306> ssd1306;
|
||||||
uint8_t counter;
|
uint8_t counter;
|
||||||
void setup(void *args);
|
uint8_t data;
|
||||||
void loop(void *args);
|
uint8_t data_counter;
|
||||||
|
void setup() override;
|
||||||
|
void loop() override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Display(/* args */);
|
Display(/* args */);
|
||||||
~Display();
|
~Display();
|
||||||
};
|
};
|
||||||
|
} // namespace Display
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,11 +1,17 @@
|
|||||||
#ifndef DISPLAY_FONTS_DIALOGBOLD16_H_GUARD
|
#ifndef ES_DISPLAY_FONTS_DIALOGBOLD16_H_GUARD
|
||||||
#define DISPLAY_FONTS_DIALOGBOLD16_H_GUARD
|
#define ES_DISPLAY_FONTS_DIALOGBOLD16_H_GUARD
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "GFXglyph.h"
|
#include "GFXglyph.h"
|
||||||
#include "GFXfont.h"
|
#include "GFXfont.h"
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Display
|
||||||
|
{
|
||||||
|
namespace Fonts
|
||||||
|
{
|
||||||
const uint8_t Dialog_bold_16Bitmaps[] = {
|
const uint8_t Dialog_bold_16Bitmaps[] = {
|
||||||
|
|
||||||
// Bitmap Data:
|
// Bitmap Data:
|
||||||
@@ -270,5 +276,8 @@ const GFXglyph Dialog_bold_16Glyphs[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const GFXfont Dialog_bold_16 = {(uint8_t *)Dialog_bold_16Bitmaps, (GFXglyph *)Dialog_bold_16Glyphs, 0x20, 0x7E, 19};
|
const GFXfont Dialog_bold_16 = {(uint8_t *)Dialog_bold_16Bitmaps, (GFXglyph *)Dialog_bold_16Glyphs, 0x20, 0x7E, 19};
|
||||||
|
} // namespace Fonts
|
||||||
|
} // namespace Display
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,11 +1,17 @@
|
|||||||
#ifndef DISPLAY_FONTS_DIALOGBOLD6_H_GUARD
|
#ifndef ES_DISPLAY_FONTS_DIALOGBOLD6_H_GUARD
|
||||||
#define DISPLAY_FONTS_DIALOGBOLD6_H_GUARD
|
#define ES_DISPLAY_FONTS_DIALOGBOLD6_H_GUARD
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "GFXglyph.h"
|
#include "GFXglyph.h"
|
||||||
#include "GFXfont.h"
|
#include "GFXfont.h"
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Display
|
||||||
|
{
|
||||||
|
namespace Fonts
|
||||||
|
{
|
||||||
// Created by https://oleddisplay.squix.ch/ Consider a donation
|
// Created by https://oleddisplay.squix.ch/ Consider a donation
|
||||||
// In case of problems make sure that you are using the font file with the correct version!
|
// In case of problems make sure that you are using the font file with the correct version!
|
||||||
const uint8_t Dialog_bold_6Bitmaps[] = {
|
const uint8_t Dialog_bold_6Bitmaps[] = {
|
||||||
@@ -205,5 +211,8 @@ const GFXglyph Dialog_bold_6Glyphs[] = {
|
|||||||
};
|
};
|
||||||
const GFXfont Dialog_bold_6 = {
|
const GFXfont Dialog_bold_6 = {
|
||||||
(uint8_t *)Dialog_bold_6Bitmaps, (GFXglyph *)Dialog_bold_6Glyphs, 0x20, 0x7E, 8};
|
(uint8_t *)Dialog_bold_6Bitmaps, (GFXglyph *)Dialog_bold_6Glyphs, 0x20, 0x7E, 8};
|
||||||
|
} // namespace Fonts
|
||||||
|
} // namespace Display
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,11 +1,17 @@
|
|||||||
#ifndef DISPLAY_FONTS_DIALOGBOLD8_H_GUARD
|
#ifndef ES_DISPLAY_FONTS_DIALOGBOLD8_H_GUARD
|
||||||
#define DISPLAY_FONTS_DIALOGBOLD8_H_GUARD
|
#define ES_DISPLAY_FONTS_DIALOGBOLD8_H_GUARD
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "GFXglyph.h"
|
#include "GFXglyph.h"
|
||||||
#include "GFXfont.h"
|
#include "GFXfont.h"
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Display
|
||||||
|
{
|
||||||
|
namespace Fonts
|
||||||
|
{
|
||||||
// Created by https://oleddisplay.squix.ch/ Consider a donation
|
// Created by https://oleddisplay.squix.ch/ Consider a donation
|
||||||
// In case of problems make sure that you are using the font file with the correct version!
|
// In case of problems make sure that you are using the font file with the correct version!
|
||||||
const uint8_t Dialog_bold_8Bitmaps[] = {
|
const uint8_t Dialog_bold_8Bitmaps[] = {
|
||||||
@@ -205,5 +211,8 @@ const GFXglyph Dialog_bold_8Glyphs[] = {
|
|||||||
};
|
};
|
||||||
const GFXfont Dialog_bold_8 = {
|
const GFXfont Dialog_bold_8 = {
|
||||||
(uint8_t *)Dialog_bold_8Bitmaps, (GFXglyph *)Dialog_bold_8Glyphs, 0x20, 0x7E, 10};
|
(uint8_t *)Dialog_bold_8Bitmaps, (GFXglyph *)Dialog_bold_8Glyphs, 0x20, 0x7E, 10};
|
||||||
|
} // namespace Fonts
|
||||||
|
} // namespace Display
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,11 +1,17 @@
|
|||||||
#ifndef DISPLAY_FONTS_MONOSPACEDPLAIN10_H_GUARD
|
#ifndef ES_DISPLAY_FONTS_MONOSPACEDPLAIN10_H_GUARD
|
||||||
#define DISPLAY_FONTS_MONOSPACEDPLAIN10_H_GUARD
|
#define ES_DISPLAY_FONTS_MONOSPACEDPLAIN10_H_GUARD
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "GFXglyph.h"
|
#include "GFXglyph.h"
|
||||||
#include "GFXfont.h"
|
#include "GFXfont.h"
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Display
|
||||||
|
{
|
||||||
|
namespace Fonts
|
||||||
|
{
|
||||||
// Created by https://oleddisplay.squix.ch/ Consider a donation
|
// Created by https://oleddisplay.squix.ch/ Consider a donation
|
||||||
// In case of problems make sure that you are using the font file with the correct version!
|
// In case of problems make sure that you are using the font file with the correct version!
|
||||||
const uint8_t Monospaced_plain_10Bitmaps[] = {
|
const uint8_t Monospaced_plain_10Bitmaps[] = {
|
||||||
@@ -205,5 +211,8 @@ const GFXglyph Monospaced_plain_10Glyphs[] = {
|
|||||||
};
|
};
|
||||||
const GFXfont Monospaced_plain_10 = {
|
const GFXfont Monospaced_plain_10 = {
|
||||||
(uint8_t *)Monospaced_plain_10Bitmaps, (GFXglyph *)Monospaced_plain_10Glyphs, 0x20, 0x7E, 13};
|
(uint8_t *)Monospaced_plain_10Bitmaps, (GFXglyph *)Monospaced_plain_10Glyphs, 0x20, 0x7E, 13};
|
||||||
|
} // namespace Fonts
|
||||||
|
} // namespace Display
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
#ifndef DISPLAY_GFXFONT_H_GUARD
|
#ifndef ES_DISPLAY_GFXFONT_H_GUARD
|
||||||
#define DISPLAY_GFXFONT_H_GUARD
|
#define ES_DISPLAY_GFXFONT_H_GUARD
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "GFXglyph.h"
|
#include "GFXglyph.h"
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Display
|
||||||
|
{
|
||||||
struct GFXfont
|
struct GFXfont
|
||||||
{
|
{
|
||||||
uint8_t *bitmap; ///< Glyph bitmaps, concatenated
|
uint8_t *bitmap; ///< Glyph bitmaps, concatenated
|
||||||
@@ -13,5 +17,7 @@ struct GFXfont
|
|||||||
uint8_t last; ///< ASCII extents (last char)
|
uint8_t last; ///< ASCII extents (last char)
|
||||||
uint8_t yAdvance; ///< Newline distance (y axis)
|
uint8_t yAdvance; ///< Newline distance (y axis)
|
||||||
};
|
};
|
||||||
|
} // namespace Display
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
#ifndef DISPLAY_GFXGLYPH_H_GUARD
|
#ifndef ES_DISPLAY_GFXGLYPH_H_GUARD
|
||||||
#define DISPLAY_GFXGLYPH_H_GUARD
|
#define ES_DISPLAY_GFXGLYPH_H_GUARD
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Display
|
||||||
|
{
|
||||||
struct GFXglyph
|
struct GFXglyph
|
||||||
{
|
{
|
||||||
uint16_t bitmapOffset; ///< Pointer into GFXfont->bitmap
|
uint16_t bitmapOffset; ///< Pointer into GFXfont->bitmap
|
||||||
@@ -12,5 +16,7 @@ struct GFXglyph
|
|||||||
int8_t xOffset; ///< X dist from cursor pos to UL corner
|
int8_t xOffset; ///< X dist from cursor pos to UL corner
|
||||||
int8_t yOffset; ///< Y dist from cursor pos to UL corner
|
int8_t yOffset; ///< Y dist from cursor pos to UL corner
|
||||||
};
|
};
|
||||||
|
} // namespace Display
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+18
-1
@@ -5,6 +5,10 @@
|
|||||||
|
|
||||||
#include "MonospacedPlain10.h"
|
#include "MonospacedPlain10.h"
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Display
|
||||||
|
{
|
||||||
void SSD1306::write_cmd(uint8_t cmd)
|
void SSD1306::write_cmd(uint8_t cmd)
|
||||||
{
|
{
|
||||||
// 0x00 for write command
|
// 0x00 for write command
|
||||||
@@ -110,7 +114,7 @@ SSD1306::SSD1306(uint8_t scl,
|
|||||||
PAGES = height / 8, BUFFERSIZE = width * PAGES;
|
PAGES = height / 8, BUFFERSIZE = width * PAGES;
|
||||||
SSD1306_SDA_PIN = sda, SSD1306_SCL_PIN = scl;
|
SSD1306_SDA_PIN = sda, SSD1306_SCL_PIN = scl;
|
||||||
FREQUENCY = freq, I2C_PORT = i2c;
|
FREQUENCY = freq, I2C_PORT = i2c;
|
||||||
myFont = &Monospaced_plain_10;
|
myFont = &Fonts::Monospaced_plain_10;
|
||||||
reversed = rev;
|
reversed = rev;
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
@@ -348,3 +352,16 @@ void SSD1306::drawBitmap(uint8_t x,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SSD1306::setBuffer(const uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
if (!data || len != BUFFERSIZE)
|
||||||
|
return false;
|
||||||
|
for (size_t i = 0; i < BUFFERSIZE; i++)
|
||||||
|
{
|
||||||
|
BUFFER[i] = data[i];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace Display
|
||||||
|
} // namespace es
|
||||||
|
|||||||
+10
-3
@@ -1,5 +1,5 @@
|
|||||||
#ifndef DISPLAY_SSD1306_H_GUARD
|
#ifndef ES_DISPLAY_SSD1306_H_GUARD
|
||||||
#define DISPLAY_SSD1306_H_GUARD
|
#define ES_DISPLAY_SSD1306_H_GUARD
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
@@ -31,6 +31,10 @@
|
|||||||
#define SET_HOR_SCROLL 0x26
|
#define SET_HOR_SCROLL 0x26
|
||||||
#define SET_COM_OUT_DIR_REVERSE 0xC0
|
#define SET_COM_OUT_DIR_REVERSE 0xC0
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Display
|
||||||
|
{
|
||||||
class SSD1306
|
class SSD1306
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@@ -46,7 +50,7 @@ private:
|
|||||||
uint8_t PAGES;
|
uint8_t PAGES;
|
||||||
uint16_t BUFFERSIZE;
|
uint16_t BUFFERSIZE;
|
||||||
bool reversed;
|
bool reversed;
|
||||||
uint8_t BUFFER[1024];
|
uint8_t BUFFER[512];
|
||||||
const GFXfont *myFont;
|
const GFXfont *myFont;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
@@ -92,6 +96,9 @@ public:
|
|||||||
uint8_t width,
|
uint8_t width,
|
||||||
uint8_t height,
|
uint8_t height,
|
||||||
const uint8_t *image);
|
const uint8_t *image);
|
||||||
|
bool setBuffer(const uint8_t *data, size_t len);
|
||||||
};
|
};
|
||||||
|
} // namespace Display
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#include "Manager.h"
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace memory
|
||||||
|
{
|
||||||
|
Manager::Manager(size_t memSize)
|
||||||
|
: size(memSize)
|
||||||
|
{
|
||||||
|
memory = new uint8_t[size];
|
||||||
|
memset(memory, 0, size);
|
||||||
|
mutex = xSemaphoreCreateMutex();
|
||||||
|
if (!mutex)
|
||||||
|
{
|
||||||
|
printf("[Memory] Failed to create mutex\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Manager::~Manager()
|
||||||
|
{
|
||||||
|
if (mutex)
|
||||||
|
vSemaphoreDelete(mutex);
|
||||||
|
delete[] memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Manager::write(size_t offset, const uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
if (!data || offset + len > size)
|
||||||
|
return false;
|
||||||
|
if (xSemaphoreTake(mutex, portMAX_DELAY) == pdTRUE)
|
||||||
|
{
|
||||||
|
memcpy(&memory[offset], data, len);
|
||||||
|
xSemaphoreGive(mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Manager::read(size_t offset, uint8_t *buffer, size_t len)
|
||||||
|
{
|
||||||
|
if (!buffer || offset + len > size)
|
||||||
|
return false;
|
||||||
|
if (xSemaphoreTake(mutex, portMAX_DELAY) == pdTRUE)
|
||||||
|
{
|
||||||
|
memcpy(buffer, &memory[offset], len);
|
||||||
|
xSemaphoreGive(mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Manager::getSize() const
|
||||||
|
{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *Manager::getRawMemory()
|
||||||
|
{
|
||||||
|
return memory;
|
||||||
|
} // осторожно, напрямую
|
||||||
|
} // namespace memory
|
||||||
|
} // namespace es
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#ifndef ES_MEMORY_MANAGER_H_GUARD
|
||||||
|
#define ES_MEMORY_MANAGER_H_GUARD
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "semphr.h"
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace memory
|
||||||
|
{
|
||||||
|
class Manager
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint8_t *memory;
|
||||||
|
size_t size;
|
||||||
|
SemaphoreHandle_t mutex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Manager(size_t memSize);
|
||||||
|
~Manager();
|
||||||
|
|
||||||
|
bool write(size_t offset, const uint8_t *data, size_t len);
|
||||||
|
bool read(size_t offset, uint8_t *buffer, size_t len);
|
||||||
|
size_t getSize() const;
|
||||||
|
uint8_t *getRawMemory(); // осторожно, напрямую
|
||||||
|
};
|
||||||
|
} // namespace memory
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
|
#endif
|
||||||
+9
-3
@@ -2,7 +2,11 @@
|
|||||||
|
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
Led::Led(/* args */) : Task("Led", 32, 1000, 1)
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Other
|
||||||
|
{
|
||||||
|
Led::Led(/* args */) : Task("Led", 1024, 1000, 1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10,14 +14,16 @@ Led::~Led()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Led::setup(void *args)
|
void Led::setup()
|
||||||
{
|
{
|
||||||
gpio_init(PICO_DEFAULT_LED_PIN);
|
gpio_init(PICO_DEFAULT_LED_PIN);
|
||||||
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Led::loop(void *args)
|
void Led::loop()
|
||||||
{
|
{
|
||||||
led_state = !led_state;
|
led_state = !led_state;
|
||||||
gpio_put(PICO_DEFAULT_LED_PIN, led_state);
|
gpio_put(PICO_DEFAULT_LED_PIN, led_state);
|
||||||
}
|
}
|
||||||
|
} // namespace Other
|
||||||
|
} // namespace es
|
||||||
|
|||||||
+11
-5
@@ -1,18 +1,24 @@
|
|||||||
#ifndef OTHER_LED_H_GUARD
|
#ifndef ES_OTHER_LED_H_GUARD
|
||||||
#define OTHER_LED_H_GUARD
|
#define ES_OTHER_LED_H_GUARD
|
||||||
|
|
||||||
#include "Task.h"
|
#include "Task.h"
|
||||||
|
|
||||||
class Led : public Task
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Other
|
||||||
|
{
|
||||||
|
class Led : public es::Task::Task<uint8_t>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
bool led_state = false;
|
bool led_state = false;
|
||||||
void setup(void *args);
|
void setup() override;
|
||||||
void loop(void *args);
|
void loop() override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Led(/* args */);
|
Led(/* args */);
|
||||||
~Led();
|
~Led();
|
||||||
};
|
};
|
||||||
|
} // namespace Other
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -10,6 +10,11 @@
|
|||||||
|
|
||||||
#define millis() (to_ms_since_boot(get_absolute_time()))
|
#define millis() (to_ms_since_boot(get_absolute_time()))
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Sensors
|
||||||
|
{
|
||||||
|
|
||||||
const uint8_t DHT20_ADDRESS = 0x38;
|
const uint8_t DHT20_ADDRESS = 0x38;
|
||||||
|
|
||||||
DHT20::DHT20(int pin_sda, int pin_scl)
|
DHT20::DHT20(int pin_sda, int pin_scl)
|
||||||
@@ -305,3 +310,5 @@ bool DHT20::_resetRegister(uint8_t reg)
|
|||||||
sleep_ms(5);
|
sleep_ms(5);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
} // namespace Sensors
|
||||||
|
} // namespace es
|
||||||
|
|||||||
+8
-3
@@ -1,5 +1,5 @@
|
|||||||
#ifndef SENSORS_DHT20_H_GUARD
|
#ifndef ES_SENSORS_DHT20_H_GUARD
|
||||||
#define SENSORS_DHT20_H_GUARD
|
#define ES_SENSORS_DHT20_H_GUARD
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raspberry Pico / RP2040 library for DHT20 I2C temperature and humidity sensor
|
* Raspberry Pico / RP2040 library for DHT20 I2C temperature and humidity sensor
|
||||||
@@ -33,9 +33,12 @@
|
|||||||
#define DHT20_ERROR_READ_TIMEOUT -14
|
#define DHT20_ERROR_READ_TIMEOUT -14
|
||||||
#define DHT20_ERROR_LASTREAD -15
|
#define DHT20_ERROR_LASTREAD -15
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Sensors
|
||||||
|
{
|
||||||
class DHT20
|
class DHT20
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTOR
|
// CONSTRUCTOR
|
||||||
// fixed address 0x38
|
// fixed address 0x38
|
||||||
@@ -105,5 +108,7 @@ private:
|
|||||||
// use with care
|
// use with care
|
||||||
bool _resetRegister(uint8_t reg);
|
bool _resetRegister(uint8_t reg);
|
||||||
};
|
};
|
||||||
|
} // namespace Sensors
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#ifndef SERIAL_BUFFER_H_GUARD
|
|
||||||
#define SERIAL_BUFFER_H_GUARD
|
|
||||||
|
|
||||||
class Buffer
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
uint8_t public : Buffer(/* args */);
|
|
||||||
~Buffer();
|
|
||||||
};
|
|
||||||
|
|
||||||
Buffer::Buffer(/* args */)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Buffer::~Buffer()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
#include "Helpers.h"
|
|
||||||
|
|
||||||
#include "Params.h"
|
|
||||||
|
|
||||||
// ---- CRC-4 (MSB-first) over sequence of bytes ----
|
|
||||||
uint8_t crc4_bytes(const std::vector<uint8_t> &data)
|
|
||||||
{
|
|
||||||
// Implementation: bitwise shift register (5 bits) with poly 0x13
|
|
||||||
uint8_t reg = 0; // will keep up to 5 bits
|
|
||||||
for (uint8_t byte : data)
|
|
||||||
{
|
|
||||||
for (int i = 7; i >= 0; --i)
|
|
||||||
{ // MSB-first
|
|
||||||
uint8_t bit = (byte >> i) & 1;
|
|
||||||
reg = (reg << 1) | bit; // push bit
|
|
||||||
if (reg & (1 << 4))
|
|
||||||
{ // if degree-4 bit set
|
|
||||||
reg ^= CRC4_POLY;
|
|
||||||
}
|
|
||||||
reg &= 0x1F;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// append 4 zeros (simulate shifting r zeros)
|
|
||||||
for (int i = 0; i < 4; ++i)
|
|
||||||
{
|
|
||||||
reg = (reg << 1);
|
|
||||||
if (reg & (1 << 4))
|
|
||||||
reg ^= CRC4_POLY;
|
|
||||||
reg &= 0x1F;
|
|
||||||
}
|
|
||||||
return reg & 0x0F; // lower 4 bits = CRC
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- helper to build header byte ----
|
|
||||||
uint8_t build_header(PacketType type, uint8_t session, uint8_t nibble)
|
|
||||||
{
|
|
||||||
// session: 0..3, nibble: 0..15
|
|
||||||
return static_cast<uint8_t>((nibble & 0x0F) << 4) | static_cast<uint8_t>((session & 0x03) << 2) | (static_cast<uint8_t>(type) & 0x03);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Packet> createPackets(const std::vector<uint8_t> &message, uint8_t session)
|
|
||||||
{
|
|
||||||
std::vector<Packet> out;
|
|
||||||
if (session > 3)
|
|
||||||
return out;
|
|
||||||
|
|
||||||
size_t total = message.size();
|
|
||||||
|
|
||||||
// Количество пакетов с полезными данными (TYPE_FIRST + TYPE_MIDDLE)
|
|
||||||
size_t data_packets = (total + MAX_PAYLOAD - 1) / MAX_PAYLOAD;
|
|
||||||
if (data_packets == 0)
|
|
||||||
data_packets = 1; // если пустое сообщение — один пустой FIRST
|
|
||||||
|
|
||||||
if (data_packets > 15)
|
|
||||||
return out; // 4 бита
|
|
||||||
|
|
||||||
// Число пакетов, которые реально будут отправлены = data_packets + 1 (LAST всегда присутствует)
|
|
||||||
size_t total_packets = data_packets + 1;
|
|
||||||
|
|
||||||
// Разбиваем данные на payload’ы для data_packets
|
|
||||||
std::vector<std::vector<uint8_t>> chunks;
|
|
||||||
chunks.reserve(data_packets);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < data_packets; ++i)
|
|
||||||
{
|
|
||||||
size_t start = i * MAX_PAYLOAD;
|
|
||||||
size_t len = std::min(MAX_PAYLOAD, total - start);
|
|
||||||
std::vector<uint8_t> c;
|
|
||||||
if (len > 0)
|
|
||||||
c.insert(c.end(), message.begin() + start, message.begin() + start + len);
|
|
||||||
chunks.push_back(std::move(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Вычисляем CRC4 по всем данным
|
|
||||||
std::vector<uint8_t> concat;
|
|
||||||
for (auto &c : chunks)
|
|
||||||
concat.insert(concat.end(), c.begin(), c.end());
|
|
||||||
uint8_t crc4 = crc4_bytes(concat);
|
|
||||||
|
|
||||||
// Генерируем пакеты
|
|
||||||
out.reserve(total_packets);
|
|
||||||
|
|
||||||
// FIRST пакет
|
|
||||||
{
|
|
||||||
Packet p;
|
|
||||||
uint8_t header = build_header(TYPE_FIRST, session, static_cast<uint8_t>(data_packets));
|
|
||||||
p.bytes.push_back(header);
|
|
||||||
p.bytes.insert(p.bytes.end(), chunks[0].begin(), chunks[0].end());
|
|
||||||
out.push_back(std::move(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
// MIDDLE пакеты (если есть)
|
|
||||||
for (size_t i = 1; i < data_packets; ++i)
|
|
||||||
{
|
|
||||||
Packet p;
|
|
||||||
uint8_t header = build_header(TYPE_MIDDLE, session, static_cast<uint8_t>(i));
|
|
||||||
p.bytes.push_back(header);
|
|
||||||
p.bytes.insert(p.bytes.end(), chunks[i].begin(), chunks[i].end());
|
|
||||||
out.push_back(std::move(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
// LAST пакет — всегда присутствует
|
|
||||||
{
|
|
||||||
Packet p;
|
|
||||||
uint8_t header = build_header(TYPE_LAST, session, crc4);
|
|
||||||
p.bytes.push_back(header);
|
|
||||||
// payload пустой
|
|
||||||
out.push_back(std::move(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#ifndef SERIAL_PROTO_HELPERS_H_GUARD
|
|
||||||
#define SERIAL_PROTO_HELPERS_H_GUARD
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
#include "PacketType.h"
|
|
||||||
#include "Packet.h"
|
|
||||||
|
|
||||||
uint8_t crc4_bytes(const std::vector<uint8_t> &data);
|
|
||||||
uint8_t build_header(PacketType type, uint8_t session, uint8_t nibble);
|
|
||||||
std::vector<Packet> createPackets(const std::vector<uint8_t> &message, uint8_t session);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,12 +1,21 @@
|
|||||||
#ifndef SERIAL_PROTO_PACKET_H_GUARD
|
#ifndef ES_SERIAL_PROTO_PACKET_H_GUARD
|
||||||
#define SERIAL_PROTO_PACKET_H_GUARD
|
#define ES_SERIAL_PROTO_PACKET_H_GUARD
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Serial
|
||||||
|
{
|
||||||
|
namespace Proto
|
||||||
|
{
|
||||||
struct Packet
|
struct Packet
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> bytes; // full raw packet (header + payload)
|
std::vector<uint8_t> bytes; // full raw packet (header + payload)
|
||||||
};
|
};
|
||||||
|
} // namespace Proto
|
||||||
|
} // namespace Serial
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef ES_SERIAL_PROTO_PACKETCOMMAND_H_GUARD
|
||||||
|
#define ES_SERIAL_PROTO_PACKETCOMMAND_H_GUARD
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Serial
|
||||||
|
{
|
||||||
|
namespace Proto
|
||||||
|
{
|
||||||
|
enum Command : uint8_t
|
||||||
|
{
|
||||||
|
CMD_READ = 0x01,
|
||||||
|
CMD_WRITE = 0x02
|
||||||
|
};
|
||||||
|
} // namespace Proto
|
||||||
|
} // namespace Serial
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef ES_SERIAL_PROTO_PACKETHEADER_H_GUARD
|
||||||
|
#define ES_SERIAL_PROTO_PACKETHEADER_H_GUARD
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Serial
|
||||||
|
{
|
||||||
|
namespace Proto
|
||||||
|
{
|
||||||
|
struct PacketHeader
|
||||||
|
{
|
||||||
|
uint8_t type; // REQUEST, RESPONSE, ACK, NACK
|
||||||
|
uint8_t cmd; // READ или WRITE
|
||||||
|
uint16_t offset; // 16-битное смещение
|
||||||
|
uint16_t length; // длина данных (0 для READ-запроса)
|
||||||
|
};
|
||||||
|
} // namespace Proto
|
||||||
|
} // namespace Serial
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,13 +1,23 @@
|
|||||||
#ifndef SERIAL_PROTO_PACKETTYPE_H_GUARD
|
#ifndef ES_SERIAL_PROTO_PACKETTYPE_H_GUARD
|
||||||
#define SERIAL_PROTO_PACKETTYPE_H_GUARD
|
#define ES_SERIAL_PROTO_PACKETTYPE_H_GUARD
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Serial
|
||||||
|
{
|
||||||
|
namespace Proto
|
||||||
|
{
|
||||||
enum PacketType : uint8_t
|
enum PacketType : uint8_t
|
||||||
{
|
{
|
||||||
TYPE_FIRST = 0b00,
|
TYPE_REQUEST = 0x01,
|
||||||
TYPE_MIDDLE = 0b01,
|
TYPE_RESPONSE = 0x02,
|
||||||
TYPE_LAST = 0b10
|
TYPE_ACK = 0x03,
|
||||||
|
TYPE_NACK = 0x04
|
||||||
};
|
};
|
||||||
|
} // namespace Proto
|
||||||
|
} // namespace Serial
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,11 +1,20 @@
|
|||||||
#ifndef SERIAL_PROTO_PARAMS_H_GUARD
|
#ifndef ES_SERIAL_PROTO_PARAMS_H_GUARD
|
||||||
#define SERIAL_PROTO_PARAMS_H_GUARD
|
#define ES_SERIAL_PROTO_PARAMS_H_GUARD
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Serial
|
||||||
|
{
|
||||||
|
namespace Proto
|
||||||
|
{
|
||||||
constexpr size_t MAX_RAW_PACKET_SIZE = 32;
|
constexpr size_t MAX_RAW_PACKET_SIZE = 32;
|
||||||
constexpr size_t HEADER_SIZE = 1;
|
constexpr size_t HEADER_SIZE = 1;
|
||||||
constexpr size_t MAX_PAYLOAD = MAX_RAW_PACKET_SIZE - HEADER_SIZE; // 31
|
constexpr size_t MAX_PAYLOAD = MAX_RAW_PACKET_SIZE - HEADER_SIZE; // 31
|
||||||
constexpr uint8_t CRC4_POLY = 0x13; // 0b1_0011 (x^4 + x + 1)
|
constexpr uint8_t CRC4_POLY = 0x13; // 0b1_0011 (x^4 + x + 1)
|
||||||
|
} // namespace Proto
|
||||||
|
} // namespace Serial
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
#include "Reassembler.h"
|
|
||||||
|
|
||||||
#include "PacketType.h"
|
|
||||||
#include "Helpers.h"
|
|
||||||
|
|
||||||
void Reassembler::startNew(uint8_t session, uint8_t num_packets)
|
|
||||||
{
|
|
||||||
active_ = true;
|
|
||||||
session_ = session & 0x03;
|
|
||||||
expected_packets_ = std::max<uint8_t>(1, num_packets & 0x0F);
|
|
||||||
last_crc_ = 0;
|
|
||||||
chunks.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reassembler::storeChunk(uint8_t idx, std::vector<uint8_t> &&payload)
|
|
||||||
{
|
|
||||||
// replace if duplicate
|
|
||||||
chunks[idx] = std::move(payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Reassembler::haveAllChunks() const
|
|
||||||
{
|
|
||||||
if (!active_)
|
|
||||||
return false;
|
|
||||||
for (uint8_t i = 0; i < expected_packets_; ++i)
|
|
||||||
{
|
|
||||||
if (chunks.find(i) == chunks.end())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint8_t> Reassembler::assembleMessage() const
|
|
||||||
{
|
|
||||||
std::vector<uint8_t> out;
|
|
||||||
for (uint8_t i = 0; i < expected_packets_; ++i)
|
|
||||||
{
|
|
||||||
auto it = chunks.find(i);
|
|
||||||
if (it != chunks.end())
|
|
||||||
{
|
|
||||||
out.insert(out.end(), it->second.begin(), it->second.end());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::vector<uint8_t>> Reassembler::feedPacket(const std::vector<uint8_t> &raw_packet)
|
|
||||||
{
|
|
||||||
if (raw_packet.size() < 1)
|
|
||||||
return std::nullopt; // invalid
|
|
||||||
|
|
||||||
uint8_t header = raw_packet[0];
|
|
||||||
PacketType type = static_cast<PacketType>(header & 0x03);
|
|
||||||
uint8_t session = (header >> 2) & 0x03;
|
|
||||||
uint8_t nibble = (header >> 4) & 0x0F;
|
|
||||||
std::vector<uint8_t> payload;
|
|
||||||
if (raw_packet.size() > 1)
|
|
||||||
payload.insert(payload.end(), raw_packet.begin() + 1, raw_packet.end());
|
|
||||||
|
|
||||||
// Если нет активной сборки — ожидание FIRST
|
|
||||||
if (!active_)
|
|
||||||
{
|
|
||||||
if (type != TYPE_FIRST)
|
|
||||||
{
|
|
||||||
// Игнорируем пакеты, пока не придёт FIRST для начала сессии
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
// Инициируем сборку
|
|
||||||
startNew(session, nibble);
|
|
||||||
if (payload.size() > 0)
|
|
||||||
storeChunk(0, std::move(payload));
|
|
||||||
// Если пакет одновременно единственный и последний (num_packets==1), то возможно нам нужен immediate CRC check:
|
|
||||||
if (expected_packets_ == 1)
|
|
||||||
{
|
|
||||||
// ожидание CRC: когда num_packets==1, last == first; но по вашей спецификации CRC находится в LAST,
|
|
||||||
// а мы получили FIRST с nibble=num_packets. В этом варианте нужен отдельный пакет LAST.
|
|
||||||
// Для простоты: считаем, что в случае num_packets==1 отправляется FIRST и LAST как один пакет?
|
|
||||||
// Чтобы покрыть оба варианта, если num_packets==1 мы считаем этот пакет и как LAST не содержащий CRC,
|
|
||||||
// поэтому здесь не завершаем — ждём прихода LAST (с flag TYPE_LAST) или второй пактета.
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// если есть активная сборка, session должен совпадать
|
|
||||||
if (session != session_)
|
|
||||||
{
|
|
||||||
// новый FIRST может начаться в любой момент — перезапускаем сборку, если пришёл FIRST с новым session
|
|
||||||
if (type == TYPE_FIRST)
|
|
||||||
{
|
|
||||||
startNew(session, nibble);
|
|
||||||
if (payload.size())
|
|
||||||
storeChunk(0, std::move(payload));
|
|
||||||
}
|
|
||||||
// иначе игнорируем
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Приёмы для текущей активной сборки:
|
|
||||||
if (type == TYPE_FIRST)
|
|
||||||
{
|
|
||||||
// Ресет сборки на тот же session
|
|
||||||
startNew(session, nibble);
|
|
||||||
if (payload.size())
|
|
||||||
storeChunk(0, std::move(payload));
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
else if (type == TYPE_MIDDLE)
|
|
||||||
{
|
|
||||||
uint8_t pkt_idx = nibble & 0x0F;
|
|
||||||
// проверка валидности индекса
|
|
||||||
if (pkt_idx == 0 || pkt_idx >= expected_packets_)
|
|
||||||
{
|
|
||||||
// packet index 0 = reserved (first); если >= expected -> некорректно
|
|
||||||
// игнорируем
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
storeChunk(pkt_idx, std::move(payload));
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
else if (type == TYPE_LAST)
|
|
||||||
{
|
|
||||||
// nibble = crc4
|
|
||||||
last_crc_ = nibble & 0x0F;
|
|
||||||
// индекс последнего пакета
|
|
||||||
uint8_t last_idx = static_cast<uint8_t>(expected_packets_ - 1);
|
|
||||||
storeChunk(last_idx, std::move(payload));
|
|
||||||
// попробуем собрать всё сообщение и проверить CRC
|
|
||||||
if (haveAllChunks())
|
|
||||||
{
|
|
||||||
auto full = assembleMessage();
|
|
||||||
uint8_t computed = crc4_bytes(full);
|
|
||||||
if (computed == last_crc_)
|
|
||||||
{
|
|
||||||
// успешная сборка
|
|
||||||
active_ = false; // очистка для следующей сессии
|
|
||||||
return full;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// CRC mismatch -> discard session
|
|
||||||
active_ = false;
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// ещё не пришли все куски, но мы знаем CRC — ждём
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#ifndef SERIAL_PROTO_REASSEMBLER_H_GUARD
|
|
||||||
#define SERIAL_PROTO_REASSEMBLER_H_GUARD
|
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
#include <vector>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
class Reassembler
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
bool active_ = false;
|
|
||||||
uint8_t session_ = 0;
|
|
||||||
uint8_t expected_packets_ = 0;
|
|
||||||
uint8_t last_crc_ = 0;
|
|
||||||
std::map<uint8_t, std::vector<uint8_t>> chunks; // key: packet index -> payload
|
|
||||||
|
|
||||||
void startNew(uint8_t session, uint8_t num_packets);
|
|
||||||
void storeChunk(uint8_t idx, std::vector<uint8_t> &&payload);
|
|
||||||
bool haveAllChunks() const;
|
|
||||||
std::vector<uint8_t> assembleMessage() const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Reassembler() = default;
|
|
||||||
|
|
||||||
// feed raw packet bytes; если сообщение собрано и CRC верен, вернёт собранное сообщение
|
|
||||||
// в out_message, и сбросит внутренний буфер. В противном случае вернёт std::nullopt.
|
|
||||||
// Для каждого нового FIRST пакета с другим session происходит начало новой сборки.
|
|
||||||
std::optional<std::vector<uint8_t>> feedPacket(const std::vector<uint8_t> &raw_packet);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#include "RingBuffer.h"
|
|
||||||
|
|
||||||
bool ring_buffer_is_empty(ring_buffer_t *rb)
|
|
||||||
{
|
|
||||||
return rb->head == rb->tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ring_buffer_is_full(ring_buffer_t *rb)
|
|
||||||
{
|
|
||||||
return ((rb->head + 1) % RING_BUFFER_SIZE) == rb->tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ring_buffer_put(ring_buffer_t *rb, uint8_t data)
|
|
||||||
{
|
|
||||||
if (ring_buffer_is_full(rb))
|
|
||||||
return false;
|
|
||||||
rb->buffer[rb->head] = data;
|
|
||||||
rb->head = (rb->head + 1) % RING_BUFFER_SIZE;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ring_buffer_get(ring_buffer_t *rb, uint8_t *data)
|
|
||||||
{
|
|
||||||
if (ring_buffer_is_empty(rb))
|
|
||||||
return false;
|
|
||||||
*data = rb->buffer[rb->tail];
|
|
||||||
rb->tail = (rb->tail + 1) % RING_BUFFER_SIZE;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
+39
-13
@@ -1,20 +1,46 @@
|
|||||||
#ifndef SERIAL_RINGBUFFER_H_GUARD
|
#ifndef ES_SERIAL_RINGBUFFER_H_GUARD
|
||||||
#define SERIAL_RINGBUFFER_H_GUARD
|
#define ES_SERIAL_RINGBUFFER_H_GUARD
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#define RING_BUFFER_SIZE 512
|
namespace es
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
{
|
||||||
uint8_t buffer[RING_BUFFER_SIZE];
|
namespace Serial
|
||||||
volatile uint16_t head;
|
{
|
||||||
volatile uint16_t tail;
|
template <size_t N>
|
||||||
} ring_buffer_t;
|
class RingBuffer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint8_t buf[N];
|
||||||
|
volatile size_t head = 0;
|
||||||
|
volatile size_t tail = 0;
|
||||||
|
|
||||||
bool ring_buffer_is_empty(ring_buffer_t *rb);
|
public:
|
||||||
bool ring_buffer_is_full(ring_buffer_t *rb);
|
bool push(uint8_t byte)
|
||||||
bool ring_buffer_put(ring_buffer_t *rb, uint8_t data);
|
{
|
||||||
bool ring_buffer_get(ring_buffer_t *rb, uint8_t *data);
|
size_t next = (head + 1) % N;
|
||||||
|
if (next == tail)
|
||||||
|
return false; // buffer full
|
||||||
|
buf[head] = byte;
|
||||||
|
head = next;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pop(uint8_t &byte)
|
||||||
|
{
|
||||||
|
if (head == tail)
|
||||||
|
return false; // buffer empty
|
||||||
|
byte = buf[tail];
|
||||||
|
tail = (tail + 1) % N;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t available() const
|
||||||
|
{
|
||||||
|
return (head >= tail) ? (head - tail) : (N - tail + head);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Serial
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+13
-10
@@ -5,7 +5,11 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "pico/stdio.h"
|
#include "pico/stdio.h"
|
||||||
|
|
||||||
SerialRx::SerialRx(/* args */) : Task("SerialRx", 256, 1000, 1)
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Serial
|
||||||
|
{
|
||||||
|
SerialRx::SerialRx(/* args */) : Task("SerialRx", 4096, 1000, 1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13,11 +17,11 @@ SerialRx::~SerialRx()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialRx::setup(void *args)
|
void SerialRx::setup()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialRx::loop(void *args)
|
void SerialRx::loop()
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> input;
|
std::vector<uint8_t> input;
|
||||||
int input_char;
|
int input_char;
|
||||||
@@ -27,13 +31,12 @@ void SerialRx::loop(void *args)
|
|||||||
packets++;
|
packets++;
|
||||||
input.push_back((char)input_char);
|
input.push_back((char)input_char);
|
||||||
}
|
}
|
||||||
|
if (packets != 0)
|
||||||
|
{
|
||||||
printf("Got %d packets\n", packets);
|
printf("Got %d packets\n", packets);
|
||||||
if (!input.empty())
|
auto display = es::Task::Registry<uint8_t>::getTask("Display");
|
||||||
{
|
display->send((uint8_t)packets);
|
||||||
auto res = reassembler.feedPacket(input);
|
|
||||||
if (res.has_value())
|
|
||||||
{
|
|
||||||
printf("Got data\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} // namespace Serial
|
||||||
|
} // namespace es
|
||||||
|
|||||||
+11
-8
@@ -1,20 +1,23 @@
|
|||||||
#ifndef SERIAL_SERIALRX_H_GUARD
|
#ifndef ES_SERIAL_SERIALRX_H_GUARD
|
||||||
#define SERIAL_SERIALRX_H_GUARD
|
#define ES_SERIAL_SERIALRX_H_GUARD
|
||||||
|
|
||||||
#include "Task.h"
|
#include "Task.h"
|
||||||
|
|
||||||
#include "Reassembler.h"
|
namespace es
|
||||||
|
{
|
||||||
class SerialRx : public Task
|
namespace Serial
|
||||||
|
{
|
||||||
|
class SerialRx : public es::Task::Task<uint8_t>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Reassembler reassembler;
|
void setup() override;
|
||||||
void setup(void *args);
|
void loop() override;
|
||||||
void loop(void *args);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SerialRx(/* args */);
|
SerialRx(/* args */);
|
||||||
~SerialRx();
|
~SerialRx();
|
||||||
};
|
};
|
||||||
|
} // namespace Serial
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+10
-4
@@ -3,7 +3,11 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "pico/stdio.h"
|
#include "pico/stdio.h"
|
||||||
|
|
||||||
SerialTx::SerialTx(/* args */) : Task("SerialTx", 128, 15000, 1)
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Serial
|
||||||
|
{
|
||||||
|
SerialTx::SerialTx(/* args */) : Task("SerialTx", 1024, 5000, 1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11,11 +15,13 @@ SerialTx::~SerialTx()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialTx::setup(void *args)
|
void SerialTx::setup()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialTx::loop(void *args)
|
void SerialTx::loop()
|
||||||
{
|
{
|
||||||
printf("SerialTx\n");
|
printf("[%s] Ping\n", name.c_str());
|
||||||
}
|
}
|
||||||
|
} // namespace Serial
|
||||||
|
} // namespace es
|
||||||
|
|||||||
+11
-5
@@ -1,17 +1,23 @@
|
|||||||
#ifndef SERIAL_SERIALTX_H_GUARD
|
#ifndef ES_SERIAL_SERIALTX_H_GUARD
|
||||||
#define SERIAL_SERIALTX_H_GUARD
|
#define ES_SERIAL_SERIALTX_H_GUARD
|
||||||
|
|
||||||
#include "Task.h"
|
#include "Task.h"
|
||||||
|
|
||||||
class SerialTx : public Task
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Serial
|
||||||
|
{
|
||||||
|
class SerialTx : public es::Task::Task<uint8_t>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
void setup(void *args);
|
void setup() override;
|
||||||
void loop(void *args);
|
void loop() override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SerialTx(/* args */);
|
SerialTx(/* args */);
|
||||||
~SerialTx();
|
~SerialTx();
|
||||||
};
|
};
|
||||||
|
} // namespace Serial
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
#ifndef TASK_REGISTRY_H_GUARD
|
||||||
|
#define TASK_REGISTRY_H_GUARD
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "semphr.h"
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Task
|
||||||
|
{
|
||||||
|
template <typename MsgT>
|
||||||
|
class Task; // forward declaration
|
||||||
|
|
||||||
|
template <typename MsgT>
|
||||||
|
class Registry
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static std::vector<std::shared_ptr<Task<MsgT>>> tasks;
|
||||||
|
static SemaphoreHandle_t mtx;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void init()
|
||||||
|
{
|
||||||
|
if (mtx == nullptr)
|
||||||
|
{
|
||||||
|
mtx = xSemaphoreCreateRecursiveMutex();
|
||||||
|
if (mtx == nullptr)
|
||||||
|
printf("Error! Mutex is not created");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void registerTask(const std::shared_ptr<Task<MsgT>> &t)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
if (xSemaphoreTake(mtx, portMAX_DELAY) == pdTRUE)
|
||||||
|
{
|
||||||
|
tasks.push_back(t);
|
||||||
|
xSemaphoreGive(mtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::shared_ptr<Task<MsgT>> getTask(const std::string &name)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
std::shared_ptr<Task<MsgT>> out = nullptr;
|
||||||
|
|
||||||
|
if (xSemaphoreTake(mtx, portMAX_DELAY) == pdTRUE)
|
||||||
|
{
|
||||||
|
for (auto &t : tasks)
|
||||||
|
{
|
||||||
|
if (t->getName() == name)
|
||||||
|
{
|
||||||
|
out = t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xSemaphoreGive(mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::shared_ptr<Task<MsgT>>> getAllTasks()
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
std::vector<std::shared_ptr<Task<MsgT>>> copy;
|
||||||
|
|
||||||
|
if (xSemaphoreTake(mtx, portMAX_DELAY) == pdTRUE)
|
||||||
|
{
|
||||||
|
copy = tasks; // shallow copy
|
||||||
|
xSemaphoreGive(mtx);
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename MsgT>
|
||||||
|
std::vector<std::shared_ptr<Task<MsgT>>> Registry<MsgT>::tasks;
|
||||||
|
|
||||||
|
template <typename MsgT>
|
||||||
|
SemaphoreHandle_t Registry<MsgT>::mtx = nullptr;
|
||||||
|
} // namespace Task
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
#include "Task.h"
|
|
||||||
|
|
||||||
Task::Task(const char *name, const UBaseType_t stack_size, const uint32_t ms, const UBaseType_t priority) : name(name), active(false), stack_size(stack_size), ms(ms), priority(priority)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Task::~Task()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
TaskHandle_t *Task::getTaskHandlePtr()
|
|
||||||
{
|
|
||||||
return &handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseType_t Task::getStatus()
|
|
||||||
{
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Task::setup(void *args)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Task::loop(void *args)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Task::taskMain(void *args)
|
|
||||||
{
|
|
||||||
TickType_t xLastWakeTime = xTaskGetTickCount();
|
|
||||||
|
|
||||||
const TickType_t xFrequency = pdMS_TO_TICKS(ms);
|
|
||||||
setup(args);
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
diff_full = xTaskGetTickCount() - tick_delay;
|
|
||||||
tick_delay = xTaskGetTickCount();
|
|
||||||
diff_delay = tick_delay - tick_loop;
|
|
||||||
diff_loop = tick_loop - tick_start;
|
|
||||||
tick_start = xTaskGetTickCount();
|
|
||||||
loop(args);
|
|
||||||
tick_loop = xTaskGetTickCount();
|
|
||||||
vTaskDelayUntil(&xLastWakeTime, xFrequency);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Task::osTaskFunction(void *ctx)
|
|
||||||
{
|
|
||||||
std::pair<Task *, void *> *obj = static_cast<std::pair<Task *, void *> *>(ctx);
|
|
||||||
obj->first->taskMain(obj->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Task::start()
|
|
||||||
{
|
|
||||||
if (active)
|
|
||||||
stop();
|
|
||||||
|
|
||||||
context = {this, nullptr};
|
|
||||||
status = xTaskCreate(osTaskFunction, name, stack_size, static_cast<void *>(&context), priority, &handle);
|
|
||||||
|
|
||||||
active = status == pdPASS;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Task::stop()
|
|
||||||
{
|
|
||||||
if (active)
|
|
||||||
{
|
|
||||||
vTaskDelete(handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+143
-27
@@ -1,43 +1,159 @@
|
|||||||
#ifndef TASK_TASK_H_GUARD
|
#ifndef TASK_TASK_H_GUARD
|
||||||
#define TASK_TASK_H_GUARD
|
#define TASK_TASK_H_GUARD
|
||||||
|
|
||||||
#include <utility>
|
#include <memory>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
#include "queue.h"
|
||||||
|
|
||||||
class Task
|
#include "Registry.h"
|
||||||
|
|
||||||
|
namespace es
|
||||||
|
{
|
||||||
|
namespace Task
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename MsgT>
|
||||||
|
class Task : public std::enable_shared_from_this<Task<MsgT>>
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
const char *name;
|
const std::string name;
|
||||||
TickType_t tick_start;
|
|
||||||
TickType_t tick_loop;
|
|
||||||
TickType_t tick_delay;
|
|
||||||
TickType_t diff_loop;
|
|
||||||
TickType_t diff_delay;
|
|
||||||
TickType_t diff_full;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool active;
|
TaskHandle_t handle = nullptr;
|
||||||
TaskHandle_t handle;
|
|
||||||
BaseType_t status;
|
const UBaseType_t stack_size;
|
||||||
UBaseType_t stack_size;
|
const TickType_t period_ticks;
|
||||||
uint32_t ms;
|
const UBaseType_t priority;
|
||||||
UBaseType_t priority;
|
|
||||||
std::pair<Task *, void *> context;
|
QueueHandle_t queue = nullptr;
|
||||||
virtual void setup(void *args);
|
size_t queue_length = 0;
|
||||||
virtual void loop(void *args);
|
|
||||||
void taskMain(void *args);
|
// Main FreeRTOS task loop
|
||||||
|
void taskMain()
|
||||||
|
{
|
||||||
|
UBaseType_t freeHeap = xPortGetFreeHeapSize();
|
||||||
|
UBaseType_t minHeap = xPortGetMinimumEverFreeHeapSize();
|
||||||
|
printf("[%s] Task starting. Free heap=%u, min ever=%u\n", name.c_str(), freeHeap, minHeap);
|
||||||
|
|
||||||
|
printf("[%s] Setup...\n", name.c_str());
|
||||||
|
setup();
|
||||||
|
printf("[%s] Setup... Done!\n", name.c_str());
|
||||||
|
|
||||||
|
TickType_t lastWakeTime = xTaskGetTickCount();
|
||||||
|
|
||||||
|
printf("[%s] Staring main loop\n", name.c_str());
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
loop();
|
||||||
|
vTaskDelayUntil(&lastWakeTime, period_ticks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void osTaskFunction(void *ctx)
|
||||||
|
{
|
||||||
|
static_cast<Task<MsgT> *>(ctx)->taskMain();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void setup() {}
|
||||||
|
virtual void loop() {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Task(const char *name = "Task", const UBaseType_t stack_size = 128, const uint32_t ms = 33, const UBaseType_t priority = 1);
|
Task(const std::string &name = "Task",
|
||||||
~Task();
|
UBaseType_t stack_size = 4096,
|
||||||
static void osTaskFunction(void *ctx);
|
uint32_t period_ms = 33,
|
||||||
TaskHandle_t *getTaskHandlePtr();
|
UBaseType_t priority = 1,
|
||||||
BaseType_t getStatus();
|
size_t queue_len = 0)
|
||||||
void start();
|
: name(name),
|
||||||
void stop();
|
stack_size(stack_size),
|
||||||
|
period_ticks(pdMS_TO_TICKS(period_ms)),
|
||||||
|
priority(priority),
|
||||||
|
queue_length(queue_len)
|
||||||
|
{
|
||||||
|
if (queue_length > 0)
|
||||||
|
{
|
||||||
|
printf("[%s] Creating queue...\n", name.c_str());
|
||||||
|
queue = xQueueCreate(queue_length, sizeof(MsgT));
|
||||||
|
if (!queue)
|
||||||
|
{
|
||||||
|
printf("[%s] Queue create failed: len %u, msg %u\n",
|
||||||
|
name.c_str(), queue_length, sizeof(MsgT));
|
||||||
|
configASSERT(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("[%s] Creating queue... Done!\n", name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~Task()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
if (queue)
|
||||||
|
{
|
||||||
|
vQueueDelete(queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Derived>
|
||||||
|
static std::shared_ptr<Derived> create()
|
||||||
|
{
|
||||||
|
auto ptr = std::make_shared<Derived>();
|
||||||
|
Registry<MsgT>::registerTask(ptr);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start()
|
||||||
|
{
|
||||||
|
if (handle)
|
||||||
|
stop();
|
||||||
|
|
||||||
|
BaseType_t res = xTaskCreate(
|
||||||
|
osTaskFunction,
|
||||||
|
name.c_str(),
|
||||||
|
stack_size,
|
||||||
|
this,
|
||||||
|
priority,
|
||||||
|
&handle);
|
||||||
|
|
||||||
|
if (res != pdPASS)
|
||||||
|
handle = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop()
|
||||||
|
{
|
||||||
|
if (handle)
|
||||||
|
{
|
||||||
|
vTaskDelete(handle);
|
||||||
|
handle = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string getName() const { return name; }
|
||||||
|
|
||||||
|
// bool send(const MsgT &msg, TickType_t timeout = portMAX_DELAY)
|
||||||
|
bool send(const MsgT &msg, TickType_t timeout = 0)
|
||||||
|
{
|
||||||
|
if (!queue)
|
||||||
|
return false;
|
||||||
|
return xQueueSend(queue, &msg, timeout) == pdPASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bool receive(MsgT &out, TickType_t timeout = portMAX_DELAY)
|
||||||
|
bool receive(MsgT &out, TickType_t timeout = 0)
|
||||||
|
{
|
||||||
|
if (!queue)
|
||||||
|
return false;
|
||||||
|
return xQueueReceive(queue, &out, timeout) == pdPASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueueHandle_t getQueueHandle() const { return queue; }
|
||||||
};
|
};
|
||||||
|
} // namespace Task
|
||||||
|
} // namespace es
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+13
-9
@@ -1,3 +1,5 @@
|
|||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
@@ -11,16 +13,18 @@ int main()
|
|||||||
{
|
{
|
||||||
stdio_init_all();
|
stdio_init_all();
|
||||||
sleep_ms(2000);
|
sleep_ms(2000);
|
||||||
printf("We have started\n");
|
printf("[Main] ---------------\n");
|
||||||
|
printf("[Main] We have started\n");
|
||||||
|
printf("[Main] ---------------\n");
|
||||||
|
|
||||||
Led led;
|
std::shared_ptr<es::Other::Led> led = es::Task::Task<uint8_t>::create<es::Other::Led>();
|
||||||
SerialTx serial_tx;
|
std::shared_ptr<es::Serial::SerialTx> serial_tx = es::Task::Task<uint8_t>::create<es::Serial::SerialTx>();
|
||||||
SerialRx serial_rx;
|
std::shared_ptr<es::Serial::SerialRx> serial_rx = es::Task::Task<uint8_t>::create<es::Serial::SerialRx>();
|
||||||
Display display;
|
std::shared_ptr<es::Display::Display> display = es::Task::Task<uint8_t>::create<es::Display::Display>();
|
||||||
led.start();
|
led->start();
|
||||||
serial_tx.start();
|
serial_tx->start();
|
||||||
serial_rx.start();
|
serial_rx->start();
|
||||||
display.start();
|
display->start();
|
||||||
|
|
||||||
vTaskStartScheduler();
|
vTaskStartScheduler();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user