2
* fsm-misc.c: Miscellaneous function for SpaghettiMonster.
4
* Copyright (C) 2017 Selene Scriven
6
* This program is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1
// fsm-misc.c: Miscellaneous function for SpaghettiMonster.
2
// Copyright (C) 2017-2023 Selene ToyKeeper
3
// SPDX-License-Identifier: GPL-3.0-or-later
24
7
#ifdef USE_DYNAMIC_UNDERCLOCKING
25
8
void auto_clock_speed() {
48
31
// "zero" digit gets a single short blink
49
32
uint8_t ontime = BLINK_SPEED * 2 / 12;
50
if (!num) { ontime = 8; num ++; }
33
if (!num) { ontime = BLINK_ONCE_TIME; num ++; }
36
// channel is set per blink, to prevent issues
37
// if another mode interrupts us (like a config menu)
38
uint8_t old_channel = channel_mode;
52
41
for (; num>0; num--) {
42
// TODO: allow setting a blink channel mode per build target
44
set_channel_mode(BLINK_CHANNEL);
53
46
set_level(BLINK_BRIGHTNESS);
48
channel_mode = old_channel;
54
50
nice_delay_ms(ontime);
53
set_channel_mode(BLINK_CHANNEL);
57
channel_mode = old_channel;
56
59
nice_delay_ms(BLINK_SPEED * 3 / 12);
63
set_channel_mode(old_channel);
58
66
return nice_delay_ms(BLINK_SPEED * 8 / 12);
84
92
#ifdef USE_BLINK_NUM
85
93
uint8_t blink_num(uint8_t num) {
86
//StatePtr old_state = current_state;
88
95
uint8_t hundreds = num / 100;
90
97
uint8_t tens = num / 10;
92
#else // 8 bytes smaller
99
#else // can be smaller or larger, depending on whether divmod is used elsewhere
93
100
uint8_t hundreds = 0;
95
102
for(; num >= 100; hundreds ++, num -= 100);
102
109
nice_delay_ms(200);
107
if (! blink_digit(hundreds)) return 0;
108
if (! blink_digit(tens)) return 0;
111
if (! blink_digit(tens)) return 0;
113
if (! blink_digit(num)) return 0;
114
return nice_delay_ms(1000);
115
#else // same size :(
116
if (hundreds) if (! blink_digit(hundreds)) return 0;
117
if (hundreds || tens) if (! blink_digit(tens)) return 0;
118
if (! blink_digit(num)) return 0;
119
return nice_delay_ms(1000);
123
uint8_t volts, tenths;
124
volts = voltage / 10;
125
tenths = voltage % 10;
126
if (! blink(volts)) return;
128
if (! blink(tenths)) return;
112
if (hundreds) blink_digit(hundreds);
113
if (hundreds || tens) blink_digit(tens);
114
return blink_digit(num);
134
118
#ifdef USE_INDICATOR_LED
135
119
void indicator_led(uint8_t lvl) {
121
#ifdef AVRXMEGA3 // ATTINY816, 817, etc
123
case 0: // indicator off
124
AUXLED_PORT.DIRSET = (1 << AUXLED_PIN); // set as output
125
AUXLED_PORT.OUTCLR = (1 << AUXLED_PIN); // set output low
126
#ifdef AUXLED2_PIN // second LED mirrors the first
127
AUXLED2_PORT.DIRSET = (1 << AUXLED2_PIN); // set as output
128
AUXLED2_PORT.OUTCLR = (1 << AUXLED2_PIN); // set output low
131
case 1: // indicator low
132
AUXLED_PORT.DIRCLR = (1 << AUXLED_PIN); // set as input
133
// this resolves to PORTx.PINxCTRL = PORT_PULLUPEN_bm;
134
*((uint8_t *)&AUXLED_PORT + 0x10 + AUXLED_PIN) = PORT_PULLUPEN_bm; // enable internal pull-up
135
#ifdef AUXLED2_PIN // second LED mirrors the first
136
AUXLED2_PORT.DIRCLR = (1 << AUXLED2_PIN); // set as input
137
// this resolves to PORTx.PINxCTRL = PORT_PULLUPEN_bm;
138
*((uint8_t *)&AUXLED2_PORT + 0x10 + AUXLED2_PIN) = PORT_PULLUPEN_bm; // enable internal pull-up
141
default: // indicator high
142
AUXLED_PORT.DIRSET = (1 << AUXLED_PIN); // set as output
143
AUXLED_PORT.OUTSET = (1 << AUXLED_PIN); // set as high
144
#ifdef AUXLED2_PIN // second LED mirrors the first
145
AUXLED2_PORT.DIRSET = (1 << AUXLED2_PIN); // set as output
146
AUXLED2_PORT.OUTSET = (1 << AUXLED2_PIN); // set as high
150
#else // MCU is old tiny style, not newer mega style
137
152
case 0: // indicator off
138
153
DDRB &= 0xff ^ (1 << AUXLED_PIN);
139
154
PORTB &= 0xff ^ (1 << AUXLED_PIN);
174
191
// TODO: Refactor this and RGB LED function to merge code and save space
175
192
void button_led_set(uint8_t lvl) {
195
#ifdef AVRXMEGA3 // ATTINY816, 817, etc
198
BUTTON_LED_PORT.DIRSET = (1 << BUTTON_LED_PIN); // set as output
199
BUTTON_LED_PORT.OUTCLR = (1 << BUTTON_LED_PIN); // set output low
202
BUTTON_LED_PORT.DIRCLR = (1 << BUTTON_LED_PIN); // set as input
203
// this resolves to PORTx.PINxCTRL = PORT_PULLUPEN_bm;
204
*((uint8_t *)&BUTTON_LED_PORT + 0x10 + BUTTON_LED_PIN) = PORT_PULLUPEN_bm; // enable internal pull-up
207
BUTTON_LED_PORT.DIRSET = (1 << BUTTON_LED_PIN); // set as output
208
BUTTON_LED_PORT.OUTSET = (1 << BUTTON_LED_PIN); // set as high
177
213
case 0: // LED off
178
214
BUTTON_LED_DDR &= 0xff ^ (1 << BUTTON_LED_PIN);
179
215
BUTTON_LED_PUE &= 0xff ^ (1 << BUTTON_LED_PIN);
201
239
uint8_t lvl = (value >> (i<<1)) & 0x03;
202
240
uint8_t pin = pins[i];
243
#ifdef AVRXMEGA3 // ATTINY816, 817, etc
246
AUXLED_RGB_PORT.DIRSET = (1 << pin); // set as output
247
AUXLED_RGB_PORT.OUTCLR = (1 << pin); // set output low
250
AUXLED_RGB_PORT.DIRCLR = (1 << pin); // set as input
251
// this resolves to PORTx.PINxCTRL = PORT_PULLUPEN_bm;
252
*((uint8_t *)&AUXLED_RGB_PORT + 0x10 + pin) = PORT_PULLUPEN_bm; // enable internal pull-up
255
AUXLED_RGB_PORT.DIRSET = (1 << pin); // set as output
256
AUXLED_RGB_PORT.OUTSET = (1 << pin); // set as high
204
261
case 0: // LED off
205
262
AUXLED_RGB_DDR &= 0xff ^ (1 << pin);
206
263
AUXLED_RGB_PUE &= 0xff ^ (1 << pin);
241
300
// reset (WDIF + WDE), no WDIE, fastest (16ms) timing (0000)
242
301
// (DS section 8.5.2 and table 8-4)
243
302
WDTCSR = 0b10001000;
303
#elif defined(AVRXMEGA3) // ATTINY816, 817, etc
304
CCP = CCP_IOREG_gc; // temporarily disable change protection
305
WDT.CTRLA = WDT_PERIOD_8CLK_gc; // Enable, timeout 8ms