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
|
||||
|
||||
// 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
|
||||
{
|
||||
AssemblyField_AssemblyName,
|
||||
AssemblyField_AssemblyScale,
|
||||
AssemblyField_AssemblyCenter,
|
||||
AssemblyField_LedStripCount,
|
||||
AssemblyField_OutputMode,
|
||||
|
||||
AssemblyField_LedStrip,
|
||||
AssemblyField_ControlBoxId,
|
||||
AssemblyField_StartUniverse,
|
||||
AssemblyField_StartChannel,
|
||||
|
||||
AssemblyField_OutputSACN,
|
||||
AssemblyField_SACN_StartUniverse,
|
||||
AssemblyField_SACN_StartChannel,
|
||||
|
||||
AssemblyField_OutputUART,
|
||||
AssemblyField_UART_Channel,
|
||||
AssemblyField_UART_ComPort,
|
||||
|
||||
AssemblyField_PointPlacementType,
|
||||
AssemblyField_InterpolatePoints,
|
||||
AssemblyField_Start,
|
||||
|
@ -34,12 +50,17 @@ global char* AssemblyFieldIdentifiers[] = {
|
|||
"assembly_scale", // AssemblyField_AssemblyScale
|
||||
"assembly_center", // AssemblyField_AssemblyCenter
|
||||
"led_strip_count", // AssemblyField_LedStripCount
|
||||
"output_mode", // AssemblyField_OutputMode
|
||||
|
||||
"led_strip", // AssemblyField_LedStrip
|
||||
|
||||
"control_box_id", // AssemblyField_ControlBoxId
|
||||
"start_universe", // AssemblyField_StartUniverse
|
||||
"start_channel", // AssemblyField_StartChannel
|
||||
"output_sacn", // AssemblyField_OutputSACN
|
||||
"start_universe", // AssemblyField_SACN_StartUniverse
|
||||
"start_channel", // AssemblyField_SACN_StartChannel
|
||||
|
||||
"output_uart", // AssemblyField_OutputUART
|
||||
"channel", // AssemblyField_UART_Channel
|
||||
"com_port", // AssemblyField_UART_ComPort
|
||||
|
||||
"point_placement_type", // AssemblyField_PointPlacementType
|
||||
"interpolate_points", // AssemblyField_InterpolatePoints
|
||||
|
@ -158,8 +179,11 @@ TokenizerPushError(assembly_tokenizer* T, char* ErrorString)
|
|||
EatToNewLine(T);
|
||||
}
|
||||
|
||||
#define PARSER_FIELD_REQUIRED true
|
||||
#define PARSER_FIELD_OPTIONAL false
|
||||
|
||||
internal bool
|
||||
ReadFieldIdentifier(assembly_field Field, assembly_tokenizer* T)
|
||||
ReadFieldIdentifier(assembly_field Field, assembly_tokenizer* T, bool Required = true)
|
||||
{
|
||||
bool Result = false;
|
||||
if (AdvanceIfTokenEquals(T, AssemblyFieldIdentifiers[Field]))
|
||||
|
@ -170,10 +194,12 @@ ReadFieldIdentifier(assembly_field Field, assembly_tokenizer* T)
|
|||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (Required)
|
||||
{
|
||||
TokenizerPushError(T, "Field Identifier Invalid");
|
||||
}
|
||||
|
@ -350,10 +376,10 @@ ReadV3Field(assembly_field Field, assembly_tokenizer* T)
|
|||
}
|
||||
|
||||
internal bool
|
||||
ReadStructOpening(assembly_field Field, assembly_tokenizer* T)
|
||||
ReadStructOpening(assembly_field Field, assembly_tokenizer* T, bool Required = true)
|
||||
{
|
||||
bool Result = false;
|
||||
if (ReadFieldIdentifier(Field, T))
|
||||
if (ReadFieldIdentifier(Field, T, Required))
|
||||
{
|
||||
if (AdvanceIfTokenEquals(T, "{"))
|
||||
{
|
||||
|
@ -400,14 +426,46 @@ ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileTe
|
|||
Assembly->StripCount = ReadIntField(AssemblyField_LedStripCount, &Tokenizer);
|
||||
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++)
|
||||
{
|
||||
v2_strip* StripAt = Assembly->Strips + i;
|
||||
if (ReadStructOpening(AssemblyField_LedStrip, &Tokenizer))
|
||||
{
|
||||
StripAt->ControlBoxID = ReadIntField(AssemblyField_ControlBoxId, &Tokenizer);
|
||||
StripAt->StartUniverse = ReadIntField(AssemblyField_StartUniverse, &Tokenizer);
|
||||
StripAt->StartChannel = ReadIntField(AssemblyField_StartChannel, &Tokenizer);
|
||||
if (ReadStructOpening(AssemblyField_OutputSACN, &Tokenizer, PARSER_FIELD_OPTIONAL))
|
||||
{
|
||||
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
|
||||
gs_string PointPlacementType = ReadStringField(AssemblyField_PointPlacementType, &Tokenizer, &Assembly->Arena);
|
||||
|
|
|
@ -12,66 +12,86 @@
|
|||
enum data_buffer_address_type
|
||||
{
|
||||
AddressType_NetworkIP,
|
||||
AddressType_ComPort,
|
||||
AddressType_Invalid,
|
||||
};
|
||||
|
||||
struct addressed_data_buffer
|
||||
{
|
||||
u8* Memory;
|
||||
u32 MemorySize;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u8* Memory;
|
||||
u32 MemorySize;
|
||||
};
|
||||
gs_data Data;
|
||||
};
|
||||
|
||||
data_buffer_address_type AddressType;
|
||||
|
||||
// IP Address
|
||||
platform_socket_handle SendSocket;
|
||||
u32 V4SendAddress;
|
||||
u32 SendPort;
|
||||
|
||||
// COM
|
||||
gs_const_string ComPort;
|
||||
|
||||
addressed_data_buffer* Next;
|
||||
};
|
||||
|
||||
struct addressed_data_buffer_list
|
||||
{
|
||||
gs_memory_arena* Arena;
|
||||
addressed_data_buffer* Root;
|
||||
addressed_data_buffer* Head;
|
||||
};
|
||||
|
||||
internal addressed_data_buffer*
|
||||
AddressedDataBufferList_Push(addressed_data_buffer_list* List, u32 BufferSize, gs_memory_arena* Storage)
|
||||
internal void
|
||||
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->MemorySize = BufferSize;
|
||||
Result->Memory = PushArray(Storage, u8, Result->MemorySize);
|
||||
Result->MemorySize = 0;
|
||||
Result->Memory = 0;
|
||||
|
||||
SLLPushOrInit(List->Root, List->Head, 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
|
||||
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->SendSocket = SendSocket;
|
||||
Buffer->V4SendAddress = V4SendAddress;
|
||||
Buffer->SendPort = SendPort;
|
||||
}
|
||||
|
||||
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;
|
||||
Context.PlatformSendTo(SendSocket, Buffer.V4SendAddress, Buffer.SendPort, (const char*)Buffer.Memory, Buffer.MemorySize, 0);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
Buffer->AddressType = AddressType_ComPort;
|
||||
Buffer->ComPort = ComPort;
|
||||
}
|
||||
|
||||
#define FOLDHAUS_ADDRESSED_DATA_H
|
||||
|
|
|
@ -5,6 +5,72 @@
|
|||
//
|
||||
#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
|
||||
LedSystemInitialize(gs_allocator PlatformMemory, u32 BuffersMax)
|
||||
{
|
||||
|
@ -116,8 +182,7 @@ LoadAssembly (assembly_array* Assemblies, led_system* LedSystem, gs_memory_arena
|
|||
s32 IndexOfLastSlash = FindLast(Path, '\\');
|
||||
gs_const_string FileName = Substring(Path, IndexOfLastSlash + 1, Path.Length);
|
||||
|
||||
Assert(Assemblies->Count < Assemblies->CountMax);
|
||||
assembly* NewAssembly = &Assemblies->Values[Assemblies->Count++];
|
||||
assembly* NewAssembly = AssemblyArray_Take(Assemblies);
|
||||
NewAssembly->Arena = CreateMemoryArena(Context.ThreadContext.Allocator);
|
||||
|
||||
if (ParseAssemblyFile(NewAssembly, FileName, AssemblyFileText, Scratch))
|
||||
|
@ -143,8 +208,7 @@ UnloadAssembly (u32 AssemblyIndex, app_state* State, context Context)
|
|||
assembly* Assembly = &State->Assemblies.Values[AssemblyIndex];
|
||||
LedSystemFreeBuffer(&State->LedSystem, Assembly->LedBufferIndex);
|
||||
FreeMemoryArena(&Assembly->Arena);
|
||||
u32 LastAssemblyIndex = --State->Assemblies.Count;
|
||||
State->Assemblies.Values[AssemblyIndex] = State->Assemblies.Values[LastAssemblyIndex];
|
||||
AssemblyArray_RemoveAt(&State->Assemblies, AssemblyIndex);
|
||||
}
|
||||
|
||||
// Querying Assemblies
|
||||
|
|
|
@ -5,6 +5,15 @@
|
|||
//
|
||||
#ifndef FOLDHAUS_ASSEMBLY_H
|
||||
|
||||
enum network_protocol
|
||||
{
|
||||
NetworkProtocol_SACN,
|
||||
NetworkProtocol_ArtNet,
|
||||
NetworkProtocol_UART,
|
||||
|
||||
NetworkProtocol_Count,
|
||||
};
|
||||
|
||||
union pixel
|
||||
{
|
||||
struct
|
||||
|
@ -40,13 +49,24 @@ struct v2_tag
|
|||
u64 ValueHash;
|
||||
};
|
||||
|
||||
struct strip_sacn_addr
|
||||
{
|
||||
s32 StartUniverse;
|
||||
s32 StartChannel;
|
||||
};
|
||||
|
||||
struct strip_uart_addr
|
||||
{
|
||||
u8 Channel;
|
||||
gs_const_string ComPort;
|
||||
};
|
||||
|
||||
struct v2_strip
|
||||
{
|
||||
s32 ControlBoxID; // TODO(Peter): I don't think we need this anymore
|
||||
|
||||
// TODO(Peter): Add in info for Serial, ArtNet, etc.
|
||||
s32 StartUniverse;
|
||||
s32 StartChannel;
|
||||
strip_sacn_addr SACNAddr;
|
||||
strip_uart_addr UARTAddr;
|
||||
|
||||
// TODO(Peter): When we create more ways to calculate points, this needs to become
|
||||
// a type enum and a union
|
||||
|
@ -81,6 +101,8 @@ struct assembly
|
|||
|
||||
u32 StripCount;
|
||||
v2_strip* Strips;
|
||||
|
||||
network_protocol OutputMode;
|
||||
};
|
||||
|
||||
struct assembly_array
|
||||
|
|
|
@ -36,10 +36,20 @@ UpackL1(const u8* ptr)
|
|||
}
|
||||
|
||||
//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*
|
||||
PackB2(u8* ptr, u16 val)
|
||||
{
|
||||
ptr[1] = (u8)(val & 0xff);
|
||||
ptr[1] = (u8)(val & 0xff);
|
||||
ptr[0] = (u8)((val & 0xff00) >> 8);
|
||||
return ptr + sizeof(val);
|
||||
}
|
||||
|
|
|
@ -208,6 +208,7 @@ InitStreamHeader (u8* Buffer, s32 BufferSize,
|
|||
cid CID
|
||||
)
|
||||
{
|
||||
// TODO(pjs): Replace packing with gs_memory_cursor
|
||||
|
||||
u8* Cursor = Buffer;
|
||||
|
||||
|
@ -285,6 +286,7 @@ InitStreamHeader (u8* Buffer, s32 BufferSize,
|
|||
Cursor = PackB1(Cursor, StartCode);
|
||||
|
||||
Assert(Cursor - Buffer == STREAM_HEADER_SIZE);
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -306,7 +308,6 @@ SACN_Initialize (context Context)
|
|||
internal void
|
||||
SACN_Cleanup(streaming_acn* SACN, context Context)
|
||||
{
|
||||
Context.PlatformCloseSocket(SACN->SendSocket);
|
||||
}
|
||||
|
||||
internal void
|
||||
|
@ -360,7 +361,7 @@ SACN_FillBufferWithLeds(u8* BufferStart, u32 BufferSize, v2_strip Strip, led_buf
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -378,13 +379,13 @@ SACN_BuildOutputData(streaming_acn* SACN, addressed_data_buffer_list* Output, as
|
|||
{
|
||||
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;
|
||||
|
||||
addressed_data_buffer* Data = AddressedDataBufferList_Push(Output, BufferSize, OutputStorage);
|
||||
AddressedDataBuffer_SetNetworkAddress(Data, V4SendAddress, SendPort);
|
||||
addressed_data_buffer* Data = AddressedDataBufferList_Push(Output, BufferSize);
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -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->Transient = Context.ThreadContext.Transient;
|
||||
|
||||
State->Assemblies.CountMax = 8;
|
||||
State->Assemblies.Values = PushArray(&State->Permanent, assembly, State->Assemblies.CountMax);
|
||||
State->Assemblies = AssemblyArray_Create(8, &State->Permanent);
|
||||
|
||||
State->GlobalLog = PushStruct(State->Transient, event_log);
|
||||
*State->GlobalLog = {0};
|
||||
|
@ -126,9 +125,6 @@ INITIALIZE_APPLICATION(InitializeApplication)
|
|||
#if 1
|
||||
gs_const_string SculpturePath = ConstString("data/blumen_lumen_v2.fold");
|
||||
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
|
||||
|
||||
State->PixelsToWorldScale = .01f;
|
||||
|
@ -343,38 +339,13 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
|||
|
||||
{
|
||||
// NOTE(pjs): Building data buffers to be sent out to the sculpture
|
||||
|
||||
addressed_data_buffer_list OutputData = {0};
|
||||
switch (State->NetworkProtocol)
|
||||
{
|
||||
case NetworkProtocol_SACN:
|
||||
{
|
||||
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");
|
||||
*/
|
||||
}
|
||||
// This array is used on the platform side to actually send the information
|
||||
assembly_array SACNAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaSACN, State->Transient);
|
||||
assembly_array UARTAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaUART, State->Transient);
|
||||
SACN_BuildOutputData(&State->SACN, OutputData, SACNAssemblies, &State->LedSystem);
|
||||
UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem);
|
||||
}
|
||||
|
||||
|
||||
PushRenderOrthographic(RenderBuffer, State->WindowBounds);
|
||||
PushRenderClearScreen(RenderBuffer);
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#include "engine/foldhaus_assembly.h"
|
||||
#include "engine/assembly_parser.cpp"
|
||||
|
||||
#include "engine/foldhaus_addressed_data.h"
|
||||
#include "engine/sacn/sacn.h"
|
||||
#include "engine/sacn/foldhaus_sacn.h"
|
||||
#include "engine/uart/foldhaus_uart.h"
|
||||
|
||||
typedef struct app_state app_state;
|
||||
|
||||
|
@ -33,15 +33,6 @@ typedef struct app_state app_state;
|
|||
|
||||
#include "engine/animation/foldhaus_animation.h"
|
||||
|
||||
enum network_protocol
|
||||
{
|
||||
NetworkProtocol_SACN,
|
||||
NetworkProtocol_ArtNet,
|
||||
NetworkProtocol_UART,
|
||||
|
||||
NetworkProtocol_Count,
|
||||
};
|
||||
|
||||
struct app_state
|
||||
{
|
||||
gs_memory_arena Permanent;
|
||||
|
|
|
@ -33,7 +33,18 @@ global debug_services* GlobalDebugServices;
|
|||
//#include "..\gs_libs\gs_vector_matrix.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 "engine/foldhaus_addressed_data.h"
|
||||
|
||||
typedef struct context context;
|
||||
|
||||
|
@ -42,7 +53,7 @@ typedef struct context context;
|
|||
#define INITIALIZE_APPLICATION(name) void name(context Context)
|
||||
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);
|
||||
|
||||
#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)
|
||||
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)
|
||||
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
|
||||
struct platform_font_info
|
||||
{
|
||||
|
@ -209,9 +198,6 @@ struct context
|
|||
platform_draw_font_codepoint* PlatformDrawFontCodepoint;
|
||||
|
||||
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_work_queue.h"
|
||||
#include "win32_foldhaus_serial.h"
|
||||
#include "win32_foldhaus_socket.h"
|
||||
|
||||
#include "../foldhaus_renderer.cpp"
|
||||
|
||||
|
@ -40,105 +41,6 @@ PLATFORM_GET_GPU_TEXTURE_HANDLE(Win32GetGPUTextureHandle)
|
|||
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;
|
||||
HBITMAP FontBitmap;
|
||||
HFONT CurrentFont;
|
||||
|
@ -462,40 +364,6 @@ Win32LoadSystemCursor(char* CursorIdentifier)
|
|||
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
|
||||
WinMain (
|
||||
HINSTANCE HInstance,
|
||||
|
@ -506,19 +374,6 @@ WinMain (
|
|||
{
|
||||
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);
|
||||
Win32UpdateWindowDimension(&MainWindow);
|
||||
|
||||
|
@ -528,12 +383,23 @@ WinMain (
|
|||
OpenGLWindowInfo.DepthBits = 0;
|
||||
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 LastFrameEnd = GetWallClock();
|
||||
r32 TargetSecondsPerFrame = 1 / 60.0f;
|
||||
r32 LastFrameSecondsElapsed = 0.0f;
|
||||
|
||||
GlobalDebugServices = (debug_services*)malloc(sizeof(debug_services));
|
||||
GlobalDebugServices = PushStruct(&PlatformPermanent, debug_services);
|
||||
s32 DebugThreadCount = PLATFORM_THREAD_COUNT + 1;
|
||||
InitDebugServices(GlobalDebugServices,
|
||||
PerformanceCountFrequency,
|
||||
|
@ -556,7 +422,7 @@ WinMain (
|
|||
worker_thread_info* WorkerThreads = 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);
|
||||
|
@ -564,7 +430,7 @@ WinMain (
|
|||
gs_work_queue WorkQueue = {};
|
||||
WorkQueue.SemaphoreHandle = &WorkQueueSemaphoreHandle;
|
||||
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.PushWorkOnQueue = Win32PushWorkOnQueue;
|
||||
WorkQueue.CompleteQueueWork = Win32DoQueueWorkUntilDone;
|
||||
|
@ -577,15 +443,6 @@ WinMain (
|
|||
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
|
||||
HCURSOR CursorArrow = Win32LoadSystemCursor(IDC_ARROW);
|
||||
HCURSOR CursorPointer = Win32LoadSystemCursor(IDC_HAND);
|
||||
|
@ -599,9 +456,6 @@ WinMain (
|
|||
Context.GeneralWorkQueue = &WorkQueue;
|
||||
Context.PlatformGetGPUTextureHandle = Win32GetGPUTextureHandle;
|
||||
Context.PlatformGetSocketHandle = Win32GetSocketHandle;
|
||||
Context.PlatformSetSocketOption = Win32SetSocketOption;
|
||||
Context.PlatformSendTo = Win32SendTo;
|
||||
Context.PlatformCloseSocket = Win32CloseSocket;
|
||||
Context.PlatformGetFontInfo = Win32GetFontInfo;
|
||||
Context.PlatformDrawFontCodepoint = Win32DrawFontCodepoint;
|
||||
|
||||
|
@ -619,11 +473,18 @@ WinMain (
|
|||
|
||||
WSADATA WSAData;
|
||||
WSAStartup(MAKEWORD(2, 2), &WSAData);
|
||||
Win32Sockets = Win32SocketArray_Create(16, &PlatformPermanent);
|
||||
|
||||
Win32SerialArray_Create(ThreadContext);
|
||||
|
||||
s32 RenderMemorySize = MB(12);
|
||||
u8* RenderMemory = (u8*)Win32Alloc(RenderMemorySize, 0);
|
||||
u8* RenderMemory = PushSize(&PlatformPermanent, RenderMemorySize);
|
||||
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);
|
||||
|
||||
Running = true;
|
||||
|
@ -666,11 +527,48 @@ WinMain (
|
|||
RenderBuffer.ViewHeight = MainWindow.Height;
|
||||
Context.DeltaTime = LastFrameSecondsElapsed;
|
||||
|
||||
Context.UpdateAndRender(&Context, InputQueue, &RenderBuffer);
|
||||
Context.UpdateAndRender(&Context, InputQueue, &RenderBuffer, &OutputData);
|
||||
|
||||
RenderCommandBuffer(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.MiddleButtonState = GetMouseButtonStateAdvanced(Context.Mouse.MiddleButtonState);
|
||||
Context.Mouse.RightButtonState = GetMouseButtonStateAdvanced(Context.Mouse.RightButtonState);
|
||||
|
@ -729,6 +627,11 @@ WinMain (
|
|||
|
||||
Context.CleanupApplication(Context);
|
||||
|
||||
for (s32 SocketIdx = 0; SocketIdx < Win32Sockets.Count; SocketIdx++)
|
||||
{
|
||||
Win32Socket_Close(Win32Sockets.Values + SocketIdx);
|
||||
}
|
||||
|
||||
s32 CleanupResult = 0;
|
||||
do {
|
||||
CleanupResult = WSACleanup();
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
//
|
||||
#ifndef WIN32_SERIAL_H
|
||||
|
||||
global u32 Win32SerialHandlesCountMax;
|
||||
global u32 Win32SerialHandlesCount;
|
||||
global HANDLE* Win32SerialHandles;
|
||||
global gs_string* Win32SerialPortNames;
|
||||
|
||||
DCB
|
||||
Win32SerialPort_GetState(HANDLE ComPortHandle)
|
||||
{
|
||||
|
@ -44,7 +49,26 @@ Win32SerialPort_Open(char* PortName)
|
|||
0, // Not overlapped I/O
|
||||
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
|
||||
s32 Error = GetLastError();
|
||||
|
@ -63,6 +87,8 @@ Win32SerialPort_Close(HANDLE PortHandle)
|
|||
void
|
||||
Win32SerialPort_Write(HANDLE PortHandle, gs_data Buffer)
|
||||
{
|
||||
Assert(PortHandle != INVALID_HANDLE_VALUE);
|
||||
|
||||
DWORD BytesWritten = 0;
|
||||
if (WriteFile(PortHandle, Buffer.Memory, Buffer.Size, &BytesWritten, NULL))
|
||||
{
|
||||
|
@ -74,8 +100,64 @@ Win32SerialPort_Write(HANDLE PortHandle, gs_data Buffer)
|
|||
else
|
||||
{
|
||||
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
|
||||
#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 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
|
||||
PopSizeOnCursor(gs_memory_cursor* Cursor, u64 Size)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue