I’m working on my first Odin project, and I want to make sure that I’m going in the right direction with the choices I’ve made so far before they’re cemented in place and too much of a hassle to change easily.
Right now, it’s basically a data structure with wheels, only able to receive packets and parse them into said data structure. However, the next step is to start developing an SDL3/microui frontend (my first real GUI), so I just want confirmation that I’ve not already stepped on a bunch of footguns. Opinions on whether any of this is idiomatic are, of course, welcome as well, as I’ve never really focused on such things, but would like to see whether it’s worth it to do that for Odin.
It is hard for me to do a full review without really understanding the purpose of the app, but here are my initial thoughts:
why start both threads in the background and then have the main thread do a useless sleep? Why not just run receiver on the main thread and spawn the parser in a background thread? (If they even to need to be on separate threads, you could potentially use the nbio instead, but that comes down to taste).
Personally, I would set up the buffers inside of main and pass them to the workers rather than use globals. I think the heavy use of global data makes the data flow confusing, as there’s quite a number of procs that modify data without any obvious inputs or outputs (from the message signature). i.e. entry_parser and data_from_packet. Error handling is also generally easier when you can return (data, ok) or (data, error), rather than have to handle everying inside one big proc.
psi_to_psi is an odd name, but if it you know what it is, then whatever xD
data_from_packet looks too big too me, but I think I prefer smaller functions moreso than the average Odin programmer, so take that with a grain of salt. That being said,
Since you’re using packed structs, that indicates to me that you are trying to map the source data 1:1, in which case, you might actually want to be reading bytes straight off the wire rather than manually mapping all the fields. i.e.
# psuedocode, won't actually work
TELEMETRY_DATA = transmute(type_of(TELEMETRY_DATA) (PACKET_DATA)
But on the whole, I didn’t see any glaring errors or mory leaks or whatnot. For context, I’m not a career C dev or anything, and am only on my second Odin project. However I’m quite familiar with go, which shares some lineage with Odin.
I suggest you have a look at the nbio package for non blocking io. There are some simple examples in the examples project, and a slightly more complicated (but still digestible) one on my github, the http library. In particular, mine may give you some ideas about putting the io in a separate thread.
I was reserving the main thread for orchestrating other threads and running the gui loop.
I’ll definitely try to make it more legible, I just generally care most about efficiency/performance, so this was the most performant idea I had when laying out the architecture.
Gotta inject humor where I can!
Yes, Packet_Structure matches the incoming data exactly, which is how I’m simply casting WORKING_DATA_BUF_PTR as a ^Packet_Structure instead of manually parsing it there. If I could do something like your pseurocode for data_from_packet, that would be perfect, I’ll definitely see if I can get it to work.