Leaderboard
Popular Content
Showing content with the highest reputation on 08/05/21 in Posts
-
Can-bus is a really simple communication protocol originally made for cars, but these days they are used for anything, even in subsea christmas trees. For starting with CAN the wiki page is surprisingly good and is a nice starting point along with this url:https://opensource.lely.com/canopen/docs/cmd-tutorial/ Anyways, so I will share two simple codebases, be warned! The code is shitty and both together was coded in less than a week which is why its a uncommented mess (literally made with a knife on my throat as a project saving kung-fu in an EU project). The code is without any lisence, but sadly I cannot show you the actual usage of the code as its properitary but its farily simple so I will just inline it here: canbus_communicator = new CanThread("vcan0"); paxterGen3Tpdo = new PaxterGen3Tpdo(); canbus_communicator->addNode((CanMethodResolver *) paxterGen3Tpdo); canbus_communicator->start(); The C version is very hacky, the first constraint was to write the software in C which is nice as I like C, but I havent programmed in it in a couple of years but it uses the deadly sin of "OOP function pointers", which can be hacky when distributing multiple signals in parallel. So we start with defining a simple canbus reader (implementation in the .c file): enum { INVALID_LENGTH_ARGUMENT = -1 }; struct canbus_reader { int canbus_socket; char *ifname; int(*read_frame)(struct canbus_reader *, int *, char [8], unsigned *); int(*write_frame)(struct canbus_reader, int, const char *, unsigned); }; typedef struct canbus_reader canbus_reader_t; canbus_reader_t *canbus_reader_create(char *ifname, bool block); void canbus_reader_destroy(canbus_reader_t *reader); So far, pretty clean, the pointers here are just for doing reading and writing contained within the namespace. To ease the parallelization processes we thus wrap this into a canbus thread with the following api: struct canbus_thread; typedef struct canbus_thread canbus_thread_t; typedef int (*frame_handler_func)(int, char*, unsigned); enum { MAXIMUM_AMOUNTS_OF_METHODS_PER_THREAD = 1 << 4 }; //__BEGIN_API /** * Creates a handle for a canbus thread * * @param ifname The network interface name to listen to, preferably a can interface * @return A new canbus thread wrapper */ canbus_thread_t *canbus_thread_create(char *ifname); /** * * The canbus thread can handle a frame in multiple ways depending on how the different listeners requires the data * @param canbus_reader The reader itself * @param func_pointer A function pointer which parses the processed can data on the format (id, data, len) * @return 0 if successful else -1 */ int add_method_to_canbus_thread_handler(canbus_thread_t *canbus_reader, frame_handler_func func); int start_thread(canbus_thread_t *thread); // THIS SHOULD PROBABLY BE REFACTORED TO THREAD STRUCT FOR OOPness :D, note: this is retarded void canbus_thread_destroy(canbus_thread_t *canbusThread); //__END_API_ Still seems... kinda clean, but also shit. Whatever, it was hastely pulled together. So we inspect this retarded programmers C file to see the struct, because surely, they know how to program C in an embedded environment...right? The thread wrapper has the following struct: struct canbus_thread { canbus_reader_t *reader; bool isRunning; pthread_t _thread; int num_methods; frame_handler_func frame_handler_functions[MAXIMUM_AMOUNTS_OF_METHODS_PER_THREAD]; }; WTF, no one would be stupid enough to have an array of function handles in order to reduce the code to work like in a modern OOP env in C? Well, sorry to say that I am that retard. So doing simple things such as creating a running a thread turns into this abomination: void *run_can_thread(void *arg) { int id; unsigned len; char data[8]; canbus_thread_t *canbus_thread = (canbus_thread_t *) arg; DLOG(INFO, "[%s] Thread func start \n", (canbus_thread->reader->ifname)); while (canbus_thread->isRunning) { if (canbus_thread->reader->read_frame(canbus_thread->reader, &id, data, &len) > 0) { for (int i = 0; i < MAXIMUM_AMOUNTS_OF_METHODS_PER_THREAD; i++) { if ((*canbus_thread->frame_handler_functions[i]) != NULL) { fprintf(stdout, "I am thread %s calling the func now!\n", canbus_thread->reader->ifname); (*canbus_thread->frame_handler_functions[i])(id, data, len); } } } } DLOG(INFO, "[%s] Thread func stop \n", (canbus_thread->reader->ifname)); return NULL; } With the implementation of sensors as you see in the C repository we got the message that we could use C++. This wa actually one of my first time using C++, but given it was an embedded env it was basically just really nice C. Which means we solve the above things with simple classes like: class CanMethodResolver { public: virtual int handle_frame(int id, char *data, unsigned len) = 0; }; Which allows you to define in interface with an external component (like NodeJ1939 in a car) as following: NodeJ1939::NodeJ1939() { msgCount1 = 0; msgCount2 = 0; msg3State = false; } int NodeJ1939::handle_frame(int id, char *data, unsigned len) { if ((id & CAN_EFF_MASK) == ID.MESSAGE1) { return appendMessage1(data, len); } else if ((id & CAN_EFF_MASK) == ID.MESSAGE2) { return appendMessage2(data, len); } else if ((id & CAN_EFF_MASK) == ID.MESSAGE3) { if (!msg3State) { msg3State = true; return appendMessage30(data, len); } else { msg3State = false; return appendMessage31(data, len); } } return 0; } int NodeJ1939::appendMessage1(char *data, unsigned len) { maxVolt = ((float) ((data[0] << 8) | data[1])) / 10; maxCurr = ((float) ((data[2] << 8) | data[3])) / 10; charging = !data[4]; msgCount1++; return 0; } int NodeJ1939::appendMessage2(char *data, unsigned len) { volt = ((float) ((data[0] << 8) | data[1])) / 10; curr = ((float) ((data[2] << 8) | data[3])) / 10; hwFail = (data[4] & 0x1); tempFail = (data[4] & 0x2); voltFail = (data[4] & 0x4); comFail = (data[4] & 0x10); msgCount2++; return 0; } int NodeJ1939::appendMessage30(char *data, unsigned len) { nomAhr = ((float) ((data[0] << 8) | data[1])) / 10; storedAhr = ((float) ((data[2] << 8) | data[3])) / 10; actualCurr = ((float) (((data[4] & 0x7f) << 8) | data[5])) / 10; actualPackVolt = ((float) ((data[6] << 8) | data[7])) / 10; soc = 100 * (storedAhr) / (nomAhr); return 0; } int NodeJ1939::appendMessage31(char *data, unsigned len) { maxCellVolt = ((float) ((data[0] << 8) | data[1])) / 1000; minCellVolt = ((float) ((data[2] << 8) | data[3])) / 1000; maxCellTemp = ((float) (((data[4] << 8) | data[5]) - 200)) / 10; minCellTemp = ((float) (((data[4] << 8) | data[5]) - 200)) / 10; return 0; } int NodeJ1939::appendMessage1X(char *data, unsigned len) { return 0; } By simple inheritence. class NodeJ1939 : CanMethodResolver { public: NodeJ1939(); int handle_frame(int id, char * data, unsigned len); struct ID{ static const int MESSAGE1 = 0x1806E5F4; static const int MESSAGE2 = 0x18FF50E5; static const int MESSAGE3 = 0x18075000; static const int MESSAGE1X = 0x1806E6F4; } ID; .................omitted. I will upload both the C and C++ repositories once I find a decent way of sharing with the members of HAXME without exposing it completlly4 points
-
So a few months ago, I heard a podcast where a person was talking about how helpful it is to do something as simple as implement an HTTP server in C. So, I decided to embark on this quest when school got a little more quieter for the summer (I am just taking a light load). I ended up doing this for a few reasons. First, as a learning experience. How better to get to know HTTP and how websites work than implementing a web server? Next was dog fooding my own code. Making something I can use. I could get the experience of writing it, but also the experiences of using my own code. And of course, implementing my own features natively in C. Lastly, I figured it would make an interesting resume project. Why C? Well, its a little closer to the metal and requires the user to get more intimate with the inner workings. Here is the code on my github. Note, as of this posting, I still have some cleaning up to do. But it passes all memory checks on valgrind and seems to be running fine. It is single threaded and does not yet use non-blocking IO. https://github.com/martintc/HttpServer Website I currently have it deployed to for testing: http://martintc.tech Thing I plan to do and improve on (and lessons learned): Implementing my own garbage collector to simplify the memory model. handling PUT request methods. Implement SSL/TLS Implement multi-threaded and non-blocking IO1 point
-
I accidentally discovered this today with @killab and thought it was pretty neat. E2E encrypted file uploads that supports streaming encryption/decryption. Potentially useful for quickly sharing disposable files, you can read more about the security here: https://wormhole.app/security URL: https://wormhole.app/1 point
-
@cwade12c I also have been a long time user. Actually, you guys got me into arch and such when I was in highschool all those years ago. But yea, recently have gotten on the BSD train. What do I like about it? It is stricter to adhering to UNIX philosophy and is a direct descendant of UNIX, unlike Linux which was a clean-room re-implementation influenced by minix. The system designs are simpler. All of the BSDs have great documentation compared to 99% of linux distributions. The BSDs are each their own independent OS. Binary compatibility is not the same across and each have taken their own routes (for instance, DragonFly BSD is transitioning to a microkernel). The major selling point for me is they also own their stack from bootloader to kernel to userland, which makes it a really solid cohesive system. In contrast, the linux kernel is its own independent project of GNU userland tools, they just happen to so benefit by working together. The communities are also close knit compared to Linux and less toxic. Within a couple of weeks of running NetBSD, I was working with the audio dev of NetBSD to test a patch of their for a machine of mine. I do believe their developers (BSD in general) are much more involved in their communities. The ports systems are great. My favorite by far is pkgsrc (NetBSD project) since it can run across multiple operating systems. I actually use pkgsrc and pkgin on Mac OS Big Sur as a replacement for brew and macports. The not so great part is hardware support. NetBSD is nice because all drivers are shipped with the generic image and NetBSD does not take a performance hit when unnecessary drivers are loaded into the kernel (where as FreeBSD and Linux are according to a few NetBSD devs I talked to). So that was on the easiest hardware wise to find out if your system is supported. The main issue would be wifi and GPUs. FreeBSD for sure does not have any 802.11 ac support (Adrian Chadd is working on it slowly), NetBSD and OpenBSD have a few devices that are supported for 802.11 ac. Otherwise, have a card with b/g/n that is supported or have a wifi dongle ready that is supported. The patch I tested for the Audio netbsd dev was for my Macbook Pro. I've got a 2015 that is dual booted with Big Sur (mostly for school stuff) and NetBSD. I dont fully understand the audio workings, but NetBSD was defaulting to channel 4 when it should have defaulted to channel 2. So the dev made a patch to check to make sure channel 2 was the default and if not, to make it so. My experience with OpenBSD has been on an old iBook G4 that I acquired last year. OpenBSD has great legacy powerpc support. It is a great system and Theo has done a great job with it since he forked from NetBSD in the early 90s. CWM is interesting and praised by users, if your not familiar, CWM is a window manager made by the OpenBSD community. And of course, OpenBSD has a legacy of great contributions like creating OpenSSH, Doas, LibreSSL, etc. I have also used it as a webserver. Their in-house HTTP client is nice and it integrates well with acme-client for automated LetsEncrypt SSL certs.1 point
-
Newsletter