From 9fc984d6f2af76e103503185f8479a008211c93b Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 20 Mar 2021 15:15:35 -0700 Subject: [PATCH] Message sending to weatherman --- src/app/foldhaus_app.cpp | 2 + src/app/foldhaus_platform.h | 17 + src/app/patterns/blumen_patterns.h | 336 +++++++++++++++++- src/app/platform_win32/win32_foldhaus.cpp | 41 +++ .../platform_win32/win32_foldhaus_serial.h | 4 + src/app/ss_blumen_lumen/blumen_lumen.cpp | 235 ++++++++---- src/app/ss_blumen_lumen/blumen_lumen.h | 60 +++- src/sculpture_gen/gen_blumen_lumen.cpp | 3 + 8 files changed, 615 insertions(+), 83 deletions(-) diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index e91070d..5016e27 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -133,12 +133,14 @@ UPDATE_AND_RENDER(UpdateAndRender) Editor_Render(State, Context, RenderBuffer); } +#if SEND_DATA // NOTE(pjs): Building data buffers to be sent out to the sculpture // This array is used on the platform side to actually send the information 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, State->Transient); +#endif } CLEANUP_APPLICATION(CleanupApplication) diff --git a/src/app/foldhaus_platform.h b/src/app/foldhaus_platform.h index 35a539d..efe8ff8 100644 --- a/src/app/foldhaus_platform.h +++ b/src/app/foldhaus_platform.h @@ -189,6 +189,20 @@ GetSecondsElapsed (s64 Start, s64 End, s64 PerformanceCountFrequency) return Result; } +typedef struct system_time +{ + u64 NanosSinceEpoch; + + s32 Year; + s32 Month; + s32 Day; + s32 Hour; // [0:23] + s32 Minute; + s32 Second; +} system_time; + +#define STATUS_PACKET_FREQ_SECONDS 5 + struct context { gs_thread_context ThreadContext; @@ -218,6 +232,9 @@ struct context platform_draw_font_codepoint* PlatformDrawFontCodepoint; platform_get_socket_handle* PlatformGetSocketHandle; + + system_time SystemTime_Last; + system_time SystemTime_Current; }; #define FOLDHAUS_PLATFORM_H diff --git a/src/app/patterns/blumen_patterns.h b/src/app/patterns/blumen_patterns.h index 4345524..0b0d2d2 100644 --- a/src/app/patterns/blumen_patterns.h +++ b/src/app/patterns/blumen_patterns.h @@ -7,6 +7,242 @@ #define FLOWER_COLORS_COUNT 12 +internal r32 +Smoothstep(r32 T) +{ + r32 Result = (T * T * (3 - (2 * T))); + return Result; +} +internal r32 +Smoothstep(r32 T, r32 A, r32 B) +{ + return LerpR32(Smoothstep(T), A, B); +} + +internal v2 +FloorV2(v2 P) +{ + v2 Result = {}; + Result.x = FloorR32(P.x); + Result.y = FloorR32(P.y); + return Result; +} +internal v3 +FloorV3(v3 P) +{ + v3 Result = {}; + Result.x = FloorR32(P.x); + Result.y = FloorR32(P.y); + Result.z = FloorR32(P.z); + return Result; +} + +internal v2 +FractV2(v2 P) +{ + v2 Result = {}; + Result.x = FractR32(P.x); + Result.y = FractR32(P.y); + return Result; +} +internal v3 +FractV3(v3 P) +{ + v3 Result = {}; + Result.x = FractR32(P.x); + Result.y = FractR32(P.y); + Result.z = FractR32(P.z); + return Result; +} + +internal v2 +SinV2(v2 P) +{ + v2 Result = {}; + Result.x = SinR32(P.x); + Result.y = SinR32(P.y); + return Result; +} +internal v3 +SinV3(v3 P) +{ + v3 Result = {}; + Result.x = SinR32(P.x); + Result.y = SinR32(P.y); + Result.y = SinR32(P.z); + return Result; +} + +internal r32 +Hash1(v2 P) +{ + v2 Result = FractV2( P * 0.3183099f ) * 50.f; + return FractR32(P.x * P.y * (P.x + P.y)); +} + +internal r32 +Hash1(r32 N) +{ + return FractR32(N * 17.0f * FractR32(N * 0.3183099f)); +} + +internal v2 +Hash2(r32 N) +{ + v2 P = V2MultiplyPairwise(SinV2(v2{N,N+1.0f}), v2{43758.5453123f,22578.1459123f}); + return FractV2(P); +} + +internal v2 +Hash2(v2 P) +{ + v2 K = v2{ 0.3183099f, 0.3678794f }; + v2 Kp = v2{K.y, K.x}; + v2 R = V2MultiplyPairwise(P, K) + Kp; + return FractV2( K * 16.0f * FractR32( P.x * P.y * (P.x + P.y))); +} + +internal v3 +Hash3(v2 P) +{ + v3 Q = v3{}; + Q.x = V2Dot(P, v2{127.1f, 311.7f}); + Q.y = V2Dot(P, v2{267.5f, 183.3f}); + Q.z = V2Dot(P, v2{419.2f, 371.9f}); + return FractV3(SinV3(Q) * 43758.5453f); +} + +internal r32 +Random(v2 N) +{ + v2 V = v2{12.9898f, 4.1414f}; + return FractR32(SinR32(V2Dot(N, V)) * 43758.5453); +} + +internal r32 +Noise2D(v2 P) +{ + v2 IP = FloorV2(P); + v2 U = FractV2(P); + U = V2MultiplyPairwise(U, U); + U = V2MultiplyPairwise(U, ((U * 2.0f) + v2{-3, -3})); + + r32 A = LerpR32(U.x, Random(IP), Random(IP + v2{1.0f, 0})); + r32 B = LerpR32(U.x, Random(IP + v2{0, 1}), Random(IP + v2{1, 1})); + r32 Res = LerpR32(U.y, A, B); + + return Res * Res; +} + +internal r32 +Noise3D(v3 Pp) +{ + v3 P = FloorV3(Pp); + v3 W = FractV3(Pp); + + //v3 U = W * W * W * (W * (W * 6.0f - 15.0f) + 10.0f); + v3 U = V3MultiplyPairwise(W, W * 6.0f - v3{15, 15, 15}); + U = U + v3{10, 10, 10}; + U = V3MultiplyPairwise(U, W); + U = V3MultiplyPairwise(U, W); + U = V3MultiplyPairwise(U, W); + + r32 N = P.x + 317.0f * P.y + 157.0f * P.z; + + r32 A = Hash1(N + 0.0f); + r32 B = Hash1(N + 1.0f); + r32 C = Hash1(N + 317.0f); + r32 D = Hash1(N + 317.0f); + r32 E = Hash1(N + 157.0f); + r32 F = Hash1(N + 158.0f); + r32 G = Hash1(N + 474.0f); + r32 H = Hash1(N + 475.0f); + + r32 K0 = A; + r32 K1 = B - A; + r32 K2 = C - A; + r32 K3 = E - A; + r32 K4 = A - B - C + D; + r32 K5 = A - C - E + G; + r32 K6 = A - B - E + F; + r32 K7 = A + B + C - D + E - F - G + H; + + return -1.0f + 2.0f * (K0 + + K1 * U.x + + K2 * U.y + + K3 * U.z + + K4 * U.x * U.y + + K5 * U.y + U.z + + K6 * U.z * U.x + + K7 * U.x * U.y * U.z); +} + +internal r32 +Fbm2D(v2 P) +{ + r32 R = 0; + r32 Amp = 1.0; + r32 Freq = 1.0; + for (u32 i = 0; i < 3; i++) + { + R += Amp * Noise2D(P * Freq); + Amp *= 0.5f; + Freq *= 1.0f / 0.5f; + } + return R; +} + +global m44 M3 = m44{ + 0.00f, 0.80f, 0.60f, 0, + -0.80f, 0.36f, -0.48f, 0, + -0.60f, -0.48f, 0.64f, 0, + 0, 0, 0, 1 +}; + +internal r32 +Fbm3D(v3 P) +{ + v3 X = P; + r32 F = 2.0f; + r32 S = 0.5f; + r32 A = 0.0f; + r32 B = 0.5f; + for (u32 i = 0; i < 4; i++) + { + r32 N = Noise3D(X); + A += B * N; + B *= S; + v4 Xp = M3 * ToV4Point(X); + X = Xp.xyz * F; + } + + return A; +} + +internal r32 +Voronoise(v2 P, r32 U, r32 V) +{ + r32 K = 1.0f + 63.0f + PowR32(1.0f - V, 6.0f); + + v2 I = FloorV2(P); + v2 F = FractV2(P); + + v2 A = v2{0, 0}; + for (s32 y = -2; y <= 2; y++) + { + for (s32 x = -2; x <= 2; x++) + { + v2 G = v2{(r32)x, (r32)y}; + v3 O = V3MultiplyPairwise(Hash3(I + G), v3{U, U, 1.0f}); + v2 D = G - F + O.xy; + r32 W = PowR32(1.0f - Smoothstep(V2Mag(D), 0.0f, 1.414f), K); + A += v2{O.z * W, W}; + } + } + + return A.x / A.y; +} + pixel FlowerAColors[FLOWER_COLORS_COUNT] = { { 232,219,88 }, { 232,219,88 }, @@ -507,13 +743,6 @@ Pattern_LighthouseRainbow(led_buffer* Leds, assembly Assembly, r32 Time, gs_memo } } -internal r32 -Smoothstep(r32 T) -{ - r32 Result = (T * T * (3 - (2 * T))); - return Result; -} - internal void Pattern_SmoothGrowRainbow(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { @@ -726,5 +955,98 @@ Pattern_BasicFlowers(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_ar } } } + +internal void +Pattern_Wavy(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + +} + +internal void +Pattern_Patchy(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + v4 P = Leds->Positions[LedIndex]; + + v3 Pp = P.xyz; + + r32 Noise = Fbm3D((Pp / 1000) + (v3{Time, -Time, SinR32(Time)} * 0.1f)); + Noise = RemapR32(Noise, -1, 1, 0, 1); + Noise = Smoothstep(Noise, 0, 1); + u8 NV = (u8)(Noise * 255); + + v3 BSeed = v3{P.z, P.x, P.y}; + r32 BNoise = 1.0f; //Fbm3D(BSeed / 50); + + pixel C = GetColor(&FlowerAColors[0], FLOWER_COLORS_COUNT, Noise); + C.R = (u8)((r32)C.R * BNoise); + C.G = (u8)((r32)C.G * BNoise); + C.B = (u8)((r32)C.B * BNoise); + + Leds->Colors[LedIndex] = C; + //Leds->Colors[LedIndex] = pixel{NV, NV, NV}; + } +} + +internal void +Pattern_Leafy(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + pixel* Colors = &FlowerBColors[0]; + + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + v4 P = Leds->Positions[LedIndex]; + r32 RefPos = P.y + Noise2D(v2{P.x, P.z} * 50); + + r32 B = 0; + + pixel C = {}; + + r32 BandWidth = 5; + r32 TransitionPeriod = 5.0f; + u32 BandCount = 10; + for (u32 Band = 0; Band < BandCount; Band++) + { + r32 BandSeed = RemapR32(Hash1((r32)Band), -1, 1, 0, 1); + r32 BandDelay = BandSeed * TransitionPeriod; + r32 BandTransitionDuration = RemapR32(Hash1((r32)Band * 3.413f), -1, 1, 0, 1) * TransitionPeriod; + r32 BandPercent = Smoothstep(ModR32(Time + BandDelay, BandTransitionDuration) / TransitionPeriod, 0, 1); + r32 BandHeight = 150 - BandPercent * 250; + + r32 BandDist = Abs(RefPos - BandHeight); + + //B += Max(0, BandWidth - BandDist); + B = Max(0, BandWidth - BandDist); + + + { + //pixel BandColor = GetColor(Colors, FLOWER_COLORS_COUNT, BandSeed); + pixel BandColor = Colors[Band % FLOWER_COLORS_COUNT]; + C.R = C.R + (BandColor.R * B); + C.G = C.G + (BandColor.G * B); + C.B = C.B + (BandColor.B * B); + } + + } + + u8 V = (u8)(B * 255); + //pixel C = { V, V, V }; + Leds->Colors[LedIndex] = C; + } +} + +internal void +Pattern_LeafyPatchy(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + +} + +internal void +Pattern_WavyPatchy(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + +} + #define BLUMEN_PATTERNS_H #endif // BLUMEN_PATTERNS_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 765af09..c34f3f4 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -620,6 +620,47 @@ WinMain ( } DEBUG_TRACK_SCOPE(MainLoop); + { + // update system time + SYSTEMTIME WinLocalTime; + GetLocalTime(&WinLocalTime); + + SYSTEMTIME WinSysTime; + FILETIME WinSysFileTime; + GetSystemTime(&WinSysTime); + if (!SystemTimeToFileTime((const SYSTEMTIME*)&WinSysTime, &WinSysFileTime)) + { + u32 Error = GetLastError(); + InvalidCodePath; + } + ULARGE_INTEGER SysTime = {}; + SysTime.LowPart = WinSysFileTime.dwLowDateTime; + SysTime.HighPart = WinSysFileTime.dwHighDateTime; + + Context.SystemTime_Last = Context.SystemTime_Current; + + Context.SystemTime_Current.NanosSinceEpoch = SysTime.QuadPart; + Context.SystemTime_Current.Year = WinLocalTime.wYear; + Context.SystemTime_Current.Month = WinLocalTime.wMonth; + Context.SystemTime_Current.Day = WinLocalTime.wDay; + Context.SystemTime_Current.Hour = WinLocalTime.wHour; + Context.SystemTime_Current.Minute = WinLocalTime.wMinute; + Context.SystemTime_Current.Second = WinLocalTime.wSecond; + +#define PRINT_SYSTEM_TIME 0 +#if PRINT_SYSTEM_TIME + gs_string T = PushStringF(Context.ThreadContext.Transient, + 256, + "%d %d %d - %lld\n", + Context.SystemTime_Current.Hour, + Context.SystemTime_Current.Minute, + Context.SystemTime_Current.Second, + Context.SystemTime_Current.NanosSinceEpoch); + NullTerminate(&T); + OutputDebugStringA(T.Str); +#endif + } + ResetInputQueue(&InputQueue); ReloadAndLinkDLL(&DLLRefresh, &Context, &Win32WorkQueue.WorkQueue, false); diff --git a/src/app/platform_win32/win32_foldhaus_serial.h b/src/app/platform_win32/win32_foldhaus_serial.h index c3dcfb1..820da09 100644 --- a/src/app/platform_win32/win32_foldhaus_serial.h +++ b/src/app/platform_win32/win32_foldhaus_serial.h @@ -151,6 +151,10 @@ Win32SerialPort_Write(HANDLE PortHandle, gs_data Buffer) // ?? }break; + case ERROR_NO_SUCH_DEVICE: + { + }break; + case ERROR_INVALID_HANDLE: InvalidDefaultCase; } diff --git a/src/app/ss_blumen_lumen/blumen_lumen.cpp b/src/app/ss_blumen_lumen/blumen_lumen.cpp index 698451f..370341d 100644 --- a/src/app/ss_blumen_lumen/blumen_lumen.cpp +++ b/src/app/ss_blumen_lumen/blumen_lumen.cpp @@ -5,6 +5,67 @@ // #ifndef BLUMEN_LUMEN_CPP +internal bool +MessageQueue_CanRead(blumen_network_msg_queue* Queue) +{ + bool Result = (Queue->ReadHead != Queue->WriteHead); + return Result; +} + +internal gs_data +MessageQueue_Read(blumen_network_msg_queue* Queue) +{ + gs_data Result = {}; + u32 ReadIndex = Queue->ReadHead++; + if (Queue->ReadHead >= BLUMEN_MESSAGE_QUEUE_COUNT) + { + Queue->ReadHead = 0; + } + Result = Queue->Buffers[ReadIndex]; + return Result; +} + +// KB(1) is just bigger than any packet we send. Good for now +#define DEFAULT_QUEUE_ENTRY_SIZE KB(1) + +internal void +MessageQueue_Init(blumen_network_msg_queue* Queue, gs_memory_arena* Arena) +{ + for (u32 i = 0; i < BLUMEN_MESSAGE_QUEUE_COUNT; i++) + { + Queue->Buffers[i] = PushSizeToData(Arena, DEFAULT_QUEUE_ENTRY_SIZE); + } +} + +internal gs_data* +MessageQueue_GetWrite(blumen_network_msg_queue* Queue) +{ + u32 Index = Queue->WriteHead++; + gs_data* Result = &Queue->Buffers[Index]; + Assert(Result->Size > 0); + + if (Queue->WriteHead >= PACKETS_MAX) + { + Queue->WriteHead = 0; + } + return Result; +} + +internal bool +MessageQueue_Write(blumen_network_msg_queue* Queue, gs_data Msg) +{ + gs_data* Dest = MessageQueue_GetWrite(Queue); + Assert(Msg.Size <= DEFAULT_QUEUE_ENTRY_SIZE); + CopyMemoryTo(Msg.Memory, Dest->Memory, Msg.Size); +} + +internal bool +MessageQueue_CanWrite(blumen_network_msg_queue Queue) +{ + bool Result = ((Queue.WriteHead >= Queue.ReadHead) || + (Queue.WriteHead < Queue.ReadHead)); + return Result; +} internal void BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) @@ -32,23 +93,13 @@ BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) Msg = SocketRecieve(Data->SocketManager, Data->ListenSocket, Ctx->Transient); if (Msg.Size > 0) { - Data->MicPacketBuffer->Values[Data->MicPacketBuffer->WriteHead++] = Msg; - if (Data->MicPacketBuffer->WriteHead >= PACKETS_MAX) - { - Data->MicPacketBuffer->WriteHead = 0; - } + MessageQueue_Write(Data->IncomingMsgQueue, Msg); } } - while (Data->OutgoingMsgQueue->ReadHead != Data->OutgoingMsgQueue->WriteHead) + while (MessageQueue_CanRead(Data->OutgoingMsgQueue)) { - u32 ReadIndex = Data->OutgoingMsgQueue->ReadHead++; - if (Data->OutgoingMsgQueue->ReadHead >= BLUMEN_MESSAGE_QUEUE_COUNT) - { - Data->OutgoingMsgQueue->ReadHead = 0; - } - - Msg = Data->OutgoingMsgQueue->Buffers[ReadIndex]; + Msg = MessageQueue_Read(Data->OutgoingMsgQueue); u32 Address = WeathermanIPV4; u32 Port = WeathermanPort; s32 Flags = 0; @@ -88,6 +139,9 @@ BlumenLumen_LoadPatterns(app_state* State) Patterns_PushPattern(Patterns, Pattern_FlowerColors); Patterns_PushPattern(Patterns, Pattern_FlowerColorToWhite); Patterns_PushPattern(Patterns, Pattern_BasicFlowers); + // 15 + Patterns_PushPattern(Patterns, Pattern_Patchy); + Patterns_PushPattern(Patterns, Pattern_Leafy); } internal pixel @@ -116,10 +170,13 @@ BlumenLumen_CustomInit(app_state* State, context Context) blumen_lumen_state* BLState = (blumen_lumen_state*)Result.Memory; BLState->Running = true; + BLState->BrightnessPercent = 1; + MessageQueue_Init(&BLState->IncomingMsgQueue, &State->Permanent); + MessageQueue_Init(&BLState->OutgoingMsgQueue, &State->Permanent); BLState->MicListenJobData.Running = &BLState->Running; BLState->MicListenJobData.SocketManager = Context.SocketManager; - BLState->MicListenJobData.MicPacketBuffer = &BLState->MicPacketBuffer; + BLState->MicListenJobData.IncomingMsgQueue = &BLState->IncomingMsgQueue; BLState->MicListenJobData.OutgoingMsgQueue = &BLState->OutgoingMsgQueue; BLState->MicListenJobData.ListenSocket = CreateSocket(Context.SocketManager, "127.0.0.1", "20185"); @@ -163,8 +220,7 @@ BlumenLumen_CustomInit(app_state* State, context Context) Anim2.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem); Animation_AddLayer(&Anim2, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); - Animation_AddBlock(&Anim2, 0, 100, Patterns_IndexToHandle(5), 0); - Animation_AddBlock(&Anim2, 50, Anim0.PlayableRange.Max, Patterns_IndexToHandle(10), 0); + Animation_AddBlock(&Anim2, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(17), 0); BLState->AnimHandles[2] = AnimationArray_Push(&State->AnimationSystem.Animations, Anim2); @@ -204,26 +260,26 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) gs_string GreenString = MakeString("green"); gs_string ILoveYouString = MakeString("i_love_you"); - while (BLState->MicPacketBuffer.ReadHead != BLState->MicPacketBuffer.WriteHead) + while (MessageQueue_CanRead(&BLState->IncomingMsgQueue)) { - gs_data PacketData = BLState->MicPacketBuffer.Values[BLState->MicPacketBuffer.ReadHead++]; + gs_data PacketData = MessageQueue_Read(&BLState->IncomingMsgQueue); - u8 PacketType = PacketData.Memory[0]; - switch (PacketType) { + blumen_packet Packet = *(blumen_packet*)PacketData.Memory; + switch (Packet.Type) { case PacketType_PatternCommand: { - microphone_packet Packet = *(microphone_packet*)(PacketData.Memory + 1); + microphone_packet Mic = Packet.MicPacket; - u32 NameLen = CStringLength(Packet.AnimationFileName); - if (StringEqualsCharArray(BlueString.ConstString, Packet.AnimationFileName, NameLen)) + u32 NameLen = CStringLength(Mic.AnimationFileName); + if (StringEqualsCharArray(BlueString.ConstString, Mic.AnimationFileName, NameLen)) { State->AnimationSystem.ActiveFadeGroup.From.Index = 0; } - else if (StringEqualsCharArray(GreenString.ConstString, Packet.AnimationFileName, NameLen)) + else if (StringEqualsCharArray(GreenString.ConstString, Mic.AnimationFileName, NameLen)) { State->AnimationSystem.ActiveFadeGroup.From.Index = 1; } - else if (StringEqualsCharArray(ILoveYouString.ConstString, Packet.AnimationFileName, NameLen)) + else if (StringEqualsCharArray(ILoveYouString.ConstString, Mic.AnimationFileName, NameLen)) { State->AnimationSystem.ActiveFadeGroup.From.Index = 2; } @@ -233,13 +289,13 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) case PacketType_MotorState: { - motor_packet Packet = *(motor_packet*)(PacketData.Memory + 1); - BLState->LastKnownMotorState = Packet; + motor_packet Motor = Packet.MotorPacket; + BLState->LastKnownMotorState = Motor; gs_string Temp = PushStringF(State->Transient, 256, "Received Motor States: %d %d %d\n", - Packet.FlowerPositions[0], - Packet.FlowerPositions[1], - Packet.FlowerPositions[2]); + Motor.FlowerPositions[0], + Motor.FlowerPositions[1], + Motor.FlowerPositions[2]); NullTerminate(&Temp); OutputDebugStringA(Temp.Str); @@ -247,66 +303,97 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) case PacketType_Temperature: { - temp_packet Packet = *(temp_packet*)(PacketData.Memory + 1); + temp_packet Temp = Packet.TempPacket; - gs_string Temp = PushStringF(State->Transient, 256, "Temperature: %d\n", - Packet.Temperature); - NullTerminate(&Temp); + if (Temp.Temperature > 21) + { + BLState->BrightnessPercent = .5f; + } + else + { + BLState->BrightnessPercent = 1.f; + } - OutputDebugStringA(Temp.Str); + gs_string TempStr = PushStringF(State->Transient, 256, "Temperature: %d\n", + Temp.Temperature); + NullTerminate(&TempStr); + OutputDebugStringA(TempStr.Str); }break; InvalidDefaultCase; } - - - if (BLState->MicPacketBuffer.ReadHead >= PACKETS_MAX) + } + + + // Open / Close the Motor + + if (MessageQueue_CanWrite(BLState->OutgoingMsgQueue)) + { + for (u32 i = 0; i < MotorOpenTimesCount; i++) { - BLState->MicPacketBuffer.ReadHead = 0; + time_range Range = MotorOpenTimes[i]; + + bool CurrTimeInRange = SystemTimeIsInTimeRange(Context->SystemTime_Current, Range); + bool LastTimeInRange = SystemTimeIsInTimeRange(Context->SystemTime_Last, Range); + + if (CurrTimeInRange && !LastTimeInRange) + { + OutputDebugString("Open\n"); + gs_data* Msg = MessageQueue_GetWrite(&BLState->OutgoingMsgQueue); + + blumen_packet* Packet = (blumen_packet*)Msg->Memory; + Packet->Type = PacketType_MotorState; + Packet->MotorPacket.FlowerPositions[0] = 2; + Packet->MotorPacket.FlowerPositions[1] = 2; + Packet->MotorPacket.FlowerPositions[2] = 2; + } + else if (!CurrTimeInRange && LastTimeInRange) + { + OutputDebugString("Close\n"); + gs_data* Msg = MessageQueue_GetWrite(&BLState->OutgoingMsgQueue); + + blumen_packet* Packet = (blumen_packet*)Msg->Memory; + Packet->Type = PacketType_MotorState; + Packet->MotorPacket.FlowerPositions[0] = 1; + Packet->MotorPacket.FlowerPositions[1] = 1; + Packet->MotorPacket.FlowerPositions[2] = 1; + } } } - if (false && MotorTimeElapsed > 0) + // Dim the leds based on temp data + for (u32 i = 0; i < State->LedSystem.BuffersCount; i++) { - // NOTE(pjs): - MotorTimeElapsed = 0; - u8 Position = LastPosition; - if (LastPosition == 2) + led_buffer Buffer = State->LedSystem.Buffers[i]; + for (u32 j = 0; j < Buffer.LedCount; j++) { - LastPosition = 1; + pixel* Color = Buffer.Colors + j; + Color->R = Color->R * BLState->BrightnessPercent; + Color->G = Color->G * BLState->BrightnessPercent; + Color->B = Color->B * BLState->BrightnessPercent; } - else + } + + // Send Status Packet + { + system_time LastSendTime = BLState->LastStatusUpdateTime; + s64 NanosSinceLastSend = ((s64)Context->SystemTime_Current.NanosSinceEpoch - (s64)LastSendTime.NanosSinceEpoch); + s64 SecondsSinceLastSend = NanosSinceLastSend * 1000000000; + if (SecondsSinceLastSend >= STATUS_PACKET_FREQ_SECONDS) { - LastPosition = 2; - } - - if ((BLState->OutgoingMsgQueue.WriteHead >= BLState->OutgoingMsgQueue.ReadHead) || - (BLState->OutgoingMsgQueue.WriteHead < BLState->OutgoingMsgQueue.ReadHead)) - { - u32 WriteIndex = BLState->OutgoingMsgQueue.WriteHead; + BLState->LastStatusUpdateTime = Context->SystemTime_Current; + gs_data* Msg = MessageQueue_GetWrite(&BLState->OutgoingMsgQueue); - gs_data* Msg = BLState->OutgoingMsgQueue.Buffers + WriteIndex; - if (Msg->Size == 0) - { - *Msg = PushSizeToData(&State->Permanent, sizeof(motor_packet)); - } - motor_packet* Packet = (motor_packet*)Msg->Memory; - Packet->FlowerPositions[0] = Position; - Packet->FlowerPositions[1] = Position; - Packet->FlowerPositions[2] = Position; + OutputDebugString("Sending Status\n"); - // NOTE(pjs): We increment the write head AFTER we've written so that - // the network thread doesn't think the buffer is ready to send before - // the data is set. We want to avoid the case of: - // 1. Main Thread increments write head to 1 - // 2. Network Thread thinks theres a new message to send at 0 - // 3. Network Thread sends the message at 0 - // 4. Main Thread sets the message at 0 - BLState->OutgoingMsgQueue.WriteHead += 1; - if (BLState->OutgoingMsgQueue.WriteHead >= BLUMEN_MESSAGE_QUEUE_COUNT) - { - BLState->OutgoingMsgQueue.WriteHead = 0; - } + blumen_packet* Packet = (blumen_packet*)Msg->Memory; + Packet->Type = PacketType_LumenariumStatus; + Packet->StatusPacket.NextMotorEventType = 0; + Packet->StatusPacket.NextEventTime = 0; + + animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); + CopyMemoryTo(ActiveAnim->Name.Str, Packet->StatusPacket.AnimFileName, + Min(ActiveAnim->Name.Length, 32)); } } } diff --git a/src/app/ss_blumen_lumen/blumen_lumen.h b/src/app/ss_blumen_lumen/blumen_lumen.h index 56ad6b6..5009dac 100644 --- a/src/app/ss_blumen_lumen/blumen_lumen.h +++ b/src/app/ss_blumen_lumen/blumen_lumen.h @@ -11,6 +11,7 @@ enum bl_python_packet_type PacketType_PatternCommand = 1, PacketType_MotorState = 2, PacketType_Temperature = 3, + PacketType_LumenariumStatus = 4, }; #pragma pack(push, 1) @@ -35,6 +36,32 @@ typedef struct temp_packet { s8 Temperature; } temp_packet; + +enum motor_event_type +{ + MotorEvent_Close = 0, + MotorEvent_Open = 1, +}; + +typedef struct status_packet +{ + u8 NextMotorEventType; + u32 NextEventTime; + char AnimFileName[32]; +} status_packet; + +typedef struct blumen_packet +{ + bl_python_packet_type Type; + union + { + motor_packet MotorPacket; + microphone_packet MicPacket; + temp_packet TempPacket; + status_packet StatusPacket; + }; +} blumen_packet; + #pragma pack(pop) #define BLUMEN_MESSAGE_QUEUE_COUNT 32 @@ -51,17 +78,41 @@ struct mic_listen_job_data bool* Running; platform_socket_manager* SocketManager; - packet_ringbuffer* MicPacketBuffer; + blumen_network_msg_queue* IncomingMsgQueue; platform_socket_handle_ ListenSocket; blumen_network_msg_queue* OutgoingMsgQueue; }; +typedef struct time_range +{ + s32 StartHour; + s32 StartMinute; + + s32 EndHour; + s32 EndMinute; +} time_range; + +internal bool +SystemTimeIsInTimeRange(system_time SysTime, time_range Range) +{ + bool Result = (SysTime.Hour >= Range.StartHour && + SysTime.Minute >= Range.StartMinute && + SysTime.Hour <= Range.EndHour && + SysTime.Minute <= Range.EndMinute); + return Result; +} + +global time_range MotorOpenTimes[] = { + { 14, 28, 14, 29 } +}; +global u32 MotorOpenTimesCount = 1; + struct blumen_lumen_state { bool Running; - packet_ringbuffer MicPacketBuffer; + blumen_network_msg_queue IncomingMsgQueue; blumen_network_msg_queue OutgoingMsgQueue; temp_job_req JobReq; @@ -75,6 +126,11 @@ struct blumen_lumen_state animation_handle AnimHandles[3]; u32 CurrAnim; + + // NOTE(pjs): Based on temperature data from weatherman + // dim the leds. + r32 BrightnessPercent; + system_time LastStatusUpdateTime; }; diff --git a/src/sculpture_gen/gen_blumen_lumen.cpp b/src/sculpture_gen/gen_blumen_lumen.cpp index d1f4462..7beea9d 100644 --- a/src/sculpture_gen/gen_blumen_lumen.cpp +++ b/src/sculpture_gen/gen_blumen_lumen.cpp @@ -219,6 +219,9 @@ int main(int ArgCount, char** Args) printf("%.*s\n", (u32)OutputBuffer.Length, OutputBuffer.Str); //printf("%d\n", StripCount); + + + return 0; }