initial commit of working code
This commit is contained in:
-35
@@ -1,35 +0,0 @@
|
||||
# ---> Android
|
||||
# Gradle files
|
||||
.gradle/
|
||||
build/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
||||
# Log/OS Files
|
||||
*.log
|
||||
|
||||
# Android Studio generated files and folders
|
||||
captures/
|
||||
.externalNativeBuild/
|
||||
.cxx/
|
||||
*.apk
|
||||
output.json
|
||||
|
||||
# IntelliJ
|
||||
*.iml
|
||||
.idea/
|
||||
misc.xml
|
||||
deploymentTargetDropDown.xml
|
||||
render.experimental.xml
|
||||
|
||||
# Keystore files
|
||||
*.jks
|
||||
*.keystore
|
||||
|
||||
# Google Services (e.g. APIs or Firebase)
|
||||
google-services.json
|
||||
|
||||
# Android Profiling
|
||||
*.hprof
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef JELLIES_H
|
||||
#define JELLIES_H
|
||||
|
||||
extern const TProgmemPalette16 rainbowPalette_p PROGMEM =
|
||||
{
|
||||
CRGB::Red,
|
||||
CRGB::OrangeRed,
|
||||
CRGB::Orange,
|
||||
CRGB::LightYellow,
|
||||
CRGB::Yellow,
|
||||
CRGB::YellowGreen,
|
||||
CRGB::LawnGreen,
|
||||
CRGB::Green,
|
||||
CRGB::Aquamarine,
|
||||
CRGB::LightBlue,
|
||||
CRGB::Blue,
|
||||
CRGB::Cyan,
|
||||
CRGB::BlueViolet,
|
||||
CRGB::Violet,
|
||||
CRGB::DarkViolet,
|
||||
CRGB::MediumVioletRed
|
||||
};
|
||||
|
||||
|
||||
// extern const CHSVPalette16 rainbowSpectrumPalette_p =
|
||||
// {
|
||||
// CHSV(0, 160, 64),
|
||||
// CHSV(12, 160, 64),
|
||||
// CHSV(24, 160, 64),
|
||||
// CHSV(36, 160, 64),
|
||||
// CHSV(48, 160, 64),
|
||||
// CHSV(64, 160, 64),
|
||||
// CHSV(82, 160, 64),
|
||||
// CHSV(104, 160, 64),
|
||||
// CHSV(124, 160, 64),
|
||||
// CHSV(138, 160, 64),
|
||||
// CHSV(156, 160, 64),
|
||||
// CHSV(174, 160, 64),
|
||||
// CHSV(192, 160, 64),
|
||||
// CHSV(204, 160, 64),
|
||||
// CHSV(230, 160, 64),
|
||||
// CHSV(244, 160, 64)
|
||||
// };
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
default_envs = jellypico32
|
||||
lib_dir = 'src/'
|
||||
|
||||
[env:jellypico32]
|
||||
platform = espressif32
|
||||
platform_packages = platformio/framework-arduinoespressif32@3.20011.230801
|
||||
board = pico32
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
monitor_filters = esp32_exception_decoder
|
||||
upload_speed = 1500000
|
||||
lib_deps =
|
||||
painlessmesh/painlessMesh @ ^1.5.0
|
||||
ArduinoJson
|
||||
AsyncTCP
|
||||
https://github.com/arkhipenko/TaskScheduler@3.7.0
|
||||
fastled/FastLED@^3.6.0
|
||||
https://github.com/hpwit/I2SClocklessLedDriver.git
|
||||
build_flags = -Iinclude/ -Wall -std=c++14
|
||||
@@ -0,0 +1,131 @@
|
||||
#ifndef LEDSWARMER_H
|
||||
#define LEDSWARMER_H
|
||||
|
||||
// #define _TASK_TIMECRITICAL // Enable monitoring scheduling overruns
|
||||
// #define _TASK_SLEEP_ON_IDLE_RUN // Enable 1 ms SLEEP_IDLE powerdowns between tasks if no callback methods were invoked during the pass
|
||||
// #define _TASK_STATUS_REQUEST // Compile with support for StatusRequest functionality - triggering tasks on status change events in addition to time only
|
||||
// #define _TASK_LTS_POINTER // Compile with support for local task storage pointer
|
||||
// #define _TASK_PRIORITY // Support for layered scheduling priority
|
||||
// #define _TASK_MICRO_RES // Support for microsecond resolution
|
||||
// #define _TASK_STD_FUNCTION // Support for std::function (ESP8266 ONLY)
|
||||
// #define _TASK_DEBUG // Make all methods and variables public for debug purposes
|
||||
// #define _TASK_INLINE // Make all methods "inline" - needed to support some multi-tab, multi-file implementations
|
||||
// #define _TASK_TIMEOUT 5
|
||||
|
||||
// #define FASTLED_ALLOW_INTERRUPTS 0
|
||||
// #define FASTLED_INTERRUPT_RETRY_COUNT 0
|
||||
|
||||
#define FASTLED_ALLOW_INTERRUPTS 1 // Allow interrupts, to prevent wifi weirdness ; https://github.com/FastLED/FastLED/wiki/Interrupt-problems
|
||||
#define INTERRUPT_THRESHOLD 1 // also see https://github.com/FastLED/FastLED/issues/367
|
||||
#define USE_GET_MILLISECOND_TIMER // Define our own millis() source for FastLED beat functions: see get_millisecond_timer()
|
||||
#define TASK_RES_MULTIPLIER 1
|
||||
|
||||
#define LED_ANIMATION_FRAME_PERIOD_MS 25 // 40 Hz update rate
|
||||
|
||||
#define NEO_PIXEL
|
||||
#define CHIPSET WS2812B
|
||||
#define COLOR_ORDER GRB
|
||||
#define LED_PIN_1 4
|
||||
#define LED_PIN_2 2
|
||||
#define LED_PIN_3 14
|
||||
#define LED_PIN_4 12
|
||||
#define LED_PIN_5 13
|
||||
#define LED_PIN_6 15
|
||||
|
||||
#define LEDS_PER_STRIP 6
|
||||
#define STRIPS_PER_NODE 6
|
||||
#define LEDS_PER_NODE LEDS_PER_STRIP * STRIPS_PER_NODE
|
||||
|
||||
#define DEFAULT_BRIGHTNESS 64
|
||||
|
||||
// ************************************************************************
|
||||
// INCLUDES
|
||||
// ************************************************************************
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <FastLED.h>
|
||||
#include <painlessMesh.h>
|
||||
#include <I2SClocklessLedDriver.h>
|
||||
|
||||
#include "jellies.h"
|
||||
|
||||
#define MESH_PREFIX "tomsJelliesMesh"
|
||||
#define MESH_PASSWORD "somethingSneaky"
|
||||
#define MESH_PORT 7465
|
||||
|
||||
#define TASK_RESTART_CYCLES 40000
|
||||
|
||||
// leds + mesh
|
||||
CRGB _localLeds[LEDS_PER_NODE];
|
||||
painlessMesh mesh;
|
||||
I2SClocklessLedDriver _driver;
|
||||
|
||||
int pins[STRIPS_PER_NODE] = {4,2,14,12,13,15}
|
||||
|
||||
// prototype for mesh timer
|
||||
uint32_t get_millisecond_timer();
|
||||
|
||||
// MESH function prototypes (callbacks)
|
||||
void receivedCallback( uint32_t from, String &msg ) ;
|
||||
void newConnectionCallback(uint32_t nodeId) ;
|
||||
void changedConnectionCallback() ;
|
||||
void nodeTimeAdjustedCallback(int32_t offset) ;
|
||||
void delayReceivedCallback(uint32_t from, int32_t delay) ;
|
||||
|
||||
// Task (User) function prototypes
|
||||
void currentPatternRun();
|
||||
void sendMessage();
|
||||
void chooseNextPattern();
|
||||
void updateLEDs();
|
||||
void updateCurrentAction();
|
||||
void darkNow();
|
||||
void rainbowDefault();
|
||||
void fadeInOut();
|
||||
void sparkle();
|
||||
void initSparkle();
|
||||
|
||||
#define LED_STILL_FRAME_PERIOD_MS 1000
|
||||
#define LED_SLOW_ANIMATION_FRAME_PERIOD_MS 100
|
||||
|
||||
#define TOTAL_PRESETS 64
|
||||
|
||||
// #define _TASK_SLEEP_ON_IDLE_RUN 1
|
||||
|
||||
#include <TaskScheduler.h>
|
||||
|
||||
//Scheduler + Tasks
|
||||
Scheduler userScheduler; // to control your personal task1
|
||||
Task taskCurrentPatternRun(
|
||||
(TASK_MILLISECOND * LED_ANIMATION_FRAME_PERIOD_MS),
|
||||
TASK_FOREVER,
|
||||
¤tPatternRun,
|
||||
&userScheduler,
|
||||
false);
|
||||
Task taskSendMessage(
|
||||
TASK_SECOND * (random8(4) + 5),
|
||||
TASK_FOREVER,
|
||||
&sendMessage,
|
||||
&userScheduler,
|
||||
false );
|
||||
Task taskEvolveColorPreset(
|
||||
TASK_SECOND * (random8(8) + 8),
|
||||
TASK_FOREVER,
|
||||
&chooseNextPattern,
|
||||
&userScheduler,
|
||||
false);
|
||||
|
||||
// State vars
|
||||
uint16_t _counter = 0;
|
||||
uint8_t _speed_lo = 2;
|
||||
uint8_t _speed_hi = 6;
|
||||
uint8_t _density = 6;
|
||||
uint8_t _current_color_preset = 45;
|
||||
uint8_t _next_color_preset = 46;
|
||||
|
||||
uint8_t _ledState[LEDS_PER_NODE*2];
|
||||
|
||||
const char *_current_action = "noaction";
|
||||
|
||||
boolean node_connected = false;
|
||||
|
||||
#endif
|
||||
+321
@@ -0,0 +1,321 @@
|
||||
#include "LEDSwarmer.h"
|
||||
|
||||
void setup()
|
||||
{
|
||||
|
||||
Serial.begin(115200);
|
||||
delay((100 * random8(20)) + 40000); // Startup delay; let things settle down0
|
||||
|
||||
// mesh.setDebugMsgTypes( ERROR | c | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on; WARNING, buggy!!
|
||||
mesh.setDebugMsgTypes( ERROR | STARTUP | CONNECTION | SYNC | MESH_STATUS ); // set before init() so that you can see startup messages
|
||||
// mesh.setDebugMsgTypes( ERROR | DEBUG | STARTUP | CONNECTION | SYNC ); // set before init() so that you can see startup messages
|
||||
// mesh.setDebugMsgTypes( ERROR | STARTUP ); // set before init() so that you can see startup messages
|
||||
|
||||
|
||||
mesh.init(
|
||||
MESH_PREFIX,
|
||||
MESH_PASSWORD,
|
||||
&userScheduler,
|
||||
MESH_PORT);
|
||||
|
||||
mesh.onReceive(&receivedCallback);
|
||||
mesh.onNewConnection(&newConnectionCallback);
|
||||
mesh.onChangedConnections(&changedConnectionCallback);
|
||||
mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
|
||||
mesh.onNodeDelayReceived(&delayReceivedCallback);
|
||||
|
||||
|
||||
// FastLED.addLeds<CHIPSET, LED_PIN_1, COLOR_ORDER>(_localLeds, 0 * LEDS_PER_STRIP, LEDS_PER_STRIP);
|
||||
// FastLED.addLeds<CHIPSET, LED_PIN_2, COLOR_ORDER>(_localLeds, 1 * LEDS_PER_STRIP, LEDS_PER_STRIP);
|
||||
// FastLED.addLeds<CHIPSET, LED_PIN_3, COLOR_ORDER>(_localLeds, 2 * LEDS_PER_STRIP, LEDS_PER_STRIP);
|
||||
// FastLED.addLeds<CHIPSET, LED_PIN_4, COLOR_ORDER>(_localLeds, 3 * LEDS_PER_STRIP, LEDS_PER_STRIP);
|
||||
// FastLED.addLeds<CHIPSET, LED_PIN_5, COLOR_ORDER>(_localLeds, 4 * LEDS_PER_STRIP, LEDS_PER_STRIP);
|
||||
// FastLED.addLeds<CHIPSET, LED_PIN_6, COLOR_ORDER>(_localLeds, 5 * LEDS_PER_STRIP, LEDS_PER_STRIP);
|
||||
|
||||
_driver.initled((uint8_t*)_localLeds, pins, 6, 6, GBR);
|
||||
_driver.setBrightness(100);
|
||||
|
||||
userScheduler.addTask(taskCurrentPatternRun);
|
||||
userScheduler.addTask(taskSendMessage);
|
||||
userScheduler.addTask(taskEvolveColorPreset);
|
||||
|
||||
taskCurrentPatternRun.enable();
|
||||
taskSendMessage.enable();
|
||||
taskEvolveColorPreset.enable();
|
||||
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
mesh.update();
|
||||
}
|
||||
|
||||
#ifdef USE_GET_MILLISECOND_TIMER
|
||||
uint32_t get_millisecond_timer()
|
||||
{
|
||||
return mesh.getNodeTime() / TASK_SECOND;
|
||||
}
|
||||
#endif
|
||||
|
||||
void initSparkle() {
|
||||
|
||||
darkNow();
|
||||
int i = 1 + random8(LEDS_PER_STRIP); // land first somewhere on strip 0
|
||||
int c = 0;
|
||||
|
||||
while (i < LEDS_PER_NODE) {
|
||||
_ledState[c] = i;
|
||||
_ledState[c+1] = 2 + random8(_speed_lo, _speed_hi);
|
||||
c += 2;
|
||||
i += (1 + random8(_density));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void darkNow() {
|
||||
|
||||
for (uint8_t i=0; i < LEDS_PER_NODE; i++)
|
||||
{
|
||||
_localLeds[i] = CRGB::Black;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void rainbowDefault() {
|
||||
|
||||
for ( uint8_t i = 0; i < LEDS_PER_NODE; i++) {
|
||||
_localLeds[i] = ColorFromPalette( rainbowPalette_p, (_current_color_preset % 16) * 16, 24, LINEARBLEND );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void stripesDefault() {
|
||||
|
||||
uint8_t _idx = beatsin8(20, 0, 5);
|
||||
// Serial.println(_idx);
|
||||
|
||||
for ( uint8_t i = 0; i < LEDS_PER_NODE; i++) {
|
||||
if (_idx == (i % 6)) {
|
||||
_localLeds[i] = ColorFromPalette( rainbowPalette_p, (_current_color_preset % 16) * 16, 24, LINEARBLEND );
|
||||
} else {
|
||||
_localLeds[i] = CRGB::Black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fadeInOut() {
|
||||
|
||||
uint8_t b = beatsin8(15, 5, 36);
|
||||
b = ease8InOutQuad(b);
|
||||
|
||||
for ( uint8_t i = 0; i < LEDS_PER_NODE; i++) {
|
||||
_localLeds[i] = ColorFromPalette( rainbowPalette_p, (_current_color_preset % 16) * 16, b, LINEARBLEND );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void sparkle() {
|
||||
|
||||
for (int i=0; i<LEDS_PER_NODE/2; i++) {
|
||||
|
||||
if (_ledState[2*i] == 0) {
|
||||
|
||||
break;
|
||||
|
||||
} else if (_ledState[2*i] > 0) {
|
||||
|
||||
_localLeds[ _ledState[(2*i)] ] = ColorFromPalette( rainbowPalette_p, (_current_color_preset % 16) * 16, beatsin8(_ledState[(2*i)+1], 2, 64));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void updateLEDs() {
|
||||
|
||||
if (strcmp(_current_action, "dark") == 0) {
|
||||
|
||||
darkNow();
|
||||
|
||||
} else if (strcmp(_current_action, "color_p") == 0) {
|
||||
|
||||
rainbowDefault();
|
||||
|
||||
} else if (strcmp(_current_action, "stripes_p") == 0) {
|
||||
|
||||
stripesDefault();
|
||||
|
||||
} else if (strcmp(_current_action, "faders_p") == 0) {
|
||||
|
||||
fadeInOut();
|
||||
|
||||
} else if (strcmp(_current_action, "sparkle_p") == 0) {
|
||||
|
||||
sparkle();
|
||||
|
||||
} else {
|
||||
|
||||
darkNow();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void currentPatternRun() {
|
||||
|
||||
if (_counter > TASK_RESTART_CYCLES)
|
||||
{
|
||||
Serial.println(_counter);
|
||||
ESP.restart();
|
||||
} else if ((_counter % 1000) == 0) {
|
||||
Serial.println("-------");
|
||||
Serial.println(_counter);
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
// if (node_connected == true) {
|
||||
|
||||
// updateCurrentAction();
|
||||
updateLEDs();
|
||||
|
||||
_driver.showPixels();
|
||||
_counter += 1;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
void chooseNextPattern() {
|
||||
|
||||
if ((random8() < 96) && (node_connected == true)) {
|
||||
|
||||
Serial.println("BING!");
|
||||
|
||||
if (_next_color_preset != _current_color_preset) {
|
||||
_current_color_preset = _next_color_preset;
|
||||
} else {
|
||||
_current_color_preset = (_current_color_preset + 1) % TOTAL_PRESETS;
|
||||
}
|
||||
|
||||
if ((_current_color_preset / 16) == 0) {
|
||||
|
||||
_current_action = "color_p";
|
||||
taskCurrentPatternRun.disable();
|
||||
taskCurrentPatternRun.setInterval(
|
||||
(TASK_MILLISECOND * LED_STILL_FRAME_PERIOD_MS)
|
||||
);
|
||||
taskCurrentPatternRun.enable();
|
||||
|
||||
} else if ((_current_color_preset / 16) == 1) {
|
||||
|
||||
_current_action = "stripes_p";
|
||||
taskCurrentPatternRun.disable();
|
||||
taskCurrentPatternRun.setInterval(
|
||||
(TASK_MILLISECOND * LED_SLOW_ANIMATION_FRAME_PERIOD_MS)
|
||||
);
|
||||
taskCurrentPatternRun.enable();
|
||||
|
||||
} else if ((_current_color_preset / 16) == 2) {
|
||||
|
||||
_current_action = "faders_p";
|
||||
taskCurrentPatternRun.disable();
|
||||
taskCurrentPatternRun.setInterval(
|
||||
(TASK_MILLISECOND * LED_ANIMATION_FRAME_PERIOD_MS)
|
||||
);
|
||||
taskCurrentPatternRun.enable();
|
||||
|
||||
} else {
|
||||
|
||||
_current_action = "sparkle_p";
|
||||
initSparkle();
|
||||
taskCurrentPatternRun.disable();
|
||||
taskCurrentPatternRun.setInterval(
|
||||
(TASK_MILLISECOND * LED_ANIMATION_FRAME_PERIOD_MS)
|
||||
);
|
||||
taskCurrentPatternRun.enable();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sendMessage()
|
||||
{
|
||||
|
||||
if (node_connected == true) {
|
||||
|
||||
static StaticJsonDocument<256> msg;
|
||||
|
||||
msg["currentAction"] = _current_action;
|
||||
msg["currentPattern"] = _current_color_preset;
|
||||
|
||||
String str;
|
||||
serializeJson(msg, str);
|
||||
mesh.sendBroadcast(str);
|
||||
Serial.printf("\n%s (%s) %u: Sent broadcast message: %s\n\n", "role.c_str()", "_nodePos", mesh.getNodeTime(), str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MESH callbacks
|
||||
void receivedCallback(uint32_t from, String &msg)
|
||||
{
|
||||
if (node_connected == true) {
|
||||
|
||||
Serial.printf("Received msg from %u: %s\n", from, msg.c_str());
|
||||
|
||||
static StaticJsonDocument<256> root;
|
||||
deserializeJson(root, msg);
|
||||
|
||||
if( root["currentPattern"] )
|
||||
{
|
||||
_next_color_preset = root["currentPattern"].as<uint8_t>() ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void newConnectionCallback(uint32_t nodeId)
|
||||
{
|
||||
Serial.printf("%s %u: New Connection from nodeId = %u\n", "role.c_str()", mesh.getNodeTime(), nodeId);
|
||||
// checkLeadership() ;
|
||||
}
|
||||
|
||||
|
||||
void changedConnectionCallback()
|
||||
{
|
||||
|
||||
Serial.printf("%s %u: Changed connections %s\n", "role.c_str()", mesh.getNodeTime(), mesh.subConnectionJson().c_str());
|
||||
|
||||
int _numNodes = mesh.getNodeList().size();
|
||||
|
||||
if (_numNodes > 0) {
|
||||
|
||||
node_connected = true;
|
||||
|
||||
} else {
|
||||
|
||||
node_connected = false;
|
||||
Serial.println(_counter);
|
||||
ESP.restart();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void nodeTimeAdjustedCallback(int32_t offset)
|
||||
{
|
||||
Serial.printf("%s: Adjusted time %u. Offset = %d\n", "role.c_str()", mesh.getNodeTime(), offset);
|
||||
}
|
||||
|
||||
|
||||
void delayReceivedCallback(uint32_t from, int32_t delay)
|
||||
{
|
||||
Serial.printf("Delay to node %u is %d us\n", from, delay);
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
|
||||
This directory is intended for PlatformIO Test Runner and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
||||
Reference in New Issue
Block a user