HN user

silentbicycle

11,689 karma

Bicycles. Sourdough bread. Puzzles, of all kinds. Tea and word games. Mountain Goats live shows.

Email: At gmail, with the account name vokes DOT s. My name is Scott, and I cook a mean frittata.

http://github.com/silentbicycle http://twitter.com/silentbicycle

Declarative real time programming NOW!

http://hackernewsers.com/users/silentbicycle.html

Posts209
Comments3,475
View on HN
www.helium.com 9y ago

Scripting Helium with Lua: Bring Your Own Business Logic

silentbicycle
1pts0
www.helium.com 9y ago

Dodging the Brick: Safely Updating IoT Devices in the Field

silentbicycle
1pts0
spin.atomicobject.com 10y ago

Distributing Command Line Tools with Docker

silentbicycle
5pts0
spin.atomicobject.com 10y ago

Configuring a Laptop with Ansible, Part Two

silentbicycle
2pts0
spin.atomicobject.com 10y ago

Configuring a Laptop with Ansible, Part One

silentbicycle
1pts0
spin.atomicobject.com 10y ago

Fuzz Testing with Afl-Fuzz (American Fuzzy Lop)

silentbicycle
2pts0
spin.atomicobject.com 10y ago

Getting Started with Embedded Programing

silentbicycle
1pts0
spin.atomicobject.com 11y ago

Fighting Log Entropy

silentbicycle
1pts0
spin.atomicobject.com 11y ago

Expect()ing the Unexpected

silentbicycle
1pts0
spin.atomicobject.com 11y ago

Fixing UI Elements That Float Away

silentbicycle
1pts0
spin.atomicobject.com 11y ago

Creating Man Pages in Markdown with Ronn

silentbicycle
2pts1
spin.atomicobject.com 11y ago

Spread Your Wings and Stop (Exclusively) Using Arduino

silentbicycle
2pts0
spin.atomicobject.com 11y ago

A Comparison of 5 Uniprocessor OS Scheduling Policies

silentbicycle
27pts3
spin.atomicobject.com 11y ago

Autoclave: A Pressure Cooker for Programs

silentbicycle
2pts0
spin.atomicobject.com 11y ago

Understanding Uniprocessor OS Scheduling Policies

silentbicycle
20pts2
spin.atomicobject.com 11y ago

Configuring a Git-Controlled Home Directory with Ansible

silentbicycle
2pts0
spin.atomicobject.com 11y ago

Embedded Rust Right Now

silentbicycle
5pts0
spin.atomicobject.com 11y ago

More Typing, Less Testing: TDD with Types, Part 1

silentbicycle
3pts0
spin.atomicobject.com 11y ago

Odo: Atomic Counters from the Command Line

silentbicycle
1pts0
spin.atomicobject.com 11y ago

Optimizing Tail Call Recursion

silentbicycle
37pts2
spin.atomicobject.com 11y ago

Nicer C99 APIs with Designated Initializers

silentbicycle
3pts3
spin.atomicobject.com 11y ago

Re-imagining Operating Systems: Xen, Unikernels, and the Library OS

silentbicycle
4pts0
spin.atomicobject.com 11y ago

Theft: Property-Based Testing for C

silentbicycle
50pts1
spin.atomicobject.com 11y ago

Property-Based Testing – Testing Assumptions You Don’t Know You’re Making

silentbicycle
2pts0
spin.atomicobject.com 11y ago

Visualizing Garbage Collection Algorithms

silentbicycle
329pts22
www.linusakesson.net 11y ago

GCR decoding on the fly

silentbicycle
62pts5
spin.atomicobject.com 11y ago

The Fisher-Yates Shuffle – An Algorithm Every Developer Should Know

silentbicycle
1pts0
spin.atomicobject.com 12y ago

0x20 Lessons Learned as a Professional Developer

silentbicycle
2pts0
spin.atomicobject.com 12y ago

Callaloo Radio System: Part 3 – Publishing Status over MQTT and HTTP

silentbicycle
11pts0
spin.atomicobject.com 12y ago

Callaloo Radio System: Part 2 – Building a Homebrew USB Device

silentbicycle
19pts4

I decided against software USB because the receiver is already spending much of its time trying to meet the real-time limits from the radio decoding, and the USB would be its own big undertaking.

As I stressed in the preceding post (http://spin.atomicobject.com/2014/05/16/radio-system-from-sc...), I'm intentionally doing these things the hard way, so I can learn how more of these things work at a deeper level than "use built-in functionality, configure to run at this baud rate, done". Otherwise, yeah, I'd use a 32-bit ARM chip and a better SMD transceiver. :)

Hello, author here. As I said, mostly stressed in the first post, I'm doing things the hard way as a learning exercise, building a bunch of infrastructure myself. I would use a better radio transceiver and a chip with actual USB and UARTs, etc. if it wasn't a self-study project. :)

There's no way to know that the payload has been received - they're transmitters, not transceivers. The messages are idempotent anyway, so just retransmitting makes the whole system simpler.

Thanks for letting me know. I made sure the ATtiny84s could be re-flashed in circuit in case something like this came up. (I also have 315MHz modules, and will prefer those in the future. Swapping out the transmitters and receivers will only take a bit of resoldering.)

Short names also make sense if the same conventions appear over and over throughout the code base. While they can be quite opaque at first, they're very consistent, and people with experience in other APLs will recognize many of them.

Thanks! There are much better indexing algorithms if you don't have such tight resource constraints, but it may be a useful trick to speed up inner loops in some other algorithms.

I realized yesterday that it can also be used as the basis for a linear-time sorting algorithm: https://gist.github.com/silentbicycle/8389129

Benchmarking indicates that it's probably not competitive speed-wise compared to counting sort (of which it is a variant), but the implementation should be pretty easy to understand. It may be good for pedagogical purposes.

I think it could work like this:

    SUITE_LIST(suites) {
        suite1,
        suite2,
        // ...
    };

    GREATEST_MAIN(suites);
but, again, I don't know if that's necessarily an improvement. RUN_SUITE is encapsulating saving the suite's name, optionally only running suites with names that match a certain pattern, and some other features that become tricky to implement with just a statically allocated function pointer array. I'm also trying to avoid doing anything "clever" with macros.

Unity alone doesn't, but ceedling and CMock do. I was referring to them as a group, because I usually see them used together, but you're right.

(I work with most of the maintainers of those tools, and have some minor commits myself.)

In my experience, unit testing is more common in embedded C development, because the code is held to much higher standard of accountability.

Sloppy embedded code can kill people, or at the very least lead to incredibly expensive hardware recalls. With the exception of poorly thought-out privacy policies, it's unlikely that errors in a web app can cause that level of problems.

It's also much easier to deploy an update to a web app than a Mars rover or a car's brake controllers.

Thanks!

I use GREATEST_MAIN_BEGIN and GREATEST_MAIN_END so that people can put other things in main, around them. Also, there are often several RUN_SUITE calls, and I can't depend on vararg macros portably without also depending on C99. While there are some ways to work around that, they don't deliver enough value to justify the added complication.

I'm been thinking about ways to get around this. I'm using macros for __FILE__ and __LINE__, but it does interfere with breakpoints.

One of my open issues is to add an ASSERT_EQ_MEMCMP function that does print out the difference, probably as a hexdump. Similarly, greatest could have something like 'ASSERT_EQ_NUM' for the cases where printing the value is meaningful, and an ASSERT_EQ_STRUCT that takes cmp and print functions. I've been thinking about it for a while, because I want to get it right before I change the API.

Knowing that a change broke a specific set of tests tells you a lot more than knowing it broke the first one of them that happened to run.

If I'm using fuzzing to run thousands of tests, and all the ones whose seed led to the same specific bit pattern are failing, that's particularly useful information. I found a particularly subtle bug in heatshrink (https://github.com/atomicobject/heatshrink) that way, but a single failing test would have looked like noise.

They've got a lot in common. tinytest looks a bit simpler, but also doesn't do any allocation and looks reasonably portable. Cool.

The single biggest difference is that greatest has more control over about which test(s) it runs. tinytest just bails at the first failure, whereas greatest can run everything and report, or individual test(s) or groups of tests whose names match a substring. That adds some to the implementation, but I've found it particularly valuable once a program has several modules and hundreds of tests.

Also, greatest supports parametric testing, which means that adding fuzzing/randomized testing is pretty straightforward (though usually project-specific).

tinytest requires C99, greatest doesn't. That shouldn't matter, but unfortunately sometimes it does. Embedded compilers for proprietary architectures can be lacking, in particular.

greatest also doesn't assume ANSI escape sequences are okay. Sometimes dumping out a bunch of [1;31m stuff is annoying. That's a matter of taste, though, and it'd be easy to make it optional.

I've seen people do that before, as well as putting the tests in the .c file, guarded by "#if TEST_MODULE_NAME", and exporting a (module_name)_run_tests(void) function.

My preference is to have separate test_module_name.c files. Failing that, I would include tests in the module's .c file rather than the header, so that the header can be relatively short and focused on documenting the module's interface, rather than its implementation details.

greatest doesn't force any specific style there, by design.

I (the author) have been doing a lot of embedded development lately, and in those cases you really can't assume very much beyond core ANSI C features. That's also why greatest doesn't do any dynamic allocation, at all. There's a relatively small struct for the current testing progress, and everything else can easily run out of ROM.

My primary goal with greatest is to assume as little as possible, and avoid imposing any additional constraints on projects just because people want to test them. I also want the implementation to be very transparent -- it's just a 600-ish line header file, carefully documented. It's a major pet peeve of mine when I have to work around features that try to automatically be helpful, but have edge cases that break down in opaque ways. (Build systems tend to be particularly bad in that way.)

Also, I'm beyond shocked that the name wasn't already taken. ;)

One of my upcoming tasks is making stdio optional in greatest, because printf doesn't do you a whole lot of good if you're running it on an Arduino or something, but in those contexts automated testing is especially valuable.