summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFred Sundvik <fsundvik@gmail.com>2016-12-29 12:13:30 +0200
committerFred Sundvik <fsundvik@gmail.com>2016-12-29 12:13:30 +0200
commitdd685eceb2045371d38f24d454f1ab08ca7416f4 (patch)
treeeef012131a9ce190512a899d4850e34741989a26
parent273faa4d9cd5a84207548f83ba550c9efee90933 (diff)
API Sysex fixes
Fix memory leaks by using stack instead of malloc Reduce memory usage by having less temporary bufffers Remove warnings by adding includes Decrease code size by 608 bytes (mostly due to not linking malloc) More robust handling of buffer overflows
-rw-r--r--quantum/api/api_sysex.c60
-rw-r--r--quantum/config_common.h2
-rw-r--r--tmk_core/protocol/lufa/lufa.c32
-rw-r--r--tmk_core/protocol/lufa/lufa.h4
4 files changed, 71 insertions, 27 deletions
diff --git a/quantum/api/api_sysex.c b/quantum/api/api_sysex.c
index a4a554e764..868f854b92 100644
--- a/quantum/api/api_sysex.c
+++ b/quantum/api/api_sysex.c
@@ -1,4 +1,6 @@
#include "api_sysex.h"
+#include "sysex_tools.h"
+#include "print.h"
void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t * bytes, uint16_t length) {
// SEND_STRING("\nTX: ");
@@ -6,24 +8,50 @@ void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t * bytes,
// send_byte(bytes[i]);
// SEND_STRING(" ");
// }
- uint8_t * precode = malloc(sizeof(uint8_t) * (length + 2));
- precode[0] = message_type;
- precode[1] = data_type;
- memcpy(precode + 2, bytes, length);
- uint8_t * encoded = malloc(sizeof(uint8_t) * (sysex_encoded_length(length + 2)));
- uint16_t encoded_length = sysex_encode(encoded, precode, length + 2);
- uint8_t * array = malloc(sizeof(uint8_t) * (encoded_length + 5));
- array[0] = 0xF0;
- array[1] = 0x00;
- array[2] = 0x00;
- array[3] = 0x00;
- array[encoded_length + 4] = 0xF7;
- memcpy(array + 4, encoded, encoded_length);
- midi_send_array(&midi_device, encoded_length + 5, array);
+ if (length > API_SYSEX_MAX_SIZE) {
+ xprintf("Sysex msg too big %d %d %d", message_type, data_type, length);
+ return;
+ }
+
+
+ // The buffer size required is calculated as the following
+ // API_SYSEX_MAX_SIZE is the maximum length
+ // In addition to that we have a two byte message header consisting of the message_type and data_type
+ // This has to be encoded with an additional overhead of one byte for every starting 7 bytes
+ // We just add one extra byte in case it's not divisible by 7
+ // Then we have an unencoded header consisting of 4 bytes
+ // Plus a one byte terminator
+ const unsigned message_header = 2;
+ const unsigned unencoded_message = API_SYSEX_MAX_SIZE + message_header;
+ const unsigned encoding_overhead = unencoded_message / 7 + 1;
+ const unsigned encoded_size = unencoded_message + encoding_overhead;
+ const unsigned unencoded_header = 4;
+ const unsigned terminator = 1;
+ const unsigned buffer_size = encoded_size + unencoded_header + terminator;
+ uint8_t buffer[encoded_size + unencoded_header + terminator];
+ // The unencoded header
+ buffer[0] = 0xF0;
+ buffer[1] = 0x00;
+ buffer[2] = 0x00;
+ buffer[3] = 0x00;
+
+ // We copy the message to the end of the array, this way we can do an inplace encoding, using the same
+ // buffer for both input and output
+ const unsigned message_size = length + message_header;
+ uint8_t* unencoded_start = buffer + buffer_size - message_size;
+ uint8_t* ptr = unencoded_start;
+ *(ptr++) = message_type;
+ *(ptr++) = data_type;
+ memcpy(ptr, bytes, length);
+
+ unsigned encoded_length = sysex_encode(buffer + unencoded_header, unencoded_start, message_size);
+ unsigned final_size = unencoded_header + encoded_length + terminator;
+ buffer[final_size - 1] = 0xF7;
+ midi_send_array(&midi_device, final_size, buffer);
// SEND_STRING("\nTD: ");
// for (uint8_t i = 0; i < encoded_length + 5; i++) {
- // send_byte(array[i]);
+ // send_byte(buffer[i]);
// SEND_STRING(" ");
// }
-} \ No newline at end of file
+}
diff --git a/quantum/config_common.h b/quantum/config_common.h
index 17c11faeb6..4bdb2065d9 100644
--- a/quantum/config_common.h
+++ b/quantum/config_common.h
@@ -80,4 +80,6 @@
# endif
#endif
+#define API_SYSEX_MAX_SIZE 32
+
#endif
diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c
index 0971897706..6dd5959dc4 100644
--- a/tmk_core/protocol/lufa/lufa.c
+++ b/tmk_core/protocol/lufa/lufa.c
@@ -1252,28 +1252,40 @@ void cc_callback(MidiDevice * device,
// midi_send_cc(device, (chan + 1) % 16, num, val);
}
+#ifdef API_SYSEX_ENABLE
uint8_t midi_buffer[MIDI_SYSEX_BUFFER] = {0};
+#endif
void sysex_callback(MidiDevice * device, uint16_t start, uint8_t length, uint8_t * data) {
#ifdef API_SYSEX_ENABLE
// SEND_STRING("\n");
// send_word(start);
// SEND_STRING(": ");
+ // Don't store the header
+ int16_t pos = start - 4;
for (uint8_t place = 0; place < length; place++) {
// send_byte(*data);
- midi_buffer[start + place] = *data;
- if (*data == 0xF7) {
- // SEND_STRING("\nRD: ");
- // for (uint8_t i = 0; i < start + place + 1; i++){
- // send_byte(midi_buffer[i]);
- // SEND_STRING(" ");
- // }
- uint8_t * decoded = malloc(sizeof(uint8_t) * (sysex_decoded_length(start + place - 4)));
- uint16_t decode_length = sysex_decode(decoded, midi_buffer + 4, start + place - 4);
- process_api(decode_length, decoded);
+ if (pos >= 0) {
+ if (*data == 0xF7) {
+ // SEND_STRING("\nRD: ");
+ // for (uint8_t i = 0; i < start + place + 1; i++){
+ // send_byte(midi_buffer[i]);
+ // SEND_STRING(" ");
+ // }
+ const unsigned decoded_length = sysex_decoded_length(pos);
+ uint8_t decoded[API_SYSEX_MAX_SIZE];
+ sysex_decode(decoded, midi_buffer, pos);
+ process_api(decoded_length, decoded);
+ return;
+ }
+ else if (pos >= MIDI_SYSEX_BUFFER) {
+ return;
+ }
+ midi_buffer[pos] = *data;
}
// SEND_STRING(" ");
data++;
+ pos++;
}
#endif
}
diff --git a/tmk_core/protocol/lufa/lufa.h b/tmk_core/protocol/lufa/lufa.h
index b11854101d..a049fd43c9 100644
--- a/tmk_core/protocol/lufa/lufa.h
+++ b/tmk_core/protocol/lufa/lufa.h
@@ -70,7 +70,6 @@ typedef struct {
#ifdef MIDI_ENABLE
void MIDI_Task(void);
MidiDevice midi_device;
- #define MIDI_SYSEX_BUFFER 32
#endif
#ifdef API_ENABLE
@@ -79,6 +78,9 @@ typedef struct {
#ifdef API_SYSEX_ENABLE
#include "api_sysex.h"
+ // Allocate space for encoding overhead.
+ //The header and terminator are not stored to save a few bytes of precious ram
+ #define MIDI_SYSEX_BUFFER (API_SYSEX_MAX_SIZE + API_SYSEX_MAX_SIZE / 7 + (API_SYSEX_MAX_SIZE % 7 ? 1 : 0))
#endif
// #if LUFA_VERSION_INTEGER < 0x120730