Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 0 additions & 2 deletions src/MoonBase/Char.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@

#pragma once

#include <Arduino.h>

#include "ArduinoJson.h"

// See https://discord.com/channels/473448917040758787/718943978636050542/1357670679196991629
Expand Down
1 change: 0 additions & 1 deletion src/MoonBase/Utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

#pragma once

#include <Arduino.h>
#include <ESPFS.h>

#include "ArduinoJson.h"
Expand Down
104 changes: 104 additions & 0 deletions src/MoonBase/pal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
@title MoonBase
@file pal.h
@repo https://github.com/MoonModules/MoonLight, submit changes to this file as PRs
@Authors https://github.com/MoonModules/MoonLight/commits/main
@Doc https://moonmodules.org/MoonLight/moonlight/overview/
@Copyright © 2025 Github MoonLight Commit Authors
@license GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
@license For non GPL-v3 usage, commercial licenses must be purchased. Contact us for more information.
**/

/**
Platform Abstraction Layer (PAL)

Goal:
* not depending on Arduino.h
* use esp-idf functions (instead of arduino.h)
* in a way to not create a new dependency on esp-idf

Approach
* Incremental changes: you can still do it the old way but the new way is available as well

Benefits
* Common way of working, within one repository, Possibly between different repo's
* No mix of arduino and esp-idf code in different places
* platform Arduino can be removed in the future
* Automated testing e.g. on Linux
**/

#pragma once

#include <stddef.h>
#include <stdint.h>

namespace pal {

/* =================================================
* Basic types
* ================================================= */

struct rgb_t {
uint8_t r;
uint8_t g;
uint8_t b;
};

/* =================================================
* Time
* ================================================= */

uint32_t millis();
uint64_t micros();
void delay_ms(uint32_t ms);

/* =================================================
* LED output (hot path)
* ================================================= */

void led_submit(const rgb_t* buffer, size_t led_count);
void led_set_brightness(uint8_t brightness);

/* =================================================
* Memory
* ================================================= */

void* malloc(size_t size);
void free(void* ptr);

/* =================================================
* Logging
* ================================================= */

enum class LogLevel : uint8_t { Error, Warn, Info, Debug };

void log(LogLevel level, const char* tag, const char* message);

/* =================================================
* Capability hints (0 = no, 1 = yes)
* ================================================= */

int cap_led_dma();
int cap_led_parallel();

/* =================================================
* UDP socket (stateful)
* ================================================= */

class UdpSocket {
public:
virtual ~UdpSocket() = default;

virtual bool open(uint16_t local_port) = 0;
virtual int send_to(const char* ip, uint16_t port, const uint8_t* data, size_t len) = 0;
virtual int recv_from(uint8_t* buffer, size_t max_len,
char* src_ip, // out
uint16_t* src_port // out
) = 0;
virtual void close() = 0;
};

UdpSocket* udp_socket_create();
void udp_socket_destroy(UdpSocket* socket);

} // namespace pal
175 changes: 175 additions & 0 deletions src/MoonBase/pal_espidf.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/**
@title MoonBase
@file pal_espidf.cpp
@repo https://github.com/MoonModules/MoonLight, submit changes to this file as PRs
@Authors https://github.com/MoonModules/MoonLight/commits/main
@Doc https://moonmodules.org/MoonLight/moonlight/overview/
@Copyright © 2025 Github MoonLight Commit Authors
@license GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
@license For non GPL-v3 usage, commercial licenses must be purchased. Contact us for more information.
**/

#include <esp_heap_caps.h>
#include <esp_log.h>
#include <esp_timer.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <lwip/inet.h>
#include <lwip/sockets.h>
#include <string.h>

#include "pal.h"

namespace pal {

/* =================================================
* Time
* ================================================= */

uint32_t millis() { return static_cast<uint32_t>(esp_timer_get_time() / 1000ULL); }

uint64_t micros() { return static_cast<uint64_t>(esp_timer_get_time()); }

void delay_ms(uint32_t ms) { vTaskDelay(pdMS_TO_TICKS(ms)); }

/* =================================================
* LED output (ESP-IDF backend placeholder)
* ================================================= */

// below functions is poc code. Need to be verified when actually used

static uint8_t s_led_brightness = 255; // brightness control will be implemented when the actual LED driver is added.

void led_submit(const rgb_t* buffer, size_t led_count) {
/* To be implemented with:
- RMT
- PARLIO
- DMA / PPA
- or external driver
*/
(void)buffer;
(void)led_count;
}

void led_set_brightness(uint8_t brightness) { s_led_brightness = brightness; }

/* =================================================
* Memory
* ================================================= */

void* malloc(size_t size) { return heap_caps_malloc(size, MALLOC_CAP_8BIT); }

void free(void* ptr) { heap_caps_free(ptr); }

/* =================================================
* Logging
* ================================================= */

void log(LogLevel level, const char* tag, const char* message) {
esp_log_level_t esp_level = ESP_LOG_INFO;

switch (level) {
case LogLevel::Error:
esp_level = ESP_LOG_ERROR;
break;
case LogLevel::Warn:
esp_level = ESP_LOG_WARN;
break;
case LogLevel::Info:
esp_level = ESP_LOG_INFO;
break;
case LogLevel::Debug:
esp_level = ESP_LOG_DEBUG;
break;
}

esp_log_write(esp_level, tag, "%s\n", message);
}

/* =================================================
* Capabilities
* ================================================= */

int cap_led_dma() { return 1; /* ESP32 supports DMA */ }

int cap_led_parallel() { return 1; /* ESP32 generally supports parallel output */ }

/* =================================================
* UDP socket (ESP-IDF / lwIP)
* ================================================= */

class EspIdfUdpSocket : public UdpSocket {
public:
EspIdfUdpSocket() : sock_(-1) {}

~EspIdfUdpSocket() override { close(); }

// below functions is poc code. Need to be verified when actually used

bool open(uint16_t local_port) override {
sock_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock_ < 0) {
return false;
}

sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_port = htons(local_port);
addr.sin_addr.s_addr = INADDR_ANY;

if (bind(sock_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) != 0) {
::close(sock_);
sock_ = -1;
return false;
}
return true;
}

int send_to(const char* ip, uint16_t port, const uint8_t* data, size_t len) override {
sockaddr_in dest{};
dest.sin_family = AF_INET;
dest.sin_port = htons(port);
if (inet_aton(ip, &dest.sin_addr) == 0) {
return -1; // Invalid IP address
}

return sendto(sock_, data, len, 0, reinterpret_cast<sockaddr*>(&dest), sizeof(dest));
}

int recv_from(uint8_t* buffer, size_t max_len,
char* src_ip, // out: must be at least 16 bytes (INET_ADDRSTRLEN)
uint16_t* src_port // out
) {
sockaddr_in src_addr{};
socklen_t src_len = sizeof(src_addr);

int received = recvfrom(sock_, buffer, max_len, 0, reinterpret_cast<sockaddr*>(&src_addr), &src_len);

if (received >= 0 && src_ip && src_port) {
inet_ntoa_r(src_addr.sin_addr, src_ip, 16);
*src_port = ntohs(src_addr.sin_port);
}

return received;
}

void close() override {
if (sock_ >= 0) {
::close(sock_);
sock_ = -1;
}
}

private:
int sock_;
};

/* =================================================
* Factory
* ================================================= */

UdpSocket* udp_socket_create() { return new EspIdfUdpSocket(); }

void udp_socket_destroy(UdpSocket* socket) { delete socket; }

} // namespace pal
2 changes: 0 additions & 2 deletions src/MoonLight/Layers/PhysicalLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@

#if FT_MOONLIGHT

#include <Arduino.h>

#include <vector>

#include "FastLED.h"
Expand Down
1 change: 0 additions & 1 deletion src/MoonLight/Layers/VirtualLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

#if FT_MOONLIGHT

#include <Arduino.h>
#include <FastLED.h>

#include <vector>
Expand Down
2 changes: 2 additions & 0 deletions src/MoonLight/Nodes/Drivers/parlio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

#include "parlio.h" //so it is compiled before Parallel LED Driver use it

#include "soc/soc_caps.h" // for SOC_PARLIO_SUPPORTED

#ifdef SOC_PARLIO_SUPPORTED

#include "driver/parlio_tx.h"
Expand Down
2 changes: 1 addition & 1 deletion src/MoonLight/Nodes/Drivers/parlio.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
**/

#pragma once
#include <Arduino.h>
#include <stdint.h> // uint8...

#if FT_MOONLIGHT

Expand Down
Loading