SACN strips now wrap around to the next universe

This commit is contained in:
PS 2021-09-25 17:08:01 -05:00
parent d6eabfe3ac
commit f0f0a48acb
2 changed files with 239 additions and 223 deletions

View File

@ -81,14 +81,14 @@ const u8 VHD_D_FLAG = 0x10;
#define CID_Bytes 16 #define CID_Bytes 16
struct cid struct cid
{ {
u8 Bytes[CID_Bytes]; u8 Bytes[CID_Bytes];
}; };
struct streaming_acn struct streaming_acn
{ {
platform_socket_handle SendSocket; platform_socket_handle SendSocket;
cid CID; cid CID;
s32 SequenceIterator; s32 SequenceIterator;
}; };
/////////////////////////////////////////////// ///////////////////////////////////////////////
@ -100,100 +100,100 @@ struct streaming_acn
internal void internal void
SetStreamHeaderSequence_ (u8* Buffer, u8 Sequence, b32 Draft) SetStreamHeaderSequence_ (u8* Buffer, u8 Sequence, b32 Draft)
{ {
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
PackB1(Buffer + SEQ_NUM_ADDR, Sequence); PackB1(Buffer + SEQ_NUM_ADDR, Sequence);
} }
internal void internal void
VHD_PackFlags_(u8* Buffer, b32 InheritVec, b32 InheritHead, b32 InheritData) VHD_PackFlags_(u8* Buffer, b32 InheritVec, b32 InheritHead, b32 InheritData)
{ {
u8* Cursor = Buffer; u8* Cursor = Buffer;
u8 NewByte = UpackB1(Cursor) & 0x8f; u8 NewByte = UpackB1(Cursor) & 0x8f;
if (!InheritVec) { NewByte |= VHD_V_FLAG; } if (!InheritVec) { NewByte |= VHD_V_FLAG; }
if (!InheritHead) { NewByte |= VHD_H_FLAG; } if (!InheritHead) { NewByte |= VHD_H_FLAG; }
if (!InheritData) { NewByte |= VHD_D_FLAG; } if (!InheritData) { NewByte |= VHD_D_FLAG; }
PackB1(Cursor, NewByte); PackB1(Cursor, NewByte);
} }
internal u8* internal u8*
VHD_PackLength_(u8* Buffer, u32 Length, b32 IncludeLength) VHD_PackLength_(u8* Buffer, u32 Length, b32 IncludeLength)
{ {
u8* Cursor = Buffer; u8* Cursor = Buffer;
u32 AdjustedLength = Length; u32 AdjustedLength = Length;
if (IncludeLength) if (IncludeLength)
{
if (Length + 1 > VHD_MAXMINLENGTH)
{ {
if (Length + 1 > VHD_MAXMINLENGTH) AdjustedLength += 2;
{
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 else
{ {
NewByte |= (PackBuffer[1] & 0x0f); AdjustedLength += 1;
Cursor = PackB1(Cursor, PackBuffer[2]);
Cursor = PackB1(Cursor, PackBuffer[3]);
} }
}
return Cursor; // 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 internal cid
gs_stringToCID_ (const char* gs_string) gs_stringToCID_ (const char* gs_string)
{ {
cid Result = {}; cid Result = {};
const char* Src = gs_string; const char* Src = gs_string;
u8* Dest = &Result.Bytes[0]; u8* Dest = &Result.Bytes[0];
b32 FirstNibble = true; b32 FirstNibble = true;
while(*Src && (Dest - &Result.Bytes[0] < CID_Bytes)) 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)
{ {
u8 Offset = 0; if (FirstNibble)
if ((*Src >= 0x30) && (*Src <= 0x39)){ Offset = 0x30; } {
else if ((*Src >= 0x41) && (*Src <= 0x46)) { Offset = 0x37; } *Dest = (u8)(*Src - Offset);
else if ((*Src >= 0x61) && (*Src <= 0x66)) { Offset = 0x66; } *Dest <<= 4;
FirstNibble = false;
if (Offset != 0) }
{ else
if (FirstNibble) {
{ *Dest |= (*Src - Offset);
*Dest = (u8)(*Src - Offset); Dest++;
*Dest <<= 4; FirstNibble = true;
FirstNibble = false; }
}
else
{
*Dest |= (*Src - Offset);
Dest++;
FirstNibble = true;
}
}
Src++;
} }
Src++;
}
return Result; return Result;
} }
internal void internal void
@ -208,84 +208,84 @@ InitStreamHeader (u8* Buffer, s32 BufferSize,
cid CID cid CID
) )
{ {
// TODO(pjs): Replace packing with gs_memory_cursor // TODO(pjs): Replace packing with gs_memory_cursor
u8* Cursor = Buffer; u8* Cursor = Buffer;
// Preamble Size // Preamble Size
Cursor = PackB2(Cursor, RLP_PREAMBLE_SIZE); Cursor = PackB2(Cursor, RLP_PREAMBLE_SIZE);
Cursor = PackB2(Cursor, RLP_POSTAMBLE_SIZE); Cursor = PackB2(Cursor, RLP_POSTAMBLE_SIZE);
CopyMemoryTo(ACN_IDENTIFIER, Cursor, ACN_IDENTIFIER_SIZE); CopyMemoryTo(ACN_IDENTIFIER, Cursor, ACN_IDENTIFIER_SIZE);
Cursor += ACN_IDENTIFIER_SIZE; Cursor += ACN_IDENTIFIER_SIZE;
// TODO(Peter): If you never use this anywhere else, go back and remove the parameters // TODO(Peter): If you never use this anywhere else, go back and remove the parameters
VHD_PackFlags_(Cursor, false, false, false); VHD_PackFlags_(Cursor, false, false, false);
Cursor = VHD_PackLength_(Cursor, Cursor = VHD_PackLength_(Cursor,
STREAM_HEADER_SIZE - RLP_PREAMBLE_SIZE + SlotCount, STREAM_HEADER_SIZE - RLP_PREAMBLE_SIZE + SlotCount,
false); false);
// root vector // root vector
Cursor = PackB4(Cursor, ROOT_VECTOR); Cursor = PackB4(Cursor, ROOT_VECTOR);
// CID Pack // CID Pack
for (s32 i = 0; i < CID_Bytes; i++) for (s32 i = 0; i < CID_Bytes; i++)
{ {
*Cursor++ = CID.Bytes[i]; *Cursor++ = CID.Bytes[i];
} }
VHD_PackFlags_(Cursor, false, false, false); VHD_PackFlags_(Cursor, false, false, false);
Cursor = VHD_PackLength_(Cursor, Cursor = VHD_PackLength_(Cursor,
STREAM_HEADER_SIZE - FRAMING_FLAGS_AND_LENGTH_ADDR + SlotCount, STREAM_HEADER_SIZE - FRAMING_FLAGS_AND_LENGTH_ADDR + SlotCount,
false); false);
// framing vector // framing vector
Cursor = PackB4(Cursor, FRAMING_VECTOR); Cursor = PackB4(Cursor, FRAMING_VECTOR);
// framing source name // framing source name
// :Check // :Check
CopyMemoryTo(SourceName, (char*)Cursor, SOURCE_NAME_SIZE); CopyMemoryTo(SourceName, (char*)Cursor, SOURCE_NAME_SIZE);
Cursor[SOURCE_NAME_SIZE - 1] = '\0'; Cursor[SOURCE_NAME_SIZE - 1] = '\0';
Cursor += SOURCE_NAME_SIZE; Cursor += SOURCE_NAME_SIZE;
// priority // priority
Cursor = PackB1(Cursor, Priority); Cursor = PackB1(Cursor, Priority);
// reserved // reserved
Cursor = PackB2(Cursor, Reserved); Cursor = PackB2(Cursor, Reserved);
// Sequence # is always set to 0/NONE at the beginning, but it is incremented when sending data // Sequence # is always set to 0/NONE at the beginning, but it is incremented when sending data
Cursor = PackB1(Cursor, 0); Cursor = PackB1(Cursor, 0);
// Options // Options
Cursor = PackB1(Cursor, Options); Cursor = PackB1(Cursor, Options);
// Universe // Universe
Cursor = PackB2(Cursor, Universe); Cursor = PackB2(Cursor, Universe);
VHD_PackFlags_(Cursor, false, false, false); VHD_PackFlags_(Cursor, false, false, false);
Cursor = VHD_PackLength_(Cursor, Cursor = VHD_PackLength_(Cursor,
STREAM_HEADER_SIZE - DMP_FLAGS_AND_LENGTH_ADDR + SlotCount, STREAM_HEADER_SIZE - DMP_FLAGS_AND_LENGTH_ADDR + SlotCount,
false); false);
// DMP Vector // DMP Vector
Cursor = PackB1(Cursor, DMP_VECTOR); Cursor = PackB1(Cursor, DMP_VECTOR);
// DMP Address and data type // DMP Address and data type
Cursor = PackB1(Cursor, ADDRESS_AND_DATA_FORMAT); Cursor = PackB1(Cursor, ADDRESS_AND_DATA_FORMAT);
// DMP first property address // DMP first property address
Cursor = PackB2(Cursor, 0); Cursor = PackB2(Cursor, 0);
// DMP Address Increment // DMP Address Increment
Cursor = PackB2(Cursor, ADDRESS_INC); Cursor = PackB2(Cursor, ADDRESS_INC);
// Property Value Count -- Includes one byte for start code // Property Value Count -- Includes one byte for start code
Cursor = PackB2(Cursor, SlotCount + 1); Cursor = PackB2(Cursor, SlotCount + 1);
Cursor = PackB1(Cursor, StartCode); Cursor = PackB1(Cursor, StartCode);
Assert(Cursor - Buffer == STREAM_HEADER_SIZE); Assert(Cursor - Buffer == STREAM_HEADER_SIZE);
} }
@ -296,13 +296,13 @@ InitStreamHeader (u8* Buffer, s32 BufferSize,
internal streaming_acn internal streaming_acn
SACN_Initialize (context Context) SACN_Initialize (context Context)
{ {
streaming_acn SACN = {}; streaming_acn SACN = {};
s32 Multicast_TimeToLive = 20; s32 Multicast_TimeToLive = 20;
SACN.SendSocket = Context.PlatformGetSocketHandle(Multicast_TimeToLive); SACN.SendSocket = Context.PlatformGetSocketHandle(Multicast_TimeToLive);
SACN.CID = gs_stringToCID_ ("{67F9D986-544E-4abb-8986-D5F79382586C}"); SACN.CID = gs_stringToCID_ ("{67F9D986-544E-4abb-8986-D5F79382586C}");
return SACN; return SACN;
} }
internal void internal void
@ -313,82 +313,98 @@ SACN_Cleanup(streaming_acn* SACN, context Context)
internal void internal void
SACN_UpdateSequence (streaming_acn* SACN) SACN_UpdateSequence (streaming_acn* SACN)
{ {
// Never use 0 after the first one // Never use 0 after the first one
if (++SACN->SequenceIterator == 0) if (++SACN->SequenceIterator == 0)
{ {
++SACN->SequenceIterator; ++SACN->SequenceIterator;
} }
} }
internal void internal void
SACN_PrepareBufferHeader (s32 Universe, u8* Buffer, s32 BufferSize, s32 SizeReservedForHeader, streaming_acn SACN) SACN_PrepareBufferHeader (s32 Universe, u8* Buffer, s32 BufferSize, s32 SizeReservedForHeader, streaming_acn SACN)
{ {
Assert(SizeReservedForHeader == STREAM_HEADER_SIZE); Assert(SizeReservedForHeader == STREAM_HEADER_SIZE);
Assert(Buffer && BufferSize > 0); Assert(Buffer && BufferSize > 0);
s32 Priority = 0; s32 Priority = 0;
InitStreamHeader(Buffer, BufferSize, STREAM_BODY_SIZE, STARTCODE_DMX, Universe, Priority, 0, 0, "Lumenarium", SACN.CID); InitStreamHeader(Buffer, BufferSize, STREAM_BODY_SIZE, STARTCODE_DMX, Universe, Priority, 0, 0, "Lumenarium", SACN.CID);
SetStreamHeaderSequence_(Buffer, SACN.SequenceIterator, false); SetStreamHeaderSequence_(Buffer, SACN.SequenceIterator, false);
} }
internal u32 internal u32
SACN_GetUniverseSendAddress(s32 Universe) SACN_GetUniverseSendAddress(s32 Universe)
{ {
u8 MulticastAddressBuffer[4] = {}; u8 MulticastAddressBuffer[4] = {};
MulticastAddressBuffer[0] = 239; MulticastAddressBuffer[0] = 239;
MulticastAddressBuffer[1] = 255; MulticastAddressBuffer[1] = 255;
MulticastAddressBuffer[2] = (u8)((Universe & 0xff00) >> 8); // high bit MulticastAddressBuffer[2] = (u8)((Universe & 0xff00) >> 8); // high bit
MulticastAddressBuffer[3] = (u8)((Universe & 0x00ff)); // low bit MulticastAddressBuffer[3] = (u8)((Universe & 0x00ff)); // low bit
u32 V4Address = (u32)UpackB4(MulticastAddressBuffer); u32 V4Address = (u32)UpackB4(MulticastAddressBuffer);
return V4Address; return V4Address;
} }
internal void internal u64
SACN_FillBufferWithLeds(u8* BufferStart, u32 BufferSize, v2_strip Strip, led_buffer LedBuffer) SACN_FillBufferWithLeds(u8* BufferStart, u32 BufferSize, v2_strip Strip, u64 LedsPlaced, led_buffer LedBuffer)
{ {
u8* DestChannel = BufferStart; u8* DestChannel = BufferStart;
for (u32 i = 0; i < Strip.LedCount; i++) u64 FirstLed = LedsPlaced;
{ u64 LedsToAdd = Min(Strip.LedCount - LedsPlaced, STREAM_BODY_SIZE / 3);
u32 LedIndex = Strip.LedLUT[i]; u64 OnePastLastLed = FirstLed + LedsToAdd;
pixel Color = LedBuffer.Colors[LedIndex]; for (u32 i = FirstLed; i < OnePastLastLed; i++)
{
u32 LedIndex = Strip.LedLUT[i];
pixel Color = LedBuffer.Colors[LedIndex];
DestChannel[0] = Color.R; DestChannel[0] = Color.R;
DestChannel[1] = Color.G; DestChannel[1] = Color.G;
DestChannel[2] = Color.B; DestChannel[2] = Color.B;
DestChannel += 3; DestChannel += 3;
} }
return LedsToAdd;
} }
internal void internal void
SACN_BuildOutputData(streaming_acn* SACN, addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem) SACN_BuildOutputData(streaming_acn* SACN, addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem)
{ {
SACN_UpdateSequence(SACN); SACN_UpdateSequence(SACN);
// TODO(pjs): 512 is a magic number - make it a constant? // TODO(pjs): 512 is a magic number - make it a constant?
s32 BufferHeaderSize = STREAM_HEADER_SIZE; s32 BufferHeaderSize = STREAM_HEADER_SIZE;
s32 BufferBodySize = 512; s32 BufferBodySize = STREAM_BODY_SIZE;
s32 BufferSize = BufferHeaderSize + BufferBodySize; s32 BufferSize = BufferHeaderSize + BufferBodySize;
for (u32 AssemblyIdx = 0; AssemblyIdx < Assemblies.Count; AssemblyIdx++) for (u32 AssemblyIdx = 0; AssemblyIdx < Assemblies.Count; AssemblyIdx++)
{
assembly Assembly = Assemblies.Values[AssemblyIdx];
led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
for (u32 StripIdx = 0; StripIdx < Assembly.StripCount; StripIdx++)
{ {
assembly Assembly = Assemblies.Values[AssemblyIdx]; v2_strip StripAt = Assembly.Strips[StripIdx];
led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
for (u32 StripIdx = 0; StripIdx < Assembly.StripCount; StripIdx++) // NOTE(PS): This isn't actually invalid, we just haven't needed to implement
{ // something more complex than only allowing strips to start at the first
v2_strip StripAt = Assembly.Strips[StripIdx]; // channel of a universe
Assert(StripAt.SACNAddr.StartChannel == 1);
u32 V4SendAddress = SACN_GetUniverseSendAddress(StripAt.SACNAddr.StartUniverse); u32 UniverseAt = StripAt.SACNAddr.StartUniverse;
u32 SendPort = DEFAULT_STREAMING_ACN_PORT; u64 LedsPlaced = 0;
while (LedsPlaced < StripAt.LedCount)
{
u32 V4SendAddress = SACN_GetUniverseSendAddress(UniverseAt);
u32 SendPort = DEFAULT_STREAMING_ACN_PORT;
addressed_data_buffer* Data = AddressedDataBufferList_Push(Output, BufferSize); addressed_data_buffer* Data = AddressedDataBufferList_Push(Output, BufferSize);
AddressedDataBuffer_SetNetworkAddress(Data, SACN->SendSocket, V4SendAddress, SendPort); AddressedDataBuffer_SetNetworkAddress(Data, SACN->SendSocket, V4SendAddress, SendPort);
SACN_PrepareBufferHeader(StripAt.SACNAddr.StartUniverse, Data->Memory, Data->MemorySize, BufferHeaderSize, *SACN); SACN_PrepareBufferHeader(UniverseAt, Data->Memory, Data->MemorySize, BufferHeaderSize, *SACN);
SACN_FillBufferWithLeds(Data->Memory + BufferHeaderSize, BufferBodySize, StripAt, *LedBuffer); LedsPlaced += SACN_FillBufferWithLeds(Data->Memory + BufferHeaderSize, BufferBodySize, StripAt, LedsPlaced, *LedBuffer);
}
UniverseAt += 1;
}
} }
}
} }
#define SACN_H #define SACN_H

View File

@ -36,9 +36,9 @@ gs_const_string VoicePatternFolder = ConstString("data/blumen_animations/audio_r
// NOTE: There is no need to modify the MotorOpenTimesCount variable - // NOTE: There is no need to modify the MotorOpenTimesCount variable -
// it is a compile time constant that gets calculated automatically // it is a compile time constant that gets calculated automatically
global time_range MotorOpenTimes[] = { global time_range MotorOpenTimes[] = {
{ 8, 00, 12, 00 }, // 8:00am to 12:00pm { 8, 00, 12, 00 }, // 8:00am to 12:00pm
{ 12, 30, 18, 00 }, // 12:30pm to 06:00pm { 12, 30, 18, 00 }, // 12:30pm to 06:00pm
{ 18, 30, 22, 00 }, // 6:30pm to 10:00pm { 18, 30, 22, 00 }, // 6:30pm to 10:00pm
}; };
global u32 MotorOpenTimesCount = CArrayLength(MotorOpenTimes); // do not edit global u32 MotorOpenTimesCount = CArrayLength(MotorOpenTimes); // do not edit
@ -50,11 +50,11 @@ global r32 MotorResendStatePeriod = 90.0f; // seconds
// The times of day when the leds should be on // The times of day when the leds should be on
// Search for @TimeFormat to find documentation // Search for @TimeFormat to find documentation
global time_range LedOnTimes[] = { global time_range LedOnTimes[] = {
{ 14, 43, 14, 44 }, { 14, 43, 14, 44 },
{ 14, 45, 14, 46 }, { 14, 45, 14, 46 },
{ 17, 00, 23, 59 }, { 17, 00, 23, 59 },
{ 00, 00, 06, 30 }, { 00, 00, 06, 30 },
}; };
global u32 LedOnTimesCount = CArrayLength(LedOnTimes); // do not edit global u32 LedOnTimesCount = CArrayLength(LedOnTimes); // do not edit
global b8 DEBUGIgnoreLedOnTimeRange = false; global b8 DEBUGIgnoreLedOnTimeRange = false;