Cleaned up network interface, separated SACN out from the actual sending of data, implemented sending over COM ports (remains to be tested), and added information specifying data output modes for com ports to the assembly file format

This commit is contained in:
PS 2020-10-03 08:46:14 -07:00
parent 0022efea8e
commit 83ed23280a
14 changed files with 709 additions and 303 deletions

View File

@ -5,17 +5,33 @@
// //
#ifndef ASSEMBLY_PARSER_CPP #ifndef ASSEMBLY_PARSER_CPP
// TODO(pjs): This is good for meta generation
// ie. It would be great to have
// // enum ident enum prefix
// BEGIN_GEN_ENUM(assembly_field, AssemblyField_)
// // value name gen string of the value name the paired string identifier
// ADD_ENUM_VALUE(AssemblyName, DO_GEN_STRING, "assembly_name")
// ADD_ENUM_VALUE(AssemblyScale, DO_GEN_STRING, "assembly_scale")
// END_GEN_ENUM(assembly_field)
enum assembly_field enum assembly_field
{ {
AssemblyField_AssemblyName, AssemblyField_AssemblyName,
AssemblyField_AssemblyScale, AssemblyField_AssemblyScale,
AssemblyField_AssemblyCenter, AssemblyField_AssemblyCenter,
AssemblyField_LedStripCount, AssemblyField_LedStripCount,
AssemblyField_OutputMode,
AssemblyField_LedStrip, AssemblyField_LedStrip,
AssemblyField_ControlBoxId,
AssemblyField_StartUniverse, AssemblyField_OutputSACN,
AssemblyField_StartChannel, AssemblyField_SACN_StartUniverse,
AssemblyField_SACN_StartChannel,
AssemblyField_OutputUART,
AssemblyField_UART_Channel,
AssemblyField_UART_ComPort,
AssemblyField_PointPlacementType, AssemblyField_PointPlacementType,
AssemblyField_InterpolatePoints, AssemblyField_InterpolatePoints,
AssemblyField_Start, AssemblyField_Start,
@ -34,12 +50,17 @@ global char* AssemblyFieldIdentifiers[] = {
"assembly_scale", // AssemblyField_AssemblyScale "assembly_scale", // AssemblyField_AssemblyScale
"assembly_center", // AssemblyField_AssemblyCenter "assembly_center", // AssemblyField_AssemblyCenter
"led_strip_count", // AssemblyField_LedStripCount "led_strip_count", // AssemblyField_LedStripCount
"output_mode", // AssemblyField_OutputMode
"led_strip", // AssemblyField_LedStrip "led_strip", // AssemblyField_LedStrip
"control_box_id", // AssemblyField_ControlBoxId "output_sacn", // AssemblyField_OutputSACN
"start_universe", // AssemblyField_StartUniverse "start_universe", // AssemblyField_SACN_StartUniverse
"start_channel", // AssemblyField_StartChannel "start_channel", // AssemblyField_SACN_StartChannel
"output_uart", // AssemblyField_OutputUART
"channel", // AssemblyField_UART_Channel
"com_port", // AssemblyField_UART_ComPort
"point_placement_type", // AssemblyField_PointPlacementType "point_placement_type", // AssemblyField_PointPlacementType
"interpolate_points", // AssemblyField_InterpolatePoints "interpolate_points", // AssemblyField_InterpolatePoints
@ -158,8 +179,11 @@ TokenizerPushError(assembly_tokenizer* T, char* ErrorString)
EatToNewLine(T); EatToNewLine(T);
} }
#define PARSER_FIELD_REQUIRED true
#define PARSER_FIELD_OPTIONAL false
internal bool internal bool
ReadFieldIdentifier(assembly_field Field, assembly_tokenizer* T) ReadFieldIdentifier(assembly_field Field, assembly_tokenizer* T, bool Required = true)
{ {
bool Result = false; bool Result = false;
if (AdvanceIfTokenEquals(T, AssemblyFieldIdentifiers[Field])) if (AdvanceIfTokenEquals(T, AssemblyFieldIdentifiers[Field]))
@ -170,10 +194,12 @@ ReadFieldIdentifier(assembly_field Field, assembly_tokenizer* T)
} }
else else
{ {
// We always throw an error if we get this far because we know you were trying to
// open the identifier
TokenizerPushError(T, "Field identifier is missing a colon"); TokenizerPushError(T, "Field identifier is missing a colon");
} }
} }
else else if (Required)
{ {
TokenizerPushError(T, "Field Identifier Invalid"); TokenizerPushError(T, "Field Identifier Invalid");
} }
@ -350,10 +376,10 @@ ReadV3Field(assembly_field Field, assembly_tokenizer* T)
} }
internal bool internal bool
ReadStructOpening(assembly_field Field, assembly_tokenizer* T) ReadStructOpening(assembly_field Field, assembly_tokenizer* T, bool Required = true)
{ {
bool Result = false; bool Result = false;
if (ReadFieldIdentifier(Field, T)) if (ReadFieldIdentifier(Field, T, Required))
{ {
if (AdvanceIfTokenEquals(T, "{")) if (AdvanceIfTokenEquals(T, "{"))
{ {
@ -400,14 +426,46 @@ ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileTe
Assembly->StripCount = ReadIntField(AssemblyField_LedStripCount, &Tokenizer); Assembly->StripCount = ReadIntField(AssemblyField_LedStripCount, &Tokenizer);
Assembly->Strips = PushArray(&Assembly->Arena, v2_strip, Assembly->StripCount); Assembly->Strips = PushArray(&Assembly->Arena, v2_strip, Assembly->StripCount);
gs_string OutputModeString = ReadStringField(AssemblyField_OutputMode, &Tokenizer, Transient);
if (StringsEqual(OutputModeString.ConstString, ConstString("UART")))
{
Assembly->OutputMode = NetworkProtocol_UART;
}
else if (StringsEqual(OutputModeString.ConstString, ConstString("SACN")))
{
Assembly->OutputMode = NetworkProtocol_SACN;
}
else
{
TokenizerPushError(&Tokenizer, "Invalid output mode specified.");
}
for (u32 i = 0; i < Assembly->StripCount; i++) for (u32 i = 0; i < Assembly->StripCount; i++)
{ {
v2_strip* StripAt = Assembly->Strips + i; v2_strip* StripAt = Assembly->Strips + i;
if (ReadStructOpening(AssemblyField_LedStrip, &Tokenizer)) if (ReadStructOpening(AssemblyField_LedStrip, &Tokenizer))
{ {
StripAt->ControlBoxID = ReadIntField(AssemblyField_ControlBoxId, &Tokenizer); if (ReadStructOpening(AssemblyField_OutputSACN, &Tokenizer, PARSER_FIELD_OPTIONAL))
StripAt->StartUniverse = ReadIntField(AssemblyField_StartUniverse, &Tokenizer); {
StripAt->StartChannel = ReadIntField(AssemblyField_StartChannel, &Tokenizer); StripAt->SACNAddr.StartUniverse = ReadIntField(AssemblyField_SACN_StartUniverse, &Tokenizer);
StripAt->SACNAddr.StartChannel = ReadIntField(AssemblyField_SACN_StartChannel, &Tokenizer);
if (!ReadStructClosing(&Tokenizer))
{
TokenizerPushError(&Tokenizer, "Struct doesn't close where expected");
}
}
if (ReadStructOpening(AssemblyField_OutputUART, &Tokenizer, PARSER_FIELD_OPTIONAL))
{
StripAt->UARTAddr.Channel = (u8)ReadIntField(AssemblyField_UART_Channel, &Tokenizer);
StripAt->UARTAddr.ComPort = ReadStringField(AssemblyField_UART_ComPort, &Tokenizer, &Assembly->Arena).ConstString;
if (!ReadStructClosing(&Tokenizer))
{
TokenizerPushError(&Tokenizer, "Struct doesn't close where expected");
}
}
// TODO(Peter): Need to store this // TODO(Peter): Need to store this
gs_string PointPlacementType = ReadStringField(AssemblyField_PointPlacementType, &Tokenizer, &Assembly->Arena); gs_string PointPlacementType = ReadStringField(AssemblyField_PointPlacementType, &Tokenizer, &Assembly->Arena);

View File

@ -12,66 +12,86 @@
enum data_buffer_address_type enum data_buffer_address_type
{ {
AddressType_NetworkIP, AddressType_NetworkIP,
AddressType_ComPort,
AddressType_Invalid, AddressType_Invalid,
}; };
struct addressed_data_buffer struct addressed_data_buffer
{ {
u8* Memory; union
u32 MemorySize; {
struct
{
u8* Memory;
u32 MemorySize;
};
gs_data Data;
};
data_buffer_address_type AddressType; data_buffer_address_type AddressType;
// IP Address // IP Address
platform_socket_handle SendSocket;
u32 V4SendAddress; u32 V4SendAddress;
u32 SendPort; u32 SendPort;
// COM
gs_const_string ComPort;
addressed_data_buffer* Next; addressed_data_buffer* Next;
}; };
struct addressed_data_buffer_list struct addressed_data_buffer_list
{ {
gs_memory_arena* Arena;
addressed_data_buffer* Root; addressed_data_buffer* Root;
addressed_data_buffer* Head; addressed_data_buffer* Head;
}; };
internal addressed_data_buffer* internal void
AddressedDataBufferList_Push(addressed_data_buffer_list* List, u32 BufferSize, gs_memory_arena* Storage) AddressedDataBufferList_Clear(addressed_data_buffer_list* List)
{ {
addressed_data_buffer* Result = PushStruct(Storage, addressed_data_buffer); List->Root = 0;
List->Head = 0;
ClearArena(List->Arena);
}
internal addressed_data_buffer*
AddressedDataBufferList_PushEmpty(addressed_data_buffer_list* List)
{
addressed_data_buffer* Result = PushStruct(List->Arena, addressed_data_buffer);
*Result = {0}; *Result = {0};
Result->MemorySize = BufferSize; Result->MemorySize = 0;
Result->Memory = PushArray(Storage, u8, Result->MemorySize); Result->Memory = 0;
SLLPushOrInit(List->Root, List->Head, Result); SLLPushOrInit(List->Root, List->Head, Result);
return Result; return Result;
} }
internal addressed_data_buffer*
AddressedDataBufferList_Push(addressed_data_buffer_list* List, u32 BufferSize)
{
addressed_data_buffer* Result = AddressedDataBufferList_PushEmpty(List);
Result->MemorySize = BufferSize;
Result->Memory = PushArray(List->Arena, u8, Result->MemorySize);
return Result;
}
internal void internal void
AddressedDataBuffer_SetNetworkAddress(addressed_data_buffer* Buffer, u32 V4SendAddress, u32 SendPort) AddressedDataBuffer_SetNetworkAddress(addressed_data_buffer* Buffer, platform_socket_handle SendSocket, u32 V4SendAddress, u32 SendPort)
{ {
Buffer->AddressType = AddressType_NetworkIP; Buffer->AddressType = AddressType_NetworkIP;
Buffer->SendSocket = SendSocket;
Buffer->V4SendAddress = V4SendAddress; Buffer->V4SendAddress = V4SendAddress;
Buffer->SendPort = SendPort; Buffer->SendPort = SendPort;
} }
internal void internal void
AddressedDataBuffer_Send(addressed_data_buffer Buffer, platform_socket_handle SendSocket, context Context) AddressedDataBuffer_SetCOMPort(addressed_data_buffer* Buffer, gs_const_string ComPort)
{ {
u32 V4SendAddress = Buffer.V4SendAddress; Buffer->AddressType = AddressType_ComPort;
Context.PlatformSendTo(SendSocket, Buffer.V4SendAddress, Buffer.SendPort, (const char*)Buffer.Memory, Buffer.MemorySize, 0); Buffer->ComPort = ComPort;
}
internal void
AddressedDataBufferList_SendAll(addressed_data_buffer_list OutputData, platform_socket_handle SendSocket, context Context)
{
for (addressed_data_buffer* BufferAt = OutputData.Root;
BufferAt != 0;
BufferAt = BufferAt->Next)
{
AddressedDataBuffer_Send(*BufferAt, SendSocket, Context);
}
} }
#define FOLDHAUS_ADDRESSED_DATA_H #define FOLDHAUS_ADDRESSED_DATA_H

View File

@ -5,6 +5,72 @@
// //
#ifndef FOLDHAUS_ASSEMBLY_CPP #ifndef FOLDHAUS_ASSEMBLY_CPP
///////////////////////////
//
// Assembly Array
//
///////////////////////////
internal assembly_array
AssemblyArray_Create(u32 CountMax, gs_memory_arena* Storage)
{
assembly_array Result = {0};
Result.CountMax = CountMax;
Result.Values = PushArray(Storage, assembly, Result.CountMax);
return Result;
}
internal u32
AssemblyArray_Push(assembly_array* Array, assembly Assembly)
{
Assert(Array->Count < Array->CountMax);
u32 Index = Array->Count++;
Array->Values[Index] = Assembly;
return Index;
}
internal assembly*
AssemblyArray_Take(assembly_array* Array)
{
u32 Index = AssemblyArray_Push(Array, {});
assembly* Result = Array->Values + Index;
return Result;
}
internal void
AssemblyArray_RemoveAt(assembly_array* Array, u32 Index)
{
u32 LastAssemblyIndex = --Array->Count;
Array->Values[Index] = Array->Values[LastAssemblyIndex];
}
typedef bool assembly_array_filter_proc(assembly A);
bool AssemblyFilter_OutputsViaSACN(assembly A) { return A.OutputMode == NetworkProtocol_SACN; }
bool AssemblyFilter_OutputsViaUART(assembly A) { return A.OutputMode == NetworkProtocol_UART; }
internal assembly_array
AssemblyArray_Filter(assembly_array Array, assembly_array_filter_proc* Filter, gs_memory_arena* Storage)
{
assembly_array Result = AssemblyArray_Create(Array.Count, Storage);
for (u32 i = 0; i < Array.Count; i++)
{
assembly At = Array.Values[i];
if (Filter(At))
{
AssemblyArray_Push(&Result, At);
}
}
return Result;
}
///////////////////////////
//
// LedSystem
//
///////////////////////////
internal led_system internal led_system
LedSystemInitialize(gs_allocator PlatformMemory, u32 BuffersMax) LedSystemInitialize(gs_allocator PlatformMemory, u32 BuffersMax)
{ {
@ -116,8 +182,7 @@ LoadAssembly (assembly_array* Assemblies, led_system* LedSystem, gs_memory_arena
s32 IndexOfLastSlash = FindLast(Path, '\\'); s32 IndexOfLastSlash = FindLast(Path, '\\');
gs_const_string FileName = Substring(Path, IndexOfLastSlash + 1, Path.Length); gs_const_string FileName = Substring(Path, IndexOfLastSlash + 1, Path.Length);
Assert(Assemblies->Count < Assemblies->CountMax); assembly* NewAssembly = AssemblyArray_Take(Assemblies);
assembly* NewAssembly = &Assemblies->Values[Assemblies->Count++];
NewAssembly->Arena = CreateMemoryArena(Context.ThreadContext.Allocator); NewAssembly->Arena = CreateMemoryArena(Context.ThreadContext.Allocator);
if (ParseAssemblyFile(NewAssembly, FileName, AssemblyFileText, Scratch)) if (ParseAssemblyFile(NewAssembly, FileName, AssemblyFileText, Scratch))
@ -143,8 +208,7 @@ UnloadAssembly (u32 AssemblyIndex, app_state* State, context Context)
assembly* Assembly = &State->Assemblies.Values[AssemblyIndex]; assembly* Assembly = &State->Assemblies.Values[AssemblyIndex];
LedSystemFreeBuffer(&State->LedSystem, Assembly->LedBufferIndex); LedSystemFreeBuffer(&State->LedSystem, Assembly->LedBufferIndex);
FreeMemoryArena(&Assembly->Arena); FreeMemoryArena(&Assembly->Arena);
u32 LastAssemblyIndex = --State->Assemblies.Count; AssemblyArray_RemoveAt(&State->Assemblies, AssemblyIndex);
State->Assemblies.Values[AssemblyIndex] = State->Assemblies.Values[LastAssemblyIndex];
} }
// Querying Assemblies // Querying Assemblies

View File

@ -5,6 +5,15 @@
// //
#ifndef FOLDHAUS_ASSEMBLY_H #ifndef FOLDHAUS_ASSEMBLY_H
enum network_protocol
{
NetworkProtocol_SACN,
NetworkProtocol_ArtNet,
NetworkProtocol_UART,
NetworkProtocol_Count,
};
union pixel union pixel
{ {
struct struct
@ -40,13 +49,24 @@ struct v2_tag
u64 ValueHash; u64 ValueHash;
}; };
struct strip_sacn_addr
{
s32 StartUniverse;
s32 StartChannel;
};
struct strip_uart_addr
{
u8 Channel;
gs_const_string ComPort;
};
struct v2_strip struct v2_strip
{ {
s32 ControlBoxID; // TODO(Peter): I don't think we need this anymore s32 ControlBoxID; // TODO(Peter): I don't think we need this anymore
// TODO(Peter): Add in info for Serial, ArtNet, etc. strip_sacn_addr SACNAddr;
s32 StartUniverse; strip_uart_addr UARTAddr;
s32 StartChannel;
// TODO(Peter): When we create more ways to calculate points, this needs to become // TODO(Peter): When we create more ways to calculate points, this needs to become
// a type enum and a union // a type enum and a union
@ -81,6 +101,8 @@ struct assembly
u32 StripCount; u32 StripCount;
v2_strip* Strips; v2_strip* Strips;
network_protocol OutputMode;
}; };
struct assembly_array struct assembly_array

View File

@ -6,7 +6,7 @@
#ifndef FOLDHAUS_NETWORK_ORDERING_H #ifndef FOLDHAUS_NETWORK_ORDERING_H
// Packs a u8 to a known big endian buffer // Packs a u8 to a known big endian buffer
inline u8* inline u8*
PackB1(u8* ptr, u8 val) PackB1(u8* ptr, u8 val)
{ {
*ptr = val; *ptr = val;
@ -14,14 +14,14 @@ PackB1(u8* ptr, u8 val)
} }
//Unpacks a u8 from a known big endian buffer //Unpacks a u8 from a known big endian buffer
inline u8 inline u8
UpackB1(const u8* ptr) UpackB1(const u8* ptr)
{ {
return *ptr; return *ptr;
} }
//Packs a u8 to a known little endian buffer //Packs a u8 to a known little endian buffer
inline u8* inline u8*
PackL1(u8* ptr, u8 val) PackL1(u8* ptr, u8 val)
{ {
*ptr = val; *ptr = val;
@ -29,30 +29,40 @@ PackL1(u8* ptr, u8 val)
} }
//Unpacks a u8 from a known little endian buffer //Unpacks a u8 from a known little endian buffer
inline u8 inline u8
UpackL1(const u8* ptr) UpackL1(const u8* ptr)
{ {
return *ptr; return *ptr;
} }
//Packs a u16 to a known big endian buffer //Packs a u16 to a known big endian buffer
inline u8* inline u16
PackB2(u16 Value)
{
u16 Result = 0;
u8* Array = (u8*)&Result;
Array[1] = (u8)(Value & 0xFF);
Array[0] = (u8)((Value & 0xFF00) >> 8);
return Result;
}
inline u8*
PackB2(u8* ptr, u16 val) PackB2(u8* ptr, u16 val)
{ {
ptr[1] = (u8)(val & 0xff); ptr[1] = (u8)(val & 0xff);
ptr[0] = (u8)((val & 0xff00) >> 8); ptr[0] = (u8)((val & 0xff00) >> 8);
return ptr + sizeof(val); return ptr + sizeof(val);
} }
//Unpacks a u16 from a known big endian buffer //Unpacks a u16 from a known big endian buffer
inline u16 inline u16
UpackB2(const u8* ptr) UpackB2(const u8* ptr)
{ {
return (u16)(ptr[1] | ptr[0] << 8); return (u16)(ptr[1] | ptr[0] << 8);
} }
//Packs a u16 to a known little endian buffer //Packs a u16 to a known little endian buffer
inline u8* inline u8*
PackL2(u8* ptr, u16 val) PackL2(u8* ptr, u16 val)
{ {
*((u16*)ptr) = val; *((u16*)ptr) = val;
@ -60,14 +70,14 @@ PackL2(u8* ptr, u16 val)
} }
//Unpacks a u16 from a known little endian buffer //Unpacks a u16 from a known little endian buffer
inline u16 inline u16
UpackL2(const u8* ptr) UpackL2(const u8* ptr)
{ {
return *((u16*)ptr); return *((u16*)ptr);
} }
//Packs a u32 to a known big endian buffer //Packs a u32 to a known big endian buffer
inline u8* inline u8*
PackB4(u8* ptr, u32 val) PackB4(u8* ptr, u32 val)
{ {
ptr[3] = (u8) (val & 0xff); ptr[3] = (u8) (val & 0xff);
@ -78,14 +88,14 @@ PackB4(u8* ptr, u32 val)
} }
//Unpacks a u32 from a known big endian buffer //Unpacks a u32 from a known big endian buffer
inline u32 inline u32
UpackB4(const u8* ptr) UpackB4(const u8* ptr)
{ {
return (u32)(ptr[3] | (ptr[2] << 8) | (ptr[1] << 16) | (ptr[0] << 24)); return (u32)(ptr[3] | (ptr[2] << 8) | (ptr[1] << 16) | (ptr[0] << 24));
} }
//Packs a u32 to a known little endian buffer //Packs a u32 to a known little endian buffer
inline u8* inline u8*
PackL4(u8* ptr, u32 val) PackL4(u8* ptr, u32 val)
{ {
*((u32*)ptr) = val; *((u32*)ptr) = val;
@ -93,14 +103,14 @@ PackL4(u8* ptr, u32 val)
} }
//Unpacks a u32 from a known little endian buffer //Unpacks a u32 from a known little endian buffer
inline u32 inline u32
UpackL4(const u8* ptr) UpackL4(const u8* ptr)
{ {
return *((u32*)ptr); return *((u32*)ptr);
} }
//Packs a u64 to a known big endian buffer //Packs a u64 to a known big endian buffer
inline u8* inline u8*
PackB8(u8* ptr, u64 val) PackB8(u8* ptr, u64 val)
{ {
ptr[7] = (u8) (val & 0xff); ptr[7] = (u8) (val & 0xff);
@ -115,17 +125,17 @@ PackB8(u8* ptr, u64 val)
} }
//Unpacks a uint64 from a known big endian buffer //Unpacks a uint64 from a known big endian buffer
inline u64 inline u64
UpackB8(const u8* ptr) UpackB8(const u8* ptr)
{ {
return ((u64)ptr[7]) | (((u64)ptr[6]) << 8) | (((u64)ptr[5]) << 16) | return ((u64)ptr[7]) | (((u64)ptr[6]) << 8) | (((u64)ptr[5]) << 16) |
(((u64)ptr[4]) << 24) | (((u64)ptr[3]) << 32) | (((u64)ptr[4]) << 24) | (((u64)ptr[3]) << 32) |
(((u64)ptr[2]) << 40) | (((u64)ptr[1]) << 48) | (((u64)ptr[2]) << 40) | (((u64)ptr[1]) << 48) |
(((u64)ptr[0]) << 56); (((u64)ptr[0]) << 56);
} }
//Packs a u64 to a known little endian buffer //Packs a u64 to a known little endian buffer
inline u8* inline u8*
PackL8(u8* ptr, u64 val) PackL8(u8* ptr, u64 val)
{ {
*((u64*)ptr) = val; *((u64*)ptr) = val;
@ -133,7 +143,7 @@ PackL8(u8* ptr, u64 val)
} }
//Unpacks a u64 from a known little endian buffer //Unpacks a u64 from a known little endian buffer
inline u64 inline u64
UpackL8(const u8* ptr) UpackL8(const u8* ptr)
{ {
return *((u64*)ptr); return *((u64*)ptr);

View File

@ -208,6 +208,7 @@ InitStreamHeader (u8* Buffer, s32 BufferSize,
cid CID cid CID
) )
{ {
// TODO(pjs): Replace packing with gs_memory_cursor
u8* Cursor = Buffer; u8* Cursor = Buffer;
@ -285,6 +286,7 @@ InitStreamHeader (u8* Buffer, s32 BufferSize,
Cursor = PackB1(Cursor, StartCode); Cursor = PackB1(Cursor, StartCode);
Assert(Cursor - Buffer == STREAM_HEADER_SIZE); Assert(Cursor - Buffer == STREAM_HEADER_SIZE);
} }
// //
@ -306,7 +308,6 @@ SACN_Initialize (context Context)
internal void internal void
SACN_Cleanup(streaming_acn* SACN, context Context) SACN_Cleanup(streaming_acn* SACN, context Context)
{ {
Context.PlatformCloseSocket(SACN->SendSocket);
} }
internal void internal void
@ -360,7 +361,7 @@ SACN_FillBufferWithLeds(u8* BufferStart, u32 BufferSize, v2_strip Strip, led_buf
} }
internal void internal void
SACN_BuildOutputData(streaming_acn* SACN, addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem, gs_memory_arena* OutputStorage) SACN_BuildOutputData(streaming_acn* SACN, addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem)
{ {
SACN_UpdateSequence(SACN); SACN_UpdateSequence(SACN);
@ -378,13 +379,13 @@ SACN_BuildOutputData(streaming_acn* SACN, addressed_data_buffer_list* Output, as
{ {
v2_strip StripAt = Assembly.Strips[StripIdx]; v2_strip StripAt = Assembly.Strips[StripIdx];
u32 V4SendAddress = SACN_GetUniverseSendAddress(StripAt.StartUniverse); u32 V4SendAddress = SACN_GetUniverseSendAddress(StripAt.SACNAddr.StartUniverse);
u32 SendPort = DEFAULT_STREAMING_ACN_PORT; u32 SendPort = DEFAULT_STREAMING_ACN_PORT;
addressed_data_buffer* Data = AddressedDataBufferList_Push(Output, BufferSize, OutputStorage); addressed_data_buffer* Data = AddressedDataBufferList_Push(Output, BufferSize);
AddressedDataBuffer_SetNetworkAddress(Data, V4SendAddress, SendPort); AddressedDataBuffer_SetNetworkAddress(Data, SACN->SendSocket, V4SendAddress, SendPort);
SACN_PrepareBufferHeader(StripAt.StartUniverse, Data->Memory, Data->MemorySize, BufferHeaderSize, *SACN); SACN_PrepareBufferHeader(StripAt.SACNAddr.StartUniverse, Data->Memory, Data->MemorySize, BufferHeaderSize, *SACN);
SACN_FillBufferWithLeds(Data->Memory + BufferHeaderSize, BufferBodySize, StripAt, *LedBuffer); SACN_FillBufferWithLeds(Data->Memory + BufferHeaderSize, BufferBodySize, StripAt, *LedBuffer);
} }
} }

View File

@ -0,0 +1,155 @@
//
// File: foldhaus_uart.h
// Author: Peter Slattery
// Creation Date: 2020-10-01
//
#ifndef FOLDHAUS_UART_H
enum uart_record_type
{
UART_SET_CHANNEL_WS2812 = 1,
UART_DRAW_ALL = 2,
};
// NOTE(pjs): these are data packet structures and need to have 1 byte packing
#pragma pack(push, 1)
struct uart_header
{
u8 MagicNumber[4];
u8 Channel;
u8 RecordType;
};
struct uart_channel
{
u8 ElementsCount;
u8 RedIndex;
u8 GreenIndex;
u8 BlueIndex;
u8 WhiteIndex;
u16 PixelsCount;
};
struct uart_footer
{
u32 CRC;
};
#pragma pack(pop)
global u32 UART_CRCTable[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
internal void
UART_FillHeader(uart_header* Header, u8 Channel, u8 RecordType)
{
Header->MagicNumber[0] = 'U';
Header->MagicNumber[1] = 'P';
Header->MagicNumber[2] = 'X';
Header->MagicNumber[3] = 'L';
Header->Channel = Channel;
Header->RecordType = RecordType;
}
internal void
UART_FillFooter(uart_footer* Footer, u8* BufferStart)
{
// Calculate the CRC
u32 CRC = 0xFFFFFFFF;
u32 BytesCount = (u8*)Footer - BufferStart;
for (u32 i = 0; i < BytesCount; i++)
{
u8 At = BufferStart[i];
// Cameron's Version
CRC = UART_CRCTable[(CRC ^ At) & 0x0F] ^ (CRC >> 4);
CRC = UART_CRCTable[(CRC ^ (At >> 4)) & 0x0F] ^ (CRC >> 4);
#if 0
// The Libraries Version
CRC = (UART_CRCTable[(CRC ^ At) & 0xFF] ^ (CRC >> 8)) & 0xFFFFFFFF;
#endif
}
Footer->CRC = CRC;
}
internal void
UART_SetChannelBuffer_Create(addressed_data_buffer_list* Output, uart_channel ChannelSettings, v2_strip Strip, led_buffer LedBuffer)
{
// NOTE(pjs): This is just here because the information is duplicated and I want to be sure
// to catch the error where they are different
Assert(ChannelSettings.PixelsCount == Strip.LedCount);
u32 BufferSize = sizeof(uart_header) + sizeof(uart_channel);
BufferSize += ChannelSettings.ElementsCount * ChannelSettings.PixelsCount;
BufferSize += sizeof(uart_footer);
addressed_data_buffer* Buffer = AddressedDataBufferList_Push(Output, BufferSize);
AddressedDataBuffer_SetCOMPort(Buffer, Strip.UARTAddr.ComPort);
gs_memory_cursor WriteCursor = CreateMemoryCursor(Buffer->Data);
uart_header* Header = PushStructOnCursor(&WriteCursor, uart_header);
UART_FillHeader(Header, Strip.UARTAddr.Channel, UART_SET_CHANNEL_WS2812);
uart_channel* Channel = PushStructOnCursor(&WriteCursor, uart_channel);
*Channel = ChannelSettings;
for (u32 i = 0; i < Channel->PixelsCount; i++)
{
u32 LedIndex = Strip.LedLUT[i];
pixel Color = LedBuffer.Colors[LedIndex];
u8* OutputPixel = PushArrayOnCursor(&WriteCursor, u8, 3);
OutputPixel[Channel->RedIndex] = Color.R;
OutputPixel[Channel->GreenIndex] = Color.G;
OutputPixel[Channel->BlueIndex] = Color.B;
if (OutputPixel[Channel->ElementsCount == 4])
{
// TODO(pjs): Calculate white from the RGB components?
// Generally we just need a good way to handle the white channel,
// both in the renderer and in output
//OutputPixel[Channel->WhiteIndex] = Color.W;
}
}
uart_footer* Footer = PushStructOnCursor(&WriteCursor, uart_footer);
UART_FillFooter(Footer, Buffer->Memory);
}
internal void
UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem)
{
uart_channel ChannelSettings = {0};
ChannelSettings.ElementsCount = 3;
ChannelSettings.RedIndex = 1;
ChannelSettings.GreenIndex = 2;
ChannelSettings.BlueIndex = 3;
ChannelSettings.WhiteIndex = 0;
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++)
{
v2_strip StripAt = Assembly.Strips[StripIdx];
ChannelSettings.PixelsCount = StripAt.LedCount;
UART_SetChannelBuffer_Create(Output, ChannelSettings, StripAt, *LedBuffer);
}
}
}
#define FOLDHAUS_UART_H
#endif // FOLDHAUS_UART_H

View File

@ -25,8 +25,7 @@ INITIALIZE_APPLICATION(InitializeApplication)
State->Permanent = CreateMemoryArena(Context.ThreadContext.Allocator); State->Permanent = CreateMemoryArena(Context.ThreadContext.Allocator);
State->Transient = Context.ThreadContext.Transient; State->Transient = Context.ThreadContext.Transient;
State->Assemblies.CountMax = 8; State->Assemblies = AssemblyArray_Create(8, &State->Permanent);
State->Assemblies.Values = PushArray(&State->Permanent, assembly, State->Assemblies.CountMax);
State->GlobalLog = PushStruct(State->Transient, event_log); State->GlobalLog = PushStruct(State->Transient, event_log);
*State->GlobalLog = {0}; *State->GlobalLog = {0};
@ -126,9 +125,6 @@ INITIALIZE_APPLICATION(InitializeApplication)
#if 1 #if 1
gs_const_string SculpturePath = ConstString("data/blumen_lumen_v2.fold"); gs_const_string SculpturePath = ConstString("data/blumen_lumen_v2.fold");
LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog); LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog);
SculpturePath = ConstString("data/radialumia_v2.fold");
LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog);
#endif #endif
State->PixelsToWorldScale = .01f; State->PixelsToWorldScale = .01f;
@ -343,38 +339,13 @@ UPDATE_AND_RENDER(UpdateAndRender)
{ {
// NOTE(pjs): Building data buffers to be sent out to the sculpture // NOTE(pjs): Building data buffers to be sent out to the sculpture
// This array is used on the platform side to actually send the information
addressed_data_buffer_list OutputData = {0}; assembly_array SACNAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaSACN, State->Transient);
switch (State->NetworkProtocol) assembly_array UARTAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaUART, State->Transient);
{ SACN_BuildOutputData(&State->SACN, OutputData, SACNAssemblies, &State->LedSystem);
case NetworkProtocol_SACN: UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem);
{
SACN_BuildOutputData(&State->SACN, &OutputData, State->Assemblies, &State->LedSystem, State->Transient);
}break;
case NetworkProtocol_UART:
{
//UART_BuildOutputData(&OutputData, State, State->Transient);
}break;
case NetworkProtocol_ArtNet:
InvalidDefaultCase;
}
// NOTE(pjs): Executing the job to actually send the data
if (0)
{
// TODO(pjs): This should happen on another thread
AddressedDataBufferList_SendAll(OutputData, State->SACN.SendSocket, *Context);
/*
Saved this lien as an example of pushing onto a queue
Context->GeneralWorkQueue->PushWorkOnQueue(Context->GeneralWorkQueue, SACNSendDMXBufferListJob, Job, "SACN Send Data Job");
*/
}
} }
PushRenderOrthographic(RenderBuffer, State->WindowBounds); PushRenderOrthographic(RenderBuffer, State->WindowBounds);
PushRenderClearScreen(RenderBuffer); PushRenderClearScreen(RenderBuffer);

View File

@ -18,8 +18,8 @@
#include "engine/foldhaus_assembly.h" #include "engine/foldhaus_assembly.h"
#include "engine/assembly_parser.cpp" #include "engine/assembly_parser.cpp"
#include "engine/foldhaus_addressed_data.h" #include "engine/sacn/foldhaus_sacn.h"
#include "engine/sacn/sacn.h" #include "engine/uart/foldhaus_uart.h"
typedef struct app_state app_state; typedef struct app_state app_state;
@ -33,15 +33,6 @@ typedef struct app_state app_state;
#include "engine/animation/foldhaus_animation.h" #include "engine/animation/foldhaus_animation.h"
enum network_protocol
{
NetworkProtocol_SACN,
NetworkProtocol_ArtNet,
NetworkProtocol_UART,
NetworkProtocol_Count,
};
struct app_state struct app_state
{ {
gs_memory_arena Permanent; gs_memory_arena Permanent;

View File

@ -33,7 +33,18 @@ global debug_services* GlobalDebugServices;
//#include "..\gs_libs\gs_vector_matrix.h" //#include "..\gs_libs\gs_vector_matrix.h"
#include "..\gs_libs\gs_input.h" #include "..\gs_libs\gs_input.h"
struct platform_network_address
{
s32 Family;
u16 Port;
u32 Address;
};
typedef s32 platform_socket_handle;
typedef s32 platform_network_address_handle;
#include "foldhaus_renderer.h" #include "foldhaus_renderer.h"
#include "engine/foldhaus_addressed_data.h"
typedef struct context context; typedef struct context context;
@ -42,7 +53,7 @@ typedef struct context context;
#define INITIALIZE_APPLICATION(name) void name(context Context) #define INITIALIZE_APPLICATION(name) void name(context Context)
typedef INITIALIZE_APPLICATION(initialize_application); typedef INITIALIZE_APPLICATION(initialize_application);
#define UPDATE_AND_RENDER(name) void name(context* Context, input_queue InputQueue, render_command_buffer* RenderBuffer) #define UPDATE_AND_RENDER(name) void name(context* Context, input_queue InputQueue, render_command_buffer* RenderBuffer, addressed_data_buffer_list* OutputData)
typedef UPDATE_AND_RENDER(update_and_render); typedef UPDATE_AND_RENDER(update_and_render);
#define RELOAD_STATIC_DATA(name) void name(context Context, debug_services* DebugServices) #define RELOAD_STATIC_DATA(name) void name(context Context, debug_services* DebugServices)
@ -102,31 +113,9 @@ struct texture_buffer
#define PLATFORM_GET_GPU_TEXTURE_HANDLE(name) s32 name(u8* Memory, s32 Width, s32 Height) #define PLATFORM_GET_GPU_TEXTURE_HANDLE(name) s32 name(u8* Memory, s32 Width, s32 Height)
typedef PLATFORM_GET_GPU_TEXTURE_HANDLE(platform_get_gpu_texture_handle); typedef PLATFORM_GET_GPU_TEXTURE_HANDLE(platform_get_gpu_texture_handle);
struct platform_network_address
{
s32 Family;
u16 Port;
u32 Address;
};
typedef s32 platform_socket_handle;
typedef s32 platform_network_address_handle;
#define PLATFORM_GET_SOCKET_HANDLE(name) platform_socket_handle name(s32 Multicast_TimeToLive) #define PLATFORM_GET_SOCKET_HANDLE(name) platform_socket_handle name(s32 Multicast_TimeToLive)
typedef PLATFORM_GET_SOCKET_HANDLE(platform_get_socket_handle); typedef PLATFORM_GET_SOCKET_HANDLE(platform_get_socket_handle);
#define PLATFORM_GET_SEND_ADDRESS_HANDLE(name) platform_network_address_handle name(s32 AddressFamily, u16 Port, u32 Address)
typedef PLATFORM_GET_SEND_ADDRESS_HANDLE(platform_get_send_address);
#define PLATFORM_SET_SOCKET_OPTION(name) s32 name(platform_socket_handle SocketHandle, s32 Level, s32 Option, const char* OptionValue, s32 OptionLength)
typedef PLATFORM_SET_SOCKET_OPTION(platform_set_socket_option);
#define PLATFORM_SEND_TO(name) s32 name(platform_socket_handle SocketHandle, u32 Address, u32 Port, const char* Buffer, s32 BufferLength, s32 Flags)
typedef PLATFORM_SEND_TO(platform_send_to);
#define PLATFORM_CLOSE_SOCKET(name) void name(platform_socket_handle SocketHandle)
typedef PLATFORM_CLOSE_SOCKET(platform_close_socket);
// Font // Font
struct platform_font_info struct platform_font_info
{ {
@ -209,9 +198,6 @@ struct context
platform_draw_font_codepoint* PlatformDrawFontCodepoint; platform_draw_font_codepoint* PlatformDrawFontCodepoint;
platform_get_socket_handle* PlatformGetSocketHandle; platform_get_socket_handle* PlatformGetSocketHandle;
platform_set_socket_option* PlatformSetSocketOption;
platform_send_to* PlatformSendTo;
platform_close_socket* PlatformCloseSocket;
}; };

View File

@ -22,6 +22,7 @@
#include "win32_foldhaus_timing.h" #include "win32_foldhaus_timing.h"
#include "win32_foldhaus_work_queue.h" #include "win32_foldhaus_work_queue.h"
#include "win32_foldhaus_serial.h" #include "win32_foldhaus_serial.h"
#include "win32_foldhaus_socket.h"
#include "../foldhaus_renderer.cpp" #include "../foldhaus_renderer.cpp"
@ -40,105 +41,6 @@ PLATFORM_GET_GPU_TEXTURE_HANDLE(Win32GetGPUTextureHandle)
return Handle; return Handle;
} }
struct win32_socket
{
SOCKET Socket;
};
#define SOCKET_DICTIONARY_GROW_SIZE 32
s32 Win32SocketHandleMax;
s32 Win32SocketHandleCount;
win32_socket* SocketValues;
PLATFORM_SET_SOCKET_OPTION(Win32SetSocketOption)
{
s32 SocketIndex = (s32)SocketHandle;
Assert(SocketIndex < Win32SocketHandleCount);
int Error = setsockopt(SocketValues[SocketIndex].Socket, Level, Option, OptionValue, OptionLength);
if (Error == SOCKET_ERROR)
{
Error = WSAGetLastError();
// TODO(Peter): :ErrorLogging
}
return Error;
}
PLATFORM_GET_SOCKET_HANDLE(Win32GetSocketHandle)
{
// NOTE(Peter): These used to be passed in as paramters, but we only use this function
// with AF_INET, SOCK_DGRAM, and Protocol = 0. These are also platform specific values
// so I was having to include windows.h in the platform agnostic code to accomodate that
// function signature.
s32 AddressFamily = AF_INET;
s32 Type = SOCK_DGRAM;
s32 Protocol = 0;
if (Win32SocketHandleCount >= Win32SocketHandleMax)
{
s32 NewDictionaryMax = Win32SocketHandleMax + SOCKET_DICTIONARY_GROW_SIZE;
s32 NewDictionaryDataSize = NewDictionaryMax * sizeof(win32_socket);
u8* DictionaryMemory = (u8*)Win32Alloc(NewDictionaryDataSize, 0);
Assert(DictionaryMemory);
win32_socket* NewValues = (win32_socket*)(DictionaryMemory);
if (SocketValues)
{
CopyMemoryTo(SocketValues, NewValues, sizeof(win32_socket) * NewDictionaryMax);
Win32Free((u8*)SocketValues, sizeof(win32_socket) * Win32SocketHandleCount);
}
SocketValues = NewValues;
Win32SocketHandleMax = NewDictionaryMax;
}
Assert(Win32SocketHandleCount < Win32SocketHandleMax);
s32 NewSocketIndex = Win32SocketHandleCount++;
SocketValues[NewSocketIndex].Socket = socket(AddressFamily, Type, Protocol);
int Error = Win32SetSocketOption(NewSocketIndex, IPPROTO_IP, IP_MULTICAST_TTL,
(const char*)(&Multicast_TimeToLive), sizeof(Multicast_TimeToLive));
return (platform_socket_handle)NewSocketIndex;
}
PLATFORM_SEND_TO(Win32SendTo)
{
s32 SocketIndex = (s32)SocketHandle;
Assert(SocketIndex < Win32SocketHandleCount);
sockaddr_in SockAddress = {};
SockAddress.sin_family = AF_INET;
SockAddress.sin_port = HostToNetU16(Port);
SockAddress.sin_addr.s_addr = HostToNetU32(Address);
s32 LengthSent = sendto(SocketValues[SocketIndex].Socket, Buffer, BufferLength, Flags, (sockaddr*)&SockAddress, sizeof(sockaddr_in));
if (LengthSent == SOCKET_ERROR)
{
s32 Error = WSAGetLastError();
if (Error == 10051)
{
}
else
{
// TODO(Peter): :ErrorLogging
InvalidCodePath;
}
}
return LengthSent;
}
PLATFORM_CLOSE_SOCKET(Win32CloseSocket)
{
s32 SocketIndex = (s32)SocketHandle;
Assert(SocketIndex < Win32SocketHandleCount);
closesocket(SocketValues[SocketIndex].Socket);
}
HDC FontDrawingDC; HDC FontDrawingDC;
HBITMAP FontBitmap; HBITMAP FontBitmap;
HFONT CurrentFont; HFONT CurrentFont;
@ -462,40 +364,6 @@ Win32LoadSystemCursor(char* CursorIdentifier)
return Result; return Result;
} }
internal void
PrintMatrix(m44 M, gs_thread_context Context)
{
gs_string PrintString = AllocatorAllocString(Context.Allocator, 256);
PrintF(&PrintString, "[\n %f %f %f %f\n %f %f %f %f\n %f %f %f %f\n %f %f %f %f\n]\n",
M.Array[0], M.Array[1], M.Array[2], M.Array[3],
M.Array[4], M.Array[5], M.Array[6], M.Array[7],
M.Array[8], M.Array[9], M.Array[10], M.Array[11],
M.Array[12], M.Array[13], M.Array[14], M.Array[15]);
NullTerminate(&PrintString);
OutputDebugStringA(PrintString.Str);
}
v4 PerspectiveDivide(v4 A)
{
v4 Result = {0, 0, 0, 1};
Result.x = A.x / A.w;
Result.y = A.y / A.w;
Result.z = A.z / A.w;
Result.w = A.w;
return Result;
}
v4 ToScreen(v4 P, rect2 WindowBounds)
{
v4 Result = P;
Result.x = RemapR32(P.x, -1, 1, WindowBounds.Min.x, WindowBounds.Max.x);
Result.y = RemapR32(P.y, -1, 1, WindowBounds.Min.y, WindowBounds.Max.y);
return Result;
}
//
// Serial
//
int WINAPI int WINAPI
WinMain ( WinMain (
HINSTANCE HInstance, HINSTANCE HInstance,
@ -506,19 +374,6 @@ WinMain (
{ {
gs_thread_context ThreadContext = Win32CreateThreadContext(); gs_thread_context ThreadContext = Win32CreateThreadContext();
{
gs_const_string TestString = ConstString("Hello World!\nTesting\n");
HANDLE SerialPortHandle = Win32SerialPort_Open("COM5");
Win32SerialPort_SetState(SerialPortHandle, 9600, 8, 0, 1);
Win32SerialPort_Write(SerialPortHandle, StringToData(TestString));
Win32SerialPort_Close(SerialPortHandle);
}
MainWindow = Win32CreateWindow (HInstance, "Foldhaus", 1440, 768, HandleWindowEvents); MainWindow = Win32CreateWindow (HInstance, "Foldhaus", 1440, 768, HandleWindowEvents);
Win32UpdateWindowDimension(&MainWindow); Win32UpdateWindowDimension(&MainWindow);
@ -528,12 +383,23 @@ WinMain (
OpenGLWindowInfo.DepthBits = 0; OpenGLWindowInfo.DepthBits = 0;
CreateOpenGLWindowContext(OpenGLWindowInfo, &MainWindow); CreateOpenGLWindowContext(OpenGLWindowInfo, &MainWindow);
s32 InitialMemorySize = MB(64);
u8* InitialMemory = (u8*)Win32Alloc(InitialMemorySize, 0);
context Context = {};
Context.ThreadContext = ThreadContext;
Context.MemorySize = InitialMemorySize;
Context.MemoryBase = InitialMemory;
Context.WindowBounds = rect2{v2{0, 0}, v2{(r32)MainWindow.Width, (r32)MainWindow.Height}};
Context.Mouse = {0};
gs_memory_arena PlatformPermanent = CreateMemoryArena(Context.ThreadContext.Allocator);
s64 PerformanceCountFrequency = GetPerformanceFrequency(); s64 PerformanceCountFrequency = GetPerformanceFrequency();
s64 LastFrameEnd = GetWallClock(); s64 LastFrameEnd = GetWallClock();
r32 TargetSecondsPerFrame = 1 / 60.0f; r32 TargetSecondsPerFrame = 1 / 60.0f;
r32 LastFrameSecondsElapsed = 0.0f; r32 LastFrameSecondsElapsed = 0.0f;
GlobalDebugServices = (debug_services*)malloc(sizeof(debug_services)); GlobalDebugServices = PushStruct(&PlatformPermanent, debug_services);
s32 DebugThreadCount = PLATFORM_THREAD_COUNT + 1; s32 DebugThreadCount = PLATFORM_THREAD_COUNT + 1;
InitDebugServices(GlobalDebugServices, InitDebugServices(GlobalDebugServices,
PerformanceCountFrequency, PerformanceCountFrequency,
@ -556,7 +422,7 @@ WinMain (
worker_thread_info* WorkerThreads = 0; worker_thread_info* WorkerThreads = 0;
if (PLATFORM_THREAD_COUNT > 0) if (PLATFORM_THREAD_COUNT > 0)
{ {
WorkerThreads = (worker_thread_info*)malloc(sizeof(worker_thread_info) * PLATFORM_THREAD_COUNT); WorkerThreads = PushArray(&PlatformPermanent, worker_thread_info, PLATFORM_THREAD_COUNT);
} }
HANDLE WorkQueueSemaphoreHandle = CreateSemaphoreEx(0, 0, PLATFORM_THREAD_COUNT, 0, 0, SEMAPHORE_ALL_ACCESS); HANDLE WorkQueueSemaphoreHandle = CreateSemaphoreEx(0, 0, PLATFORM_THREAD_COUNT, 0, 0, SEMAPHORE_ALL_ACCESS);
@ -564,7 +430,7 @@ WinMain (
gs_work_queue WorkQueue = {}; gs_work_queue WorkQueue = {};
WorkQueue.SemaphoreHandle = &WorkQueueSemaphoreHandle; WorkQueue.SemaphoreHandle = &WorkQueueSemaphoreHandle;
WorkQueue.JobsMax = 512; WorkQueue.JobsMax = 512;
WorkQueue.Jobs = (gs_threaded_job*)Win32Alloc(sizeof(gs_threaded_job) * WorkQueue.JobsMax, 0); WorkQueue.Jobs = PushArray(&PlatformPermanent, gs_threaded_job, WorkQueue.JobsMax);
WorkQueue.NextJobIndex = 0; WorkQueue.NextJobIndex = 0;
WorkQueue.PushWorkOnQueue = Win32PushWorkOnQueue; WorkQueue.PushWorkOnQueue = Win32PushWorkOnQueue;
WorkQueue.CompleteQueueWork = Win32DoQueueWorkUntilDone; WorkQueue.CompleteQueueWork = Win32DoQueueWorkUntilDone;
@ -577,15 +443,6 @@ WinMain (
WorkerThreads[i].Handle = CreateThread(0, 0, &WorkerThreadProc, (void*)&WorkerThreads[i], 0, 0); WorkerThreads[i].Handle = CreateThread(0, 0, &WorkerThreadProc, (void*)&WorkerThreads[i], 0, 0);
} }
s32 InitialMemorySize = MB(64);
u8* InitialMemory = (u8*)Win32Alloc(InitialMemorySize, 0);
context Context = {};
Context.ThreadContext = ThreadContext;
Context.MemorySize = InitialMemorySize;
Context.MemoryBase = InitialMemory;
Context.WindowBounds = rect2{v2{0, 0}, v2{(r32)MainWindow.Width, (r32)MainWindow.Height}};
Context.Mouse = {0};
// Cursors // Cursors
HCURSOR CursorArrow = Win32LoadSystemCursor(IDC_ARROW); HCURSOR CursorArrow = Win32LoadSystemCursor(IDC_ARROW);
HCURSOR CursorPointer = Win32LoadSystemCursor(IDC_HAND); HCURSOR CursorPointer = Win32LoadSystemCursor(IDC_HAND);
@ -599,9 +456,6 @@ WinMain (
Context.GeneralWorkQueue = &WorkQueue; Context.GeneralWorkQueue = &WorkQueue;
Context.PlatformGetGPUTextureHandle = Win32GetGPUTextureHandle; Context.PlatformGetGPUTextureHandle = Win32GetGPUTextureHandle;
Context.PlatformGetSocketHandle = Win32GetSocketHandle; Context.PlatformGetSocketHandle = Win32GetSocketHandle;
Context.PlatformSetSocketOption = Win32SetSocketOption;
Context.PlatformSendTo = Win32SendTo;
Context.PlatformCloseSocket = Win32CloseSocket;
Context.PlatformGetFontInfo = Win32GetFontInfo; Context.PlatformGetFontInfo = Win32GetFontInfo;
Context.PlatformDrawFontCodepoint = Win32DrawFontCodepoint; Context.PlatformDrawFontCodepoint = Win32DrawFontCodepoint;
@ -619,11 +473,18 @@ WinMain (
WSADATA WSAData; WSADATA WSAData;
WSAStartup(MAKEWORD(2, 2), &WSAData); WSAStartup(MAKEWORD(2, 2), &WSAData);
Win32Sockets = Win32SocketArray_Create(16, &PlatformPermanent);
Win32SerialArray_Create(ThreadContext);
s32 RenderMemorySize = MB(12); s32 RenderMemorySize = MB(12);
u8* RenderMemory = (u8*)Win32Alloc(RenderMemorySize, 0); u8* RenderMemory = PushSize(&PlatformPermanent, RenderMemorySize);
render_command_buffer RenderBuffer = AllocateRenderCommandBuffer(RenderMemory, RenderMemorySize, Win32Realloc); render_command_buffer RenderBuffer = AllocateRenderCommandBuffer(RenderMemory, RenderMemorySize, Win32Realloc);
addressed_data_buffer_list OutputData = {};
OutputData.Arena = AllocatorAllocStruct(Context.ThreadContext.Allocator, gs_memory_arena);
*OutputData.Arena = CreateMemoryArena(Context.ThreadContext.Allocator);
Context.InitializeApplication(Context); Context.InitializeApplication(Context);
Running = true; Running = true;
@ -666,11 +527,48 @@ WinMain (
RenderBuffer.ViewHeight = MainWindow.Height; RenderBuffer.ViewHeight = MainWindow.Height;
Context.DeltaTime = LastFrameSecondsElapsed; Context.DeltaTime = LastFrameSecondsElapsed;
Context.UpdateAndRender(&Context, InputQueue, &RenderBuffer); Context.UpdateAndRender(&Context, InputQueue, &RenderBuffer, &OutputData);
RenderCommandBuffer(RenderBuffer); RenderCommandBuffer(RenderBuffer);
ClearRenderBuffer(&RenderBuffer); ClearRenderBuffer(&RenderBuffer);
if (true)
{
// NOTE(pjs): Send the network data
// TODO(pjs): This should happen on another thread
/*
Saved this lien as an example of pushing onto a queue
Context->GeneralWorkQueue->PushWorkOnQueue(Context->GeneralWorkQueue, SACNSendDMXBufferListJob, Job, "SACN Send Data Job");
*/
for (addressed_data_buffer* BufferAt = OutputData.Root;
BufferAt != 0;
BufferAt = BufferAt->Next)
{
switch(BufferAt->AddressType)
{
case AddressType_NetworkIP:
{
Win32Socket_SendTo(BufferAt->SendSocket,
BufferAt->V4SendAddress,
BufferAt->SendPort,
(const char*)BufferAt->Memory,
BufferAt->MemorySize,
0);
}break;
case AddressType_ComPort:
{
HANDLE SerialPort = Win32SerialArray_GetOrOpen(BufferAt->ComPort, 9600, 8, 0, 1);
Win32SerialPort_Write(SerialPort, BufferAt->Data);
}break;
InvalidDefaultCase;
}
}
}
Context.Mouse.LeftButtonState = GetMouseButtonStateAdvanced(Context.Mouse.LeftButtonState); Context.Mouse.LeftButtonState = GetMouseButtonStateAdvanced(Context.Mouse.LeftButtonState);
Context.Mouse.MiddleButtonState = GetMouseButtonStateAdvanced(Context.Mouse.MiddleButtonState); Context.Mouse.MiddleButtonState = GetMouseButtonStateAdvanced(Context.Mouse.MiddleButtonState);
Context.Mouse.RightButtonState = GetMouseButtonStateAdvanced(Context.Mouse.RightButtonState); Context.Mouse.RightButtonState = GetMouseButtonStateAdvanced(Context.Mouse.RightButtonState);
@ -729,6 +627,11 @@ WinMain (
Context.CleanupApplication(Context); Context.CleanupApplication(Context);
for (s32 SocketIdx = 0; SocketIdx < Win32Sockets.Count; SocketIdx++)
{
Win32Socket_Close(Win32Sockets.Values + SocketIdx);
}
s32 CleanupResult = 0; s32 CleanupResult = 0;
do { do {
CleanupResult = WSACleanup(); CleanupResult = WSACleanup();

View File

@ -5,6 +5,11 @@
// //
#ifndef WIN32_SERIAL_H #ifndef WIN32_SERIAL_H
global u32 Win32SerialHandlesCountMax;
global u32 Win32SerialHandlesCount;
global HANDLE* Win32SerialHandles;
global gs_string* Win32SerialPortNames;
DCB DCB
Win32SerialPort_GetState(HANDLE ComPortHandle) Win32SerialPort_GetState(HANDLE ComPortHandle)
{ {
@ -44,7 +49,26 @@ Win32SerialPort_Open(char* PortName)
0, // Not overlapped I/O 0, // Not overlapped I/O
NULL); NULL);
if (ComPortHandle == INVALID_HANDLE_VALUE) if (ComPortHandle != INVALID_HANDLE_VALUE)
{
COMMTIMEOUTS Timeouts = { 0 };
Timeouts.ReadIntervalTimeout = 50; // in milliseconds
Timeouts.ReadTotalTimeoutConstant = 50; // in milliseconds
Timeouts.ReadTotalTimeoutMultiplier = 10; // in milliseconds
Timeouts.WriteTotalTimeoutConstant = 50; // in milliseconds
Timeouts.WriteTotalTimeoutMultiplier = 10; // in milliseconds
if (SetCommTimeouts(ComPortHandle, &Timeouts))
{
}
else
{
s32 Error = GetLastError();
InvalidCodePath;
}
}
else
{ {
// Error // Error
s32 Error = GetLastError(); s32 Error = GetLastError();
@ -63,6 +87,8 @@ Win32SerialPort_Close(HANDLE PortHandle)
void void
Win32SerialPort_Write(HANDLE PortHandle, gs_data Buffer) Win32SerialPort_Write(HANDLE PortHandle, gs_data Buffer)
{ {
Assert(PortHandle != INVALID_HANDLE_VALUE);
DWORD BytesWritten = 0; DWORD BytesWritten = 0;
if (WriteFile(PortHandle, Buffer.Memory, Buffer.Size, &BytesWritten, NULL)) if (WriteFile(PortHandle, Buffer.Memory, Buffer.Size, &BytesWritten, NULL))
{ {
@ -74,8 +100,64 @@ Win32SerialPort_Write(HANDLE PortHandle, gs_data Buffer)
else else
{ {
OutputDebugStringA("Error: Unable to write to port\n"); OutputDebugStringA("Error: Unable to write to port\n");
s32 Error = GetLastError();
//InvalidCodePath;
} }
} }
/////////////////////////
// Win32SerialArray
void
Win32SerialArray_Create(gs_thread_context Context)
{
Win32SerialHandlesCountMax = 32;
Win32SerialHandlesCount = 0;
Win32SerialHandles = AllocatorAllocArray(Context.Allocator, HANDLE, Win32SerialHandlesCountMax);
Win32SerialPortNames = AllocatorAllocArray(Context.Allocator, gs_string, Win32SerialHandlesCountMax);
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
{
Win32SerialPortNames[i] = AllocatorAllocString(Context.Allocator, 256);
}
}
void
Win32SerialArray_Push(HANDLE SerialHandle, gs_const_string PortName)
{
Assert(Win32SerialHandlesCount < Win32SerialHandlesCountMax);
u32 Index = Win32SerialHandlesCount++;
Win32SerialHandles[Index] = SerialHandle;
PrintF(&Win32SerialPortNames[Index], "%S", PortName);
}
HANDLE
Win32SerialArray_Get(gs_const_string PortName)
{
HANDLE PortHandle = INVALID_HANDLE_VALUE;
for (u32 i = 0; i < Win32SerialHandlesCount; i++)
{
if (StringsEqual(Win32SerialPortNames[i].ConstString, PortName))
{
PortHandle = Win32SerialHandles[i];
break;
}
}
return PortHandle;
}
HANDLE
Win32SerialArray_GetOrOpen(gs_const_string PortName, u32 BaudRate, u8 ByteSize, u8 Parity, u8 StopBits)
{
HANDLE PortHandle = Win32SerialArray_Get(PortName);
if (PortHandle == INVALID_HANDLE_VALUE)
{
Assert(IsNullTerminated(PortName));
PortHandle = Win32SerialPort_Open(PortName.Str);
Win32SerialPort_SetState(PortHandle, BaudRate, ByteSize, Parity, StopBits);
Win32SerialArray_Push(PortHandle, PortName);
}
return PortHandle;
}
#define WIN32_SERIAL_H #define WIN32_SERIAL_H
#endif // WIN32_SERIAL_H #endif // WIN32_SERIAL_H

View File

@ -0,0 +1,140 @@
//
// File: win32_foldhaus_socket.h
// Author: Peter Slattery
// Creation Date: 2020-10-03
//
#ifndef WIN32_FOLDHAUS_SOCKET_H
struct win32_socket
{
SOCKET Socket;
};
struct win32_socket_array
{
win32_socket* Values;
s32 CountMax;
s32 Count;
};
//////////////////////
//
// Win32 Socket Array
internal win32_socket_array
Win32SocketArray_Create(u32 CountMax, gs_memory_arena* Storage)
{
win32_socket_array Result = {};
Result.CountMax = CountMax;
Result.Values = PushArray(Storage, win32_socket, CountMax);
return Result;
}
internal s32
Win32SocketArray_Take(win32_socket_array* Array)
{
Assert(Array->Count < Array->CountMax);
s32 Result = Array->Count++;
win32_socket* Socket = Array->Values + Result;
*Socket = {0};
return Result;
}
internal win32_socket*
Win32SocketArray_Get(win32_socket_array Array, s32 Index)
{
Assert(Index < Array.Count);
win32_socket* Result = Array.Values + Index;
return Result;
}
//////////////////////
//
// Win32 Socket System
global win32_socket_array Win32Sockets;
internal s32
Win32Socket_SetOption(win32_socket* Socket, s32 Level, s32 Option, const char* OptionValue, s32 OptionLength)
{
int Error = setsockopt(Socket->Socket, Level, Option, OptionValue, OptionLength);
if (Error == SOCKET_ERROR)
{
Error = WSAGetLastError();
// TODO(Peter): :ErrorLogging
}
return Error;
}
internal s32
Win32Socket_SetOption(platform_socket_handle SocketHandle, s32 Level, s32 Option, const char* OptionValue, s32 OptionLength)
{
win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, (s32)SocketHandle);
return Win32Socket_SetOption(Socket, Level, Option, OptionValue, OptionLength);
}
PLATFORM_GET_SOCKET_HANDLE(Win32GetSocketHandle)
{
// NOTE(Peter): These used to be passed in as paramters, but we only use this function
// with AF_INET, SOCK_DGRAM, and Protocol = 0. These are also platform specific values
// so I was having to include windows.h in the platform agnostic code to accomodate that
// function signature.
s32 AddressFamily = AF_INET;
s32 Type = SOCK_DGRAM;
s32 Protocol = 0;
s32 Result = Win32SocketArray_Take(&Win32Sockets);
win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, Result);
Socket->Socket = socket(AddressFamily, Type, Protocol);
if (Socket->Socket != INVALID_SOCKET)
{
int Error = Win32Socket_SetOption(Socket, IPPROTO_IP, IP_MULTICAST_TTL,
(const char*)(&Multicast_TimeToLive), sizeof(Multicast_TimeToLive));
}
else
{
s32 Error = WSAGetLastError();
InvalidCodePath;
}
return (platform_socket_handle)Result;
}
internal s32
Win32Socket_SendTo(platform_socket_handle SocketHandle, u32 Address, u32 Port, const char* Buffer, s32 BufferLength, s32 Flags)
{
win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, (s32)SocketHandle);
sockaddr_in SockAddress = {};
SockAddress.sin_family = AF_INET;
SockAddress.sin_port = HostToNetU16(Port);
SockAddress.sin_addr.s_addr = HostToNetU32(Address);
s32 LengthSent = sendto(Socket->Socket, Buffer, BufferLength, Flags, (sockaddr*)&SockAddress, sizeof(sockaddr_in));
if (LengthSent == SOCKET_ERROR)
{
s32 Error = WSAGetLastError();
if (Error == 10051)
{
}
else
{
// TODO(Peter): :ErrorLogging
InvalidCodePath;
}
}
return LengthSent;
}
internal void
Win32Socket_Close(win32_socket* Socket)
{
closesocket(Socket->Socket);
Socket->Socket = INVALID_SOCKET;
}
#define WIN32_FOLDHAUS_SOCKET_H
#endif // WIN32_FOLDHAUS_SOCKET_H

View File

@ -2235,6 +2235,9 @@ PushSizeOnCursor_(gs_memory_cursor* Cursor, u64 Size, char* Location)
#define PushStructOnCursor(cursor,type) (type*)PushSizeOnCursor_((cursor), sizeof(type), FileNameAndLineNumberString).Memory #define PushStructOnCursor(cursor,type) (type*)PushSizeOnCursor_((cursor), sizeof(type), FileNameAndLineNumberString).Memory
#define PushArrayOnCursor(cursor,type,count) (type*)PushSizeOnCursor_((cursor), sizeof(type) * (count), FileNameAndLineNumberString).Memory #define PushArrayOnCursor(cursor,type,count) (type*)PushSizeOnCursor_((cursor), sizeof(type) * (count), FileNameAndLineNumberString).Memory
#define MemoryCursor_WriteValue(cursor, type, value) *PushStructOnCursor(cursor, type) = value
#define MemoryCursor_WriteBuffer(cursor, buf, len) CopyMemoryTo((u8*)(buf), PushArrayOnCursor((cursor), u8, (len)), (len))
internal void internal void
PopSizeOnCursor(gs_memory_cursor* Cursor, u64 Size) PopSizeOnCursor(gs_memory_cursor* Cursor, u64 Size)
{ {