1 /* 2 ============================================================================== 3 4 This file is part of the JUCE library. 5 Copyright (c) 2020 - Raw Material Software Limited 6 7 JUCE is an open source library subject to commercial or open-source 8 licensing. 9 10 The code included in this file is provided under the terms of the ISC license 11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission 12 To use, copy, modify, and/or distribute this software for any purpose with or 13 without fee is hereby granted provided that the above copyright notice and 14 this permission notice appear in all copies. 15 16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER 17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE 18 DISCLAIMED. 19 20 ============================================================================== 21 */ 22 23 namespace juce 24 { 25 class BlockSerialReader 26 : private MIDIDeviceConnection::Listener, 27 private Timer 28 { 29 public: 30 //============================================================================== BlockSerialReader(MIDIDeviceConnection & deviceConnectionToUse)31 BlockSerialReader (MIDIDeviceConnection& deviceConnectionToUse) : deviceConnection (deviceConnectionToUse) 32 { 33 deviceConnection.addListener (this); 34 startTimer (10); 35 } 36 ~BlockSerialReader()37 ~BlockSerialReader() override 38 { 39 deviceConnection.removeListener (this); 40 } 41 hasSerial() const42 bool hasSerial() const { return serial.isNotEmpty(); } 43 getSerial() const44 String getSerial() const { return serial; } 45 46 private: 47 MIDIDeviceConnection& deviceConnection; 48 String serial; 49 shouldStop()50 bool shouldStop() { return hasSerial(); } 51 52 //============================================================================== timerCallback()53 void timerCallback() override 54 { 55 if (shouldStop()) 56 { 57 stopTimer(); 58 return; 59 } 60 61 sendRequest(); 62 startTimer (300); 63 } 64 sendRequest()65 void sendRequest() 66 { 67 const uint8 dumpRequest[] = { 0xf0, 0x00, 0x21, 0x10, 0x78, 0x3f, 0xf7 }; 68 deviceConnection.sendMessageToDevice (dumpRequest, sizeof (dumpRequest)); 69 } 70 handleIncomingMidiMessage(const MidiMessage & message)71 void handleIncomingMidiMessage (const MidiMessage& message) override 72 { 73 if (hasSerial()) 74 return; 75 76 if (isResponse (message)) 77 parseResponse (message); 78 } 79 connectionBeingDeleted(const MIDIDeviceConnection &)80 void connectionBeingDeleted (const MIDIDeviceConnection&) override 81 { 82 stopTimer(); 83 } 84 isResponse(const MidiMessage message)85 bool isResponse (const MidiMessage message) 86 { 87 const uint8 roliDumpHeader[] = { 0xf0, 0x00, 0x21, 0x10, 0x78}; 88 return memcmp (message.getRawData(), roliDumpHeader, sizeof (roliDumpHeader)) == 0; 89 } 90 parseResponse(const MidiMessage & message)91 void parseResponse (const MidiMessage& message) 92 { 93 int index = findMacAddressStart (message); 94 95 if (index >= 0) 96 { 97 const int macSize = 17; 98 const int offset = index + macSize; 99 const int serialSize = 16; 100 101 if (message.getRawDataSize() - offset < serialSize) 102 { 103 jassertfalse; 104 return; 105 } 106 107 serial = String ((const char*)message.getRawData() + offset, serialSize); 108 } 109 } 110 findMacAddressStart(const MidiMessage & message)111 int findMacAddressStart (const MidiMessage& message) 112 { 113 const uint8 macStart[] = { '4', '8', ':', 'B', '6', ':', '2', '0', ':' }; 114 return findSequence (macStart, sizeof (macStart), message); 115 } 116 findSequence(const uint8 * sequence,int sequenceSize,const MidiMessage & message)117 int findSequence (const uint8* sequence, int sequenceSize, const MidiMessage& message) 118 { 119 for (int i = 0; i < message.getRawDataSize() - sequenceSize; i++) 120 { 121 if (memcmp (message.getRawData() + i, sequence, size_t (sequenceSize)) == 0) 122 return i; 123 } 124 125 return -1; 126 } 127 128 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BlockSerialReader) 129 }; 130 } 131