ia: Benvenite! In mi blog io scribe in interlingua, italiano e anglese.

it: Benvenuti! Nel mio blog scrivo in interlingua, italiano e inglese.

en: Welcome! In my blog I write in Interlingua, Italian and English.

Some thoughts on generative AI

Among all the blog posts and videos in the internet which are critical of AI (specifically LLM, generative AI), I haven't yet met one which puts the main focus where I'd put it, so here's yet another text critical of AI.

A good list of points can be found on this site, which, to my surprise, is missing exactly that point that I'd bring up first: the destructive impact of AI on society. Many other pain points, such environmental, copyright, centralization and quality issues, can (and, hopefully, will) be addressed and fixed as the technology improves, but one aspect that will never be resolved is the disintegration of human relationships. They are already at a pretty low stage, judging by the amount of people who sit in restaurants looking at their phones instead of talking to each other, but generative AI takes this further down by quite a few steps.

By empowering the individual to reach their goal in autonomy, AI renders social contacts less necessary: if I ask it to generate a picture, a book, a program, a medical diagnosis (don't laugh, this is happening already!), a holiday plan, I'm certainly saving a lot of time, but I'm also not talking to a designer, an author, a software developer, a doctor, a friend, who might have fulfilled the same task and give me something more, too: they could have made me learn something about this task or their profession, share a bit of their expertise, they could have asked questions that would help me better understand what I really want, made some suggestions and, why not, started developing a friendship.1

People are harder to deal with, that's a fact: AI doesn't (or will not, as it improves) require you to be polite, patient, ask you to repeat the same thing a couple of times, it will not delay the delivery because of some family issues or disappoint you with the result (if it does, just try again, it's anyway fast to iterate). But in my opinion talking to humans is an effort well worth the candle: humans can grow wiser through experience and interactions, and by talking to the same artist whose work initially disappointed you, you can both gain something and learn how to productively work with each other.

As human generations pass, it's becoming clearer and clearer that evolution has stopped and we are degrading on several fronts, including communication, empathy, and the ability to organise ourselves in communities (no matter how small). We are getting into a point where someone in power can effectively disable you with a click of a mouse button, by cutting your only link with the rest of the humanity. No one will ever hear of you again, remember that you exist and that you might be in need of help.

That's all for the main point of this article. I'm continuing with more considerations below, for those few who are into reading.

It's not a tool

Describing AI as a tool like many others is lying to ourselves. It's only true in those cases where the result is predetermined by the inputs, but as soon as the "generative" part of the AI kicks in, it stops being a tool and it becomes an independent brain, with its own creativity. A hammer does not decide where and how strongly to hit, a car does not decide where to go, and a photocamera does not decide what to photograph. It's true that complex algorithms have started to creep into our tools since a long time, so a car might decide to limit your speed and your photocamera might adjust the exposure and decide on which subject to set the focus, but we are still speaking of predictable algorithms, which anyway many professionals detest and switch off whenever possible — exactly because they wanted a tool, and nothing more than that.

Result versus process

AI is mostly about the result: you just want something done, quickly and as soon as possible. Non-AI is about the process: it's when you enjoy doing something, even if it's hard, even if it's new to you, because you like the journey of learning and discoverying. That's why I don't program using AI. Progress is not just about getting work done faster and better; it's mostly about improving your life, being able to do things you enjoy doing. I shoot using a film camera, I go shopping by foot, I write paper letters by hand, and people do still ride horses.

Using AI-generated products

I don't mind using something that's AI-generated, as long as that's something of little importance to me (like a software program that I know I'll use just once in my lifetime). But especially if we talk about software programs, then we need to keep in mind that, using AI, the speed of their creation is potentially proportional to the speed of their dismissal: it's harder to build a community around an AI-generated project (and its author might not even feel like he needs one), and without a community the project is dead the moment that it's author decides that it's not worth to work on it anymore. And given that the invested time (and received pleasure) creating and maintaining this project is typically lower than that of a non-AI project, the personal attachment to it is also likely lower.

If people enjoy creating programs (and even whole operating systems) using AI that's completely fine, but my interest towards them is close to zero: I don't want to risk getting accustomed to (or dependent on) something that could get discontinued at any time.


  1. Not even to mention the case where AI is not being used to solve a task, but just as a chat companion. ↩

Tip: setup debugging messages for Wii/GameCube applications

Here's a small piece of advice if you are into Wii/GameCube development and are not sure how to produce debug messages in a way that allows you to easily see them.

On the Dolphin emulator

This is the way I'd recommend you to debug your application, since Dolphin makes it quite easy:

  • Write your messages to stderr. For example: fprintf(stderr, "%s:%d Hello!\n", __func__, __LINE__);. Or use a macro, like those I have in bt-embedded.
  • Near the beginning of your main(), call "SYS_STDIO_Report(false);": this instructs libogc to redirect all the stderr to Dolphin's OSReport log type (setting the parameter to "true" will also send the stdout to the log; but at least for console applications, this is something you probably don't want to do).
  • In Dolphin, enable the OSREPORT log type, and disable OSREPORT_HLE (otherwise this will capture stdout too; which is better done by calling "SYS_STDIO_Report(true)"), as shown in the image below:
Image
Enabling logging in Dolphin

If you follow this setup, you'll see all the stderr in Dolphin's logs, and the stdout (if you have any) will continue to be shown on the application's console, if you did set up one.

On a real Wii/GameCube

Unless you have an USB Gecko device (which I don't have), your choices are limited to sending the messages to the screen or logging them into a file on the SD card. Here's how:

  • As above, write your messages to stderr.
  • If you want to see them on the screen, I recommend using my gxconsole library, which can be setup by just calling three functions, plus one more call to draw its contents:
    GxConsole *console = gx_console_new(60, 20, &font_cozette_6x13);
    gx_console_set_input(console, 2); /* The file descriptor to capture (2 = stderr) */
    gx_console_set_alpha(console, 128); /* Set 50% transparency */

    /* Then, inside the application loop: */
    while (app_running) {
        ...
        gx_console_draw(console, pos_x, pos_y);
        ...
  • If, instead, you want to capture the messages to a file, you'll need to install a handler for the write operation of your file descriptor:
#include <sys/iosupport.h>

static int s_log_fd = -1;

static ssize_t stderr_write(struct _reent *r, void *fd, const char *ptr, size_t len)
{
    return write(s_log_fd, ptr, len);
}

static devoptab_t s_log_dotab = {
    .name = "log-to-file",
    .structSize = sizeof(devoptab_t),
    .write_r = stderr_write,
};

static void log_file_open()
{
    fatInitDefault();
    s_log_fd = open("my-application.log", O_CREAT | O_TRUNC | O_WRONLY, 0666);
    devoptab_list[STD_ERR] = &s_log_dotab;
}

static void log_file_close()
{
    if (s_log_fd >= 0) {
        fsync(s_log_fd);
        close(s_log_fd);
    }
}

int main(int argc, char **argv)
{
    log_file_open();
    fprintf(stderr, "%s:%d Hello, world!\n", __func__, __LINE__);
    ... the rest of your program...
    log_file_close();
    return EXIT_SUCCESS;
}

Note that showing the messages on the screen or writing them into a file is considerably slower than sending them to Dolphin's log, so this methods can slow down your application quite a lot.

Hope this helps!

Teaser: connecting Nintendo Switch controllers to the Wii

A few months ago I started playing with the Bluetooth controller embedded in the Nintendo Wii, to see if it was possible to get it to connect to other devices than just the Wii remotes. If you ask internet forums, you might fall into the impression that the Wii is not using a standard Bluetooth controller, or that it has been somehow "crippled" in order to restrict it to connect to the Wiimotes only, but that's not the case: it's an ordinary controller from its era, it's just that the Wii software (both the official SDK and the homebrew libogc) only uses it for the Wiimotes.

I first started looking into lwBT, the bluetooth stack used in libogc, but I quickly realized that it was impossible to get full control over the controller via this library: it has been adapted to work with the subset of the HID protocol used by the Wiimotes, and even if you can issue bluetooth commands to the controller via the HCI layer, you cannot receive the replies, since they are already intercepted by lwBT and there's no way to hook into them.

So I started writing my own little bluetooth stack, bt-embedded which from the ground up has been designed to be used by embedded devices and covering the use case of serving different clients running in a single process, and I've integrated it into embedded-game-controller (though this is not merged into the master branch yet) in order to allow connecting to bluetooth controllers. And in the last couple of days I've written a little ugly program to visualize the controllers in a 3D scene, in order to better test them:

Yes, the 3D model sucks, it was a nice model when I downloaded it from a free site, but then heavily reduced the number of polygons using Blender and went a bit too far; I'll do a better model later. The accelerometer information is not shown yet (I'd like to use it to actually tilt the controller, instead of using the joystick), but that will not be hard.

At the moment, the only supported controllers are the Nintendo Switch Pro controller (I'm using a clone here) and the Joy-cons, so there's still quite some work to do to add more.

It's been a journey in which I learned a lot about Bluetooth and USB and, who knows, maybe this will come handy in the future too.

Choreograph is still alive

Back in 2023 I started writing a game -- which is still under development as I'm dedicating very little time to it -- and at a certain point I found myself in need of animating the movement of a few rectangles on the screen. Having decided to code the game in C++ and to use just libSDL as a base (in order to keep the game as portable as possible), I started looking around for existing solutions which would do just what I need: animating points between two values, while being display and platform agnostic.

Choreograph

I was happy to find the Choreograph library, which promised to do exactly what I needed, without bringing in any more dependencies. Integrating it in my project proved to be extremely easy, and it took me a few minutes to implement the animation.

All was perfect, except one thing: the last commit to the repository happened in 2016. I submitted a couple of minor fixes, and there was no reaction. Even though I was very happy with the library, I decided not to get tied to a project that was apparently dead, so I dropped this integration and instead wrote my own implementation -- which was just enough to fill my immediate need, but was unlikely to be reusable as a generic animation framework.

Over time, though, several times I happened to bump into a situation where I would have liked to add some animation, but given that I was not really happy with my home-brew solution, I always held myself back from this desire and focused on more substantial issues: so, no animations. In March this year I decided to write to the author of Choreograph to check whether he was still interested in maintaining the project, but got no answer.

A maintained fork

Well, one cannot certainly accuse me of being impatient in this case, since I waited a few more months before finally deciding that I find Choreograph to be too convenient to let it just rot. Here is my maintained (for how long, we'll see!) fork of the Choreograph project; so far I've added:

  • A few commits to fix compilation warnings
  • Recipes for the Meson build system, to make it easier to build the project in Linux
  • CI via GitHub actions
  • Updated the tests and the samples to build without libCinder

I'm not yet able to announce what I'm going to work on next in Choreograph; this will become clear as I'll be using it more. For the time being, it's enough for you to know that such a project exists, and I'll be happy to accept contributions in the form of code and ideas.

No, libogc did not steal RTEMS code

Update 09/05/2025: while the text below addresses a couple of specific blocks of code, after publishing this article I've been contacted by some people providing more evidence pointing that the similarity of the code goes beyond what one might interpret as “inspiration”. There are also a couple of other bits on information that the reader might want to take into account: first, a screenshot of an email in which Shagkur tells his version of how the code came about (which seems to point that, if a copyright infringement actually happened, this was done without the knowledge of devkitPro's maintainers) and a public statement by RTEMS.

All of a sudden the Wii homebrew community is in flames after Hector Martin (marcan, also known in the Linux Kernel community), co-author of “The Homebrew Channel” application, decided to close the project and denounce libogc for its “theft” of RTEMS's code:

It has recently been revealed that the threading/OS implementation in libogc is, in fact, stolen from RTEMS. The authors of libogc didn't just steal proprietary Nintendo code, but also saw it fit to steal an open source RTOS and remove all attribution and copyright information. This goes far beyond ignorance about the copyright implications of reverse engineering Nintendo binaries, and goes straight into outright deliberate, malicious code theft and copyright infringement.

A little below, Hector Martin provides this “proof”: you can compare this function in libogc to this function in a really old version of RTEMS.

While I don't know the truth about libogc's history (I've started contributing to it only in the last couple of years), and I'd welcome a first-hand explanation from shagkur (Michael Wiedenbauer), I can confidently say that the accusation is unfounded, by just looking at the code. To be more precise: I cannot vouch for the whole of libogc, I can only say that this function, that Hector Martin offers as example, actually hints that the code was not stolen.

While it's obvious that the developer of libogc's code did have a look at RTEMS's code, and this can be assumed because the variable names are very similar (and in some cases they are so badly named, that they cannot be this similar by accident!), the code only looks vaguely similar. Furthermore, for some reason Hector Martin decided to pick a rather recent version of libogc's code, but if we look at the first version that was committed (well, to git, at least), we see that similarities are much less striking. Let's look at a small snippet of the function, where the thread object's members are being initialized:

RTEMS from 1996:

  the_thread->Start.is_preemptible = is_preemptible;
  the_thread->Start.is_timeslice   = is_timeslice;
  the_thread->Start.isr_level      = isr_level;

  the_thread->current_state          = STATES_DORMANT;
  the_thread->resource_count         = 0;
  the_thread->real_priority          = priority;
  the_thread->Start.initial_priority = priority;

libogc from 2023:

    thethread->budget_algo = (prio<128 ? LWP_CPU_BUDGET_ALGO_NONE : LWP_CPU_BUDGET_ALGO_TIMESLICE);
    thethread->is_preemptible = is_preemtible;
    thethread->isr_level = isr_level;
    thethread->real_prio = prio;
    thethread->cur_state = LWP_STATES_DORMANT;
    thethread->cpu_time_budget = _lwp_ticks_per_timeslice;
    thethread->suspendcnt = 0;
    thethread->res_cnt = 0;

libogc from before 2004:

    thethread->isr_level = isr_level;
    thethread->real_prio = prio;
    thethread->cur_state = LWP_STATES_DORMANT;
    thethread->suspendcnt = 0;
    thethread->res_cnt = 0;

Let's pay attention to the is_preemtible variable, which is present in current's libogc and in RTEMS, but not in the old libogc: it was added later. Now, RTEMS has it since at least 1996, so, if libogc was actually copied from it, how come this variable was not copied, too, but added at a later time? Note, the accusation against libogc has been formulated in clear-cut terms: ...steal an open source RTOS and remove all attribution and copyright information...; it's clear that this is not what happened. It's much more likely that libogc's developers did look at RTEMS code (which at that time had another license and was known as the Real Time Executive for Missile Systems or Real Time Executive for Military Systems) as a model and source of information, but since the code was heavily adapted for libogc, they didn't feel they were creating a “derivative work”. It's a grey area, but even myself, if I took a project written in C++ and translated it into Rust or C#, for example, I'm rather sure I wouldn't consider my work to be a derivative of the original; I'm not a lawyer, so I might be plain wrong here, but I would be in good faith.

At most, libogc could be accused of plagiarism, but in my humble opinion even that would be a stretch: since we are not talking of some artistic work, but of work of science/ingeneering, it's normal to build upon others' work. Yes, credit should generally be given, but given that we are talking of a US military-related project, I can see that there could be ethical reasons for not wanting to do so.

Summing up

I'm consciously omitting the other old accusations about “stealing” Nintendo's code, first because they are not new, and secondly because I don't consider reverse-engineering as stealing. What I found most disturbing about this story is that it smells hatred from far away, since I have a hard time to understand why someone felt the need to look into libogc's origin and publicly smearing the project and ultimately harming the whole of the Wii homebrew community.