diff --git a/.gitignore b/.gitignore
index af0c826..4426ddc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
ConfigStatic.h
.vscode/*
+build/out/*
diff --git a/AudioCustomLogger.h b/AudioCustomLogger.h
index 08327fa..13c3401 100644
--- a/AudioCustomLogger.h
+++ b/AudioCustomLogger.h
@@ -18,6 +18,7 @@ class AudioCustomLogger: public DevNullOut
va_list args;
va_start(args, msg);
Log.printFormat(msg, args);
+ return 0; //TOOD?
};
};
diff --git a/AudioGeneratorWAVStatic.cpp b/AudioGeneratorWAVStatic.cpp
new file mode 100644
index 0000000..2887d58
--- /dev/null
+++ b/AudioGeneratorWAVStatic.cpp
@@ -0,0 +1,297 @@
+/*
+ AudioGeneratorWAVStatic
+ Audio output generator that reads 8 and 16-bit WAV files
+
+ Copyright (C) 2017 Earle F. Philhower, III
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+
+#include "AudioGeneratorWAVStatic.h"
+
+
+AudioGeneratorWAVStatic::~AudioGeneratorWAVStatic(){}
+
+bool AudioGeneratorWAVStatic::stop()
+{
+ if (!running) return true;
+ running = false;
+ output->stop();
+ return file->close();
+}
+
+bool AudioGeneratorWAVStatic::isRunning()
+{
+ return running;
+}
+
+
+// Handle buffered reading, reload each time we run out of data
+bool AudioGeneratorWAVStatic::GetBufferedData(int bytes, void *dest)
+{
+ if (!running) return false; // Nothing to do here!
+ uint8_t *p = reinterpret_cast(dest);
+ while (bytes--) {
+ // Potentially load next batch of data...
+ if (buffPtr >= buffLen) {
+ buffPtr = 0;
+ uint32_t toRead = availBytes > BUFFER_SIZE ? BUFFER_SIZE : availBytes;
+ buffLen = file->read( buff, toRead );
+ availBytes -= buffLen;
+ }
+ if (buffPtr >= buffLen)
+ return false; // No data left!
+ *(p++) = buff[buffPtr++];
+ }
+ return true;
+}
+
+bool AudioGeneratorWAVStatic::loop()
+{
+ if (!running) goto done; // Nothing to do here!
+
+ // First, try and push in the stored sample. If we can't, then punt and try later
+ if (!output->ConsumeSample(lastSample)) goto done; // Can't send, but no error detected
+
+ // Try and stuff the buffer one sample at a time
+ do
+ {
+ if (bitsPerSample == 8) {
+ uint8_t l, r;
+ if (!GetBufferedData(1, &l)) stop();
+ if (channels == 2) {
+ if (!GetBufferedData(1, &r)) stop();
+ } else {
+ r = 0;
+ }
+ lastSample[AudioOutput::LEFTCHANNEL] = l;
+ lastSample[AudioOutput::RIGHTCHANNEL] = r;
+ } else if (bitsPerSample == 16) {
+ if (!GetBufferedData(2, &lastSample[AudioOutput::LEFTCHANNEL])) stop();
+ if (channels == 2) {
+ if (!GetBufferedData(2, &lastSample[AudioOutput::RIGHTCHANNEL])) stop();
+ } else {
+ lastSample[AudioOutput::RIGHTCHANNEL] = 0;
+ }
+ }
+ } while (running && output->ConsumeSample(lastSample));
+
+done:
+ file->loop();
+ output->loop();
+
+ return running;
+}
+
+
+bool AudioGeneratorWAVStatic::ReadWAVInfo()
+{
+ uint32_t u32;
+ uint16_t u16;
+ int toSkip;
+
+ // WAV specification document:
+ // https://www.aelius.com/njh/wavemetatools/doc/riffmci.pdf
+
+ // Header == "RIFF"
+ if (!ReadU32(&u32)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: failed to read WAV data\n"));
+ return false;
+ };
+ if (u32 != 0x46464952) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: cannot read WAV, invalid RIFF header, got: %08X \n"), (uint32_t) u32);
+ return false;
+ }
+
+ // Skip ChunkSize
+ if (!ReadU32(&u32)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: failed to read WAV data\n"));
+ return false;
+ };
+
+ // Format == "WAVE"
+ if (!ReadU32(&u32)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: failed to read WAV data\n"));
+ return false;
+ };
+ if (u32 != 0x45564157) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: cannot read WAV, invalid WAVE header, got: %08X \n"), (uint32_t) u32);
+ return false;
+ }
+
+ // there might be JUNK or PAD - ignore it by continuing reading until we get to "fmt "
+ while (1) {
+ if (!ReadU32(&u32)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: failed to read WAV data\n"));
+ return false;
+ };
+ if (u32 == 0x20746d66) break; // 'fmt '
+ };
+
+ // subchunk size
+ if (!ReadU32(&u32)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: failed to read WAV data\n"));
+ return false;
+ };
+ if (u32 == 16) { toSkip = 0; }
+ else if (u32 == 18) { toSkip = 18 - 16; }
+ else if (u32 == 40) { toSkip = 40 - 16; }
+ else {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: cannot read WAV, appears not to be standard PCM \n"));
+ return false;
+ } // we only do standard PCM
+
+ // AudioFormat
+ if (!ReadU16(&u16)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: failed to read WAV data\n"));
+ return false;
+ };
+ if (u16 != 1) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: cannot read WAV, AudioFormat appears not to be standard PCM \n"));
+ return false;
+ } // we only do standard PCM
+
+ // NumChannels
+ if (!ReadU16(&channels)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: failed to read WAV data\n"));
+ return false;
+ };
+ if ((channels<1) || (channels>2)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: cannot read WAV, only mono and stereo are supported \n"));
+ return false;
+ } // Mono or stereo support only
+
+ // SampleRate
+ if (!ReadU32(&sampleRate)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: failed to read WAV data\n"));
+ return false;
+ };
+ if (sampleRate < 1) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: cannot read WAV, unknown sample rate \n"));
+ return false;
+ } // Weird rate, punt. Will need to check w/DAC to see if supported
+
+ // Ignore byterate and blockalign
+ if (!ReadU32(&u32)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: failed to read WAV data\n"));
+ return false;
+ };
+ if (!ReadU16(&u16)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: failed to read WAV data\n"));
+ return false;
+ };
+
+ // Bits per sample
+ if (!ReadU16(&bitsPerSample)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: failed to read WAV data\n"));
+ return false;
+ };
+ if ((bitsPerSample!=8) && (bitsPerSample != 16)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: cannot read WAV, only 8 or 16 bits is supported \n"));
+ return false;
+ } // Only 8 or 16 bits
+
+ // Skip any extra header
+ while (toSkip) {
+ uint8_t ign;
+ if (!ReadU8(&ign)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: failed to read WAV data\n"));
+ return false;
+ };
+ toSkip--;
+ }
+
+ // look for data subchunk
+ do {
+ // id == "data"
+ if (!ReadU32(&u32)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: failed to read WAV data\n"));
+ return false;
+ };
+ if (u32 == 0x61746164) break; // "data"
+ // Skip size, read until end of chunk
+ if (!ReadU32(&u32)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: failed to read WAV data\n"));
+ return false;
+ };
+ if(!file->seek(u32, SEEK_CUR)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: failed to read WAV data, seek failed\n"));
+ return false;
+ }
+ } while (1);
+ if (!file->isOpen()) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: cannot read WAV, file is not open\n"));
+ return false;
+ };
+
+ // Skip size, read until end of file...
+ if (!ReadU32(&u32)) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::ReadWAVInfo: failed to read WAV data\n"));
+ return false;
+ };
+ availBytes = u32;
+
+ buffPtr = 0;
+ buffLen = 0;
+
+ return true;
+}
+
+bool AudioGeneratorWAVStatic::begin(AudioFileSource *source, AudioOutput *output) {
+ running = false;
+ buffPtr = 0;
+ buffLen = 0;
+
+ if (!source) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::begin: failed: invalid source\n"));
+ return false;
+ }
+ file = source;
+ if (!output) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::begin: invalid output\n"));
+ return false;
+ }
+ this->output = output;
+ if (!file->isOpen()) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::begin: file not open\n"));
+ return false;
+ } // Error
+
+ if (!ReadWAVInfo()) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::begin: failed during ReadWAVInfo\n"));
+ return false;
+ }
+
+ if (!output->SetRate( sampleRate )) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::begin: failed to SetRate in output\n"));
+ return false;
+ }
+ if (!output->SetBitsPerSample( bitsPerSample )) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::begin: failed to SetBitsPerSample in output\n"));
+ return false;
+ }
+ if (!output->SetChannels( channels )) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::begin: failed to SetChannels in output\n"));
+ return false;
+ }
+ if (!output->begin()) {
+ audioLogger->printf_P(PSTR("AudioGeneratorWAVStatic::begin: output's begin did not return true\n"));
+ return false;
+ }
+
+ running = true;
+
+ return true;
+}
diff --git a/AudioGeneratorWAVStatic.h b/AudioGeneratorWAVStatic.h
new file mode 100644
index 0000000..04f1d68
--- /dev/null
+++ b/AudioGeneratorWAVStatic.h
@@ -0,0 +1,62 @@
+/*
+ AudioGeneratorWAV
+ Audio output generator that reads 8 and 16-bit WAV files
+
+ Copyright (C) 2017 Earle F. Philhower, III
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef _AUDIOGENERATORWAVSTATIC_H
+#define _AUDIOGENERATORWAVSTATIC_H
+
+#include "AudioGenerator.h"
+
+class AudioGeneratorWAVStatic : public AudioGenerator
+{
+ public:
+ virtual ~AudioGeneratorWAVStatic() override;
+ virtual bool begin(AudioFileSource *source, AudioOutput *output) override;
+ virtual bool loop() override;
+ virtual bool stop() override;
+ virtual bool isRunning() override;
+
+ private:
+ bool ReadU32(uint32_t *dest) { return file->read(reinterpret_cast(dest), 4); }
+ bool ReadU16(uint16_t *dest) { return file->read(reinterpret_cast(dest), 2); }
+ bool ReadU8(uint8_t *dest) { return file->read(reinterpret_cast(dest), 1); }
+ bool GetBufferedData(int bytes, void *dest);
+ bool ReadWAVInfo();
+
+
+ protected:
+ // WAV info
+ uint16_t channels;
+ uint32_t sampleRate;
+ uint16_t bitsPerSample;
+
+ uint32_t availBytes;
+
+ // We need to buffer some data in-RAM to avoid doing 1000s of small reads
+ //uint32_t buffSize;
+ //uint8_t *buff;
+ uint16_t buffPtr;
+ uint16_t buffLen;
+
+ static const uint16_t BUFFER_SIZE = 256;
+ uint8_t buff[BUFFER_SIZE];
+};
+
+#endif
+
diff --git a/AudioOutputCC3200I2S.cpp b/AudioOutputCC3200I2S.cpp
index 3ceaa02..4586e1a 100644
--- a/AudioOutputCC3200I2S.cpp
+++ b/AudioOutputCC3200I2S.cpp
@@ -113,6 +113,7 @@ void AudioOutputCC3200I2S::flush() {
bool AudioOutputCC3200I2S::stop() {
flush();
+ return true;
}
bool AudioOutputCC3200I2S::begin() {
return true;
diff --git a/BoxAccelerometer.cpp b/BoxAccelerometer.cpp
index b4a034f..4c5fea6 100644
--- a/BoxAccelerometer.cpp
+++ b/BoxAccelerometer.cpp
@@ -49,9 +49,53 @@ void BoxAccelerometer::loop() {
Events.handleAccelerometerOrientationEvent(_orientation);
}
- byte tap = _accel.readTap();
+ uint8_t tap = _accel.readTap();
if (tap) {
- Log.verbose("Tap recieved %i", tap);
+ bool AxZ = tap&0b1000000; //event on axis
+ bool AxY = tap&0b0100000;
+ bool AxX = tap&0b0010000;
+ //bool DPE = tap&0b0001000; //double
+ bool PolZ = tap&0b0000100; //0=positive 1=negative
+ bool PolY = tap&0b0000010;
+ bool PolX = tap&0b0000001;
+
+ //X+ = box bottom
+ //X- = box top
+ //Y+ = box back left (big ear)
+ //Y- = box front right (speaker, small ear)
+ //Z+ = box back right (small ear)
+ //Z- = box front left (speaker, big ear)
+
+ //Something wrong, only blinks red or greenyellow
+ TapOn tapOn = TapOn::NONE;
+ if (AxX) {
+ if (PolX) {
+ tapOn = TapOn::BOTTOM;
+ Box.boxLEDs.setActiveAnimationByIteration(BoxLEDs::ANIMATION_TYPE::BLINK, BoxLEDs::CRGB::Red, 2);
+ } else {
+ tapOn = TapOn::TOP;
+ Box.boxLEDs.setActiveAnimationByIteration(BoxLEDs::ANIMATION_TYPE::BLINK, BoxLEDs::CRGB::Orange, 2);
+ }
+ }
+ if (AxY && AxZ) {
+ if (PolY && PolZ) {
+ tapOn = TapOn::BACK;
+ Box.boxLEDs.setActiveAnimationByIteration(BoxLEDs::ANIMATION_TYPE::BLINK, BoxLEDs::CRGB::Blue, 2);
+ } else if (!PolY && !PolZ) {
+ tapOn = TapOn::FRONT;
+ Box.boxLEDs.setActiveAnimationByIteration(BoxLEDs::ANIMATION_TYPE::BLINK, BoxLEDs::CRGB::Violet, 2);
+ } else if (PolY && !PolZ) {
+ tapOn = TapOn::LEFT;
+ Box.boxLEDs.setActiveAnimationByIteration(BoxLEDs::ANIMATION_TYPE::BLINK, BoxLEDs::CRGB::Green, 2);
+ } else if (!PolY && PolZ) {
+ tapOn = TapOn::RIGHT;
+ Box.boxLEDs.setActiveAnimationByIteration(BoxLEDs::ANIMATION_TYPE::BLINK, BoxLEDs::CRGB::GreenYellow, 2);
+ }
+ }
+
+ Log.verbose("Tap recieved %B, direction %X", tap, tapOn);
+
+
}
}
diff --git a/BoxAccelerometer.h b/BoxAccelerometer.h
index a703d17..2ce0d3a 100644
--- a/BoxAccelerometer.h
+++ b/BoxAccelerometer.h
@@ -20,13 +20,14 @@ class BoxAccelerometer : public EnhancedThread {
EARS_UP2 = 0x6,
EARS_DOWN2 = 0x4
};
- enum class TapFrom {
- LEFT,
- RIGHT, //17,34,68 - 34
- FRONT, //16, 17
- BACK,
- TOP, //16,32,64,68,24 - 16
- BOTTOM //17
+ enum class TapOn {
+ NONE = 0x0,
+ LEFT = 0x1,
+ RIGHT = 0x2, //17,34,68 - 34
+ FRONT = 0x3, //16, 17
+ BACK = 0x4,
+ TOP = 0x5, //16,32,64,68,24 - 16
+ BOTTOM = 0x6 //17
};
void
diff --git a/BoxAudioBufferTriple.cpp b/BoxAudioBufferTriple.cpp
index 955ad10..8aa4c5a 100644
--- a/BoxAudioBufferTriple.cpp
+++ b/BoxAudioBufferTriple.cpp
@@ -54,6 +54,8 @@ BoxAudioBufferTriple::BufferStruct* BoxAudioBufferTriple::getBuffer(BoxAudioBuff
return _bufferRead;
case BufferType::WRITE:
return _bufferWrite;
+ case BufferType::WAIT:
+ return NULL;
}
return NULL;
}
diff --git a/BoxAudioBufferTriple.h b/BoxAudioBufferTriple.h
index be5d0f6..dba5a5f 100644
--- a/BoxAudioBufferTriple.h
+++ b/BoxAudioBufferTriple.h
@@ -47,6 +47,8 @@ class BoxAudioBufferTriple {
BufferStruct* _bufferRead;
BufferStruct* _bufferWrite;
+ //static uint16_t _dataBufferSize = _eringbuffer - _ringbuffer; //TODO
+ //uint8_t* _dataBuffer = (uint8_t*)_ringbuffer;
const static uint16_t _dataBufferSize = 0x4000;
uint8_t* _dataBuffer = (uint8_t*)0x20000000; //lower memory up to 0x4000 length;
//uint8_t __attribute__((section(".blsec"))) _dataBuffer[_dataBufferSize];
diff --git a/BoxBattery.cpp b/BoxBattery.cpp
index 9bd5ebc..d9bc126 100644
--- a/BoxBattery.cpp
+++ b/BoxBattery.cpp
@@ -11,6 +11,9 @@ void BoxBattery::begin() {
_batteryAdcRaw = analogRead(60);
_batteryAdcLowRaw = 9999;
+ batteryTestThread.setInterval(10*60*1000);
+ batteryTestThread.enabled = false;
+
loop();
logBatteryStatus();
@@ -41,8 +44,6 @@ void BoxBattery::loop() {
_wasLow = false;
_wasCritical = false;
}
-
- _batteryTestThread.runIfNeeded();
}
bool BoxBattery::isChargerConnected() {
@@ -92,7 +93,7 @@ void BoxBattery::reloadConfig() {
_batteryCriticalAdc = config->battery.criticalAdc;
}
-void BoxBattery::_doBatteryTestStep() {
+void BoxBattery::doBatteryTestStep() {
Log.info("Write battery test data...");
FileFs file;
@@ -128,7 +129,7 @@ void BoxBattery::_doBatteryTestStep() {
void BoxBattery::startBatteryTest() {
Log.info("Start battery test...");
- _batteryTestThread.enabled = true;
+ batteryTestThread.enabled = true;
_batteryTestStartMillis = millis();
FileFs file;
if (file.open(_batteryTestFilename, FA_CREATE_ALWAYS | FA_WRITE)) {
@@ -143,23 +144,24 @@ void BoxBattery::startBatteryTest() {
file.writeString("Comments");
file.writeString("\r\n");
file.writeString("0;;;;;;");
- sprintf(output, "vFactor=%u, vChargerFactor=%u;", _batteryVoltageFactor, _batteryVoltageChargerFactor);
+ sprintf(output, "vFactor=%lu, vChargerFactor=%lu;v2-wav", _batteryVoltageFactor, _batteryVoltageChargerFactor);
file.writeString(output);
file.writeString("\r\n");
file.close();
- _batteryTestThread.run();
+ batteryTestThread.run();
+ Box.boxDAC.initBatteryTest();
} else {
Log.error("Couldn't init battery log %s", _batteryTestFilename);
- _batteryTestThread.enabled = false;
+ batteryTestThread.enabled = false;
}
}
void BoxBattery::stopBatteryTest() {
- if (!_batteryTestThread.enabled)
+ if (!batteryTestThread.enabled)
return;
Log.info("Stop battery test...");
- _batteryTestThread.enabled = false;
- _doBatteryTestStep();
+ batteryTestThread.enabled = false;
+ doBatteryTestStep();
FileFs file;
if (file.open(_batteryTestFilename, FA_OPEN_APPEND | FA_WRITE)) {
char output[13+5+1];
@@ -170,11 +172,11 @@ void BoxBattery::stopBatteryTest() {
file.close();
} else {
Log.error("Couldn't write battery log %s", _batteryTestFilename);
- _batteryTestThread.enabled = false;
+ batteryTestThread.enabled = false;
}
}
bool BoxBattery::batteryTestActive() {
- return _batteryTestThread.enabled;
+ return batteryTestThread.enabled;
}
BoxBattery::BatteryStats BoxBattery::getBatteryStats() {
diff --git a/BoxBattery.h b/BoxBattery.h
index cfa1185..3df357c 100644
--- a/BoxBattery.h
+++ b/BoxBattery.h
@@ -45,8 +45,8 @@ class BoxBattery : public EnhancedThread {
void stopBatteryTest();
bool batteryTestActive();
- EnhancedThread _batteryTestThread;
- void _doBatteryTestStep();
+ EnhancedThread batteryTestThread;
+ void doBatteryTestStep();
BoxBattery::BatteryStats getBatteryStats();
@@ -62,7 +62,7 @@ class BoxBattery : public EnhancedThread {
uint16_t _batteryAdcRaw;
uint16_t _batteryAdcLowRaw;
- char* _batteryTestFilename = "/revvox/batteryTest.csv";
+ const char* _batteryTestFilename = "/revvox/batteryTest.csv";
uint64_t _batteryTestStartMillis;
};
diff --git a/BoxCLI.cpp b/BoxCLI.cpp
index a1eecd3..ed2a7d5 100644
--- a/BoxCLI.cpp
+++ b/BoxCLI.cpp
@@ -128,7 +128,7 @@ void BoxCLI::parse() {
void BoxCLI::execI2C() {
Command c = lastCmd;
- int argNum = c.countArgs();
+ //int argNum = c.countArgs();
unsigned long int tmpNum;
uint8_t addr, regi;
diff --git a/BoxConfig.cpp b/BoxConfig.cpp
index 29f9440..de9423b 100644
--- a/BoxConfig.cpp
+++ b/BoxConfig.cpp
@@ -75,7 +75,9 @@ String BoxConfig::getAsJson() {
JsonObject miscDoc = doc.createNestedObject("misc");
ConfigMisc* miscCfg = &_config.misc;
miscDoc["autodump"] = miscCfg->autodump;
+ miscDoc["swd"] = miscCfg->swd;
+ _json = "";
serializeJson(doc, _json);
return _json;
}
@@ -115,6 +117,7 @@ bool BoxConfig::setFromJson(String json) {
JsonObject miscDoc = doc["misc"];
ConfigMisc* miscCfg = &_config.misc;
miscCfg->autodump = miscDoc["autodump"].as();
+ miscCfg->swd = miscDoc["swd"].as();
// Convert old config version to latest one.
if (_config.version != CONFIG_ACTIVE_VERSION) {
@@ -126,6 +129,9 @@ bool BoxConfig::setFromJson(String json) {
case 3:
miscCfg->autodump = false;
_config.version = 4;
+ case 4:
+ miscCfg->swd = false;
+ _config.version = 5;
write();
break;
default:
@@ -166,4 +172,5 @@ void BoxConfig::_initializeConfig() {
ConfigMisc* misc = &_config.misc;
misc->autodump = false;
+ misc->swd = false;
}
\ No newline at end of file
diff --git a/BoxConfig.h b/BoxConfig.h
index 9d07b16..7c51e16 100644
--- a/BoxConfig.h
+++ b/BoxConfig.h
@@ -6,8 +6,8 @@
#include "BoxSD.h"
-#define BOXCONFIG_JSON_SIZE 515
-//{"version":255,"battery":{"voltageFactor":4294967295,"voltageChargerFactor":4294967295,"lowAdc":65535,"criticalAdc":65535,"sleepMinutes":255},"buttonEars":{"longPressMs":65535,"veryLongPressMs":65535},"wifi":{"ssid":"12345678901234567890123456789012","password":"1234567890123456789012345678901234567890123456789012345678901234"},"log":{"sdLog":false},"misc":{"autodump":false}}
+#define BOXCONFIG_JSON_SIZE 528
+//{"version":255,"battery":{"voltageFactor":4294967295,"voltageChargerFactor":4294967295,"lowAdc":65535,"criticalAdc":65535,"sleepMinutes":255},"buttonEars":{"longPressMs":65535,"veryLongPressMs":65535},"wifi":{"ssid":"12345678901234567890123456789012","password":"1234567890123456789012345678901234567890123456789012345678901234"},"log":{"sdLog":false},"misc":{"autodump":false,"swd":false}}
//Size from https://arduinojson.org/v6/assistant/
class BoxConfig {
diff --git a/BoxDAC.cpp b/BoxDAC.cpp
index 4529592..ba85bd7 100644
--- a/BoxDAC.cpp
+++ b/BoxDAC.cpp
@@ -105,23 +105,18 @@ void BoxDAC::begin() {
MAP_I2SIntEnable(I2S_BASE, I2S_INT_XDATA);
MAP_I2SEnable(I2S_BASE, I2S_MODE_TX_ONLY);
-
- /*
- for (uint32_t i = 0; i<5; i++) {
- beep();
- delay(200);
- beep();
- delay(100);
- }*/
-
- //beepTest();
-
setInterval(0);
- setVolume(current_volume);
+ setVolume(VOL_MIN);
send(ADDR::PAGE_CONTROL, PAGE::SERIAL_IO);
send(ADDR_P0_SERIAL::DAC_VOL_CTRL, 0x00);
+ Log.info("Sources");
+ _srcSD = AudioFileSourceFatFs();
+
+ Log.info("Generators");
+ _genWAV = AudioGeneratorWAVStatic();
+
Log.info("...done");
//samSay("Hackiebox by Team Revvox!");
@@ -146,7 +141,7 @@ void BoxDAC::opusTest() {
Log.info("Mp3 finished");
*/
//AudioGeneratorTonie *opus;
- AudioFileSourceFatFs *file;
+ //AudioFileSourceFatFs *file;
//file = new AudioFileSourceFatFs("/gs-16b-2c-44100hz.opus");
/*file = new AudioFileSourceFatFs("/CONTENT/6977960C/500304E0");
@@ -195,6 +190,7 @@ void BoxDAC::loop(uint16_t timeoutMs) {
if (audioPlaying) {
if (!audioGenerator || !audioSource) {
audioPlaying = false;
+ Box.boxPlayer.songEnded();
return;
}
@@ -206,11 +202,36 @@ void BoxDAC::loop(uint16_t timeoutMs) {
audioGenerator->stop();
timeout.tick();
}
- if (!audioGenerator->isRunning())
+ if (!audioGenerator->isRunning()) {
audioPlaying = false;
+ Box.boxPlayer.songEnded();
+ }
+ Box.boxPower.feedSleepTimerSilent();
} else {
generateZeroAudio(timeoutMs);
}
+ batteryTestLoop();
+}
+
+void BoxDAC::initBatteryTest() {
+ if (!Box.boxPlayer.playDir("/revvox/audio", BoxPlayer::PLAYER_FLAGS::LOOP)) {
+ Log.error("BatteryTest could not play audio, stopping...");
+ Box.boxLEDs.setActiveAnimationByIteration(BoxLEDs::ANIMATION_TYPE::BLINK, BoxLEDs::CRGB::Red, 3);
+ Box.boxBattery.stopBatteryTest();
+ }
+}
+void BoxDAC::batteryTestLoop() {
+ if (Box.boxBattery.batteryTestActive()) {
+ if (current_volume != VOL_TEST)
+ setVolume(VOL_TEST); //reset volume
+
+ if (!audioPlaying) {
+ if (!hasStopped()) {
+ Log.info("BatteryTest continue after pause...");
+ Box.boxPlayer.play(); //continue
+ }
+ }
+ }
}
void BoxDAC::play() {
@@ -254,28 +275,24 @@ bool BoxDAC::playFile(const char* path) {
if (audioGenerator && audioGenerator->isRunning()) {
audioGenerator->stop();
- free(audioGenerator);
}
if (audioSource && audioSource->isOpen()) {
audioSource->close();
- free(audioSource);
}
audioPlaying = false;
return _playWAV(path);
}
bool BoxDAC::_playWAV(const char* path) {
- AudioGeneratorWAV *ag = new AudioGeneratorWAV();
- ag->SetBufferSize(128);
-
- audioGenerator = ag;
- audioSource = new AudioFileSourceFatFs(path);
+ audioGenerator = &_genWAV;
+ audioSource = &_srcSD;
+ audioSource->open(path);
if (!audioGenerator->begin(audioSource, audioOutput)) {
Log.error("Couldn't play wav?!");
return false;
}
- Log.info("WAV file loaded...");
+ Log.info("WAV file loaded with samplerate=%i...", audioOutputI2S->GetRate());
audioPlaying = true;
return true;
}
@@ -432,7 +449,7 @@ void BoxDAC::beepRaw(uint16_t sin, uint16_t cos, uint32_t length) {
beepRaw(sin, cos, length, convertDacVol2BeepVol(current_volume));
}
void BoxDAC::beepRaw(uint16_t sin, uint16_t cos, uint32_t length, uint8_t volume) {
- Log.info("beep sin=%i, cos=%i, len=%l, vol=%X", sin, cos, length, volume);
+ Log.info("beep sr=%i sin=%X, cos=%X, len=%X, vol=%X", audioOutputI2S->GetRate(), sin, cos, length, volume);
logBeepVolume(volume);
send(ADDR::PAGE_CONTROL, PAGE::SERIAL_IO);
@@ -568,19 +585,34 @@ uint8_t BoxDAC::readByte(ADDR_P3_MCLK source_register) {
return readByte((uint8_t)source_register);
}
+uint8_t BoxDAC::getSampleRateIndex() {
+ uint16_t sr = audioOutputI2S->GetRate();
+ if (sr == 48000) {
+ return 4;
+ } else if (sr == 44100) {
+ return 3;
+ } else if (sr == 32000) {
+ return 2;
+ } else if (sr == 22050) {
+ return 1;
+ }
+ return 0; //16000
+}
+
bool BoxDAC::increaseVolume() {
bool result = false;
+ uint16_t (*pBeep)[2] = ofwButtonFreqTable[getSampleRateIndex()];
+
if (current_volume < VOL_MAX) {
- current_volume += VOL_STEP;
- setVolume(current_volume);
- beepRaw(0x278A, 0x79BD, 0x000140); //16kHz
- //beepMidi(78,50,true);
- result = true;
+ setVolume(current_volume+VOL_STEP);
+ beepRaw(pBeep[0][0], pBeep[0][1], 0x000140); //beepRaw(0x278A, 0x79BD, 0x000140); //16kHz - 799,69hz/799,80hz/16
+ //beepMidi(79,50,true);
+ result = true;
} else {
- beepRaw(0x30F9, 0x763F, 0x000140); //16kHz
+ beepRaw(pBeep[1][0], pBeep[1][1], 0x000140); //beepRaw(0x30F9, 0x763F, 0x000140); //16kHz - 999,77hz/1000,54hz/20
Box.delayTask(50);
- beepRaw(0x30F9, 0x763F, 0x000140); //16kHz
- //beepMidi(84,50,true);
+ beepRaw(pBeep[1][0], pBeep[1][1], 0x000140);
+ //beepMidi(83,50,true);
Log.info("Max volume reached");
}
logVolume();
@@ -588,16 +620,18 @@ bool BoxDAC::increaseVolume() {
}
bool BoxDAC::decreaseVolume() {
bool result = false;
+ uint16_t (*pBeep)[2] = ofwButtonFreqTable[getSampleRateIndex()];
+
if (current_volume > VOL_MIN) {
- current_volume -= VOL_STEP;
- setVolume(current_volume);
- beepRaw(0x18F5, 0x7D87, 0x000140); //16kHz
- //beepMidi(70, 50, true);
+ setVolume(current_volume-VOL_STEP);
+ beepRaw(pBeep[2][0], pBeep[2][1], 0x000140); //beepRaw(0x18F5, 0x7D87, 0x000140); //16kHz - 499,71hz/501,34hz/10
+ //beepMidi(71, 50, true);
result = true;
} else {
- beepRaw(0x0F0A, 0x7F1A, 0x000140); //16kHz
+ beepRaw(pBeep[3][0], pBeep[3][1], 0x000140); //beepRaw(0x0F0A, 0x7F1A, 0x000140); //16kHz - 299,89hz/301,57hz/6
+
Box.delayTask(50);
- beepRaw(0x0F0A, 0x7F1A, 0x000140); //16kHz
+ beepRaw(pBeep[3][0], pBeep[3][1], 0x000140);
//beepMidi(62, 50, true);
Log.info("Min volume reached");
}
@@ -611,6 +645,7 @@ void BoxDAC::setVolume(uint8_t volume) {
send(ADDR_P0_SERIAL::DAC_VOL_L_CTRL, volumeConv);
send(ADDR_P0_SERIAL::DAC_VOL_R_CTRL, volumeConv);
while ((readByte(ADDR_P0_SERIAL::DAC_FLAG_REG) & 0b00010001) != 0b00010001) { Box.delayTask(1); }
+ current_volume = volume;
}
void BoxDAC::logVolume() {
diff --git a/BoxDAC.h b/BoxDAC.h
index 7ab3867..886a0bf 100755
--- a/BoxDAC.h
+++ b/BoxDAC.h
@@ -14,7 +14,7 @@
#include "AudioFileSourceFatFs.h"
#include "AudioGeneratorTonie.h"
#include
-#include
+#include "AudioGeneratorWAVStatic.h"
//#include "libopus/opus.h"
@@ -40,6 +40,10 @@ class BoxDAC : public EnhancedThread {
void samSay(const char *text, enum ESP8266SAM::SAMVoice voice = ESP8266SAM::SAMVoice::VOICE_SAM, uint8_t speed = 0, uint8_t pitch = 0, uint8_t throat = 0, uint8_t mouth = 0, bool sing = false, bool phoentic = false);
void dmaPingPingComplete();
+
+ void initBatteryTest();
+ void batteryTestLoop();
+
BoxAudioBufferTriple audioBuffer;
unsigned long dmaIRQcount = 0;
unsigned long lastDmaIRQcount = 0xFFFF;
@@ -76,10 +80,11 @@ class BoxDAC : public EnhancedThread {
bool playFile(const char* path);
bool _playWAV(const char* path);
- const static uint8_t VOL_MIN = 0xB0+0x7F; //0xB0=-40.0dB /min allowed value 0x81=-63.5dB
- const static uint8_t VOL_MAX = 0x0A+0x7F; //0x0A=+04.0dB /max allowed value 0x30=+24.0dB
+ const static uint8_t VOL_MIN = 0x2F; //0xB0+0x7F; //0xB0=-40.0dB /min allowed value 0x81=-63.5dB
+ const static uint8_t VOL_MAX = 0x89; //0x0A+0x7F; //0x0A=+04.0dB /max allowed value 0x30=+24.0dB
const static uint8_t VOL_STEP = 0x06; //3dB
- uint8_t current_volume = VOL_MIN;
+ const static uint8_t VOL_TEST = VOL_MIN + 6*VOL_STEP;
+ uint8_t current_volume;
//const static uint8_t VOL_BEEP_MIN = 0x2A; //0x2A=-40dB /min allowed value 0x3F=-61dB
//const static uint8_t VOL_BEEP_MAX = 0x00; //0x00=+02dB /max allowed value 0x00=+02dB
@@ -100,9 +105,6 @@ class BoxDAC : public EnhancedThread {
//0x02
//0x00
-
-
-
bool increaseVolume();
bool decreaseVolume();
@@ -118,6 +120,10 @@ class BoxDAC : public EnhancedThread {
bool hasStopped();
private:
+ uint8_t _batteryTestFileId;
+ AudioGeneratorWAVStatic _genWAV;
+ AudioFileSourceFatFs _srcSD;
+
enum class PAGE {
SERIAL_IO = 0x00,
DAC_OUT_VOL = 0x01,
@@ -197,6 +203,36 @@ class BoxDAC : public EnhancedThread {
void initDACI2C();
+ uint8_t getSampleRateIndex();
+ uint16_t ofwButtonFreqTable[5][4][2] = {
+ { //16000
+ {0x278A, 0x79BD}, //+
+ {0x30F9, 0x763F}, //++
+ {0x18F5, 0x7D87}, //-
+ {0x0F0A, 0x7F1A} //--
+ }, {//22050
+ {0x1CEA, 0x7CB1}, //+
+ {0x23F9, 0x7AD5}, //++
+ {0x122A, 0x7EB2}, //-
+ {0x0AED, 0x7F87} //--
+ }, {//32000
+ {0x1404, 0x7E6D}, //+
+ {0x18F7, 0x7D8A}, //++
+ {0x0C8A, 0x7F61}, //-
+ {0x0788, 0x7FC7} //--
+ }, {//44100
+ {0x0E8D, 0x7F2B}, //+
+ {0x122C, 0x7EB4}, //++
+ {0x091B, 0x7FAC}, //-
+ {0x0578, 0x7FE2} //--
+ }, {//48000
+ {0x0D60, 0x7F4D}, //+
+ {0x10B4, 0x7EE7}, //++
+ {0x085E, 0x7FB9}, //-
+ {0x0506, 0x7FE6} //--
+ }
+ };
+
uint32_t frequencyTable[128] = {
818,
866,
diff --git a/BoxEvents.cpp b/BoxEvents.cpp
index 4783717..425b719 100644
--- a/BoxEvents.cpp
+++ b/BoxEvents.cpp
@@ -8,9 +8,9 @@ void BoxEvents::loop() {
}
void BoxEvents::handleEarEvent(BoxButtonEars::EarButton earId, BoxButtonEars::PressedType pressType, BoxButtonEars::PressedTime pressLength) {
- char* nameEar;
- char* nameType;
- char* nameLength;
+ const char* nameEar;
+ const char* nameType;
+ const char* nameLength;
switch (earId) {
case BoxButtonEars::EarButton::SMALL:
@@ -203,7 +203,7 @@ void BoxEvents::handlePowerEvent(BoxPower::PowerEvent event) {
}
void BoxEvents::handleAccelerometerOrientationEvent(BoxAccelerometer::Orientation orient) {
- char* orientText;
+ const char* orientText;
switch (orient) {
case BoxAccelerometer::Orientation::EARS_UP:
orientText = "ears up";
@@ -247,12 +247,12 @@ void BoxEvents::handleTagEvent(BoxRFID::TAG_EVENT event) {
if (!Box.boxDAC.hasStopped() && (memcmp(Box.boxRFID.tagUid, Box.boxTonie.currentUid, 8) == 0)) {
Log.info("Continue playing last file");
- Box.boxDAC.play();
+ Box.boxPlayer.play();
} else {
DirFs dir;
if(Config.get()->misc.autodump) {
Log.info("Autodump...");
- char* rdump = "/rDUMP";
+ const char* rdump = "/rDUMP";
if (!dir.openDir(rdump)) {
Log.info("Create dir %s...", rdump);
if (!FatFs.mkdir(rdump)) {
@@ -269,7 +269,7 @@ void BoxEvents::handleTagEvent(BoxRFID::TAG_EVENT event) {
Log.info("No Autodump");
}
- char* rcontent = "/rCONTENT";
+ const char* rcontent = "/rCONTENT";
if (!dir.openDir(rcontent)) {
Log.info("Create dir %s...", rcontent);
if (!FatFs.mkdir(rcontent)) {
@@ -292,25 +292,7 @@ void BoxEvents::handleTagEvent(BoxRFID::TAG_EVENT event) {
Log.info("...fail!");
}
} else {
- bool foundFile = false;
- while (dir.nextFile()) {
- if (!dir.isDir()) {
- foundFile = true;
- break;
- }
- }
- if (!foundFile) {
- Log.info("No file play.");
- } else {
- uint8_t filepath[256];
- sprintf(
- (char*)filepath,
- "%s/%s",
- path,
- dir.fileName()
- );
- Box.boxDAC.playFile((const char*)filepath);
- }
+ Box.boxPlayer.playDir((const char*)path, BoxPlayer::PLAYER_FLAGS::NONE);
}
}
break;
diff --git a/BoxI2C.cpp b/BoxI2C.cpp
index aa992e9..0109c58 100644
--- a/BoxI2C.cpp
+++ b/BoxI2C.cpp
@@ -19,6 +19,7 @@ bool BoxI2C::send(uint8_t address, uint8_t target_register, uint8_t data) {
uint8_t result = Wire.endTransmission(false);
if (!result) return true;
Log.error("Couldn't send I2C buffer, error=%i", result);
+ return false;
}
uint8_t BoxI2C::readByte(uint8_t address, uint8_t source_register) {
diff --git a/BoxLEDs.cpp b/BoxLEDs.cpp
index 2f5f847..925f434 100644
--- a/BoxLEDs.cpp
+++ b/BoxLEDs.cpp
@@ -2,9 +2,10 @@
#include "wiring_private.h"
#include "Hackiebox.h"
-void BoxLEDs::begin() {
- PWMPrepare(PIN_RED);
- //disableRedLED(true);
+void BoxLEDs::begin(bool swd) {
+ disableRedLED(swd); //PWMPrepare(PIN_RED);
+ if (swd)
+ Log.info("Keep red LED inactive to enable SWD");
PWMPrepare(PIN_GREEN);
PWMPrepare(PIN_BLUE);
@@ -70,13 +71,16 @@ void BoxLEDs::_handleAnimation(ANIMATION* animation) {
}
void BoxLEDs::disableRedLED(bool disabled) {
- _redLedDisabled = disabled;
+ if (_redLedDisabled == disabled)
+ return;
+
if (disabled) {
MAP_PinModeSet(PIN_19, PIN_MODE_1); //TCK
MAP_PinModeSet(PIN_20, PIN_MODE_1); //TMS
} else {
PWMPrepare(PIN_RED);
}
+ _redLedDisabled = disabled;
}
unsigned long BoxLEDs::getDurationByIterations(uint8_t iterations, ANIMATION_TYPE animationType) {
@@ -278,7 +282,7 @@ void BoxLEDs::setAllBool(bool red, bool green, bool blue) {
setBlueBool(blue);
}
-void BoxLEDs::setAll(uint8_t intensity) {
+void BoxLEDs::setWhite(uint8_t intensity) {
setAll(intensity, intensity, intensity);
}
@@ -292,6 +296,12 @@ void BoxLEDs::setAll(CRGB crgb) {
setAll(crgb.red, crgb.green, crgb.blue);
}
+void BoxLEDs::setAll(uint32_t color) {
+ CRGB crgb;
+ crgb.setRGB(color);
+ setAll(crgb);
+}
+
void BoxLEDs::testLEDs() {
uint8_t ledR = getRed();
uint8_t ledG = getGreen();
diff --git a/BoxLEDs.h b/BoxLEDs.h
index d75e14a..d8e8516 100644
--- a/BoxLEDs.h
+++ b/BoxLEDs.h
@@ -25,6 +25,11 @@ class BoxLEDs : public EnhancedThread {
red = r;
green = g;
blue = b;
+ }
+ void setRGB(uint32_t colorcode) {
+ red = (colorcode >> 16) & 0xFF;
+ green = (colorcode >> 8) & 0xFF;
+ blue = (colorcode >> 0) & 0xFF;
}
inline CRGB& operator= (const uint32_t colorcode) __attribute__((always_inline)) {
red = (colorcode >> 16) & 0xFF;
@@ -193,7 +198,7 @@ class BoxLEDs : public EnhancedThread {
};
void
- begin(),
+ begin(bool swd),
loop();
void testLEDs();
@@ -209,9 +214,10 @@ class BoxLEDs : public EnhancedThread {
setRed(uint8_t intensity),
setGreen(uint8_t intensity),
setBlue(uint8_t intensity),
- setAll(uint8_t intensity),
+ setWhite(uint8_t intensity),
setAll(uint8_t red, uint8_t green, uint8_t blue),
- setAll(CRGB crgb);
+ setAll(CRGB crgb),
+ setAll(uint32_t color);
uint8_t
getRed(),
@@ -251,7 +257,7 @@ class BoxLEDs : public EnhancedThread {
CRGB _wheel(uint8_t wheelPos);
void _handleAnimation(ANIMATION* animation);
- bool _redLedDisabled;
+ bool _redLedDisabled = true;
};
#endif
diff --git a/BoxPlayer.cpp b/BoxPlayer.cpp
new file mode 100644
index 0000000..3cddfdc
--- /dev/null
+++ b/BoxPlayer.cpp
@@ -0,0 +1,126 @@
+#include "BoxPlayer.h"
+#include "Hackiebox.h"
+
+void BoxPlayer::begin() {
+ Log.info("Init Player...");
+ _mode = PLAYER_MODE::NONE;
+ _flags = PLAYER_FLAGS::NONE;
+ _dirPath[0] = 0x00;
+ Log.info("...done");
+}
+
+void BoxPlayer::loop() {
+
+}
+
+void BoxPlayer::play() {
+ Log.info("Player play");
+ Box.boxDAC.play();
+ Box.boxPower.feedSleepTimer();
+}
+void BoxPlayer::pause() {
+ Log.info("Player pause");
+ Box.boxDAC.pause();
+ Box.boxPower.feedSleepTimer();
+}
+void BoxPlayer::stop() {
+ Log.info("Player stop");
+ Box.boxDAC.stop();
+ Box.boxPower.feedSleepTimer();
+}
+void BoxPlayer::rewind() {
+ //TODO
+}
+
+void BoxPlayer::songEnded() {
+ Log.info("Song ended with mode=%X and flags=%X...", _mode, _flags);
+ if (_mode == PLAYER_MODE::FILE) {
+ if (_flags == PLAYER_FLAGS::LOOP) {
+ rewind();
+ } else {
+ stop();
+ }
+ } else if (_mode == PLAYER_MODE::DIR) {
+ _currentSongId++;
+ if (_currentSongId >= _dirSongCount) {
+ if (_flags == PLAYER_FLAGS::LOOP) {
+ _currentSongId = 0;
+ } else {
+ Log.info("Played all %i songs from dir %s", _dirSongCount, _dirPath);
+ stop();
+ return;
+ }
+ }
+
+ DirFs dir;
+ if (dir.openDir(_dirPath)) {
+ char songPath[256];
+ uint8_t songIndex = 0;
+ while (dir.nextFile()) {
+ if (dir.isDir())
+ continue;
+ if (_currentSongId == songIndex) {
+ Log.info("Playing next song in dir %s with id %i...", _dirPath, _currentSongId);
+ sprintf(songPath,"%s/%s", _dirPath, (const char*)dir.fileName());
+ }
+ songIndex++;
+ }
+ dir.closeDir();
+ if (songIndex > 0)
+ _play(songPath);
+ } else {
+ Log.error("Player could not open dir %s...", _dirPath);
+ }
+ }
+}
+
+bool BoxPlayer::_play(const char* path) {
+ Box.boxPower.feedSleepTimer();
+ return Box.boxDAC.playFile(path);
+}
+
+bool BoxPlayer::playDir(const char* path, PLAYER_FLAGS flags) {
+ Log.info("Playing dir %s", _dirPath);
+
+ char songPath[256];
+
+ _mode = BoxPlayer::PLAYER_MODE::DIR;
+ _flags = flags;
+ _currentSongId = 0;
+ _dirSongCount = 0;
+ memcpy((char*)_dirPath, (const char*)path, 256);
+
+ DirFs dir;
+ if (dir.openDir(_dirPath)) {
+ while (dir.nextFile()) {
+ if (dir.isDir())
+ continue;
+ if (_dirSongCount == 0) {
+ sprintf(songPath,"%s/%s",_dirPath, (const char*)dir.fileName());
+ }
+ _dirSongCount++;
+ }
+ dir.closeDir();
+ if (_dirSongCount > 0) {
+ return _play(songPath);
+ } else {
+ Log.error("Player could not find songs to play...");
+ }
+ } else {
+ Log.error("Player could not open dir %s...", _dirPath);
+ }
+ return false;
+}
+bool BoxPlayer::playFile(const char* file, PLAYER_FLAGS flags) {
+ _mode = PLAYER_MODE::FILE;
+ _flags = flags;
+ Log.info("Playing file %s", file);
+ return _play(file);
+}
+
+bool BoxPlayer::isPlaying() {
+ return (Box.boxDAC.audioPlaying);
+}
+bool BoxPlayer::isStopped() {
+ return (Box.boxDAC.hasStopped());
+}
\ No newline at end of file
diff --git a/BoxPlayer.h b/BoxPlayer.h
new file mode 100644
index 0000000..b706bea
--- /dev/null
+++ b/BoxPlayer.h
@@ -0,0 +1,53 @@
+#ifndef BoxPlayer_h
+#define BoxPlayer_h
+
+#include "BaseHeader.h"
+
+class BoxPlayer {
+ public:
+ enum class PLAYER_EVENT {
+ };
+ enum class PLAYER_MODE {
+ NONE = 0x0,
+ FILE = 0x1,
+ DIR = 0x2
+ };
+
+ enum class PLAYER_FLAGS {
+ NONE = 0x0,
+ LOOP = 0x1,
+ RANDOM = 0x2
+ };
+ void
+ begin(),
+ loop();
+
+ void
+ play(),
+ pause(),
+ stop(),
+ next(),
+ previous(),
+ rewind(),
+ songEnded();
+
+ bool
+ playDir(const char* path, PLAYER_FLAGS flags),
+ playFile(const char* file, PLAYER_FLAGS flags);
+
+ bool
+ isPlaying(),
+ isStopped();
+
+ private:
+ PLAYER_MODE _mode;
+ PLAYER_FLAGS _flags;
+ char _dirPath[256];
+ uint8_t _currentSongId;
+ uint8_t _dirSongCount;
+
+ bool _play(const char* path);
+
+};
+
+#endif
\ No newline at end of file
diff --git a/BoxPower.cpp b/BoxPower.cpp
index 8f7972e..71f5bf1 100644
--- a/BoxPower.cpp
+++ b/BoxPower.cpp
@@ -13,7 +13,7 @@ void BoxPower::begin() {
_lastFeed = millis();
setInterval(5000);
- Log.info("Init BoxPower class, sleepMinutes=%i", _sleepMinutes);
+ Log.info("Init BoxPower, sleepMinutes=%i", _sleepMinutes);
}
void BoxPower::loop() {
@@ -26,9 +26,21 @@ void BoxPower::loop() {
}
void BoxPower::feedSleepTimer() {
+ feedSleepTimerSilent();
+ Log.verbose("Sleep timer rst, _lastFeed=%l, Mem: free(str/ptr/cny/end) Stack: %ib(%X/%X/%X/%X), Heap: %ib(%X/%X/%X/%X)",
+ _lastFeed,
+ freeStackMemory(), (uint32_t)stackStart()-0x20004000, (uint32_t)stackPointer()-0x20004000, (uint32_t)getFirstStackCanary()-0x20004000, (uint32_t)stackEnd()-0x20004000,
+ freeHeapMemory(), (uint32_t)heapStart()-0x20004000, (uint32_t)heapPointer()-0x20004000, (uint32_t)getFirstHeapCanary()-0x20004000, (uint32_t)heapEnd()-0x20004000
+ );
+ uint32_t stackCanaries = countStackCanaries();
+ uint32_t heapCanaries = countHeapCanaries();
+ if (stackCanaries < 10 || heapCanaries < 10) {
+ Log.error("!!! Canaries low !!! Stack=%l, Heap=%l", stackCanaries, heapCanaries);
+ }
+}
+void BoxPower::feedSleepTimerSilent() {
_lastFeed = millis();
Box.watchdog_feed();
- Log.verbose("Sleep timer reset, _lastFeed=%l, freeStackMEM=%ib, freeHeapMEM=%ib, *Stack=%X, *Heap=%X", _lastFeed, freeStackMemory(), freeHeapMemory(), stackPointer()-0x20004000, heapPointer()-0x20004000);
}
void BoxPower::_preparePowerDown() {
diff --git a/BoxPower.h b/BoxPower.h
index f8c0f35..8da2f85 100644
--- a/BoxPower.h
+++ b/BoxPower.h
@@ -19,6 +19,7 @@ class BoxPower : public EnhancedThread {
void
feedSleepTimer(),
+ feedSleepTimerSilent(),
reset(),
hibernate();
diff --git a/BoxRFID.cpp b/BoxRFID.cpp
index e4976f6..30ef725 100644
--- a/BoxRFID.cpp
+++ b/BoxRFID.cpp
@@ -25,29 +25,30 @@ void BoxRFID::loop() {
resetRFID();
initRFID();
- writeRegister(REGISTER::CHIP_STATUS_CONTROL, 0b00100001); //turnRfOn();
- // The VCD should wait at least 1 ms after it activated the
- // powering field before sending the first request, to
- // ensure that the VICCs are ready to receive it. (ISO15693-3)
- Box.delayTask(20); //not 1 ms?!
+ turnFieldOn();
ISO15693_RESULT result;
uint32_t knownPasswords[3] = { 0x7FFD6E5B, 0x0F0F0F0F, 0x00000000 };
if (tagActive) {
- result = ISO15693_getRandomSlixL(NULL);
- if (result != ISO15693_RESULT::GET_RANDOM_VALID) {
- tagActive = false;
- Events.handleTagEvent(TAG_EVENT::TAG_REMOVED);
- }
+ for (uint8_t i=0; i<3; i++) {
+ result = ISO15693_getRandomSlixL(NULL);
+ if (result == ISO15693_RESULT::GET_RANDOM_VALID)
+ break;
+ }
+
+ if (result != ISO15693_RESULT::GET_RANDOM_VALID) {
+ tagActive = false;
+ Events.handleTagEvent(TAG_EVENT::TAG_REMOVED);
+ }
} else {
for (uint8_t i = 0; i < 3; i++) {
result = ISO15693_setPassSlixL(0x04, knownPasswords[i]); //reversed!
if (result == ISO15693_RESULT::SET_PASSWORD_CORRECT) {
- Log.info("Password %X (i=%i) was ok", knownPasswords[i], i);
+ Log.info("Password %X (i=%i) ok", knownPasswords[i], i);
break;
} else if (result == ISO15693_RESULT::SET_PASSWORD_INCORRECT) {
- Log.info("Password %X (i=%i) was wrong", knownPasswords[i], i);
- writeRegister(REGISTER::CHIP_STATUS_CONTROL, 0b00000001); //turnRfOff();
+ Log.info("Password %X (i=%i) wrong", knownPasswords[i], i);
+ turnFieldOff();
Box.delayTask(20);
reinitRFID();
} else {
@@ -71,7 +72,7 @@ void BoxRFID::loop() {
}
}
- writeRegister(REGISTER::CHIP_STATUS_CONTROL, 0b00000001); //turnRfOff();
+ turnFieldOff();
}
void BoxRFID::receivedInterrupt() {
@@ -124,8 +125,8 @@ void BoxRFID::processInterrupt(IRQ_STATUS irqStatus) {
trfOffset += trfRxLength;
} else {
- trfStatus == TRF_STATUS::PROTOCOL_ERROR;
- Log.error("Read buffer to small, size=%i, count=%", FIFO_SIZE, (trfOffset+trfRxLength));
+ trfStatus = TRF_STATUS::PROTOCOL_ERROR;
+ Log.error("Read buffer too small, size=%i, count=%", FIFO_SIZE, (trfOffset+trfRxLength));
return;
}
trfStatus = TRF_STATUS::RX_WAIT_EXTENSION;
@@ -210,9 +211,10 @@ uint8_t BoxRFID::readRegister(uint8_t regi) {
uint8_t data = regi & 0b00011111;
data |= (uint8_t)REG_CMD_WORD_BITS::REGISTER_B7 | (uint8_t)REG_CMD_WORD_BITS::READ_B6;
- uint8_t res1, res2;
+ //uint8_t res1;
+ uint8_t res2;
spiEnable();
- res1 = SPI.transfer(data);
+ SPI.transfer(data);
SPI.setDataMode(SPI_SUB_MODE_1);
res2 = SPI.transfer(0x00); //0xFF or 0x00? (Ghost bytes)
SPI.setDataMode(SPI_SUB_MODE_0);
@@ -252,10 +254,10 @@ void BoxRFID::writeRegister(uint8_t regi, uint8_t value) {
uint8_t data = regi & 0b00011111;
data |= (uint8_t)REG_CMD_WORD_BITS::REGISTER_B7 | (uint8_t)REG_CMD_WORD_BITS::WRITE_B6;
- uint8_t res1, res2;
+ //uint8_t res1, res2;
spiEnable();
- res1 = SPI.transfer(data);
- res2 = SPI.transfer(value);
+ SPI.transfer(data);
+ SPI.transfer(value);
spiDisable();
//Log.info("Write register %i, data=%i, value=%i, res1=%i, res2=%i", regi, data, value, res1, res2);
@@ -267,10 +269,10 @@ void BoxRFID::sendCommand(uint8_t command) {
uint8_t data = command & 0b00011111;
data |= (uint8_t)REG_CMD_WORD_BITS::COMMAND_B7 | (uint8_t)REG_CMD_WORD_BITS::WRITE_B6;
- uint8_t res1, res2;
+ //uint8_t res1, res2;
spiEnable();
- res1 = SPI.transfer(data);
- res2 = SPI.transfer(0x00); //0xFF or 0x00? (Ghost bytes) //Dummy transfer, see TRF796xA SPI Design Tips (sloa140)
+ SPI.transfer(data);
+ SPI.transfer(0x00); //0xFF or 0x00? (Ghost bytes) //Dummy transfer, see TRF796xA SPI Design Tips (sloa140)
spiDisable();
//Log.info("Write command %i, data=%i, res1=%i, res2=%i", command, data, res1, res2);
@@ -401,7 +403,7 @@ BoxRFID::ISO15693_RESULT BoxRFID::ISO15693_readSingleBlock(uint8_t blockId, uint
}
BoxRFID::ISO15693_RESULT BoxRFID::ISO15693_sendSingleSlotInventory(uint8_t* uid) {
- uint8_t g_ui8TagDetectedCount;
+ //uint8_t g_ui8TagDetectedCount;
uint8_t ui8LoopCount = 0;
uint8_t offset = 0;
@@ -424,7 +426,7 @@ BoxRFID::ISO15693_RESULT BoxRFID::ISO15693_sendSingleSlotInventory(uint8_t* uid)
Log.printf("%x ", uid[7-ui8LoopCount]); // Send UID to host
}
Log.println();*/
- g_ui8TagDetectedCount = 1;
+ //g_ui8TagDetectedCount = 1;
return ISO15693_RESULT::INVENTORY_VALID_RESPONSE;
} else {
Log.error("Invalid length, should be %i but is %i", 10, trfRxLength);
@@ -443,7 +445,6 @@ BoxRFID::ISO15693_RESULT BoxRFID::ISO15693_sendSingleSlotInventory(uint8_t* uid)
}
BoxRFID::ISO15693_RESULT BoxRFID::ISO15693_getRandomSlixL(uint8_t* random) {
uint8_t offset = 0;
- uint16_t randomNum;
trfBuffer[offset++] = 0x02; // ISO15693 flags - ISO15693_REQ_DATARATE_HIGH
trfBuffer[offset++] = 0xB2; // ISO15693_CMD_NXP_GET_RANDOM_NUMBER
@@ -457,7 +458,7 @@ BoxRFID::ISO15693_RESULT BoxRFID::ISO15693_getRandomSlixL(uint8_t* random) {
random[0] = trfBuffer[1];
random[1] = trfBuffer[2];
}
- randomNum = ((trfBuffer[1]<<8)|trfBuffer[2]);
+ //uint16_t randomNum = ((trfBuffer[1]<<8)|trfBuffer[2]);
//Log.info("Random number=%X", randomNum);
return ISO15693_RESULT::GET_RANDOM_VALID;
} else {
@@ -491,7 +492,7 @@ BoxRFID::ISO15693_RESULT BoxRFID::ISO15693_setPassSlixL(uint8_t pass_id, uint32_
buffer[2] = (password>>16) & 0xFF;
buffer[3] = (password>>24) & 0xFF;
- if(random) {
+ if (random[0] || random[1]) {
buffer[0] ^= random[0];
buffer[1] ^= random[1];
buffer[2] ^= random[0];
@@ -535,8 +536,7 @@ void BoxRFID::reinitRFID() {
trfOffset = 0;
trfRxLength = 0;
trfStatus = TRF_STATUS::TRF_IDLE;
- writeRegister(REGISTER::CHIP_STATUS_CONTROL, 0b00100001); //turnRfOn();
- Box.delayTask(20);
+ turnFieldOn();
}
uint8_t BoxRFID::readIrqRegister() {
@@ -676,7 +676,7 @@ void BoxRFID::initRFID() {
}
BoxRFID::TRF_STATUS BoxRFID::sendDataTag(uint8_t *sendBuffer, uint8_t sendLen) {
- sendDataTag(sendBuffer, sendLen, 15, 15); //15, 5 vs. 15, 15 (longer timeout for set password)
+ return sendDataTag(sendBuffer, sendLen, 15, 15); //15, 5 vs. 15, 15 (longer timeout for set password)
}
BoxRFID::TRF_STATUS BoxRFID::sendDataTag(uint8_t *sendBuffer, uint8_t sendLen, uint8_t txTimeout, uint8_t rxTimeout) {
uint8_t buffer[sendLen+5];
@@ -723,8 +723,7 @@ uint8_t BoxRFID::readBlocks(uint8_t* data, uint8_t maxBytes) {
resetRFID();
initRFID();
- writeRegister(REGISTER::CHIP_STATUS_CONTROL, 0b00100001); //turnRfOn();
- Box.delayTask(20); //not 1 ms?!
+ turnFieldOn();
for (uint8_t i=0; imisc.swd);
boxLEDs.setAll(BoxLEDs::CRGB::White);
boxBattery.begin();
boxLEDs.setAll(BoxLEDs::CRGB::Orange);
@@ -43,14 +79,20 @@ void Hackiebox::setup() {
boxCLI.begin();
+ Box.boxPower.feedSleepTimerSilent();
boxWiFi = WrapperWiFi(config->wifi.ssid, config->wifi.password);
boxWiFi.begin();
+ Box.boxPower.feedSleepTimerSilent();
webServer = WrapperWebServer();
webServer.begin();
+
+ boxPlayer = BoxPlayer();
+ boxPlayer.begin();
boxAccel.setName("Accelerometer");
boxBattery.setName("Battery");
+ boxBattery.batteryTestThread.setName("Battery.Test");
boxCLI.setName("CLI");
boxDAC.setName("DAC");
boxRFID.setName("RFID");
@@ -69,35 +111,38 @@ void Hackiebox::setup() {
boxPower.priority = 10;
boxWiFi.priority = 50;
boxBattery.priority = 100;
+ boxBattery.batteryTestThread.priority = 100;
boxCLI.priority = 100;
threadController = ThreadController();
threadController.add(&boxAccel);
threadController.add(&boxBattery);
+ threadController.add(&boxBattery.batteryTestThread);
threadController.add(&boxCLI);
threadController.add(&boxDAC);
- threadController.add(&boxRFID);
threadController.add(&boxEars);
+ threadController.add(&boxRFID);
threadController.add(&boxLEDs);
threadController.add(&boxPower);
threadController.add(&boxWiFi);
threadController.add(&webServer);
+ threadController.sortThreads();
Log.info("Config: %s", Config.getAsJson().c_str());
boxAccel.onRun(ThreadCallbackHandler([&]() { boxAccel.loop(); }));
+ boxBattery.onRun(ThreadCallbackHandler([&]() { boxBattery.loop(); }));
+ boxBattery.batteryTestThread.onRun(ThreadCallbackHandler([&]() { boxBattery.doBatteryTestStep(); }));
boxCLI.onRun(ThreadCallbackHandler([&]() { boxCLI.loop(); }));
boxDAC.onRun(ThreadCallbackHandler([&]() { boxDAC.loop(); }));
+ boxEars.onRun(ThreadCallbackHandler([&]() { boxEars.loop(); }));
boxRFID.onRun(ThreadCallbackHandler([&]() { boxRFID.loop(); }));
- boxPower.onRun(ThreadCallbackHandler([&]() { boxPower.loop(); }));
boxLEDs.onRun(ThreadCallbackHandler([&]() { boxLEDs.loop(); }));
- boxBattery.onRun(ThreadCallbackHandler([&]() { boxBattery.loop(); }));
- boxEars.onRun(ThreadCallbackHandler([&]() { boxEars.loop(); }));
+ boxPower.onRun(ThreadCallbackHandler([&]() { boxPower.loop(); }));
boxWiFi.onRun(ThreadCallbackHandler([&]() { boxWiFi.loop(); }));
webServer.onRun(ThreadCallbackHandler([&]() { webServer.loop(); }));
- boxBattery._batteryTestThread = EnhancedThread(ThreadCallbackHandler([&]() { boxBattery._doBatteryTestStep(); }), 10*60*1000);
- boxBattery._batteryTestThread.enabled = false;
+ //logStreamSse.setSsePaused(false);
boxLEDs.defaultIdleAnimation();
Log.info("Hackiebox started!");
@@ -108,8 +153,6 @@ void Hackiebox::setup() {
//Workaround, as something seems to interfere / remove the irq.
//But box now crashes!
boxDAC.i2sStartMicros = micros();
-
- threadController.sortThreads();
}
void Hackiebox::delayTask(uint16_t millis) {
@@ -164,15 +207,16 @@ bool Hackiebox::watchdog_start() {
MAP_PRCMPeripheralClkEnable(PRCM_WDT, PRCM_RUN_MODE_CLK);
MAP_WatchdogUnlock(WDT_BASE);
MAP_IntPrioritySet(INT_WDT, INT_PRIORITY_LVL_1);
+ MAP_WatchdogStallEnable(WDT_BASE); //Allow Debugging
MAP_WatchdogIntRegister(WDT_BASE, watchdog_handler);
- MAP_WatchdogReloadSet(WDT_BASE, 80000000*5); //5s
+ MAP_WatchdogReloadSet(WDT_BASE, 80000000*10); //10s
MAP_WatchdogEnable(WDT_BASE);
return MAP_WatchdogRunning(WDT_BASE);
}
void Hackiebox::watchdog_stop() {
MAP_WatchdogUnlock(WDT_BASE);
- MAP_WatchdogStallDisable(WDT_BASE);
+ MAP_WatchdogReloadSet(WDT_BASE, 0xFFFFFFFF); //set timer to high value
MAP_WatchdogIntClear(WDT_BASE);
MAP_WatchdogIntUnregister(WDT_BASE);
}
diff --git a/Hackiebox.h b/Hackiebox.h
index 075d03f..aa8b8cb 100644
--- a/Hackiebox.h
+++ b/Hackiebox.h
@@ -18,6 +18,7 @@
#include "BoxEvents.h"
#include "BoxI2C.h"
#include "BoxLEDs.h"
+#include "BoxPlayer.h"
#include "BoxPower.h"
#include "BoxRFID.h"
#include "BoxSD.h"
@@ -60,6 +61,7 @@ class Hackiebox {
BoxI2C boxI2C;
BoxLEDs boxLEDs;
BoxPower boxPower;
+ BoxPlayer boxPlayer;
BoxRFID boxRFID;
BoxSD boxSD;
BoxTonies boxTonie;
diff --git a/LogStreamMulti.cpp b/LogStreamMulti.cpp
index 0341866..153cf1d 100644
--- a/LogStreamMulti.cpp
+++ b/LogStreamMulti.cpp
@@ -9,7 +9,7 @@ void LogStreamMulti::setSlot(Stream* stream, uint8_t id) {
}
size_t LogStreamMulti::write(uint8_t character) {
- write(&character, 1);
+ return write(&character, 1);
}
size_t LogStreamMulti::write(const uint8_t *buffer, size_t size) {
size_t position = 0;
@@ -35,7 +35,7 @@ size_t LogStreamMulti::println() {
for (uint8_t i = 0; i < LOG_STREAM_MULTI_MAX_SIZE; i++) {
if (_streams[i] == 0)
continue;
- result = _streams[i]->print("\r\n");
+ result = _streams[i]->println();//("\r\n");
}
flush();
return 2;
@@ -46,6 +46,7 @@ void LogStreamMulti::flush() {
if (_streams[i] == 0)
continue;
_streams[i]->write((const uint8_t*)&_buffer, _getBufferPosition());
+ _streams[i]->flush();
}
memset(_buffer, '\0', LOG_STREAM_MULTI_BUFFER_SIZE);
}
diff --git a/LogStreamMulti.h b/LogStreamMulti.h
index 26cbf29..103400b 100644
--- a/LogStreamMulti.h
+++ b/LogStreamMulti.h
@@ -15,9 +15,9 @@ class LogStreamMulti : public Stream {
size_t write(uint8_t character);
size_t write(const uint8_t *buffer, size_t size);
- int available(){};
- int read(){};
- int peek(){};
+ int available() { return 0; };
+ int read() { return 0; };
+ int peek() { return 0; };
void flush();
private:
diff --git a/LogStreamSd.cpp b/LogStreamSd.cpp
index ee64830..ffd54bb 100644
--- a/LogStreamSd.cpp
+++ b/LogStreamSd.cpp
@@ -6,7 +6,7 @@
#include
size_t LogStreamSd::write(uint8_t character) {
- write(&character, 1);
+ return write(&character, 1);
}
size_t LogStreamSd::write(const uint8_t *buffer, size_t size) {
if (!Box.boxSD.isInitialized())
diff --git a/LogStreamSd.h b/LogStreamSd.h
index afe1b4c..a8df873 100644
--- a/LogStreamSd.h
+++ b/LogStreamSd.h
@@ -10,10 +10,10 @@ class LogStreamSd : public Stream {
size_t write(uint8_t character);
size_t write(const uint8_t *buffer, size_t size);
- int available() {};
- int read(){};
- void flush(){};
- int peek(){};
+ int available() { return 0; };
+ int read() { return 0; };
+ int peek() { return 0; };
+ void flush() { };
private:
FileFs _file;
diff --git a/LogStreamSse.cpp b/LogStreamSse.cpp
index f9e297e..8a7c7dd 100644
--- a/LogStreamSse.cpp
+++ b/LogStreamSse.cpp
@@ -6,20 +6,44 @@
size_t LogStreamSse::write(uint8_t character) {
if (Box.webServer.subscriptionCount == 0 || _ssePaused)
return 0;
-
+
for (uint8_t i = 0; i < SSE_MAX_CHANNELS; i++) {
WrapperWebServer::SSESubscription* subscription = &Box.webServer.subscription[i];
WiFiClient* client = &(subscription->client);
if (!(subscription->clientIP) || !client->connected())
continue;
- if (_lineFinished) {
- client->print("data: { \"type\":\"");
- client->print("log");
- client->print("\", \"data\":\"");
- _lineFinished = false;
+ bool tagIsOpen = _tagIsOpen;
+ if (character == '\n') {
+ if (_tagIsOpen) {
+ client->print("\" }\n\n"); // Extra newline required by SSE standard
+ tagIsOpen = false;
+ }
+ client->flush();
+ } else {
+ if (!_tagIsOpen) {
+ client->print("data: { \"type\":\"");
+ client->print("log");
+ client->print("\", \"data\":\"");
+ tagIsOpen = true;
+ }
+ switch (character) {
+ case '\r':
+ case '\b':
+ case '\f':
+ break;
+ case '\t':
+ break;
+ client->print("\\t");
+ case '\"':
+ break;
+ client->print("\\\"");
+ default:
+ client->print((char)character);
+ break;
+ }
}
- client->print(character); //TODO escape ";
+ _tagIsOpen = tagIsOpen;
}
return 1;
}
@@ -28,12 +52,7 @@ size_t LogStreamSse::println() {
if (Box.webServer.subscriptionCount == 0 || _ssePaused)
return 0;
- size_t result = print("\" }\n\n"); // Extra newline required by SSE standard
- _lineFinished = true;
- return result;
-}
-bool LogStreamSse::isLineFinished() {
- return _lineFinished;
+ return print("\n");
}
void LogStreamSse::setSsePaused(bool paused) {
_ssePaused = paused;
diff --git a/LogStreamSse.h b/LogStreamSse.h
index 9c5711e..dfaabcd 100644
--- a/LogStreamSse.h
+++ b/LogStreamSse.h
@@ -8,17 +8,16 @@ class LogStreamSse : public Stream {
size_t println();
size_t write(uint8_t);
- int available() {};
- int read(){};
- void flush(){};
- int peek(){};
+ int available() { return 0; };
+ int read() { return 0; };
+ int peek() { return 0; };
+ void flush() { };
- bool isLineFinished();
void setSsePaused(bool paused);
private:
- bool _lineFinished = true;
bool _ssePaused = true;
+ bool _tagIsOpen = false;
};
#endif
\ No newline at end of file
diff --git a/README.md b/README.md
index a6878be..8e8bb1f 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ The custom bootloader is fully functional. The hackiebox custom firmware itself
- Hardware drivers (WiFi, AMP/DAC, RFID reader, accelleration sensor, battery/charger, SD, LEDs)
- Webinterface with basic CLI and file upload/download
- JSON configuration file
-- Battery stamina test with csv log
+- Battery stamina test with WAV-playback with csv log
- Tonie file header decoder
- WAV player (with cli + by wav file in /rCONTENT//)
### Todo
@@ -31,7 +31,7 @@ The custom bootloader is fully functional. The hackiebox custom firmware itself
## Compiling
### Preface
-Currently building only works with Windows. Linux doesn't work on a x64 only system.
+Building works on Windows, macOS and Linux.
You should prepare the toniebox with the [sd bootloader](https://github.com/toniebox-reverse-engineering/hackiebox_cfw/wiki/Custom-bootloader) to load the cfw from your sd card.
### Prerequisite
#### Energia
@@ -47,7 +47,7 @@ The folder with the boards packages are located at:
`~/.energia15/packages/energia/hardware/`
##### macOS
`~/Library/Energia15/packages/hardware/`
-#### Additional libraries
+#### Additional libraries (Install lib via ZIP)
[SimpleCLI](https://github.com/toniebox-reverse-engineering/SimpleCLI)
[ESP8266Audio](https://github.com/toniebox-reverse-engineering/ESP8266Audio)
[ESP8266SAM](https://github.com/toniebox-reverse-engineering/ESP8266SAM)
@@ -57,11 +57,11 @@ Open hackiebox_cfw.ino with energia and build the cfw. Remember the path where t
### Preface
It is recommended to have a second copy of the cfw to be able to load the working image and update a broken cfw image over your backup cfw.
### Copy to sd
-First of all you need to create "/revvox/web" on your sd card (subdir revvox should be already there if you have successfully installed the sd bootloader) and copy over the content of the /web/ directory of this repository. In addition you have to copy your cfw image to your selected slot(s) on the sd card. (ex. "/revvox/boot/pre-img1.bin")
+First of all you need to create "/revvox/web" on your sd card (subdir revvox should be already there if you have successfully installed the sd bootloader) and copy over the content of the /web/ directory of this repository. The same applies to the "/revvox/audio" directory for WAV-playback during the battery test. In addition you have to copy your cfw image to your selected slot(s) on the sd card. (ex. "/revvox/boot/pre-img1.bin")
### First boot
Reinsert the sd card and run the cfw once. Then shutdown the box again (put the box onto the front where the speaker/tonie logo is and press both ears for 10s). Then remove the sd card again and add your wifi credentials to the created "/revvox/hackiebox.config.json" config file.
## Firmware updates
To update the firmware ota you can just use the hackiebox website und the box' ip address. (Expert->File Upload).
## Additional information for developers
-Keep in mind that connecting the RX Pin of the box to a serial interface blocks the big ear. For reading the log messages it is enough to have the TX Pin only connected (beside GND).
-[Trello Hackiebox Dev Board](https://trello.com/b/NcoJ9crt/hackiebox-cfw)
+Keep in mind that connecting the RX Pin of the box to a serial interface blocks the big ear. For reading the log messages it is enough to have the TX Pin only connected (beside GND).
+In general there is something wrong with the firmware. If you start to refactor the firmware or make bigger changes, it may crash on startup. The reason is currently unknown. Could be a linker problem or some kind of overflow.
diff --git a/WrapperWebServer.cpp b/WrapperWebServer.cpp
index 0000c81..f2c6769 100755
--- a/WrapperWebServer.cpp
+++ b/WrapperWebServer.cpp
@@ -143,11 +143,13 @@ void WrapperWebServer::handleAjax(void) {
if (commandGetFlashFile(&filename, read_start, read_length))
return;
} else if (cmd.equals("copy-file")) {
+ /*
String source_str = _server->arg("source");
String target_str = _server->arg("target");
char* source = (char*)source_str.c_str();
char* target = (char*)target_str.c_str();
- //TBD
+ //TODO
+ */
} else if (cmd.equals("move-file")) {
String source_str = _server->arg("source");
String target_str = _server->arg("target");
@@ -202,11 +204,13 @@ void WrapperWebServer::handleAjax(void) {
}
}
} else if (cmd.equals("copy-dir")) {
+ /*
String source_str = _server->arg("source");
String target_str = _server->arg("target");
char* source = (char*)source_str.c_str();
char* target = (char*)target_str.c_str();
- //TBD
+ //TODO
+ */
} else if (cmd.equals("delete-dir")) {
String dir_str = _server->arg("dir");
char* dir = (char*)dir_str.c_str();
@@ -337,7 +341,7 @@ void WrapperWebServer::sendJsonSuccess() {
_server->send(200, "text/json", "{ \"success\": true }");
}
-bool WrapperWebServer::commandGetFile(String* path, long read_start, long read_length, bool download) {
+bool WrapperWebServer::commandGetFile(String* path, uint32_t read_start, uint32_t read_length, bool download) {
FileFs file;
if (file.open((char*)path->c_str(), FA_OPEN_EXISTING | FA_READ)) {
if (read_length == 0 || file.fileSize() < read_length)
@@ -381,7 +385,7 @@ bool WrapperWebServer::commandGetFile(String* path, long read_start, long read_l
}
return false;
}
-bool WrapperWebServer::commandGetFlashFile(String* path, long read_start, long read_length) {
+bool WrapperWebServer::commandGetFlashFile(String* path, uint32_t read_start, uint32_t read_length) {
if (SerFlash.open((char*)path->c_str(), FS_MODE_OPEN_READ) == SL_FS_OK) {
if (read_length == 0 || SerFlash.size() < read_length)
read_length = SerFlash.size();
@@ -416,10 +420,10 @@ bool WrapperWebServer::commandGetFlashFile(String* path, long read_start, long r
}
void WrapperWebServer::handleUploadFile() {
- Box.boxPower.feedSleepTimer();
Box.delayTask(0);
HTTPUpload& upload = _server->upload();
if (upload.status == UPLOAD_FILE_START) {
+ Box.boxPower.feedSleepTimer();
String filepath = _server->arg("filepath");
char* filename = (char*)filepath.c_str();
bool overwrite = false;
@@ -438,14 +442,16 @@ void WrapperWebServer::handleUploadFile() {
_uploadFile.seekSet(write_start);
return;
}
- Log.error("File Couldn't be opened.");
+ Log.error("File couldn't be opened.");
} else if (upload.status == UPLOAD_FILE_WRITE) {
+ Box.boxPower.feedSleepTimerSilent();
//Log.verbose("handleUploadFile Data: %i", upload.currentSize);
if (_uploadFileOpen) {
_uploadFile.write(upload.buf, upload.currentSize);
return;
}
} else if (upload.status == UPLOAD_FILE_END) {
+ Box.boxPower.feedSleepTimer();
if (_uploadFileOpen) {
_uploadFile.close();
Log.info("handleUploadFile Size: %ikB", upload.totalSize / 1024);
@@ -507,7 +513,7 @@ void WrapperWebServer::handleUploadFlashFile() {
handleNotFound();
}
-void WrapperWebServer::sendEvent(char* eventname, char* content) {
+void WrapperWebServer::sendEvent(const char* eventname, const char* content) {
bool clientConnected = false;
for (uint8_t i = 0; i < SSE_MAX_CHANNELS; i++) {
if (!(subscription[i].clientIP))
diff --git a/WrapperWebServer.h b/WrapperWebServer.h
index 8d2a651..20b8f89 100755
--- a/WrapperWebServer.h
+++ b/WrapperWebServer.h
@@ -38,13 +38,13 @@ class WrapperWebServer : public EnhancedThread {
void
sseHandler(uint8_t channel),
sseKeepAlive(),
- sendEvent(char* eventname, char* content);
+ sendEvent(const char* eventname, const char* content);
//sendEventJSON(char* eventname, xyzjsondoc jsonContent);
bool
- commandGetFile(String* path, long read_start, long read_length, bool download),
- commandGetFlashFile(String* path, long read_start, long read_length);
+ commandGetFile(String* path, uint32_t read_start, uint32_t read_length, bool download),
+ commandGetFlashFile(String* path, uint32_t read_start, uint32_t read_length);
BoxTimer _sseTimer;
WebServer* _server;
diff --git a/WrapperWiFi.cpp b/WrapperWiFi.cpp
index 64c2493..ea94f39 100755
--- a/WrapperWiFi.cpp
+++ b/WrapperWiFi.cpp
@@ -31,8 +31,10 @@ void WrapperWiFi::begin() {
Log.info("Known WiFi Profiles:");
for (uint8_t i=0; i<7; i++) {
- if (strlen(profiles[i].wifiName)>0)
+ if (profiles[i].wifiNameLen>0) {
+ profiles[i].wifiName[profiles[i].wifiNameLen] = '\0';
Log.info(" -%i: Name=%s", i, profiles[i].wifiName);
+ }
}
setInterval(5000);
diff --git a/audio/both-of-us-14037.wav b/audio/both-of-us-14037.wav
new file mode 100644
index 0000000..317ad0d
Binary files /dev/null and b/audio/both-of-us-14037.wav differ
diff --git a/audio/cinematic-fairy-tale-story-main-8697.wav b/audio/cinematic-fairy-tale-story-main-8697.wav
new file mode 100644
index 0000000..61a7d63
Binary files /dev/null and b/audio/cinematic-fairy-tale-story-main-8697.wav differ
diff --git a/audio/electronic-rock-king-around-here-15045.wav b/audio/electronic-rock-king-around-here-15045.wav
new file mode 100644
index 0000000..47b7fdc
Binary files /dev/null and b/audio/electronic-rock-king-around-here-15045.wav differ
diff --git a/audio/into-the-night-20928.wav b/audio/into-the-night-20928.wav
new file mode 100644
index 0000000..2a1e4b5
Binary files /dev/null and b/audio/into-the-night-20928.wav differ
diff --git a/audio/melody-of-nature-main-6672.wav b/audio/melody-of-nature-main-6672.wav
new file mode 100644
index 0000000..e05e5dd
Binary files /dev/null and b/audio/melody-of-nature-main-6672.wav differ
diff --git a/audio/nightlife-michael-kobrin-95bpm-3783.wav b/audio/nightlife-michael-kobrin-95bpm-3783.wav
new file mode 100644
index 0000000..75a6afe
Binary files /dev/null and b/audio/nightlife-michael-kobrin-95bpm-3783.wav differ
diff --git a/audio/source/both-of-us-14037.txt b/audio/source/both-of-us-14037.txt
new file mode 100644
index 0000000..889ba7a
--- /dev/null
+++ b/audio/source/both-of-us-14037.txt
@@ -0,0 +1 @@
+https://pixabay.com/de/music/schlagt-both-of-us-14037/
diff --git a/audio/source/cinematic-fairy-tale-story-main-8697.txt b/audio/source/cinematic-fairy-tale-story-main-8697.txt
new file mode 100644
index 0000000..5a4c23f
--- /dev/null
+++ b/audio/source/cinematic-fairy-tale-story-main-8697.txt
@@ -0,0 +1 @@
+https://pixabay.com/de/music/uberschrift-cinematic-fairy-tale-story-main-8697/
diff --git a/audio/source/electronic-rock-king-around-here-15045.txt b/audio/source/electronic-rock-king-around-here-15045.txt
new file mode 100644
index 0000000..3232ea0
--- /dev/null
+++ b/audio/source/electronic-rock-king-around-here-15045.txt
@@ -0,0 +1 @@
+https://pixabay.com/de/music/schlagt-electronic-rock-king-around-here-15045/
diff --git a/audio/source/into-the-night-20928.txt b/audio/source/into-the-night-20928.txt
new file mode 100644
index 0000000..0232b49
--- /dev/null
+++ b/audio/source/into-the-night-20928.txt
@@ -0,0 +1 @@
+https://pixabay.com/de/music/schlagt-into-the-night-20928/
diff --git a/audio/source/melody-of-nature-main-6672.txt b/audio/source/melody-of-nature-main-6672.txt
new file mode 100644
index 0000000..99ccbde
--- /dev/null
+++ b/audio/source/melody-of-nature-main-6672.txt
@@ -0,0 +1 @@
+https://pixabay.com/de/music/schone-stucke-melody-of-nature-main-6672/
diff --git a/audio/source/nightlife-michael-kobrin-95bpm-3783.txt b/audio/source/nightlife-michael-kobrin-95bpm-3783.txt
new file mode 100644
index 0000000..d3b1374
--- /dev/null
+++ b/audio/source/nightlife-michael-kobrin-95bpm-3783.txt
@@ -0,0 +1 @@
+https://pixabay.com/de/music/akustische-gruppe-nightlife-michael-kobrin-95bpm-3783/
diff --git a/audio/source/the-cradle-of-your-soul-15700.txt b/audio/source/the-cradle-of-your-soul-15700.txt
new file mode 100644
index 0000000..a1456d4
--- /dev/null
+++ b/audio/source/the-cradle-of-your-soul-15700.txt
@@ -0,0 +1 @@
+https://pixabay.com/de/music/solo-gitarre-the-cradle-of-your-soul-15700/
diff --git a/audio/source/trailer-sport-stylish-16073.txt b/audio/source/trailer-sport-stylish-16073.txt
new file mode 100644
index 0000000..ffc931c
--- /dev/null
+++ b/audio/source/trailer-sport-stylish-16073.txt
@@ -0,0 +1 @@
+https://pixabay.com/de/music/schlagt-trailer-sport-stylish-16073/
diff --git a/audio/source/yesterday-extended-version-14197.txt b/audio/source/yesterday-extended-version-14197.txt
new file mode 100644
index 0000000..38a5ece
--- /dev/null
+++ b/audio/source/yesterday-extended-version-14197.txt
@@ -0,0 +1 @@
+https://pixabay.com/de/music/schlagt-yesterday-extended-version-14197/
diff --git a/audio/the-cradle-of-your-soul-15700.wav b/audio/the-cradle-of-your-soul-15700.wav
new file mode 100644
index 0000000..7cbcf9a
Binary files /dev/null and b/audio/the-cradle-of-your-soul-15700.wav differ
diff --git a/audio/trailer-sport-stylish-16073.wav b/audio/trailer-sport-stylish-16073.wav
new file mode 100644
index 0000000..8bff677
Binary files /dev/null and b/audio/trailer-sport-stylish-16073.wav differ
diff --git a/audio/yesterday-extended-version-14197.wav b/audio/yesterday-extended-version-14197.wav
new file mode 100644
index 0000000..87f21c3
Binary files /dev/null and b/audio/yesterday-extended-version-14197.wav differ
diff --git a/web/hackiebox.html b/web/hackiebox.html
index 828a2ad..886d898 100644
--- a/web/hackiebox.html
+++ b/web/hackiebox.html
@@ -410,7 +410,7 @@ Credits
this._contentPage = new ContentPage();
this._server = this._params.get("server");
this._console = new WebConsole(this);
- //this._initSse();
+ this._initSse();
$("input[type='checkbox']").bootstrapSwitch();
@@ -703,4 +703,4 @@ Credits
}