Line data Source code
1 : #pragma once 2 : 3 : #include <MIDI_Inputs/MIDIInputElementCC.hpp> 4 : #include <Print.h> 5 : #include <string.h> 6 : 7 : BEGIN_CS_NAMESPACE 8 : 9 : namespace MCU { 10 : 11 : template <uint8_t LENGTH> 12 13 : class SevenSegmentDisplay : public MIDIInputElementCC, public Printable { 13 : public: 14 : /** 15 : * @brief Constructor. 16 : * @todo Documentation. 17 : */ 18 13 : SevenSegmentDisplay(const MIDIAddress &address) 19 26 : : MIDIInputElementCC{address} { 20 13 : fillWithSpaces(); 21 13 : } 22 : 23 13 : void fillWithSpaces() { 24 143 : for (char &c : text) 25 130 : c = ' '; 26 13 : } 27 : 28 0 : void reset() override { 29 : #ifdef SEVENSEG_RESET 30 : fillWithSpaces(); 31 : #endif 32 0 : } 33 : 34 : private: 35 : /** 36 : * @brief Update a character. 37 : */ 38 67 : virtual bool updateImpl(const ChannelMessageMatcher &midimsg, 39 : const MIDIAddress &target) override { 40 67 : uint8_t index = LENGTH - 1 - getRangeIndex(target); 41 : // MIDI msg: character data → bits 0-5 42 : // MIDI msg: decimal point → bit 6 set, no decimal point → bit 6 not set 43 : // text: decimal point → bit 7 set, no decimal point → bit 7 not set 44 67 : uint8_t decimalPt = (midimsg.data2 & 0x40) << 1; 45 67 : uint8_t chardata = midimsg.data2 & 0x3F; 46 67 : uint8_t character = chardata >= 0x20 ? chardata : chardata + 0x40; 47 67 : character |= decimalPt; 48 67 : text[index] = character; 49 67 : return true; 50 67 : } 51 : 52 : /// Check if the address of the incoming MIDI message is within the range 53 : /// of addresses of this element. 54 67 : bool match(const MIDIAddress &target) const override { 55 67 : return MIDIAddress::matchAddressInRange(target, address, 56 : LENGTH); 57 : } 58 : 59 : /// @todo 60 67 : uint8_t getRangeIndex(const MIDIAddress &target) const { 61 67 : return target.getAddress() - this->address.getAddress(); 62 : } 63 : 64 : public: 65 : /** 66 : * @brief Copy the ASCII text into the given buffer. 67 : * 68 : * @param[out] buffer 69 : * The destination to write the text to. 70 : * Will be null-terminated. 71 : * Should have a size of at least `length`+1 bytes. 72 : * @param[in] offset 73 : * The offset to start copying from (in the source text, the offset 74 : * in the destination buffer is always zero). 75 : * @param[in] length 76 : * The number of characters to copy. 77 : */ 78 30 : void getText(char *buffer, uint8_t offset = 0, 79 : uint8_t length = LENGTH) const { 80 30 : if (offset >= LENGTH) 81 1 : offset = LENGTH - 1; 82 30 : if (length > LENGTH - offset) 83 4 : length = LENGTH - offset; 84 172 : for (uint8_t i = 0; i < length; i++) 85 142 : buffer[i] = getCharacterAt(i + offset); 86 30 : buffer[length] = '\0'; 87 30 : } 88 : 89 : /** 90 : * @brief Get the character at the given index. 91 : * @todo Documentation. 92 : */ 93 176 : char getCharacterAt(uint8_t index) const { return text[index] & 0x7F; } 94 : 95 : /** 96 : * @brief Copy the decimal points into the given buffer. 97 : * 98 : * @param[out] buffer 99 : * The destination to write the decimal points to. 100 : * Should have a size of at least `LENGTH` bytes. 101 : */ 102 : void getDecimalPoints(bool *buffer) const { 103 : for (uint8_t i = 0; i < LENGTH; i++) 104 : buffer[i] = getDecimalPointAt(i); 105 : } 106 : 107 : /** 108 : * @brief Get the decimal point state at the given index. 109 : * @todo Documentation. 110 : */ 111 0 : bool getDecimalPointAt(uint8_t index) const { return text[index] & 0x80; } 112 : 113 : /** 114 : * @brief Print out the text of the display to the given Print. 115 : */ 116 0 : size_t printTo(Print &printer) const override { 117 0 : size_t s = 0; 118 0 : for (uint8_t i = 0; i < LENGTH; i++) { 119 0 : s += printer.print(getCharacterAt(i)); 120 0 : if (getDecimalPointAt(i)) 121 0 : s += printer.print('.'); 122 0 : } 123 0 : return s; 124 0 : } 125 : 126 : private: 127 : char text[LENGTH]; 128 : }; 129 : 130 : } // namespace MCU 131 : 132 : END_CS_NAMESPACE