Reorganisation fichiers

This commit is contained in:
Serge NOEL
2026-02-13 08:49:53 +01:00
parent ec9957d5b1
commit 758f73bc0e
33 changed files with 977 additions and 499 deletions

View File

@@ -0,0 +1,411 @@
/**
* @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/
*/
////////////////////////////////////////////////////////////
// ***** ACCESSORY FIFO *****
////////////////////////////////////////////////////////////
void initFIFO() {
lastInFIFO = 0;
firstOutFIFO = 0;
cntFIFO = 0;
stateFIFO = FIFO_EMPTY;
}
unsigned int readFIFO () {
firstOutFIFO = (firstOutFIFO + 1 ) & 0x1F; // next one (hardcoded)
cntFIFO--;
return (accessoryFIFO[firstOutFIFO]);
}
void writeFIFO (uint16_t FAdr, uint8_t pos) {
lastInFIFO = (lastInFIFO + 1 ) & 0x1F; // next one (hardcoded)
cntFIFO++;
if (pos > 0)
FAdr |= 0x8000;
accessoryFIFO[lastInFIFO] = FAdr; // save in FIFO
}
void sendAccessoryFIFO () {
switch (stateFIFO) {
case FIFO_ACC_CDU: // wait for CDU recharge
case FIFO_EMPTY:
if (cntFIFO > 0) { // activate accessory from FIFO
lastAccessory = readFIFO();
sendAccessory(lastAccessory & 0x7FFF, bitRead(lastAccessory, 15), true);
setTimer(TMR_ACCESSORY, TIME_ACC_ON, TMR_ONESHOT);
stateFIFO = FIFO_ACC_ON;
DEBUG_MSG("Moving acc. %d-%d", lastAccessory & 0x7FFF, lastAccessory >> 15);
}
else
stateFIFO = FIFO_EMPTY;
break;
case FIFO_ACC_ON: // deactivate accessory
sendAccessory(lastAccessory & 0x7FFF, bitRead(lastAccessory, 15), false);
setTimer(TMR_ACCESSORY, TIME_ACC_CDU, TMR_ONESHOT);
stateFIFO = FIFO_ACC_CDU;
break;
}
}
////////////////////////////////////////////////////////////
// ***** ACCESSORY *****
////////////////////////////////////////////////////////////
void moveAccessory(uint16_t FAdr, uint8_t pos) {
writeFIFO(FAdr, pos); // put accessory in FIFO
if (stateFIFO == FIFO_EMPTY) // if not pending accessories, force sending now
sendAccessoryFIFO();
}
void setAccAspect(uint16_t FAdr, uint16_t FAdr2, uint8_t aspect, uint16_t outs) {
uint8_t pos;
pos = aspect * 4;
if (FAdr > 0) {
if (bitRead(outs, pos)) {
moveAccessory(FAdr, 0);
}
else {
if (bitRead(outs, pos + 1))
moveAccessory(FAdr, 1);
}
}
if (FAdr2 > 0) {
if (bitRead(outs, pos + 2)) {
moveAccessory(FAdr2, 0);
}
else {
if (bitRead(outs, pos + 3))
moveAccessory(FAdr2, 1);
}
}
}
////////////////////////////////////////////////////////////
// ***** PANEL *****
////////////////////////////////////////////////////////////
void deleteAccPanelElement(uint8_t pos) {
accPanel[pos].type = ACC_UNDEF;
accPanel[pos].currAspect = 0;
accPanel[pos].addr = 0;
accPanel[pos].addr2 = 0;
accPanel[pos].activeOutput = 0;
accPanel[pos].accName[0] = '\0';
}
void loadDefaultAccPanel() {
uint8_t n;
for (n = 0; n < 16; n++) { // Default panel is all blank with only a keypad button
deleteAccPanelElement(n);
}
accPanel[15].type = ACC_KEYPAD;
}
void updateAccPanel() {
uint8_t n, type, aspect;
snprintf(panelNameBuf, PANEL_LNG + 1, panelNamesBuf[currPanel]);
for (n = 0; n < 16; n++) {
type = accPanel[n].type;
aspect = accPanel[n].currAspect;
snprintf(accNamesBuf[n], ACC_LNG + 1, accPanel[n].accName);
fncData[FNC_ACC0 + n].num = accDef[type].num;
fncData[FNC_ACC0 + n].idIcon = accDef[type].icon[aspect].fncIcon;
fncData[FNC_ACC0 + n].color = accDef[type].icon[aspect].color;
fncData[FNC_ACC0 + n].colorOn = accDef[type].icon[aspect].colorOn;
fncData[FNC_ACC0 + n].backgnd = (type == ACC_UNDEF) ? COLOR_WHITE : COLOR_LIGHTGREY;
buttonData[BUT_ACC_0 + n].backgnd = (type == ACC_UNDEF) ? COLOR_WHITE : COLOR_LIGHTGREY;
}
}
void saveCurrentAspects() {
uint8_t n;
for (n = 0; n < 16; n++)
savedAspect[currPanel][n] = accPanel[n].currAspect;
}
void getLastAspects() {
uint8_t n;
for (n = 0; n < 16; n++)
accPanel[n].currAspect = savedAspect[currPanel][n];
}
void deleteLastAspects() {
uint8_t n;
for (n = 0; n < 16; n++)
accPanel[n].currAspect = 0;
}
void initLastAspects() {
uint8_t i, j;
for (i = 0; i < 16; i++)
for (j = 0; j < 16; j++)
savedAspect[i][j] = 0;;
}
void populateAccPanel() {
loadDefaultAccPanel(); // Load panel data
if (sdDetected) {
if (loadAccPanel(SD))
getLastAspects();
else
deleteLastAspects();
}
else {
if (loadAccPanel(LittleFS))
getLastAspects();
else
deleteLastAspects();
}
updateAccPanel();
}
void accPanelClick(uint8_t pos) {
uint16_t addr, outs;
uint8_t type, aspect;
currPanelAcc = pos;
if (editAccessory) {
paramChild = pos;
type = accPanel[pos].type;
fncData[FNC_ACC_TYPE].num = accDef[type].num;
fncData[FNC_ACC_TYPE].idIcon = accDef[type].icon[0].fncIcon;
fncData[FNC_ACC_TYPE].color = accDef[type].icon[0].color;
fncData[FNC_ACC_TYPE].colorOn = accDef[type].icon[0].colorOn;
encoderValue = type;
encoderMax = ACC_MAX - 1;
openWindow(WIN_ACC_TYPE);
}
else {
type = accPanel[pos].type;
switch (type) {
case ACC_UNDEF:
break;
case ACC_KEYPAD:
openWindow(WIN_ACC_CTRL);
break;
default:
addr = accPanel[pos].addr;
outs = accPanel[pos].activeOutput;
switch (accDef[type].aspects) {
case 2:
aspect = (accPanel[pos].currAspect > 0) ? 0 : 1;
accPanel[pos].currAspect = aspect;
fncData[FNC_ACC0 + pos].idIcon = accDef[type].icon[aspect].fncIcon;
fncData[FNC_ACC0 + pos].color = accDef[type].icon[aspect].color;
fncData[FNC_ACC0 + pos].colorOn = accDef[type].icon[aspect].colorOn;
setAccAspect(addr, 0, aspect, outs);
newEvent(OBJ_BUTTON, BUT_ACC_0 + pos, EVNT_DRAW);
break;
case 3:
currAccAspects = 3;
winData[WIN_ACC_ASPECT].x = 30;
winData[WIN_ACC_ASPECT].w = 180;
buttonData[BUT_ACC_ASPECT0].x = 50;
buttonData[BUT_ACC_ASPECT1].x = 100;
buttonData[BUT_ACC_ASPECT2].x = 150;
fncData[FNC_ASPECT0].x = 54;
fncData[FNC_ASPECT0].idIcon = accDef[type].icon[0].fncIcon;
fncData[FNC_ASPECT0].color = accDef[type].icon[0].color;
fncData[FNC_ASPECT0].colorOn = accDef[type].icon[0].colorOn;
fncData[FNC_ASPECT1].x = 104;
fncData[FNC_ASPECT1].idIcon = accDef[type].icon[1].fncIcon;
fncData[FNC_ASPECT1].color = accDef[type].icon[1].color;
fncData[FNC_ASPECT1].colorOn = accDef[type].icon[1].colorOn;
fncData[FNC_ASPECT2].x = 154;
fncData[FNC_ASPECT2].idIcon = accDef[type].icon[2].fncIcon;
fncData[FNC_ASPECT2].color = accDef[type].icon[2].color;
fncData[FNC_ASPECT2].colorOn = accDef[type].icon[2].colorOn;
openWindow(WIN_ACC_ASPECT);
break;
case 4:
currAccAspects = 4;
winData[WIN_ACC_ASPECT].x = 5;
winData[WIN_ACC_ASPECT].w = 230;
buttonData[BUT_ACC_ASPECT0].x = 25;
buttonData[BUT_ACC_ASPECT1].x = 75;
buttonData[BUT_ACC_ASPECT2].x = 125;
buttonData[BUT_ACC_ASPECT3].x = 175;
fncData[FNC_ASPECT0].x = 29;
fncData[FNC_ASPECT0].idIcon = accDef[type].icon[0].fncIcon;
fncData[FNC_ASPECT0].color = accDef[type].icon[0].color;
fncData[FNC_ASPECT0].colorOn = accDef[type].icon[0].colorOn;
fncData[FNC_ASPECT1].x = 79;
fncData[FNC_ASPECT1].idIcon = accDef[type].icon[1].fncIcon;
fncData[FNC_ASPECT1].color = accDef[type].icon[1].color;
fncData[FNC_ASPECT1].colorOn = accDef[type].icon[1].colorOn;
fncData[FNC_ASPECT2].x = 129;
fncData[FNC_ASPECT2].idIcon = accDef[type].icon[2].fncIcon;
fncData[FNC_ASPECT2].color = accDef[type].icon[2].color;
fncData[FNC_ASPECT2].colorOn = accDef[type].icon[2].colorOn;
fncData[FNC_ASPECT3].x = 179;
fncData[FNC_ASPECT3].idIcon = accDef[type].icon[3].fncIcon;
fncData[FNC_ASPECT3].color = accDef[type].icon[3].color;
fncData[FNC_ASPECT3].colorOn = accDef[type].icon[3].colorOn;
openWindow(WIN_ACC_ASPECT);
break;
default:
buttonData[BUT_ACC_0 + pos].backgnd = COLOR_BLACK;
drawObject(OBJ_BUTTON, BUT_ACC_0 + pos);
buttonData[BUT_ACC_0 + pos].backgnd = COLOR_LIGHTGREY;
setAccAspect(addr, 0, 0, outs);
newEvent(OBJ_BUTTON, BUT_ACC_0 + pos, EVNT_DRAW);
delay(80);
break;
}
break;
}
}
}
void accAspectClick(uint8_t aspect) {
uint16_t addr, addr2, outs;
uint8_t type;
type = accPanel[currPanelAcc].type;
accPanel[currPanelAcc].currAspect = aspect;
fncData[FNC_ACC0 + currPanelAcc].idIcon = accDef[type].icon[aspect].fncIcon;
fncData[FNC_ACC0 + currPanelAcc].color = accDef[type].icon[aspect].color;
fncData[FNC_ACC0 + currPanelAcc].colorOn = accDef[type].icon[aspect].colorOn;
addr = accPanel[currPanelAcc].addr;
addr2 = accPanel[currPanelAcc].addr2;
outs = accPanel[currPanelAcc].activeOutput;
setAccAspect(addr, addr2, aspect, outs);
}
void accTypeClick() {
uint8_t index, n;
index = encoderValue;
switch (index) {
case ACC_UNDEF:
alertWindow(ERR_ASK_SURE);
break;
case ACC_KEYPAD:
editAccessory = false;
winData[WIN_ACCESSORY].backgnd = COLOR_WHITE;
deleteAccPanelElement(paramChild);
accPanel[paramChild].type = ACC_KEYPAD;
updateAccPanel();
updateSpeedHID(); // set encoder
closeWindow(WIN_ACC_TYPE);
break;
default:
if (index != accPanel[paramChild].type) {
currAccEdit.type = (accType)index;
currAccEdit.addr = 0;
currAccEdit.addr2 = 0;
currAccEdit.currAspect = 0;
currAccEdit.activeOutput = accOutDefault[index];
currAccEdit.accName[0] = '\0';
}
else {
currAccEdit = accPanel[paramChild];
}
snprintf(accKeybName, ACC_LNG + 1, currAccEdit.accName);
snprintf(accKeybAddr1, ADDR_LNG + 1, "%d", currAccEdit.addr);
snprintf(accKeybAddr2, ADDR_LNG + 1, "%d", currAccEdit.addr2);
for (n = 0; n < 4; n++) {
fncData[FNC_EDIT_ASPECT0 + n].idIcon = accDef[index].icon[n].fncIcon;
fncData[FNC_EDIT_ASPECT0 + n].color = accDef[index].icon[n].color;
fncData[FNC_EDIT_ASPECT0 + n].colorOn = accDef[index].icon[n].colorOn;
}
accOutUpdate();
closeWindow(WIN_ACC_TYPE);
openWindow(WIN_ACC_EDIT);
break;
}
}
void accOutUpdate() {
uint8_t n;
for (n = 0; n < 16; n += 2) {
buttonData[BUT_ACC_OUT0 + n].backgnd = bitRead(currAccEdit.activeOutput, n) ? COLOR_RED : COLOR_LIGHTBLACK;
buttonData[BUT_ACC_OUT0 + n + 1].backgnd = bitRead(currAccEdit.activeOutput, n + 1) ? COLOR_GREEN : COLOR_LIGHTBLACK;
}
}
void accOutClick(uint8_t out) {
uint8_t outR, outG;
outR = out & 0xFE;
outG = out | 0x01;
currAccEdit.activeOutput ^= bit(out);
if (bitRead(out, 0)) { // green
if (bitRead(currAccEdit.activeOutput, outG))
bitClear(currAccEdit.activeOutput, outR);
}
else { // red
if (bitRead(currAccEdit.activeOutput, outR))
bitClear(currAccEdit.activeOutput, outG);
}
accOutUpdate();
newEvent(OBJ_BUTTON, BUT_ACC_OUT0 + outR, EVNT_DRAW);
newEvent(OBJ_BUTTON, BUT_ACC_OUT0 + outG, EVNT_DRAW);
}
void updateAccChange() {
accPanel[paramChild] = currAccEdit;
updateAccPanel();
accPanelChanged = true;
}