Skip to content

Commit a96abb8

Browse files
author
ScrapComputing
committed
Rev 0.9: The user can now delete presets
1 parent 92206e2 commit a96abb8

20 files changed

Lines changed: 402 additions & 137 deletions

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ It is tailored to the needs of vintage PC enthusiasts, so it drives a 4-digit 7-
5252
- The devices starts at the "Presets" state (mode).
5353
- Turn the knob to select a frequency
5454
- Short push to switch to fine-grain frequency selection
55+
- Long push to enter configuration of the current preset:
56+
- Fine-tune actual frequency, short push to switch to PWM period tuning. Long-push escapes.
57+
- Fine-tune PWM period, short push to switch to preset deletion. Long-push escapes.
58+
- Select if preset should be deleted, short push to confirm.
5559

5660
<img src='img/rotary_states.png' height=240 width=auto>
5761

@@ -95,6 +99,12 @@ It is tailored to the needs of vintage PC enthusiasts, so it drives a 4-digit 7-
9599
You can connect to the Throttle Blaster via the serial port and set the Frequency and PWM Period.
96100
This is convenient for launching a game with a `.bat` file that first configures the Throttle Blaster and then launches the game.
97101

102+
## Reset to factory defaults during power on (since rev 0.9)
103+
104+
Press the button (rotary encoder, or any individual button in other modes) and plug in the ThrottleBlaster to power. The led on the Pico will start flashing fast for around 2 seconds and the MHz display will show "RES".
105+
106+
This helps revert the deleted presets or any potential flash-related issue.
107+
98108
### UART Circuit
99109
- Connect the Throttle Blaster's Tx pin to the PC's serial port Rx pin (that is pin 2 of the serial connector), the Throttle Blaster's Rx pin to serial Tx (pin 3) and ground to ground (pin 5)
100110

@@ -277,6 +287,7 @@ So I don't think there is a way to get the Throttle Blaster to work universally
277287

278288

279289
# Change Log
290+
- Rev 0.9: Allows deletion of presets and adds flash reset when button pressed during boot.
280291
- Rev 0.8e: Fixes single/two-button configuration bug (introduced in 0.8b). Adds Pico2 support.
281292
- Rev 0.8d: Fixes reset detection
282293
- Rev 0.8c: Fixes bugs introduced in Rev 0.8b.

firmware/src/CMakeLists.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ cmake_minimum_required(VERSION 3.13)
1111
# -------
1212
# o -DDISPLAY_SHIFT_LEFT=<num> If the numbers displayed need shifting
1313
# o -DDISPLAY_BRIGHTNESS=<num> (0-7) Sets the brightness 7 is max, default: 1.
14-
# o -DDISABLE_PICO_LED=on to disable the Pico's blinking LED.
1514
# o -DDBGPRINT=on to enable debug messages
1615
#
1716
# This will place the firmware into: build/ThrottleBlaster.uf2
@@ -100,7 +99,6 @@ if (DISABLE_USB_DBG STREQUAL "0")
10099
endif ()
101100
message("DISABLE_USB_DBG = ${DISABLE_USB_DBG}")
102101

103-
message("PICO_LED = ${PICO_LED}")
104102
message("PICO_TM1637_PATH = ${PICO_TM1637_PATH}")
105103
message("LCD_SHIFT_LEFT = ${LCD_SHIFT_LEFT}")
106104
message("MHZ = ${MHZ}")

firmware/src/CommonLogic.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ void CommonLogic::setMode(Mode NewMode) {
99
BeforeMaxMHz = Presets.getMaxMHz();
1010
BeforePeriod = Presets.getPeriod();
1111
BeforeActualKHz = Presets.getActualKHz();
12+
BeforeDeleted = Presets.isDeleted();
1213

1314
CurrMode = NewMode;
1415
DBG_PRINT(std::cout << getModeStr(CurrMode) << "\n";)
@@ -17,7 +18,8 @@ void CommonLogic::setMode(Mode NewMode) {
1718
void CommonLogic::tryWritePresetsToFlash() {
1819
if (Presets.getActualKHz() != BeforeActualKHz ||
1920
Presets.getPeriod() != BeforePeriod ||
20-
Presets.getMaxMHz() != BeforeMaxMHz) {
21+
Presets.getMaxMHz() != BeforeMaxMHz ||
22+
Presets.isDeleted() != BeforeDeleted) {
2123
DBG_PRINT(std::cout << "WriteToFlash:\n";)
2224
DBG_PRINT(std::cout << " Before After\n";)
2325
DBG_PRINT(std::cout << "ActualKHz: " << BeforeActualKHz << " "
@@ -26,6 +28,8 @@ void CommonLogic::tryWritePresetsToFlash() {
2628
<< Presets.getPeriod() << "\n";)
2729
DBG_PRINT(std::cout << "MaxMHz: " << BeforeMaxMHz << " "
2830
<< Presets.getMaxMHz() << "\n";)
31+
DBG_PRINT(std::cout << "Deleted: " << BeforeDeleted << " "
32+
<< Presets.isDeleted() << "\n";)
2933
Presets.writeToFlash(Flash);
3034
} else {
3135
DBG_PRINT(
@@ -50,6 +54,9 @@ void CommonLogic::updateDisplay() {
5054
case Mode::ConfigPeriod:
5155
Disp.printRaw(Presets.getPeriod());
5256
break;
57+
case Mode::DeletePreset:
58+
Disp.printTxt(Presets.isDeleted() ? MsgYes : MsgNo);
59+
break;
5360
case Mode::Manual:
5461
case Mode::Uart:
5562
Disp.printKHz(DC.getKHz());

firmware/src/CommonLogic.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class CommonLogic {
3232
Presets,
3333
ConfigMHz,
3434
ConfigPeriod,
35+
DeletePreset,
3536
Manual,
3637
ConfigMaxMHz,
3738
ResetToDefaults,
@@ -46,6 +47,7 @@ class CommonLogic {
4647
case Mode::Presets: return "Presets";
4748
case Mode::ConfigMHz: return "ConfigMHz";
4849
case Mode::ConfigPeriod: return "ConfigPeriod";
50+
case Mode::DeletePreset: return "DeletePreset";
4951
case Mode::Manual: return "Manual";
5052
case Mode::ConfigMaxMHz: return "ConfigMaxMHz";
5153
case Mode::ResetToDefaults: return "ResetToDefaults";
@@ -60,6 +62,7 @@ class CommonLogic {
6062
void tryWritePresetsToFlash();
6163
Mode getMode() const { return CurrMode; }
6264

65+
public:
6366
static constexpr const char *MsgActualFreq = "FrE";
6467
static constexpr const char *MsgPeriod = "PEr";
6568
static constexpr const char *MsgMaxMHz = "CPUF";
@@ -71,10 +74,15 @@ class CommonLogic {
7174
static constexpr const char *MsgUartErr = "UErr";
7275
static constexpr const char *MsgUartMode = "UArt";
7376
static constexpr const char *MsgResetDetected = "boot";
77+
static constexpr const char *MsgDeletePreset = "dEL";
78+
static constexpr const char *MsgYes = "yes";
79+
static constexpr const char *MsgNo = " no";
7480

81+
protected:
7582
int BeforeMaxMHz = 0;
7683
int BeforeActualKHz = 0;
7784
int BeforePeriod = 0;
85+
bool BeforeDeleted = false;
7886

7987
std::vector<Button</*OffVal=*/true, ButtonDebounceSz, ButtonLongPressCnt,
8088
ButtonMedReleaseCnt>>

firmware/src/ConfigOpts.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,10 @@ static constexpr const int PrintSleep = 1000;
9999
// No need to update the PWM period on every UI tick. Skip this many.
100100
static constexpr const int UpdatePWMSamplePeriod = 8;
101101

102+
// Factory defaults press button.
103+
static constexpr const int ResetBtnPressMs = 2000;
104+
static constexpr const int ResetBtnCheckMs = 50;
105+
static constexpr const int ResetDefaultsFlashOnMs = 100;
106+
static constexpr const uint32_t ResetDefaultFlashCnt = 20;
107+
102108
#endif // __CONFIGOPTS_H__

firmware/src/Flash.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class FlashStorage {
1515
// Use the last sector (4KB) of the 2MB flash.
1616
static constexpr const int BaseOffset = 2 * (1u << 20) - FLASH_SECTOR_SIZE;
1717
static constexpr const int BytesToFlash = FLASH_SECTOR_SIZE;
18-
std::vector<int> MagicNumber = {11111111, 42, 0, 666, 11111111};
18+
std::vector<int> MagicNumber = {11191111, 42 + 1, 0, 666, 11111191};
1919

2020
/// Points to the first usable int ptr, after the magic number and revision.
2121
const int *FlashArray = nullptr;
@@ -26,9 +26,7 @@ class FlashStorage {
2626
FlashStorage();
2727
void write(const std::vector<int> &Values);
2828
/// \Reads a value at \p ValueIdx offset (after the magic numbers).
29-
int read(int ValueIdx) const {
30-
return FlashArray[ValueIdx];
31-
}
29+
int read(int ValueIdx) const { return FlashArray[ValueIdx]; }
3230
std::pair<int, int> readRevision() const;
3331
std::vector<int> readMagicNumber() const;
3432
bool valid() const;

firmware/src/PotentiometerLogic.cpp

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,11 @@ void PotentiometerLogic::configPeriod(int PotVal, ButtonState BtnState) {
8585
DBG_PRINT(std::cout << "Period=" << Presets.getPeriod() << "\n";)
8686
return;
8787
case ButtonState::LongPress:
88-
tryWritePresetsToFlash();
8988
Disp.setFlash(false);
90-
printTxtAndSleep(MsgConfirm);
89+
printTxtAndSleep(MsgDeletePreset);
9190
savePotVal(PotVal);
92-
setMode(Mode::Presets);
91+
setMode(Mode::DeletePreset);
92+
Disp.setFlash(true);
9393
return;
9494
default:
9595
break;
@@ -112,6 +112,39 @@ void PotentiometerLogic::configPeriod(int PotVal, ButtonState BtnState) {
112112
}
113113
}
114114

115+
void PotentiometerLogic::configDeletePreset(int PotVal, ButtonState BtnState) {
116+
switch (BtnState) {
117+
case ButtonState::Release:
118+
case ButtonState::MedRelease:
119+
Presets.toggleDeleted();
120+
DBG_PRINT(std::cout << "Deleted=" << Presets.isDeleted() << "\n";)
121+
return;
122+
case ButtonState::LongPress:
123+
tryWritePresetsToFlash();
124+
Disp.setFlash(false);
125+
printTxtAndSleep(MsgConfirm);
126+
savePotVal(PotVal);
127+
setMode(Mode::Presets);
128+
if (Presets.isDeleted())
129+
Presets.prev();
130+
return;
131+
default:
132+
break;
133+
}
134+
135+
// If we moved the potentiometer enough, use it to control the value.
136+
if (EnablePot && movedPotComparedToSaved(PotVal)) {
137+
switch (getPotDir(PotVal)) {
138+
case PotDir::Right:
139+
case PotDir::Left:
140+
Presets.toggleDeleted();
141+
break;
142+
default:
143+
break;
144+
}
145+
}
146+
}
147+
115148
void PotentiometerLogic::configResetToDefaults(int PotVal,
116149
ButtonState BtnState) {
117150
auto DontReset = [this, PotVal]() {
@@ -249,6 +282,9 @@ void PotentiometerLogic::tick() {
249282
case Mode::ConfigPeriod:
250283
configPeriod(PotVal, BtnState);
251284
break;
285+
case Mode::DeletePreset:
286+
configDeletePreset(PotVal, BtnState);
287+
break;
252288
case Mode::ConfigMaxMHz:
253289
configMaxMHz(PotVal, BtnState);
254290
break;

firmware/src/PotentiometerLogic.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class PotentiometerLogic : public CommonLogic {
4343

4444
void configPeriod(int PotVal, ButtonState BtnState);
4545

46+
void configDeletePreset(int PotVal, ButtonState BtnState);
47+
4648
void configResetToDefaults(int PotVal, ButtonState BtnState);
4749

4850
void configMaxMHz(int PotVal, ButtonState BtnState);
@@ -86,9 +88,12 @@ class PotentiometerLogic : public CommonLogic {
8688
: CommonLogic(SamplePeriod, Disp, DC, Presets, Flash, Pi),
8789
Btn(ButtonGPIO, Pi, "Pot.Btn"), Pot(PotGPIO, Pi, ReverseDirection),
8890
Pi(Pi), EnablePot(EnablePot) {
89-
// One of the potentiometer's best features is that it remembers its
90-
// positions across rrestarts. So start in manual mode to make use of it.
91-
setMode(Mode::Manual);
91+
if (EnablePot)
92+
// One of the potentiometer's best features is that it remembers its
93+
// positions across restarts. So start in manual mode to make use of it.
94+
setMode(Mode::Manual);
95+
else
96+
setMode(Mode::Presets);
9297
}
9398
void tick() final;
9499
};

firmware/src/Presets.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,17 @@ void PresetsTable::decrPeriod() {
3232
Val = std::max(PeriodLimitLo, Val - 1);
3333
}
3434

35+
int PresetsTable::minNonDeleted() const {
36+
for (int Idx = 0, E = getMaxIdx(); Idx <= E; ++Idx) {
37+
if (!Table[Idx].Deleted)
38+
return Idx;
39+
}
40+
std::cerr << "minNonDeleted() beyond max!\n";
41+
return 0;
42+
}
43+
3544
void PresetsTable::cyclePrev() {
36-
if (Idx == 0)
45+
if (Idx == minNonDeleted())
3746
Idx = getMaxIdx();
3847
else
3948
prev();

firmware/src/Presets.h

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,44 +17,45 @@ class PresetsTable {
1717
struct Entry {
1818
int PresetKHz;
1919
int ActualKHz;
20-
int Period; ///> PWM Period
20+
int Period; ///> PWM Period.
21+
bool Deleted = false; ///> If the user has deleted this preset.
2122
Entry(int PresetKHz, int ActualKHz, int Period)
2223
: PresetKHz(PresetKHz), ActualKHz(ActualKHz), Period(Period) {}
2324
Entry(FlashStorage &Flash, int &Offset) {
2425
PresetKHz = Flash.read(Offset++);
2526
ActualKHz = Flash.read(Offset++);
2627
Period = Flash.read(Offset++);
28+
Deleted = Flash.read(Offset++);
2729
}
2830
void dump() const {
29-
std::cout << PresetKHz << ", " << ActualKHz << ", " << Period << "\n";
31+
std::cout << PresetKHz << ", " << ActualKHz << ", " << Period << ", "
32+
<< Deleted << "\n";
3033
}
3134
/// Helper for writing to Flash.
3235
void appendToVec(std::vector<int> &Vec) const {
3336
Vec.push_back(PresetKHz);
3437
Vec.push_back(ActualKHz);
3538
Vec.push_back(Period);
39+
Vec.push_back(Deleted);
3640
}
3741
unsigned checksum() const {
38-
return (unsigned)PresetKHz ^ (unsigned)ActualKHz ^ (unsigned)Period;
42+
return (unsigned)PresetKHz ^ (unsigned)ActualKHz ^ (unsigned)Period ^
43+
(unsigned)Deleted;
3944
}
4045
};
4146

4247
static constexpr const int DefaultPeriod = 8; // ~50us
4348

44-
// const std::vector<Entry> ImmutableTable = {
45-
// {4770, 4770, DefaultPeriod}, {8000, 8000, DefaultPeriod},
46-
// {10000, 10000, DefaultPeriod}, {25000, 25000, DefaultPeriod},
47-
// {33000, 33000, DefaultPeriod}, {66000, 66000, DefaultPeriod},
48-
// {100000, 100000, DefaultPeriod}, {133000, 133000, DefaultPeriod},
49-
// {266000, 266000, DefaultPeriod}, {450000, 450000, DefaultPeriod},
50-
// {733000, 733000, DefaultPeriod}, {1000000, 1000000, DefaultPeriod},
51-
// {1666000, 1666000, DefaultPeriod}, {3200000, 3200000, DefaultPeriod}};
5249
const std::vector<Entry> ImmutableTable = {
53-
{4770, 4770, DefaultPeriod}, {8000, 8000, DefaultPeriod},
54-
{10000, 10000, DefaultPeriod}, {25000, 25000, DefaultPeriod},
55-
{33000, 33000, DefaultPeriod}, {66000, 66000, DefaultPeriod},
56-
{133000, 133000, DefaultPeriod}, {450000, 450000, DefaultPeriod},
57-
{733000, 733000, DefaultPeriod}};
50+
Entry(4770, 4770, DefaultPeriod),
51+
Entry(8000, 8000, DefaultPeriod),
52+
Entry(10000, 10000, DefaultPeriod),
53+
Entry(25000, 25000, DefaultPeriod),
54+
Entry(33000, 33000, DefaultPeriod),
55+
Entry(66000, 66000, DefaultPeriod),
56+
Entry(133000, 133000, DefaultPeriod),
57+
Entry(450000, 450000, DefaultPeriod),
58+
Entry(733000, 733000, DefaultPeriod)};
5859

5960
std::vector<Entry> Table;
6061

@@ -77,10 +78,28 @@ class PresetsTable {
7778
void decrActualKHz();
7879
int getPeriod() const { return Table[Idx].Period; }
7980
void incrPeriod();
81+
void toggleDeleted() { Table[Idx].Deleted = !Table[Idx].Deleted; }
82+
bool isDeleted() const { return Table[Idx].Deleted; }
8083
void decrPeriod();
81-
void prev() { Idx = std::max(0, Idx - 1); }
82-
void next() { Idx = std::min(getMaxIdx(), Idx + 1); }
84+
void prev() {
85+
int FoundIdx = Idx;
86+
do {
87+
--FoundIdx;
88+
} while (FoundIdx >= 0 && Table[FoundIdx].Deleted);
89+
if (FoundIdx >= 0) // if legal
90+
Idx = FoundIdx;
91+
}
92+
void next() {
93+
int FoundIdx = Idx;
94+
do {
95+
++FoundIdx;
96+
} while (FoundIdx < getMaxIdx() && Table[FoundIdx].Deleted);
97+
if (FoundIdx <= getMaxIdx()) // if legal
98+
Idx = FoundIdx;
99+
}
83100
void setIdx(int NewIdx) { Idx = std::clamp(NewIdx, 0, getMaxIdx()); }
101+
/// Returns the minimum Idx that is not deleted.
102+
int minNonDeleted() const;
84103
void cyclePrev();
85104
void cycleNext();
86105
void cycleMax();

0 commit comments

Comments
 (0)