Lumenarium/src/app/sacn/sacn.h

348 lines
8.6 KiB
C
Raw Normal View History

2020-01-02 02:41:43 +00:00
//
// File: sacn.h
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef SACN_H
2019-11-23 00:07:25 +00:00
#define NETWORKINTID_INVALID -1
#define DEFAULT_STREAMING_ACN_PORT 5568
#define IP_ADDRESS_BYTES 16
#define STARTCODE_DMX 0
/*
* a description of the address space being used
*/
#define PREAMBLE_SIZE_ADDR 0
#define POSTAMBLE_SIZE_ADDR 2
#define ACN_IDENTIFIER_ADDR 4
#define ROOT_FLAGS_AND_LENGTH_ADDR 16
#define ROOT_VECTOR_ADDR 18
#define CID_ADDR 22
#define FRAMING_FLAGS_AND_LENGTH_ADDR 38
#define FRAMING_VECTOR_ADDR 40
#define SOURCE_NAME_ADDR 44
#define PRIORITY_ADDR 108
#define RESERVED_ADDR 109
#define SEQ_NUM_ADDR 111
#define OPTIONS_ADDR 112
#define UNIVERSE_ADDR 113
#define DMP_FLAGS_AND_LENGTH_ADDR 115
#define DMP_VECTOR_ADDR 117
#define DMP_ADDRESS_AND_DATA_ADDR 118
#define FIRST_PROPERTY_ADDRESS_ADDR 119
#define ADDRESS_INC_ADDR 121
#define PROP_COUNT_ADDR 123
#define START_CODE_ADDR 125
#define PROP_VALUES_ADDR (START_CODE_ADDR + 1)
/*
* common sizes
*/
#define STREAM_HEADER_SIZE 126
#define STREAM_BODY_SIZE 512
#define SOURCE_NAME_SIZE 64
#define RLP_PREAMBLE_SIZE 16
#define RLP_POSTAMBLE_SIZE 0
#define ACN_IDENTIFIER_SIZE 12
/*
* data definitions
*/
#define ACN_IDENTIFIER "ASC-E1.17\0\0\0"
#define ROOT_VECTOR 4
#define FRAMING_VECTOR 2
#define DMP_VECTOR 2
#define ADDRESS_AND_DATA_FORMAT 0xa1
#define ADDRESS_INC 1
#define DMP_FIRST_PROPERTY_ADDRESS_FORCE 0
#define RESERVED_VALUE 0
//for support of the early draft
#define DRAFT_STREAM_HEADER_SIZE 90
#define DRAFT_SOURCE_NAME_SIZE 32
//for support of the early draft
#define DRAFT_ROOT_VECTOR 3
const u32 VHD_MAXFLAGBYTES = 7; //The maximum amount of bytes used to pack the flags, len, and vector
const u32 VHD_MAXLEN = 0x0fffff; //The maximum packet length is 20 bytes long
const u32 VHD_MAXMINLENGTH = 4095; //The highest length that will fit in the "smallest" length pack
//Defines for the VHD flags
const u8 VHD_L_FLAG = 0x80;
const u8 VHD_V_FLAG = 0x40;
const u8 VHD_H_FLAG = 0x20;
const u8 VHD_D_FLAG = 0x10;
#define CID_Bytes 16
struct cid
{
u8 Bytes[CID_Bytes];
};
struct streaming_acn
{
platform_socket_handle SendSocket;
cid CID;
s32 SequenceIterator;
};
///////////////////////////////////////////////
//
// SACN Data Header Functions
//
///////////////////////////////////////////////
internal void
SetStreamHeaderSequence_ (u8* Buffer, u8 Sequence, b32 Draft)
{
DEBUG_TRACK_FUNCTION;
PackB1(Buffer + SEQ_NUM_ADDR, Sequence);
}
internal void
VHD_PackFlags_(u8* Buffer, b32 InheritVec, b32 InheritHead, b32 InheritData)
{
u8* Cursor = Buffer;
u8 NewByte = UpackB1(Cursor) & 0x8f;
if (!InheritVec) { NewByte |= VHD_V_FLAG; }
if (!InheritHead) { NewByte |= VHD_H_FLAG; }
if (!InheritData) { NewByte |= VHD_D_FLAG; }
PackB1(Cursor, NewByte);
}
internal u8*
VHD_PackLength_(u8* Buffer, u32 Length, b32 IncludeLength)
{
u8* Cursor = Buffer;
u32 AdjustedLength = Length;
if (IncludeLength)
{
if (Length + 1 > VHD_MAXMINLENGTH)
{
AdjustedLength += 2;
}
else
{
AdjustedLength += 1;
}
}
// Mask out the length bits to keep flags intact
u8 NewByte = UpackB1(Cursor) & 0x70;
if (AdjustedLength > VHD_MAXMINLENGTH)
{
NewByte |= VHD_L_FLAG;
}
u8 PackBuffer[4];
PackB4(PackBuffer, AdjustedLength);
if (AdjustedLength <= VHD_MAXMINLENGTH)
{
NewByte |= (PackBuffer[2] & 0x0f);
Cursor = PackB1(Cursor, NewByte);
Cursor = PackB1(Cursor, PackBuffer[3]);
}
else
{
NewByte |= (PackBuffer[1] & 0x0f);
Cursor = PackB1(Cursor, PackBuffer[2]);
Cursor = PackB1(Cursor, PackBuffer[3]);
}
return Cursor;
}
internal cid
StringToCID_ (const char* String)
{
cid Result = {};
const char* Src = String;
u8* Dest = &Result.Bytes[0];
b32 FirstNibble = true;
while(*Src && (Dest - &Result.Bytes[0] < CID_Bytes))
{
u8 Offset = 0;
if ((*Src >= 0x30) && (*Src <= 0x39)){ Offset = 0x30; }
else if ((*Src >= 0x41) && (*Src <= 0x46)) { Offset = 0x37; }
else if ((*Src >= 0x61) && (*Src <= 0x66)) { Offset = 0x66; }
if (Offset != 0)
{
if (FirstNibble)
{
*Dest = (u8)(*Src - Offset);
*Dest <<= 4;
FirstNibble = false;
}
else
{
*Dest |= (*Src - Offset);
Dest++;
FirstNibble = true;
}
}
Src++;
}
return Result;
}
internal void
InitStreamHeader (u8* Buffer, s32 BufferSize,
u16 SlotCount,
u8 StartCode,
u16 Universe,
u8 Priority,
u16 Reserved,
u8 Options,
const char* SourceName,
cid CID
)
{
u8* Cursor = Buffer;
// Preamble Size
Cursor = PackB2(Cursor, RLP_PREAMBLE_SIZE);
Cursor = PackB2(Cursor, RLP_POSTAMBLE_SIZE);
GSMemCopy(ACN_IDENTIFIER, Cursor, ACN_IDENTIFIER_SIZE);
2019-11-23 00:07:25 +00:00
Cursor += ACN_IDENTIFIER_SIZE;
// TODO(Peter): If you never use this anywhere else, go back and remove the parameters
VHD_PackFlags_(Cursor, false, false, false);
Cursor = VHD_PackLength_(Cursor,
STREAM_HEADER_SIZE - RLP_PREAMBLE_SIZE + SlotCount,
false);
// root vector
Cursor = PackB4(Cursor, ROOT_VECTOR);
// CID Pack
for (s32 i = 0; i < CID_Bytes; i++)
{
*Cursor++ = CID.Bytes[i];
}
VHD_PackFlags_(Cursor, false, false, false);
Cursor = VHD_PackLength_(Cursor,
STREAM_HEADER_SIZE - FRAMING_FLAGS_AND_LENGTH_ADDR + SlotCount,
false);
// framing vector
Cursor = PackB4(Cursor, FRAMING_VECTOR);
// framing source name
// :Check
GSMemCopy(SourceName, (char*)Cursor, SOURCE_NAME_SIZE);
2019-11-23 00:07:25 +00:00
Cursor[SOURCE_NAME_SIZE - 1] = '\0';
Cursor += SOURCE_NAME_SIZE;
// priority
Cursor = PackB1(Cursor, Priority);
// reserved
Cursor = PackB2(Cursor, Reserved);
// Sequence # is always set to 0/NONE at the beginning, but it is incremented when sending data
Cursor = PackB1(Cursor, 0);
// Options
Cursor = PackB1(Cursor, Options);
// Universe
Cursor = PackB2(Cursor, Universe);
VHD_PackFlags_(Cursor, false, false, false);
Cursor = VHD_PackLength_(Cursor,
STREAM_HEADER_SIZE - DMP_FLAGS_AND_LENGTH_ADDR + SlotCount,
false);
// DMP Vector
Cursor = PackB1(Cursor, DMP_VECTOR);
// DMP Address and data type
Cursor = PackB1(Cursor, ADDRESS_AND_DATA_FORMAT);
// DMP first property address
Cursor = PackB2(Cursor, 0);
// DMP Address Increment
Cursor = PackB2(Cursor, ADDRESS_INC);
// Property Value Count -- Includes one byte for start code
Cursor = PackB2(Cursor, SlotCount + 1);
Cursor = PackB1(Cursor, StartCode);
Assert(Cursor - Buffer == STREAM_HEADER_SIZE);
}
//
// New SACN
//
internal streaming_acn
InitializeSACN ( context Context)
{
streaming_acn SACN = {};
s32 Multicast_TimeToLive = 20;
SACN.SendSocket = Context.PlatformGetSocketHandle(Multicast_TimeToLive);
2019-11-23 00:07:25 +00:00
SACN.CID = StringToCID_ ("{67F9D986-544E-4abb-8986-D5F79382586C}");
return SACN;
}
internal void
SACNCleanup(streaming_acn* SACN, context Context)
{
Context.PlatformCloseSocket(SACN->SendSocket);
}
internal void
SACNUpdateSequence (streaming_acn* SACN)
{
// Never use 0 after the first one
if (++SACN->SequenceIterator == 0)
{
++SACN->SequenceIterator;
}
}
internal void
SACNPrepareBufferHeader (s32 Universe, u8* Buffer, s32 BufferSize, s32 SizeReservedForHeader, streaming_acn SACN)
{
Assert(SizeReservedForHeader == STREAM_HEADER_SIZE);
Assert(Buffer && BufferSize > 0);
s32 Priority = 0;
InitStreamHeader(Buffer, BufferSize, STREAM_BODY_SIZE, STARTCODE_DMX, Universe, Priority, 0, 0, "Lumenarium", SACN.CID);
SetStreamHeaderSequence_(Buffer, SACN.SequenceIterator, false);
}
internal u32
2019-11-23 00:07:25 +00:00
SACNGetUniverseSendAddress(s32 Universe)
{
u8 MulticastAddressBuffer[4] = {};
MulticastAddressBuffer[0] = 239;
MulticastAddressBuffer[1] = 255;
MulticastAddressBuffer[2] = (u8)((Universe & 0xff00) >> 8); // high bit
MulticastAddressBuffer[3] = (u8)((Universe & 0x00ff)); // low bit
2019-11-23 00:07:25 +00:00
u32 V4Address = (u32)UpackB4(MulticastAddressBuffer);
2019-11-23 00:07:25 +00:00
return V4Address;
2020-01-02 02:41:43 +00:00
}
#define SACN_H
#endif // SACN_H