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 namespace BlocksProtocol 26 { 27 28 /** 29 Helper class for constructing a packet for sending to a BLOCKS device 30 31 @tags{Blocks} 32 */ 33 template <int maxPacketBytes> 34 struct HostPacketBuilder 35 { HostPacketBuilderHostPacketBuilder36 HostPacketBuilder() noexcept {} 37 HostPacketBuilder (const HostPacketBuilder&) = delete; 38 HostPacketBuilder (HostPacketBuilder&&) = default; 39 getDataHostPacketBuilder40 const void* getData() const noexcept { return data.getData(); } sizeHostPacketBuilder41 int size() const noexcept { return data.size(); } 42 43 //============================================================================== writePacketSysexHeaderBytesHostPacketBuilder44 void writePacketSysexHeaderBytes (TopologyIndex deviceIndex) noexcept 45 { 46 static_assert (maxPacketBytes > 10, "Not enough bytes for a sensible message!"); 47 48 jassert ((deviceIndex & 64) == 0); 49 50 data.writeHeaderSysexBytes (deviceIndex); 51 } 52 writePacketSysexFooterHostPacketBuilder53 void writePacketSysexFooter() noexcept 54 { 55 data.writePacketSysexFooter(); 56 } 57 58 //============================================================================== deviceControlMessageHostPacketBuilder59 bool deviceControlMessage (DeviceCommand command) noexcept 60 { 61 if (! data.hasCapacity ((int) MessageType::bits + (int) DeviceCommand::bits)) 62 return false; 63 64 writeMessageType (MessageFromHost::deviceCommandMessage); 65 data << command; 66 return true; 67 } 68 69 //============================================================================== beginDataChangesHostPacketBuilder70 bool beginDataChanges (PacketIndex packetIndex) noexcept 71 { 72 if (! data.hasCapacity ((int) MessageType::bits + (int) PacketIndex::bits + (int) DataChangeCommand::bits)) 73 return false; 74 75 writeMessageType (MessageFromHost::sharedDataChange); 76 data << packetIndex; 77 return true; 78 } 79 endDataChangesHostPacketBuilder80 bool endDataChanges (bool isLastChange) noexcept 81 { 82 if (! data.hasCapacity (DataChangeCommand::bits)) 83 return false; 84 85 data << DataChangeCommand ((uint32) isLastChange ? endOfChanges : endOfPacket); 86 return true; 87 } 88 skipBytesHostPacketBuilder89 bool skipBytes (int numToSkip) noexcept 90 { 91 if (numToSkip <= 0) 92 return true; 93 94 auto state = data.getState(); 95 96 while (numToSkip > ByteCountMany::maxValue) 97 { 98 if (! skipBytes (ByteCountMany::maxValue)) 99 { 100 data.restore (state); 101 return false; 102 } 103 104 numToSkip -= ByteCountMany::maxValue; 105 } 106 107 if (numToSkip > ByteCountFew::maxValue) 108 { 109 if (! data.hasCapacity (DataChangeCommand::bits * 2 + ByteCountMany::bits)) 110 { 111 data.restore (state); 112 return false; 113 } 114 115 data << DataChangeCommand ((uint32) skipBytesMany) << ByteCountMany ((uint32) numToSkip); 116 return true; 117 } 118 119 if (! data.hasCapacity (DataChangeCommand::bits * 2 + ByteCountFew::bits)) 120 { 121 data.restore (state); 122 return false; 123 } 124 125 data << DataChangeCommand ((uint32) skipBytesFew) << ByteCountFew ((uint32) numToSkip); 126 return true; 127 } 128 setMultipleBytesHostPacketBuilder129 bool setMultipleBytes (const uint8* values, int num) noexcept 130 { 131 if (num <= 0) 132 return true; 133 134 if (! data.hasCapacity (DataChangeCommand::bits * 2 + num * (1 + ByteValue::bits))) 135 return false; 136 137 data << DataChangeCommand ((uint32) setSequenceOfBytes); 138 139 for (int i = 0; i < num; ++i) 140 data << ByteValue ((uint32) values[i]) 141 << ByteSequenceContinues (i < num - 1 ? 1 : 0); 142 143 return true; 144 } 145 setMultipleBytesHostPacketBuilder146 bool setMultipleBytes (uint8 value, uint8 lastValue, int num) noexcept 147 { 148 if (num <= 0) 149 return true; 150 151 if (num == 1) 152 return setMultipleBytes (&value, 1); // (this is a more compact message) 153 154 auto state = data.getState(); 155 156 if (num > ByteCountMany::maxValue) 157 { 158 if (! setMultipleBytes (value, lastValue, ByteCountMany::maxValue)) 159 { 160 data.restore (state); 161 return false; 162 } 163 164 return setMultipleBytes (value, lastValue, num - ByteCountMany::maxValue); 165 } 166 167 if (num > ByteCountFew::maxValue) 168 { 169 if (! data.hasCapacity (DataChangeCommand::bits * 2 + ByteCountMany::bits + ByteValue::bits)) 170 { 171 data.restore (state); 172 return false; 173 } 174 175 data << DataChangeCommand ((uint32) setManyBytesWithValue) 176 << ByteCountMany ((uint32) num) 177 << ByteValue ((uint32) value); 178 179 return true; 180 } 181 182 if (value == lastValue) 183 { 184 if (! data.hasCapacity (DataChangeCommand::bits * 2 + ByteCountFew::bits)) 185 { 186 data.restore (state); 187 return false; 188 } 189 190 data << DataChangeCommand ((uint32) setFewBytesWithLastValue) << ByteCountFew ((uint32) num); 191 return true; 192 } 193 194 if (! data.hasCapacity (DataChangeCommand::bits * 2 + ByteCountFew::bits + ByteValue::bits)) 195 { 196 data.restore (state); 197 return false; 198 } 199 200 data << DataChangeCommand ((uint32) setFewBytesWithValue) << ByteCountFew ((uint32) num) 201 << ByteValue ((uint32) value); 202 203 return true; 204 } 205 addProgramEventMessageHostPacketBuilder206 bool addProgramEventMessage (const int32* messageData) 207 { 208 if (! data.hasCapacity (BitSizes::programEventMessage)) 209 return false; 210 211 writeMessageType (MessageFromHost::programEventMessage); 212 213 for (uint32 i = 0; i < numProgramMessageInts; ++i) 214 data << IntegerWithBitSize<32> ((uint32) messageData[i]); 215 216 return true; 217 } 218 addFirmwareUpdatePacketHostPacketBuilder219 bool addFirmwareUpdatePacket (const uint8* packetData, uint8 size) 220 { 221 if (! data.hasCapacity (MessageType::bits + FirmwareUpdatePacketSize::bits + 7 * size)) 222 return false; 223 224 writeMessageType (MessageFromHost::firmwareUpdatePacket); 225 data << FirmwareUpdatePacketSize (size); 226 227 for (uint8 i = 0; i < size; ++i) 228 data << IntegerWithBitSize<7> ((uint32) packetData[i]); 229 230 return true; 231 } 232 233 //============================================================================== addConfigSetMessageHostPacketBuilder234 bool addConfigSetMessage (int32 item, int32 value) 235 { 236 if (! data.hasCapacity (BitSizes::configSetMessage)) 237 return false; 238 239 writeMessageType(MessageFromHost::configMessage); 240 ConfigCommand type = ConfigCommands::setConfig; 241 data << type << IntegerWithBitSize<8> ((uint32) item) << IntegerWithBitSize<32>((uint32) value); 242 return true; 243 } 244 addRequestMessageHostPacketBuilder245 bool addRequestMessage (int32 item) 246 { 247 if (! data.hasCapacity (BitSizes::configSetMessage)) 248 return false; 249 250 writeMessageType(MessageFromHost::configMessage); 251 ConfigCommand type = ConfigCommands::requestConfig; 252 data << type << IntegerWithBitSize<32> (0) << IntegerWithBitSize<8> ((uint32) item); 253 return true; 254 } 255 addRequestFactorySyncMessageHostPacketBuilder256 bool addRequestFactorySyncMessage() 257 { 258 if (! data.hasCapacity ((int) MessageType::bits + (int) ConfigCommand::bits)) 259 return false; 260 261 writeMessageType (MessageFromHost::configMessage); 262 ConfigCommand type = ConfigCommands::requestFactorySync; 263 data << type; 264 return true; 265 } 266 addRequestUserSyncMessageHostPacketBuilder267 bool addRequestUserSyncMessage() 268 { 269 if (! data.hasCapacity ((int) MessageType::bits + (int) ConfigCommand::bits)) 270 return false; 271 272 writeMessageType (MessageFromHost::configMessage); 273 ConfigCommand type = ConfigCommands::requestUserSync; 274 data << type; 275 return true; 276 } 277 278 //============================================================================== addFactoryResetHostPacketBuilder279 bool addFactoryReset() 280 { 281 if (! data.hasCapacity (MessageType::bits)) 282 return false; 283 284 writeMessageType (MessageFromHost::factoryReset); 285 return true; 286 } 287 addBlockResetHostPacketBuilder288 bool addBlockReset() 289 { 290 if (! data.hasCapacity (MessageType::bits)) 291 return false; 292 293 writeMessageType (MessageFromHost::blockReset); 294 return true; 295 } 296 addSetBlockNameHostPacketBuilder297 bool addSetBlockName (const String& name) 298 { 299 if (name.length() > 32 || ! data.hasCapacity (MessageType::bits + 7 + (7 * name.length()))) 300 return false; 301 302 writeMessageType (MessageFromHost::setName); 303 304 data << IntegerWithBitSize<7> ((uint32) name.length()); 305 306 for (auto i = 0; i < name.length(); ++i) 307 data << IntegerWithBitSize<7> ((uint32) name.toRawUTF8()[i]); 308 309 data << IntegerWithBitSize<7> (0); 310 311 return true; 312 } 313 314 //============================================================================== 315 private: 316 Packed7BitArrayBuilder<maxPacketBytes> data; 317 writeMessageTypeHostPacketBuilder318 void writeMessageType (MessageFromHost type) noexcept 319 { 320 data << MessageType ((uint32) type); 321 } 322 }; 323 324 } // namespace BlocksProtocol 325 } // namespace juce 326