Compare commits

...

19 Commits

Author SHA1 Message Date
r4
ea93980795 fix message 2022-11-27 02:07:03 +01:00
r4
dac3a33e9e fix typo 2022-11-27 02:06:43 +01:00
r4
618c75b72b - error message 2022-04-19 19:45:13 +02:00
r4
6f962c0d88 fmt 2022-04-19 19:37:38 +02:00
r4
9ecb2f5579 basic FS commands 2022-04-19 19:30:15 +02:00
r4
5ed8e8f226 add copyright notice 2022-04-19 16:48:43 +02:00
r4
9420eb8293 add reset sketch and reorganize files 2022-04-19 16:44:54 +02:00
r4
4e90b217cb update readme 2022-04-18 23:48:23 +02:00
r4
bbb53a31b3 update readme 2022-04-18 23:47:15 +02:00
r4
1f17f87822 save more power (actually 6μA this time) 2022-04-18 23:15:19 +02:00
r4
25d7967d69 error on incompatible hardware 2022-04-18 23:04:53 +02:00
r4
6599bf151d consistency 2022-04-18 23:02:12 +02:00
r4
b6004c42e0 update readme 2022-04-18 20:42:52 +02:00
r4
7773dc7c1f fix fmt 2022-04-18 19:45:21 +02:00
r4
5728233bad add exit command 2022-04-18 19:33:41 +02:00
r4
580ba5e577 reset wait time after waiting 2022-04-18 19:32:11 +02:00
r4
232df37f5c fix watchdog + library independence 2022-04-18 19:31:51 +02:00
r4
3101c3add6 add commands and improve documentation 2022-04-18 17:47:36 +02:00
r4
fe6734dcba rename U8 amplify option and comment out by default 2022-04-17 10:47:48 +02:00
15 changed files with 457 additions and 121 deletions

View File

@@ -2,7 +2,7 @@
A simple voice recorder for Arduino using an SD card and an electret microphone amplifier circuit.
Independent of any 3rd party libraries (unless delayed recording is used).
Independent of any third-party libraries.
## Wiring (also documented in spybug/spybug.ino)
### SD Card Wiring
@@ -29,3 +29,9 @@ GND | GND
Out | A0
Out defaults to A0 (AdcChannel0), but can be set manually in `ADC_CHANNEL`.
## Power Consumption (Arduino Nano)
Mode | Unmodified | No voltage regulator | No TTL module or voltage regulator
----------|------------|----------------------|-----------------------------------
Waiting | ~10mA | ~5.8mA | ~6μA
Recording | ~30mA | ~25.1mA | ~25mA

View File

@@ -0,0 +1,14 @@
// Copyright 2022 Darwin Schuppan <darwin@nobrain.org>
// SPDX license identifier: MIT
#include "settings.hh"
void setup() {
Serial.begin(9600);
Serial.print("Resetting EEPROM...");
EEPROM_Settings_Class settings;
settings.save();
Serial.println("done.");
}
void loop() {}

1
reset_sketch/settings.hh Symbolic link
View File

@@ -0,0 +1 @@
../spybug/settings.hh

31
spybug/aaa_config.hh Normal file
View File

@@ -0,0 +1,31 @@
// Copyright 2022 Darwin Schuppan <darwin@nobrain.org>
// SPDX license identifier: MIT
#pragma once
/************************
BEGIN USER CONFIGURATION
************************/
//#define DEBUG_RECORDING
#define PIN_COMPONENT_SWITCH 2 /* Use a digital signal to switch on/off the microphone and SD card for less power draw. */
#define COMPONENT_SWITCH_ON HIGH
#define SAMPLE_MODE_U8
//#define SAMPLE_MODE_S16
//#define ADC_PRESCALE_16 /* Up to ~60kHz. */
//#define ADC_PRESCALE_32 /* Up to ~27kHz. */
#define ADC_PRESCALE_64 /* Up to ~18kHz. */
//#define U8_AMPLIFY_X2 /* (U8 sampling mode only) amplify audio by factor 2. */
#define ADC_CHANNEL AdcChannel0
#define TIMER_COMPARE 1000 /* 16MHz / 1000 = 16kHz. */
#define FLUSH_SAMPLES 64000 /* Flush WAV file every n samples. */
#define PIN_SS 10
#define REC_FILE_FMT "REC_%03u.WAV" /* Must be all caps; must use %u in some form exactly once. */
/**********************
END USER CONFIGURATION
**********************/

191
spybug/cmd.cpp Normal file
View File

@@ -0,0 +1,191 @@
// Copyright 2022 Darwin Schuppan <darwin@nobrain.org>
// SPDX license identifier: MIT
#include "cmd.hh"
#include <Arduino.h>
#include <SD.h>
#include "aaa_config.hh"
#include "fstr.hh"
#include "io.hh"
#include "settings.hh"
#include "sys.hh"
static bool sd_initialized = false;
static void try_init_sd() {
if (sd_initialized)
return;
printf(F("Initializing SD card..."));
#ifdef PIN_COMPONENT_SWITCH
digitalWrite(PIN_COMPONENT_SWITCH, COMPONENT_SWITCH_ON);
delay(500); /* Wait for components to initialize. */
#endif
if (SD.begin(PIN_SS)) {
printf(F("Done.\n"));
sd_initialized = true;
} else
printf(F("\nError initializing SD card.\n"));
}
static void sd_error() {
printf(F("Error reading from SD card.\n"));
sd_initialized = false;
}
static void command_loop() {
// Process Commands
if (Serial.available()) {
char args[6][20];
size_t len = 0;
size_t n_args = 0;
int c = getchar();
while (c != '\n' && n_args < 4) {
if (c == ' ')
c = getchar();
else {
do {
args[n_args][len++] = c;
c = getchar();
} while (c != ' ' && c != '\n' && len < 20-1);
args[n_args][len] = 0;
len = 0;
n_args++;
}
}
if (n_args >= 1) {
if (fstreq(args[0], F("set"))) {
if ((n_args == 3 || n_args == 4) && fstreq(args[1], F("wait"))) {
float n = atof(args[2]);
unsigned long mins;
if (n_args == 4 && (fstreq(args[3], F("hours")) || fstreq(args[3], F("hour"))))
mins = 60.f * n;
else
mins = n;
settings.recording_delay = mins;
settings.save();
printf(F("Set waiting time to %lu minutes or "), settings.recording_delay);
print_special((float)settings.recording_delay / 60.f);
printf(F(" hours.\n"));
} else if (n_args == 3 && fstreq(args[1], F("serial"))) {
if (fstreq(args[2], F("on"))) {
settings.serial_log = true;
settings.save();
printf(F("Serial log enabled.\n"));
} else if (fstreq(args[2], F("off"))) {
settings.serial_log = false;
settings.save();
printf(F("Serial log disabled.\n"));
} else {
printf(F("Usage: 'set serial [on|off]'.\n"));
}
} else {
printf(F("Usage: 'set wait <number> [minutes|hours]' or 'set serial [on|off]'.\n"));
}
} else if (fstreq(args[0], F("get"))) {
if (n_args == 2 && fstreq(args[1], F("wait"))) {
printf(F("Current waiting time: %lu minutes or "), settings.recording_delay);
print_special((float)settings.recording_delay / 60.f);
printf(F(" hours.\n"));
} else {
printf(F("Usage: 'get wait'.\n"));
}
} else if (fstreq(args[0], F("sd"))) {
try_init_sd();
if (sd_initialized) {
if (n_args == 2 && fstreq(args[1], F("list"))) {
File root = SD.open("/");
if (root) {
printf(F("Files:\n"));
bool files = false;
size_t cols = 0;
while (1) {
File entry = root.openNextFile();
if (!entry)
break;
files = true;
if (cols >= 3) {
cols = 0;
printf(F("\n"));
}
printf(F(" %s"), entry.name());
cols++;
entry.close();
}
if (!files)
printf(F("[NONE]"));
printf(F("\n"));
} else
sd_error();
root.close();
} else if (n_args == 3 && fstreq(args[1], F("remove"))) {
if (SD.remove(args[2]))
printf(F("Deleted '%s'.\n"), args[2]);
else
printf(F("Error removing '%s'.\n"), args[2]);
} else if (n_args == 2 && fstreq(args[1], F("remove_all"))) {
File root = SD.open("/");
if (root) {
printf(F("Deleted:\n"));
bool deleted = false;
size_t cols = 0;
while (1) {
File entry = root.openNextFile();
if (!entry)
break;
const char *name = entry.name();
unsigned int garbage;
if (!entry.isDirectory() && sscanf(name, REC_FILE_FMT, &garbage) == 1) {
if (cols >= 3) {
cols = 0;
printf(F("\n"));
}
deleted = true;
SD.remove(name);
printf(F(" %s"), name);
cols++;
}
entry.close();
}
if (!deleted)
printf(F("[NONE]"));
printf(F("\n"));
} else
sd_error();
root.close();
} else if (n_args != 1) {
printf(F("Usage: 'sd list', 'sd remove <filename>' or 'sd remove_all'.\n"));
}
}
} else if (fstreq(args[0], F("help"))) {
printf(F("Commands:\n"));
printf(F(" help -- Display this page.\n"));
printf(F(" exit -- Leave command mode.\n"));
printf(F(" get wait -- Display current delay setting.\n"));
printf(F(" set wait <number> [minutes|hours] -- Change current delay setting.\n"));
printf(F(" set serial [on|off] -- Write log to serial output.\n"));
printf(F(" sd -- Initialize the SD card.\n"));
printf(F(" sd list -- List file on SD card.\n"));
printf(F(" sd remove <filename> -- Delete a file from SD card.\n"));
printf(F(" sd remove_all -- Delete all recordings from SD card.\n"));
} else if (fstreq(args[0], F("exit"))) {
printf(F("Bye!\n"));
Serial.flush();
full_reset();
} else
printf(F("Invalid command: '%s'. Type 'help' for a list of commands.\n"), args[0]);
} else {
printf(F("Please specify a command. Type 'help' for a list of commands.\n"));
}
}
}
void cmd() {
printf(F("You are now in command mode. Type 'help' for a list of commands.\n"));
while (Serial.available()) Serial.read();
while (1) {
command_loop();
delay(50);
}
}

6
spybug/cmd.hh Normal file
View File

@@ -0,0 +1,6 @@
// Copyright 2022 Darwin Schuppan <darwin@nobrain.org>
// SPDX license identifier: MIT
#pragma once
void cmd();

37
spybug/fstr.cpp Normal file
View File

@@ -0,0 +1,37 @@
// Copyright 2022 Darwin Schuppan <darwin@nobrain.org>
// SPDX license identifier: MIT
#include "fstr.hh"
size_t fstrlen(const __FlashStringHelper *s) {
PGM_P sp = (PGM_P)s;
size_t len = 0;
while (pgm_read_byte(sp++))
len++;
return len;
}
bool fstreq(const char *a, const __FlashStringHelper *b_fsh) {
PGM_P b = (PGM_P)b_fsh;
while (1) {
if (*a != pgm_read_byte(b))
return false;
if (*a == 0)
return true;
a++; b++;
}
}
int printf(const __FlashStringHelper *fmt, ...) {
size_t len = fstrlen(fmt);
char buf[len + 1];
buf[len] = 0;
memcpy_P(buf, fmt, len + 1);
va_list args;
va_start(args, fmt);
int ret = vprintf(buf, args);
va_end(args);
return ret;
}

12
spybug/fstr.hh Normal file
View File

@@ -0,0 +1,12 @@
// Copyright 2022 Darwin Schuppan <darwin@nobrain.org>
// SPDX license identifier: MIT
#pragma once
#include <Arduino.h>
size_t fstrlen(const __FlashStringHelper *s);
bool fstreq(const char *a, const __FlashStringHelper *b_fsh);
int printf(const __FlashStringHelper *fmt, ...);

22
spybug/io.cpp Normal file
View File

@@ -0,0 +1,22 @@
// Copyright 2022 Darwin Schuppan <darwin@nobrain.org>
// SPDX license identifier: MIT
#include "io.hh"
static int serial_putch(char c, FILE *f) {
(void)f;
return Serial.write(c) == 1 ? 0 : 1;
}
static int serial_getch(FILE *f) {
(void)f;
while(Serial.available() == 0);
return Serial.read();
}
static FILE serial_in_out;
void io_setup() {
fdev_setup_stream(&serial_in_out, serial_putch, serial_getch, _FDEV_SETUP_RW);
stdout = stdin = stderr = &serial_in_out;
}

14
spybug/io.hh Normal file
View File

@@ -0,0 +1,14 @@
// Copyright 2022 Darwin Schuppan <darwin@nobrain.org>
// SPDX license identifier: MIT
#pragma once
#include <Arduino.h>
void io_setup();
#define print_special(x) { Serial.print(x); }
#define die(fmt, ...) { disable_recording_interrupts(); if (settings.serial_log) { printf(F("Fatal: ")); printf(fmt, ##__VA_ARGS__); Serial.flush(); } while(1); }
#define dbg(fmt, ...) { printf(F("Debug: ")); printf(fmt, ##__VA_ARGS__); }
#define info(fmt, ...) { if (settings.serial_log) printf(fmt, ##__VA_ARGS__); }
#define info_special(x) { if (settings.serial_log) Serial.print(x); }

6
spybug/settings.cpp Normal file
View File

@@ -0,0 +1,6 @@
// Copyright 2022 Darwin Schuppan <darwin@nobrain.org>
// SPDX license identifier: MIT
#include "settings.hh"
EEPROM_Settings_Class settings;

17
spybug/settings.hh Normal file
View File

@@ -0,0 +1,17 @@
// Copyright 2022 Darwin Schuppan <darwin@nobrain.org>
// SPDX license identifier: MIT
#pragma once
#include <EEPROM.h>
#define EEADDR_SETTINGS 0x00
struct EEPROM_Settings_Class {
unsigned long recording_delay = 0l;
bool serial_log = true;
inline void load() { EEPROM.get(EEADDR_SETTINGS, *this); }
inline void save() { EEPROM.put(EEADDR_SETTINGS, *this); }
};
extern EEPROM_Settings_Class settings;

View File

@@ -30,110 +30,18 @@
#include <SD.h>
#include <SPI.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/wdt.h>
/************************
BEGIN USER CONFIGURATION
************************/
//#define DEBUG_RECORDING
//#define SERIAL_OUTPUT
#include "aaa_config.hh"
#include "cmd.hh"
#include "fstr.hh"
#include "io.hh"
#include "settings.hh"
#include "sys.hh"
//#define PIN_COMPONENT_SWITCH 2 /* Use a digital signal to switch on/off the microphone and SD card for less power draw. */
//#define COMPONENT_SWITCH_ON HIGH
#define SAMPLE_MODE_U8
//#define SAMPLE_MODE_S16
//#define ADC_PRESCALE_16 /* Up to ~60kHz. */
//#define ADC_PRESCALE_32 /* Up to ~27kHz. */
#define ADC_PRESCALE_64 /* Up to ~18kHz. */
#define U8_EXTRA_PRECISION /* (U8 sampling mode only) use 9th ADC reading bit and chop off 1st bit for more precision (sacrificing half of the bandwidth) */
#define RECORDING_DELAY_IN_MINUTES 0 /* Wait n minutes before starting to record. */
#define ADC_CHANNEL AdcChannel0
#define TIMER_COMPARE 1000 /* 16MHz / 1000 = 16kHz. */
#define FLUSH_SAMPLES 64000 /* Flush WAV file every n samples. */
#define PIN_SS 10
/**********************
END USER CONFIGURATION
**********************/
#ifdef SERIAL_OUTPUT
static int serial_putch(char c, FILE *f) {
(void)f;
return Serial.write(c) == 1 ? 0 : 1;
}
static int serial_getch(FILE *f) {
(void)f;
while(Serial.available() == 0);
return Serial.read();
}
static FILE serial_in_out;
static void setup_serial_in_out() {
fdev_setup_stream(&serial_in_out, serial_putch, serial_getch, _FDEV_SETUP_RW);
stdout = stdin = stderr = &serial_in_out;
}
static size_t fstrlen(const __FlashStringHelper *s) {
PGM_P sp = (PGM_P)s;
size_t len = 0;
while (pgm_read_byte(sp++))
len++;
return len;
}
static int printf(const __FlashStringHelper *fmt, ...) {
size_t len = fstrlen(fmt);
char buf[len + 1];
buf[len] = 0;
memcpy_P(buf, fmt, len + 1);
va_list args;
va_start(args, fmt);
int ret = vprintf(buf, args);
va_end(args);
return ret;
}
#define die(fmt, ...) { disable_recording_interrupts(); printf(F("Fatal: ")); printf(fmt, ##__VA_ARGS__); Serial.flush(); while(1); }
#define dbg(fmt, ...) { printf(F("Debug: ")); printf(fmt, ##__VA_ARGS__); }
#define print_special(x) Serial.print(x)
#else
#define printf(fmt, ...) {}
#define die(fmt, ...) { disable_recording_interrupts(); while(1); }
#define dbg(fmt, ...) {}
#define print_special(x) {}
#if !defined(__AVR_ATmega328P__) || F_CPU != 16000000
#error "This program only works on ATmega328P devices with a clock frequency of 16MHz!"
#endif
#if defined(RECORDING_DELAY_IN_MINUTES) && RECORDING_DELAY_IN_MINUTES != 0
#include <LowPower.h> /* https://github.com/rocketscream/Low-Power */
static void low_power_sleep_minutes(unsigned long t) {
for (unsigned long i = 0; 8ul * i < 60ul * t; i++) {
/* Power down for 8s. */
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
}
#endif
static void start_watchdog_with_full_reset() {
MCUSR &= ~B00001000; /* Clear reset flag. */
WDTCSR |= B00011000; /* Prepare prescaler change. */
WDTCSR = B00100001; /* Set watchdog timeout to 8s. */
// Enable Watchdog Timer
WDTCSR |= B01000000;
MCUSR = MCUSR & B11110111;
}
static inline void disable_recording_interrupts() {
TIMSK1 &= ~(_BV(OCIE1A) | _BV(OCIE1B));
}
enum AdcChannel : uint8_t {
AdcChannel0 = 0,
AdcChannel1 = 1,
@@ -177,9 +85,9 @@ ISR(TIMER1_COMPA_vect) {
sei();
const size_t bufsz = sizeof(SAMPLE_BUF_TYPE) * samples_in_buffer[!which_buffer];
if (file.write((char*)sample_buffer[!which_buffer], bufsz) != bufsz) {
printf(F("Lost "));
print_special((float)samples_hanging / (float)(F_CPU / TIMER_COMPARE)); /* Printf doesn't handle floats. */
printf(F(" seconds of recording.\n"));
info(F("Lost "));
info_special((float)samples_hanging / (float)(F_CPU / TIMER_COMPARE)); /* Printf doesn't handle floats. */
info(F(" seconds of recording.\n"));
die(F("Error writing to SD card. You can ignore this if you removed the SD card intentionally.\n"));
}
samples_hanging += samples_in_buffer[!which_buffer];
@@ -197,7 +105,7 @@ ISR(TIMER1_COMPA_vect) {
ISR(TIMER1_COMPB_vect) {
// Retrieve ADC Value and Write to Buffer
#if defined(SAMPLE_MODE_U8)
#ifdef U8_EXTRA_PRECISION
#ifdef U8_AMPLIFY_X2
uint8_t l = ADCL; /* Read ADC registers. (Order matters!) */
uint8_t h = ADCH;
uint8_t adcval = (h << 7) | (l >> 1);
@@ -270,30 +178,41 @@ static void wav_write_header(uint32_t nsamples) {
void setup() {
// Serial Setup
#ifdef SERIAL_OUTPUT
Serial.begin(9600); /* Set baud rate. */
setup_serial_in_out(); /* Add printf support. */
#endif
io_setup(); /* Add printf support. */
// Component Switch Setup
#ifdef PIN_COMPONENT_SWITCH
pinMode(PIN_COMPONENT_SWITCH, OUTPUT);
#endif
// Delay Triggering
#if defined(RECORDING_DELAY_IN_MINUTES) && RECORDING_DELAY_IN_MINUTES != 0
// Load EEPROM Data
settings.load();
// Handle Commands
info(F("Type anything in the next 4s to enter command mode.\n"));
for (size_t i = 0; i < 4 * 4; i++) {
if (Serial.available())
cmd();
delay(250);
}
// Delayed Triggering
if (settings.recording_delay) {
#ifdef PIN_COMPONENT_SWITCH
digitalWrite(PIN_COMPONENT_SWITCH, !COMPONENT_SWITCH_ON);
#endif
printf(F("Waiting %u minute%s before starting to record...\n"), RECORDING_DELAY_IN_MINUTES, RECORDING_DELAY_IN_MINUTES == 1 ? "" : "s");
Serial.flush();
low_power_sleep_minutes(RECORDING_DELAY_IN_MINUTES); /* Draws ~12.5mA instead of ~30mA when using delay(). */
digitalWrite(PIN_COMPONENT_SWITCH, !COMPONENT_SWITCH_ON);
#endif
info(F("Sleeping for %lu minute%s before starting to record...\n"), settings.recording_delay, settings.recording_delay == 1 ? "" : "s");
Serial.flush();
/* Using this function, an Arduino Nano (with its voltage regulator and TTL module removed) draws ~6μA. */
low_power_sleep_minutes(settings.recording_delay);
/* Reset wait time. */
settings.recording_delay = 0;
settings.save();
}
// Activate Components
#ifdef PIN_COMPONENT_SWITCH
digitalWrite(PIN_COMPONENT_SWITCH, COMPONENT_SWITCH_ON);
delay(500); /* Wait for components to initialize. */
#endif
// Start Watchdog (wdt_enable() doesn't fully reset)
start_watchdog_with_full_reset();
wdt_enable_with_full_reset();
// SD Card Setup
if (!SD.begin(PIN_SS))
die(F("Error initializing SD card!\n"));
@@ -302,11 +221,11 @@ void setup() {
char filename[32];
do {
filenum++;
snprintf(filename, 32, "rec_%03u.wav", filenum);
snprintf(filename, 32, REC_FILE_FMT, filenum);
} while (SD.exists(filename));
// Open File
file = SD.open(filename, O_READ | O_WRITE | O_CREAT); /* Seeking doesn't seem to work with FILE_WRITE?! */
printf(F("Recording to file '%s'.\n"), filename);
info(F("Recording to file '%s'.\n"), filename);
if (!file)
die(F("Error opening '%s' for writing!\n"), filename);
wav_write_header(0);
@@ -323,7 +242,7 @@ void setup() {
#endif
ADCSRB = _BV(ADTS2) | _BV(ADTS0); /* Auto-trigger source select: "Timer/Counter1 Compare Match B". */
ADMUX = _BV(REFS0) /* Use AREF pin (VCC by default) as reference voltage. */
#if defined(SAMPLE_MODE_U8) && !defined(U8_EXTRA_PRECISION)
#if defined(SAMPLE_MODE_U8) && !defined(U8_AMPLIFY_X2)
| _BV(ADLAR) /* Left adjust ADC output so we only need to read ADCH. */
#endif
| (0xF & ADC_CHANNEL); /* Select our ADC input channel. */
@@ -336,8 +255,9 @@ void setup() {
| _BV(OCIE1B); /* Enable "Output Compare B Match Interrupt". */
}
void loop() {
delay(1000);
delay(2000);
wdt_reset(); /* Reset watchdog timer. */
#ifdef DEBUG_RECORDING
dbg(F("n=%lu\tavg=%lu\tmin=%d\tmax=%d\n"), dbg_total, dbg_sum / (dbg_samples ? dbg_samples : 1), dbg_min, dbg_max);
@@ -346,5 +266,5 @@ void loop() {
dbg_min = 32767;
dbg_max = -32768;
#endif
printf(F("samples: written=%lu, hanging=%lu, dropped=%lu\n"), samples_written, samples_hanging, samples_dropped);
info(F("samples: written=%lu, hanging=%lu, dropped=%lu\n"), samples_written, samples_hanging, samples_dropped);
}

37
spybug/sys.cpp Normal file
View File

@@ -0,0 +1,37 @@
// Copyright 2022 Darwin Schuppan <darwin@nobrain.org>
// SPDX license identifier: MIT
#include "sys.hh"
void (*full_reset)() = nullptr;
static volatile bool wdt_in_sleep_mode = false;
ISR (WDT_vect) {
if (wdt_in_sleep_mode)
wdt_disable();
else
full_reset();
}
/* Based on https://github.com/rocketscream/Low-Power. */
void low_power_sleep_minutes(unsigned long t) {
wdt_in_sleep_mode = true;
ADCSRA &= ~_BV(ADEN); /* Disable ADC. */
for (unsigned long i = 0; 8ul * i < 60ul * t; i++) {
// Power Down for 8s
wdt_enable(WDTO_8S); /* Start watchdog timer for 8s. */
WDTCSR |= (1 << WDIE); /* Enable watchdog interrupt. */
do {
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
cli();
sleep_enable();
sleep_bod_disable();
sei();
sleep_cpu();
sleep_disable();
sei();
} while (0);
}
ADCSRA |= _BV(ADEN); /* Re-enable ADC. */
wdt_in_sleep_mode = false;
}

22
spybug/sys.hh Normal file
View File

@@ -0,0 +1,22 @@
// Copyright 2022 Darwin Schuppan <darwin@nobrain.org>
// SPDX license identifier: MIT
#pragma once
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/sleep.h>
extern void (*full_reset)();
void low_power_sleep_minutes(unsigned long t);
static inline void wdt_enable_with_full_reset() {
wdt_enable(WDTO_8S); /* Start watchdog timer for 8s. */
WDTCSR |= (1 << WDIE); /* Enable watchdog interrupt. */
}
static inline void disable_recording_interrupts() {
TIMSK1 &= ~(_BV(OCIE1A) | _BV(OCIE1B));
}