Open sucrz opened 4 years ago
I've tried A couple of things but I can get parameter name on display, here is the code I try :
-for information I test the code on arduino UNO but the final board will be a MEGA. -I send this message " 0xF0 0x77 0x48 0x65 0x6C 0x6C 0xF7 " using MIDI-OX thru loop midi and hairless-midiserial. The board receive the message (the TX led light up, and hairless-midiserial debug show the message)
#include <Encoder.h> // Include the Encoder library.
#include <Control_Surface.h> // Include the Control Surface library
#include <Display/DisplayInterfaces/DisplayInterfaceSSD1306.hpp>
HairlessMIDI_Interface midi;
//USBMIDI_Interface midi;
constexpr uint8_t SCREEN_WIDTH = 128;
constexpr uint8_t SCREEN_HEIGHT = 32;
constexpr int8_t OLED_RESET = -1;
Adafruit_SSD1306 ssd1306Display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
class MySSD1306_DisplayInterface : public SSD1306_DisplayInterface {
public:
MySSD1306_DisplayInterface(Adafruit_SSD1306 &display)
: SSD1306_DisplayInterface(display) {}
void begin() override {
// Initialize the Adafruit_SSD1306 display
if (!disp.begin())
FATAL_ERROR(F("SSD1306 allocation failed."), 0x1306);
// If you override the begin method, remember to call the super class method
SSD1306_DisplayInterface::begin();
}
void drawBackground() override {}
} display = ssd1306Display;
void display_max7219(uint8_t msg[]) {
if (msg[1] != 0x77) return; // check for desired manufacturer code
char txt[5]; // array for the number as char array
for (int i = 0; i < strlen(msg); i++)
{
txt[i] = int8_t(msg[i + 3]); // convert uint8_t sysex to int8_t char
display.setTextColor(WHITE);
display.setTextSize(2);
display.setCursor(0, 18);
display.print(txt[i]);
}
}
// sysex example message : 0xF0 0x77 0x48 0x65 0x6C 0x6C 0xF7
bool sysExMessageCallback(SysExMessage se) {
display_max7219(se.data); // pass the data to MAX7219 function
return true; // Return true to indicate that handling is done,
// and Control_Surface shouldn't handle it anymore.
// If you want Control_Surface to handle it as well,
// return false;
}
Bank<4> bank(1); // Create a new bank with two tracks per bank
IncrementDecrementSelector<4> bankselector = {bank, {A0, A1}, Wrap::Wrap};
BankDisplay bankDisp[] = {{display, bank, 1, {0, 0}, 2, WHITE}};
//textDisplay textDisp[] = {{display, {0x48, 0x65, 0x6C, 0x6C, 0x6f}, {0, 18}, 2, WHITE}};
//wordDisplay wordDisp[] = {{display, 0x48, 0x65, 0x6C, 0x6C, {0, 18}, 2, 12, WHITE}};
void setup() {
//midi.begin();
Control_Surface.begin();
Control_Surface.setMIDIInputCallbacks(nullptr, //
sysExMessageCallback, //
nullptr); //
}
void loop() {
Control_Surface.loop(); // Refresh all elements
//midi.update();
}
strlen(msg)
will not work. strlen
keeps on counting until it encounters a null character, but your message doesn't contain a null character. The number that strlen
returns is unknowable (because you're invoking undefined behavior), but it's most likely greater than 5, the length of your buffer. That means that the for loop will write out of bounds to your buffer txt
, most likely crashing your program.
Some other remarks: you aren't terminating your txt
buffer with a null character, so it's not a proper string that can be printed. char
and int8_t
are distinct data types, don't use it to convert from uint8_t
to char
.
I'd highly recommend starting with a much simpler program. Don't print to the display, print to the Serial monitor. Don't use Hairless, because it disables the Serial monitor, use the debug MIDI interface first. Once that's all working, you can start adding the display, and finally replace the debug interface with Hairless.
#include <Control_Surface.h> // Include the Control Surface library
#include <AH/STL/vector> // std::vector
#include <AH/STL/algorithm> // std::copy
USBDebugMIDI_Interface midi;
// sysex example message : F0 77 48 65 6C 6C 6F F7
// H e l l o
bool sysExMessageCallback(SysExMessage se) {
if (se.length < 3) // Ensure that the message is long enough
return false;
if (se.data[1] != 0x77) // Check for desired manufacturer code
return false;
// Get the length of the text message and limit it to 32 characters
auto length = se.length - 3;
length = constrain(length, 0, 32);
// Allocate memory for the text + null terminator
std::vector<char> text(length + 1);
// Copy the text from the message
const uint8_t text_start = se.data + 2;
std::copy(text_start, text_start + length, std::begin(text));
text.back() = '\0'; // properly terminate the string
Serial.println(text.data()); // print it
return true; // Return true to indicate that handling is done,
// and Control_Surface shouldn't handle it anymore.
// If you want Control_Surface to handle it as well,
// return false;
}
void setup() {
Control_Surface.begin();
Control_Surface.setMIDIInputCallbacks(nullptr, //
sysExMessageCallback, //
nullptr); //
}
void loop() {
Control_Surface.loop();
}
Try uploading this sketch, then open the serial monitor, and send the following text:
F0 77 48 65 6C 6C 6F F7
It should print Hello
.
Thanks for the reply,
I've tried to compile the sketch but I have a error message for the line :
std::copy(text_start, text_start + length, std::begin(text));
A get this message :
no matching function for call to 'copy(const uint8_t&, int, std::vector<char>::iterator)'
My apologies, I made a copy-paste mistake, there should be an asterisk here:
const uint8_t *text_start = se.data + 2;
Thanks for the quick reply, it works well!
I've try to display on the screen but it doesn't work any idea ?
#include <Control_Surface.h> // Include the Control Surface library
#include <AH/STL/vector> // std::vector
#include <AH/STL/algorithm> // std::copy
#include <Display/DisplayInterfaces/DisplayInterfaceSSD1306.hpp>
USBDebugMIDI_Interface midi;
//OLED
constexpr uint8_t SCREEN_WIDTH = 128;
constexpr uint8_t SCREEN_HEIGHT = 32;
constexpr int8_t OLED_RESET = -1;
//OLED END
Adafruit_SSD1306 ssd1306Display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
class MySSD1306_DisplayInterface : public SSD1306_DisplayInterface {
public:
MySSD1306_DisplayInterface(Adafruit_SSD1306 &display)
: SSD1306_DisplayInterface(display) {}
void begin() override {
// Initialize the Adafruit_SSD1306 display
if (!disp.begin())
FATAL_ERROR(F("SSD1306 allocation failed."), 0x1306);
// If you override the begin method, remember to call the super class method
SSD1306_DisplayInterface::begin();
}
void drawBackground() override {}
} display = ssd1306Display;
// sysex example message : F0 77 48 65 6C 6C 6F F7
// H e l l o
bool sysExMessageCallback(SysExMessage se) {
if (se.length < 3) // Ensure that the message is long enough
return false;
if (se.data[1] != 0x77) // Check for desired manufacturer code
return false;
// Get the length of the text message and limit it to 32 characters
auto length = se.length - 3;
length = constrain(length, 0, 32);
// Allocate memory for the text + null terminator
std::vector<char> text(length + 1);
// Copy the text from the message
const uint8_t *text_start = se.data + 2;
std::copy(text_start, text_start + length, std::begin(text));
text.back() = '\0'; // properly terminate the string
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 10);
display.println(text.data());
Serial.println(text.data()); // print it
return true; // Return true to indicate that handling is done,
// and Control_Surface shouldn't handle it anymore.
// If you want Control_Surface to handle it as well,
// return false;
}
void setup() {
Control_Surface.begin();
Control_Surface.setMIDIInputCallbacks(nullptr, //
sysExMessageCallback, //
nullptr); //
}
void loop() {
Control_Surface.loop();
}
Hi,
I've tested everything I can this past 3days to get the message print on the OLED screen without luck. I obviously missing something but with my knowledge on arduino I can't undestrand why it doesn't work.
Can someone explain to me how to print the message on the display or at least give me some leads?
You're never actually writing the data to the display. You have to call display.display()
.
If you want to manage the display yourself, you have to use the Adafruit_SSD1306
display directly, don't create a SSD1306_DisplayInterface
with it because then Control Surface will take over control, and you can only use Display Elements to draw to the display.
The following works for me:
#include <Control_Surface.h> // Include the Control Surface library
#include <AH/STL/vector> // std::vector
#include <AH/STL/algorithm> // std::copy
#include <Adafruit_SSD1306.h>
#include <Wire.h>
USBDebugMIDI_Interface midi;
constexpr uint8_t SCREEN_WIDTH = 128;
constexpr uint8_t SCREEN_HEIGHT = 64;
constexpr int8_t OLED_RESET = -1;
Adafruit_SSD1306 display = {SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET};
// sysex example message : F0 77 48 65 6C 6C 6F F7
// H e l l o
bool sysExMessageCallback(SysExMessage se) {
if (se.length < 3) // Ensure that the message is long enough
return false;
if (se.data[1] != 0x77) // Check for desired manufacturer code
return false;
// Get the length of the text message and limit it to 32 characters
auto length = se.length - 3;
length = constrain(length, 0, 32);
// Allocate memory for the text + null terminator
std::vector<char> text(length + 1);
// Copy the text from the message
const uint8_t *text_start = se.data + 2;
std::copy(text_start, text_start + length, std::begin(text));
text.back() = '\0'; // properly terminate the string
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 10);
display.println(text.data());
display.display();
Serial.println(text.data()); // print it
return true; // Return true to indicate that handling is done,
// and Control_Surface shouldn't handle it anymore.
// If you want Control_Surface to handle it as well,
// return false;
}
void setup() {
// Initialize the Adafruit_SSD1306 display
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))
FATAL_ERROR(F("SSD1306 allocation failed."), 0x1306);
Control_Surface.begin();
Control_Surface.setMIDIInputCallbacks(nullptr, //
sysExMessageCallback, //
nullptr); //
}
void loop() {
Control_Surface.loop();
}
Be sure to select the right I²C address and display dimensions.
Thanks a lot!
I had to add a "custom selector callback" to display the banks but it works well even with the hairless interface.
Hi,
I would like to display sysex message on SSD1306 oled display.
The idea is to send the name and value of a parameter thru sysex and display it on the screen.
Honestly I dont know where to start maybe you can give me some leads.
I'm plan to send sysex from "Max for Live" device from ableton so I can create the sysex message I want (In the limit of what allow sysex)