Skip to content

Commit

Permalink
Merge pull request #252 from kivancsikert/small-fixes
Browse files Browse the repository at this point in the history
Various small fixes and debugging improvements
  • Loading branch information
lptr authored Nov 30, 2024
2 parents 9b730c9 + dedca76 commit fcb3bf5
Show file tree
Hide file tree
Showing 13 changed files with 210 additions and 75 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/.vscode/*
!/.vscode/launch.json

*.log

Expand Down
25 changes: 25 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "gdbtarget",
"request": "attach",
"name": "Eclipse CDT GDB Adapter"
},
{
"type": "espidf",
"name": "Launch",
"request": "launch"
},
{
"name": "Wokwi GDB",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/ugly-duckling.elf",
"cwd": "${workspaceFolder}",
"MIMode": "gdb",
"miDebuggerPath": "${command:espIdf.getToolchainGdb}",
"miDebuggerServerAddress": "localhost:3333"
}
]
}
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,22 @@ mkspiffs -c data -s 0x30000 build/data.bin; esptool write_flash 0x3D0000 build/d
idf.py monitor
```

### Simulation

Can use [Wokwi](https://wokwi.com/) to run the firmware in a simulated environment.
For this the firmware must be built with `-DWOKWI=1`.

```bash
idf.py -DUD_GEN=MK6 -DUD_DEBUG=0 -DFSUPLOAD=1 -DWOKWI=1 build
```

The opening a diagram in the [`wokwi`](wokwi) directory will start the simulation.

#### Debugging with Wokwi

To start the simulation with the debugger enabled, place a breakpoint, then hit `Cmd+Shift+P` and select `Wokwi: Start Simulator and Wait for Debugger`.
After that from the "Run and Debug" panel select the "Wokwi GDB" configuration and hit the play button.

### Testing

TBD
55 changes: 55 additions & 0 deletions lookup-backtrace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env python3

import re
import subprocess
import sys

# Define regex patterns for the two formats
PATTERN1 = r"caller ((?:0x[0-9a-fA-F]+:)+0x[0-9a-fA-F]+)"
PATTERN2 = r"Backtrace: ((?:0x[0-9a-fA-F]+:[0-9a-fA-F]+ ?)+)"

def parse_and_run_addr2line(line):
# Print the input line
print(f"Input: {line.strip()}")

# Check for the first format
match1 = re.search(PATTERN1, line)
if match1:
addresses = match1.group(1).split(":")
process_addresses(addresses)

# Check for the second format
match2 = re.search(PATTERN2, line)
if match2:
pairs = match2.group(1).split()
addresses = [pair.split(":")[0] for pair in pairs]
process_addresses(addresses)

def process_addresses(addresses):
# Prepare the addr2line command
cmd = ["xtensa-esp32-elf-addr2line", "-f", "-e", "build/ugly-duckling.elf"] + addresses
try:
# Run the addr2line command
result = subprocess.run(cmd, text=True, capture_output=True)
# Split output into lines
lines = result.stdout.strip().splitlines()
# Process lines in pairs
for i in range(0, len(lines), 2):
function_name = lines[i].strip() if i < len(lines) else "unknown"
source_info = lines[i + 1].strip() if i + 1 < len(lines) else "unknown"
print(f" -- {source_info} -- {function_name}")
except Exception as e:
print(f"Error running addr2line: {e}")

def main():
try:
# Read lines from standard input
for line in sys.stdin:
parse_and_run_addr2line(line)
except KeyboardInterrupt:
print("\nTerminated by user.")
except EOFError:
print("\n")

if __name__ == "__main__":
main()
4 changes: 2 additions & 2 deletions main/devices/Device.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ class ConsoleProvider : public LogConsumer {

void consumeLog(Level level, const char* message) override {
if (level <= recordedLevel) {
logRecords.offer(LogRecord { level, message });
logRecords.offer(level, message);
}
#ifdef FARMHUB_DEBUG
consolePrinter.printLog(level, message);
Expand Down Expand Up @@ -573,7 +573,7 @@ class Device {
kernel.prepareUpdate(url);
} };

Queue<bool> telemetryPublishQueue { "telemetry-publish", 1 };
CopyQueue<bool> telemetryPublishQueue { "telemetry-publish", 1 };
};

} // namespace farmhub::devices
20 changes: 4 additions & 16 deletions main/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,7 @@
## IDF Component Manager Manifest File
dependencies:
espressif/arduino-esp32: "^3.1.0-RC1"
espressif/mdns: "^1.4.0"
bblanchon/arduinojson: "^7.2.0"
## Required IDF version
espressif/arduino-esp32: "3.1.0-rc1"
espressif/mdns: "1.4.2"
bblanchon/arduinojson: "7.2.1"
idf:
version: ">=5.3.1,<5.4.0"
# # Put list of dependencies here
# # For components maintained by Espressif:
# component: "~1.0.0"
# # For 3rd party components:
# username/component: ">=1.0.0,<2.0.0"
# username2/component2:
# version: "~1.0.0"
# # For transient dependencies `public` flag can be set.
# # `public` flag doesn't have an effect dependencies of the `main` component.
# # All dependencies of `main` are public by default.
# public: true
version: "5.3.1"
48 changes: 39 additions & 9 deletions main/kernel/Concurrent.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <chrono>
#include <functional>
#include <optional>
#include <memory>
#include <utility>

#include <freertos/FreeRTOS.h>
Expand Down Expand Up @@ -65,12 +67,6 @@ class Queue : public BaseQueue {
return sentWithoutDropping;
}

template <typename... Args>
void overwrite(Args&&... args) {
TMessage* copy = new TMessage(std::forward<Args>(args)...);
xQueueOverwrite(this->queue, &copy);
}

typedef std::function<void(TMessage&)> MessageHandler;

size_t drain(MessageHandler handler) {
Expand Down Expand Up @@ -124,31 +120,65 @@ class Queue : public BaseQueue {
};

template <typename TMessage>

class CopyQueue : public BaseQueue {
public:
CopyQueue(const String& name, size_t capacity = 16)
: BaseQueue(name, sizeof(TMessage), capacity) {
}

void put(const TMessage message) {
while (!offerIn(ticks::max(), message)) { }
}

bool offer(const TMessage message) {
return offerIn(ticks::zero(), message);
}

bool offerIn(ticks timeout, const TMessage message) {
bool sentWithoutDropping = xQueueSend(this->queue, &message, timeout.count()) == pdTRUE;
if (!sentWithoutDropping) {
ESP_LOGW("farmhub", "Overflow in queue '%s', dropping message",
this->name.c_str());
}
return sentWithoutDropping;
}

bool IRAM_ATTR offerFromISR(const TMessage& message) {
BaseType_t xHigherPriorityTaskWoken;
bool sentWithoutDropping = xQueueSendFromISR(this->queue, &message, &xHigherPriorityTaskWoken) == pdTRUE;
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
return sentWithoutDropping;
}

void overwrite(const TMessage message) {
xQueueOverwrite(this->queue, &message);
}

void IRAM_ATTR overwriteFromISR(const TMessage& message) {
BaseType_t xHigherPriorityTaskWoken;
xQueueOverwriteFromISR(this->queue, &message, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

TMessage take() {
while (true) {
auto message = pollIn(ticks::max());
if (message.has_value()) {
return message.value();
}
}
}

std::optional<TMessage> poll() {
return pollIn(ticks::zero());
}

std::optional<TMessage> pollIn(ticks timeout) {
TMessage message;
while (!xQueueReceive(this->queue, &message, ticks::max().count())) {
if (xQueueReceive(this->queue, &message, timeout.count())) {
return message;
}
return message;
return std::nullopt;
}

void clear() {
Expand Down
4 changes: 4 additions & 0 deletions main/kernel/SleepManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ class SleepManager {
#if FARMHUB_DEBUG
Log.warn("Light sleep is disabled in debug mode");
return false;
#elif WOKWI
// See https://github.com/wokwi/wokwi-features/issues/922
Log.warn("Light sleep is disabled when running under Wokwi");
return false;
#elif not(CONFIG_PM_ENABLE)
Log.info("Power management is disabled because CONFIG_PM_ENABLE is not set");
return false;
Expand Down
2 changes: 1 addition & 1 deletion main/kernel/Task.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ class Task {
return time - (currentTime - ticks(lastWakeTime));
} else {
// 'currentTime' has surpassed our target time, indicating the delay has expired.
Log.printfToSerial("Task '%s' missed deadline by %lld ms\n",
Log.printfToSerial("Task '%s' is already past deadline by %lld ms\n",
pcTaskGetName(nullptr), duration_cast<milliseconds>(currentTime - ticks(lastWakeTime)).count());
return ticks::zero();
}
Expand Down
2 changes: 1 addition & 1 deletion main/kernel/drivers/LedDriver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class LedDriver {
}

private:
void setPattern(BlinkPattern pattern) {
void setPattern(const BlinkPattern& pattern) {
patternQueue.put(pattern);
}

Expand Down
13 changes: 8 additions & 5 deletions main/kernel/drivers/WiFiDriver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,9 @@ class WiFiDriver {
inline void runLoop() {
int clients = 0;
while (true) {
eventQueue.pollIn(WIFI_CHECK_INTERVAL, [&clients](const WiFiEvent event) {
switch (event) {
auto event = eventQueue.pollIn(WIFI_CHECK_INTERVAL);
if (event.has_value()) {
switch (event.value()) {
case WiFiEvent::CONNECTED:
break;
case WiFiEvent::DISCONNECTED:
Expand All @@ -125,7 +126,7 @@ class WiFiDriver {
clients--;
break;
}
});
}

bool connected = WiFi.isConnected();
if (clients > 0) {
Expand Down Expand Up @@ -179,7 +180,9 @@ class WiFiDriver {

void disconnect() {
networkReady.clear();
WiFi.disconnect(true);
if (!WiFi.disconnect(true)) {
Log.error("WiFi: failed to shut down");
}
}

StateSource& acquire() {
Expand All @@ -205,7 +208,7 @@ class WiFiDriver {
WANTS_DISCONNECT
};

Queue<WiFiEvent> eventQueue { "wifi-events", 16 };
CopyQueue<WiFiEvent> eventQueue { "wifi-events", 16 };

static constexpr milliseconds WIFI_QUEUE_TIMEOUT = 1s;
static constexpr milliseconds WIFI_CHECK_INTERVAL = 5s;
Expand Down
Loading

0 comments on commit fcb3bf5

Please sign in to comment.