|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2017 - ROLI Ltd.
-
- JUCE is an open source library subject to commercial or open-source
- licensing.
-
- The code included in this file is provided under the terms of the ISC license
- http://www.isc.org/downloads/software-support-policy/isc-license. Permission
- To use, copy, modify, and/or distribute this software for any purpose with or
- without fee is hereby granted provided that the above copyright notice and
- this permission notice appear in all copies.
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- namespace juce
- {
- namespace BlocksProtocol
- {
-
- /**
- Helper class for constructing a packet for sending to a BLOCKS device
- */
- template <int maxPacketBytes>
- struct HostPacketBuilder
- {
- HostPacketBuilder() noexcept {}
- HostPacketBuilder (const HostPacketBuilder&) = delete;
- HostPacketBuilder (HostPacketBuilder&&) = default;
-
- const void* getData() const noexcept { return data.getData(); }
- int size() const noexcept { return data.size(); }
-
- //==============================================================================
- void writePacketSysexHeaderBytes (TopologyIndex deviceIndex) noexcept
- {
- static_assert (maxPacketBytes > 10, "Not enough bytes for a sensible message!");
-
- jassert ((deviceIndex & 64) == 0);
-
- data.writeHeaderSysexBytes (deviceIndex);
- }
-
- void writePacketSysexFooter() noexcept
- {
- data.writePacketSysexFooter();
- }
-
- //==============================================================================
- bool deviceControlMessage (DeviceCommand command) noexcept
- {
- if (! data.hasCapacity (MessageType::bits + DeviceCommand::bits))
- return false;
-
- writeMessageType (MessageFromHost::deviceCommandMessage);
- data << command;
- return true;
- }
-
- //==============================================================================
- bool beginDataChanges (PacketIndex packetIndex) noexcept
- {
- if (! data.hasCapacity (MessageType::bits + PacketIndex::bits + DataChangeCommand::bits))
- return false;
-
- writeMessageType (MessageFromHost::sharedDataChange);
- data << packetIndex;
- return true;
- }
-
- bool endDataChanges (bool isLastChange) noexcept
- {
- if (! data.hasCapacity (DataChangeCommand::bits))
- return false;
-
- data << DataChangeCommand ((uint32) isLastChange ? endOfChanges : endOfPacket);
- return true;
- }
-
- bool skipBytes (int numToSkip) noexcept
- {
- if (numToSkip <= 0)
- return true;
-
- auto state = data.getState();
-
- while (numToSkip > ByteCountMany::maxValue)
- {
- if (! skipBytes (ByteCountMany::maxValue))
- {
- data.restore (state);
- return false;
- }
-
- numToSkip -= ByteCountMany::maxValue;
- }
-
- if (numToSkip > ByteCountFew::maxValue)
- {
- if (! data.hasCapacity (DataChangeCommand::bits * 2 + ByteCountMany::bits))
- {
- data.restore (state);
- return false;
- }
-
- data << DataChangeCommand ((uint32) skipBytesMany) << ByteCountMany ((uint32) numToSkip);
- return true;
- }
-
- if (! data.hasCapacity (DataChangeCommand::bits * 2 + ByteCountFew::bits))
- {
- data.restore (state);
- return false;
- }
-
- data << DataChangeCommand ((uint32) skipBytesFew) << ByteCountFew ((uint32) numToSkip);
- return true;
- }
-
- bool setMultipleBytes (const uint8* values, int num) noexcept
- {
- if (num <= 0)
- return true;
-
- if (! data.hasCapacity (DataChangeCommand::bits * 2 + num * (1 + ByteValue::bits)))
- return false;
-
- data << DataChangeCommand ((uint32) setSequenceOfBytes);
-
- for (int i = 0; i < num; ++i)
- data << ByteValue ((uint32) values[i])
- << ByteSequenceContinues (i < num - 1 ? 1 : 0);
-
- return true;
- }
-
- bool setMultipleBytes (uint8 value, uint8 lastValue, int num) noexcept
- {
- if (num <= 0)
- return true;
-
- if (num == 1)
- return setMultipleBytes (&value, 1); // (this is a more compact message)
-
- auto state = data.getState();
-
- if (num > ByteCountMany::maxValue)
- {
- if (! setMultipleBytes (value, lastValue, ByteCountMany::maxValue))
- {
- data.restore (state);
- return false;
- }
-
- return setMultipleBytes (value, lastValue, num - ByteCountMany::maxValue);
- }
-
- if (num > ByteCountFew::maxValue)
- {
- if (! data.hasCapacity (DataChangeCommand::bits * 2 + ByteCountMany::bits + ByteValue::bits))
- {
- data.restore (state);
- return false;
- }
-
- data << DataChangeCommand ((uint32) setManyBytesWithValue)
- << ByteCountMany ((uint32) num)
- << ByteValue ((uint32) value);
-
- return true;
- }
-
- if (value == lastValue)
- {
- if (! data.hasCapacity (DataChangeCommand::bits * 2 + ByteCountFew::bits))
- {
- data.restore (state);
- return false;
- }
-
- data << DataChangeCommand ((uint32) setFewBytesWithLastValue) << ByteCountFew ((uint32) num);
- return true;
- }
-
- if (! data.hasCapacity (DataChangeCommand::bits * 2 + ByteCountFew::bits + ByteValue::bits))
- {
- data.restore (state);
- return false;
- }
-
- data << DataChangeCommand ((uint32) setFewBytesWithValue) << ByteCountFew ((uint32) num)
- << ByteValue ((uint32) value);
-
- return true;
- }
-
- bool addProgramEventMessage (const int32* messageData)
- {
- if (! data.hasCapacity (BitSizes::programEventMessage))
- return false;
-
- writeMessageType (MessageFromHost::programEventMessage);
-
- for (uint32 i = 0; i < numProgramMessageInts; ++i)
- data << IntegerWithBitSize<32> ((uint32) messageData[i]);
-
- return true;
- }
-
- bool addFirmwareUpdatePacket (const uint8* packetData, uint8 size)
- {
- if (! data.hasCapacity (MessageType::bits + FirmwareUpdatePacketSize::bits + 7 * size))
- return false;
-
- writeMessageType (MessageFromHost::firmwareUpdatePacket);
- data << FirmwareUpdatePacketSize (size);
-
- for (uint8 i = 0; i < size; ++i)
- data << IntegerWithBitSize<7> ((uint32) packetData[i]);
-
- return true;
- }
-
- //==============================================================================
- bool addConfigSetMessage (int32 item, int32 value)
- {
- if (! data.hasCapacity (BitSizes::configSetMessage))
- return false;
-
- writeMessageType(MessageFromHost::configMessage);
- ConfigCommand type = ConfigCommands::setConfig;
- data << type << IntegerWithBitSize<8> ((uint32) item) << IntegerWithBitSize<32>((uint32) value);
- return true;
- }
-
- bool addRequestMessage (int32 item)
- {
- if (! data.hasCapacity (BitSizes::configSetMessage))
- return false;
-
- writeMessageType(MessageFromHost::configMessage);
- ConfigCommand type = ConfigCommands::requestConfig;
- data << type << IntegerWithBitSize<32> (0) << IntegerWithBitSize<8> ((uint32) item);
- return true;
- }
-
- bool addRequestFactorySyncMessage()
- {
- if (! data.hasCapacity (MessageType::bits + ConfigCommand::bits))
- return false;
-
- writeMessageType (MessageFromHost::configMessage);
- ConfigCommand type = ConfigCommands::requestFactorySync;
- data << type;
- return true;
- }
-
- bool addRequestUserSyncMessage()
- {
- if (! data.hasCapacity (MessageType::bits + ConfigCommand::bits))
- return false;
-
- writeMessageType (MessageFromHost::configMessage);
- ConfigCommand type = ConfigCommands::requestUserSync;
- data << type;
- return true;
- }
-
- //==============================================================================
- bool addFactoryReset()
- {
- if (! data.hasCapacity (MessageType::bits))
- return false;
-
- writeMessageType(MessageFromHost::factoryReset);
- return true;
- }
-
- bool addBlockReset()
- {
- if (! data.hasCapacity (MessageType::bits))
- return false;
-
- writeMessageType(MessageFromHost::blockReset);
- return true;
- }
-
- bool addSetBlockName (const juce::String& name)
- {
- if (name.length() > 32 || ! data.hasCapacity (MessageType::bits + 7 + (7 * name.length())))
- return false;
-
- writeMessageType (MessageFromHost::setName);
-
- data << IntegerWithBitSize<7> ((uint32) name.length());
-
- for (auto i = 0; i < name.length(); ++i)
- data << IntegerWithBitSize<7> ((uint32) name.toRawUTF8()[i]);
-
- data << IntegerWithBitSize<7> (0);
-
- return true;
- }
-
- //==============================================================================
- private:
- Packed7BitArrayBuilder<maxPacketBytes> data;
-
- void writeMessageType (MessageFromHost type) noexcept
- {
- data << MessageType ((uint32) type);
- }
- };
-
- } // namespace BlocksProtocol
- } // namespace juce
|