Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom device #214

Closed
wants to merge 55 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
cdde47b
add custom device
elral Oct 20, 2022
898def5
deactivate custom device per default
elral Oct 20, 2022
715add9
increase no. callbacks for Custom Device
elral Oct 21, 2022
d343748
consider upper/lower case
elral Oct 21, 2022
1a80601
custom .json files added + comments
elral Oct 24, 2022
891949b
Merge branch 'main' into Custom_Device
elral Dec 9, 2022
7cc3320
failure from merging main
elral Dec 15, 2022
ee3b4ba
add Nano to custom devices
elral Dec 15, 2022
0972884
Merge branch 'MobiFlight:main' into Custom_Device
elral Jan 6, 2023
027ae2c
Merge branch 'main' into Custom_Device
elral Jan 6, 2023
7382dca
Merge branch 'Custom_Device' of https://github.com/elral/MobiFlight-F…
elral Jan 6, 2023
6bba2af
Merge branch 'MobiFlight:main' into Custom_Device
elral Jan 6, 2023
ed14b47
solve merge error from main
elral Jan 6, 2023
844a95d
Merge branch 'main' into Custom_Device
elral Jan 16, 2023
5590524
Merge branch 'MobiFlight:main' into Custom_Device
elral Mar 19, 2023
089ecc7
adds a messageID to mark diff. values
elral Apr 2, 2023
bb94346
eliminate warnings/error
elral Apr 2, 2023
4abc3a2
fixed wrong board type
elral Apr 6, 2023
4eeb919
Pico for custom device added
elral Apr 6, 2023
0d83a87
Pico for custom device added
elral Apr 6, 2023
f8b222d
consider upper case
elral Jun 6, 2023
139cde2
wrong board type for custom board
elral Jun 17, 2023
33a97c7
Merge branch 'Custom_Device' of https://github.com/elral/MobiFlight-F…
elral Jun 17, 2023
b49b6bb
Merge branch 'main' into Custom_Device
elral Jun 19, 2023
95cbba0
keep order of commands
elral Jun 22, 2023
7038c3d
adapt to new structure
elral Jul 20, 2023
0580a15
change definition of pins to string parameter
elral Jul 22, 2023
e3d11b4
each 2nd custom device was skipped
elral Jul 24, 2023
857b514
reduce RAM usage, type/pin/config transferred as adress to eeprom fro…
elral Jul 24, 2023
b9f4eba
function not required anymore
elral Jul 24, 2023
a53fc88
add reading configuration from EEPROM
elral Jul 24, 2023
153b9e5
add basic code to check for different types of one custom device
elral Jul 25, 2023
7e60c80
add function to report back the custom types
elral Jul 25, 2023
b20fc8c
wrong messageID for getting custom Type, delimiter is already "," fro…
elral Jul 25, 2023
d024c7a
getting type of custom device was nonsense, fixed it
elral Jul 25, 2023
f9e83a2
messageID = 0 is shutdown of device
elral Jul 25, 2023
7551e72
some more explanations, clleaning up
elral Jul 26, 2023
e17cede
PowerSavingMode added, messageID to signed integer
elral Jul 26, 2023
ddd2eca
cleaning up platformio.ini
elral Jul 27, 2023
6b5f975
avoid modifying mobiflight.cpp if a regulary update is required
elral Jul 27, 2023
8e8c923
prepare for custom firmware version in platformio.ini, but commented
elral Jul 27, 2023
fb6c1db
move definition of MOBIFLIGHT_TYPE to platformio.ini
elral Jul 27, 2023
cea69dd
better formatting and more explanations
elral Jul 27, 2023
f40ca05
move MY_CUSTOM_TYPE to platformio.ini
elral Jul 28, 2023
18498bb
move files for custom devices to separate folder
elral Jul 28, 2023
ac02f93
consider upper_lower case in file name
elral Jul 28, 2023
854acdf
custom environments to be build in separate ini file
elral Jul 29, 2023
92c5057
more comments how to set up a custom envoronment, better naming
elral Jul 30, 2023
372f545
Custom type to device.json, better structure for custom devices, mods…
elral Sep 6, 2023
407ff92
not equired callback deleted
elral Sep 6, 2023
41f69f6
correct order to get pins and config parameter
elral Sep 6, 2023
b4aac2b
better naming
elral Sep 7, 2023
41cb16b
Merge branch 'main' into Custom_Device
elral Sep 8, 2023
8440c4d
readme with basic hints are added
elral Sep 9, 2023
96d537a
add max. custom devices in board.json files
elral Sep 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
230 changes: 230 additions & 0 deletions CustomDevices/_template/MFCustomDevice.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
#include "MFCustomDevice.h"
#include "commandmessenger.h"
#include "allocateMem.h"
#include "MyCustomClass.h"
#include "MFEEPROM.h"
extern MFEEPROM MFeeprom;

/* **********************************************************************************
The custom device pins, type and configuration is stored in the EEPROM
While loading the config the adresses in the EEPROM are transferred to the constructor
Within the constructor you have to copy the EEPROM content to a buffer
and evaluate him. The buffer is used for all 3 types (pins, type configuration),
so do it step by step.
The max size of the buffer is defined here. It must be the size of the
expected max length of these strings.

E.g. 6 pins are required, each pin could have two characters (two digits),
each pins are delimited by "|" and the string is NULL terminated.
-> (6 * 2) + 5 + 1 = 18 bytes is the maximum.
The custom type is "MyCustomClass", which means 14 characters plus NULL = 15
The configuration is "myConfig", which means 8 characters plus NULL = 9
The maximum characters to be expected is 18, so MEMLEN_STRING_BUFFER has to be at least 18
********************************************************************************** */
#define MEMLEN_STRING_BUFFER 40

// reads a string from EEPROM at given address which is '.' terminated and saves it to the buffer
bool MFCustomDevice::getStringFromEEPROM(uint16_t addreeprom, char *buffer)
{
char temp = 0;
uint8_t counter = 0;
do {
temp = MFeeprom.read_byte((addreeprom)++); // read the first character
buffer[counter++] = temp; // save character and locate next buffer position
if (counter >= MEMLEN_STRING_BUFFER) { // nameBuffer will be exceeded
return false; // abort copying to buffer
}
} while (temp != '.'); // reads until limiter '.' and locates the next free buffer position
buffer[counter - 1] = 0x00; // replace '.' by NULL, terminates the string
return true;
}

/* **********************************************************************************
Within the connector pins, a device name and a config string can be defined
These informations are stored in the EEPROM like for the other devices.
While reading the config from the EEPROM this function is called.
It is the first function which will be called for the custom device.
If it fits into the memory buffer, the constructor for the customer device
will be called
********************************************************************************** */

MFCustomDevice::MFCustomDevice(uint16_t adrPin, uint16_t adrType, uint16_t adrConfig)
{
_initialized = true;
/* **********************************************************************************
Do something which is required to setup your custom device
********************************************************************************** */

char *params, *p = NULL;
char parameter[MEMLEN_STRING_BUFFER];
uint8_t _pin1, _pin2, _pin3;

/* **********************************************************************************
read the Type from the EEPROM, copy it into a buffer and evaluate it
it's only required if your custom device handles multiple devices with
different contructors
the string get's NOT stored as this would need a lot of RAM, instead a variable
is used to store the type
********************************************************************************** */
getStringFromEEPROM(adrType, parameter);
if (strcmp(parameter, MY_CUSTOM_TYPE_1) == 0)
_customType = MY_CUSTOM_DEVICE_1;
if (strcmp(parameter, MY_CUSTOM_TYPE_2) == 0)
_customType = MY_CUSTOM_DEVICE_2;

/* **********************************************************************************
Next call the constructor of your custom device
adapt it to the needs of your constructor
if you have multiple classes, check for _customType which constructor
has to be called (e.g. if (_customType == MY_CUSTOM_DEVICE_1) ....)
********************************************************************************** */
if (_customType == 1) {
if (!FitInMemory(sizeof(MyCustomClass))) {
// Error Message to Connector
cmdMessenger.sendCmd(kStatus, F("Custom Device does not fit in Memory"));
return;
}
/* **********************************************************************************************
read the pins from the EEPROM, copy them into a buffer
********************************************************************************************** */
getStringFromEEPROM(adrPin, parameter);
/* **********************************************************************************************
split the pins up into single pins. As the number of pins could be different between
multiple devices, it is done here.
********************************************************************************************** */
params = strtok_r(parameter, "|", &p);
_pin1 = atoi(params);
params = strtok_r(NULL, "|", &p);
_pin2 = atoi(params);
params = strtok_r(NULL, "|", &p);
_pin3 = atoi(params);

/* **********************************************************************************
read the configuration from the EEPROM, copy it into a buffer.
********************************************************************************** */
getStringFromEEPROM(adrConfig, parameter);
/* **********************************************************************************
split the config up into single parameter. As the number of parameters could be
different between multiple devices, it is done here.
This is just an example how to process the init string. Do NOT use
"," or ";" as delimiter for multiple parameters but e.g. "|"
For most customer devices it is not required.
In this case just delete the following
********************************************************************************** */
uint16_t Parameter1;
char *Parameter2;
params = strtok_r(parameter, "|", &p);
Parameter1 = atoi(params);
params = strtok_r(NULL, "|", &p);
Parameter2 = params;

// In most cases you need only one of the following functions
// depending on if the constuctor takes the variables or a separate function is required
_mydevice = new (allocateMemory(sizeof(MyCustomClass))) MyCustomClass(_pin1, _pin2);
_mydevice->attach(Parameter1, Parameter2);
// if your custom device does not need a separate begin() function, delete the following
// or this function could be called from the custom constructor or attach() function
_mydevice->begin();
} else if (_customType == 2) {
if (!FitInMemory(sizeof(MyCustomClass))) {
// Error Message to Connector
cmdMessenger.sendCmd(kStatus, F("Custom Device does not fit in Memory"));
return;
}
/* **********************************************************************************************
read the pins from the EEPROM, copy them into a buffer
********************************************************************************************** */
getStringFromEEPROM(adrPin, parameter);
/* **********************************************************************************************
split the pins up into single pins, as the number of pins could be different between
multiple devices, it is done here
********************************************************************************************** */
params = strtok_r(parameter, "|", &p);
_pin1 = atoi(params);
params = strtok_r(NULL, "|", &p);
_pin2 = atoi(params);
params = strtok_r(NULL, "|", &p);
_pin3 = atoi(params);

/* **********************************************************************************
read the configuration from the EEPROM, copy it into a buffer.
********************************************************************************** */
getStringFromEEPROM(adrConfig, parameter);
/* **********************************************************************************
split the config up into single parameter. As the number of parameters could be
different between multiple devices, it is done here.
This is just an example how to process the init string. Do NOT use
"," or ";" as delimiter for multiple parameters but e.g. "|"
For most customer devices it is not required.
In this case just delete the following
********************************************************************************** */
uint16_t Parameter1;
char *Parameter2;
params = strtok_r(parameter, "|", &p);
Parameter1 = atoi(params);
params = strtok_r(NULL, "|", &p);
Parameter2 = params;

// In most cases you need only one of the following functions
// depending on if the constuctor takes the variables or a separate function is required
_mydevice = new (allocateMemory(sizeof(MyCustomClass))) MyCustomClass(_pin1, _pin2);
_mydevice->attach(Parameter1, Parameter2);
// if your custom device does not need a separate begin() function, delete the following
// or this function could be called from the custom constructor or attach() function
_mydevice->begin();
}
/* ******************************************************************************* */
}

/* **********************************************************************************
The custom devives gets unregistered if a new config gets uploaded.
Keep it as it is, mostly nothing must be changed.
It gets called from CustomerDevice::Clear()
********************************************************************************** */
void MFCustomDevice::detach()
{
_initialized = false;
if (_customType == 1) {
_mydevice->detach();
} else if (_customType == 2) {
_mydevice->detach();
}
}

/* **********************************************************************************
Within in loop() the update() function is called regularly
Within the loop() you can define a time delay where this function gets called
or as fast as possible. See comments in loop().
It is only needed if you have to update your custom device without getting
new values from the connector.
Otherwise just make a return; in the calling function.
It gets called from CustomerDevice::update()
********************************************************************************** */
void MFCustomDevice::update()
{
if (!_initialized) return;
/* **********************************************************************************
Do something if required
********************************************************************************** */
if (_customType == 1) {
_mydevice->update();
} else if (_customType == 2) {
_mydevice->update();
}
}

/* **********************************************************************************
If an output for the custom device is defined in the connector,
this function gets called when a new value is available.
It gets called from CustomerDevice::OnSet()
********************************************************************************** */
void MFCustomDevice::set(int8_t messageID, char *setPoint)
{
if (!_initialized) return;

if (_customType == 1) {
_mydevice->set(messageID, setPoint);
} else if (_customType == 2) {
_mydevice->set(messageID, setPoint);
}
}
25 changes: 25 additions & 0 deletions CustomDevices/_template/MFCustomDevice.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <Arduino.h>
#include "MyCustomClass.h"

// only required if you have more than one custom device
enum {
MY_CUSTOM_DEVICE_1 = 1,
MY_CUSTOM_DEVICE_2
};
class MFCustomDevice
{
public:
MFCustomDevice(uint16_t adrPin, uint16_t adrType, uint16_t adrConfig);
void detach();
void update();
void set(int8_t messageID, char *setPoint);

private:
bool getStringFromEEPROM(uint16_t addreeprom, char *buffer);
bool _initialized = false;
MyCustomClass *_mydevice;
uint8_t _pin1, _pin2, _pin3;
uint8_t _customType = 0;
};
71 changes: 71 additions & 0 deletions CustomDevices/_template/MyCustomClass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#include "MyCustomClass.h"

/* **********************************************************************************
This is just the basic code to set up your custom device.
Change/add your code as needed.
If you have no class and/or only less code you could also put it
into MFCustomDevice.cpp and delete this file and MyCustomClass.h
********************************************************************************** */

MyCustomClass::MyCustomClass(uint8_t Pin1, uint8_t Pin2)
{
_pin1 = Pin1;
_pin2 = Pin2;
}

void MyCustomClass::begin()
{
}

void MyCustomClass::attach(uint16_t Pin3, char *init)
{
_pin3 = Pin3;
}

void MyCustomClass::detach()
{
if (!_initialised)
return;
_initialised = false;
}

void MyCustomClass::set(int8_t messageID, char *setPoint)
{
/* **********************************************************************************
Each messageID has it's own value
check for the messageID and define what to do.
Important Remark!
MessageID == -1 will be send from the connector when Mobiflight is closed
Put in your code to shut down your custom device (e.g. clear a display)
MessageID == -2 will be send from the connector when PowerSavingMode is entered
Put in your code to enter this mode (e.g. clear a display)

********************************************************************************** */
int32_t data = atoi(setPoint);
uint16_t output;

// do something according your messageID
switch (messageID) {
case -1:
// tbd., get's called when Mobiflight shuts down
case -2:
// tbd., get's called when PowerSavingMode is entered
case 0:
output = (uint16_t)data;
data = output;
break;
case 1:
/* code */
break;
case 2:
/* code */
break;
default:
break;
}
}

void MyCustomClass::update()
{
// Do something which is required regulary
}
27 changes: 27 additions & 0 deletions CustomDevices/_template/MyCustomClass.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once

#include "Arduino.h"

/* **********************************************************************************
These defines are required to differ between multiple classes within
MFCustomDevice.cpp (see example in this file)
If you have only one class, these defines are not required as you have
not to differ.
********************************************************************************** */
#define MY_CUSTOM_TYPE_1 "MyCustomType1"
// This define should be in the second class, it's only here to show how to handle it
#define MY_CUSTOM_TYPE_2 "MyCustomType2"
class MyCustomClass
{
public:
MyCustomClass(uint8_t Pin1, uint8_t Pin2);
void begin();
void attach(uint16_t Pin3, char *init);
void detach();
void set(int8_t messageID, char *setPoint);
void update();

private:
bool _initialised;
uint8_t _pin1, _pin2, _pin3;
};
Loading
Loading