From e9368dd5a55b8f306ac92007db2f79de6eff4e64 Mon Sep 17 00:00:00 2001 From: Jan-Henrik Bruhn Date: Mon, 28 Oct 2019 18:56:37 +0100 Subject: [PATCH] Implement ui stuff --- midi2cv/.lvimrc | 6 +++ midi2cv/drivers/display.cc | 2 - midi2cv/drivers/encoder.cc | 56 ++++++++++++++++++++++++++ midi2cv/drivers/encoder.h | 82 ++++++++++++++++++++++++++++++++++++++ midi2cv/midi2cv.cc | 11 ++++- midi2cv/ui.cc | 58 ++++++++++++++++++++++++++- midi2cv/ui.h | 16 ++++++-- 7 files changed, 223 insertions(+), 8 deletions(-) create mode 100644 midi2cv/.lvimrc create mode 100644 midi2cv/drivers/encoder.cc create mode 100644 midi2cv/drivers/encoder.h diff --git a/midi2cv/.lvimrc b/midi2cv/.lvimrc new file mode 100644 index 0000000..fc7fcbe --- /dev/null +++ b/midi2cv/.lvimrc @@ -0,0 +1,6 @@ +:packadd termdebug + +let termdebugger = "/usr/bin/arm-none-eabi-gdb" +:map :Termdebug /home/jhbruhn/eurorack/eurorack-dev-environment/eurorack-modules/build/midi2cv/midi2cv.elf --eval-command='target remote localhost:3333' + + diff --git a/midi2cv/drivers/display.cc b/midi2cv/drivers/display.cc index 8004062..641e876 100644 --- a/midi2cv/drivers/display.cc +++ b/midi2cv/drivers/display.cc @@ -22,8 +22,6 @@ u8g2_t* Display::u8g2() return &u8g2_; } -void InitSPI(void); - void Display::Init() { // init SS/CS/RST GPIO diff --git a/midi2cv/drivers/encoder.cc b/midi2cv/drivers/encoder.cc new file mode 100644 index 0000000..ac75f65 --- /dev/null +++ b/midi2cv/drivers/encoder.cc @@ -0,0 +1,56 @@ +// Copyright 2013 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Driver for rotary encoder. + +#include "midi2cv/drivers/encoder.h" + + +void Encoder::Init() { + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); + + + GPIO_InitTypeDef gpio_init; + + gpio_init.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; + gpio_init.GPIO_Speed = GPIO_Speed_10MHz; + gpio_init.GPIO_Mode = GPIO_Mode_IN; + gpio_init.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_Init(GPIOC, &gpio_init); + + switch_state_ = 0xff; + quadrature_decoding_state_[0] = quadrature_decoding_state_[1] = 0xff; +} + +void Encoder::Debounce() { + switch_state_ = (switch_state_ << 1) | \ + GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_15); + quadrature_decoding_state_[0] = (quadrature_decoding_state_[0] << 1) | \ + GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13); + quadrature_decoding_state_[1] = (quadrature_decoding_state_[1] << 1) | \ + GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_14); +} + diff --git a/midi2cv/drivers/encoder.h b/midi2cv/drivers/encoder.h new file mode 100644 index 0000000..018d3e2 --- /dev/null +++ b/midi2cv/drivers/encoder.h @@ -0,0 +1,82 @@ +// Copyright 2013 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Driver for rotary encoder. + +#ifndef YARNS_DRIVERS_ENCODER_H_ +#define YARNS_DRIVERS_ENCODER_H_ + +#include +#include "stmlib/stmlib.h" + +class Encoder { + public: + Encoder() { } + ~Encoder() { } + + void Init(); + void Debounce(); + + inline bool released() const { + return switch_state_ == 0x7f; + } + + inline bool just_pressed() const { + return switch_state_ == 0x80; + } + + inline bool pressed() const { + return switch_state_ == 0x00; + } + + inline bool pressed_immediate() const { + return !GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_15); + } + + inline int32_t increment() const { + int32_t increment = 0; + uint8_t a = quadrature_decoding_state_[0]; + uint8_t b = quadrature_decoding_state_[1]; + if ((a & 0x03) == 0x02 && (b & 0x03) == 0x00) { + increment = -1; + } else { + if ((b & 0x03) == 0x02 && (a & 0x03) == 0x00) { + increment = 1; + } + } + return increment; + } + + private: + uint8_t switch_state_; + uint8_t quadrature_decoding_state_[2]; + + DISALLOW_COPY_AND_ASSIGN(Encoder); +}; + +extern Encoder encoder; + +#endif // YARNS_DRIVERS_ENCODER_H_ diff --git a/midi2cv/midi2cv.cc b/midi2cv/midi2cv.cc index 428e8e4..8370f0e 100644 --- a/midi2cv/midi2cv.cc +++ b/midi2cv/midi2cv.cc @@ -1,6 +1,7 @@ #include #include "drivers/display.h" +#include "drivers/encoder.h" #include "drivers/gpio.h" #include "part.h" #include "stmlib/system/system_clock.h" @@ -10,8 +11,9 @@ using namespace stmlib; GPIO gpio; Display display; +Encoder encoder; + UI ui; -//SystemClock system_clock; Part part[PART_COUNT]; // Default interrupt handlers. @@ -46,6 +48,7 @@ void SysTick_Handler() { IWDG_ReloadCounter(); system_clock.Tick(); + ui.Poll(); } void TIM2_IRQHandler(void) @@ -116,6 +119,8 @@ void Init(void) gpio.Init(); // asm("bkpt #0"); display.Init(); + encoder.Init(); + ui.Init(); InitTimers(); } @@ -125,6 +130,8 @@ int main(void) while (1) { // In this loop we do things that dont depend on any timing, but that have to be done. // you should not write on spi here because that should happen in the TIM2 interrupt - ui.Update(); + // do we want to call the watchdog here? it's the only part thats getting interrupted after all + // (next to the interrupts themselves potentially interrupting each other) + ui.DoEvents(); } } diff --git a/midi2cv/ui.cc b/midi2cv/ui.cc index 04c8e40..383ecfe 100644 --- a/midi2cv/ui.cc +++ b/midi2cv/ui.cc @@ -1,5 +1,6 @@ #include "ui.h" #include "drivers/display.h" +#include "midi2cv/drivers/encoder.h" #include "part.h" #include "stmlib/utils/random.h" #include @@ -10,9 +11,23 @@ using namespace stmlib; const char part_names[4][2] = { "A", "B", "C", "D" }; -void UI::Update() +void UI::Init() { + input_queue.Init(); +} + +void UI::Poll() +{ + encoder.Debounce(); + int32_t increment = encoder.increment(); + if (increment != 0) { + input_queue.AddEvent(CONTROL_ENCODER, 0, increment); + } +} + +void UI::Draw() { u8g2_ClearBuffer(display.u8g2()); + switch (current_menu) { case MENU_PART_1: case MENU_PART_2: @@ -25,6 +40,7 @@ void UI::Update() break; } + display.Swap(); } @@ -53,3 +69,43 @@ void UI::Flush() { display.Flush(); } + +bool UI::DoEvents() +{ + bool refresh_display = false; + while (input_queue.available()) { + Event e = input_queue.PullEvent(); + if (e.control_type == CONTROL_ENCODER_CLICK) { + OnClick(); + } else if (e.control_type == CONTROL_ENCODER_LONG_CLICK) { + OnLongClick(); + } else if (e.control_type == CONTROL_ENCODER) { + OnIncrement(e); + } + refresh_display = true; + } + + if (input_queue.idle_time() > 1000) { + refresh_display = true; + } + + if(refresh_display) { + input_queue.Touch(); + Draw(); + } + + return refresh_display; +} + +void UI::OnClick() +{ +} + +void UI::OnLongClick() +{ +} + +void UI::OnIncrement(Event& e) +{ + current_menu = (Menu_t) (((uint32_t)current_menu + e.data) % MENU_COUNT); +} diff --git a/midi2cv/ui.h b/midi2cv/ui.h index 8b37947..d3e868a 100644 --- a/midi2cv/ui.h +++ b/midi2cv/ui.h @@ -2,9 +2,10 @@ #define MIDI2CV_UI_H #include "stmlib/stmlib.h" +#include "stmlib/ui/event_queue.h" typedef enum { - MENU_PART_1, + MENU_PART_1 = 0, MENU_PART_2, MENU_PART_3, MENU_PART_4, @@ -16,15 +17,24 @@ class UI { UI() {} ~UI() {} - void Update(); + void Init(); + void Poll(); void Flush(); + bool DoEvents(); private: - Menu_t current_menu; + Menu_t current_menu; + stmlib::EventQueue<16> input_queue; + + void Draw(); void DrawHeader(); void DrawPartMenu(Menu_t menu); + void OnClick(); + void OnLongClick(); + void OnIncrement(stmlib::Event &e); + DISALLOW_COPY_AND_ASSIGN(UI); };