Reorganisation fichiers
This commit is contained in:
399
PacoMouseCYD/Platformio/Arduino.old/steam.ino
Normal file
399
PacoMouseCYD/Platformio/Arduino.old/steam.ino
Normal file
@@ -0,0 +1,399 @@
|
||||
/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ***** STEAM THROTTLE *****
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
void initSteamThrottle () {
|
||||
uint16_t n;
|
||||
if (oldSteamLoco != locoData[myLocoData].myAddr.address) {
|
||||
oldSteamLoco = locoData[myLocoData].myAddr.address;
|
||||
steamPressure = 80;
|
||||
waterLevelBoiler = 80;
|
||||
waterLevelTender = 350;
|
||||
oldPressure = 0;
|
||||
oldLevelBoiler = 0;
|
||||
oldLevelTender = 0;
|
||||
barData[BAR_JOHNSON].value = STEAM_JOHNSON_NEUTRAL; // neutral position
|
||||
barData[BAR_BRAKE].value = 0;
|
||||
steamDir = locoData[myLocoData].myDir;
|
||||
for (n = 0; n < MAX_LIMIT; n++)
|
||||
steamSpeedLimit[n] = LIMIT_NONE;
|
||||
}
|
||||
currentSteamTime = millis();
|
||||
steamTimeSpeed = currentSteamTime;
|
||||
steamTimeSteam = currentSteamTime;
|
||||
steamTimeWater = currentSteamTime;
|
||||
steamTimeLoad = currentSteamTime;
|
||||
steamTimeSmoke = currentSteamTime;
|
||||
shovelCoal = false;
|
||||
setFirebox();
|
||||
endWaterInjection();
|
||||
endTenderFill();
|
||||
setTimer(TMR_STEAM, 5, TMR_ONESHOT);
|
||||
changeSmoke = STEAM_SMOKE_FAST;
|
||||
oldPressure = 0;
|
||||
oldSpeedSteam = 305;
|
||||
encoderMax = 31; // set throttle to current speed
|
||||
updateSteamThrottle();
|
||||
if (steamDir != locoData[myLocoData].myDir) { // check Johnson bar position
|
||||
steamDir = locoData[myLocoData].myDir;
|
||||
barData[BAR_JOHNSON].value = 6 - barData[BAR_JOHNSON].value;
|
||||
}
|
||||
}
|
||||
|
||||
void updateSteamThrottle() {
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
case CLIENT_XNET:
|
||||
if (bitRead(locoData[myLocoData].mySteps, 2)) { // 0..127
|
||||
currentSteamSpeed = locoData[myLocoData].mySpeed;
|
||||
encoderValue = currentSteamSpeed >> 2;
|
||||
}
|
||||
else {
|
||||
if (bitRead(locoData[myLocoData].mySteps, 1)) { // 0..31
|
||||
encoderValue = (locoData[myLocoData].mySpeed & 0x0F) << 1;
|
||||
if (bitRead(locoData[myLocoData].mySpeed, 4))
|
||||
bitSet(encoderValue, 0);
|
||||
currentSteamSpeed = (encoderValue > 3) ? (encoderValue << 2) + (encoderValue >> 3) : 0;
|
||||
}
|
||||
else { // 0..15
|
||||
encoderValue = locoData[myLocoData].mySpeed & 0x0F;
|
||||
encoderValue = (encoderValue > 1) ? encoderValue << 1 : 0;
|
||||
currentSteamSpeed = (encoderValue << 2) + (encoderValue >> 3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
case CLIENT_ECOS:
|
||||
currentSteamSpeed = locoData[myLocoData].mySpeed;
|
||||
encoderValue = currentSteamSpeed >> 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void steamProcess() {
|
||||
uint16_t value, newSpeed, mappedThrottle, jFactor;
|
||||
|
||||
steamSpeedLimit[LIMIT_THROTTLE] = (encoderValue << 2) + (encoderValue >> 3); // Read Throtle Speed (0..31 -> 0..127)
|
||||
|
||||
steamSpeedLimit[LIMIT_JOHNSON] = LIMIT_NONE;
|
||||
switch (barData[BAR_JOHNSON].value) { // Read Johnson Bar
|
||||
case 0: // full reverse
|
||||
jFactor = 3;
|
||||
changeSpeed = 80;
|
||||
steamDir = 0x00;
|
||||
break;
|
||||
case 1:
|
||||
jFactor = 2;
|
||||
changeSpeed = 200;
|
||||
steamDir = 0x00;
|
||||
break;
|
||||
case 2:
|
||||
jFactor = 1;
|
||||
changeSpeed = 500;
|
||||
steamDir = 0x00;
|
||||
break;
|
||||
case STEAM_JOHNSON_NEUTRAL: // Neutral position of Johnson Bar
|
||||
jFactor = 1;
|
||||
changeSpeed = 1000;
|
||||
steamSpeedLimit[LIMIT_JOHNSON] = 0;
|
||||
break;
|
||||
case 4:
|
||||
jFactor = 1;
|
||||
changeSpeed = 500;
|
||||
steamDir = 0x80;
|
||||
break;
|
||||
case 5:
|
||||
jFactor = 2;
|
||||
changeSpeed = 200;
|
||||
steamDir = 0x80;
|
||||
break;
|
||||
case 6: // full forward
|
||||
jFactor = 3;
|
||||
changeSpeed = 80;
|
||||
steamDir = 0x80;
|
||||
break;
|
||||
}
|
||||
|
||||
if (steamDir != locoData[myLocoData].myDir) { // Check direction
|
||||
locoData[myLocoData].myDir = steamDir;
|
||||
changeDirection();
|
||||
DEBUG_MSG("STEAM: Change direction")
|
||||
}
|
||||
|
||||
value = steamSpeedLimit[LIMIT_THROTTLE];
|
||||
changeSteam = 10000 - ((value * 9) * jFactor); // Steam timeout: 6571 to 10000
|
||||
changeWater = 14000 - ((value * 27) * jFactor); // Water timeout: 3713 to 14000
|
||||
if (barData[BAR_BRAKE].value > 0) { // Brake bar: 300, 150, 100
|
||||
changeSpeed = 300 / barData[BAR_BRAKE].value;
|
||||
}
|
||||
currentSteamTime = millis();
|
||||
|
||||
if (currentSteamTime > (steamTimeWater + changeWater)) { // Water consumption
|
||||
steamTimeWater = currentSteamTime;
|
||||
if (waterLevelBoiler > 0) {
|
||||
waterLevelBoiler--;
|
||||
DEBUG_MSG("Boiler Level: %d", waterLevelBoiler)
|
||||
}
|
||||
}
|
||||
if (waterLevelBoiler < 10) { // Stop loco if not enough water
|
||||
steamSpeedLimit[LIMIT_WATER] = 0;
|
||||
steamThrottleStop();
|
||||
}
|
||||
else {
|
||||
steamSpeedLimit[LIMIT_WATER] = LIMIT_NONE;
|
||||
}
|
||||
|
||||
if (currentSteamTime > (steamTimeSteam + changeSteam)) { // Steam consumption
|
||||
steamTimeSteam = currentSteamTime;
|
||||
if (steamPressure > 0)
|
||||
steamPressure--;
|
||||
}
|
||||
|
||||
if (steamPressure < 50) { // Limit speed based on steam level
|
||||
value = (steamPressure < 20) ? 0 : map(steamPressure, 20, 50, 20, 120);
|
||||
steamSpeedLimit[LIMIT_PRESSURE] = value;
|
||||
}
|
||||
else {
|
||||
steamSpeedLimit[LIMIT_PRESSURE] = LIMIT_NONE;
|
||||
}
|
||||
|
||||
if (currentSteamTime > (steamTimeLoad + STEAM_LOAD_TIME)) { // Load coal and water
|
||||
steamTimeLoad = currentSteamTime;
|
||||
if (shovelCoal) { // Fire open for shoveling coal
|
||||
if (steamPressure > 96) {
|
||||
shovelCoal = false;
|
||||
setFirebox();
|
||||
newEvent(OBJ_FNC, FNC_ST_FIRE, EVNT_DRAW);
|
||||
}
|
||||
else {
|
||||
if (steamPressure < 20) // slowly pressure up at beginning
|
||||
steamPressure += 1;
|
||||
else
|
||||
steamPressure += 2;
|
||||
}
|
||||
}
|
||||
if (waterInjection) { // Water injector open
|
||||
if (waterLevelTender > 0) { // Inject water with water from tender
|
||||
if (waterLevelBoiler > 95) {
|
||||
endWaterInjection();
|
||||
}
|
||||
else {
|
||||
waterLevelBoiler += 2;
|
||||
waterLevelTender--;
|
||||
}
|
||||
steamSpeedLimit[LIMIT_TENDER] = LIMIT_NONE;
|
||||
}
|
||||
else {
|
||||
endWaterInjection(); // Stop locomotive if tender empty
|
||||
steamSpeedLimit[LIMIT_TENDER] = 0;
|
||||
steamThrottleStop();
|
||||
}
|
||||
}
|
||||
if (fillTender) {
|
||||
if ((waterLevelTender > 495) || (currentSteamSpeed != 0)) { // Only fill tender when stopped
|
||||
endTenderFill();
|
||||
}
|
||||
else {
|
||||
waterLevelTender++;
|
||||
if (waterLevelTender > 6) // Minimum level to run again
|
||||
steamSpeedLimit[LIMIT_TENDER] = LIMIT_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentSteamTime > (steamTimeSmoke + changeSmoke)) { // Chimney smoke
|
||||
steamTimeSmoke = currentSteamTime;
|
||||
if (currentSteamSpeed > 0) {
|
||||
fncData[FNC_ST_SMOKE].state = !fncData[FNC_ST_SMOKE].state;
|
||||
changeSmoke = map(currentSteamSpeed, 0, 127, STEAM_SMOKE_SLOW, STEAM_SMOKE_FAST);
|
||||
}
|
||||
else {
|
||||
fncData[FNC_ST_SMOKE].state = false;
|
||||
changeSmoke = STEAM_SMOKE_SLOW + STEAM_SMOKE_SLOW;
|
||||
}
|
||||
newEvent(OBJ_FNC, FNC_ST_SMOKE, EVNT_DRAW);
|
||||
}
|
||||
|
||||
if (barData[BAR_BRAKE].value > 0) { // Braking
|
||||
value = barData[BAR_BRAKE].value * 8;
|
||||
value = (currentSteamSpeed > value) ? (currentSteamSpeed - value) : 0;
|
||||
steamSpeedLimit[LIMIT_BRAKE] = value;
|
||||
}
|
||||
else {
|
||||
steamSpeedLimit[LIMIT_BRAKE] = LIMIT_NONE;
|
||||
}
|
||||
|
||||
targetSpeedSteam = LIMIT_NONE; // Find lower limit
|
||||
for (value = 0; value < MAX_LIMIT; value++) {
|
||||
if (steamSpeedLimit[value] < targetSpeedSteam)
|
||||
targetSpeedSteam = steamSpeedLimit[value];
|
||||
}
|
||||
|
||||
newSpeed = currentSteamSpeed;
|
||||
if (currentSteamTime > (steamTimeSpeed + changeSpeed)) { // Speed acceleration
|
||||
steamTimeSpeed = currentSteamTime;
|
||||
//DEBUG_MSG("Target: %d Current: %d New: %d", targetSpeedSteam, currentSteamSpeed, newSpeed)
|
||||
if (targetSpeedSteam > currentSteamSpeed) {
|
||||
newSpeed = currentSteamSpeed + 1;
|
||||
DEBUG_MSG("Inc New: %d", newSpeed)
|
||||
}
|
||||
if (targetSpeedSteam < currentSteamSpeed) {
|
||||
newSpeed = currentSteamSpeed - 1;
|
||||
DEBUG_MSG("Dec New: %d", newSpeed)
|
||||
}
|
||||
//DEBUG_MSG("New acc: %d", newSpeed)
|
||||
}
|
||||
|
||||
|
||||
if (currentSteamSpeed != newSpeed) { // changes in speed
|
||||
DEBUG_MSG("Step: %d - New: %d LIMITS ", currentSteamSpeed, newSpeed)
|
||||
#ifdef DEBUG
|
||||
for (value = 0; value < MAX_LIMIT; value++) {
|
||||
Serial.print(steamSpeedLimit[value]);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
currentSteamSpeed = newSpeed;
|
||||
switch (wifiSetting.protocol) {
|
||||
case CLIENT_Z21:
|
||||
case CLIENT_XNET:
|
||||
if (bitRead(locoData[myLocoData].mySteps, 2)) { // 128 steps
|
||||
mappedThrottle = (currentSteamSpeed > 1) ? currentSteamSpeed : 0;
|
||||
}
|
||||
else {
|
||||
if (bitRead(locoData[myLocoData].mySteps, 1)) { // 28 steps
|
||||
if (currentSteamSpeed > 15) {
|
||||
mappedThrottle = currentSteamSpeed >> 3;
|
||||
bitWrite(mappedThrottle, 4, bitRead(currentSteamSpeed, 2));
|
||||
}
|
||||
else {
|
||||
mappedThrottle = 0;
|
||||
}
|
||||
}
|
||||
else { // 14 steps
|
||||
mappedThrottle = (currentSteamSpeed > 15) ? currentSteamSpeed >> 3 : 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CLIENT_LNET:
|
||||
case CLIENT_ECOS:
|
||||
mappedThrottle = (currentSteamSpeed > 1) ? currentSteamSpeed : 0;
|
||||
break;
|
||||
}
|
||||
locoData[myLocoData].mySpeed = mappedThrottle;
|
||||
locoOperationSpeed();
|
||||
DEBUG_MSG("Steam step: %d", currentSteamSpeed)
|
||||
if ((currentSteamSpeed > 0) && (changeSmoke > STEAM_SMOKE_SLOW)) { // initial chuff
|
||||
changeSmoke = 0;
|
||||
fncData[FNC_ST_SMOKE].state = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((oldLevelTender / 10) != (waterLevelTender / 10)) {
|
||||
oldLevelTender = waterLevelTender;
|
||||
barData[BAR_TENDER].value = waterLevelTender;
|
||||
newEvent(OBJ_BAR, BAR_TENDER, EVNT_DRAW);
|
||||
}
|
||||
|
||||
value = waterLevelBoiler / 2;
|
||||
if (oldLevelBoiler != value ) {
|
||||
oldLevelBoiler = value;
|
||||
barData[BAR_WATER].value = value;
|
||||
newEvent(OBJ_BAR, BAR_WATER, EVNT_DRAW);
|
||||
}
|
||||
|
||||
value = steamPressure * 270 / 100;
|
||||
if (oldPressure != value) {
|
||||
showPressure(value);
|
||||
DEBUG_MSG("Pressure: %d", steamPressure)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void startWaterInjection () {
|
||||
waterInjection = true;
|
||||
fncData[FNC_ST_WATER].colorOn = COLOR_DARKGREEN;
|
||||
drawObject(OBJ_FNC, FNC_ST_WATER);
|
||||
}
|
||||
|
||||
|
||||
void endWaterInjection () {
|
||||
waterInjection = false;
|
||||
fncData[FNC_ST_WATER].colorOn = COLOR_RED;
|
||||
drawObject(OBJ_FNC, FNC_ST_WATER);
|
||||
}
|
||||
|
||||
|
||||
void startTenderFill() {
|
||||
fillTender = true;
|
||||
//fncData[FNC_ST_TENDER].color = COLOR_RED;
|
||||
fncData[FNC_ST_TENDER].colorOn = COLOR_DARKGREEN;
|
||||
drawObject(OBJ_FNC, FNC_ST_TENDER);
|
||||
}
|
||||
|
||||
|
||||
void endTenderFill() {
|
||||
fillTender = false;
|
||||
//fncData[FNC_ST_TENDER].color = COLOR_WHITE;
|
||||
fncData[FNC_ST_TENDER].colorOn = COLOR_RED;
|
||||
drawObject(OBJ_FNC, FNC_ST_TENDER);
|
||||
}
|
||||
|
||||
|
||||
void setFirebox() {
|
||||
if (shovelCoal) {
|
||||
fncData[FNC_ST_FIRE].idIcon = FNC_FIRE_OP_OFF;
|
||||
fncData[FNC_ST_FIRE].color = COLOR_ORANGE;
|
||||
fncData[FNC_ST_FIRE].colorOn = COLOR_YELLOW;
|
||||
}
|
||||
else {
|
||||
fncData[FNC_ST_FIRE].idIcon = FNC_FIRE_CL_OFF;
|
||||
fncData[FNC_ST_FIRE].color = COLOR_SILVER;
|
||||
fncData[FNC_ST_FIRE].colorOn = COLOR_RED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void steamThrottleStop() { // set controls for stop
|
||||
if (encoderValue > 0) {
|
||||
encoderValue = 0;
|
||||
showSpeedSteam(240);
|
||||
}
|
||||
if (barData[BAR_JOHNSON].value != STEAM_JOHNSON_NEUTRAL) {
|
||||
barData[BAR_JOHNSON].value = STEAM_JOHNSON_NEUTRAL; // Neutral
|
||||
drawObject(OBJ_BAR, BAR_JOHNSON);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void showPressure(uint16_t angle) {
|
||||
tft.setPivot(140, 105); // Set pivot to center of manometer in TFT screen
|
||||
sprite.setColorDepth(8); // Create an 8bpp Sprite
|
||||
sprite.createSprite(19, 19); // 8bpp requires 19 * 19 = 361 bytes
|
||||
sprite.setPivot(9, 9); // Set pivot relative to top left corner of Sprite
|
||||
sprite.fillSprite(COLOR_WHITE); // Fill the Sprite with background
|
||||
sprite.pushRotated(oldPressure);
|
||||
oldPressure = angle;
|
||||
sprite.drawBitmap(0, 0, needle_bar, 19, 19, COLOR_BLUE);
|
||||
sprite.pushRotated(angle);
|
||||
sprite.deleteSprite();
|
||||
}
|
||||
|
||||
void showSpeedSteam(uint16_t angle) {
|
||||
tft.setPivot(120, 170); // Set pivot to center of bar in TFT screen
|
||||
sprite.setColorDepth(8); // Create an 8bpp Sprite
|
||||
sprite.createSprite(83, 15); // 8bpp requires 83 * 15 = 1245 bytes
|
||||
sprite.setPivot(76, 7); // Set pivot relative to top left corner of Sprite
|
||||
sprite.fillSprite(COLOR_BLACK); // Fill the Sprite with background
|
||||
sprite.pushRotated(oldSpeedSteam);
|
||||
oldSpeedSteam = angle;
|
||||
sprite.drawBitmap(0, 0, speed_steam, 83, 15, COLOR_RED);
|
||||
sprite.pushRotated(angle);
|
||||
tft.drawArc(120, 170, 27, 22, 315, 45, COLOR_RED, COLOR_BLACK, false);
|
||||
sprite.deleteSprite();
|
||||
}
|
||||
Reference in New Issue
Block a user