Skip to content

Commit 0403d9b

Browse files
authored
Merge pull request #1 from esp-cpp/feature/main-functionality
feat(main): implement main functionality
2 parents 846f871 + 41e0f25 commit 0403d9b

24 files changed

+1478
-42
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[submodule "components/espp"]
22
path = components/espp
33
url = [email protected]:esp-cpp/espp
4+
[submodule "components/esp-protocols"]
5+
path = components/esp-protocols
6+
url = [email protected]:espressif/esp-protocols

CMakeLists.txt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,16 @@ include($ENV{IDF_PATH}/tools/cmake/project.cmake)
88
set(EXTRA_COMPONENT_DIRS
99
"components/"
1010
"components/espp/components/"
11+
"components/esp-protocols/components"
1112
)
1213

1314
set(
1415
COMPONENTS
15-
# TODO: add additional esp-idf and espp components you want to use to the line below:
16-
"main esptool_py logger task"
16+
"main esptool_py driver lwip button display display_drivers input_drivers logger lvgl mdns socket task tt21100 wifi gui"
1717
CACHE STRING
1818
"List of components to include"
1919
)
2020

21-
# TODO: update this with your project's name
22-
project(template)
21+
project(wireless-debug-display)
2322

2423
set(CMAKE_CXX_STANDARD 20)

README.md

Lines changed: 112 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,101 @@
1-
# ESP++ Template
1+
# Wireless Debug Display
2+
3+
This repository contains an example application designed for either
4+
ESP32-WROVER-KIT or ESP32-S3-BOX (selectable via menuconfig) which listens on a
5+
UDP socket for data. It then parses that data and if it matches a certain
6+
format, it will plot the data in a graph, otherwise it will print the data to a
7+
text log for display.
8+
9+
https://github.com/esp-cpp/wireless-debug-display/assets/213467/f835922f-e17f-4f76-95ee-5d6585e84656
10+
11+
## Configuration
12+
13+
You'll need to configure the build using `idf.py set-target <esp32 or esp32s3>`
14+
and then `idf.py menuconfig` to then set the `Wireless Debug Display
15+
Configuration` which allows you to set which hardware you want to run it on, as
16+
well as the WiFi Access Point connection information (ssid/password). It also
17+
allows customization of the port of the UDP server that the debug display is
18+
running.
19+
20+
## Use
21+
22+
This code receives string data from a UDP server. It will parse that string data
23+
and determine which of the following three types of data it is:
24+
25+
* *Commands*: contain the prefix (`+++`) in the string.
26+
* *Plot data*: contain the delimiter (`::`) in the string followed by a
27+
single value which can be converted successfully to a number. If the
28+
conversion fails, the message will be printed as a log.
29+
* *Log / text data*: all data that is not a command and cannot be
30+
plotted.
31+
32+
They are parsed in that priority order.
33+
34+
Some example data (no commands) can be found in [test_data.txt](./test_data.txt).
35+
36+
A couple python scripts are provided for sending data from a computer to your
37+
logger to showcase simple UDP socket sending, as well as automatic service
38+
discovery using mDNS.
39+
40+
- [./send_to_display.py](./send_to_display.py): Uses simple UDP sockets to send
41+
messages or a file to the debug display.
42+
- [./send_to_display_mdns.py](./send_to_display_mdns.py): Uses python's
43+
`zeroconf` package to discover the wireless display on the network and then
44+
send messages or a file to the debug display. NOTE: zeroconf may not be
45+
installed / accessible within the python environment used by ESP-IDF.
46+
47+
## Sending Data to the Display
48+
49+
This display is designed to receive data from any other device on the network,
50+
though it is primarily intended for other embedded wireless devices such as
51+
other ESP-based systems. However, I have provided some scripts to help show how
52+
data can be sent from computers or other systems if you choose.
53+
54+
Assuming that your computer is also on the network (you'll need to replace the
55+
IP address below with the ip address displayed in the `info` page of the
56+
display if you don't use the mDNS version):
57+
58+
```console
59+
# this python script uses mDNS to automatically find the display on the network
60+
python ./send_to_display_mdns.py --file <file>
61+
python ./send_to_display_mdns.py --message "<message 1>" --message "<message 2>" ...
62+
# e.g.
63+
python ./send_to_display_mdns.py --file test_data.txt
64+
python ./send_to_display_mdns.py --message "Hello world" --message "trace1::0" --message "trace1::1" --message "Goodbye World"
65+
66+
# this python script uses raw UDP sockets to send data to the display on the network
67+
python ./send_to_display.py --ip <IP Address> --port <port, default 5555> --file <file>
68+
python ./send_to_display.py --ip <IP Address> --port <port, default 5555> --message "<message 1>" --message "<message 2>" ...
69+
# e.g.
70+
python ./send_to_display.py --ip 192.168.1.23 --file additional_data.txt
71+
python ./send_to_display.py --ip 192.168.1.23 --message "Hello world" --message "trace1::0" --message "trace1::1" --message "Goodbye World"
72+
```
73+
74+
### Commands
75+
76+
There are a limited set of commands in the system, which are
77+
determined by a prefix and the command itself. If the prefix is found
78+
_ANYWHERE_ in the string message (where messages are separated by
79+
newlines), then the message is determined to be a command.
280

3-
Template repository for building an ESP app with ESP++ (espp) components and
4-
ESP-IDF components.
81+
**PREFIX:** `+++` - three plus characters in a row
582

6-
## Development
83+
* **Remove Plot:** this command (`RP:` followed by the string plot name) will remove the named plot from the graph.
84+
* **Clear Plots:** this command (`CP`) will remove _all_ plots from the graph.
85+
* **Clear Logs:** this command (`CL`) will remove _all_ logs / text.
786

8-
This repository is designed to be used as a template repository - so you can
9-
sepcify this as the template repository type when creating a new repository on
10-
GitHub.
87+
### Plotting
1188

12-
After setting this as the template, make sure to update the following:
13-
- [This README](./README.md) to contain the relevant description and images of your project
14-
- The [./CMakeLists.txt](./CMakeLists.txt) file to have the components that you
15-
want to use (and any you may have added to the [components
16-
folder](./components)) as well as to update the project name
17-
- The [./main/main.cpp](./main/main.cpp) To run the main code for your app. The
18-
[main folder](./main) is also where you can put additional header and source
19-
files that you don't think belong in their own components but help keep the
20-
main code clean.
89+
Messages which contain the string `::` and which have a value that
90+
successfully and completely converts into a number are determined to
91+
be a plot. Plots are grouped by their name, which is any string
92+
preceding the `::`.
93+
94+
### Logging
95+
96+
All other text is treated as a log and written out to the log
97+
window. Note, we do not wrap lines, so any text that would go off the
98+
edge of the screen is simply not rendered.
2199

22100
## Cloning
23101

@@ -51,6 +129,22 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui
51129

52130
## Output
53131

54-
Example screenshot of the console output from this app:
132+
### Console Logs:
133+
![initial output](https://github.com/esp-cpp/wireless-debug-display/assets/213467/c20993a7-9873-4c76-bc8e-1b115f63a5e0)
134+
![receiving more info](https://github.com/esp-cpp/wireless-debug-display/assets/213467/0413e79e-018c-497e-b9d7-511481d17385)
135+
136+
### Python script:
137+
![python script](https://github.com/esp-cpp/wireless-debug-display/assets/213467/9d5d4899-3074-47b1-8d57-1ef22aa4bfba)
138+
139+
### ESP32-WROVER-KIT
140+
141+
https://github.com/esp-cpp/wireless-debug-display/assets/213467/395400f6-e677-464c-a258-df06049cc562
142+
143+
### ESP32-S3-BOX
144+
145+
![image](https://github.com/esp-cpp/wireless-debug-display/assets/213467/5aa28996-4ad7-4dbc-bc00-756ecd7ec736)
146+
![image](https://github.com/esp-cpp/wireless-debug-display/assets/213467/2c75f6dc-4528-4663-ae12-f894ec2bcdc9)
147+
![image](https://github.com/esp-cpp/wireless-debug-display/assets/213467/e59536a1-da8c-40fb-9f37-fdfdfb2d5b52)
148+
149+
https://github.com/esp-cpp/wireless-debug-display/assets/213467/f835922f-e17f-4f76-95ee-5d6585e84656
55150

56-
![CleanShot 2023-07-12 at 14 01 21](https://github.com/esp-cpp/template/assets/213467/7f8abeae-121b-4679-86d8-7214a76f1b75)

additional_data.txt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
Some additional logs!
2+
This is some more logging
3+
#FF00FF wow# there really are a lot of logs here
4+
you really can't believe it can you?
5+
#FF0000 Hopefully# at some point
6+
I'll be able to stop typing
7+
and I'll have gotten to
8+
the bottom of the logs...
9+
t0::5
10+
t0::7
11+
t0::35
12+
t0::76
13+
t0::32
14+
t0::11
15+
t0::15
16+
t0::13
17+
t0::5
18+
t0::0
19+
t0::10
20+
t0::-31
21+
t0::-75
22+
t0::3
23+
t0::1
24+
t0::1
25+
t0::3
26+
t0::5
27+
r0::0
28+
r0::10
29+
r0::3
30+
r0::5
31+
r0::3
32+
r0::1
33+
r0::1
34+
r0::3
35+
r0::5
36+
r0::0
37+
r0::10
38+
r0::30
39+
r0::5
40+
r0::3
41+
r0::1
42+
r0::-10
43+
r0::-30
44+
r0::5

components/esp-protocols

Submodule esp-protocols added at 12bacdc

components/gui/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
idf_component_register(
2+
SRC_DIRS "src"
3+
INCLUDE_DIRS "include"
4+
REQUIRES task display logger)

components/gui/include/converter.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#pragma once
2+
3+
#include <cerrno>
4+
#include <climits>
5+
#include <stdlib.h>
6+
7+
class Converter {
8+
public:
9+
enum class Status { Success, Overflow, Underflow, Inconvertible };
10+
static Status str2int(int &i, char const *s, int base = 0);
11+
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <cstring>
5+
#include <unordered_map>
6+
7+
#include "window.hpp"
8+
9+
class GraphWindow : public Window {
10+
public:
11+
void init(lv_obj_t *parent, size_t width, size_t height) override;
12+
void update() override;
13+
14+
void clear_plots ( void );
15+
void add_data ( const std::string& plot_name, int new_data );
16+
void remove_plot ( const std::string& plot_name );
17+
18+
protected:
19+
lv_chart_series_t* create_plot ( const std::string& plotName );
20+
lv_chart_series_t* get_plot ( const std::string& plotName );
21+
22+
void update_ticks ( void );
23+
24+
private:
25+
lv_obj_t *chart_;
26+
lv_obj_t *legend_;
27+
std::string y_ticks_;
28+
std::unordered_map<std::string, lv_chart_series_t*> plot_map_;
29+
};

components/gui/include/gui.hpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#pragma once
2+
3+
#include <memory>
4+
#include <mutex>
5+
#include <queue>
6+
#include <sstream>
7+
8+
#include <sdkconfig.h>
9+
10+
#include "converter.hpp"
11+
#include "display.hpp"
12+
#include "task.hpp"
13+
#include "logger.hpp"
14+
#include "text_window.hpp"
15+
#include "graph_window.hpp"
16+
17+
class Gui {
18+
public:
19+
const std::string delimeter_data = "::"; ///< Delimeter indicating this contains plottable data
20+
const std::string delimeter_command = "+++"; ///< Delimeter indicating this contains a command
21+
const std::string command_remove_plot = "RP:"; ///< Command: remove plot
22+
const std::string command_clear_plots = "CP"; ///< Command: clear plots
23+
const std::string command_clear_logs = "CL"; ///< Command: clear logs
24+
25+
struct Config {
26+
std::shared_ptr<espp::Display> display;
27+
espp::Logger::Verbosity log_level{espp::Logger::Verbosity::WARN};
28+
};
29+
30+
explicit Gui(const Config& config)
31+
: display_(config.display)
32+
, logger_({.tag = "Gui", .level = config.log_level}) {
33+
init_ui();
34+
// now start the gui updater task
35+
using namespace std::placeholders;
36+
task_ = espp::Task::make_unique({
37+
.name = "Gui Task",
38+
.callback = std::bind(&Gui::update, this, _1, _2),
39+
.stack_size_bytes = 6 * 1024
40+
});
41+
task_->start();
42+
}
43+
44+
~Gui() {
45+
task_->stop();
46+
deinit_ui();
47+
}
48+
49+
void switch_tab();
50+
51+
void push_data(const std::string& data);
52+
std::string pop_data();
53+
54+
void clear_info();
55+
void add_info(const std::string& info);
56+
57+
bool handle_data();
58+
59+
protected:
60+
void init_ui();
61+
void deinit_ui();
62+
63+
bool update(std::mutex& m, std::condition_variable& cv) {
64+
{
65+
std::lock_guard<std::recursive_mutex> lk(mutex_);
66+
lv_task_handler();
67+
}
68+
{
69+
using namespace std::chrono_literals;
70+
std::unique_lock<std::mutex> lk(m);
71+
cv.wait_for(lk, 16ms);
72+
}
73+
// don't want to stop the task
74+
return false;
75+
}
76+
77+
static void event_callback(lv_event_t *e) {
78+
lv_event_code_t event_code = lv_event_get_code(e);
79+
auto user_data = lv_event_get_user_data(e);
80+
auto gui = static_cast<Gui*>(user_data);
81+
if (!gui) {
82+
return;
83+
}
84+
switch (event_code) {
85+
case LV_EVENT_SHORT_CLICKED:
86+
break;
87+
case LV_EVENT_PRESSED:
88+
gui->on_pressed(e);
89+
break;
90+
case LV_EVENT_VALUE_CHANGED:
91+
// gui->on_value_changed(e);
92+
break;
93+
case LV_EVENT_LONG_PRESSED:
94+
break;
95+
case LV_EVENT_KEY:
96+
break;
97+
default:
98+
break;
99+
}
100+
}
101+
102+
void on_pressed(lv_event_t *e);
103+
104+
GraphWindow plot_window_;
105+
TextWindow log_window_;
106+
TextWindow info_window_;
107+
lv_obj_t *tabview_;
108+
109+
std::mutex data_queue_mutex_;
110+
std::queue<std::string> data_queue_;
111+
112+
std::shared_ptr<espp::Display> display_;
113+
std::unique_ptr<espp::Task> task_;
114+
115+
espp::Logger logger_;
116+
std::recursive_mutex mutex_;
117+
};

0 commit comments

Comments
 (0)