diff --git a/Graphics/MortseUi.cpp b/Graphics/MortseUi.cpp deleted file mode 100644 index 85f8f52..0000000 --- a/Graphics/MortseUi.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "MortseUi.h" - diff --git a/TrigorMortse.ino b/TrigorMortse.ino index 4ed985b..ed1d827 100644 --- a/TrigorMortse.ino +++ b/TrigorMortse.ino @@ -1,8 +1,8 @@ - - #include #include +//#include "src/MortseUi.h" +const byte MorseTable[] = {0b00000000,0,0b00010010,0,0,0,0,0b00011110,0b10110110,0b00101101,0,0b10101010,0b00110011,0b00100001,0b00010101,0b10110010,0b10111111,0b10101111,0b10100111,0b10100011,0b10100001,0b10100000,0b10110000,0b10111000,0b10111100,0b10111111,0b00111000,0b00101010,0,0b10110001,0,0b00001100,0b00011010,0b01000001,0b10001000,0b10001010,0b01100100,0b00100000,0b10000010,0b01100110,0b10000000,0b01000000,0b10000111,0b01100101,0b10000100,0b01000011,0b01000010,0b01100111,0b10000110,0b10001101,0b01100010,0b01100000,0b00100001,0b01100001,0b10000001,0b01100011,0b10001001,0b10001011,0b10001100,0b10110110,0,0b00101101,0,0b00001101,0b00011110,0b01000001,0b10001000,0b10001010,0b01100100,0b00100000,0b10000010,0b01100110,0b10000000,0b01000000,0b10000111,0b01100101,0b10000100,0b01000011,0b01000010,0b01100111,0b10000110,0b10001101,0b01100010,0b01100000,0b00100001,0b01100001,0b10000001,0b01100011,0b10001001,0b10001011,0b10001100,0b10110110,0,0b00101101,0}; const int Channel1 = 9; //Output Channel 1 const int Channel2 = 10; //Output Channel 2 @@ -17,17 +17,27 @@ const int ClockIn = 4; //Clock In const int ClockDetect = 7; //Detect clock jack const int DebounceTime = 10; //Debounce time in ms +const int DisplaySpi = 0; //todo: find spi port ## from library + Encoder LeftEnc( Enc1P1, Enc1P2); Encoder RightEnc( Enc2P1, Enc2P2); +MortseUi Ui(DisplaySpi); + +String TestText = "Momento Mortse" + int E1 = 0; int E2 = 0; +int Channel1Index = 0; +int MorseIndex = 0; bool E1Btn = false; bool E2Btn = false; bool ClockState = false; -bool E1Prev, E2Prev, CDPrev, E1Click, E2Click, CDIn = false; -unsigned int E1Bounce, E2Bounce, CDBounce = 0; -unsigned long ClockPrev = 0; +bool Beat = false; +unsigned int Channel1Trig = 0, Channel2Trig = 0; Channel3Trig = 0; +bool E1Prev, E2Prev, CDPrev, E1Click, E2Click, CDIn = false, Channel1State = false, Channel2State = false, Channel3State = false; +unsigned int E1Bounce, E2Bounce, CDBounce = 0, BeatBounce = 0; +unsigned long ClockPrev = 0, ClockInPrev = 0, LastBeat = 0; byte Input = 0; int PpQN = 24; float Clock = 120; @@ -40,13 +50,16 @@ void setup() { //Open Serial for output prior to installing a screen Serial.begin( 115200 ); - Serial.println("Env Gen"); + Serial.println("Momento Mortse"); randomSeed(analogRead(A7)); pinMode(Enc1Btn, INPUT_PULLUP); pinMode(Enc2Btn, INPUT_PULLUP); pinMode(ClockIn, INPUT); pinMode(ClockDetect, INPUT_PULLUP); + pinMode(Channel1, OUTPUT); + PinMode(Channel2, OUTPUT); + PinMode(Channel3, OUTPUT); E1Btn = digitalRead(Enc1Btn); E1Prev = E1Btn; @@ -54,6 +67,9 @@ void setup() { E2Prev = E2Btn; ClockState = digitalRead(ClockIn); CDPrev = digitalRead(ClockDetect); + digitalWrite(Channel1, 0); + digitalWrite(Channel2, 0); + digitalWrite(Channel2, 0); // Timer0 is already used for millis() - we'll just interrupt somewhere // in the middle and call the "Compare A" function below @@ -105,11 +121,10 @@ void loop() { if (ClockState){ unsigned long tmpClock = micros(); float clkInTick = tmpClock - ClockPrev; - float newBPM = ((1.0/(clkInTick/1000000.0)) * 60.0)/(float)PpQN; ClockPrev = tmpClock; - if (abs(Clock - newBPM) > 0.5){ - Clock = newBPM; + if (abs(ClockInPrev - clkInTick) > 500){ + Clock = = ((1.0/(clkInTick/1000000.0)) * 60.0)/(float)PpQN; String outputBPM = "New BPM: "; outputBPM.concat(newBPM); Serial.println(outputBPM); @@ -118,9 +133,18 @@ void loop() { Serial.println(outputBPM); ClockTick = (1/((Clock * PpQN)/60)) * 1000; } + else{ + Beat = true; + LastBeat = tmpClock; + } } } + if ((LastBeat + ClockTick) < micros()){ + Beat = true; + LastBeat = micros(); + } + if (newLEnc != EncLeft || newREnc != EncRight){ String output = "Left Enc Pos: "; output.concat(newLEnc); @@ -146,12 +170,51 @@ void loop() { } - unsigned long currentTime = millis(); + if (Beat){ + Beat = false; + if (!BeatBounce){ - if ((currentTime - LastStepTime) > ClockTick){ - ClockTime++; - LastStepTime = currentTime; - }} + //Insert Beat Output here! + char outputChar = TestString[Channel1Index]; + if (outputChar == '/0'){ + Channel1Index = 0; + outputChar = TestString[Channel1Index]; + } + byte morselength = MorseTable[((int)outputChar - 32)]; + byte morsePattern = morseLength; + bool trigger = (morsePattern >> MorseIndex) & 1; + + if (MorseIndex == 0){ + Channel1Index++; + outputChar = TestString[Channel1Index]; + MorseIndex = ((MorseTable[((int)outputChar - 32)]) >> 5) - 1; + } + + MorseIndex--; + + if (trigger){ + digitalWrite(Channel1, true); + Channel1Trig = 5; + } + } + } + + if (Channel1State && !Channel1Trig){ + digitalWrite(Channel1, 0); + Channel1State = false; + } + if (Channel2State && !Channel2Trig){ + digitalWrite(Channel2, 0); + Channel2State = false; + } + if (Channel3State && !Channel3Trig){ + digitalWrite(Channel3, 0); + Channel3State = false; + } + + Ui.tick(); + + } // Interrupt is called once a millisecond, @@ -160,4 +223,8 @@ SIGNAL(TIMER0_COMPA_vect) E1Bounce = (E1Bounce - 1) & 0b10000000; E2Bounce = (E2Bounce - 1) & 0b10000000; CDBounce = (CDBounce - 1) & 0b10000000; + BeatBounce = (BeatBounce - 1) & 0b10000000; + Channel1Trig = (Channel1Trig - 1) & 0b10000000; + Channel2Trig = (Channel2Trig - 1) & 0b10000000; + Channel3Trig = (Channel3Trig - 1) & 0b10000000; } \ No newline at end of file diff --git a/src/MortseGfx.cpp b/src/MortseGfx.cpp new file mode 100644 index 0000000..66809cb --- /dev/null +++ b/src/MortseGfx.cpp @@ -0,0 +1,11 @@ +#include "MortseGfx.h" + + +byte MortseGfx::cursor_x = 0; +byte MortseGfx::cursor_y = 0; +enum cursorState MortseGfx::cursor_state = hidden; + + +void MortseGfx::init(){ + +} \ No newline at end of file diff --git a/Graphics/MortseUi.h b/src/MortseGfx.h similarity index 69% rename from Graphics/MortseUi.h rename to src/MortseGfx.h index bd1c457..dddf8e0 100644 --- a/Graphics/MortseUi.h +++ b/src/MortseGfx.h @@ -1,5 +1,5 @@ -#ifndef MORTSE_UI_H -#define MORTSE_UI_H +#ifndef MORTSE_GFX_H +#define MORTSE_GFX_H #include #include @@ -26,13 +26,32 @@ #define LOGO_WIDTH 16 static const unsigned char PROGMEM -class MortseUI{ - +class MortseGfx +{ private: + byte cursor_x; + byte cursor_y; + enum cursorState cursor_state; + public: - void Init(); + void init(); + void tick(); + + void MoveCursor(byte row, byte column); + + void SetChar(byte row, byte column, char value); + + void ClearChar(byte row, byte column); + + void SetCursorState(cursorState state); + } +enum cursorState { + hidden, + below +} + #endif \ No newline at end of file diff --git a/src/MortseUi.cpp b/src/MortseUi.cpp new file mode 100644 index 0000000..ab1d4eb --- /dev/null +++ b/src/MortseUi.cpp @@ -0,0 +1,107 @@ +/// + +#include "MortseUi.h" + + +//Private Variables +unsigned long MortseUI::nextCursorFlash = 0; +MortseGfx MortseUI::Gfx(); + +enum cursorState MortseUI::_cursorStyle = below; +bool MortseUI::_cursor_visible = true; + +byte MortseUI::_cursorLine = 0; +byte MortseUI::_cursorPosition = 0; +byte MortseUI::_cursorLine_buff = 0; +byte MortseUI::_cursorPosition_buff = 0; +bool MortseUI::_updateCursor = false; + +char MortseUI::_line1[LINE_LENGTH]; +char MortseUI::_line2[LINE_LENGTH]; +char MortseUI::_line1_buff[LINE_LENGTH]; +char MortseUI::_line2_buff[LINE_LENGTH]; +bool MortseUI::_updateLine1 = false; +bool MortseUI::_updateLine2 = false; + +//Public Methods + +/// @brief Constructor for Mortse UI +void MortseUi::MortseUi(){ + this->_incrementCursor(); + this ->_cursor = visible_blink; + + //Initialize lines to be blank + for(int ix = 0; ix < LINE_LENGTH; ix++){ + _line1[ix] = _line2[ix] = _line1_buff[ix] = _line2_buff[ix] = ' '; + } +} + +/// @brief Called every frame +void MortseUi::Tick(){ + if(millis() >= nextCursorFlash){ + this->_toggleCursor(); + this->_incrementCursor(); + } +} + + +/// @brief Returns a pointer to the first line on the screen +/// @param line1 character pointer array which is the length of LINE_LENGTH +void MortseUi::GetLine1(char *line1){ + line1 = &this->_line1_buff; +} + +/// @brief Returns a pointer to the second line on the screen +/// @param line2 character pointer array which is the length of LINE_LENGTH +void MortseUi::GetLine2(char *line2){ + line2 = &this->_line2_buff; +} + +/// @brief Lets the graphics library know that the line1 array should be updated on the screen +void MortseUi::UpdateLine1(){ + this->_updateLine(*_line1, *_line1_buff, 1); +} + +/// @brief Lets the graphics library know that the line2 array should be updated on the screen +void MortseUi::UpdateLine2(){ + this->_updateLine(*_line2, *_line2_buff, 2; +} + + +/// @brief Returns pointers to the line number and +/// @param line +/// @param position +void GetCursor(byte *line, byte* position){ + line = &this->_curs +} + +/// @brief Lets the graphics library know that the cursor position should be updated on the screen +void UpdateCursor(){ + if(cursor) +} + + + +/// Private Methods + +void MortseUi::void _incrementCursor(){ + nextCursorFlash = millis() + CURSOR_DELAY_MS; +} + +void MortseUi::void _toggleCursor(){ + if(this->_cursor_visible = !_cursor_visible){ + this->_gfx.SetCursorState(this->_cursorStyle); + } + else{ + this->_gfx.SetCursorState(hidden); + } +} + +void MortseUi::_updateLine(byte *lineRef, byte *lineBuff, byte lineNo){ + for(int ix = 0; ix > LINE_LENGTH; ix++){ + if(lineRef[ix] != lineBuff[ix]){ + lineRef[ix] = lineBuff[ix]; + _gfx->SetChar(lineNo, ix, lineRef[ix]); + } + } +} \ No newline at end of file diff --git a/src/MortseUi.h b/src/MortseUi.h new file mode 100644 index 0000000..0a73975 --- /dev/null +++ b/src/MortseUi.h @@ -0,0 +1,75 @@ +#ifndef MORTSE_UI_H +#define MORTSE_UI_H + +#define CURSOR_DELAY_MS 500; +#define LINE_LENGTH 16; + +#include +#include "MortseGfx.h" + +class MortseUI{ + + private: + //Graphics Library + MortseGfx _gfx(); + + //Cursor State + enum cursorState _cursorStyle; + bool _cursor_visible; + unsigned long _nextCursorFlash; + byte _cursorLine_buff; + byte _cursorLine; + byte _cursorPosition_buff; + byte _cursorPosition; + bool _updateCursor; + + char _line1[LINE_LENGTH]; + char _line2[LINE_LENGTH]; + char _line1_buff[LINE_LENGTH]; + char _line2_buff[LINE_LENGTH]; + bool _updateLine1; + bool _updateLine2; + + //Line State + + + + //Cursor State Updates + void _incrementCursor(); + void _toggleCursor(); + + void _updateLine(byte &lineRef, byte &lineBuff, byte lineNo); + + + public: + MortseUI(byte port); + + /// @brief Called Every Frame + void Tick(); + + /// @brief Returns a pointer to the first line on the screen + /// @param line1 character pointer array which is the length of LINE_LENGTH + void GetLine1(char *line1); + + /// @brief Returns a pointer to the second line on the screen + /// @param line2 character pointer array which is the length of LINE_LENGTH + void GetLine2(char *line2); + + /// @brief Lets the graphics library know that the line1 array should be updated on the screen + void UpdateLine1(); + + /// @brief Lets the graphics library know that the line2 array should be updated on the screen + void UpdateLine2(); + + + /// @brief Returns pointers to the line number and + /// @param line + /// @param position + void GetCursor(byte *line, byte* position); + + /// @brief Lets the graphics library know that the cursor position should be updated on the screen + void UpdateCursor(); + +} + +#endif \ No newline at end of file