diff --git a/src/app/engine/assembly_parser.cpp b/src/app/engine/assembly_parser.cpp index d23b596..636c11c 100644 --- a/src/app/engine/assembly_parser.cpp +++ b/src/app/engine/assembly_parser.cpp @@ -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); diff --git a/src/app/engine/foldhaus_addressed_data.h b/src/app/engine/foldhaus_addressed_data.h index 6436a0d..79a84de 100644 --- a/src/app/engine/foldhaus_addressed_data.h +++ b/src/app/engine/foldhaus_addressed_data.h @@ -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 diff --git a/src/app/engine/foldhaus_assembly.cpp b/src/app/engine/foldhaus_assembly.cpp index afb3919..5be7342 100644 --- a/src/app/engine/foldhaus_assembly.cpp +++ b/src/app/engine/foldhaus_assembly.cpp @@ -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 diff --git a/src/app/engine/foldhaus_assembly.h b/src/app/engine/foldhaus_assembly.h index a4ebd0e..c702a3b 100644 --- a/src/app/engine/foldhaus_assembly.h +++ b/src/app/engine/foldhaus_assembly.h @@ -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 diff --git a/src/app/engine/foldhaus_network_ordering.h b/src/app/engine/foldhaus_network_ordering.h index 65b60c7..05e5afd 100644 --- a/src/app/engine/foldhaus_network_ordering.h +++ b/src/app/engine/foldhaus_network_ordering.h @@ -6,7 +6,7 @@ #ifndef FOLDHAUS_NETWORK_ORDERING_H // Packs a u8 to a known big endian buffer -inline u8* +inline u8* PackB1(u8* ptr, u8 val) { *ptr = val; @@ -14,14 +14,14 @@ PackB1(u8* ptr, u8 val) } //Unpacks a u8 from a known big endian buffer -inline u8 +inline u8 UpackB1(const u8* ptr) { return *ptr; } //Packs a u8 to a known little endian buffer -inline u8* +inline u8* PackL1(u8* ptr, u8 val) { *ptr = val; @@ -29,30 +29,40 @@ PackL1(u8* ptr, u8 val) } //Unpacks a u8 from a known little endian buffer -inline u8 +inline u8 UpackL1(const u8* ptr) { return *ptr; } //Packs a u16 to a known big endian buffer -inline u8* +inline u16 +PackB2(u16 Value) +{ + u16 Result = 0; + u8* Array = (u8*)&Result; + Array[1] = (u8)(Value & 0xFF); + Array[0] = (u8)((Value & 0xFF00) >> 8); + return Result; +} + +inline u8* PackB2(u8* ptr, u16 val) { - ptr[1] = (u8)(val & 0xff); + ptr[1] = (u8)(val & 0xff); ptr[0] = (u8)((val & 0xff00) >> 8); return ptr + sizeof(val); } //Unpacks a u16 from a known big endian buffer -inline u16 +inline u16 UpackB2(const u8* ptr) { return (u16)(ptr[1] | ptr[0] << 8); } //Packs a u16 to a known little endian buffer -inline u8* +inline u8* PackL2(u8* ptr, u16 val) { *((u16*)ptr) = val; @@ -60,14 +70,14 @@ PackL2(u8* ptr, u16 val) } //Unpacks a u16 from a known little endian buffer -inline u16 +inline u16 UpackL2(const u8* ptr) { return *((u16*)ptr); } //Packs a u32 to a known big endian buffer -inline u8* +inline u8* PackB4(u8* ptr, u32 val) { ptr[3] = (u8) (val & 0xff); @@ -78,14 +88,14 @@ PackB4(u8* ptr, u32 val) } //Unpacks a u32 from a known big endian buffer -inline u32 +inline u32 UpackB4(const u8* ptr) { return (u32)(ptr[3] | (ptr[2] << 8) | (ptr[1] << 16) | (ptr[0] << 24)); } //Packs a u32 to a known little endian buffer -inline u8* +inline u8* PackL4(u8* ptr, u32 val) { *((u32*)ptr) = val; @@ -93,14 +103,14 @@ PackL4(u8* ptr, u32 val) } //Unpacks a u32 from a known little endian buffer -inline u32 +inline u32 UpackL4(const u8* ptr) { return *((u32*)ptr); } //Packs a u64 to a known big endian buffer -inline u8* +inline u8* PackB8(u8* ptr, u64 val) { ptr[7] = (u8) (val & 0xff); @@ -115,17 +125,17 @@ PackB8(u8* ptr, u64 val) } //Unpacks a uint64 from a known big endian buffer -inline u64 +inline u64 UpackB8(const u8* ptr) { return ((u64)ptr[7]) | (((u64)ptr[6]) << 8) | (((u64)ptr[5]) << 16) | - (((u64)ptr[4]) << 24) | (((u64)ptr[3]) << 32) | - (((u64)ptr[2]) << 40) | (((u64)ptr[1]) << 48) | + (((u64)ptr[4]) << 24) | (((u64)ptr[3]) << 32) | + (((u64)ptr[2]) << 40) | (((u64)ptr[1]) << 48) | (((u64)ptr[0]) << 56); } //Packs a u64 to a known little endian buffer -inline u8* +inline u8* PackL8(u8* ptr, u64 val) { *((u64*)ptr) = val; @@ -133,7 +143,7 @@ PackL8(u8* ptr, u64 val) } //Unpacks a u64 from a known little endian buffer -inline u64 +inline u64 UpackL8(const u8* ptr) { return *((u64*)ptr); diff --git a/src/app/engine/sacn/sacn.h b/src/app/engine/sacn/foldhaus_sacn.h similarity index 96% rename from src/app/engine/sacn/sacn.h rename to src/app/engine/sacn/foldhaus_sacn.h index a12c4b8..6004361 100644 --- a/src/app/engine/sacn/sacn.h +++ b/src/app/engine/sacn/foldhaus_sacn.h @@ -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); } } diff --git a/src/app/engine/uart/foldhaus_uart.h b/src/app/engine/uart/foldhaus_uart.h new file mode 100644 index 0000000..a80b7ff --- /dev/null +++ b/src/app/engine/uart/foldhaus_uart.h @@ -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 \ No newline at end of file diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index 8914b3c..ed12a0a 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -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); diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index e3b5532..51938b4 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -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; diff --git a/src/app/foldhaus_platform.h b/src/app/foldhaus_platform.h index 4f066d4..96a7ec7 100644 --- a/src/app/foldhaus_platform.h +++ b/src/app/foldhaus_platform.h @@ -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; }; diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 338f957..dc076eb 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -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(); diff --git a/src/app/platform_win32/win32_foldhaus_serial.h b/src/app/platform_win32/win32_foldhaus_serial.h index 31f4d73..c5e356a 100644 --- a/src/app/platform_win32/win32_foldhaus_serial.h +++ b/src/app/platform_win32/win32_foldhaus_serial.h @@ -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 \ No newline at end of file diff --git a/src/app/platform_win32/win32_foldhaus_socket.h b/src/app/platform_win32/win32_foldhaus_socket.h new file mode 100644 index 0000000..18df318 --- /dev/null +++ b/src/app/platform_win32/win32_foldhaus_socket.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 \ No newline at end of file diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index a86c01c..4db796a 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -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) {