Message |
|
TcMenu is mainly static for the reasons discussed earlier, there's a few small allocations at runtime, with things that are generally not known upfront, but they are pretty small, maybe adding 500 or 600 bytes extra on an AVR. Menu Items structures are completely static, it is task-manager, switches and possibly the rendering that may need to allocate at runtime - they do so once and don't let go of the memory.
I did notice that all the required support tcmenu needs takes up a substantial amount of room. I'm currently at 29400bytes Flash, and 1065 Ram
For what it's doing that is pretty small, an Uno is on the edge of what we can support, and in some ways, it's been holding back what we can do on bigger boards. Don't forget that includes all the parts of Arduino we're using, your display code, any Wire, Serial libraries etc. Only the smallest menu will work on an Uno. You'd struggle to write a browser-side javascript menu program that would fit in 30K, let alone a full program with all runtime included
I was under the impression that the compiler would look at all variables, functions and objects, and when they are called in say, the setup() function,
Linking and memory allocation in C++ is a huge topic, we cannot cover it here. The basic rule is stick to statically allocated memory when you can, especially on smaller boards.
|
|
|
That said, as I understand it, globals are bad practice and should be avoided
In the embedded world runtime memory allocation tends to be minimised, you normally see globals used a bit more often.
In the future we may make it possible to have menu callbacks that is based on an implementation of an interface as an option, similar to taskManager and switches. But I would hazard a guess that the vast majority would want that statically allocated at compile time.
TcMenu itself is a hybrid, it does do some dynamic memory allocation during setup, but we try to avoid using new after setup completes. Otherwise we could limit the audience who would use it.
Don’t forget that even the boards that sound huge has less available memory than you may expect after RTOS has started.
|
|
|
Testing so far:
* ESP32 with ILI9341 320x240 display using TFT_eSPI library with double buffering.
Previously tested on, but interfaces need very minor work:
* ESP32 with ILI9341 320x240 display using AdafruitGFX library
* ESP8266 with SH1106 132x64 unit using the u8g2 driver.
* Mega2560 AVR using 20x4 display
* Arduino Uno using 16x2 display
Next steps:
* Support for editing of multi-edit items such as Text, IpAddress, Large numbers, and date-time values.
* Write a renderer for STM32 built-in LCD driver with a 320x240 touch screen.
* Fix up all renderers to match TFT_eSPI
* Test on all our known configurations
* Fix negative values bug
* Release early beta version - that will be for evaluation purposes only
* Update the documentation on the site
|
|
|
We've reversed the way that renderers are written, 90% of the code is now in the core, the outer rendering classes for U8G2, Adafruit, TFT_eSPI, mbed OLED, and STM32 display buffer are minimal, containing only code for drwaing on that display.
This means that going forward we can support many more displays with less duplication, the displays can have unprecedented levels of configuration, bringing the rendering support up to the levels of simple UI toolkits (grids, icons, custom fonts, color palettes and spacing).
We've also rebuilt the dialog on the top of the new menu support, meaning that you'll even be able to generate custom dialogs with your own buttons, sliders, and most other types of menu-item in them.
The drawing items can be configured globally, for a submenu, or for a specific item.
As we said before, the changes are large, and we want to introduce them slowly, so we'll be starting with a BETA and building up from there. The BETA will be announced here once we've done more internal testing.
|
|
|
Here's an example of how we configure the grids and rendering in 2.0, taken from this example: https://github.com/davetcc/tcMenuLib/tree/master/examples/esp32Amplifier
// first we get the graphics factory
auto & factory = renderer.getGraphicsPropertiesFactory();
// now we add the icons that we want to use with certain menu items
const Coord iconSize(APPICONS_WIDTH, APPICONS_HEIGHT);
factory.addImageToCache(DrawableIcon(menuSettings.getId(), iconSize, DrawableIcon::ICON_XBITMAP, settingsIcon40Bits));
factory.addImageToCache(DrawableIcon(menuStatus.getId(), iconSize, DrawableIcon::ICON_XBITMAP, statusIcon40Bits));
factory.addImageToCache(DrawableIcon(menuMute.getId(), iconSize, DrawableIcon::ICON_XBITMAP, muteOffIcon40Bits, muteOnIcon40Bits));
// and now we define that row 3 of the main menu will have three columns, drawn as icons
factory.addGridPosition(&menuSettings, GridPosition(GridPosition::DRAW_AS_ICON_ONLY,
GridPosition::JUSTIFY_CENTER_NO_VALUE, 3, 1, 4, 45));
factory.addGridPosition(&menuStatus, GridPosition(GridPosition::DRAW_AS_ICON_ONLY,
GridPosition::JUSTIFY_CENTER_NO_VALUE, 3, 2, 4, 45));
factory.addGridPosition(&menuMute, GridPosition(GridPosition::DRAW_AS_ICON_ONLY,
GridPosition::JUSTIFY_CENTER_NO_VALUE, 3, 3, 4, 45));
// here is how we completely redefine the drawing of a specific item, you can also define for submenu or default
color_t specialPalette[] { ILI9341_WHITE, ILI9341_RED, ILI9341_BLACK, ILI9341_BLUE};
factory.setDrawingPropertiesForItem(ItemDisplayProperties::COMPTYPE_TITLE, menuStatus.getId(), specialPalette,
MenuPadding(4), nullptr, 4, 10, 30,
GridPosition::JUSTIFY_CENTER_WITH_VALUE );
|
|
|
We are now quite a way through the development effort for tcMenu 2.0, it improves the rendering onto graphical displays (and even LCD to a lesser extent) with some significant new functionality. For most apps, there will be no need to change anything, and even if changes are needed, they are small. We'll continue to support 1.7 for 6 months from the release date, which we think is about a month away.
We won't be releasing it directly like prior release as it's quite a large release. Instead, we'll start with a beta version that will be available soon.
Some of the major highlights will be:
1. All the renderers now share a common base, meaning they all share far more of the code than before, this means we've been able to invest far more time into the core renderer than we could previously.
2. The U8G2 renderer will have a custom byte function for I2C displays, it yields more frequently to taskmanager, making the app feel more fluid.
3. We've reworked the way you work with graphics, it's now more like an embedded UI with grids, font, color and padding overrides.
4. It is possible to present actionable items with icons.
5. Touch screens are now supported, the first version will support resistive touch screens, with additional options following later.
5. We will support TFT_eSPI for much faster rendering, and massively improved double-buffered rendering.
6. Dialogs are now based directly on menu items and you can add additional menu items to them (you can also style / skin them like everything else too).
Most of the work is already in the repo on the master branch.
|
|
|
If you can give me a sample program that deals with the touch sensors, I'll turn it into an IoAbstraction so you can use it with tcMenu. I have an ESP32 board as one of my main development boards, so testing should be easy.
What I'd need to avoid needing to read the docs:
* How to set up a pin as a touch sensor and prepare it for use.
* How to read the current value of a touch sensor.
* Anything else specific to the touch sensor support.
* Any circuit that I'd need to build in order to test at least one pin.
|
|
|
For the benefit of others looking at this forum. We've checked this ourselves, both with and without a hardware debugger on ESP32, we cannot recreate this issue.
If anyone else is able to recreate it, please provide the hardware and steps here and we'll look into it without delay.
|
|
|
It can sometimes be a bit tricky, PlatformIO picks up libraries that should be included by looking at your main file and also header files by default IIRC. I recommend if you're running into problems you set the mode to chain+, you can read about that over on the platformIO site: https://docs.platformio.org/en/latest/librarymanager/ldf.html
The easiest option is to add the IoAbstraction.h header file include directly to your main file, that is the file containing either main() or setup() and loop(), I think that will make it pick up the dependency. Worst case if you still don't pick it up, add the dependency directly in the platformio.ini file (see the docs above).
|
|
|
At the moment you can't move the callbacks out of main when using the designer, it will just put them back into the main file again on the next pass, thinking that they are missing. Has tcMenu designer detected your main class with that name?
The designer comes with a few limitations on how the menu software is put together, these make it trivial to build most applications, but if you don't follow the same pattern, you just make life difficult for yourself.
The path of least resistance is to keep the callbacks in your project main, and refer to the objects in their various places. You can still keep all your other code in separate class files.
|
|
|
So here's a few starter points, quite long so it may take me a few iterations to get through it.
Instead of your control method that currently needs to do the timing loop, why not create a taskManager event or task that does this instead. TcMenu is built on top of taskManager, so it's there for you to use by default. Essentially, you could either extend BaseEvent and register an event, or you could schedule work to be done (once or fixed rate). Take a look at the task manager docs: https://www.thecoderscorner.com/products/arduino-libraries/taskmanager-io/ and there are many examples packaged with it too, including demonstrating multithreaded use with ESP32 and mbed.
On the design front, we can't do much in the short term to change where tcMenu puts the callback functions, but I would recommend something more like:
void CALLBACK_FUNCTION cycleFrequency(int id)
{
auto cycles = int(menuTestSettingsCyclesPerSecond.getAsFloatingPointValue()); //update pnuma1 with value
pnuma1.onCycleFrequencyChanged(cycles);
}
The callback functions are actually global, they are scoped using extern so that they are available everywhere. You just need to include the projectName_menu.h in any file you want to use them. But that should not be of interest to users, as they probably shouldn't be called directly.
If I define a global instance of PnumaControl, within REPTestOS, I have access to it within the callback functions which I've moved to REPTestOS
If I understand this correctly, you want to access your global instance in different places, this is a bit beyond to scope of this forum to be honest, it's more a C++ question. But hey let's give it a go here:
If I had class Abc that I wanted to access in various places.
Abc.h
class Abc {
private:
int a;
int b;
int c;
public:
void onAChanged(int val) {
a = val
}
};
// forward declare Abc here, so it can be used anywhere
extern Abc myGlobalAbc;
abc.cpp
// declare it global here
Abc myGlobalAbc;
main.cpp
#include <abc.h>
// use myGlobalAbc here
Also, are you confusing classes with libraries, or are you putting each class in it's own Arduino / PIO library?
|
|
|
It would most certainly be quite easy to integrate, I would imagine there would be many ways to do it, but the easiest may be to make a simple IoAbstraction implementation around the touch sensors.
If you did this you would then not need an RTOS task, instead you'd just pass your new IoAbstraction to switches instead of the regular one. If you did this you'd get all the debouncing and everything else for free. However, you could just service the keyboard yourself and just tell tcMenu when changes occur, again with the caveat that this must happen on the right thread, see the execute example below for that. All the methods to move around menu items are on menuMgr: https://www.thecoderscorner.com/products/arduino-libraries/tc-menu/menumanager-and-iteration/
An IoAbstraction is a simple interface that exposes methods similar to the Arduino pin functions. So you would need to implement the setup of each numbered sensor and the acquisition of data, you could skip anything to do with writing.
For example a starting point to look at would be: https://github.com/davetcc/IoAbstraction/blob/master/src/DfRobotInputAbstraction.h
The base class BasicIoAbstraction is implemented in https://github.com/davetcc/IoAbstraction/blob/master/src/BasicIoAbstraction.h
On the subject of RTOS, yes you can use RTOS and taskmanager / tcMenu at the same time, yes with a few limitations. You can create as many threads as you like, you can schedule work to be done from those tasks by using any task manager scheduling function. You can raise any events against task manager either from an interrupt or another thread. However, and this applies generally to all multithreaded software, you need to be very careful about object state. Currently, menu items are not thread-safe, you should only interact with them from taskManager.
However, if you have another thread, and you wanted to update a menu item you either create an event, or do something like
void runningOnAnotherThread() {
taskManager.execute(someTaskToExecuteOnTaskManagerThread);
}
Think of tcMenu like you would a desktop UI, it has a compositing thread, and you should honour that when working with menu items. I recommend you read the task manager documentation thoroughly around creating events and muli-threading before proceeding.
|
|
|
For the benefit of others too, I'll expand on this a little.
Apart from the OLED mbed support, where we provide a modified version of the AdafruitGFX library, all other display libraries are written by third parties, and we provide the glue code to allow you to use it in tcMenu without writing a line of code.
Along with the list below, you can look at the display plugins section here where there's a more complete list with associated documentation: https://www.thecoderscorner.com/products/arduino-libraries/tc-menu/
Arduino
Arduino: For OLEDs SSD1306, SH1106 and many other variants
On Uno and other ATMega328 based processors with limited memory - use SSD1306Ascii
On any other processor - use u8g2
For Colour and other monochrome TFTs
ESP32 and STM32 - For most larger color TFTs we are integrating the excellent TFT_eSPI library that provides much faster drawing than other options. Due in 1.8.
Other Arduino devices: Use AdafruitGFX in nearly all cases, almost invariably these displays will not be usable with an Uno / ATMega328. You're better with 32-bit boards for larger color displays, where the SPI speed can be boosted.
For 16x2, 20x4 and other LCD units
Use the inbuilt LiquidCrystal plugin.
Mbed
Mbed: For OLEDs SSD1306 and SH1106
Use the inbuilt AdafruitGFX fork in the designer.
For Colour and other monochrome TFTs
Due in 1.8 - for STM32 boards will be able to support the inbuilt frame buffer.
For 16x2, 20x4 and other LCD units
Use the inbuilt LiquidCrystal plugin.
|
|
|
What should I do to handle this OLED (SSD1306) with ESP32?
That is easier, use the u8g2 plugin.
|
|
|
I don’t think you can to be honest. But you should ask the library provider, as the errors are in their library. We just provide some glue code to make it work with tcMenu. On such a large processor why not u8g2 with an SPI OLED?
|
|
|
|
|