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:
parent
0022efea8e
commit
83ed23280a
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -36,10 +36,20 @@ UpackL1(const u8* ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Packs a u16 to a known big endian buffer
|
//Packs a u16 to a known big endian buffer
|
||||||
|
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*
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue