Reorganisation fichiers
This commit is contained in:
@@ -1,24 +1,22 @@
|
||||
FROM python:3.11
|
||||
# RUN python -c "$(curl -fsSL https://raw.githubusercontent.com/platformio/platformio/master/scripts/get-platformio.py)"
|
||||
|
||||
# RUN platformio platforms install atmelavr \
|
||||
# --with-package framework-arduinoavr
|
||||
|
||||
RUN python -c "$(curl -fsSL https://raw.githubusercontent.com/platformio/platformio/master/scripts/get-platformio.py)"
|
||||
|
||||
RUN platformio platforms install atmelavr \
|
||||
--with-package framework-arduinoavr
|
||||
|
||||
RUN platformio platforms install ststm32 \
|
||||
--with-package framework-libopencm3 \
|
||||
--with-package framework-spl \
|
||||
--with-package framework-cmsis \
|
||||
--with-package framework-mbed
|
||||
# RUN platformio platforms install ststm32 \
|
||||
# --with-package framework-libopencm3 \
|
||||
# --with-package framework-spl \
|
||||
# --with-package framework-cmsis \
|
||||
# --with-package framework-mbed
|
||||
# Install PlatformIO
|
||||
# RUN pip install platformio
|
||||
RUN pip install platformio
|
||||
|
||||
# Install OpenSSH for remote access
|
||||
RUN apt-get update && apt-get install -y openssh-server && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Set up SSH
|
||||
RUN mkdir /var/run/sshd
|
||||
# RUN mkdir /var/run/sshd
|
||||
RUN echo 'root:root' | chpasswd
|
||||
RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
|
||||
EXPOSE 22
|
||||
|
||||
4
PacoMouseCYD/Platformio/.devcontainer/build.sh
Normal file
4
PacoMouseCYD/Platformio/.devcontainer/build.sh
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker build -t easylinux/platformio-dev:1.0 .
|
||||
docker image push easylinux/platformio-dev:1.0
|
||||
2
PacoMouseCYD/Platformio/.gitignore
vendored
2
PacoMouseCYD/Platformio/.gitignore
vendored
@@ -1,4 +1,4 @@
|
||||
.pio
|
||||
.pio/*
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
|
||||
@@ -1 +1 @@
|
||||
fed900e679701433dcf0b1c100208ae4193278e2
|
||||
5b3abfbb1412581b7a1f0de41d5ba1926b6f6f95
|
||||
@@ -1,3 +1,56 @@
|
||||
|
||||
/**
|
||||
* @file accessories.ino
|
||||
* @brief Accessory FIFO and control functions for PacoMouseCYD throttle.
|
||||
* @author F. Cañada
|
||||
* @date 2025-2026
|
||||
* @copyright https://usuaris.tinet.cat/fmco/
|
||||
*
|
||||
* This file contains functions to manage accessory commands using a FIFO buffer,
|
||||
* and to send accessory commands to the model train system.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// API Documentation
|
||||
////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* @brief Initializes the accessory FIFO buffer.
|
||||
*
|
||||
* Resets FIFO indices and state to empty.
|
||||
*/
|
||||
void initFIFO();
|
||||
|
||||
/**
|
||||
* @brief Reads the next accessory command from the FIFO.
|
||||
* @return The next accessory command in the FIFO.
|
||||
*/
|
||||
unsigned int readFIFO();
|
||||
|
||||
/**
|
||||
* @brief Writes an accessory command to the FIFO.
|
||||
* @param FAdr The accessory address.
|
||||
* @param pos The position or state to set.
|
||||
*/
|
||||
void writeFIFO(uint16_t FAdr, uint8_t pos);
|
||||
|
||||
/**
|
||||
* @brief Processes and sends accessory commands from the FIFO.
|
||||
*
|
||||
* Handles timing and state transitions for accessory activation and deactivation.
|
||||
*/
|
||||
void sendAccessoryFIFO();
|
||||
|
||||
/**
|
||||
* @brief Adds an accessory command to the FIFO for later execution.
|
||||
* @param FAdr The accessory address.
|
||||
* @param pos The position or state to set.
|
||||
*/
|
||||
void moveAccessory(uint16_t FAdr, uint8_t pos);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// End API Documentation
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
|
||||
*/
|
||||
|
||||
@@ -1,13 +1,69 @@
|
||||
|
||||
/**
|
||||
* @file ecos.ino
|
||||
* @brief ECoS protocol support for PacoMouseCYD throttle.
|
||||
* @author F. Cañada
|
||||
* @date 2025-2026
|
||||
* @copyright https://usuaris.tinet.cat/fmco/
|
||||
*
|
||||
* This file contains functions to communicate with ECoS/CS1 command stations,
|
||||
* including sending and receiving messages, requesting locomotive and system status,
|
||||
* and handling ECoS-specific operations.
|
||||
*
|
||||
* This software and associated files are a DIY project that is not intended for commercial use.
|
||||
* This software uses libraries with different licenses, follow all their different terms included.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
|
||||
*
|
||||
* Sources are only provided for building and uploading to the device.
|
||||
* You are not allowed to modify the source code or fork/publish this project.
|
||||
* Commercial use is forbidden.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// API Documentation
|
||||
////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* @brief Sends a message to the ECoS command station.
|
||||
* @param buf The message buffer to send.
|
||||
*/
|
||||
void sendMsgECOS(char *buf);
|
||||
|
||||
/**
|
||||
* @brief Requests various views and information from the ECoS command station.
|
||||
*/
|
||||
void requestViews();
|
||||
|
||||
/**
|
||||
* @brief Requests the power status from the ECoS command station.
|
||||
*/
|
||||
void getStatusECoS();
|
||||
|
||||
/**
|
||||
* @brief Requests the list of locomotives from the ECoS command station.
|
||||
*/
|
||||
void requestLocoList();
|
||||
|
||||
/**
|
||||
* @brief Requests information about a specific locomotive from the ECoS command station.
|
||||
* @param ID The ECoS locomotive ID.
|
||||
*/
|
||||
void infoLocomotoraECoS(unsigned int ID);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// End API Documentation
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
|
||||
|
||||
This software and associated files are a DIY project that is not intended for commercial use.
|
||||
This software uses libraries with different licenses, follow all their different terms included.
|
||||
This software and associated files are a DIY project that is not intended for commercial use.
|
||||
This software uses libraries with different licenses, follow all their different terms included.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
|
||||
|
||||
Sources are only provided for building and uploading to the device.
|
||||
You are not allowed to modify the source code or fork/publish this project.
|
||||
Commercial use is forbidden.
|
||||
Sources are only provided for building and uploading to the device.
|
||||
You are not allowed to modify the source code or fork/publish this project.
|
||||
Commercial use is forbidden.
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,3 +1,44 @@
|
||||
|
||||
/**
|
||||
* @file encoder.ino
|
||||
* @brief Rotary encoder and button handling for PacoMouseCYD throttle.
|
||||
* @author F. Cañada
|
||||
* @date 2025-2026
|
||||
* @copyright https://usuaris.tinet.cat/fmco/
|
||||
*
|
||||
* This file contains interrupt service routines and functions for reading and processing
|
||||
* rotary encoder and button input, including debouncing and value management.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// API Documentation
|
||||
////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* @brief Interrupt Service Routine for the encoder.
|
||||
*
|
||||
* Sets a flag indicating the encoder needs service.
|
||||
*/
|
||||
void IRAM_ATTR encoderISR();
|
||||
|
||||
/**
|
||||
* @brief Handles encoder state changes and updates encoder value.
|
||||
*/
|
||||
void encoderService();
|
||||
|
||||
/**
|
||||
* @brief Reads the encoder button and updates its state.
|
||||
*/
|
||||
void readButtons();
|
||||
|
||||
/**
|
||||
* @brief Processes encoder movement and updates UI or state accordingly.
|
||||
*/
|
||||
void controlEncoder();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// End API Documentation
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
|
||||
*/
|
||||
|
||||
File diff suppressed because one or more lines are too long
36
PacoMouseCYD/Platformio/SD/bgr565.html
Normal file
36
PacoMouseCYD/Platformio/SD/bgr565.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>BGR565 Inverted Image Converter</title>
|
||||
<link rel="stylesheet" href="css/bgr565.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>BGR565 Inverted Image Converter</h1>
|
||||
<form id="imageForm">
|
||||
<input type="file" id="imageInput" accept="image/*">
|
||||
<br>
|
||||
<label>Width: <input type="number" id="width" value="190" min="1"></label>
|
||||
<label>Height: <input type="number" id="height" value="40" min="1"></label>
|
||||
<button type="button" id="convertBtn">Convert & Download .raw</button>
|
||||
</form>
|
||||
<canvas id="canvas" style="display:none;"></canvas>
|
||||
<div id="preview"></div>
|
||||
<script src="js/bgr565.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
<!--
|
||||
How this tool works:
|
||||
1. Select an image file (any format supported by your browser).
|
||||
2. Set the desired width and height (default: 190x40).
|
||||
3. Click "Convert & Download .raw".
|
||||
4. The image is resized/cropped to the specified size, converted to inverted BGR565 format (matching your display), and a .raw file is downloaded.
|
||||
5. The .raw file can be copied to your SD card and displayed directly on your ESP32 with your display code.
|
||||
|
||||
Technical details:
|
||||
- Uses HTML5 Canvas to process the image in the browser.
|
||||
- JavaScript reads pixel data, converts to BGR565, inverts each value, and outputs a binary .raw file.
|
||||
- No data is uploaded; all processing is local in your browser.
|
||||
-->
|
||||
</html>
|
||||
</html>
|
||||
32
PacoMouseCYD/Platformio/SD/css/bgr565.css
Normal file
32
PacoMouseCYD/Platformio/SD/css/bgr565.css
Normal file
@@ -0,0 +1,32 @@
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 2em;
|
||||
background: #f9f9f9;
|
||||
color: #222;
|
||||
}
|
||||
h1 {
|
||||
color: #005580;
|
||||
}
|
||||
form {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
label {
|
||||
margin-right: 1em;
|
||||
}
|
||||
#preview img {
|
||||
max-width: 300px;
|
||||
border: 1px solid #ccc;
|
||||
margin-top: 1em;
|
||||
}
|
||||
button {
|
||||
padding: 0.5em 1em;
|
||||
font-size: 1em;
|
||||
background: #005580;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
button:hover {
|
||||
background: #0077aa;
|
||||
}
|
||||
275
PacoMouseCYD/Platformio/SD/css/style.css
Normal file
275
PacoMouseCYD/Platformio/SD/css/style.css
Normal file
File diff suppressed because one or more lines are too long
64
PacoMouseCYD/Platformio/SD/image/image.md
Normal file
64
PacoMouseCYD/Platformio/SD/image/image.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# 1001.bmp Image Characteristics
|
||||
|
||||
- **File Name:** 1001.bmp
|
||||
- **Location:** SD/image/1001.bmp
|
||||
- **Format:** Windows 3.x BMP (BMP3)
|
||||
- **Dimensions:** 190 x 40 pixels
|
||||
- **Color Depth:** 24-bit (8-bit per channel, sRGB)
|
||||
- **Image Size:** 22,934 bytes
|
||||
- **Resolution:** 2834 x 2834 pixels/meter
|
||||
- **Data Offset:** 54 bytes (header size)
|
||||
|
||||
This image is suitable for use with ESP32 projects that support 24-bit BMP files. For optimal performance on microcontrollers, consider converting to a raw or 16-bit (RGB565) format if needed by your display library.
|
||||
|
||||
# Converting
|
||||
|
||||
For ESP32 with ILIxxx displays, storing images as uncompressed 24-bit BMP (like your current 1001.bmp) is convenient if your display library supports BMP decoding and you have enough storage and RAM. However, for best performance and efficiency, especially on microcontrollers, the most common and recommended format is:
|
||||
|
||||
Raw RGB565 (16-bit) format: This matches the color format of most ILIxxx displays, is fast to load, and uses less space than 24-bit BMP.
|
||||
Why RGB565 Raw is Better:
|
||||
Directly compatible with ILIxxx displays (no conversion needed at runtime).
|
||||
Smaller file size (190 × 40 × 2 bytes = 15,200 bytes).
|
||||
|
||||
Fastest to read and display.
|
||||
|
||||
# How to Convert a Photo or Image:
|
||||
|
||||
## Resize and Crop:
|
||||
|
||||
Use an image editor (GIMP, Photoshop, or free online tools) to resize your image to 190x40 pixels.
|
||||
Crop as needed to fit the aspect ratio.
|
||||
## Convert to RGB565 Raw:
|
||||
|
||||
Use a tool or script to convert the image to RGB565 format.
|
||||
Save as a .raw or .bin file (not BMP, not compressed).
|
||||
|
||||
## Copy to SD Card:
|
||||
|
||||
Place the .raw file on your SD card.
|
||||
Read and display it directly using your ESP32 code.
|
||||
|
||||
## Example Conversion Tools:
|
||||
|
||||
**GIMP**: Export as RGB565 using a plugin or export as raw data.
|
||||
Python script: Use PIL (Pillow) to convert and save as RGB565.
|
||||
Online tools: Search for “image to RGB565 converter”.
|
||||
If you want, I can provide a Python script to automate the conversion from any image to 190x40 RGB565 raw format. Let me know if you need this!
|
||||
|
||||
|
||||
Your display uses an inverted BGR565 format (not standard RGB565), meaning:
|
||||
|
||||
The color order is BGR (not RGB).
|
||||
The 16-bit value is inverted: color = 0xFFFF - standard BGR565.
|
||||
How to Convert an Image for Your Display
|
||||
Convert the image to 16-bit BGR565 format.
|
||||
Invert each 16-bit value (bitwise NOT or subtract from 0xFFFF).
|
||||
Save as a .raw file (no header, just pixel data).
|
||||
Can This Be Done in JavaScript (Browser)?
|
||||
Yes! You can:
|
||||
|
||||
Use an HTML <canvas> to load, resize, and crop the image.
|
||||
Read pixel data with getImageData.
|
||||
Convert each pixel to BGR565, invert it, and write to a binary buffer.
|
||||
Offer the result as a downloadable .raw file.
|
||||
Would you like a ready-to-use JavaScript/HTML tool for this? I can provide a complete example you can run in your browser.
|
||||
5
PacoMouseCYD/Platformio/SD/index.html
Normal file
5
PacoMouseCYD/Platformio/SD/index.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
49
PacoMouseCYD/Platformio/SD/js/bgr565.js
Normal file
49
PacoMouseCYD/Platformio/SD/js/bgr565.js
Normal file
@@ -0,0 +1,49 @@
|
||||
document.getElementById('convertBtn').onclick = function() {
|
||||
const fileInput = document.getElementById('imageInput');
|
||||
const width = parseInt(document.getElementById('width').value, 10);
|
||||
const height = parseInt(document.getElementById('height').value, 10);
|
||||
if (!fileInput.files.length) {
|
||||
alert('Please select an image file.');
|
||||
return;
|
||||
}
|
||||
const file = fileInput.files[0];
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
const img = new Image();
|
||||
img.onload = function() {
|
||||
const canvas = document.getElementById('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
ctx.drawImage(img, 0, 0, width, height);
|
||||
// Preview
|
||||
document.getElementById('preview').innerHTML = '';
|
||||
const previewImg = new Image();
|
||||
previewImg.src = canvas.toDataURL();
|
||||
document.getElementById('preview').appendChild(previewImg);
|
||||
// Get pixel data
|
||||
const imageData = ctx.getImageData(0, 0, width, height).data;
|
||||
const buf = new Uint8Array(width * height * 2);
|
||||
for (let i = 0, j = 0; i < imageData.length; i += 4, j += 2) {
|
||||
let r = imageData[i];
|
||||
let g = imageData[i+1];
|
||||
let b = imageData[i+2];
|
||||
// Convert to BGR565
|
||||
let bgr565 = ((b & 0xF8) << 8) | ((g & 0xFC) << 3) | (r >> 3);
|
||||
// Invert
|
||||
bgr565 = 0xFFFF - bgr565;
|
||||
buf[j] = bgr565 & 0xFF;
|
||||
buf[j+1] = (bgr565 >> 8) & 0xFF;
|
||||
}
|
||||
// Download
|
||||
const blob = new Blob([buf], {type: 'application/octet-stream'});
|
||||
const a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = file.name.replace(/\.[^.]+$/, '') + `_${width}x${height}_bgr565inv.raw`;
|
||||
a.click();
|
||||
};
|
||||
img.src = e.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
};
|
||||
184
PacoMouseCYD/Platformio/SD/js/loco.js
Normal file
184
PacoMouseCYD/Platformio/SD/js/loco.js
Normal file
@@ -0,0 +1,184 @@
|
||||
|
||||
changelanguage();
|
||||
|
||||
// Check for Web Browser API support.
|
||||
if (window.File && window.FileReader && window.FileList && window.Blob) {
|
||||
} else {
|
||||
alert("File APIs are not fully supported in this browser.");
|
||||
}
|
||||
|
||||
function saveTextAsFile()
|
||||
{
|
||||
var textToSave = document.getElementById("inputTextToSave").value;
|
||||
var textToSaveAsBlob = new Blob([textToSave], {type:"text/plain"});
|
||||
var textToSaveAsURL = window.URL.createObjectURL(textToSaveAsBlob);
|
||||
var fileNameToSaveAs = document.getElementById("inputFileNameToSaveAs").value;
|
||||
fileNameToSaveAs = fileNameToSaveAs + ".csv";
|
||||
|
||||
var downloadLink = document.createElement("a");
|
||||
downloadLink.download = fileNameToSaveAs;
|
||||
downloadLink.innerHTML = "Download File";
|
||||
downloadLink.href = textToSaveAsURL;
|
||||
downloadLink.onclick = destroyClickedElement;
|
||||
downloadLink.style.display = "none";
|
||||
document.body.appendChild(downloadLink);
|
||||
|
||||
downloadLink.click();
|
||||
}
|
||||
|
||||
function destroyClickedElement(event)
|
||||
{
|
||||
document.body.removeChild(event.target);
|
||||
}
|
||||
|
||||
function parseCSV()
|
||||
{
|
||||
var iconName;
|
||||
var funcName;
|
||||
var iconSel;
|
||||
var textToSave = document.getElementById("inputTextToSave");
|
||||
var textCSV = textToSave.value;
|
||||
var lines = textCSV.split("\n");
|
||||
var information = lines[1].split(";");
|
||||
var field = document.getElementById("NameLoco");
|
||||
field.value = information[0];
|
||||
field = document.getElementById("NumImage");
|
||||
field.value = information[1];
|
||||
field = document.getElementById("SpeedMax");
|
||||
field.value = information[2];
|
||||
for (let i = 0; i < 29; i++) {
|
||||
iconName = "iconID" + information[3 + i];
|
||||
funcName = "F" + i;
|
||||
iconSel = document.getElementById(funcName);
|
||||
iconSel.className = iconName;
|
||||
}
|
||||
var imgSrc = document.getElementById("imageToShow");
|
||||
imgSrc.src = "image/" + information[1] + ".bmp";
|
||||
}
|
||||
|
||||
|
||||
function loadFileAsText()
|
||||
{
|
||||
var fileToLoad = document.getElementById("fileToLoad").files[0];
|
||||
var loco = document.getElementById("NumLoco");
|
||||
var locoFileName = fileToLoad.name.split(".");
|
||||
loco.value = locoFileName[0];
|
||||
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function(fileLoadedEvent)
|
||||
{
|
||||
var textFromFileLoaded = fileLoadedEvent.target.result;
|
||||
document.getElementById("inputTextToSave").value = textFromFileLoaded;
|
||||
};
|
||||
fileReader.onloadend = function(progressEvent)
|
||||
{
|
||||
parseCSV();
|
||||
}
|
||||
fileReader.readAsText(fileToLoad, "UTF-8");
|
||||
hideInstrucctions();
|
||||
}
|
||||
|
||||
function loadFileAsImage()
|
||||
{
|
||||
var imgSrc = document.getElementById("imageToShow");
|
||||
var imgNum = document.getElementById("NumImage");
|
||||
var fileToLoad = document.getElementById("imageToLoad").files[0];
|
||||
var imgFileName = fileToLoad.name.split(".");
|
||||
imgNum.value = imgFileName[0];
|
||||
imgSrc.src = "image/" + imgFileName[0] + ".bmp";
|
||||
|
||||
hideInstrucctions();
|
||||
}
|
||||
|
||||
function changeImageLoco()
|
||||
{
|
||||
var imgNum = document.getElementById("NumImage");
|
||||
var imgSrc = document.getElementById("imageToShow");
|
||||
imgSrc.src = "image/" + imgNum.value + ".bmp";
|
||||
}
|
||||
|
||||
|
||||
function changelanguage()
|
||||
{
|
||||
const languageSelect = document.getElementById('language-select');
|
||||
elements = document.querySelectorAll(`span[lang]`);
|
||||
for (let element of elements) {
|
||||
element.style.display = 'none';
|
||||
}
|
||||
var x = languageSelect.selectedIndex;
|
||||
if (x==0) {elements = document.querySelectorAll(`span[lang="en"]`);}
|
||||
if (x==1) {elements = document.querySelectorAll(`span[lang="es"]`);}
|
||||
if (x==2) {elements = document.querySelectorAll(`span[lang="de"]`);}
|
||||
if (x==3) {elements = document.querySelectorAll(`span[lang="ca"]`); }
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
elements[i].style.display = 'inline-block';
|
||||
}
|
||||
};
|
||||
|
||||
function selectIcon(value)
|
||||
{
|
||||
var allIcon = document.getElementById('iconAll');
|
||||
allIcon.style.display = 'block';
|
||||
var funcNum = document.getElementById('NumFunc');
|
||||
funcNum.value = value;
|
||||
var iconFunc = document.getElementById('Fx');
|
||||
const iconText = "F" + value;
|
||||
iconFunc.innerHTML = iconText;
|
||||
}
|
||||
|
||||
|
||||
function updateIcon(value)
|
||||
{
|
||||
var funcNum = document.getElementById('NumFunc');
|
||||
const iconName = "iconID" + value;
|
||||
const funcName = "F" + funcNum.value;
|
||||
var iconSel = document.getElementById(funcName);
|
||||
iconSel.className = iconName;
|
||||
var allIcon = document.getElementById('iconAll');
|
||||
allIcon.style.display = 'none';
|
||||
hideInstrucctions();
|
||||
}
|
||||
|
||||
function hideInstrucctions()
|
||||
{
|
||||
var showIns = document.getElementById('instruc');
|
||||
showIns.style.display = 'none';
|
||||
}
|
||||
|
||||
function createTextCSV()
|
||||
{
|
||||
var fileNameToSaveAs = document.getElementById("inputFileNameToSaveAs")
|
||||
var textToSave = document.getElementById("inputTextToSave");
|
||||
var textCSV = "Name;Image;Vmax;F0;F1;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12;F13;F14;F15;F16;F17;F18;F19;F20;F21;F22;F23;F24;F25;F26;F27;F28\n";
|
||||
var loco = document.getElementById("NumLoco");
|
||||
var field = document.getElementById("NameLoco");
|
||||
var funcName;
|
||||
var iconSel;
|
||||
if (loco.value != "") {
|
||||
textCSV = textCSV + field.value;
|
||||
field = document.getElementById("NumImage");
|
||||
if (field.value == "")
|
||||
field.value = "0";
|
||||
textCSV = textCSV + ";" + field.value;
|
||||
field = document.getElementById("SpeedMax");
|
||||
if (field.value == "")
|
||||
field.value = "100";
|
||||
textCSV = textCSV + ";" + field.value ;
|
||||
|
||||
for (let i = 0; i < 29; i++) {
|
||||
funcName = "F" + i;
|
||||
iconSel = document.getElementById(funcName).className.split("iconID");
|
||||
iconSel = iconSel[1];
|
||||
textCSV = textCSV + ";" + iconSel ;
|
||||
}
|
||||
textCSV = textCSV + "\n"
|
||||
textToSave.value = textCSV;
|
||||
fileNameToSaveAs.value = loco.value;
|
||||
saveTextAsFile();
|
||||
field = document.getElementById('instruc');
|
||||
field.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
31
PacoMouseCYD/Platformio/SD/loco/loco.md
Normal file
31
PacoMouseCYD/Platformio/SD/loco/loco.md
Normal file
@@ -0,0 +1,31 @@
|
||||
From an ESP32 perspective, replacing .csv files with .yaml files for rarely loaded configuration is not costly in terms of performance or memory, as long as:
|
||||
|
||||
The YAML files are not excessively large.
|
||||
You use a lightweight YAML parser (such as arduino-yaml or a minimal C++ YAML parser).
|
||||
Configuration is only loaded occasionally (not in a tight loop).
|
||||
Pros of YAML:
|
||||
|
||||
More readable and maintainable for complex or nested data.
|
||||
Supports comments and richer data structures.
|
||||
Cons:
|
||||
|
||||
Slightly more code and memory required for parsing compared to simple CSV.
|
||||
Fewer lightweight YAML parsers available for microcontrollers than CSV/token-based parsing.
|
||||
Summary:
|
||||
If your configuration is not huge and is only loaded at startup or on demand, switching to YAML is reasonable and will not significantly impact ESP32 performance or memory usage. Just choose a minimal YAML parser suitable for embedded systems.
|
||||
|
||||
So format will be
|
||||
|
||||
```yaml
|
||||
Name: "Loco name"
|
||||
Image: "File name"
|
||||
Vmax: <speed>
|
||||
Functions:
|
||||
F0:
|
||||
F1:
|
||||
F2:
|
||||
...
|
||||
F28:
|
||||
Decoder:
|
||||
Brand:
|
||||
```
|
||||
71
PacoMouseCYD/Platformio/UsingDocker.md
Normal file
71
PacoMouseCYD/Platformio/UsingDocker.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Using PlatformIO with Docker and VS Code for ESP32 Development
|
||||
|
||||
This guide explains how to set up a workflow where:
|
||||
- VS Code is installed on your local workstation.
|
||||
- Source code and PlatformIO are inside a Docker container running on a remote machine.
|
||||
- The ESP32 device is physically connected to your local computer.
|
||||
|
||||
## Is this possible?
|
||||
Yes, it is possible! You can develop for ESP32 using PlatformIO in Docker on a remote machine, while connecting the ESP32 board to your local workstation. The key is to forward the ESP32's serial port from your local machine to the Docker container on the remote machine.
|
||||
|
||||
## Steps to Set Up
|
||||
|
||||
### 1. Prepare Your Remote Machine
|
||||
- Ensure Docker is installed and running on the remote machine.
|
||||
- Clone your project repository (with PlatformIO sources) to the remote machine.
|
||||
|
||||
### 2. Create a Docker Image with PlatformIO
|
||||
- Use a Dockerfile (see `.devcontainer/Dockerfile` or create your own) that installs PlatformIO CLI and any required dependencies.
|
||||
- Build the Docker image:
|
||||
```sh
|
||||
docker build -t platformio-dev .
|
||||
```
|
||||
|
||||
### 3. Share Source Code
|
||||
- Mount your project directory into the Docker container using Docker volumes:
|
||||
```sh
|
||||
docker run -it --name pio-dev -v /path/to/project:/workspace easylinux/platformio-dev:1.0
|
||||
```
|
||||
|
||||
### 4. Forward the ESP32 Serial Port
|
||||
- **Option 1: Use `socat` to forward the serial port over SSH**
|
||||
- On your local machine, install `socat`.
|
||||
- Find your ESP32 serial device (e.g., `/dev/ttyUSB0`).
|
||||
- Forward the serial port to the remote machine:
|
||||
```sh
|
||||
socat TCP-LISTEN:12345,reuseaddr,fork FILE:/dev/ttyUSB0,raw,echo=0
|
||||
```
|
||||
- On the remote machine (in Docker or before entering the container), forward the TCP port to a virtual serial device:
|
||||
```sh
|
||||
socat -d -d PTY,link=/tmp/ttyESP32,raw TCP:your.local.ip.address:12345
|
||||
```
|
||||
- In PlatformIO, use `/tmp/ttyESP32` as the upload port.
|
||||
|
||||
- **Option 2: Use VS Code Remote Development**
|
||||
- Use the "Remote - SSH" extension to open the remote folder in VS Code.
|
||||
- Use the "Remote - Containers" extension to develop inside the Docker container.
|
||||
- Use the "Serial Port Forwarding" feature (if available) to forward the ESP32 port.
|
||||
|
||||
### 5. Configure PlatformIO
|
||||
- In your `platformio.ini`, set the upload port to the forwarded device (e.g., `/tmp/ttyESP32`).
|
||||
- Example:
|
||||
```ini
|
||||
upload_port = /tmp/ttyESP32
|
||||
```
|
||||
|
||||
### 6. Develop and Upload
|
||||
- Edit code in VS Code (locally or via remote extensions).
|
||||
- Build and upload firmware using PlatformIO in Docker.
|
||||
|
||||
## Notes
|
||||
- Serial port forwarding may introduce some latency.
|
||||
- For debugging, ensure the forwarded port supports bidirectional communication.
|
||||
- You may need to adjust permissions for the serial device.
|
||||
|
||||
## References
|
||||
- [PlatformIO Docs: Remote Development](https://docs.platformio.org/en/latest/plus/pio-remote.html)
|
||||
- [VS Code Remote Development](https://code.visualstudio.com/docs/remote/remote-overview)
|
||||
- [Socat Serial Port Forwarding](https://stackoverflow.com/questions/39636742/forward-serial-port-over-tcp)
|
||||
|
||||
---
|
||||
This setup allows you to keep your development environment and sources on a remote machine, while still programming and debugging your ESP32 connected locally.
|
||||
1
PacoMouseCYD/Platformio/include/IPAddress.h
Normal file
1
PacoMouseCYD/Platformio/include/IPAddress.h
Normal file
@@ -0,0 +1 @@
|
||||
// None
|
||||
@@ -15,15 +15,13 @@ platform_packages =
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
|
||||
lib_deps =
|
||||
bodmer/TFT_eSPI
|
||||
bblanchon/ArduinoJson
|
||||
paulstoffregen/XPT2046_Touchscreen
|
||||
WiFi
|
||||
me-no-dev/AsyncTCP@1.1.1
|
||||
me-no-dev/ESPAsyncWebServer@1.2.3
|
||||
|
||||
SD
|
||||
build_flags =
|
||||
-DYELLOW_DISPLAY
|
||||
-DUSER_SETUP_LOADED
|
||||
@@ -49,5 +47,5 @@ build_flags =
|
||||
-DLOAD_FONT7
|
||||
-DLOAD_FONT8
|
||||
-DLOAD_GFXFF
|
||||
-DUSE_HSPI_PORT
|
||||
-DUSE_HSPI_PORT
|
||||
-DTFT_RGB_ORDER=TFT_BGR
|
||||
27
PacoMouseCYD/Platformio/run_pio_docker.sh
Executable file
27
PacoMouseCYD/Platformio/run_pio_docker.sh
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Usage: ./run_pio_docker.sh <ESP_PORT> [additional docker args]
|
||||
# Example: ./run_pio_docker.sh /dev/ttyUSB0
|
||||
|
||||
ESP_PORT="$1"
|
||||
shift
|
||||
|
||||
# if [ -z "$ESP_PORT" ]; then
|
||||
# echo "Usage: $0 <ESP_PORT> [additional docker args]"
|
||||
# exit 1
|
||||
# fi
|
||||
|
||||
IMAGE="easylinux/platformio-dev:1.0"
|
||||
CONTAINER="pio-dev"
|
||||
PROJECT_DIR="$(pwd)"
|
||||
|
||||
# Run Docker container with ESP port and project directory mounted
|
||||
# --device allows direct access to the ESP serial port
|
||||
|
||||
if [ -z "$ESP_PORT" ]; then
|
||||
docker run -d --rm --name "$CONTAINER" -v "$PROJECT_DIR:/workspace" -p 8022:22 "$IMAGE" "$@"
|
||||
else
|
||||
docker run -d --rm --name "$CONTAINER" -v "$PROJECT_DIR:/workspace" --device "$ESP_PORT" -p 8022:22 "$IMAGE" "$@"
|
||||
fi
|
||||
|
||||
# For advanced port forwarding, see UsingDocker.md (socat instructions)
|
||||
@@ -1,16 +1,14 @@
|
||||
#include <WiFi.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <AsyncTCP.h>
|
||||
|
||||
void launchWiFiConfig();
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <TFT_eSPI.h>
|
||||
#include "color.h"
|
||||
#include <EEPROM.h>
|
||||
#include <WiFi.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <EEPROM.h>
|
||||
#include <AsyncTCP.h>
|
||||
#include <SD.h>
|
||||
|
||||
#include "color.h"
|
||||
|
||||
void launchWiFiConfig();
|
||||
|
||||
// Read WiFi credentials from EEPROM
|
||||
#define WIFI_SSID_ADDR 0
|
||||
@@ -75,13 +73,28 @@ void setup()
|
||||
tft.println("WiFi credentials missing!");
|
||||
tft.setCursor(10, 40);
|
||||
tft.setTextColor(COLOR_YELLOW);
|
||||
tft.println("Launch WiFiConfig to set them.");
|
||||
tft.println("Please connect to CYD_Config AP");
|
||||
tft.setCursor(10, 55);
|
||||
tft.println("and set WiFi credentials");
|
||||
launchWiFiConfig(); // Function to start WiFi configuration mode (not implemented here)
|
||||
|
||||
} else {
|
||||
// Ok connect to WiFi
|
||||
tft.setCursor(60, 10);
|
||||
tft.setTextColor(COLOR_GREEN);
|
||||
tft.println("OK");
|
||||
DEBUG_MSG("WiFi SSID: %s", wifi_ssid);
|
||||
DEBUG_MSG("WiFi PASS: %s", wifi_pass);
|
||||
}
|
||||
// Try to open SD card and read content
|
||||
if (!SD.begin()) {
|
||||
tft.println("SD Card not found!");
|
||||
while (1); // or handle error as needed
|
||||
}
|
||||
if (!SD.exists("/loco")) {
|
||||
tft.println("loco/ folder not found!");
|
||||
while (1); // or handle error as needed
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -114,7 +127,7 @@ void launchWiFiConfig()
|
||||
WiFi.softAP("CYD_Config", "12345678");
|
||||
IPAddress myIP = WiFi.softAPIP();
|
||||
DEBUG_MSG("AP IP address: %s", myIP.toString().c_str());
|
||||
AsyncWebServer server(80);
|
||||
AsyncWebServer server(80);
|
||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
String html = "<html><body><h2>WiFi Config</h2>"
|
||||
"<form action='/save' method='post'>"
|
||||
|
||||
Reference in New Issue
Block a user