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 /** This value is incremented when the format of the API changes in a way which 29 breaks compatibility. 30 */ 31 static constexpr uint32 currentProtocolVersion = 1; 32 33 using ProtocolVersion = IntegerWithBitSize<8>; 34 35 //============================================================================== 36 /** A timestamp for a packet, in milliseconds since device boot-up */ 37 using PacketTimestamp = IntegerWithBitSize<32>; 38 39 /** This relative timestamp is for use inside a packet, and it represents a 40 number of milliseconds that should be added to the packet's timestamp. 41 */ 42 using PacketTimestampOffset = IntegerWithBitSize<5>; 43 44 45 //============================================================================== 46 /** Messages that a device may send to the host. */ 47 enum class MessageFromDevice 48 { 49 deviceTopology = 0x01, 50 packetACK = 0x02, 51 firmwareUpdateACK = 0x03, 52 deviceTopologyExtend = 0x04, 53 deviceTopologyEnd = 0x05, 54 deviceVersion = 0x06, 55 deviceName = 0x07, 56 57 touchStart = 0x10, 58 touchMove = 0x11, 59 touchEnd = 0x12, 60 61 touchStartWithVelocity = 0x13, 62 touchMoveWithVelocity = 0x14, 63 touchEndWithVelocity = 0x15, 64 65 configMessage = 0x18, 66 67 controlButtonDown = 0x20, 68 controlButtonUp = 0x21, 69 70 programEventMessage = 0x28, 71 72 logMessage = 0x30 73 }; 74 75 /** Messages that the host may send to a device. */ 76 enum class MessageFromHost 77 { 78 deviceCommandMessage = 0x01, 79 sharedDataChange = 0x02, 80 programEventMessage = 0x03, 81 firmwareUpdatePacket = 0x04, 82 83 configMessage = 0x10, 84 factoryReset = 0x11, 85 blockReset = 0x12, 86 87 setName = 0x20 88 }; 89 90 /** Messages that the host may send to a device that do not have the usual message format */ 91 namespace SpecialMessageFromHost 92 { 93 constexpr uint8 resetMaster[6] = { 0xf0, 0x00, 0x21, 0x10, 0x49, 0xf7 }; 94 } 95 96 /** This is the first item in a BLOCKS message, identifying the message type. */ 97 using MessageType = IntegerWithBitSize<7>; 98 99 //============================================================================== 100 /** This is a type of index identifier used to refer to a block within a group. 101 It refers to the index of a device in the list of devices that was most recently 102 sent via a topology change message 103 (It's not a global UID for a block unit). 104 NB: to send a message to all devices, pass the getDeviceIndexForBroadcast() value. 105 */ 106 using TopologyIndex = uint8; 107 108 static constexpr int topologyIndexBits = 7; 109 110 /** Use this value as the index if you want a message to be sent to all devices in 111 the group. 112 */ 113 static constexpr TopologyIndex topologyIndexForBroadcast = 63; 114 115 using DeviceCount = IntegerWithBitSize<7>; 116 using ConnectionCount = IntegerWithBitSize<8>; 117 118 //============================================================================== 119 /** Battery charge level. */ 120 using BatteryLevel = IntegerWithBitSize<5>; 121 122 /** Battery charger connection flag. */ 123 using BatteryCharging = IntegerWithBitSize<1>; 124 125 //============================================================================== 126 /** ConnectorPort is an index, starting at 0 for the leftmost port on the 127 top edge, and going clockwise. 128 */ 129 using ConnectorPort = IntegerWithBitSize<5>; 130 131 //============================================================================== 132 /** Structure for generic block data 133 134 @tags{Blocks} 135 */ 136 template <size_t MaxSize> 137 struct BlockStringData 138 { 139 uint8 data[MaxSize] = {}; 140 uint8 length = 0; 141 142 static const size_t maxLength { MaxSize }; 143 isNotEmptyBlockStringData144 bool isNotEmpty() const 145 { 146 return length > 0; 147 } 148 asStringBlockStringData149 String asString() const 150 { 151 return String ((const char*) data, length); 152 } 153 154 bool operator== (const BlockStringData& other) const 155 { 156 if (length != other.length) 157 return false; 158 159 for (int i = 0; i < length; ++i) 160 if (data[i] != other.data[i]) 161 return false; 162 163 return true; 164 } 165 166 bool operator!= (const BlockStringData& other) const 167 { 168 return ! ( *this == other ); 169 } 170 }; 171 172 using VersionNumber = BlockStringData<21>; 173 using BlockName = BlockStringData<33>; 174 175 //============================================================================== 176 /** Structure describing a block's serial number 177 178 @tags{Blocks} 179 */ 180 struct BlockSerialNumber : public BlockStringData<16> 181 { isValidBlockSerialNumber182 bool isValid() const noexcept 183 { 184 for (auto c : data) 185 if (c == 0) 186 return false; 187 188 return isAnyControlBlock() || isPadBlock() || isSeaboardBlock() || isLumiKeysBlock(); 189 } 190 isPadBlockBlockSerialNumber191 bool isPadBlock() const noexcept { return hasPrefix ("LPB") || hasPrefix ("LPM"); } isLiveBlockBlockSerialNumber192 bool isLiveBlock() const noexcept { return hasPrefix ("LIC"); } isLoopBlockBlockSerialNumber193 bool isLoopBlock() const noexcept { return hasPrefix ("LOC"); } isDevCtrlBlockBlockSerialNumber194 bool isDevCtrlBlock() const noexcept { return hasPrefix ("DCB"); } isTouchBlockBlockSerialNumber195 bool isTouchBlock() const noexcept { return hasPrefix ("TCB"); } isSeaboardBlockBlockSerialNumber196 bool isSeaboardBlock() const noexcept { return hasPrefix ("SBB"); } isLumiKeysBlockBlockSerialNumber197 bool isLumiKeysBlock() const noexcept { return hasPrefix ("LKB"); } 198 isAnyControlBlockBlockSerialNumber199 bool isAnyControlBlock() const noexcept { return isLiveBlock() || isLoopBlock() || isDevCtrlBlock() || isTouchBlock(); } 200 hasPrefixBlockSerialNumber201 bool hasPrefix (const char* prefix) const noexcept { return memcmp (data, prefix, 3) == 0; } 202 }; 203 204 //============================================================================== 205 /** Structure for the device status 206 207 @tags{Blocks} 208 */ 209 struct DeviceStatus 210 { 211 BlockSerialNumber serialNumber; 212 TopologyIndex index; 213 BatteryLevel batteryLevel; 214 BatteryCharging batteryCharging; 215 }; 216 217 //============================================================================== 218 /** Structure for the device connection 219 220 @tags{Blocks} 221 */ 222 struct DeviceConnection 223 { 224 TopologyIndex device1, device2; 225 ConnectorPort port1, port2; 226 227 bool operator== (const DeviceConnection& other) const 228 { 229 return isEqual (other); 230 } 231 232 bool operator!= (const DeviceConnection& other) const 233 { 234 return ! isEqual (other); 235 } 236 237 private: isEqualDeviceConnection238 bool isEqual (const DeviceConnection& other) const 239 { 240 return device1 == other.device1 241 && device2 == other.device2 242 && port1 == other.port1 243 && port2 == other.port2; 244 } 245 }; 246 247 //============================================================================== 248 /** Structure for the device version 249 250 @tags{Blocks} 251 */ 252 struct DeviceVersion 253 { 254 TopologyIndex index; 255 VersionNumber version; 256 }; 257 258 //============================================================================== 259 /** Structure used for the device name 260 261 @tags{Blocks} 262 */ 263 struct DeviceName 264 { 265 TopologyIndex index; 266 BlockName name; 267 }; 268 269 static constexpr uint8 maxBlocksInTopologyPacket = 6; 270 static constexpr uint8 maxConnectionsInTopologyPacket = 24; 271 272 //============================================================================== 273 /** Configuration Item Identifiers. */ 274 enum ConfigItemId 275 { 276 // MIDI 277 midiStartChannel = 0, 278 midiEndChannel = 1, 279 midiUseMPE = 2, 280 pitchBendRange = 3, 281 octave = 4, 282 transpose = 5, 283 slideCC = 6, 284 slideMode = 7, 285 octaveTopology = 8, 286 midiChannelRange = 9, 287 MPEZone = 40, 288 // Touch 289 velocitySensitivity = 10, 290 glideSensitivity = 11, 291 slideSensitivity = 12, 292 pressureSensitivity = 13, 293 liftSensitivity = 14, 294 fixedVelocity = 15, 295 fixedVelocityValue = 16, 296 pianoMode = 17, 297 glideLock = 18, 298 glideLockEnable = 19, 299 // Live 300 mode = 20, 301 volume = 21, 302 scale = 22, 303 hideMode = 23, 304 chord = 24, 305 arpPattern = 25, 306 tempo = 26, 307 key = 27, 308 autoTransposeToKey = 28, 309 // Tracking 310 xTrackingMode = 30, 311 yTrackingMode = 31, 312 zTrackingMode = 32, 313 // Graphics 314 gammaCorrection = 33, 315 globalKeyColour = 34, 316 rootKeyColour = 35, 317 brightness = 36, 318 // User 319 user0 = 64, 320 user1 = 65, 321 user2 = 66, 322 user3 = 67, 323 user4 = 68, 324 user5 = 69, 325 user6 = 70, 326 user7 = 71, 327 user8 = 72, 328 user9 = 73, 329 user10 = 74, 330 user11 = 75, 331 user12 = 76, 332 user13 = 77, 333 user14 = 78, 334 user15 = 79, 335 user16 = 80, 336 user17 = 81, 337 user18 = 82, 338 user19 = 83, 339 user20 = 84, 340 user21 = 85, 341 user22 = 86, 342 user23 = 87, 343 user24 = 88, 344 user25 = 89, 345 user26 = 90, 346 user27 = 91, 347 user28 = 92, 348 user29 = 93, 349 user30 = 94, 350 user31 = 95 351 }; 352 353 static constexpr uint8 numberOfUserConfigs = 32; 354 static constexpr uint8 maxConfigIndex = uint8 (ConfigItemId::user0) + numberOfUserConfigs; 355 356 static constexpr uint8 configUserConfigNameLength = 32; 357 static constexpr uint8 configMaxOptions = 16; 358 static constexpr uint8 configOptionNameLength = 16; 359 360 //============================================================================== 361 /** The coordinates of a touch. 362 363 @tags{Blocks} 364 */ 365 struct TouchPosition 366 { 367 using Xcoord = IntegerWithBitSize<12>; 368 using Ycoord = IntegerWithBitSize<12>; 369 using Zcoord = IntegerWithBitSize<8>; 370 371 Xcoord x; 372 Ycoord y; 373 Zcoord z; 374 375 enum { bits = Xcoord::bits + Ycoord::bits + Zcoord::bits }; 376 }; 377 378 /** The velocities for each dimension of a touch. 379 380 @tags{Blocks} 381 */ 382 struct TouchVelocity 383 { 384 using VXcoord = IntegerWithBitSize<8>; 385 using VYcoord = IntegerWithBitSize<8>; 386 using VZcoord = IntegerWithBitSize<8>; 387 388 VXcoord vx; 389 VYcoord vy; 390 VZcoord vz; 391 392 enum { bits = VXcoord::bits + VYcoord::bits + VZcoord::bits }; 393 }; 394 395 /** The index of a touch, i.e. finger number. */ 396 using TouchIndex = IntegerWithBitSize<5>; 397 398 using PacketCounter = IntegerWithBitSize<10>; 399 400 //============================================================================== 401 enum DeviceCommands 402 { 403 beginAPIMode = 0x00, 404 requestTopologyMessage = 0x01, 405 endAPIMode = 0x02, 406 ping = 0x03, 407 debugMode = 0x04, 408 saveProgramAsDefault = 0x05 409 }; 410 411 using DeviceCommand = IntegerWithBitSize<9>; 412 413 //============================================================================== 414 enum ConfigCommands 415 { 416 setConfig = 0x00, 417 requestConfig = 0x01, // Request a config update 418 requestFactorySync = 0x02, // Requests all active factory config data 419 requestUserSync = 0x03, // Requests all active user config data 420 updateConfig = 0x04, // Set value, min and max 421 updateUserConfig = 0x05, // As above but contains user config metadata 422 setConfigState = 0x06, // Set config activation state and whether it is saved in flash 423 factorySyncEnd = 0x07, 424 clusterConfigSync = 0x08, 425 factorySyncReset = 0x09 426 }; 427 428 using ConfigCommand = IntegerWithBitSize<4>; 429 using ConfigItemIndex = IntegerWithBitSize<8>; 430 using ConfigItemValue = IntegerWithBitSize<32>; 431 432 //============================================================================== 433 /** An ID for a control-block button type */ 434 using ControlButtonID = IntegerWithBitSize<12>; 435 436 //============================================================================== 437 using RotaryDialIndex = IntegerWithBitSize<7>; 438 using RotaryDialAngle = IntegerWithBitSize<14>; 439 using RotaryDialDelta = IntegerWithBitSize<14>; 440 441 //============================================================================== 442 enum DataChangeCommands 443 { 444 endOfPacket = 0, 445 endOfChanges = 1, 446 skipBytesFew = 2, 447 skipBytesMany = 3, 448 setSequenceOfBytes = 4, 449 setFewBytesWithValue = 5, 450 setFewBytesWithLastValue = 6, 451 setManyBytesWithValue = 7 452 }; 453 454 using PacketIndex = IntegerWithBitSize<16>; 455 using DataChangeCommand = IntegerWithBitSize<3>; 456 using ByteCountFew = IntegerWithBitSize<4>; 457 using ByteCountMany = IntegerWithBitSize<8>; 458 using ByteValue = IntegerWithBitSize<8>; 459 using ByteSequenceContinues = IntegerWithBitSize<1>; 460 461 using FirmwareUpdateACKCode = IntegerWithBitSize<7>; 462 using FirmwareUpdateACKDetail = IntegerWithBitSize<32>; 463 using FirmwareUpdatePacketSize = IntegerWithBitSize<7>; 464 465 static constexpr uint32 numProgramMessageInts = 3; 466 467 static constexpr uint32 apiModeHostPingTimeoutMs = 5000; 468 469 static constexpr uint32 padBlockProgramAndHeapSize = 7200; 470 static constexpr uint32 padBlockStackSize = 800; 471 472 static constexpr uint32 controlBlockProgramAndHeapSize = 3000; 473 static constexpr uint32 controlBlockStackSize = 800; 474 475 476 //============================================================================== 477 /** Contains the number of bits required to encode various items in the packets */ 478 enum BitSizes 479 { 480 topologyMessageHeader = (int) MessageType::bits + (int) ProtocolVersion::bits + (int) DeviceCount::bits + (int) ConnectionCount::bits, 481 topologyDeviceInfo = (int) BlockSerialNumber::maxLength * 7 + (int) BatteryLevel::bits + (int) BatteryCharging::bits, 482 topologyConnectionInfo = topologyIndexBits + (int) ConnectorPort::bits + topologyIndexBits + (int) ConnectorPort::bits, 483 484 typeDeviceAndTime = (int) MessageType::bits + (int) PacketTimestampOffset::bits, 485 486 touchMessage = (int) typeDeviceAndTime + (int) TouchIndex::bits + (int) TouchPosition::bits, 487 touchMessageWithVelocity = (int) touchMessage + (int) TouchVelocity::bits, 488 489 programEventMessage = (int) MessageType::bits + 32 * numProgramMessageInts, 490 packetACK = (int) MessageType::bits + (int) PacketCounter::bits, 491 492 firmwareUpdateACK = (int) MessageType::bits + (int) FirmwareUpdateACKCode::bits + (int) FirmwareUpdateACKDetail::bits, 493 494 controlButtonMessage = (int) typeDeviceAndTime + (int) ControlButtonID::bits, 495 496 configSetMessage = (int) MessageType::bits + (int) ConfigCommand::bits + (int) ConfigItemIndex::bits + (int) ConfigItemValue::bits, 497 configRespMessage = (int) MessageType::bits + (int) ConfigCommand::bits + (int) ConfigItemIndex::bits + ((int) ConfigItemValue::bits * 3), 498 configSyncEndMessage = (int) MessageType::bits + (int) ConfigCommand::bits, 499 }; 500 501 //============================================================================== 502 // These are the littlefoot functions provided for use in BLOCKS programs 503 static constexpr const char* ledProgramLittleFootFunctions[] = 504 { 505 "min/iii", 506 "min/fff", 507 "max/iii", 508 "max/fff", 509 "clamp/iiii", 510 "clamp/ffff", 511 "abs/ii", 512 "abs/ff", 513 "map/ffffff", 514 "map/ffff", 515 "mod/iii", 516 "getRandomFloat/f", 517 "getRandomInt/ii", 518 "log/vi", 519 "logHex/vi", 520 "getMillisecondCounter/i", 521 "getFirmwareVersion/i", 522 "getTimeInCurrentFunctionCall/i", 523 "getBatteryLevel/f", 524 "isBatteryCharging/b", 525 "isMasterBlock/b", 526 "isConnectedToHost/b", 527 "setStatusOverlayActive/vb", 528 "getNumBlocksInTopology/i", 529 "getBlockIDForIndex/ii", 530 "getBlockIDOnPort/ii", 531 "getPortToMaster/i", 532 "getBlockTypeForID/ii", 533 "sendMessageToBlock/viiii", 534 "sendMessageToHost/viii", 535 "getHorizontalDistFromMaster/i", 536 "getVerticalDistFromMaster/i", 537 "getAngleFromMaster/i", 538 "setAutoRotate/vb", 539 "getClusterIndex/i", 540 "getClusterWidth/i", 541 "getClusterHeight/i", 542 "getClusterXpos/i", 543 "getClusterYpos/i", 544 "getNumBlocksInCurrentCluster/i", 545 "getBlockIdForBlockInCluster/ii", 546 "isMasterInCurrentCluster/b", 547 "setClusteringActive/vb", 548 "makeARGB/iiiii", 549 "blendARGB/iii", 550 "fillPixel/viii", 551 "blendPixel/viii", 552 "fillRect/viiiii", 553 "blendRect/viiiii", 554 "blendGradientRect/viiiiiiii", 555 "blendCircle/vifffb", 556 "addPressurePoint/vifff", 557 "drawPressureMap/v", 558 "fadePressureMap/v", 559 "drawNumber/viiii", 560 "clearDisplay/v", 561 "clearDisplay/vi", 562 "displayBatteryLevel/v", 563 "sendMIDI/vi", 564 "sendMIDI/vii", 565 "sendMIDI/viii", 566 "sendNoteOn/viii", 567 "sendNoteOff/viii", 568 "sendAftertouch/viii", 569 "sendCC/viii", 570 "sendPitchBend/vii", 571 "sendPitchBend/viii", 572 "sendChannelPressure/vii", 573 "addPitchCorrectionPad/viiffff", 574 "setPitchCorrectionEnabled/vb", 575 "getPitchCorrectionPitchBend/iii", 576 "setChannelRange/vbii", 577 "assignChannel/ii", 578 "deassignChannel/vii", 579 "getControlChannel/i", 580 "useMPEDuplicateFilter/vb", 581 "getSensorValue/iii", 582 "handleTouchAsSeaboard/vi", 583 "setPowerSavingEnabled/vb", 584 "getLocalConfig/ii", 585 "setLocalConfig/vii", 586 "requestRemoteConfig/vii", 587 "setRemoteConfig/viii", 588 "setLocalConfigItemRange/viii", 589 "setLocalConfigActiveState/vibb", 590 "linkBlockIDtoController/vi", 591 "repaintControl/v", 592 "onControlPress/vi", 593 "onControlRelease/vi", 594 "initControl/viiiiiiiii", 595 "setButtonMode/vii", 596 "setButtonType/viii", 597 "setButtonMinMaxDefault/viiii", 598 "setButtonColours/viii", 599 "setButtonTriState/vii", 600 "padControllerInitDefault/vb", 601 "padControllerReset/v", 602 "padControllerRegenDefault/v", 603 "padControllerRepaint/v", 604 "padControllerDrawPad/vi", 605 "setUseDefaultKeyHandler/vb", 606 "setUseDefaultKeyHandler/vbb", 607 608 nullptr 609 }; 610 611 } // namespace BlocksProtocol 612 } // namespace juce 613