Skip to main content

Ralsina.Me — Roberto Alsina's website

Audio! Navecitas!

Un­os min­u­tos eligien­do as­sets de ken­ney.n­l, un par de fun­ciones para que ten­ga so­porte de au­dio (sí, to­do el au­dio viene del código) ... ob­vi­a­mente no hay col­i­siones to­davía, y to­do es ... pre­cari­o.

El códi­go del jue­go: http://linkode.org/#E­Ja2EXWn­ToRI4zFr7vof15

The perfect Raspberry Pi setup

I am do­ing some semi-se­ri­ous Rasp­ber­ry Pi de­vel­op­men­t, so it was time I fig­ured out how to do it com­fort­ably.

My desk­top set­up is a two-­mon­i­tor con­fig­u­ra­tion, with my note­book on the ta­ble and a larg­er mon­i­tor above it. I like it, it's nice. The point­er nat­u­ral­ly goes from one screen to the oth­er in the ob­vi­ous way.

Desktop setup

Spe­cial­ly nice is that the lap­top's screen is touch and has an ac­tive pen, so I can use it nat­u­ral­ly.

But now, with the Rasp­ber­ry, I want to oc­ca­sion­al­ly show its dis­play. And that means switch­ing the mon­i­tor to it. Since I hate plug­ging and un­plug­ging things, I use one of the­se:

HDMI switch

It's a cheap tiny black plas­tic box that takes up to 5 HD­MI in­puts and switch­es be­tween them to its one out­put by click­ing a but­ton. It on­ly goes through the in­puts that have sig­nal, so since I on­ly have the lap­top's and the Pi's the but­ton tog­gles be­tween them.

If your mon­i­tor has more than one HD­MI in­put you can prob­a­bly just use that, but mine has just one.

But... what about key­board and mouse?

I could get a mul­ti­de­vice key­board and mouse, but I like the ones I have.

I could use a USB switch and tog­gle be­tween the two de­vices, but ... I don't have one.

So, I use bar­ri­er and con­fig­ure it in both the rasp­ber­ry pi and in the lap­top so that when my point­er goes "up" in­put goes to the Pi, and when it goes "down" in­put goes to the lap­top. That's ex­act­ly the same as with the du­al-dis­play se­tup, but with two com­put­er­s. Neat!

So, go ahead and con­fig­ure bar­ri­er. It's easy and there are tons of tu­to­ri­al­s.

Nex­t, make sure bar­ri­er starts when I lo­gin in­to both com­put­er­s. They way I pre­fer to do these things is us­ing sys­temd.

Put this in ~/.local/share/systemd/user/barrier.service in both machines:

[Unit]
Description=Barrier server
[Service]
Environment=DISPLAY=:0
Type=simple
TimeoutStartSec=0
ExecStart=/usr/bin/barrier
[Install]
WantedBy=default.target

Now you can make it start with systemctl --user start barrier or stop with systemctl --user stop barrier and make it start on every login with systemctl --user enable barrier

But while this is nice, it presents a prob­lem. When I am us­ing both dis­plays for the lap­top, I don't want bar­ri­er run­ning! Since I can't see the Pi's dis­play, it makes no sense.

So, I want to start bar­ri­er when the lap­top is us­ing one mon­i­tor, and stop it when it's us­ing two.

To do that, the trick is udev in the laptop. Put this (replacing my username with yours) in /etc/udev/rules.d/90-barrier.rules:

ACTION=="change", \
    KERNEL=="card0", \
    SUBSYSTEM=="drm", \
    ENV{DISPLAY}=":0", \
    ENV{XAUTHORITY}="/home/ralsina/.Xauthority", \
    ENV{XDG_RUNTIME_DIR}="/run/user/1000", \
    RUN+="/home/ralsina/bin/monitors-changed"

Basically that means "when there is a change in the configuration of the video card, run monitors-changed. Change the 1000 by your user ID, too.

The last piece of the puzzle is the monitors-changed script:

if `xrandr --listmonitors | grep -q HDMI`
then
    # The HDMI output is connected, stop barrier
    su ralsina -c '/usr/bin/systemctl stop --user barrier'
else
    # The Pi is using the monitor, start barrier
    su ralsina -c '/usr/bin/systemctl start --user barrier'
fi

And that's it!

This is the be­hav­iour now:

  • When the lap­­top is us­ing both dis­­­plays, they work nor­­mal­­ly in a "ex­­tend­ed dis­­­play" con­­fig­u­ra­­tion. They be­have like a sin­­gle large screen.

  • When I click on the HD­­MI switch and change the top dis­­­play to show the Pi's desk­­top, au­­to­­mat­i­­cal­­ly bar­ri­er starts in the lap­­top, and now the point­er and key­board change from one com­put­er to the oth­­er when the point­er moves from one mon­i­­tor to the nex­t.

  • If I click on the HD­­MI switch again, bar­ri­er stops on the lap­­top and I have a sin­­gle two-screen desk­­top again.

Ev­ery­thing be­haves per­fect­ly and I can switch be­tween com­put­ers by click­ing a but­ton.

Al­ter­na­tive­ly, we could start the bar­ri­er client when the rasp­ber­ry pi "get­s" the dis­play, and stops it when it goes away. The re­sult should be the same ex­cept for some cor­ner cas­es, but it has the added ben­e­fit of al­low­ing for a set­up with up to 5 de­vices :-)

The lost opportunity in test coverage

Dis­claimer: This is a bit of a rant, but it's a friend­ly rant :-)

When peo­ple look at code cov­er­age, they are read­ing it wrong.

Suppose you have a class, something stupid, like your own implementation of a stack, called Stack. Because you are not a total monster, you have tests in your code right? In fact, you are claiming that you are doing TDD (Test Driven Development), or at least you like TDD, or you would like the idea of TDD, or, let's be honest here, you just say you are doing TDD, but what you do is you sprinkle the tests you feel are needed, which is largely OK, I am not going to judge you, you freak.

And then you add test cov­er­age check­s, and it says: 80%

What most peo­ple feel when they see that is dread. They see that 80% and feel "OM­FG, my tests suck! I don't have enough! If even 100% cov­er­age is not enough then this 80% means my code is an un­sta­ble piece of garbage!"

Well, no.

Whether your code is good or not is in­de­pen­dent of test­s. Tests give you the abil­i­ty to know if your code is crap or not... some­times. What tests re­al­ly give you (if they are not to­tal garbage in them­selves) is the con­fi­dence that you can change your code with­out sig­nif­i­cant­ly af­fect­ing the be­hav­iours the tests are test­ing.

So, if your tests of Stack ensure that:

  • Stack.push puts the element at the top
  • Stack.pop gets the top element
  • Your stack can hold as many el­e­ments as your re­quire­ment de­fines (may be in­finite)

Then what you implemented is a stack. Period. It works. It's fine. It may be inefficient, it may be ugly, who knows, but tests are not going to give you good taste. All they are going to do is ensure that Stack is, indeed, a stack, and behaves like a stack, and that when you stick your mittens in it and change things inside it it stays a stack.

Yet, your cov­er­age is 80%.

Should you add more test­s?

No.

You should delete 20% of your code.

Since code is a li­a­bil­i­ty and the as­set is the code's be­haviour, then that's what the first D in TDD is for.

Test Driv­en De­vel­op­men­t.

Use the tests to de­fine the be­hav­iour you wan­t. Then add code to im­ple­ment that be­hav­iour.

Don't chase use­less stats like cov­er­age.

If cov­er­age is not 100%, con­sid­er your test­s.

Is there be­hav­iour you want that is not rep­re­sent­ed as a sce­nario in a test?

If yes: then add test­s.

If not: re­move code.

And us­ing "cov­er­age is low" as an op­por­tu­ni­ty to delete code in­stead of adding tests is some­thing a lot of de­vel­op­ers mis­s.

CobraPy: a group of minimum viable things

A group of crows is called a mur­der of crows. A group of hares is called a coun­cil of hares.

In fac­t, that's just a bunch of things vic­to­ri­ans made up be­cause they had lots of free time and they had­n't in­vent­ed the In­ter­net yet, and most of those were nev­er ac­tu­al­ly wide­ly used.

BUT what's the name for a group of things that are in a min­i­mal­ly vi­able state?

Well, Co­braPy, my 80s-style python pro­gram­ming en­vi­ron­ment is slow­ly crawl­ing in­to be­com­ing one of those.

Of the com­po­nents I wan­t, I have one of each. They all suck but they suck in the same way a 3 year old play­ing pool suck­s. He will not be great but it's still cool.

  • I am go­ing to punt in hav­ing the ed­i­tor I want be­cause I can make do with Mi­cro for the time be­ing (works flaw­less­ly in my ter­mi­nal!)
  • The RE­PL is not great but it can do what it can do
  • The graph­ics serv­er works (although its API is lim­it­ed to draw­ing cir­cles)
  • The ter­mi­nal is bet­ter than ex­pect­ed, could re­al­ly be used as a dai­ly driv­er ex­cept for some pro­grams re­al­ly not lik­ing it.

And al­so, I have com­bined all the things so that you can start a win­dow that:

  • Is a ter­mi­nal
  • That runs the re­pl
  • Where you can use the graph­ics API
  • And it dis­plays in the same win­dow

What nex­t? I could think about what nex­t. Or ...

I could try to write a sim­ple game and im­ple­ment all the things that don't ex­ist.

Ex­cept for in­put. I need to solve how to do in­put. You see, the user-cre­at­ed pro­grams don't run in the same space as the win­dow. That's why we have a graph­ics pro­to­col. The pro­gram puts things in it, the win­dow reads them and graph­ics ap­pear.

But in­put needs to go the oth­er way around. So I need to add a sec­ond pro­to­col to send back events and it needs to be pret­ty fast. I don't think it's go­ing to be a prob­lem (us­er ac­tions hap­pen on­ly once ev­ery few dozens of mil­lisec­ond­s!) but af­ter that's done?

It's go­ing to be time for ...

Or ac­tu­al­ly, to fail at im­ple­ment­ing it, but im­prov­ing the plat­form in the process. Be­cause fail­ure is what im­prove­ments are made of.


Contents © 2000-2023 Roberto Alsina