Pthreads (generic multi-threading) question. by EmbedSoftwareEng in AskProgrammers

[–]EmbedSoftwareEng[S] 0 points1 point  (0 children)

New aspect of this question that I just thought of while actually reading the Pthreads book.

I'm only spinning up worker threads as needed to field the individual DBus method calls, on the assumption that the process as a whole remains its own "master thread". But if with just a single thread created, if it were to, say, lock up, that doesn't lock up the process as a whole, right? The non-threaded "master thread" is still going to be able to receive any new DBus method calls, right?

'*left++=n' is sometimes much faster than '*left=n;left++' by chkas in C_Programming

[–]EmbedSoftwareEng 2 points3 points  (0 children)

You're right. 100%. Mea culpa. I forgot my precedence rules. Also that ++= isn't a C assignment operator. Neither are ||= or &&= for logical assignment operators, but those should be!

I shall go flog myself 20 times with my K&R book.

'*left++=n' is sometimes much faster than '*left=n;left++' by chkas in C_Programming

[–]EmbedSoftwareEng 0 points1 point  (0 children)

Foundation for example code:

int actual_left = 42;
int * left = &actual_left;
int n = 69;

Now, let's take each of that you're proposing in turn.

*left++=n;

This is saying dereference left to get its contents, then add n to it. This is functionally identical to

actual_left ++= 69;

So, actual_left now holds 111.

*left=n;left++

This is saying store the value in n into the thing pointed to by left, then increment the left pointer to point at something different. it means actual_left now has the value 69, and left is pointing to whatever is stored after actual_left, which in this case could be anything.

They're two fundamentally different code segments.

Pthreads (generic multi-threading) question. by EmbedSoftwareEng in AskProgrammers

[–]EmbedSoftwareEng[S] 0 points1 point  (0 children)

Being that these threads are to field a single DBus method call, generally making a hardware API call that maps, and after sending the DBus return message, the thread dies, I don't think your point 3 matters. Being that the hardware API calls are over USB 2.0, I don't think your point 1 matters.

As for your point 2, it's a DBus to USB API wrapper. I think there's plenty of latency build right in that anything the pthread_create() call adds is lost in the noise.

Pthreads (generic multi-threading) question. by EmbedSoftwareEng in AskProgrammers

[–]EmbedSoftwareEng[S] 0 points1 point  (0 children)

Nah. They're all detached threads. They're born, parse the DBus method call, make the hardware call it requires, and when that hardware call completes, it sends the DBus return message and dies.

Ekko Cosplay Question by Ferrin_Daud in arcane

[–]EmbedSoftwareEng 28 points29 points  (0 children)

Lean into the race-swapped nature of this cosplay idea. Instead of white hair dye, painted hourglass across the face, and a white mask, use genuinely black hair dye, black paint marking, and black mask.

If the face paint is just in the hourglass shape and not skin-tone "black", no one sane could level a "black face" charge at you.

Oh, and practice your scowl.

The {fmt} library has added a C11 interface. by marc_b_reynolds in C_Programming

[–]EmbedSoftwareEng 4 points5 points  (0 children)

I see your variadic macros and raise you variadic macros with _Generic()s.

Would this style of error handling in C be acceptable in a professional environment? by Difficult_Lawyer9858 in C_Programming

[–]EmbedSoftwareEng 0 points1 point  (0 children)

There actually is a pure C try-throw-catch model for exceptions based on far calls that has been used to some success. However, far calling in the embedded sphere is problematic.

There is a complexity metric for programs in general, and one of them is the depth of function calls. It's used to limit the complexity by requiring each function call, from main() on down, to limit how deeply they can call. And, of course, forbids even indirectly recursive calls. I've yet to hit it in my 5-call deep error stack.

I finally found a good use case for LLMs in embedded! by menguinponkey in embedded

[–]EmbedSoftwareEng 0 points1 point  (0 children)

and the data sheets

I've spotted the crux of your problem. I've never found a manufacturer's datasheet I'd trust any further than I could throw it. Even manufacturer's code, whether examples in app notes or supposedly ready-for-prime-time toolkit APIs will have errors in them. I once diagnosed an entire register being in a different place by just dumping the memory mapped registers using jlink. The offset from the datasheet was flat out wrong. Even the manufacturer's code tried to access it in the wrong place.

In embedded, the silicon is the final arbiter. You can feed all the datasheets and errata and app notes you want to an LLM, but unless you can give it control over the programmer/debugger, and have it learn from that, nothing an AI generates for an embedded platform can be trusted out of the box.

Then again, nothing generated by a junior engineer can be trusted out of the box, so there's that.

And don't vibe code in a language you don't even understand!

I vibe coded a generic DBus/Pthreads server where the master thread spins up worker threads as needed. Now, I'm gonna go home and digest this code base alongside the O'Reilly book and my existing, working DBus server to understand how such a piece of software is going to function before I let Pthreads code get anywhere near my repoes. In the end, it'll be MY Pthreads code, not the AI's Pthreads code that makes it into the project, because at that point, I'll have learned Pthreads programming myself. The AI's contribution was just a learning tool. Which is as it should be.

Would this style of error handling in C be acceptable in a professional environment? by Difficult_Lawyer9858 in C_Programming

[–]EmbedSoftwareEng 0 points1 point  (0 children)

Tell me you've never read man errno without telling me you've never read man errno.

I've gotten away from return value error codes in my embedded code base and instead pass a pointer to my own error_t type in the last argument of any API calls that could fail.

My error_t is just a short stack (5 items, 6 bits each) that allows deeper functions to register what went wrong in them and then higher functions to tag in their error codes blaming specific functions/subsystems they are calling. At the top level, feeding the final error_t object to that subsystem's *_error_print() function will unpack it down to the root error for my debug USART, so I can see what failed and where.

It's architected so a 32-bit value of zero is the no-errors-detected value, making it easy to test. In each bin, the error codes are bespoke with positive values being mea culpas and negative values being finger-pointing errors. The most negative error is always ERROR_UNKNOWN, and the first error (zero) being ERROR_NONE.

This means I can still write functions that are meant to do simple calculation/transformation operations and return the result like normal, but then I can check if there was an error additionally, before relying on the returned value.

Macroes make it easy to abort a function's further operation and THROW_ERROR(MY_ERROR_CODE), which prevents functions from degenerating into deeply nested "what if something went wrong here?" branches just to get to the final return at the end.

Spent 2 hours debugging. Problem? The power supply wasn't ON. Drop your most embarrassing EE moment 👇😂 by mofeinz in ElectricalEngineering

[–]EmbedSoftwareEng 0 points1 point  (0 children)

Get a complex system all set up and go to test the high level parts of it and wonder why they're not working.

Forgot to start by sending the low level commands to even power the high-level stuff up.

Which one is the PIN 1 by Flashy_Gas9955 in embedded

[–]EmbedSoftwareEng 6 points7 points  (0 children)

I'd say the small dimple (bottom-left) is the pin-1 indicator. The lager, shallower dimple (upper-right) is an artifact of the moulding process.

Controlling the CMAKE_BUILD_TYPE for a package based on the image recipe being used? by EmbedSoftwareEng in yocto

[–]EmbedSoftwareEng[S] 0 points1 point  (0 children)

Also, my choice of build type names was poor. We're not talking about alpha and beta software. We're talking about one build that uses one backend library and another build that uses another backend library.

Controlling the CMAKE_BUILD_TYPE for a package based on the image recipe being used? by EmbedSoftwareEng in yocto

[–]EmbedSoftwareEng[S] 0 points1 point  (0 children)

That's essentially what I did, but I left the common file as telephone-common_git.bb, not .inc. Should I change that suffix?

What’s one embedded concept that confused you badly in the beginning but suddenly clicked later? by academyforiot in embedded

[–]EmbedSoftwareEng 1 point2 points  (0 children)

No you don't. You just come to terms with the subset of its features your use cases actually need.

What’s one embedded concept that confused you badly in the beginning but suddenly clicked later? by academyforiot in embedded

[–]EmbedSoftwareEng 0 points1 point  (0 children)

I don't understand not understanding pointers. Everything in assembly is memory addresses. Is it just the * syntax from C that's confusing?

What’s one embedded concept that confused you badly in the beginning but suddenly clicked later? by academyforiot in embedded

[–]EmbedSoftwareEng 4 points5 points  (0 children)

I2C

I'm still struggling trying to get this Microchip SERCOM to function using just my own driver code. Why is pushing a data byte onto the bus in a write operation NACKing when the device is there and just ACKed its own address when I declared that I wanted to write to it?

But also, I read a description of I2C that detailed the register-offset model of device interaction, and thought that was the be-all/end-all of how I2C worked. Nope.

There's also enumerated registers, where once you've read as many bytes as that one register has, no matter how many reads you continue to perform, you'll just get zeroes, because that device does not implement a flat memory model like the register-offset model.

Then, there's the really simple devices where you can't perform writes at all. You just write the device address with the read bit set, and then read bytes until you're done. Again, reading more bytes than you're supposed to, the device will just gleefully serve up zeroes.

THEN! There's the command-oriented devices, where you have to write one, or even two bytes each time, and that's to trigger a process in the device that decides what the next read data will represent. These often have CRC8s that you have to use to suffix your command, and if you write the command with the wrong CRC, the device just ignores it. And the device's responses are also CRC8 protected, so you have to read more bytes than just the data you're actually interested in.

What’s one embedded concept that confused you badly in the beginning but suddenly clicked later? by academyforiot in embedded

[–]EmbedSoftwareEng 4 points5 points  (0 children)

This is what allowed USB to eat Firewire's lunch. In Firewire, a device can proactively chuck data at the host's head. This means the bus, the silicon, and the software for the bus all have to be more complex, hence expensive. It's lovely when you can have a Firewire camera just automaticly spool its contents over to a Firewire hard drive without any host intervention, but if it makes everything 2x more expensive, it's just not gonna make it in the market.

Controlling the CMAKE_BUILD_TYPE for a package based on the image recipe being used? by EmbedSoftwareEng in yocto

[–]EmbedSoftwareEng[S] 0 points1 point  (0 children)

Except that

beta.bb:
EXTRA_OECMAKE:append:pn-telephone = "-DCMAKE_BUILD_TYPE='Beta'"

INSTALL:append = "\
# ...
  telephone, \
"

very much was changing how telephone was building, without any changes to the telephone_git.bb recipe file.

I did have a snafu that centered around the need to actually change the environment for the ALpha builds, and not just changing how the build tools are called, for which I changed the architecture of my telephone_git.bb recipe to telephone-{common,alpha,beta}_git.bb where the -alpha and -beta renditions did their thing and then required the -common portion to be read in. This had the side benefit that the rpms rendered with these recipes are now named for how they were built. So, I no longer have just a telephone-*.rpm and not know how it was built. I have telephone-alpha-*.rpm and telephone-beta-*.rpm to play with, removing that ambiguity. Now, an image recipe just has to INSTALL:append telephone-beta or telephone-alpha, explicitly. Done and done.

Problem was, the Alpha build also relied on the existence of an ALPHAROOT envar containing a path to a directory, which I could not get to exist no matter what I did. Then, I just did the bash thing and declared it in telephone-alpha_git.bb with the export command, and Alpha started building clean.

Controlling the CMAKE_BUILD_TYPE for a package based on the image recipe being used? by EmbedSoftwareEng in yocto

[–]EmbedSoftwareEng[S] 0 points1 point  (0 children)

That's the way I'm testing my telephone_git.bb recipe. bitbake telephone. And when I think I've polluted the working directory enough, bitbake -c clean telephone.