diff --git a/run_tree/osx/arm64/debug/lumenarium b/run_tree/osx/arm64/debug/lumenarium index 17af5b0..35a3987 100755 Binary files a/run_tree/osx/arm64/debug/lumenarium and b/run_tree/osx/arm64/debug/lumenarium differ diff --git a/src/app/engine/sacn/foldhaus_sacn.h b/src/app/engine/sacn/foldhaus_sacn.h index 7c03209..ae29913 100644 --- a/src/app/engine/sacn/foldhaus_sacn.h +++ b/src/app/engine/sacn/foldhaus_sacn.h @@ -275,10 +275,10 @@ InitStreamHeader (u8* Buffer, s32 BufferSize, Cursor = PackB1(Cursor, ADDRESS_AND_DATA_FORMAT); // DMP first property address - Cursor = PackB2(Cursor, 0); + Cursor = PackB1(Cursor, 0); // DMP Address Increment - Cursor = PackB2(Cursor, ADDRESS_INC); + Cursor = PackB1(Cursor, ADDRESS_INC); // Property Value Count -- Includes one byte for start code Cursor = PackB2(Cursor, SlotCount + 1); diff --git a/src_v2/core/lumenarium_core_memory.h b/src_v2/core/lumenarium_core_memory.h index 2f4e7ef..f732897 100644 --- a/src_v2/core/lumenarium_core_memory.h +++ b/src_v2/core/lumenarium_core_memory.h @@ -199,7 +199,7 @@ dw_get_u8(Data_Writer* w) u8 result = 0; if (w->at < w->data.size) { - result = w->data.base[w->at++]; + result = w->data.base[w->at]; } return result; } diff --git a/src_v2/core/lumenarium_core_socket.h b/src_v2/core/lumenarium_core_socket.h index c59b228..9b78460 100644 --- a/src_v2/core/lumenarium_core_socket.h +++ b/src_v2/core/lumenarium_core_socket.h @@ -3,6 +3,91 @@ typedef struct { u64 value; } Socket_Handle; -// TODO +u16 endian_swap_u16(u16 v); +u32 endian_swap_u32(u32 v); +u64 endian_swap_u64(u64 v); + +#define hton_u16(v) endian_swap_u16(v) +#define hton_u32(v) endian_swap_u32(v) +#define hton_u64(v) endian_swap_u64(v) +#define ntoh_s16(v) endian_swap_u16(v) +#define ntoh_s32(v) endian_swap_u32(v) +#define ntoh_s64(v) endian_swap_u64(v) + + +////////////////////////////////////////// +// Implementation + +u16 +endian_swap_u16(u16 v) +{ + u8* p = (u8*)&v; + u16 result = (u16)( + (p[0] << 8) | + (p[1] << 0) + ); + return result; +} + +u32 +endian_swap_u32(u32 v) +{ + u8* p = (u8*)&v; + u32 result = (u32)( + (p[0] << 24) | + (p[1] << 16) | + (p[2] << 8) | + (p[3] << 0) + ); + return result; +} + +u64 +endian_swap_u64(u64 v) +{ + u8* p = (u8*)&v; + u64 result = (u64)( + ((u64)p[0] << 56) | + ((u64)p[1] << 48) | + ((u64)p[2] << 40) | + ((u64)p[3] << 32) | + ((u64)p[4] << 24) | + ((u64)p[5] << 16) | + ((u64)p[6] << 8) | + ((u64)p[7] << 0) + ); + return result; +} + +#if defined(DEBUG) + +void +core_socket_tests() +{ + // u16 endian swap + u16 a_0 = 0xABCD; + u16 a_1 = endian_swap_u16(a_0); + u16 a_2 = endian_swap_u16(a_1); + assert(a_1 == 0xCDAB); + assert(a_2 == a_0); + + // u32 endian swap + u32 b_0 = 0x89ABCDEF; + u32 b_1 = endian_swap_u32(b_0); + u32 b_2 = endian_swap_u32(b_1); + assert(b_1 == 0xEFCDAB89); + assert(b_2 == b_0); + + // u64 endian swap + u64 c_0 = 0x7654321089ABCDEF; + u64 c_1 = endian_swap_u64(c_0); + u64 c_2 = endian_swap_u64(c_1); + assert(c_1 == 0xEFCDAB8910325476); + assert(c_2 == c_0); +} + +#else +# define core_socket_tests() +#endif #endif // LUMENARIUM_CORE_SOCKET_H \ No newline at end of file diff --git a/src_v2/core/lumenarium_core_string.h b/src_v2/core/lumenarium_core_string.h index 92a81ef..6f7b5b8 100644 --- a/src_v2/core/lumenarium_core_string.h +++ b/src_v2/core/lumenarium_core_string.h @@ -1,6 +1,8 @@ ////////////////////////////////////////////// // String +internal u64 c_str_len(char* s); + // NOTE(PS): even though this has a len and cap, it should always be // null terminated typedef struct String String; @@ -296,4 +298,22 @@ dw_put_str(Data_Writer* w, String str) { dw_put_u8(w, str.str[i]); } +} + +internal void +dw_put_str_min_len(Data_Writer* w, String str, u64 min_len) +{ + u64 start = w->at; + dw_put_str(w, str); + if (str.len < min_len) + { + w->at = start + min_len; + } +} + +internal void +dw_put_str_min_len_nullterm(Data_Writer* w, String str, u64 min_len) +{ + dw_put_str_min_len(w, str, min_len); + w->data.base[w->at - 1] = '\0'; } \ No newline at end of file diff --git a/src_v2/engine/lumenarium_engine.c b/src_v2/engine/lumenarium_engine.c index 747a923..9892dc6 100644 --- a/src_v2/engine/lumenarium_engine.c +++ b/src_v2/engine/lumenarium_engine.c @@ -7,9 +7,9 @@ en_init(App_State* state, App_Init_Desc desc) state->assemblies = assembly_array_create(permanent, desc.assembly_cap); Output* o = &state->output; - register_output_method(o, OutputData_Invalid, 0, 0); - register_output_method(o, OutputData_NetworkSACN, output_network_sacn_build, output_network_sacn_init()); - register_output_method(o, OutputData_ComUART, output_network_sacn_build, output_com_uart_init()); + register_output_method(o, OutputData_Invalid, 0, 0, 0); + register_output_method(o, OutputData_NetworkSACN, output_network_sacn_update, output_network_sacn_build, output_network_sacn_init()); + register_output_method(o, OutputData_ComUART, 0, output_network_sacn_build, output_com_uart_init()); lumenarium_env_validate(); } @@ -50,28 +50,38 @@ en_frame(App_State* state) /////////////////////////////////////// // Output Data - + Output_Methods methods = state->output.methods; + + // update each method that has an update method + for (u32 i = 0; i < OutputData_Count; i++) + { + if (methods.update_procs[i] == 0) continue; + methods.update_procs[i](methods.method_data[i]); + } + Output_Data_Queue output_queue = {}; output_queue.a = scratch.a; // build output data buffers - Output_Methods methods = state->output.methods; for (u32 i = 0; i < assemblies.len; i++) { Assembly_Strip_Array strips = assemblies.strip_arrays[i]; + Assembly_Pixel_Buffer* pixels = assemblies.pixel_buffers + i; for (u32 j = 0; j < strips.len; j++) { Assembly_Strip* strip = strips.strips + j; Build_Output_Data_Buffer* method_proc = methods.procs[strip->output_kind]; u8* method_data = methods.method_data[strip->output_kind]; if (method_proc == 0) continue; - method_proc(state, i, strip, method_data, &output_queue); + method_proc(state, i, pixels, strip, method_data, &output_queue); } } // output the buffers // TODO(PS): we could sort these first if switchig between output // types is time consuming + + Sacn* sacn = (Sacn*)state->output.methods.method_data[OutputData_NetworkSACN]; for (Output_Data* at = output_queue.first; at != 0; at = at->next) { // NOTE(PS): we can overload each switch case as more methods come in @@ -82,7 +92,13 @@ en_frame(App_State* state) { case OutputData_NetworkSACN: { - // TODO(PS): platform network io + os_socket_send_to( + sacn->socket, + at->network.v4_addr, + at->network.port, + at->data, + 0 + ); } break; case OutputData_ComUART: diff --git a/src_v2/engine/lumenarium_engine_output.c b/src_v2/engine/lumenarium_engine_output.c index 92c23ad..d295d19 100644 --- a/src_v2/engine/lumenarium_engine_output.c +++ b/src_v2/engine/lumenarium_engine_output.c @@ -1,7 +1,8 @@ internal void -register_output_method(Output* output, Output_Data_Kind kind, Build_Output_Data_Buffer* proc, u8* method_data) +register_output_method(Output* output, Output_Data_Kind kind, Output_Method_Update* update, Build_Output_Data_Buffer* proc, u8* method_data) { + output->methods.update_procs[kind] = update; output->methods.procs[kind] = proc; output->methods.method_data[kind] = method_data; } @@ -13,6 +14,7 @@ output_data_queue_push(Output_Data_Queue* q, u32 size, Output_Data_Kind kind) d->kind = kind; d->data.size = size; d->data.base = allocator_alloc(q->a, size); + sll_push(q->first, q->last, d); return d; } diff --git a/src_v2/engine/lumenarium_engine_output.h b/src_v2/engine/lumenarium_engine_output.h index 3d3ff56..027ce26 100644 --- a/src_v2/engine/lumenarium_engine_output.h +++ b/src_v2/engine/lumenarium_engine_output.h @@ -49,11 +49,13 @@ struct Output_Data_Queue Allocator* a; }; -typedef void Build_Output_Data_Buffer(App_State* state, u32 assembly_id, Assembly_Strip* strip, u8* method_data, Output_Data_Queue* queue); +typedef void Output_Method_Update(u8* method_data); +typedef void Build_Output_Data_Buffer(App_State* state, u32 assembly_id, Assembly_Pixel_Buffer* pixels, Assembly_Strip* strip, u8* method_data, Output_Data_Queue* queue); typedef struct Output_Methods Output_Methods; struct Output_Methods { + Output_Method_Update* update_procs[OutputData_Count]; Build_Output_Data_Buffer* procs[OutputData_Count]; u8* method_data[OutputData_Count]; }; @@ -64,7 +66,7 @@ struct Output Output_Methods methods; }; -internal void register_output_method(Output* output, Output_Data_Kind kind, Build_Output_Data_Buffer* proc, u8* method_data); +internal void register_output_method(Output* output, Output_Data_Kind kind, Output_Method_Update* update, Build_Output_Data_Buffer* proc, u8* method_data); internal Output_Data* output_data_queue_push(Output_Data_Queue* q, u32 size, Output_Data_Kind kind); diff --git a/src_v2/engine/output/lumenarium_output_sacn.c b/src_v2/engine/output/lumenarium_output_sacn.c index ada76ca..fd46365 100644 --- a/src_v2/engine/output/lumenarium_output_sacn.c +++ b/src_v2/engine/output/lumenarium_output_sacn.c @@ -1,5 +1,6 @@ #define SACN_DEFAULT_PORT 5568 +#define SACN_STARTCODE_DMX 0 // a description of the address space being used #define SACN_PREAMBLE_SIZE_ADDR 0 @@ -59,13 +60,12 @@ internal void sacn_vhd_pack_flags(Data_Writer* w, b8 inherit_vec, b8 inherit_head, b8 inherit_data) { u8 last_byte = dw_get_u8(w) & 0x8F; - w->at -= 1; if (!inherit_vec) { last_byte |= SACN_VHD_V_FLAG; } if (!inherit_head) { last_byte |= SACN_VHD_H_FLAG; } if (!inherit_data) { last_byte |= SACN_VHD_D_FLAG; } - dw_put_u8(w, last_byte); + w->data.base[w->at] = last_byte; } internal void @@ -86,7 +86,6 @@ sacn_vhd_pack_len(Data_Writer* w, u32 len, b8 include_len) // Mask out the length bits to keep flags intact u8 last_byte = dw_get_u8(w) & 0x70; - w->at -= 1; if (len_adjusted > SACN_VHD_MAXMINLENGTH) last_byte |= SACN_VHD_L_FLAG; @@ -105,14 +104,230 @@ sacn_vhd_pack_len(Data_Writer* w, u32 len, b8 include_len) } } +#define CopyMemoryTo(from, to, size) CopyMemory_((u8*)(from), (u8*)(to), (size)) +internal void +CopyMemory_(u8* From, u8* To, u64 Size) +{ + for (u64 i = 0; i < Size; i++) + { + To[i] = From[i]; + } +} + +// Packs a u8 to a known big endian buffer +u8* +PackB1(u8* ptr, u8 val) +{ + *ptr = val; + return ptr + sizeof(val); +} + +//Unpacks a u8 from a known big endian buffer +u8 +UpackB1(const u8* ptr) +{ + return *ptr; +} + +//Packs a u8 to a known little endian buffer +u8* +PackL1(u8* ptr, u8 val) +{ + *ptr = val; + return ptr + sizeof(val); +} + +//Unpacks a u8 from a known little endian buffer +u8 +UpackL1(const u8* ptr) +{ + return *ptr; +} + +u8* +PackB2(u8* ptr, u16 val) +{ + ptr[1] = (u8)(val & 0xff); + ptr[0] = (u8)((val & 0xff00) >> 8); + return ptr + sizeof(val); +} + +//Unpacks a u16 from a known big endian buffer +u16 +UpackB2(const u8* ptr) +{ + return (u16)(ptr[1] | ptr[0] << 8); +} + +//Packs a u32 to a known big endian buffer +u8* +PackB4(u8* ptr, u32 val) +{ + ptr[3] = (u8) (val & 0xff); + ptr[2] = (u8)((val & 0xff00) >> 8); + ptr[1] = (u8)((val & 0xff0000) >> 16); + ptr[0] = (u8)((val & 0xff000000) >> 24); + return ptr + sizeof(val); +} + +internal void +VHD_PackFlags_(u8* Buffer, b32 InheritVec, b32 InheritHead, b32 InheritData) +{ + u8* Cursor = Buffer; + u8 NewByte = UpackB1(Cursor) & 0x8f; + + if (!InheritVec) { NewByte |= SACN_VHD_V_FLAG; } + if (!InheritHead) { NewByte |= SACN_VHD_H_FLAG; } + if (!InheritData) { NewByte |= SACN_VHD_D_FLAG; } + + PackB1(Cursor, NewByte); +} + +internal u8* +VHD_PackLength_(u8* Buffer, u32 Length, b32 IncludeLength) +{ + u8* Cursor = Buffer; + u32 AdjustedLength = Length; + if (IncludeLength) + { + if (Length + 1 > SACN_VHD_MAXMINLENGTH) + { + AdjustedLength += 2; + } + else + { + AdjustedLength += 1; + } + } + + // Mask out the length bits to keep flags intact + u8 NewByte = UpackB1(Cursor) & 0x70; + if (AdjustedLength > SACN_VHD_MAXMINLENGTH) + { + NewByte |= SACN_VHD_L_FLAG; + } + + u8 PackBuffer[4]; + PackB4(PackBuffer, AdjustedLength); + if (AdjustedLength <= SACN_VHD_MAXMINLENGTH) + { + NewByte |= (PackBuffer[2] & 0x0f); + Cursor = PackB1(Cursor, NewByte); + Cursor = PackB1(Cursor, PackBuffer[3]); + } + else + { + NewByte |= (PackBuffer[1] & 0x0f); + Cursor = PackB1(Cursor, PackBuffer[2]); + Cursor = PackB1(Cursor, PackBuffer[3]); + } + + return Cursor; +} + +internal void +InitStreamHeader (u8* Buffer, s32 BufferSize, + u16 SlotCount, + u8 StartCode, + u16 Universe, + u8 Priority, + u16 Reserved, + u8 Options, + const char* SourceName, + Sacn_Cid CID + ) +{ + // TODO(pjs): Replace packing with gs_memory_cursor + + u8* Cursor = Buffer; + + // Preamble Size + Cursor = PackB2(Cursor, SACN_RLP_PREAMBLE_SIZE); + Cursor = PackB2(Cursor, SACN_RLP_POSTAMBLE_SIZE); + + CopyMemoryTo(SACN_ACN_IDENTIFIER.str, Cursor, SACN_ACN_IDENTIFIER_SIZE); + Cursor += SACN_ACN_IDENTIFIER_SIZE; + + // TODO(Peter): If you never use this anywhere else, go back and remove the parameters + VHD_PackFlags_(Cursor, false, false, false); + Cursor = VHD_PackLength_(Cursor, + SACN_BUFFER_HEADER_SIZE - SACN_RLP_PREAMBLE_SIZE + SlotCount, + false); + + // root vector + Cursor = PackB4(Cursor, SACN_ROOT_VECTOR); // 22 + + // CID Pack + for (s32 i = 0; i < SACN_CID_BYTES; i++) + { + *Cursor++ = CID.bytes[i]; + }// 38 + + VHD_PackFlags_(Cursor, false, false, false); + Cursor = VHD_PackLength_(Cursor, + SACN_BUFFER_HEADER_SIZE - SACN_FRAMING_FLAGS_AND_LEN_ADDR + SlotCount, + false); + // 40 + // framing vector + Cursor = PackB4(Cursor, SACN_FRAMING_VECTOR); + + // framing source name + // :Check + + CopyMemoryTo(SourceName, (char*)Cursor, c_str_len((char*)SourceName)); + Cursor[SACN_SOURCE_NAME_SIZE - 1] = '\0'; + Cursor += SACN_SOURCE_NAME_SIZE; // 108 + + // priority + Cursor = PackB1(Cursor, Priority); + + // reserved + Cursor = PackB2(Cursor, Reserved); // 111 + + // Sequence # is always set to 0/NONE at the beginning, but it is incremented when sending data + Cursor = PackB1(Cursor, 0); + + // Options + Cursor = PackB1(Cursor, Options); + + // Universe + Cursor = PackB2(Cursor, Universe); // 115 + + VHD_PackFlags_(Cursor, false, false, false); + Cursor = VHD_PackLength_(Cursor, + SACN_BUFFER_HEADER_SIZE - SACN_DMP_FLAGS_AND_LEN_ADDR + SlotCount, + false); // 117 + + // DMP Vector + Cursor = PackB1(Cursor, SACN_DMP_VECTOR); + + // DMP Address and data type + Cursor = PackB1(Cursor, SACN_ADDRESS_AND_DATA_FORMAT); + + // DMP first property address + Cursor = PackB1(Cursor, 0); + + // DMP Address Increment + Cursor = PackB1(Cursor, SACN_ADDR_INC); + + // Property Value Count -- Includes one byte for start code + Cursor = PackB2(Cursor, SlotCount + 1); + + Cursor = PackB1(Cursor, StartCode); + + assert(Cursor - Buffer == SACN_BUFFER_HEADER_SIZE); + +} + internal void sacn_fill_buffer_header(Output_Data* d, u16 universe, Sacn* sacn) { assert(d && d->data.size > 0); // TODO(PS): these should be passed in? - u16 slot_count = 0; - u8 start_code = 0; + u16 slot_count = SACN_BUFFER_BODY_SIZE; + u8 start_code = SACN_STARTCODE_DMX; + // universe u8 priority = 0; u16 reserved = 0; u8 options = 0; @@ -122,7 +337,7 @@ sacn_fill_buffer_header(Output_Data* d, u16 universe, Sacn* sacn) dw_put_u16_b(&w, SACN_RLP_PREAMBLE_SIZE); dw_put_u16_b(&w, SACN_RLP_POSTAMBLE_SIZE); - dw_put_str(&w, SACN_ACN_IDENTIFIER); + dw_put_str_min_len(&w, SACN_ACN_IDENTIFIER, SACN_ACN_IDENTIFIER_SIZE); sacn_vhd_pack_flags(&w, false, false, false); sacn_vhd_pack_len(&w, SACN_BUFFER_HEADER_SIZE - SACN_RLP_PREAMBLE_SIZE + slot_count, false); @@ -130,16 +345,17 @@ sacn_fill_buffer_header(Output_Data* d, u16 universe, Sacn* sacn) dw_put_u32_b(&w, SACN_ROOT_VECTOR); for (u32 i = 0; i < SACN_CID_BYTES; i++) dw_put_u8(&w, sacn->cid.bytes[i]); - + sacn_vhd_pack_flags(&w, false, false, false); sacn_vhd_pack_len(&w, SACN_BUFFER_HEADER_SIZE - SACN_FRAMING_FLAGS_AND_LEN_ADDR + slot_count, false); dw_put_u32_b(&w, SACN_FRAMING_VECTOR); - dw_put_str(&w, sacn->source_name); + + dw_put_str_min_len_nullterm(&w, sacn->source_name, SACN_SOURCE_NAME_SIZE); dw_put_u8(&w, priority); - dw_put_u16_b(&w, reserved); - dw_put_u8(&w, 0); // Sequence Number starts at 0, gets updated + dw_put_u16_b(&w, reserved); // synchronization + dw_put_u8(&w, sacn->sequence_iter); dw_put_u8(&w, options); dw_put_u16_b(&w, universe); @@ -148,8 +364,8 @@ sacn_fill_buffer_header(Output_Data* d, u16 universe, Sacn* sacn) dw_put_u8(&w, SACN_DMP_VECTOR); dw_put_u8(&w, SACN_ADDRESS_AND_DATA_FORMAT); - dw_put_u8(&w, 0); // dmp first priority addr - dw_put_u8(&w, SACN_ADDR_INC); // dmp address increment + dw_put_u16_b(&w, 0); // dmp first priority addr + dw_put_u16_b(&w, SACN_ADDR_INC); // dmp address increment dw_put_u16_b(&w, slot_count + 1); dw_put_u8(&w, start_code); @@ -157,9 +373,20 @@ sacn_fill_buffer_header(Output_Data* d, u16 universe, Sacn* sacn) } internal void -sacn_fill_buffer_body(Output_Data* d, u32* leds_placed) +sacn_fill_buffer_body(Output_Data* d, Assembly_Pixel_Buffer* pixels, Assembly_Strip* strip, u32* leds_placed) { - + u32 first = *leds_placed; + u32 to_add = min(strip->pixels_len - first, SACN_BUFFER_BODY_SIZE / 3); + u32 one_past_last = first + to_add; + for (u32 i = *leds_placed; i < one_past_last; i++) + { + u32 led_index = strip->pixels[i]; + Assembly_Pixel color = pixels->pixels[led_index]; + d->data.base[SACN_BUFFER_HEADER_SIZE + (i * 3) + 0] = color.r; + d->data.base[SACN_BUFFER_HEADER_SIZE + (i * 3) + 1] = color.g; + d->data.base[SACN_BUFFER_HEADER_SIZE + (i * 3) + 2] = color.b; + } + *leds_placed += to_add; } internal Sacn_Cid @@ -178,16 +405,34 @@ internal u8* output_network_sacn_init() { Sacn* result = allocator_alloc_struct(permanent, Sacn); - // TODO(PS): get platform send socket + zero_struct(*result); + + result->source_name = string_f(permanent, "lumenarium::incenter"); String cid_str = lit_str("{67F9D986-544E-4abb-8986-D5F79382586C}"); result->cid = sacn_string_to_cid(cid_str); - + + s32 ttl = 20; + result->socket = os_socket_create(AF_INET, SOCK_DGRAM, 0); + os_socket_set_opt( + result->socket, + IPPROTO_IP, + IP_MULTICAST_TTL, + (u8*)&ttl, sizeof(ttl) + ); + return (u8*)result; } internal void -output_network_sacn_build(App_State* state, u32 assembly_id, Assembly_Strip* strip, u8* method_data, Output_Data_Queue* queue) +output_network_sacn_update(u8* method_data) +{ + Sacn* sacn = (Sacn*)method_data; + sacn->sequence_iter += 1; +} + +internal void +output_network_sacn_build(App_State* state, u32 assembly_id, Assembly_Pixel_Buffer* pixels, Assembly_Strip* strip, u8* method_data, Output_Data_Queue* queue) { Sacn* sacn = (Sacn*)method_data; @@ -200,8 +445,9 @@ output_network_sacn_build(App_State* state, u32 assembly_id, Assembly_Strip* str Output_Data* d = output_data_queue_push(queue, SACN_BUFFER_SIZE, OutputData_NetworkSACN); output_data_set_network_addr(d, v4_send_addr, send_port); + //InitStreamHeader(d->data.base, d->data.size, SACN_BUFFER_BODY_SIZE, SACN_STARTCODE_DMX, universe, 0, 0, 0, "lumenarium::sacn", sacn->cid); sacn_fill_buffer_header(d, universe, sacn); - sacn_fill_buffer_body(d, &leds_placed); + sacn_fill_buffer_body(d, pixels, strip, &leds_placed); universe += 1; } } diff --git a/src_v2/engine/output/lumenarium_output_sacn.h b/src_v2/engine/output/lumenarium_output_sacn.h index 0f762c7..09f96ae 100644 --- a/src_v2/engine/output/lumenarium_output_sacn.h +++ b/src_v2/engine/output/lumenarium_output_sacn.h @@ -16,9 +16,11 @@ struct Sacn Sacn_Cid cid; s32 sequence_iter; String source_name; + Socket_Handle socket; }; internal u8* output_network_sacn_init(); -internal void output_network_sacn_build(App_State* state, u32 assembly_id, Assembly_Strip* strip, u8* method_data, Output_Data_Queue* queue); +internal void output_network_sacn_update(u8* method_data); +internal void output_network_sacn_build(App_State* state, u32 assembly_id, Assembly_Pixel_Buffer* pixels, Assembly_Strip* strip, u8* method_data, Output_Data_Queue* queue); #endif //LUMENARIUM_OUTPUT_SACN_H diff --git a/src_v2/lumenarium_first.c b/src_v2/lumenarium_first.c index 5178b03..5249156 100644 --- a/src_v2/lumenarium_first.c +++ b/src_v2/lumenarium_first.c @@ -9,7 +9,8 @@ lumenarium_init(Editor_Desc* ed_desc) permanent = bump_allocator_create_reserve(GB(2)); global_scratch_ = bump_allocator_create_reserve(GB(4)); - //run_tests(); + run_tests(); + scratch_get(scratch); App_Init_Desc desc = incenter_get_init_desc(); // TODO(PS): make sure the values make sense in desc @@ -20,6 +21,7 @@ lumenarium_init(Editor_Desc* ed_desc) add_flag(state->flags, AppState_RunUserSpace); state->file_async_job_system = os_file_jobs_init(); + open_sockets_init(); state->input_state = input_state_create(permanent); String exe_file_path = os_get_exe_path(scratch.a); diff --git a/src_v2/lumenarium_first.h b/src_v2/lumenarium_first.h index 92d2067..16970f1 100644 --- a/src_v2/lumenarium_first.h +++ b/src_v2/lumenarium_first.h @@ -17,6 +17,7 @@ global Allocator* global_scratch_; // gets reset at frame boundaries // Engine typedef struct Assembly_Strip Assembly_Strip; +typedef struct Assembly_Pixel_Buffer Assembly_Pixel_Buffer; #include "engine/lumenarium_engine_output.h" #include "engine/lumenarium_engine_assembly.h" #include "engine/output/lumenarium_output_uart.h" @@ -48,6 +49,8 @@ lumenarium_env_validate_() bump_allocator_validate(permanent); bump_allocator_validate(global_scratch_); bump_allocator_validate(file_jobs_arena); + + core_socket_tests(); } diff --git a/src_v2/lumenarium_types.h b/src_v2/lumenarium_types.h index 85e32dc..7937a14 100644 --- a/src_v2/lumenarium_types.h +++ b/src_v2/lumenarium_types.h @@ -155,7 +155,7 @@ dw_get_u8(Data_Writer* w) u8 result = 0; if (w->at < w->data.size) { - result = w->data.base[w->at++]; + result = w->data.base[w->at]; } return result; } @@ -227,6 +227,24 @@ dw_put_str(Data_Writer* w, String str) } } +internal void +dw_put_str_min_len(Data_Writer* w, String str, u64 min_len) +{ + u64 start = w->at; + dw_put_str(w, str); + if (str->len < min_len) + { + w->at = start + min_len; + } +} + +internal void +dw_put_str_min_len_nullterm(Data_Writer* w, String str, u64 min_len) +{ + dw_put_str_min_len(w, str, min_len); + w->data.base[w->at - 1] = '\0'; +} + // TODO(PS): get functions #define Bytes(x) (x) diff --git a/src_v2/platform/lumenarium_os.h b/src_v2/platform/lumenarium_os.h index b83cf91..67e1719 100644 --- a/src_v2/platform/lumenarium_os.h +++ b/src_v2/platform/lumenarium_os.h @@ -45,14 +45,17 @@ u32 os_interlocked_cmp_exchg(volatile u32* dest, u32 new_value, u32 old_value); /////////////////////////////////////// // Network Access -Socket_Handle os_socket_create(); +Socket_Handle os_socket_create(s32 domain, s32 type, s32 protocol); bool os_socket_bind(); bool os_socket_connect(); bool os_socket_close(); Data os_socket_recv(); -s32 os_Socket_set_listening(); -s32 os_Socket_send(); -s32 os_Socket_send_to(); -s32 os_Socket_set_opt(); +s32 os_socket_set_listening(); +s32 os_socket_send(); +s32 os_socket_send_to(Socket_Handle handle, u32 addr, u32 port, Data data, s32 flags); +s32 os_socket_set_opt(Socket_Handle handle, int level, int option_name, +u8* option_value, s32 option_len); + +void open_sockets_init(); #endif // LUMENARIUM_OS \ No newline at end of file diff --git a/src_v2/platform/osx/lumenarium_first_osx.c b/src_v2/platform/osx/lumenarium_first_osx.c index 220bc7b..e2cbde7 100644 --- a/src_v2/platform/osx/lumenarium_first_osx.c +++ b/src_v2/platform/osx/lumenarium_first_osx.c @@ -8,6 +8,9 @@ #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #include +#include +#include + #include "lumenarium_osx_memory.h" #include "../../core/lumenarium_core.h" #include "../lumenarium_os.h" @@ -37,34 +40,15 @@ osx_err_print_(char* proc, char* sub_proc, s32 errsv) #define OS_FILE_HANDLE_TYPE s32 #define OS_FILE_MAX_PATH PATH_MAX #define OS_FILE_INVALID_HANDLE -1 +#define OS_SOCKET_TYPE s32 +#define OS_SOCKET_INVALID_HANDLE -1 #include "../shared/lumenarium_shared_file_tracker.h" #include "../shared/lumenarium_shared_file_async_work_on_job.h" +#include "../shared/lumenarium_shared_network.h" #include "lumenarium_osx_file.h" #include "lumenarium_osx_time.h" #include "lumenarium_osx_graphics.h" - -void osx_tests() -{ - Ticks t0 = os_get_ticks(); - - // File Tests - File_Handle file = os_file_open(lit_str("text.txt"), FileAccess_Read | FileAccess_Write, FileCreate_OpenAlways); - File_Info info = os_file_get_info(file, global_scratch_); - Data d = os_file_read_all(file, global_scratch_); - os_file_write_all(file, d); - os_file_close(file); - - // Path tests - String path_exe = os_get_exe_path(global_scratch_); - printf("%.*s\n", str_varg(path_exe)); - String path = string_chop_last_slash(path_exe); - String path0 = string_copy(path, global_scratch_); - os_pwd_set(path0); - - Ticks t1 = os_get_ticks(); - Ticks td = get_ticks_elapsed(t0, t1); - r64 sd = ticks_to_seconds(td, os_get_ticks_per_second()); -} +#include "lumenarium_osx_network.h" void glfw_error_callback(int error, const char* description) @@ -279,9 +263,7 @@ scroll_callback(GLFWwindow* window, double xoffset, double yoffset) } int main (int arg_count, char** args) -{ - // osx_tests(); - +{ if (!glfwInit()) { printf("Error: Could not initialize glfw.\n"); diff --git a/src_v2/platform/osx/lumenarium_osx_network.h b/src_v2/platform/osx/lumenarium_osx_network.h new file mode 100644 index 0000000..983efda --- /dev/null +++ b/src_v2/platform/osx/lumenarium_osx_network.h @@ -0,0 +1,86 @@ +Socket_Handle +os_socket_create(s32 domain, s32 type, s32 protocol) +{ + Socket_Handle result = {}; + OS_SOCKET_TYPE sock = socket(domain, type, protocol); + if (sock == -1) { + perror("Error: os_socket_create\n"); + return result; + } + + result = open_sockets_put(sock); + if (result.value == 0) + { + fprintf(stderr, "Error: os_socket_create - not enough room in open_sockets\n"); + } + return result; +} + +bool +os_socket_bind() +{ + return false; +} + +bool +os_socket_connect() +{ + return false; +} + +bool +os_socket_close() +{ + return false; +} + +Data +os_socket_recv() +{ + return (Data){}; +} + +s32 +os_socket_set_listening() +{ + return 0; +} + +s32 +os_socket_send() +{ + return 0; +} + +s32 +os_socket_send_to(Socket_Handle handle, u32 addr, u32 port, Data data, s32 flags) +{ + OS_SOCKET_TYPE sock = open_sockets_get(handle); + + struct sockaddr_in dst = { + .sin_family = AF_INET, + .sin_port = hton_u16(port), + .sin_addr.s_addr = hton_u32(addr), + }; + struct sockaddr* dst_ptr = (struct sockaddr*)&dst; + s32 len_sent = sendto(sock, data.base, data.size, flags, dst_ptr, sizeof(struct sockaddr_in)); + if (len_sent == -1) + { + perror("Error: os_socket_send_to\n"); + return 0; + } + + return len_sent; +} + +s32 +os_socket_set_opt(Socket_Handle handle, int level, int option_name, +u8* option_value, s32 option_len) +{ + OS_SOCKET_TYPE sock = open_sockets_get(handle); + s32 err = setsockopt(sock, level, option_name, (void*)option_value, (socklen_t)option_len); + if (err) { + fprintf(stderr, "Error: setsockopt - %d\n\targs: %d %d %.*s\n", err, level, option_name, option_len, (char*)option_value); + } + return 0; +} diff --git a/src_v2/platform/shared/lumenarium_shared_network.h b/src_v2/platform/shared/lumenarium_shared_network.h new file mode 100644 index 0000000..d4d1986 --- /dev/null +++ b/src_v2/platform/shared/lumenarium_shared_network.h @@ -0,0 +1,67 @@ +#if !defined(OS_SOCKET_TYPE) +# error "You must define an OS_SOCKET_TYPE" +#endif + +#if !defined(OS_SOCKET_INVALID_HANDLE) +# error "You must define an OS_SOCKET_INVALID_HANDLE" +#endif + +#define open_sockets_cap 2 +global u32 open_sockets_len = 1; +global OS_SOCKET_TYPE open_sockets[open_sockets_cap]; + +void open_sockets_init(); +s32 open_sockets_next_free(); +bool open_sockets_has_room(); +OS_SOCKET_TYPE open_sockets_get(Socket_Handle handle); +Socket_Handle open_sockets_put(OS_SOCKET_TYPE socket); +void open_sockets_rem(Socket_Handle handle); + +//////////////////////////////////////////////// +// IMPLEMENTATION + +void +open_sockets_init() +{ + for (u32 i = 0; i < open_sockets_cap; i++) + { + open_sockets[i] = OS_SOCKET_INVALID_HANDLE; + } +} + +s32 +open_sockets_next_free() +{ + if (open_sockets_len < open_sockets_cap) return open_sockets_len++; + for (u32 i = 1; i < open_sockets_len; i++) + { + if (open_sockets[i] == OS_SOCKET_INVALID_HANDLE) return i; + } + return 0; +} + +OS_SOCKET_TYPE +open_sockets_get(Socket_Handle handle) +{ + assert(handle.value < open_sockets_len); + return open_sockets[handle.value]; +} + +Socket_Handle +open_sockets_put(OS_SOCKET_TYPE socket) +{ + Socket_Handle result = { .value = open_sockets_next_free() }; + assert(result.value != 0); + open_sockets[result.value] = socket; + return result; +} + +void +open_sockets_rem(Socket_Handle handle) +{ + assert(handle.value < open_sockets_len); + open_sockets[handle.value] = OS_SOCKET_INVALID_HANDLE; + if (handle.value + 1 == open_sockets_len) { + open_sockets_len -= 1; + } +} diff --git a/src_v2/user_space/user_space_incenter.cpp b/src_v2/user_space/user_space_incenter.cpp index 876fbe5..3f28c9e 100644 --- a/src_v2/user_space/user_space_incenter.cpp +++ b/src_v2/user_space/user_space_incenter.cpp @@ -40,6 +40,8 @@ incenter_init(App_State* state) for (u32 i = 0; i < 40; i++) { Assembly_Strip* strip = assembly_add_strip(&state->assemblies, ah, 123); + strip->output_kind = OutputData_NetworkSACN; + strip->sacn_universe = i; r32 theta = random_series_next_unilateral(&rand) * r32_tau; r32 phi = random_series_next_unilateral(&rand) * r32_tau;