Control Surface main
MIDI Control Surface library for Arduino
Loading...
Searching...
No Matches
LCD.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <AH/Debug/Debug.hpp>
6#include <string.h> // memcpy
7
8#ifndef ARDUINO
9#include <cassert>
10#endif
11
13
14using AH::max;
15using AH::min;
16
17namespace MCU {
18
23 public:
26
27 static uint8_t getInstances() { return instances; }
28
29 private:
30 static uint8_t instances;
31};
50template <uint8_t BufferSize = 112>
51class LCD : public MIDIInputElementSysEx, private LCDCounter {
52 public:
62 LCD(uint8_t offset = 0, Cable cable = Cable_1)
64 // Null-terminate the buffer
65 buffer[BufferSize] = '\0';
66 // Fill the buffer with spaces
67 for (uint8_t i = 0; i < BufferSize; i++) buffer[i] = ' ';
68 }
69
70 protected:
71 bool updateWith(SysExMessage midimsg) override {
72 // If this message is meant for a different cable than ours, return:
73 if (midimsg.getCable() != this->cable)
74 return false;
75
76 // We can't handle chunked SysEx data (yet), and it wouldn't make a ton
77 // of sense, since the default SysEx buffer size is the same size as the
78 // SysEx message we expect, so it shouldn't arrive in chunks.
79 if (!midimsg.isCompleteMessage())
80 return false;
81
82 // Format:
83 // F0 mm mm mm nn 12 oo yy... F7
84 // mm = manufacturer ID (00 00 66 for Mackie)
85 // nn = model number (10 for Logic Control, 11 for Logic Control XT)
86 // oo = offset [0x00, 0x6F]
87 // yy... = ASCII data
88 if (midimsg.data[5] != 0x12)
89 return false;
90
91 const uint8_t midiOffset = midimsg.data[6];
92 const uint8_t midiLength = midimsg.length - 8;
93 const uint8_t *text = midimsg.data + 7;
94 const uint8_t midiBufferEnd = midiOffset + midiLength;
95
96 const uint8_t bufferEnd = this->offset + BufferSize;
97
98 // If there's no overlap between incoming range and the range that we're
99 // listening for, return:
100 if (midiOffset >= bufferEnd || this->offset >= midiBufferEnd)
101 // If there are other instances, maybe it'll match one of those,
102 // otherwise, stop handling this message:
103 return getInstances() == 1;
104
105 // Find the ranges that overlap between the text data in the message
106 // (src) and the range of characters we're listening for (dst):
107 uint8_t srcStart = max(0, this->offset - midiOffset);
108 uint8_t dstStart = max(0, midiOffset - this->offset);
109 uint8_t length = midiBufferEnd - midiOffset -
110 max(0, this->offset - midiOffset) -
111 max(0, midiBufferEnd - bufferEnd);
112
113 // Copy the interesting part to our buffer:
114#ifdef ARDUINO
115 memcpy(&buffer[dstStart], &text[srcStart], length);
116#else // Tests
117 for (uint8_t i = 0; i < length; ++i) {
118 buffer[dstStart + i] = text[srcStart + i];
119 assert(dstStart + i < BufferSize);
120 assert(srcStart + i < midiLength);
121 }
122#endif
123
124 markDirty();
125
126 // If this is the only instance, the others don't have to be updated
127 // anymore, so we return true to break the loop:
128 return getInstances() == 1;
129 }
130
131 public:
132 void begin() override { markDirty(); }
133
136
138 const char *getText() const { return buffer.data; }
139
141
144
148 bool getDirty() const { return dirty > 0; }
150 void clearDirty() {
151 if (dirty > 0)
152 --dirty;
153 }
158
160
161 private:
163 uint8_t offset;
165 uint8_t dirty = 0;
166 uint8_t num_subscribers = 0;
167};
168
169} // namespace MCU
170
constexpr Cable Cable_1
Definition Cable.hpp:118
#define END_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
A type-safe class for MIDI USB Cable numbers.
Definition Cable.hpp:13
Counts the number of instances of the LCD class.
Definition LCD.hpp:22
static uint8_t getInstances()
Definition LCD.hpp:27
static uint8_t instances
Definition LCD.hpp:30
A class that represents the Mackie Control Universal LCD display and saves the text it receives.
Definition LCD.hpp:51
const char * getText() const
Get a pointer to the null-terminated display text.
Definition LCD.hpp:138
void markDirty()
Set the dirty counter to the number of subscribers (or one).
Definition LCD.hpp:155
void removeSubscriber()
Definition LCD.hpp:157
void addSubscriber()
Definition LCD.hpp:156
bool getDirty() const
Check if the text was updated since the last time the dirty flag was cleared.
Definition LCD.hpp:148
void begin() override
Initialize the input element.
Definition LCD.hpp:132
LCD(uint8_t offset=0, Cable cable=Cable_1)
Definition LCD.hpp:62
Cable cable
Definition LCD.hpp:164
uint8_t offset
Definition LCD.hpp:163
uint8_t num_subscribers
Definition LCD.hpp:166
Array< char, BufferSize+1 > buffer
Definition LCD.hpp:162
uint8_t dirty
Definition LCD.hpp:165
bool updateWith(SysExMessage midimsg) override
Definition LCD.hpp:71
void clearDirty()
Clear the dirty flag.
Definition LCD.hpp:150
A class for objects that listen for incoming MIDI events.
constexpr auto min(const T &a, const U &b) -> decltype(b< a ? b :a)
Return the smaller of two numbers/objects.
Definition MinMaxFix.hpp:12
constexpr auto max(const T &a, const U &b) -> decltype(a< b ? b :a)
Return the larger of two numbers/objects.
Definition MinMaxFix.hpp:19
An array wrapper for easy copying, comparing, and iterating.
Definition Array.hpp:32
const uint8_t * data
Cable getCable() const
Get the MIDI USB cable number of the message.
bool isCompleteMessage() const