Message sending to weatherman

This commit is contained in:
PS 2021-03-20 15:15:35 -07:00
parent c054a0e6b6
commit 9fc984d6f2
8 changed files with 615 additions and 83 deletions

View File

@ -133,12 +133,14 @@ UPDATE_AND_RENDER(UpdateAndRender)
Editor_Render(State, Context, RenderBuffer); Editor_Render(State, Context, RenderBuffer);
} }
#if SEND_DATA
// NOTE(pjs): Building data buffers to be sent out to the sculpture // NOTE(pjs): Building data buffers to be sent out to the sculpture
// This array is used on the platform side to actually send the information // 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 SACNAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaSACN, State->Transient);
assembly_array UARTAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaUART, State->Transient); assembly_array UARTAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaUART, State->Transient);
SACN_BuildOutputData(&State->SACN, OutputData, SACNAssemblies, &State->LedSystem); SACN_BuildOutputData(&State->SACN, OutputData, SACNAssemblies, &State->LedSystem);
UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem, State->Transient); UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem, State->Transient);
#endif
} }
CLEANUP_APPLICATION(CleanupApplication) CLEANUP_APPLICATION(CleanupApplication)

View File

@ -189,6 +189,20 @@ GetSecondsElapsed (s64 Start, s64 End, s64 PerformanceCountFrequency)
return Result; 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 struct context
{ {
gs_thread_context ThreadContext; gs_thread_context ThreadContext;
@ -218,6 +232,9 @@ struct context
platform_draw_font_codepoint* PlatformDrawFontCodepoint; platform_draw_font_codepoint* PlatformDrawFontCodepoint;
platform_get_socket_handle* PlatformGetSocketHandle; platform_get_socket_handle* PlatformGetSocketHandle;
system_time SystemTime_Last;
system_time SystemTime_Current;
}; };
#define FOLDHAUS_PLATFORM_H #define FOLDHAUS_PLATFORM_H

View File

@ -7,6 +7,242 @@
#define FLOWER_COLORS_COUNT 12 #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] = { pixel FlowerAColors[FLOWER_COLORS_COUNT] = {
{ 232,219,88 }, { 232,219,88 },
{ 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 internal void
Pattern_SmoothGrowRainbow(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) 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 #define BLUMEN_PATTERNS_H
#endif // BLUMEN_PATTERNS_H #endif // BLUMEN_PATTERNS_H

View File

@ -620,6 +620,47 @@ WinMain (
} }
DEBUG_TRACK_SCOPE(MainLoop); 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); ResetInputQueue(&InputQueue);
ReloadAndLinkDLL(&DLLRefresh, &Context, &Win32WorkQueue.WorkQueue, false); ReloadAndLinkDLL(&DLLRefresh, &Context, &Win32WorkQueue.WorkQueue, false);

View File

@ -151,6 +151,10 @@ Win32SerialPort_Write(HANDLE PortHandle, gs_data Buffer)
// ?? // ??
}break; }break;
case ERROR_NO_SUCH_DEVICE:
{
}break;
case ERROR_INVALID_HANDLE: case ERROR_INVALID_HANDLE:
InvalidDefaultCase; InvalidDefaultCase;
} }

View File

@ -5,6 +5,67 @@
// //
#ifndef BLUMEN_LUMEN_CPP #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 internal void
BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) 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); Msg = SocketRecieve(Data->SocketManager, Data->ListenSocket, Ctx->Transient);
if (Msg.Size > 0) if (Msg.Size > 0)
{ {
Data->MicPacketBuffer->Values[Data->MicPacketBuffer->WriteHead++] = Msg; MessageQueue_Write(Data->IncomingMsgQueue, Msg);
if (Data->MicPacketBuffer->WriteHead >= PACKETS_MAX)
{
Data->MicPacketBuffer->WriteHead = 0;
}
} }
} }
while (Data->OutgoingMsgQueue->ReadHead != Data->OutgoingMsgQueue->WriteHead) while (MessageQueue_CanRead(Data->OutgoingMsgQueue))
{ {
u32 ReadIndex = Data->OutgoingMsgQueue->ReadHead++; Msg = MessageQueue_Read(Data->OutgoingMsgQueue);
if (Data->OutgoingMsgQueue->ReadHead >= BLUMEN_MESSAGE_QUEUE_COUNT)
{
Data->OutgoingMsgQueue->ReadHead = 0;
}
Msg = Data->OutgoingMsgQueue->Buffers[ReadIndex];
u32 Address = WeathermanIPV4; u32 Address = WeathermanIPV4;
u32 Port = WeathermanPort; u32 Port = WeathermanPort;
s32 Flags = 0; s32 Flags = 0;
@ -88,6 +139,9 @@ BlumenLumen_LoadPatterns(app_state* State)
Patterns_PushPattern(Patterns, Pattern_FlowerColors); Patterns_PushPattern(Patterns, Pattern_FlowerColors);
Patterns_PushPattern(Patterns, Pattern_FlowerColorToWhite); Patterns_PushPattern(Patterns, Pattern_FlowerColorToWhite);
Patterns_PushPattern(Patterns, Pattern_BasicFlowers); Patterns_PushPattern(Patterns, Pattern_BasicFlowers);
// 15
Patterns_PushPattern(Patterns, Pattern_Patchy);
Patterns_PushPattern(Patterns, Pattern_Leafy);
} }
internal pixel internal pixel
@ -116,10 +170,13 @@ BlumenLumen_CustomInit(app_state* State, context Context)
blumen_lumen_state* BLState = (blumen_lumen_state*)Result.Memory; blumen_lumen_state* BLState = (blumen_lumen_state*)Result.Memory;
BLState->Running = true; 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.Running = &BLState->Running;
BLState->MicListenJobData.SocketManager = Context.SocketManager; BLState->MicListenJobData.SocketManager = Context.SocketManager;
BLState->MicListenJobData.MicPacketBuffer = &BLState->MicPacketBuffer; BLState->MicListenJobData.IncomingMsgQueue = &BLState->IncomingMsgQueue;
BLState->MicListenJobData.OutgoingMsgQueue = &BLState->OutgoingMsgQueue; BLState->MicListenJobData.OutgoingMsgQueue = &BLState->OutgoingMsgQueue;
BLState->MicListenJobData.ListenSocket = CreateSocket(Context.SocketManager, "127.0.0.1", "20185"); 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); Anim2.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem);
Animation_AddLayer(&Anim2, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); Animation_AddLayer(&Anim2, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem);
Animation_AddBlock(&Anim2, 0, 100, Patterns_IndexToHandle(5), 0); Animation_AddBlock(&Anim2, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(17), 0);
Animation_AddBlock(&Anim2, 50, Anim0.PlayableRange.Max, Patterns_IndexToHandle(10), 0);
BLState->AnimHandles[2] = AnimationArray_Push(&State->AnimationSystem.Animations, Anim2); 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 GreenString = MakeString("green");
gs_string ILoveYouString = MakeString("i_love_you"); 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]; blumen_packet Packet = *(blumen_packet*)PacketData.Memory;
switch (PacketType) { switch (Packet.Type) {
case PacketType_PatternCommand: case PacketType_PatternCommand:
{ {
microphone_packet Packet = *(microphone_packet*)(PacketData.Memory + 1); microphone_packet Mic = Packet.MicPacket;
u32 NameLen = CStringLength(Packet.AnimationFileName); u32 NameLen = CStringLength(Mic.AnimationFileName);
if (StringEqualsCharArray(BlueString.ConstString, Packet.AnimationFileName, NameLen)) if (StringEqualsCharArray(BlueString.ConstString, Mic.AnimationFileName, NameLen))
{ {
State->AnimationSystem.ActiveFadeGroup.From.Index = 0; 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; 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; State->AnimationSystem.ActiveFadeGroup.From.Index = 2;
} }
@ -233,13 +289,13 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context)
case PacketType_MotorState: case PacketType_MotorState:
{ {
motor_packet Packet = *(motor_packet*)(PacketData.Memory + 1); motor_packet Motor = Packet.MotorPacket;
BLState->LastKnownMotorState = Packet; BLState->LastKnownMotorState = Motor;
gs_string Temp = PushStringF(State->Transient, 256, "Received Motor States: %d %d %d\n", gs_string Temp = PushStringF(State->Transient, 256, "Received Motor States: %d %d %d\n",
Packet.FlowerPositions[0], Motor.FlowerPositions[0],
Packet.FlowerPositions[1], Motor.FlowerPositions[1],
Packet.FlowerPositions[2]); Motor.FlowerPositions[2]);
NullTerminate(&Temp); NullTerminate(&Temp);
OutputDebugStringA(Temp.Str); OutputDebugStringA(Temp.Str);
@ -247,66 +303,97 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context)
case PacketType_Temperature: 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", if (Temp.Temperature > 21)
Packet.Temperature); {
NullTerminate(&Temp); 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; }break;
InvalidDefaultCase; InvalidDefaultCase;
} }
}
if (BLState->MicPacketBuffer.ReadHead >= PACKETS_MAX) // Open / Close the Motor
if (MessageQueue_CanWrite(BLState->OutgoingMsgQueue))
{ {
BLState->MicPacketBuffer.ReadHead = 0; for (u32 i = 0; i < MotorOpenTimesCount; i++)
{
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): led_buffer Buffer = State->LedSystem.Buffers[i];
MotorTimeElapsed = 0; for (u32 j = 0; j < Buffer.LedCount; j++)
u8 Position = LastPosition;
if (LastPosition == 2)
{ {
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
{
LastPosition = 2;
} }
if ((BLState->OutgoingMsgQueue.WriteHead >= BLState->OutgoingMsgQueue.ReadHead) || // Send Status Packet
(BLState->OutgoingMsgQueue.WriteHead < BLState->OutgoingMsgQueue.ReadHead))
{ {
u32 WriteIndex = BLState->OutgoingMsgQueue.WriteHead; 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)
{
BLState->LastStatusUpdateTime = Context->SystemTime_Current;
gs_data* Msg = MessageQueue_GetWrite(&BLState->OutgoingMsgQueue);
gs_data* Msg = BLState->OutgoingMsgQueue.Buffers + WriteIndex; OutputDebugString("Sending Status\n");
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;
// NOTE(pjs): We increment the write head AFTER we've written so that blumen_packet* Packet = (blumen_packet*)Msg->Memory;
// the network thread doesn't think the buffer is ready to send before Packet->Type = PacketType_LumenariumStatus;
// the data is set. We want to avoid the case of: Packet->StatusPacket.NextMotorEventType = 0;
// 1. Main Thread increments write head to 1 Packet->StatusPacket.NextEventTime = 0;
// 2. Network Thread thinks theres a new message to send at 0
// 3. Network Thread sends the message at 0 animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
// 4. Main Thread sets the message at 0 CopyMemoryTo(ActiveAnim->Name.Str, Packet->StatusPacket.AnimFileName,
BLState->OutgoingMsgQueue.WriteHead += 1; Min(ActiveAnim->Name.Length, 32));
if (BLState->OutgoingMsgQueue.WriteHead >= BLUMEN_MESSAGE_QUEUE_COUNT)
{
BLState->OutgoingMsgQueue.WriteHead = 0;
}
} }
} }
} }

View File

@ -11,6 +11,7 @@ enum bl_python_packet_type
PacketType_PatternCommand = 1, PacketType_PatternCommand = 1,
PacketType_MotorState = 2, PacketType_MotorState = 2,
PacketType_Temperature = 3, PacketType_Temperature = 3,
PacketType_LumenariumStatus = 4,
}; };
#pragma pack(push, 1) #pragma pack(push, 1)
@ -35,6 +36,32 @@ typedef struct temp_packet
{ {
s8 Temperature; s8 Temperature;
} temp_packet; } 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) #pragma pack(pop)
#define BLUMEN_MESSAGE_QUEUE_COUNT 32 #define BLUMEN_MESSAGE_QUEUE_COUNT 32
@ -51,17 +78,41 @@ struct mic_listen_job_data
bool* Running; bool* Running;
platform_socket_manager* SocketManager; platform_socket_manager* SocketManager;
packet_ringbuffer* MicPacketBuffer; blumen_network_msg_queue* IncomingMsgQueue;
platform_socket_handle_ ListenSocket; platform_socket_handle_ ListenSocket;
blumen_network_msg_queue* OutgoingMsgQueue; 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 struct blumen_lumen_state
{ {
bool Running; bool Running;
packet_ringbuffer MicPacketBuffer; blumen_network_msg_queue IncomingMsgQueue;
blumen_network_msg_queue OutgoingMsgQueue; blumen_network_msg_queue OutgoingMsgQueue;
temp_job_req JobReq; temp_job_req JobReq;
@ -75,6 +126,11 @@ struct blumen_lumen_state
animation_handle AnimHandles[3]; animation_handle AnimHandles[3];
u32 CurrAnim; u32 CurrAnim;
// NOTE(pjs): Based on temperature data from weatherman
// dim the leds.
r32 BrightnessPercent;
system_time LastStatusUpdateTime;
}; };

View File

@ -219,6 +219,9 @@ int main(int ArgCount, char** Args)
printf("%.*s\n", (u32)OutputBuffer.Length, OutputBuffer.Str); printf("%.*s\n", (u32)OutputBuffer.Length, OutputBuffer.Str);
//printf("%d\n", StripCount); //printf("%d\n", StripCount);
return 0; return 0;
} }