From ecca6c691ad1f4367d408168f8e947b9cb2529ac Mon Sep 17 00:00:00 2001 From: PS Date: Mon, 5 Oct 2020 13:17:33 -0700 Subject: [PATCH] Speeding up COM writing --- src/app/engine/animation/foldhaus_animation.h | 11 +++ .../foldhaus_animation_serializer.cpp | 10 ++ src/app/engine/assembly_parser.cpp | 11 ++- src/app/engine/foldhaus_addressed_data.h | 1 + src/app/engine/foldhaus_assembly.h | 2 +- src/app/engine/uart/foldhaus_uart.h | 47 ++++++---- src/app/foldhaus_log.h | 1 + src/app/platform_win32/win32_foldhaus.cpp | 93 ++++++++++++------- .../platform_win32/win32_foldhaus_serial.h | 77 ++++++++++++--- 9 files changed, 186 insertions(+), 67 deletions(-) create mode 100644 src/app/engine/animation/foldhaus_animation_serializer.cpp diff --git a/src/app/engine/animation/foldhaus_animation.h b/src/app/engine/animation/foldhaus_animation.h index 98a5c08..a7444b5 100644 --- a/src/app/engine/animation/foldhaus_animation.h +++ b/src/app/engine/animation/foldhaus_animation.h @@ -35,6 +35,17 @@ struct anim_layer blend_mode BlendMode; }; +struct animation +{ + anim_layer* Layers; + u32 LayersCount; + u32 LayersMax; + + gs_list Blocks; + + frame_range PlayableRange; +}; + #define ANIMATION_SYSTEM_LAYERS_MAX 128 #define ANIMATION_SYSTEM_BLOCKS_MAX 128 struct animation_system diff --git a/src/app/engine/animation/foldhaus_animation_serializer.cpp b/src/app/engine/animation/foldhaus_animation_serializer.cpp new file mode 100644 index 0000000..481b248 --- /dev/null +++ b/src/app/engine/animation/foldhaus_animation_serializer.cpp @@ -0,0 +1,10 @@ +// +// File: foldhaus_animation_serializer.cpp +// Author: Peter Slattery +// Creation Date: 2020-10-04 +// +#ifndef FOLDHAUS_ANIMATION_SERIALIZER_CPP + + +#define FOLDHAUS_ANIMATION_SERIALIZER_CPP +#endif // FOLDHAUS_ANIMATION_SERIALIZER_CPP \ No newline at end of file diff --git a/src/app/engine/assembly_parser.cpp b/src/app/engine/assembly_parser.cpp index 636c11c..006ae62 100644 --- a/src/app/engine/assembly_parser.cpp +++ b/src/app/engine/assembly_parser.cpp @@ -284,7 +284,7 @@ ReadInt(assembly_tokenizer* T) } internal gs_string -ReadStringField(assembly_field Field, assembly_tokenizer* T, gs_memory_arena* Arena) +ReadStringField(assembly_field Field, assembly_tokenizer* T, gs_memory_arena* Arena, bool ShouldNullTerminate = false) { gs_string Result = {}; if (ReadFieldIdentifier(Field, T)) @@ -293,8 +293,13 @@ ReadStringField(assembly_field Field, assembly_tokenizer* T, gs_memory_arena* Ar if (ReadFieldEnd(T)) { // Success - Result = PushString(Arena, ExistingString.Length); + u64 Length = ExistingString.Length + (ShouldNullTerminate ? 1 : 0); + Result = PushString(Arena, Length); PrintF(&Result, "%S", ExistingString); + if (ShouldNullTerminate) + { + NullTerminate(&Result); + } } } return Result; @@ -430,6 +435,7 @@ ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileTe if (StringsEqual(OutputModeString.ConstString, ConstString("UART"))) { Assembly->OutputMode = NetworkProtocol_UART; + Assembly->UARTComPort = ReadStringField(AssemblyField_UART_ComPort, &Tokenizer, &Assembly->Arena, true).ConstString; } else if (StringsEqual(OutputModeString.ConstString, ConstString("SACN"))) { @@ -459,7 +465,6 @@ ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileTe 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)) { diff --git a/src/app/engine/foldhaus_addressed_data.h b/src/app/engine/foldhaus_addressed_data.h index 79a84de..47b70d7 100644 --- a/src/app/engine/foldhaus_addressed_data.h +++ b/src/app/engine/foldhaus_addressed_data.h @@ -61,6 +61,7 @@ AddressedDataBufferList_PushEmpty(addressed_data_buffer_list* List) { addressed_data_buffer* Result = PushStruct(List->Arena, addressed_data_buffer); *Result = {0}; + Result->Next = 0; Result->MemorySize = 0; Result->Memory = 0; diff --git a/src/app/engine/foldhaus_assembly.h b/src/app/engine/foldhaus_assembly.h index c702a3b..55185e3 100644 --- a/src/app/engine/foldhaus_assembly.h +++ b/src/app/engine/foldhaus_assembly.h @@ -58,7 +58,6 @@ struct strip_sacn_addr struct strip_uart_addr { u8 Channel; - gs_const_string ComPort; }; struct v2_strip @@ -103,6 +102,7 @@ struct assembly v2_strip* Strips; network_protocol OutputMode; + gs_const_string UARTComPort; }; struct assembly_array diff --git a/src/app/engine/uart/foldhaus_uart.h b/src/app/engine/uart/foldhaus_uart.h index a80b7ff..7e36e00 100644 --- a/src/app/engine/uart/foldhaus_uart.h +++ b/src/app/engine/uart/foldhaus_uart.h @@ -81,25 +81,16 @@ UART_FillFooter(uart_footer* Footer, u8* BufferStart) } internal void -UART_SetChannelBuffer_Create(addressed_data_buffer_list* Output, uart_channel ChannelSettings, v2_strip Strip, led_buffer LedBuffer) +UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, 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_header* Header = PushStructOnCursor(WriteCursor, uart_header); UART_FillHeader(Header, Strip.UARTAddr.Channel, UART_SET_CHANNEL_WS2812); - uart_channel* Channel = PushStructOnCursor(&WriteCursor, uart_channel); + uart_channel* Channel = PushStructOnCursor(WriteCursor, uart_channel); *Channel = ChannelSettings; for (u32 i = 0; i < Channel->PixelsCount; i++) @@ -107,7 +98,7 @@ UART_SetChannelBuffer_Create(addressed_data_buffer_list* Output, uart_channel Ch u32 LedIndex = Strip.LedLUT[i]; pixel Color = LedBuffer.Colors[LedIndex]; - u8* OutputPixel = PushArrayOnCursor(&WriteCursor, u8, 3); + u8* OutputPixel = PushArrayOnCursor(WriteCursor, u8, 3); OutputPixel[Channel->RedIndex] = Color.R; OutputPixel[Channel->GreenIndex] = Color.G; @@ -123,8 +114,18 @@ UART_SetChannelBuffer_Create(addressed_data_buffer_list* Output, uart_channel Ch } } - uart_footer* Footer = PushStructOnCursor(&WriteCursor, uart_footer); - UART_FillFooter(Footer, Buffer->Memory); + uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer); + UART_FillFooter(Footer, (u8*)Header); +} + +internal void +UART_DrawAll_Create(gs_memory_cursor* WriteCursor) +{ + uart_header* Header = PushStructOnCursor(WriteCursor, uart_header); + UART_FillHeader(Header, 1, UART_DRAW_ALL); + + uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer); + UART_FillFooter(Footer, (u8*)Header); } internal void @@ -137,17 +138,31 @@ UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assembli ChannelSettings.BlueIndex = 3; ChannelSettings.WhiteIndex = 0; + // NOTE(pjs): This is the minimum size of every UART message. SetChannelBuffer messages will + // be bigger than this, but their size is based on the number of pixels in each channel + u32 MessageBaseSize = sizeof(uart_header) + sizeof(uart_channel) + sizeof(uart_footer); + for (u32 AssemblyIdx = 0; AssemblyIdx < Assemblies.Count; AssemblyIdx++) { assembly Assembly = Assemblies.Values[AssemblyIdx]; led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex); + u32 TotalBufferSize = MessageBaseSize * Assembly.StripCount; // SetChannelBuffer messages + TotalBufferSize += MessageBaseSize; // DrawAll message + TotalBufferSize += ChannelSettings.ElementsCount * Assembly.LedCountTotal; // pixels * channels per pixel + + addressed_data_buffer* Buffer = AddressedDataBufferList_Push(Output, TotalBufferSize); + AddressedDataBuffer_SetCOMPort(Buffer, Assembly.UARTComPort); + gs_memory_cursor WriteCursor = CreateMemoryCursor(Buffer->Data); + 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); + UART_SetChannelBuffer_Create(&WriteCursor, ChannelSettings, StripAt, *LedBuffer); } + + UART_DrawAll_Create(&WriteCursor); } } diff --git a/src/app/foldhaus_log.h b/src/app/foldhaus_log.h index 0cffd1a..5d1c936 100644 --- a/src/app/foldhaus_log.h +++ b/src/app/foldhaus_log.h @@ -44,5 +44,6 @@ PushLogEntry(event_log* Log, gs_string Message, log_entry_type Type) + #define FOLDHAUS_LOG_H #endif // FOLDHAUS_LOG_H \ No newline at end of file diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index dc076eb..d70938d 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -364,6 +364,58 @@ Win32LoadSystemCursor(char* CursorIdentifier) return Result; } +internal void +Win32_SendAddressedDataBuffers(gs_thread_context Context, addressed_data_buffer_list OutputData) +{ + DEBUG_TRACK_FUNCTION; + + u32 BuffersSent = 0; + + 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, 2000000, 8, NOPARITY, 1); + if (SerialPort != INVALID_HANDLE_VALUE) + { + if (Win32SerialPort_Write(SerialPort, BufferAt->Data)) + { + BuffersSent += 1; + } + } + }break; + + InvalidDefaultCase; + } + } + + gs_string OutputStr = AllocatorAllocString(Context.Allocator, 256); + PrintF(&OutputStr, "Buffers Sent: %d\n", BuffersSent); + NullTerminate(&OutputStr); + OutputDebugStringA(OutputStr.Str); +} + +internal void +Win32_SendAddressedDataBuffers_Job(gs_thread_context Context, gs_data Arg) +{ + addressed_data_buffer_list* OutputData = (addressed_data_buffer_list*)Arg.Memory; + Win32_SendAddressedDataBuffers(Context, *OutputData); +} + int WINAPI WinMain ( HINSTANCE HInstance, @@ -504,6 +556,8 @@ WinMain ( Context.ReloadStaticData(Context, GlobalDebugServices); } + AddressedDataBufferList_Clear(&OutputData); + { // Mouse Position POINT MousePos; GetCursorPos (&MousePos); @@ -534,39 +588,10 @@ WinMain ( 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; - } - } + gs_data ProcArg = {}; + ProcArg.Memory = (u8*)&OutputData; + ProcArg.Size = sizeof(OutputData); + Win32PushWorkOnQueue(&WorkQueue, Win32_SendAddressedDataBuffers_Job, ProcArg, ConstString("Send UART Data")); } Context.Mouse.LeftButtonState = GetMouseButtonStateAdvanced(Context.Mouse.LeftButtonState); @@ -610,6 +635,8 @@ WinMain ( SwapBuffers(DeviceContext); ReleaseDC(MainWindow.Handle, DeviceContext); + //Win32DoQueueWorkUntilDone(&WorkQueue, Context.ThreadContext); + s64 FinishedWorkTime = GetWallClock(); r32 SecondsElapsed = GetSecondsElapsed(LastFrameEnd, FinishedWorkTime, PerformanceCountFrequency); diff --git a/src/app/platform_win32/win32_foldhaus_serial.h b/src/app/platform_win32/win32_foldhaus_serial.h index c5e356a..fbf389f 100644 --- a/src/app/platform_win32/win32_foldhaus_serial.h +++ b/src/app/platform_win32/win32_foldhaus_serial.h @@ -13,6 +13,7 @@ global gs_string* Win32SerialPortNames; DCB Win32SerialPort_GetState(HANDLE ComPortHandle) { + DEBUG_TRACK_FUNCTION; DCB ControlSettings = {0}; ZeroStruct(&ControlSettings); ControlSettings.DCBlength = sizeof(ControlSettings); @@ -26,14 +27,45 @@ Win32SerialPort_GetState(HANDLE ComPortHandle) void Win32SerialPort_SetState(HANDLE ComPortHandle, u32 BaudRate, u8 ByteSize, u8 Parity, u8 StopBits) { + DEBUG_TRACK_FUNCTION; DCB ControlSettings = Win32SerialPort_GetState(ComPortHandle); - //PrintCommState(ControlSettings); // TODO(pjs): Validate BaudRate - There's only certain rates that are valid right? ControlSettings.BaudRate = BaudRate; - ControlSettings.ByteSize = ByteSize; - ControlSettings.Parity = Parity; + + if (Parity == NOPARITY) + { + ControlSettings.Parity = Parity; + ControlSettings.fParity = 0; + } + if (Parity == EVENPARITY || Parity == ODDPARITY) + { + ControlSettings.Parity = Parity; + ControlSettings.fParity = 1; + } + ControlSettings.StopBits = StopBits; + ControlSettings.ByteSize = ByteSize; + + ControlSettings.fBinary = true; + + ControlSettings.fOutxCtsFlow = false; + ControlSettings.fOutxDsrFlow = false; + ControlSettings.fDtrControl = DTR_CONTROL_DISABLE; + ControlSettings.fDsrSensitivity = 0; + ControlSettings.fRtsControl = RTS_CONTROL_DISABLE; + ControlSettings.fOutX = false; + ControlSettings.fInX = false; + + ControlSettings.fErrorChar = 0; + ControlSettings.fNull = false; + ControlSettings.fAbortOnError = false; + ControlSettings.wReserved = false; + ControlSettings.XonLim = 2; + ControlSettings.XoffLim = 4; + ControlSettings.XonChar = 0x13; + ControlSettings.XoffChar = 0x19; + ControlSettings.EvtChar = 0; bool Success = SetCommState(ComPortHandle, &ControlSettings); } @@ -41,6 +73,7 @@ Win32SerialPort_SetState(HANDLE ComPortHandle, u32 BaudRate, u8 ByteSize, u8 Par HANDLE Win32SerialPort_Open(char* PortName) { + DEBUG_TRACK_FUNCTION; HANDLE ComPortHandle = CreateFile(PortName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, @@ -52,11 +85,11 @@ Win32SerialPort_Open(char* PortName) 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 + Timeouts.ReadIntervalTimeout = 0; // in milliseconds + Timeouts.ReadTotalTimeoutConstant = 0; // in milliseconds + Timeouts.ReadTotalTimeoutMultiplier = 0; // in milliseconds + Timeouts.WriteTotalTimeoutConstant = 0; // in milliseconds + Timeouts.WriteTotalTimeoutMultiplier = 0; // in milliseconds if (SetCommTimeouts(ComPortHandle, &Timeouts)) { @@ -65,14 +98,14 @@ Win32SerialPort_Open(char* PortName) else { s32 Error = GetLastError(); - InvalidCodePath; + // TODO(pjs): Error logging } } else { // Error s32 Error = GetLastError(); - InvalidCodePath; + // TODO(pjs): Error logging } return ComPortHandle; @@ -84,15 +117,18 @@ Win32SerialPort_Close(HANDLE PortHandle) CloseHandle(PortHandle); } -void +bool Win32SerialPort_Write(HANDLE PortHandle, gs_data Buffer) { + DEBUG_TRACK_FUNCTION; Assert(PortHandle != INVALID_HANDLE_VALUE); + bool Success = false; DWORD BytesWritten = 0; if (WriteFile(PortHandle, Buffer.Memory, Buffer.Size, &BytesWritten, NULL)) { - if (BytesWritten != Buffer.Size) + Success = (BytesWritten == Buffer.Size); + if (!Success) { OutputDebugString("Error: Entire buffer not written.\n"); } @@ -103,6 +139,8 @@ Win32SerialPort_Write(HANDLE PortHandle, gs_data Buffer) s32 Error = GetLastError(); //InvalidCodePath; } + + return Success; } ///////////////////////// @@ -111,6 +149,8 @@ Win32SerialPort_Write(HANDLE PortHandle, gs_data Buffer) void Win32SerialArray_Create(gs_thread_context Context) { + DEBUG_TRACK_FUNCTION; + Win32SerialHandlesCountMax = 32; Win32SerialHandlesCount = 0; Win32SerialHandles = AllocatorAllocArray(Context.Allocator, HANDLE, Win32SerialHandlesCountMax); @@ -124,6 +164,8 @@ Win32SerialArray_Create(gs_thread_context Context) void Win32SerialArray_Push(HANDLE SerialHandle, gs_const_string PortName) { + DEBUG_TRACK_FUNCTION; + Assert(Win32SerialHandlesCount < Win32SerialHandlesCountMax); u32 Index = Win32SerialHandlesCount++; Win32SerialHandles[Index] = SerialHandle; @@ -133,6 +175,8 @@ Win32SerialArray_Push(HANDLE SerialHandle, gs_const_string PortName) HANDLE Win32SerialArray_Get(gs_const_string PortName) { + DEBUG_TRACK_FUNCTION; + HANDLE PortHandle = INVALID_HANDLE_VALUE; for (u32 i = 0; i < Win32SerialHandlesCount; i++) { @@ -148,13 +192,18 @@ Win32SerialArray_Get(gs_const_string PortName) HANDLE Win32SerialArray_GetOrOpen(gs_const_string PortName, u32 BaudRate, u8 ByteSize, u8 Parity, u8 StopBits) { + DEBUG_TRACK_FUNCTION; + 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); + if (PortHandle != INVALID_HANDLE_VALUE) + { + Win32SerialPort_SetState(PortHandle, BaudRate, ByteSize, Parity, StopBits); + Win32SerialArray_Push(PortHandle, PortName); + } } return PortHandle; }