Embedded

View Original

423: Speaking of Aardvarks

Transcript from 423: Speaking of Aardvarks with Phillip Johnston, Chris White, and Elecia White.

EW (00:00:06):

Welcome to Embedded. I'm Elecia White, alongside Christopher White. We're going to chat with Phillip Johnston of Embedded Artistry about changes.

CW (00:00:16):

Hi, Phillip. Welcome back.

PJ (00:00:18):

Hi, thanks for having me back on.

EW (00:00:20):

Could you tell us about yourself as if we met at an embedded systems conference?

PJ (00:00:26):

Sure. I'm Phillip Johnston, the founder of Embedded Artistry. We are an embedded systems consulting and education firm. I've been an embedded developer for 13-ish years now. And in that time I've helped ship more than a dozen products across a number of industries, including desktop software, consumer electronics, defense, robotics, drones, you name it.

PJ (00:00:47):

My main interest is helping to bring embedded software development out of the dark ages. And currently I'm focused on doing that through a three-pronged approach of designing software for change, building testable systems, and leveraging automated software quality enforcement practices.

CW (00:01:04):

Where's the fourth prong of getting people to listen to you?

PJ (00:01:08):

I try not to worry about that one too much, -

CW (00:01:10):

Okay.

PJ (00:01:10):

- because I can't control it.

EW (00:01:13):

Are you ready for lightning round?

PJ (00:01:15):

I am. This is always the most stressful part.

CW (00:01:17):

What was your first computer?

PJ (00:01:21):

I don't know, but it ran Windows 95.

CW (00:01:25):

What is that look for?

EW (00:01:27):

I just expected it to be older than that. What was your first programming language?

PJ (00:01:34):

C.

CW (00:01:35):

When you were five, what did you want to be when you grew up? If you can't remember when you were five, pick any later date.

PJ (00:01:41):

I do remember, and I wanted to be a paleontologist.

CW (00:01:45):

I still want to be a paleontologist.

PJ (00:01:47):

Yeah, I think it would be quite cool.

EW (00:01:49):

When you were starting college, what did you want to be when you grew up?

PJ (00:01:54):

A philosopher.

CW (00:01:56):

Okay. Continuing on this theme apparently, what do you want to be when you grow up now?

PJ (00:02:01):

I guess now I'd settle for gardener.

EW (00:02:03):

When you were in college, how much RAM was a lot of RAM for your computer?

PJ (00:02:10):

In college, I want to say I was in the gigabyte range. I don't remember exactly. But my first computer, I do remember my father paid, I think, a thousand dollars extra to get the 4MB option.

EW (00:02:23):

Yeah. Alright. Let us -

CW (00:02:28):

You don't want to know how much an extra 16K was for my first computer.

EW (00:02:32):

Yeah.

CW (00:02:33):

And you had to put the chips in by yourself. They went in chips into sockets Anyway.

PJ (00:02:40):

Yeah. I luckily missed all that.

EW (00:02:42):

You recently posted a blog post about how your approach to abstract interfaces has changed over the years. And that caught my eye, because you don't always think about how your design philosophies and implementation principles change. Could you describe what you wrote?

PJ (00:03:08):

Sure. So I guess backing up, before the article, the main problems that I'm interested in solving are related to the fact that no matter how well we think we design our software, there's always some change that comes in, either a part changes, or you've got to use a new processor, or some requirements change comes in.

PJ (00:03:32):

And then it's not easy to make that change. It's always a huge rewrite, it seems. And it's not just swapping out a couple files. Suddenly I find that whatever I'm changing has touched every file in the repository, and now it's a big effort.

PJ (00:03:48):

So that inspired a lot of my interest in, "Well, how can I solve this problem?" And abstract interfaces, through the work of David Parnas in particular and the ideas of information hiding, were something that really struck me when I first came across it, and that I've employed with great success in my career.

PJ (00:04:05):

So I described how, when I encountered abstract interfaces and actually used them in systems, I would I guess go through the typical exercise of, let's say I have a SPI or an I2C interface for a SPI controller or an I2C controller. By having a standard interface for that, I can swap out implementations using the same interface and any software that relies on that interface. It doesn't have to change.

CW (00:04:34):

When you say interface for those things, you mean read, write, start, - ?

PJ (00:04:38):

Read, write, start, stop, depending on what it is, configuration may or may not be included. I think SPI configuration is probably a bit more standard than configuring an accelerometer where every accelerometer has different frequencies, and filtering options, and wake-up events, and things like that.

EW (00:04:58):

And I always, I mean, the POSIX open, close, read, write, or ioctl has always been in the back of my mind as a, "Let's just standardize the interfaces to everything." Okay. But now you don't think it should be like that? I mean, that works. That works for a lot of things.

PJ (00:05:18):

It works for a lot of things. I've done a lot of really cool stuff with it. Nowadays, I almost always write new drivers for new components on my development machine using a Aardvark debug adapter. So I'm connected to whatever breakout board I have over USB, and I can talk to the actual hardware.

PJ (00:05:41):

I can write my driver, I can write tests against real hardware. I can record data and play that back in automated testing. And most importantly, I can move it to my target processor, and it's just going to work for the most part.

PJ (00:05:55):

There's always some gotchas that might come up with memory, or timing, or your implementation isn't quite correct. Things like that do still happen. But for the most part, I can easily move stuff around. So that has a lot of benefits, but there are downsides that I think come up quite a bit.

PJ (00:06:14):

One is you're always locked into a particular interface. So the goals of, "Okay, now I can change what hardware I'm working" on have been met, but I can't necessarily take that driver and use it in a totally different ecosystem or a totally different client project that's not using all of my abstractions, and supporting tools, and things of that nature.

PJ (00:06:36):

And so you sort of become locked into whatever ecosystem or whatever set of interfaces you've developed for yourself. And two, and I think this part, it's very difficult to overcome it, it's hard to create good interfaces without a lot of experience.

PJ (00:06:51):

And getting an abstract interface wrong, and having a lot of different implementations, and then finding out that you have to change that causes just as much cascading change to happen as if you didn't have it in the first place. Now, I mean, that's true of whether or not an interface is abstract or not, right?

PJ (00:07:10):

Interface changes are always painful. But the scope of the interface, I think, makes it more likely that you're going to do something erroneously that you want to change later.

PJ (00:07:21):

And so my efforts shifted after being exposed to, just randomly through a client project, coming across a driver that did something totally differently, where instead of depending on some particular SDK or particular abstract interface for a SPI controller, this driver just defined one function that you had to implement in your own application to handle the SPI transactions.

PJ (00:07:49):

And that was just a totally novel approach to me. And it addresses some of these concerns of, "Well, I just have one function."

PJ (00:07:57):

So the odds that you're going to define one function correctly in such a way that the interface you create is going to be able to meet the needs of that component within your system and to support multiple implementations, that's going to be a lot easier to get correct than if you're going to define a fully-fledged SPI controller interface with a bunch of different knobs.

PJ (00:08:18):

And even though those knobs do provide benefits to you, like being able to control a device in a standard way, you're still locked in, whereas if I have one function to define in my driver implementation, I can use it with Arduino STK. I can use it with my own framework. I can run it on Zephyr. You name it right. Implementing one function is easy. Implementing a full interface, it takes a lot more time.

EW (00:08:47):

Okay. We've been pretty abstract here. And I think I need to get to some concrete examples.

PJ (00:08:53):

Great.

EW (00:08:54):

And what I'm thinking of as you talk is, there's an inertial navigation library that does fancy things. And it uses a particular IMU, and it runs library code on my processor in order to do this.

CW (00:09:16):

So that I understand, library code on your processor to speak to the device?

EW (00:09:21):

Yeah. So they have a library that implements, say, the Kalman filter.

CW (00:09:25):

Right.

EW (00:09:26):

And I'm not allowed to really look in there.

CW (00:09:28):

Right.

EW (00:09:28):

And what they want me to do is be able to provide the code that talks to the actual unit.

CW (00:09:34):

Okay.

EW (00:09:35):

Because they know how to do all of the registers on the unit, but they don't really know whether I'm using SPI -

CW (00:09:41):

Got you.

EW (00:09:41):

- on a Cypress or -

CW (00:09:42):

Got you.

EW (00:09:43):

SPI on a PIC.

CW (00:09:44):

Got you.

EW (00:09:46):

Okay. So I have this library that wants to be able to send and receive messages to the device that it was written for. And this is kind of a complicated example, but if you think about the libraries, that means that you have something separate and something that you do want to think about changing for the future.

EW (00:10:06):

And I can see how in the past, I would've expected that library to ask me to implement a driver that had an init, a reinit, maybe a reset, a read, and a write that would do lengths. But actually, in fact recently when I had this entire problem, it had me implement SPI transfer, read, write, and it didn't want any other functions.

EW (00:10:37):

It didn't want to know about inits. It didn't care about resets. That was all up to me. What it wanted was to be able to talk to the unit. And so it was only one function I had to implement. Is that what you mean? Or am I on a different path?

PJ (00:10:52):

That is exactly what I mean, exact same example.

EW (00:10:57):

That's when you have control over something somebody else is going to implement the lower levels for. In this example, I would be the library developer, or in a different example, I would be the GUI developer wanting to talk to an LCD, but not wanting to have to deal with whether it's hooked up in SPI or parallel. I just want to send things. Is this abstracting the hardware, or is it abstracting the software, or does it matter?

PJ (00:11:33):

I don't think it matters. I think that we can view it as a general technique that we can use in our systems. So one tool in the toolbox is the full abstract interface, and that's still useful, having a standard way to talk to a device from your application code that allows you to swap out the device you're talking to, or it could be anything.

PJ (00:11:58):

It could be a particular library, it could be a database, whatever, but having some abstraction on top of that, so you can swap out an implementation without impacting other code. That's great. And that's one tool.

PJ (00:12:10):

On the other hand, I think another tool that we should have in our kits that we should be able to employ when we need it, is to realize that, "Okay, we don't need a full interface for this problem. I really just need one function," or, "There's one particular detail that I can't manage in this library that's going to change when some aspect of the system changes."

PJ (00:12:33):

That might be what implementation I'm using, or a specific configuration, or maybe some applications are threaded and some aren't. And I need to have a way to defer that kind of decision to the application. So I think there are a number of ways that this can really benefit our system design that aren't just decoupling from hardware.

EW (00:12:54):

The old way of implementing abstract interfaces, in your blog post, it mentioned function pointers. And so the library in this case would say, "You have to implement a structure that includes these functions," the read, and init, and all of those functions, and you do the function pointers.

EW (00:13:14):

That was an extremely TI thing. I mean, they did that, I would say to excess, because sometimes there were 20 or 30 functions you needed to put in. Where did you pick it up? Please don't say my book.

PJ (00:13:31):

I didn't pick it up from your book.

EW (00:13:32):

Yes.

PJ (00:13:35):

I must have been exposed to that idea, ... it must have been at Apple. I was working on the diagnostic firmware team, and I think they managed a lot of things that way. The code was based on the EFI framework, and we definitely had some function pointer structs and abstract interface ideas in there.

CW (00:13:56):

That's funny you mentioned Apple, because this whole idea of having a framework that does something, but it needs help and the help can vary so, "Give me the one function that will help me," is very straight out of the UI frameworks, where there are delegates and things, these callback functions that maybe something draws a table for you.

CW (00:14:18):

But it needs to know how to draw each individual cell. So it can do all the machinery and lay things out, but it doesn't know what you want to do for drawing the cell. So here's this function, draw a cell that you have to fill in, and then it takes care of that low-level part of the drawing based on what you want it to do.

CW (00:14:35):

This seems very similar to me of, "Okay, here's this complicated driver that maybe has lots of high-level intelligence, but really, it also needs to know how to talk to its device. And please tell us how to talk to the device. And that's all I need."

EW (00:14:47):

That's interesting. That's the word we should be using.

CW (00:14:50):

What?

EW (00:14:50):

This function that we need to implement for our API or our library, this one function, or even the five functions in a driver that they want us to implement, those are delegates. Those are things that they have said, "We need you to implement this."

EW (00:15:11):

It's not a delegate like it is in Swift, but it is a concept. And I think for many things in C, we don't always have the word, because we don't have the concept or -

CW (00:15:25):

The design pattern.

EW (00:15:28):

I guess. But is the word delegate and how it works a design pattern?

CW (00:15:33):

I don't know.

EW (00:15:33):

I guess maybe.

CW (00:15:34):

I don't know. I don't remember.

EW (00:15:37):

Anyway, so delegates, and then I feel like what about callbacks? Those aren't delegates.

CW (00:15:42):

They can be. It depends on their function.

EW (00:15:44):

That's another thing I see with some library implementations -

CW (00:15:48):

Yeah.

EW (00:15:48):

- is that they don't want to tell me what's happening inside, like a UI library needing to get images from somewhere. It doesn't want to know where it's getting images from. It just wants to call a callback that says, "Give me more data."

CW (00:16:07):

Yeah. Can you tell we've been working on UIs lately?

PJ (00:16:11):

I can tell.

EW (00:16:14):

Okay. So do you use the word delegate in your blog post?

PJ (00:16:20):

So I'm going to get to that, but I want to address another point that you had made earlier and then come back to this.

EW (00:16:25):

Okay.

PJ (00:16:26):

So when you said that TI does it to the extreme, and sometimes there's 20-something interfaces you have to implement, I think that's an anti-pattern, right? Because you don't want to have to implement 20 interfaces to get something up and running.

PJ (00:16:42):

That's a pretty significant time cost, where essentially you're going to take whatever implementation you already have, and now I'm going to shim it to this TI implementation interface expectation. Being able to do that on a smaller set of interfaces is much easier, right?

PJ (00:16:56):

You're going to be able to react, and change, and swap things out, and get things running much easier if you have a smaller set of things to work with. So I think that TI example is a good indicator of where this kind of abstraction approach can go wrong, -

EW (00:17:12):

It is.

PJ (00:17:13):

- or not wrong, but difficult, perhaps.

EW (00:17:16):

It's like they have a whole operating system, and they do it with function pointers so you can replace things. And they do give it all to you for the default version, but you can change every little thing, which means that you have to think about changing every little thing, which, I never really want to even think about it.

EW (00:17:38):

Because then if I do it, I've done it wrong. But if I don't do it, maybe I'm doing that wrong. Anyway, back to you Phillip.

PJ (00:17:45):

Right. So back to the delegate question. I don't call it delegates. I think it's a perfectly suitable word. I view it as the template method pattern. And I think that's just, I was exposed to that before I was exposed to the concept of a delegate. But I think they serve the same thing. And so that pattern comes from, as far as I know, the classical Gang of Four Design Patterns book.

CW (00:18:06):

Yeah. Okay.

PJ (00:18:07):

And basically it says that you have a function, the template method, that has some steps that are controlled by that function and some steps which are deferred to the user application. ... Either your function requires the user application to implement it or it provides an optional hook, which, I think a callback applies in the same conceptual idea that allows an application to override or modify slightly how an implementation is doing things.

PJ (00:18:41):

And with embedded systems in particular, I think just that idea of, "Okay, we can have a function. I am going to have some steps that I'm going to defer to the user that they have to implement, like a SPI transfer function for your particular platform, and some things that you can override, if my particular default implementation doesn't meet the needs of the situation," I think that's a powerful tool.

PJ (00:19:04):

Because we do care about performance in the embedded world, perhaps more than other software systems with multiple gigahertz processors and gigabytes of RAM have to care. And so I think it's probably more common for us to need to tune the implementation, although I'm sure now that I've said that, a thousand counter examples can be thrown my way showing how I don't know what I'm talking about.

EW (00:19:30):

It's funny, the template method. I was trying to remember why I don't think about that one. And it's partially because it says very clearly that it is based on inheritance. And so as soon as it says that I'm like, "Well, let's just chuck that one out." It's not like I can't use inheritance.

EW (00:19:47):

It's just that I don't have a language that makes it easy. So, meh. But you're right. That is what it is. You're taking pieces out and allowing their implementation to be done elsewhere.

PJ (00:19:59):

Well, I think this is one of the trickier points of design patterns, right? It's easy to look at a pattern and say, "Oh, this doesn't apply to me because of whatever thing." And yet there are still going to be aspects about a pattern that are crucial.

PJ (00:20:17):

We could debate, and probably there are very good points to be made on either side about whether or not inheritance is really key to the template method or not. In my interpretation, I just kind of ignore inheritance altogether.

PJ (00:20:30):

I think you could achieve a template method through any number of ways that don't rely on inheritance. Although that was the classical application of the pattern.

EW (00:20:41):

The thing with design patterns is that there are a billion of them. And at some point I can't sit down at my desk and say, "Okay, today I need to fix this bug or make this LED blink at some frequency. Which pattern should I use?" It's not that it's metacognition, but there is the chance of having design where you don't really need it.

CW (00:21:12):

The best places I've encountered patterns and been able to use them is when the thing I'm working with enforces them. Coming back to Apple, they're very opinionated about the way the language is set up, and the way the frameworks work, and you will use these patterns, or you'll be unhappy with your life.

CW (00:21:32):

And that's the best way I've learned about them is, "Well, this is what's happening on this project. These are the patterns." Certainly I've never come into something and said, "Well, time to flip through this book and see if I want an adapter for this."

CW (00:21:42):

Yeah. I don't know how to bridge that gap unless you're doing a lot of whiteboard design and trying to be very abstract.

PJ (00:21:55):

Well, I guess for me, I mean, I agree I don't sit down, and approach a problem, and think about what patterns apply. I guess if I'm trying to analyze my own process, which is always fraught with error.

PJ (00:22:09):

But I think when I'm reading about patterns or I encounter a new pattern, in the back of my mind, I have a general set of problems that I'm sort of always dealing with, or something that I'm struggling with at the moment, or something I'm unsatisfied with how I implemented it.

PJ (00:22:26):

And when I'm reading patterns, often I'm in the back of my mind, I'm running through my collected set of problems, and seeing how this pattern might apply to this particular situation. And that can lead to interesting results, or I might run an experiment and see how it works.

PJ (00:22:43):

And then having implemented something, it's more likely to be fresh in my mind, or I might like a particular thing in a given pattern and realize I can apply that one little piece to some problem I'm dealing with. So I think for me, that's how it usually ends up working out in practice.

CW (00:23:04):

And there's definitely a couple of them that I tend to reach for, because I've learned to use them, and, "Okay, this is the way I do things." Like you said, there's a billion of them. But there's three or four that are sort of key core concepts that, whether or not you know you're using them, a lot of times people will be using.

EW (00:23:23):

Yeah. But sometimes I find them confusing, because there's publish-subscribe.

CW (00:23:29):

Yeah. Yeah.

EW (00:23:29):

That's something I'm very familiar with. I've worked with the Robot Operating System. It's all about that. If you ever want to see publish and subscribe on a large scale, go there. But then when somebody said something about the observer pattern, I was like, "Which one is that?"

EW (00:23:45):

And it's Pub/Sub, but they have different names. And if I used the state pattern, which is a state machine, which I use all the time, do I have to call it a state pattern?

CW (00:24:00):

I mean, only if the people who are reading it care. I don't think there's any board of certification saying, "Well, I'm sorry. You called this something wrong so your code doesn't work."

EW (00:24:14):

But Phillip was saying that he comes across it, and then he thinks about it -

CW (00:24:18):

Yeah.

EW (00:24:18):

- for a while in the future. How do you come across them?

PJ (00:24:25):

I'm always reading. I think it's been a perennial thing in my life that's ongoing. I'm probably reading something an hour or two a day, whenever I get my free time. And so it's not always technical. It's not always a book.

PJ (00:24:41):

But whenever I encounter ideas that are interesting, I either play with them in my mind, or I have some project I can apply it to to see if it solves my problem, or I just make some notes and start coalescing the ideas over time. Especially if I keep running into a given situation or a given pattern, and I notice that my notes are building some momentum, and actually of sufficient size, it's probably something I should pay attention to.

EW (00:25:09):

What kind of books do you read to randomly come across software patterns?

PJ (00:25:16):

Well, there's great design pattern books. I mean, "Design Patterns," the classic Gang of Four books is one. Your book has design patterns.

EW (00:25:25):

The "Head First" one. If you're new to design patterns, I've really liked the "Head First" one. It's written in Java, but it makes things physical in many ways that is what I need to make things work in my head.

PJ (00:25:39):

I'll have to look for that one. I don't think I've heard of that. There's Bruce Powel's book. I can't think of the name right now, but it's something along the lines of embedded software patterns in C. We can find that book title and link it in the show notes so we're not misleading people.

PJ (00:25:56):

But that's another one. And papers, I mean, there's a whole conference on the pattern language of programming, something like that, where people are submitting new patterns. And I occasionally look through that to try to find anything that might be relevant in the embedded space.

EW (00:26:17):

You go out and look at academic papers for design pattern conferences?

CW (00:26:29):

Are you research shaming him?

EW (00:26:31):

I don't mean to be. I guess I'm research shaming me.

PJ (00:26:35):

I read a lot of academic papers. I don't necessarily seek out papers about patterns. That's just one that's in my radar, but I found a lot of really valuable ideas from papers. One of my favorite papers of all time is a David Parnas paper from 1978.

PJ (00:26:54):

And again, I don't remember the title off my head so we can link that one too. But I mean, Parnas describes the exact same situation that I deal with all the time in embedded software being difficult to change. And so there's ideas that are still to be discovered or not well-socialized.

PJ (00:27:11):

Because I don't think a lot of embedded software professionals are reading the software academic literature to look for new ideas. Another paper I like comes from the '90s. ... This one's called "Towards a New Model of Abstraction in Software Engineering," or something like that.

PJ (00:27:31):

I should have practiced all these titles beforehand. I didn't. But that one is related to Joel Spolsky's famous law of leaky abstractions where the author of this paper notes that we have these ideas of what abstraction provides us. It supports change. We don't have to worry about the implementation, the general things of that nature.

PJ (00:27:55):

And then Spolsky points out that no, generally when something goes wrong with an abstraction, it is related to the implementation causing some performance problem that impacts your system. And the general recourse to that, which I think we're all familiar with, if you're using an open source project that doesn't quite work the way you want is, now you have to take over the implementation yourself, right?

PJ (00:28:17):

So you went from having this nice abstraction, or library, or driver, whatever you got from someone else, and it just doesn't work well for you. So now you have to reimplement it. And I mean, nobody's going to be surprised by that, right?

PJ (00:28:33):

But in the ideal world, you'd be able to tune something about that implementation without having to take on full ownership of it, or write your own implementation, or whatever other recourse you're stuck with. And so he talks about this idea of, "Well, don't just make one interface for your components. Why don't you make two interfaces?"

PJ (00:28:53):

You have the traditional interface that we use to interact with the component that we'll design according to information hiding principles. So we're hiding the implementation, and we can swap out implementations if we need. And our application code can remain unchanged. We can still have all that.

PJ (00:29:10):

We just also need a second interface that lets us tune the parts about the implementation that we need to change. And when you think about that problem, "Okay, this is paper that was written in the '90s. I've never heard anybody tell me that I should think about all of my components as having two interfaces, one which is used to make my program work and the other which is actually used to change how it behaves if I need to."

PJ (00:29:36):

And so there are a lot of ideas like that that have really impacted how I approach design or solve problems. I have new tools in my mental tool kit to reach for whenever I notice I'm in a particular situation. And so I don't spend all my time in the literature, but I do try to at least read the famous papers and the papers those reference or papers that reference those. I do a lot of bibliography diving to find what I should read next.

CW (00:30:04):

It's funny, because I feel like so much of, not computer science, but professional software engineering has been this struggle to find ways to stop doing things over and over again.

CW (00:30:17):

But there's this tension between making things abstract so that we can reuse code and be portable and having things be well suited for the platform we're running on. And it keeps going back and forth where, "Oh, this cross-platform library is very popular. Oh, but it doesn't work as well as developing native."

CW (00:30:37):

So now everybody has a native team for every mobile device that writes a different app. And then, "Oh, it goes back, and now we're all using the same thing." I just feel like this has been this constant struggle between, "How do we reuse code," and, "Well, we should just give up, because it ends up not working that well."

CW (00:30:55):

And that's not necessarily towards the thing we're talking about right now, which doesn't really have that problem. It's a very focused thing. But I do feel like that's been a struggle that hasn't been resolved and kind of goes back and forth.

CW (00:31:09):

And I don't know if it's resolvable in the general sense, but it just seems like, why are we writing all these things over and over again? Why, when I start a new client project, am I writing some of the same code that I did at the previous client project?

CW (00:31:26):

There's ownership issues, of course, but it just feels like we should be building on the shoulders of the previous code. And we don't get to do that that much.

EW (00:31:35):

I have a good story about this. It's from Classpert. When people were turning in their final projects, one person turned in a final project that was pretty good. But there was one section of code that was really good, really nice. And I asked them to be sure to check the licenses and to document that in their final reports.

EW (00:32:02):

And so it was documented in the final report, but in the code, it wasn't. And I was about to write a nice long complimentary paragraph about how this code was super clean. And it was good, and it looked like he had tested it very well.

EW (00:32:21):

And then I thought about it for a little while, and I went and I looked. And I noticed the license, and it turned out it was written by Phillip. It was his circular buffer library.

CW (00:32:32):

So you're just saying I should take everything from Phillip.

EW (00:32:36):

I believe so. He's got this whole -

CW (00:32:38):

Okay.

EW (00:32:38):

- embedded virtual machine.

CW (00:32:39):

Problem solved. ... That may be the solution partially, not to take everything from Phillip, but to -

PJ (00:32:49):

Please don't. That's a lot of pressure.

CW (00:32:51):

- have a better awareness of what's already out there or go looking for things, not in a stack overflow sort of search way. But at the start of a project, "Oh, is there something that's already been done that does what I want that is licensable," instead of saying, "Time to implement a state machine framework for these people," and, "Oh, time to implement a logger for these people."

EW (00:33:19):

I mean, the chip I'm using now has 97 application notes for how to do bootloading. And each one has something just a little different, whether you're doing it from serial or -

CW (00:33:29):

Well, that's what I'm getting at is -

EW (00:33:29):

- Bluetooth, -

CW (00:33:30):

- sometimes your efforts -

EW (00:33:32):

- or secure or very secure, and digging through this information has horrible. And I knew what change I needed to make the first day, but I couldn't figure out how to prove it to myself. It took me a week of reading their documents and trying out their stupid bootloaders before I got back to the original decision to just change this thing that the compiler said I shouldn't.

PJ (00:34:01):

Now, I might argue that that could be worth a week's worth of research time for a bootloader, right? You want i make sure that thing is actually working correctly and that thing the compiler's telling you not to do isn't really a problem.

EW (00:34:13):

Yeah. Don't push on that. It's already been a week.

PJ (00:34:16):

Sorry.

EW (00:34:16):

They're going to want results soon.

PJ (00:34:18):

Yeah, there is that. ...

CW (00:34:22):

"I've worked in the private sector. They want results."

PJ (00:34:27):

And I think this general idea goes back to a theme that has come up over and over again in our conversations, which is maybe you can take two weeks to research things instead of starting immediately.

PJ (00:34:37):

Now I know that no team in the world wants to hear that, and I've never convinced any startups I've worked with ever that two weeks is an acceptable period of research, and prototyping, and design, to figure out what you're actually going to do.

PJ (00:34:48):

But I think it is certainly worth it to figure out what's out there, and "What components can I reuse that exist?"

EW (00:34:57):

I understand the reading for an hour a day, but how do you choose whether you're reading academic software papers or working on a personal project with an Arduino?

PJ (00:35:11):

I let my interest drive what I'm spending time on more than anything, at least in the learning regard. Obviously I have constraints from the work I'm trying to get done too. And sometimes that drives my reading too.

PJ (00:35:24):

If I need to figure something out for a particular project, I will try to focus on things that are relevant to that. So it's a little bit of a choose your own adventure and a little bit of the needs drive the situation.

CW (00:35:40):

Where do you look?

PJ (00:35:43):

For papers?

CW (00:35:43):

Yeah.

PJ (00:35:43):

Or just in general?

CW (00:35:44):

Yeah.

PJ (00:35:45):

Papers. Again, I do a lot of bibliography diving. So in any paper I come across that I like, I look for references that seem interesting. And then I'll usually go to the ACM or IEEE digital libraries to see if the papers are there. Sometimes I Google stuff.

PJ (00:36:06):

I can't remember the name, but there's a list of famous software engineering papers or award-winning software engineering papers by year for a particular journal. So I'll look for collections like that. In books, if there's papers mentioned in a book that seem interesting, I tend to pick those up.

PJ (00:36:24):

So usually my reading is guided by other reading more than it is from me just going out and randomly trying to pick things.

EW (00:36:33):

Alright. Well, I'm not going to feel bad that I would rather do projects.

PJ (00:36:38):

I think that's okay.

EW (00:36:40):

I don't always get as much software education as I want, but if it's a matter of staying motivated, having it do something is more pleasing to me.

CW (00:36:50):

We just have people come tell us things about software.

EW (00:36:52):

Well, that is true.

PJ (00:36:55):

Yeah, you have the come-to-me model. That's a pretty good one. Tell me all the interesting things you know, and I'll pick and choose what I'm going to focus on.

CW (00:37:02):

I read Phillip's blog post, and I learned a ton. He's already filtered all that research into a blog post.

PJ (00:37:08):

There is that. That is true. A lot of research went into that over the years.

EW (00:37:12):

One of the things that your blog post says is that your opinion has changed. And how you describe it, it totally makes sense. But that sort of change is hard for us. I mean, ... I still hear people argue about vi versus Emacs. Nobody cares.

PJ (00:37:33):

Right.

CW (00:37:33):

Yeah. Why aren't you using VS Code?

EW (00:37:36):

There's some truth. Yeah.

CW (00:37:38):

You can have vi and Emacs in one beautiful package.

EW (00:37:42):

What other changes have you identified for yourself? I mean, that's hard to even identify, but have you identified other ones?

PJ (00:37:53):

Tying that point back into what Chris mentioned earlier, I originally approached a lot of my design and development efforts from the idea of, "Okay, I've written literally the same IMU driver for six clients." The reason I'm doing that is because of IP reasons, and whatever implementation is out there doesn't meet the needs for whatever I have to do.

PJ (00:38:16):

And that kind of thing happened over and over again. I can't tell you the number of TI gas gauge drivers I've written over the years. It's just over and over again. See, the thing is -

CW (00:38:28):

This is resonating, because for a while I was very specialist, for some reason, in doing optical coherent tomography imaging front-end software and driver software for medical startups.

PJ (00:38:41):

I don't know what any of that means.

CW (00:38:42):

It doesn't matter, but it was complicated. And I had to do UIs, and graphics, and talk to specific weird hardware. And for some reason, after doing it once, all these clients came out at the woodwork and said, "Oh." I just kept getting referred one to another. And I kept writing the same exact software package.

CW (00:39:01):

I think I did it four times. And by the fourth time, it was autopilot. I just wrote the same code. I wasn't stealing. There was no IP, but I'd done it so many times that I was just autopilot.

CW (00:39:12):

"Okay, well, here's this data acquisition class, and here's this UI thing. And here's how I'm going to set this up," and type, type, type, type. But, yes. I mean, so does it matter? I mean, by the time you've done it six times, it's pretty easy, right?

PJ (00:39:25):

Pretty easy. But it's not how I want to be spending my -

CW (00:39:30):

No.

PJ (00:39:30):

- valuable working time, right? It's not satisfying to rewrite the same thing over and over again, practically from memory. And ... you start thinking about, "Okay, well, I could have a standard offering where I've already got all this stuff in place, and think of how fast it's going to be for my clients to actually make this work really quickly."

PJ (00:39:51):

"I can get them set up. They can have all the drivers they need. If they need a new one, ... okay, it'll take me a couple days to bring it up. And it's going to work fine. All the machinery to support is already there. Great. It's going to be great. We're going to live in a perfect world. Everybody's gonna be happy."

PJ (00:40:06):

And ... the goals of reusability across products and portability across systems, it didn't play out in the way that I envisioned it would. A lot of times clients didn't want that. Regardless of the benefits that would come, they didn't want to pay a licensing cost, or they didn't even want to just not own all of the IP, right?

PJ (00:40:27):

They'd rather have you reimplement it for them even in a worse way just to own the IP outright. So there are a lot of other concerns like that that end up taking precedence over some of the engineering ideals.

PJ (00:40:42):

And I really had to change my views on what was the real value of portability and reusability, at least in the embedded systems space. For instance, I don't focus on portability and reusability as a goal anymore.

PJ (00:40:59):

I'm more interested in, "How can I use these same things that would enable reusability and would enable portability to just make it easier to change the product I'm working on in response to changes in requirements, or changes in the hardware availability," like you found out one implementation for whatever library you're using isn't suitable and you need to have another one now.

PJ (00:41:23):

So the same ideas have been sort of shifted to a different goal, but I'm sort of heartbroken now with the fact that my reusability and portability dreams just didn't play out when I had a chance to actually make that happen.

EW (00:41:37):

Have we switched to talking about the embedded virtual machine?

PJ (00:41:40):

We can. That was the project. That was my -

EW (00:41:43):

Okay. That was what I was wondering.

PJ (00:41:44):

- portability and reusability project. Yep.

EW (00:41:46):

Tell me about this embedded virtual machine.

PJ (00:41:49):

Well, nowadays I would describe it as my thesis on how to build software or how you could build software if you wanted to apply these techniques and practice.

PJ (00:42:00):

And so the idea there was, I would have a set of design patterns built in that you could employ to make it easier to set up portable applications, easily changed applications, supplying a standard set of driver interfaces, and ways to keep your application code decoupled from specific hardware, and just reusable machinery that comes up again and again, like a subsystem for managing different power states in your system or a logging implementation, things like that.

PJ (00:42:34):

And the goal was, again, I could license this to clients and bring up their system quickly. It would be easily supported. We could make changes very, very fast. If they needed new hardware, it would be easy to add new hardware or even outsource some components of that.

PJ (00:42:53):

And other benefits come out, like it was built with full static analysis tool support. It had three or four static analysis tools running. Everything was analyzed. It worked with multiple compilers. And I think my favorite feature was, with the way it was designed, you could supply an alternate what you might call platform definition.

PJ (00:43:19):

So, "What is my application running on in terms of OS and hardware?" And you could have an application running on your development machine, like a simulator for whatever you're building. And most of the code could be common across your simulator application and the application running on the target.

PJ (00:43:39):

And all these goals are achievable. But like I mentioned, nobody was interested in licensing it or even using it for a number of reasons that I think are totally understandable now, which is, one, not owning the IP. And I think two, it really ended up being an expert system where, well, I guess there's three.

PJ (00:43:59):

But two, it ended up being an expert system where you had to know C++ pretty well and know the full framework to really take advantage of it.

PJ (00:44:06):

So for that reason, you end up with vendor lock-in, where I'm the vendor maintaining the thing, and your people can't necessarily maintain the lower layers just due to lack of knowledge, or you don't want them to invest their time in that way.

PJ (00:44:21):

And so that was a pretty big eye-opener for me and sort of the impetus for me changing some of my ideas.

EW (00:44:29):

So you made a system that was everything Christopher wanted for usability, but then found out you really do have to rewrite everything?

PJ (00:44:39):

Because that's what people want. Yeah.

EW (00:44:41):

But not just because that's -

PJ (00:44:42):

For real reasons. Yeah.

EW (00:44:44):

For real reasons.

PJ (00:44:44):

Yeah.

EW (00:44:44):

Yeah.

PJ (00:44:46):

And I'm very sympathetic to the vendor lock-in. Because it's hard when part of the reason that I was working on such a project is because I don't want to be locked into a vendor, to then become that vendor, being accused of vendor lock-in. It's hard.

CW (00:45:02):

But ... so many clients, I mean, aren't they locked in anyway? Everybody's locked into some framework. "Oh, I've got to have a file system." Nobody's going to write their own file system. So they go buy a file system. And nobody's going to write their own UI library. I've seen it, but nobody should write -

EW (00:45:18):

But don't do it.

CW (00:45:19):

- their own UI library. People go buy those. So is that a real concern, or is it more, they don't want to be locked into things that they feel like are the core of their product?

PJ (00:45:29):

I think it's a complicated answer, but that's a reasonable hypothesis.

CW (00:45:33):

Yeah. I was expecting speculation, but it just seems weird to me. But -

PJ (00:45:40):

Well, it's undeniable -

CW (00:45:40):

- there are many choices that are weird to me.

PJ (00:45:43):

Agreed. I mean, yeah. The same clients are happy to have their software layer directly interact with their processor SDK, right?

CW (00:45:51):

Yes.

PJ (00:45:51):

And so now you're locked into a particular processor vendor. So, I'm not saying from the client's perspective that it makes sense. But I'm saying that I do understand the accusation of vendor lock-in. Regardless of any other things that might happen that might make that claim dubious, I think it is true that you're locked in in a system like I built.

PJ (00:46:14):

Because, going back to the full-fledged abstract interface conversation, you can't use one part of the system without another part of the system, because you're dependent on specific interfaces.

PJ (00:46:26):

So you now get the problem of, "Okay, well, I can't just pull out this particular thing I want to use, because now I have to pull out this interface, which is dependent on these types that are in this place." And, great. You have a modular framework for yourself.

PJ (00:46:39):

And I mean, this kind of thing, inside of one company, certainly has benefits. But for me, where I'm developing software for multiple people, it becomes more problematic if there's not a way to just take the pieces that they want and leave the rest, especially when that comes with the cost of complexity that may make you not want to take the full full system on.

PJ (00:47:02):

I think of Miro Samek's QP framework. I'm a huge fan of the QP framework. And I just can't tell you the number of times that I've heard people say, "I like it. I just can't convince anyone on my team to use it. So we just rewrote everything ourselves."

PJ (00:47:17):

So I do think there's a complexity argument to it and "I just can't take the pieces I need" argument to it that impact everything.

CW (00:47:25):

And what's so sad is most of the things we're talking about are infrastructure. They're not the special thing about anyone's product, right? Nobody on their marketing sheet says, "Now with special in-house design state machine!"

PJ (00:47:41):

And that's a key point. And I think that was that was something I emphasized in my own marketing or attempts to convince people to use this was, the part of your project that makes you money is not the drivers, or the file system, or the logging library, or how your code boots, or supporting over-the-air updates.

PJ (00:47:59):

That's not key to your business model, right? You have a product that's going to do something unique that provides value to your customers. And that's what you should be focusing on. And all the rest should be secondary, right?

PJ (00:48:11):

It should be whatever I can get off the shelf or however I can invest the least amount of time in it, over-the-air updates being a bad example with that particular point.

CW (00:48:19):

Well, yeah. I mean, TI does it for you, sort of.

EW (00:48:27):

Yeah. The lock-in, and the tools, and the framework, I think about Grenning's TDD, test-driven development for embedded systems, is based on CppUTest. And I want to do more test-driven development, but CppUTest is horrible.

CW (00:48:52):

Breaking news.

EW (00:48:56):

I mean, I'm sure once you have it working and set up, it's acceptable. But that step, it's just no fun. And I did it for one client. And afterwards I was like, "No, never again. I don't want to set this up." And so I get where you're going with this, and it is a complexity thing. It's a complexity and flexibility. It's very complex, because it's very flexible, but -

CW (00:49:26):

But no actual product team often needs that level of flexibility.

EW (00:49:31):

Right. The only reason you need that level of flexibility is because you're trying to support everything at once.

CW (00:49:35):

Or you have dreams about platform development, where you're going to make eight products on something and port them to different chips, which sometimes comes true.

EW (00:49:45):

Oh, at LeapFrog just had that part locked in. The only thing we had to do were the state machines and the behaviors. And we did not mess around with how it outputs audio.

CW (00:49:59):

And the frog voices. You had to change the frog voices.

EW (00:50:01):

Well yes, but that was a matter of putting the voices into the memory. I didn't have to worry about once they were in the memory -

CW (00:50:06):

Yeah, but you had to get the frogs to talk, which is the hard part.

EW (00:50:08):

Yes, that's true. But there's the little squeaky one. That was the best one. Phillip, are you still there?

PJ (00:50:16):

Hi, I'm still here.

EW (00:50:17):

If so, why? When we started the show, you said that Embedded Artistry was a consumer service, no, product services, but something about -

PJ (00:50:29):

Consulting and education.

EW (00:50:31):

It was the education thing. You used to say consulting. And now you say consulting and education. When you were here last, you were starting a program to have a member section to your blog, but that's extended. So what's going on with the education world of Embedded Artistry?

PJ (00:50:54):

So we do still run our membership program, and that's doing quite well. I don't have the current country count, but I think we have representation from more than 40 countries. We just added Morocco yesterday, so that was pretty exciting, and continue to publish members-only posts that go into analyses of some of these papers that I read, but also technical approaches to different problems or what you might call focus topics.

PJ (00:51:26):

I have a section on handling code reviews in an organization, not just code reviews, I should say, code and design reviews, or a Capability Maturity Model for a connected IoT device. What kind of features do you really need to have on that device to take full advantage of your connected capabilities?

PJ (00:51:50):

So there are explorations like that, but we're also working on a number of courses. The current one that should be finished, version one, by the time, well, not the time this comes out, but maybe a couple weeks after this comes out, is our Designing Embedded Software for Change course.

PJ (00:52:04):

We have a couple others like using C++ without the heap. I think some people in the embedded.fm Slack group used our CMake course in the book club.

EW (00:52:17):

Yep.

PJ (00:52:17):

We have a Meson course. We have a Make course. So all sorts of, I would call them, in-depth courses that are targeted for professionals. So you're a professional embedded software developer. You need to solve some particular problems in your field.

PJ (00:52:34):

What's the latest and greatest techniques that you can actually apply to your systems to achieve these goals of building a system that can be easily tested, of building at least pieces of your system that can be easily changed, of automating software quality enforcement, things like that.

EW (00:52:51):

You have a pretty long list. Are they self-paced or cohorts?

PJ (00:52:55):

Right now everything is self-paced, and it is a long list, but some of them are also in development. So I would say about half the courses, they are completed, and then half are in different states of development. But all of them, I have hundreds of notes for each course that when I get the time, I organize them and release that content on a rolling basis.

PJ (00:53:18):

I would like to do cohort-based stuff, but I haven't figured out a model that works for me yet, just managing the time, and how to interact with people, and what aspects to focus on. So that is something that I have in mind, but it's probably a couple years out.

EW (00:53:35):

The cohorts are fun. You get a lot more interaction, but they're also fairly exhausting.

PJ (00:53:42):

Right.

EW (00:53:44):

Are you having fun doing the classes? You must be, because you're expanding them.

PJ (00:53:50):

Having a lot of fun. Yeah. It's probably the most fun I've had in my career the past couple years.

EW (00:53:55):

Do you have to give up much in the way of consulting services to make time for the education?

PJ (00:54:01):

I do, especially now with two kids, but I still consult. I have three clients now, but it tends to be I'm doing more advising work, or helping review code, or someone comes to me with a file and says, "We don't like how this file's implemented. How could we make it better," and then coming up with ways to do that.

PJ (00:54:22):

So that tends to be more of the work I'm doing now. And it's good, because a lot of it is related to the courses I'm building. So I just advised one client on, "What does it look like to have a reproducible build environment with a standard build interface? How do I take advantage of that with a CI system?"

PJ (00:54:42):

And these are all topics that we're developing for our automated software quality enforcement course. So a lot of it helps me test out some of these concepts and see how they hold up in the field.

PJ (00:54:54):

It's not just like I've made up a bunch of ideas in my head and put them on a course for people to learn and try themselves. So for that reason, I don't think I'll ever give up the consulting, because it's good to have some way to test all these ideas out.

EW (00:55:07):

Designing Embedded Software for Change, what's that one going to be like?

PJ (00:55:11):

So that course, ... it's a mix of theory and coding, I would say. So there's the theory of, "Why does it matter that we design our systems for change? And what are some fundamental design principles that we can use when approaching systems that we want to design for change?"

PJ (00:55:29):

And those are topics like loose coupling, separation of concerns, information hiding, and open-closed principle. And then, "Okay, great. We have this theory." You need to apply that to a system somehow. So there's some system-level strategies for approaching a system to make it changeable.

PJ (00:55:47):

And then each of those strategies I've mapped to specific coding techniques. Some of them are the template method and callbacks that we talked about, so showing examples in the code of how I can actually apply these techniques to support change in my system.

PJ (00:56:06):

And on top of that, we're trying to find real-world software. I think that ... part of the problem in my own career and that I've seen in others is, we read a lot of code and we copy a lot of code to do whatever we need to do. And so if the models that you're studying, or you're basing your own designs off of, or the code you're copying are poor, I mean, you're going to get poor results.

PJ (00:56:30):

And I'm saying poor at least on the axis of changeability. So I'm trying to identify, "What are real-world projects that use these techniques that you can look at and see how they actually support whatever aspect of change they need to support?"

PJ (00:56:45):

And ... I have some demonstrations we've put together showing again, "Okay, I've got this driver that was written for the Arduino STK. How can I refactor the implementation just a little bit to make it so now that could be used in any framework I want instead of just on the Arduino?"

EW (00:57:02):

I'm back to where do you find the time?

PJ (00:57:06):

Little bit of progress every day adds up. That's all I can say.

EW (00:57:12):

What other design patterns do you think are important for embedded software engineers to know?

PJ (00:57:19):

So state machines have been mentioned. I'm continually surprised, I think, based on how fundamental state machines are to my own work, to find that it's not the case in a lot of the projects I've worked on and teams I've consulted with. I think state machines can clean up a lot of code if you can think about structuring your code in that way.

CW (00:57:39):

Just moving to event-driven systems, -

PJ (00:57:41):

That's another thing.

CW (00:57:42):

- which comes with state machines, but it's just so much easier to think about. And since the topic has changed, that's one of the things that's changed in my development is, starting out with a very choose your own adventure approach to software development where just lots of if-then-else's, and functions, and things.

CW (00:58:00):

And I wrote very bad code when I was sort of starting out to where I hope I am now, which is, "Okay, ... what are the main actors? How do they need to communicate? What are the things that happen, and how are those conveyed to each other?" And it ends up in lots of event loops, and state machines, and things that I think are pretty readable.

EW (00:58:20):

And how do you delete code, and how do you delete shared states so -

CW (00:58:25):

Or add code. "How do I extend functionality?" State machines make that quite easy too.

EW (00:58:29):

I tend to realize that the code I wrote initially was 90% delete if I could just replace it with a state machine or something.

CW (00:58:38):

Yes.

EW (00:58:39):

Not more clever, but something more canonical.

CW (00:58:44):

You've done one panel discussion with Memfault, I think it was in April. And you have another one coming up, right?

PJ (00:58:54):

Yep. That will be at the end of August, the 28th.

CW (00:58:58):

What's the topic? The first one was scaling embedded systems, right?

PJ (00:59:02):

Sorry, the 25th.

CW (00:59:04):

Okay.

PJ (00:59:04):

Man, I'm not doing good with all my memorization of facts. The first one was on device metrics, and how we can use metric collection in the field to help our debugging, and, well, I guess all sorts of prioritization efforts, how do you figure out what features to develop next, things like that, using metrics collected from the field.

PJ (00:59:26):

And then this upcoming panel, we're going to be discussing more generally, how do you debug devices once they've gone out into production.

CW (00:59:36):

Cool. And people can sign up for that. We'll have the link, I think.

PJ (00:59:43):

We'll have a link in the show notes.

CW (00:59:44):

A link in the show notes.

PJ (00:59:44):

We'll have a collection of links in the show notes.

CW (00:59:46):

Collection of links.

EW (00:59:47):

I have a bunch of tabs open, so I'll be copying those over before we close them all.

PJ (00:59:56):

I have one more design pattern that came to mind.

CW (00:59:58):

Oh, sure.

EW (00:59:58):

Okay.

PJ (00:59:59):

Communicating through queues.

CW (01:00:02):

Yes.

PJ (01:00:03):

I mean, it ties again into states and events, but just more generally sending data through queues instead of directly passing data between components, it's a great way for decoupling things. And you can isolate stuff to test.

PJ (01:00:17):

It doesn't matter what's at the other end of the queue as long as you have a standard definition of the data that both modules are using. That's been something that's really helped a lot of my designs

CW (01:00:27):

And it's easier to instrument. I mean, you said you can put something on the other end, but you can also instrument to transmit and receive everywhere. So, "Oh, this happened and this guy didn't get it."

CW (01:00:40):

I mean, you can sort of do that with calling functions directly, but it's very messy. And ... everything funnels into a central receive. So it's much easier to say, "Oh, I received this message and just have a little debug printout that says, "Got this event."

EW (01:00:57):

I totally -

CW (01:00:59):

Uh-oh.

EW (01:00:59):

- agree with you about -

CW (01:01:00):

I totally agree, but -

EW (01:01:03):

- the queues, because I've seen that. It does make things better, but as I'm on the Wikipedia list of software design patterns, there's no queues here.

CW (01:01:15):

Well, I mean, there's no design pattern board.

EW (01:01:21):

Well, that's the thing is I feel like both, I don't know all of these patterns as well as I want to, and many of the things that we do commonly aren't even on here. So design patterns are broken. Let's just give up. No, wait, that's not what I meant to take away from that. I don't know what I meant to take away. Oh, I guess, Phillip, could you fix that for us?

PJ (01:01:47):

I will try. I have my own design pattern catalog. So I'm working on it.

EW (01:01:53):

That would be kind of interesting. You mentioned design patterns in embedded C, which is up here somewhere. "Design Patterns for Embedded Systems in C" by -

PJ (01:02:05):

There we go.

EW (01:02:06):

- Bruce Powel Douglass. Maybe that's where I should be looking instead of Wikipedia.

PJ (01:02:13):

Yeah, we know that Wikipedia is always 100% factually correct. And there are no political motivations or people trying to claim territory on Wikipedia. That never happens.

EW (01:02:23):

Well, I mean the software design patterns page seems fairly straightforward.

CW (01:02:30):

You go in there and add queues.

PJ (01:02:32):

I was going to say, "Add queues, see what happens." I consider message queues and event queues to be a design pattern, but I could see message queues being under a message passing design pattern, right? So certainly names are hard.

CW (01:02:48):

Yeah, but it would be called the loosely-coupled Aardvark or something.

EW (01:02:50):

Yeah.

PJ (01:02:52):

Maybe that's what we need. More memorable names.

CW (01:02:54):

Yeah.

EW (01:02:55):

Yes. Yes. I think so. Speaking of aardvarks, you mentioned the Aardvark tool.

CW (01:03:00):

Oh wow. Nice.

EW (01:03:03):

And like I said, I have a lot of tabs up. Could you explain it? I hadn't come across it before.

PJ (01:03:12):

So I had discovered them through their USB debug adapter, which is excellent, if anybody's working on a USB device and you really need to do analysis of the messages that are going over the bus. But this device is a USB to SPI, I2C, and GPIO, I guess, debug adapter.

PJ (01:03:34):

So they have a little GUI program that you can use to talk to devices and send raw SPI or I2C commands and see what response comes back. But they also provide an API that you can use. I think you also need libusb. So you can programmatically work with the adapter.

PJ (01:03:53):

And so for my standard SPI and I2C interfaces, I have an Aardvark driver, and I have SPI and I2C interfaces that use that Aardvark driver to talk to the device. And yeah, I can control any SPI or I2C device. Chip select lines can work because you can do SPI plus GPIO.

PJ (01:04:16):

So it's a pretty powerful tool for one, debugging those devices, if it's not working in your system, and you want to just talk to the raw device itself ... whether you have a fundamental flaw in your understanding, or whether there's something else going on, but also, yeah, for developing devices without having like a full board in-house. And so that's been a real beneficial practice in my career.

EW (01:04:43):

Have you used the Bus Pirate?

PJ (01:04:45):

I have not. Should I?

EW (01:04:48):

I don't know. How you describe it is largely how I would describe the Bus Pirate, but it's an order of magnitude less in cost, price. And so I think there must be some qualitative difference.

CW (01:05:02):

I don't think it's quite as sophisticated.

EW (01:05:04):

No, you're definitely kind of bashing at it.

CW (01:05:06):

Yeah.

EW (01:05:06):

But you can make scripts.

CW (01:05:07):

Yeah.

PJ (01:05:09):

I don't think that you need to necessarily use an Aardvark. I've done the same thing in the past using an FTDI chip. So I wouldn't recommend that necessarily. It's a little more painful than using -

EW (01:05:23):

Oh, yeah.

PJ (01:05:23):

- an API that somebody else manages for you. But yeah, you can generally use any number of adapters for this. And I think I have a couple of little China-designed boards that I've used from time to time. For example, I wouldn't travel to China with my Aardvark. I usually took a little multi-protocol board with me that I could do JTAG, SWD, SPI, I2C, GPIO controls, all sorts of stuff.

EW (01:05:50):

I mean, now for bringing up a new I2C or SPI device that, I wanted to just talk to it, I would seriously consider a MicroPython board. I mean, it's just so easy to use, and I mean, you can use it both to do the communication and to monitor the lines. So you get both logic analyzing and communication. I don't know. I haven't tried it yet, but I've been thinking a lot about it.

EW (01:06:25):

Well, Phillip, we have gotten off whatever the topic was. Clearly we are not in a rut, because we went all over the road. So do you have any thoughts you'd like to leave us with?

PJ (01:06:39):

Check out our website, if you like this kind of conversation. I explore all of these ideas in great depth, much deeper than you can get to in a live conversation without code, right? It's hard to conceptualize some of this stuff without code.

PJ (01:06:56):

So if you want to learn more about this stuff, check out our website, look at our course list, become a member, check out some of the great members-only content we have in the field atlas. And you can always contact me if you have any questions, and I'll point you to the right stuff if I know.

EW (01:07:12):

Our guest has been Phillip Johnston of Embedded Artistry. There will be many links in the show notes, but if you just search for Embedded Artistry, you can get to his site.

CW (01:07:22):

Thanks, Phillip. It was good to talk to you again.

PJ (01:07:24):

Thanks for having me. Talk soon.

EW (01:07:26):

Thank you to Christopher for producing and co-hosting. Thank you to our Patreon listener Slack group for some ideas about how they have changed over their careers. And of course, thank you for listening. You can always contact us at show@embedded.fm, or hit the contact link on embedded.fm.

EW (01:07:44):

And now a quote to leave you with, from Maya Angelou. I wonder if I've used this one before. Anyway, from Maya Angelou. "We delight in the beauty of the butterfly, but rarely admit the changes it has gone through to achieve that beauty."