Skip to content

Commit d318070

Browse files
committed
#243 menu builder added and one sketch refactored to start using it.
1 parent f763ab6 commit d318070

10 files changed

Lines changed: 1287 additions & 132 deletions

examples/esp/esp32s2Saola/esp32s2Saola.emf

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,50 @@
294294
"visible": true,
295295
"staticDataInRAM": false
296296
}
297+
},
298+
{
299+
"parentId": 0,
300+
"type": "subMenu",
301+
"item": {
302+
"secured": false,
303+
"name": "IoT Setup",
304+
"id": 22,
305+
"eepromAddress": -1,
306+
"readOnly": false,
307+
"localOnly": false,
308+
"visible": true,
309+
"staticDataInRAM": false
310+
}
311+
},
312+
{
313+
"parentId": 22,
314+
"type": "textItem",
315+
"defaultValue": "",
316+
"item": {
317+
"textLength": 5,
318+
"itemType": "IP_ADDRESS",
319+
"name": "IP Addr",
320+
"id": 23,
321+
"eepromAddress": -1,
322+
"readOnly": false,
323+
"localOnly": false,
324+
"visible": true,
325+
"staticDataInRAM": false
326+
}
327+
},
328+
{
329+
"parentId": 22,
330+
"type": "customBuildItem",
331+
"item": {
332+
"menuType": "REMOTE_IOT_MONITOR",
333+
"name": "IoT Monitor1",
334+
"id": 24,
335+
"eepromAddress": -1,
336+
"readOnly": false,
337+
"localOnly": true,
338+
"visible": true,
339+
"staticDataInRAM": false
340+
}
297341
}
298342
],
299343
"codeOptions": {

examples/esp/esp32s2Saola/esp32s2Saola.ino

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,32 +23,53 @@
2323
bool connectedToWiFi = false;
2424
void startWiFiAndListener();
2525

26-
// we add two widgets that show both the connection status and wifi signal strength
27-
// these are added to the renderer and rendered upon any change.
26+
// we add two widgets, one generated by tcMenu Designer Bitmap and Widget Creator, and the inbuilt Wi-Fi widget
27+
// START widgets
28+
2829
// https://tcmenu.github.io/documentation/arduino-libraries//tc-menu/rendering-with-tcmenu-lcd-tft-oled
2930
TitleWidget wifiWidget(iconsWifi, 5, 16, 12);
3031

32+
using namespace tcgfx;
33+
34+
// XBM_LSB_FIRST width=12, height=12, size=24
35+
// auto size = Coord(12, 12);
36+
const uint8_t myWidgetWidIcon0[] PROGMEM = {
37+
0x00,0x00,0x8e,0x03,0x51,0x04,0x51,0x04,0x51,0x04,0x51,0x04,0x51,0x04,0x51,0x04,0x59,0x06,0x5d,0x07,
38+
0x5d,0x07,0x8e,0x03
39+
};
40+
// XBM_LSB_FIRST width=12, height=12, size=24
41+
// auto size = Coord(12, 12);
42+
const uint8_t myWidgetWidIcon1[] PROGMEM = {
43+
0x00,0x00,0x8e,0x03,0xd7,0x05,0xd7,0x05,0xd3,0x04,0x51,0x04,0x51,0x04,0x51,0x04,0x51,0x04,0x51,0x04,
44+
0x51,0x04,0x8e,0x03
45+
};
46+
const uint8_t* const myWidgetWidIcons[] PROGMEM = { myWidgetWidIcon0, myWidgetWidIcon1 };
47+
48+
// See https://tcmenu.github.io/documentation/arduino-libraries//tc-menu/creating-and-using-bitmaps-menu/
49+
TitleWidget myWidgetWidget(myWidgetWidIcons, 2, 12, 12, nullptr);
50+
51+
// END widgets
52+
3153
void setup() {
3254
// before proceeding, we must start wire and serial, then call setup menu.
3355
Serial.begin(115200);
3456
serdebugF("Starting ESP32-S2 example");
3557
SPI.begin(36, 37, 35, -1);
3658

37-
EEPROM.begin(512);
38-
3959
setupMenu();
4060

4161
// always call load after setupMenu, as the EEPROM you chose in initialised only after this setupMenu()
4262
menuMgr.load();
4363

4464
// set the number of rows in the list.
45-
menuExtrasMyList.setNumberOfRows(42);
65+
getListItemById(EXTRAS_LIST_ID).setNumberOfRows(42);
4666

4767
// next start WiFi and register our wifi widget
4868
startWiFiAndListener();
4969

5070
auto themeBuilder = TcThemeBuilder(renderer);
5171
themeBuilder.addingTitleWidget(wifiWidget);
72+
themeBuilder.addingTitleWidget(myWidgetWidget);
5273

5374
// lastly we capture when the root title is pressed present a standard version dialog.
5475
setTitlePressedCallback([](int titleCb) {
@@ -61,11 +82,13 @@ void loop() {
6182
}
6283

6384
void startWiFiAndListener() {
85+
TextMenuItem& ssidMenuItem = getTextItemById(CONNECTIVITY_SSID_ID);
86+
TextMenuItem& passphraseMenuItem = getTextItemById(CONNECTIVITY_PASSCODE_ID);
6487
// You can choose between station and access point mode by setting the connectivity/Wifi Mode option to your
6588
// own choice
66-
if(menuConnectivityWiFiMode.getCurrentValue() == MENU_WIFIMODE_STATION) {
89+
if(asEnumItem(getMenuItemById(CONNECTIVITY_WIFI_MODE_ID)).getCurrentValue() == MENU_WIFIMODE_STATION) {
6790
// we are in station mode
68-
WiFi.begin(menuConnectivitySSID.getTextValue(), menuConnectivityPasscode.getTextValue());
91+
WiFi.begin(ssidMenuItem.getTextValue(), passphraseMenuItem.getTextValue());
6992
WiFi.mode(WIFI_STA);
7093
serdebugF("Connecting to Wifi using settings from connectivity menu");
7194
}
@@ -74,25 +97,34 @@ void startWiFiAndListener() {
7497
WiFi.mode(WIFI_AP);
7598
char ssid[25];
7699
char pwd[25];
77-
copyMenuItemValueDefault(&menuConnectivitySSID, ssid, sizeof ssid, "tcmenu");
78-
copyMenuItemValueDefault(&menuConnectivityPasscode, pwd, sizeof pwd, "secret");
100+
copyMenuItemValueDefault(&ssidMenuItem, ssid, sizeof ssid, "tcmenu");
101+
copyMenuItemValueDefault(&passphraseMenuItem, pwd, sizeof pwd, "secret");
79102
WiFi.softAP(ssid, pwd);
80103
serdebugF3("Started up in AP mode, connect with ", ssid, pwd);
81104
}
82105

83-
// now monitor the wifi level every second and report it in a widget.
84-
taskManager.scheduleFixedRate(1000, [] {
106+
//
107+
// Here we use the inbuilt task manager to schedule something to run every second. To use
108+
// it you simply provide either a function callback or a lambda as we do here.
109+
//
110+
taskManager.schedule(repeatSeconds(1), [] {
111+
// check the wifi connection status
85112
if(WiFi.status() == WL_CONNECTED) {
86113
if(!connectedToWiFi) {
114+
// we are fully connected, so we now get the address that DHCP gave us to put into
115+
// the Ip Address item.
87116
IPAddress localIp = WiFi.localIP();
88117
Serial.print("Now connected to WiFi");
89118
Serial.println(localIp);
90-
menuConnectivityIPAddress.setIpAddress(localIp[0], localIp[1], localIp[2], localIp[3]);
119+
getIpAddressItemById(CONNECTIVITY_IP_ADDR_ID).setIpAddress(localIp[0], localIp[1], localIp[2], localIp[3]);
91120
connectedToWiFi = true;
92121
}
122+
123+
// if the networking is up, then we always render the current signal strength in the title widget.
93124
wifiWidget.setCurrentState(fromWiFiRSSITo4StateIndicator(WiFi.RSSI()));
94125
}
95126
else {
127+
// We've not got networking, set it
96128
connectedToWiFi = false;
97129
wifiWidget.setCurrentState(0);
98130
}
@@ -124,7 +156,7 @@ int CALLBACK_FUNCTION fnExtrasMyListRtCall(RuntimeMenuItem* item, uint8_t row, R
124156
}
125157

126158
void CALLBACK_FUNCTION onListSelected(int id) {
127-
Serial.print("List item select "); Serial.println(menuExtrasMyList.getActiveIndex());
159+
Serial.print("List item select "); Serial.println(getListItemById(EXTRAS_LIST_ID).getActiveIndex());
128160
}
129161

130162

examples/esp/esp32s2Saola/esp32s2Saola_menu.cpp

Lines changed: 35 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <tcMenu.h>
1414
#include "esp32s2Saola_menu.h"
1515
#include "einkThemeBuilderBlock.h"
16+
#include "TcMenuBuilder.h"
1617

1718
// Global variable declarations
1819
const PROGMEM ConnectorLocalInfo applicationInfo = { "ESP32-S2 Saola board", "b447b433-fe4f-4ce7-8746-d94bfeefc707" };
@@ -27,76 +28,59 @@ EthernetInitialisation ethernetInitialisation(&server);
2728
EthernetTagValTransport ethernetTransport;
2829
TagValueRemoteServerConnection ethernetConnection(ethernetTransport, ethernetInitialisation);
2930

30-
// Global Menu Item declarations
31-
const PROGMEM char pgmStrConnectivityAuthenticatorText[] = { "Authenticator" };
32-
EepromAuthenticationInfoMenuItem menuConnectivityAuthenticator(pgmStrConnectivityAuthenticatorText, NO_CALLBACK, 20, nullptr);
33-
const PROGMEM char pgmStrConnectivityIoTMonitorText[] = { "IoT Monitor" };
34-
RemoteMenuItem menuConnectivityIoTMonitor(pgmStrConnectivityIoTMonitorText, 19, &menuConnectivityAuthenticator);
35-
const PROGMEM AnyMenuInfo minfoConnectivityIPAddress = { "IP Address", 15, 0xffff, 0, NO_CALLBACK };
36-
IpAddressMenuItem menuConnectivityIPAddress(&minfoConnectivityIPAddress, IpAddressStorage(127, 0, 0, 1), &menuConnectivityIoTMonitor, INFO_LOCATION_PGM);
37-
const char enumStrConnectivityWiFiMode_0[] PROGMEM = "Station";
38-
const char enumStrConnectivityWiFiMode_1[] PROGMEM = "Soft AP";
39-
const char* const enumStrConnectivityWiFiMode[] PROGMEM = { enumStrConnectivityWiFiMode_0, enumStrConnectivityWiFiMode_1 };
40-
const PROGMEM EnumMenuInfo minfoConnectivityWiFiMode = { "WiFi Mode", 18, 64, 1, NO_CALLBACK, enumStrConnectivityWiFiMode };
41-
EnumMenuItem menuConnectivityWiFiMode(&minfoConnectivityWiFiMode, 0, &menuConnectivityIPAddress, INFO_LOCATION_PGM);
42-
const PROGMEM AnyMenuInfo minfoConnectivityPasscode = { "Passcode", 17, 42, 0, NO_CALLBACK };
43-
TextMenuItem menuConnectivityPasscode(&minfoConnectivityPasscode, "", 22, &menuConnectivityWiFiMode, INFO_LOCATION_PGM);
44-
const PROGMEM AnyMenuInfo minfoConnectivitySSID = { "SSID", 16, 20, 0, NO_CALLBACK };
45-
TextMenuItem menuConnectivitySSID(&minfoConnectivitySSID, "", 22, &menuConnectivityPasscode, INFO_LOCATION_PGM);
46-
const PROGMEM SubMenuInfo minfoConnectivity = { "Connectivity", 14, 0xffff, 0, NO_CALLBACK };
47-
BackMenuItem menuBackConnectivity(&minfoConnectivity, &menuConnectivitySSID, INFO_LOCATION_PGM);
48-
SubMenuItem menuConnectivity(&minfoConnectivity, &menuBackConnectivity, nullptr, INFO_LOCATION_PGM);
49-
const PROGMEM AnyMenuInfo minfoExtrasMyList = { "My List", 13, 0xffff, 0, onListSelected };
50-
ListRuntimeMenuItem menuExtrasMyList(&minfoExtrasMyList, 0, fnExtrasMyListRtCall, nullptr, INFO_LOCATION_PGM);
51-
const PROGMEM AnyMenuInfo minfoExtrasColor = { "Color", 12, 16, 0, NO_CALLBACK };
52-
Rgb32MenuItem menuExtrasColor(&minfoExtrasColor, RgbColor32(0, 0, 0), false, &menuExtrasMyList, INFO_LOCATION_PGM);
53-
const PROGMEM AnyMenuInfo minfoExtrasText = { "Text", 11, 11, 0, NO_CALLBACK };
54-
TextMenuItem menuExtrasText(&minfoExtrasText, "", 5, &menuExtrasColor, INFO_LOCATION_PGM);
55-
const PROGMEM SubMenuInfo minfoExtras = { "Extras", 10, 0xffff, 0, NO_CALLBACK };
56-
BackMenuItem menuBackExtras(&minfoExtras, &menuExtrasText, INFO_LOCATION_PGM);
57-
SubMenuItem menuExtras(&minfoExtras, &menuBackExtras, &menuConnectivity, INFO_LOCATION_PGM);
58-
const PROGMEM BooleanMenuInfo minfoDoorOpen = { "Door Open", 5, 10, 1, NO_CALLBACK, NAMING_YES_NO };
59-
BooleanMenuItem menuDoorOpen(&minfoDoorOpen, false, &menuExtras, INFO_LOCATION_PGM);
60-
const char enumStrFoods_0[] PROGMEM = "Pizza";
61-
const char enumStrFoods_1[] PROGMEM = "Pasta";
62-
const char enumStrFoods_2[] PROGMEM = "Salad";
63-
const char enumStrFoods_3[] PROGMEM = "Pie";
64-
const char* const enumStrFoods[] PROGMEM = { enumStrFoods_0, enumStrFoods_1, enumStrFoods_2, enumStrFoods_3 };
65-
const PROGMEM EnumMenuInfo minfoFoods = { "Foods", 4, 8, 3, NO_CALLBACK, enumStrFoods };
66-
EnumMenuItem menuFoods(&minfoFoods, 0, &menuDoorOpen, INFO_LOCATION_PGM);
67-
const PROGMEM AnalogMenuInfo minfoHalves = { "Halves", 3, 6, 200, NO_CALLBACK, 0, 2, "" };
68-
AnalogMenuItem menuHalves(&minfoHalves, 0, &menuFoods, INFO_LOCATION_PGM);
69-
const PROGMEM AnalogMenuInfo minfoDecEdit = { "Dec Edit", 2, 4, 1000, NO_CALLBACK, 0, 10, "oC" };
70-
AnalogMenuItem menuDecEdit(&minfoDecEdit, 0, &menuHalves, INFO_LOCATION_PGM);
71-
const PROGMEM AnalogMenuInfo minfoIntEdit = { "Int Edit", 1, 2, 100, NO_CALLBACK, 0, 1, "%" };
72-
AnalogMenuItem menuIntEdit(&minfoIntEdit, 0, &menuDecEdit, INFO_LOCATION_PGM);
73-
const PROGMEM AnyMenuInfo minfoHibernate = { "Hibernate", 21, 0xffff, 0, onHibernate };
74-
ActionMenuItem menuHibernate(&minfoHibernate, &menuIntEdit, INFO_LOCATION_PGM);
31+
const char* enumWiFiMode[] = { "Station", "Soft AP" };
32+
const char* enumFoodsArray[] = { "Pizza", "Pasta", "Salad", "Pie" };
33+
34+
void buildMenu(TcMenuBuilder& builder) {
35+
builder.usingDynamicEEPROMStorage()
36+
.actionItem(HIBERNATE_ID, "Hibernate", NoMenuFlags, onHibernate)
37+
.analogBuilder(INT_EDIT_ID, "Int Edit", ROM_SAVE, NoMenuFlags, 4)
38+
.offset(0).divisor(1).maxValue(100).unit("%").endItem()
39+
.analogBuilder(DEC_EDIT_ID, "Dec Edit", ROM_SAVE, NoMenuFlags, 0)
40+
.offset(0).divisor(100).maxValue(1000).unit("oC").endItem()
41+
.analogBuilder(HALVES_ID, "Halves", ROM_SAVE, MenuFlags().readOnly(), 0)
42+
.offset(0).divisor(2).maxValue(100).unit("").endItem()
43+
.enumItem(FOODS_ID, "Foods", ROM_SAVE, enumFoodsArray, 4, NoMenuFlags)
44+
.boolItem(DOOR_OPEN_ID, "Door Open", ROM_SAVE, NAMING_YES_NO, NoMenuFlags)
45+
.subMenu(EXTRAS_ID, "Extras", NoMenuFlags)
46+
.textItem(EXTRAS_TEXT_ID, "Text", ROM_SAVE, 10, NoMenuFlags)
47+
.rgb32Item(EXTRAS_RGB_ID, "Color", ROM_SAVE, false, NoMenuFlags)
48+
.listItemRtCustom(EXTRAS_LIST_ID, "My List", 10, fnExtrasMyListRtCall, NoMenuFlags)
49+
.endSub()
50+
.subMenu(CONNECTIVITY_ID, "Connectivity", NoMenuFlags)
51+
.textItem(CONNECTIVITY_SSID_ID, "SSID", ROM_SAVE, 20, NoMenuFlags)
52+
.textItem(CONNECTIVITY_PASSCODE_ID, "Passcode", ROM_SAVE, 20, NoMenuFlags)
53+
.enumItem(CONNECTIVITY_WIFI_MODE_ID, "WiFi Mode", ROM_SAVE, enumWiFiMode, 2, NoMenuFlags)
54+
.ipAddressItem(CONNECTIVITY_IP_ADDR_ID, "IP Address", DONT_SAVE, NoMenuFlags)
55+
.remoteConnectivityMonitor(CONNECTIVITY_MON_ID, "IoT Monitor", MenuFlags().localOnly())
56+
.eepromAuthenticationItem(CONNECTIVITY_AUTH_ID, "Authenticator", MenuFlags().localOnly())
57+
.endSub();
58+
}
7559

7660
void setupMenu() {
61+
auto builder = TcMenuBuilder(&MenuManager::ROOT);
62+
buildMenu(builder);
63+
7764
// First we set up eeprom and authentication (if needed).
7865
setSizeBasedEEPROMStorageEnabled(false);
7966
glEspRom.init();
8067
menuMgr.setEepromRef(&glEspRom);
8168
authManager.initialise(menuMgr.getEepromAbstraction(), 200);
8269
menuMgr.setAuthenticator(&authManager);
83-
// Now add any readonly, non-remote and visible flags.
84-
menuConnectivityIoTMonitor.setLocalOnly(true);
85-
menuConnectivityAuthenticator.setLocalOnly(true);
8670

8771
// Code generated by plugins and new operators.
8872
display.init(115200, true, 10, false);
8973
display.setRotation(0);
9074
renderer.setUpdatesPerSecond(1);
9175
switches.init(internalDigitalIo(), SWITCHES_POLL_EVERYTHING, true);
92-
menuMgr.initFor4WayJoystick(&renderer, &menuHibernate, 2, 1, 3, 4, -1, 20);
76+
menuMgr.initFor4WayJoystick(&renderer, builder.getRootItem(), 2, 1, 3, 4, -1, 20);
9377
remoteServer.addConnection(&ethernetConnection);
9478
applyTheme(renderer);
9579

9680
// We have an IoT monitor, register the server
97-
menuConnectivityIoTMonitor.setRemoteServer(remoteServer);
81+
getIoTRemoteMenuById(CONNECTIVITY_MON_ID).setRemoteServer(remoteServer);
9882

9983
// We have an EEPROM authenticator, it needs initialising
100-
menuConnectivityAuthenticator.init();
84+
getAuthenticationMenuById(CONNECTIVITY_AUTH_ID).init();
10185
}
10286

examples/esp/esp32s2Saola/esp32s2Saola_menu.h

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,29 +37,26 @@ extern EthernetInitialisation ethernetInitialisation;
3737
// Any externals needed by IO expanders, EEPROMs etc
3838
extern EspPreferencesEeprom glEspRom;
3939

40-
// Global Menu Item exports
41-
extern EepromAuthenticationInfoMenuItem menuConnectivityAuthenticator;
42-
extern RemoteMenuItem menuConnectivityIoTMonitor;
43-
extern IpAddressMenuItem menuConnectivityIPAddress;
44-
extern EnumMenuItem menuConnectivityWiFiMode;
45-
extern TextMenuItem menuConnectivityPasscode;
46-
extern TextMenuItem menuConnectivitySSID;
47-
extern BackMenuItem menuBackConnectivity;
48-
extern SubMenuItem menuConnectivity;
49-
extern ListRuntimeMenuItem menuExtrasMyList;
50-
extern Rgb32MenuItem menuExtrasColor;
51-
extern TextMenuItem menuExtrasText;
52-
extern BackMenuItem menuBackExtras;
53-
extern SubMenuItem menuExtras;
54-
extern BooleanMenuItem menuDoorOpen;
55-
extern EnumMenuItem menuFoods;
56-
extern AnalogMenuItem menuHalves;
57-
extern AnalogMenuItem menuDecEdit;
58-
extern AnalogMenuItem menuIntEdit;
59-
extern ActionMenuItem menuHibernate;
40+
#define HIBERNATE_ID 21
41+
#define INT_EDIT_ID 1
42+
#define DEC_EDIT_ID 2
43+
#define HALVES_ID 3
44+
#define FOODS_ID 4
45+
#define DOOR_OPEN_ID 5
46+
#define EXTRAS_ID 6
47+
#define EXTRAS_TEXT_ID 11
48+
#define EXTRAS_RGB_ID 12
49+
#define EXTRAS_LIST_ID 13
50+
#define CONNECTIVITY_ID 14
51+
#define CONNECTIVITY_SSID_ID 15
52+
#define CONNECTIVITY_PASSCODE_ID 16
53+
#define CONNECTIVITY_WIFI_MODE_ID 17
54+
#define CONNECTIVITY_IP_ADDR_ID 18
55+
#define CONNECTIVITY_MON_ID 19
56+
#define CONNECTIVITY_AUTH_ID 20
6057

6158
// Provide a wrapper to get hold of the root menu item and export setupMenu
62-
inline MenuItem& rootMenuItem() { return menuHibernate; }
59+
inline MenuItem& rootMenuItem() { return *getMenuItemById(HIBERNATE_ID); }
6360
void setupMenu();
6461

6562
// Callback functions must always include CALLBACK_FUNCTION after the return type

0 commit comments

Comments
 (0)