venerdì 20 giugno 2025

NanoProtoBuf Esp32 IDF

Su Esp32 (e piu' in generale sui microcontrollori) la libreria Protobuf non puo' funzionare e quindi si deve usare nanopb (nano proto buffer)  https://github.com/nanopb/nanopb

Il seguente progetto e' stato creato usando il plugin Esp-Idf di VSCode

Per utilizzarla si deve prima installare il compilare protoc e poi scaricare e compilare il pacchetto nanopb da GitHub ...questo servira' come plugin per protoc

Si procede  quindi con il seguente comando che genera i file sensor.pb.c e sensor.pb.h dove sono inserite le classi per la lettura scrittura del file sensor.proto. questi due file sono da inserire nella main del progetto mentre i file pb_common.c pb_common.h pb_decode.c pb_decode.h pc_encode.c e pb_encode.h si inseriscono nel folder nanopb all'interno del folder main  

protoc --plugin=protoc-gen-nanopb=/home/luca/nanopb/generator/protoc-gen-nanopb --nanopb_out=./ --proto_path=/home/luca/nanopb/generator/proto sensor.proto

sensor.proto

syntax = "proto3";

message SensorData {
int32 id = 1;
float temperature = 2;
float humidity = 3;
}

Si modifica quindi il file CMakeLists.txt per puntare i nuovi file

idf_component_register(
SRCS
"main.c"
"sensor.pb.c"
"nanopb/pb_encode.c"
"nanopb/pb_decode.c"
"nanopb/pb_common.c"
INCLUDE_DIRS
"."
"nanopb"
)

e si puo' compilare questo semplice programma di esempio sull'utilizzo di nanopb 

#include <stdio.h>

#include "sensor.pb.h"
#include "pb_encode.h"
#include "pb_decode.h"

#include "driver/uart.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

void app_main(void)
{
const uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
};



uart_driver_install(UART_NUM_0, 1024, 0, 0, NULL, 0);
uart_param_config(UART_NUM_0, &uart_config);

const char *msg = "Hello from UART0 via USB!\n";
uart_write_bytes(UART_NUM_0, msg, strlen(msg));


vTaskDelay(pdMS_TO_TICKS(3000));
printf("USB CDC active\n");

vTaskDelay(pdMS_TO_TICKS(500)); // Delay to let USB CDC connect


uint8_t buffer[128];
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));

SensorData da = SensorData_init_zero;
da.id = 42;
da.temperature = 23.5;
da.humidity = 55.2;

if (pb_encode(&stream, SensorData_fields, &da)) {
size_t message_length = stream.bytes_written;
// Send buffer over serial, BLE, etc.
} else {
//Serial.println("Encoding failed!");
}

size_t message_length = stream.bytes_written;

SensorData da_r = SensorData_init_zero;
//int received_length = 0;
pb_istream_t str = pb_istream_from_buffer(buffer, message_length);

while(1){
if (pb_decode(&str, SensorData_fields, &da_r)) {
char str_out[32];
snprintf(str_out, sizeof(str_out), "%.2f\n", da_r.humidity);
uart_write_bytes(UART_NUM_0, str_out, strlen(str_out));
printf("Temp: %.2f, Humidity: %.2f\n",da_r.temperature, da_r.humidity);
} else {
uart_write_bytes(UART_NUM_0, "Decoding error\n", strlen("Decoding error\n"));
printf("Error decoding\n");
}

vTaskDelay(pdMS_TO_TICKS(1000));}

}

 

 

 

mercoledì 11 giugno 2025

CrowdLed

Ad un torneo di pallavolo a mia figlia hanno regalato un braccialetto...ad occhio visto la presenza della batteria e di un pulsante, sembrava  qualcosa di luminoso...tranne per il fatto che non si notava nessun segno di vita (le batterie sono cariche)

 

 

 
 
 

Frugando su internet ho trovato che il braccialetto viene di solito distribuito agli spettatori di concerti ed e' radio controllato

Sono stati fatti alcuni reverse engineering..peccato che il mio sia gruppo 4

https://github.com/gabry99018/Flipper-Zero-CrowdLED-Wristbands/tree/main

https://forum.flipper.net/t/new-device-protocol-crowd-led-and-dmx/6571/12



 

 

 

 

 

 

 

ESP32-4848S040CIY1

Dopo CYW ho preso il modello superiore (che per costo, visto il case gia' presente e' decisamente da preferire) ESP32-4848S040CIY1 che monta un ESP32-S3

Interessante la presenza dei relay per usare il display come interruttore ma non ho ancora chiaro se siano a 130V (americani) o 220V(europei) 

https://github.com/rzeldent/esp32-smartdisplay-demo 

https://github.com/sand1812/ESP32-4848S040
 

Entrambe gli esempi usano LVGL 9.x quindi non e' possibile usare SquareLine

L'unica difficolta' e' settare il path di lv_conf.h 

ho modificato il file lv_conf_internal.h per puntare al file lv_conf.h

 

/* If lv_conf.h is not skipped, include it. */
#if !defined(LV_CONF_SKIP) || defined(LV_CONF_PATH)
#ifdef LV_CONF_PATH /* If there is a path defined for lv_conf.h, use it */
//#include LV_CONF_PATH
#include "../lv_conf.h" /* Note: Make sure to define custom CONF_PATH as a string */
#elif defined(LV_CONF_INCLUDE_SIMPLE) /* Or simply include lv_conf.h is enabled. */
#include "lv_conf.h"
#else
#include "../../lv_conf.h" /* Else assume lv_conf.h is next to the lvgl folder. */
#endif
#if !defined(LV_CONF_H) && !defined(LV_CONF_SUPPRESS_DEFINE_CHECK)
/* #include will sometimes silently fail when __has_include is used */
/* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80753 */
#pragma messag

 

lunedì 9 giugno 2025

M5 Dial LVGL e Platformio

Per compilare i progetti M5Dial con Platformio si scaricano gli esempi da https://github.com/mzyy94/M5Dial-LVGL

 


 

Da dentro Platformio si apre il folder del progetto in examples/dial_number e si effettua la build

Un dettaglio .. il pulsante di reset e' nascosto dietro l'adesivo

 



 

T-Dongle S3 ed IDF 5

Ho ripreso in mano il T-Dongle S3 di Lilygo ed i progetti IDF che sono presenti sul github ufficiale non funzionano piu' perche' la libreria LovyanGFX non risulta compatibile con IDF 5.x (il codice e' stato scritto per una versione precedente di IDF)


 

Ho provato a correggere ma alla fine ho preso un docker IDF 4.4 ed ho usato questo per compilare il progetto 

Importante: per mettere in modalita' programmazione la scheda si deve premere il pulsante e poi inserire la scheda nella porta USB.  Per avviare lo sketch la scheda deve essere rimossa e poi inserita

sudo apt update
sudo apt install docker.io
sudo systemctl enable docker --now
sudo usermod -aG docker $USER
newgrp docker

 

docker pull espressif/idf:release-v4.4

docker run --rm -it   --device=/dev/ttyACM0   -v ~/T-Dongle-S3:/project   -w /project   espressif/idf:release-v4.4 

 

 idf.py set-target esp32s3

 idf.py build

 

 

 

giovedì 5 giugno 2025

Stream Deck per VLC su Linux con

 

https://github.com/c1p81/CYD_BLE_Streamdeck

 


 


 

Mandelbrot su CYD (Cheap Yellow Display) ESP32-2432S028

Ho provato ad usare ESP32 in CYD per generare Mandelbrot utilizzando entrambi i core

Il codice del progetto Platformio si trova a questo link

https://github.com/c1p81/mandelbrot_esp32_cyd

 



Preparazione dati Marida

 

 

 


 

ricampiona i file jp2 originali di Sentinel 2 in geotiff a 10 m

 

import os
import rasterio
import numpy as np
from rasterio.windows import Window
from pathlib import Path

def create_tiles_from_geotiffs(input_files, output_dir, tile_size_km=2.5):
"""
Cut multiple geotiffs into tiles and stack them as bands in new geotiffs.
Args:
input_files: List of paths to input geotiffs (must cover same area)
output_dir: Directory to save output tiles
tile_size_km: Size of tiles in kilometers
"""
# Create output directory if it doesn't exist
os.makedirs(output_dir, exist_ok=True)
# Open first file to get metadata
with rasterio.open(input_files[0]) as src:
# Get spatial reference metadata
crs = src.crs
transform = src.transform
# Calculate tile size in pixels
# Get resolution in meters per pixel
res_x = abs(transform.a) # x resolution in map units/pixel
res_y = abs(transform.e) # y resolution in map units/pixel
# Calculate tile size in pixels
tile_size_x = int(tile_size_km * 1000 / res_x)
tile_size_y = int(tile_size_km * 1000 / res_y)
# Get image dimensions
width = src.width
height = src.height
# Calculate number of tiles
num_tiles_x = (width + tile_size_x - 1) // tile_size_x
num_tiles_y = (height + tile_size_y - 1) // tile_size_y
print(f"Input size: {width}x{height} pixels")
print(f"Tile size: {tile_size_x}x{tile_size_y} pixels ({tile_size_km}km x {tile_size_km}km)")
print(f"Creating {num_tiles_x * num_tiles_y} tiles ({num_tiles_x}x{num_tiles_y})")
# Process each tile
for tile_y in range(num_tiles_y):
for tile_x in range(num_tiles_x):
# Calculate window coordinates
x_offset = tile_x * tile_size_x
y_offset = tile_y * tile_size_y
# Adjust for edge tiles
actual_tile_width = min(tile_size_x, width - x_offset)
actual_tile_height = min(tile_size_y, height - y_offset)
# Skip if tile is empty or too small
if actual_tile_width <= 0 or actual_tile_height <= 0:
continue
# Define the window to read
window = Window(x_offset, y_offset, actual_tile_width, actual_tile_height)
# Calculate new geotransform for the tile
new_transform = rasterio.transform.from_origin(
transform.c + transform.a * x_offset, # upper left x
transform.f + transform.e * y_offset, # upper left y
transform.a, # pixel width
transform.e # pixel height
)
# Create empty array for the 11-band tile
tile_data = np.zeros((len(input_files), actual_tile_height, actual_tile_width),
dtype=rasterio.float32)
# Read data from each input file
for band_idx, file_path in enumerate(input_files):
with rasterio.open(file_path) as src:
tile_data[band_idx] = src.read(1, window=window)
# Define output file path
out_path = os.path.join(output_dir, f"tile_x{tile_x}_y{tile_y}.tif")
# Write the tile to a new file
with rasterio.open(
out_path,
'w',
driver='GTiff',
height=actual_tile_height,
width=actual_tile_width,
count=len(input_files),
dtype=tile_data.dtype,
crs=crs,
transform=new_transform,
) as dst:
dst.write(tile_data)
print(f"Created tile: {out_path}")
# Optional: Add metadata about original tile position
with rasterio.open(out_path, 'r+') as dst:
dst.update_tags(
tile_x=tile_x,
tile_y=tile_y,
original_extent=f"{width}x{height}",
tile_size_km=tile_size_km
)

if __name__ == "__main__":
# Directory containing input geotiffs
input_dir = "output_10m"
# List of input geotiff files (11 bands)
input_files = [
os.path.join(input_dir, f"B{i+1}.tif") for i in range(11)
]
# Check if files exist
for f in input_files:
if not os.path.exists(f):
print(f"Warning: File {f} does not exist!")
# Directory to save output tiles
output_dir = "output_tiles"
# Create tiles
create_tiles_from_geotiffs(input_files, output_dir, tile_size_km=2.56)


 

 

crea una tile di 2560x2560m 11 bande

import os
import rasterio
from rasterio.windows import Window
import numpy as np

# Parameters
input_folder = "./output_10m" # folder with B1.tif to B11.tif
output_folder = "./output_tiles"
tile_size_m = 2560 # meters
pixel_size = 10 # meters per pixel
tile_size_px = tile_size_m // pixel_size

# Get list of sorted input files (assumes filenames like B1.tif, B2.tif, ..., B11.tif)
input_files = sorted([f for f in os.listdir(input_folder) if f.endswith(".tif")])
input_paths = [os.path.join(input_folder, f) for f in input_files]

# Open all rasters
rasters = [rasterio.open(fp) for fp in input_paths]

# Check that all rasters have same dimensions
width, height = rasters[0].width, rasters[0].height
transform = rasters[0].transform
crs = rasters[0].crs

# Create output folder
os.makedirs(output_folder, exist_ok=True)

tile_id = 0
for y in range(0, height, tile_size_px):
for x in range(0, width, tile_size_px):
if x + tile_size_px > width or y + tile_size_px > height:
continue # Skip partial tiles

# Read corresponding tile from each band
tile_stack = []
for r in rasters:
tile = r.read(1, window=Window(x, y, tile_size_px, tile_size_px))
tile_stack.append(tile)

tile_stack = np.stack(tile_stack) # shape: (bands, height, width)

# Define transform for this tile
tile_transform = rasterio.windows.transform(Window(x, y, tile_size_px, tile_size_px), transform)

# Write output GeoTIFF with multiple bands
out_path = os.path.join(output_folder, f"tile_{tile_id:04d}.tif")
with rasterio.open(
out_path,
"w",
driver="GTiff",
height=tile_size_px,
width=tile_size_px,
count=len(rasters),
dtype=tile_stack.dtype,
crs=crs,
transform=tile_transform,
) as dst:
for i in range(len(rasters)):
dst.write(tile_stack[i], i + 1)

tile_id += 1

# Close all files
for r in rasters:
r.close()

print(f"Done. Created {tile_id} multi-band tiles.")


 

Montagne frattali

 Negli anni 90 quando i miei amici matematici leggevano (Ri)creazioni al calcolatore di Dewdney (vedi anche pag. 107 del libro The Magic Mac...