mailto: blog -at- heyrick -dot- eu

Yikes!

It's freezing.

Literally. It was -3.5°C this morning. It was supposed to be 8°C and rainy, but it's only made it to three and a half. And rainy. It's going to soon be time to feed kitty. Oh joy.

I did work outside a little around noon while waiting for the post. Even though it wasn't any warmer, it felt warm enough in the sun.

I have taken the laptop to the kitchen table, because it is a smaller room so I can close the doors and run the electric radiator as well as a lap warmer. On the worktop the old Panasonic bread maker that I got from a vide grenier is working its magic. The larger Lidl breadmaker doesn't seem quite so good when it's cold in here and since it's just over 9°C, I think that counts as cold enough to upset bread. Certainly I can here the heater element clicking on and off a lot more than the Lidl machine.

Of course, copious amounts of tea. ☺

I got out the box to have a few pieces of laughing cow (La Vache qui rit), a sort of squishy concoction like firm yoghurt that is trying to pass itself off as a type of cheese. It is quite moreish, so the box is now empty. I guess I ought to move on to Pringles or something.

I was going to make a cake, but I didn't feel like dealing with the icing. Bread, on the other hand, more or less looks after itself, doesn't it?

Later: The bread actually looks quite nice. I think I'm going to upload this, feed kitty, and then crawl into bed under the heated blanket with a big chunk of bread and a packet of crisps. I just discovered that I never got around to watching season two of The Uncanny Counter (a Korean series on Netflix, so...).

 

Getting that Lidl pocket printer working with Linux

Half a year ago, I got myself a little thermal printer from Lidl. It has an app which is... yeah... the app works, mostly. But it's a bit rubbish. And completely incapable of correctly printing multiple copies of something.

I tried with Bluetooth, I tried the cat-printer stuff, but whatever ID strings this thing uses are different so no go. I don't understand enough about what's going on inside to even have a clue about trying to fix this.

I decided to plug it into my USB port and see if anything showed up, or if it was just for charging.

[74945.532702] usb 1-4: New USB device found, idVendor=09c7, idProduct=0020, bcdDevice= 2.00
[74945.532749] usb 1-4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[74945.532771] usb 1-4: Product: Printer
[74945.532788] usb 1-4: Manufacturer: Printer
[74945.532803] usb 1-4: SerialNumber: 3DB9xxxxxx03
[74945.791241] usblp 1-4:1.0: usblp0: USB Bidirectional printer dev 4 if 0 alt 0
                        proto 2 vid 0x09C7 pid 0x0020
[74945.791901] usbcore: registered new interface driver usblp

Well that looks like something, doesn't it? Although it's an unknown vendor (I've not managed to find Vendor ID 9C7 online) and the device strings (1, 2, 3!) look quite suspect, it does identify itself as a printer. I could test by looking to see what device it offers, and pushing some data to it:

rick@Rick-E200HA:~$ ls /dev/usb
lp0
rick@Rick-E200HA:~$ echo "Testing, testing, 1, 2, 3..." > /dev/usb/lp0
bash: /dev/usb/lp0: Permission denied
rick@Rick-E200HA:~$ 

As you can see, you can't normally write directly to the printer device. Because this is Linux, not early Windows. ☺

I installed the printer via the printer manager and it recommended an Epson ESC/POS driver, which is sort of correct as this printer uses ESC/POS commands, but not quite the same commands it would seem. The test print printed some text that looked a bit like PostScript but had a visible string saying If you can read this, you are using the wrong driver for your printer. Thank you...

I looked online and came across something that looked promising at https://github.com/klirichek/zj-58, a driver for a generic thermal printer like the Zjiang ZJ-58 and other cheap thermal printers. The '58' is the paper width, 58mm. This is typically arranged as a 5mm left margin, then 48mm active print section with 384 active pixels, and a 5mm right margin.

The problem is that one can't just apt install this, it has to be built from source.

rick@Rick-E200HA:~$ cd ~Coding
rick@Rick-E200HA:~/Coding$ mkdir zj58
rick@Rick-E200HA:~/Coding$ cd zj58
rick@Rick-E200HA:~/Coding/zj58$ git clone https://github.com/klirichek/zj-58.git
Cloning into 'zj-58'...
remote: Enumerating objects: 118, done.
remote: Total 118 (delta 0), reused 0 (delta 0), pack-reused 118 (from 1)
Receiving objects: 100% (118/118), 59.69 KiB | 2.29 MiB/s, done.
Resolving deltas: 100% (66/66), done.
rick@Rick-E200HA:~/Coding/zj58$ cd zj-58
rick@Rick-E200HA:~/Coding/zj58/zj-58$ ls
CMakeLists.txt  LICENSE       README.md  zj80.ppd
install         rastertozj.c  zj58.ppd   zjdrv.drv
rick@Rick-E200HA:~/Coding/zj58/zj-58$ 

Now having sorted out the source, one must sort out the dependencies. You'll need the CUPS and CUPS-image development stuff (about 3MB), plus cmake (about 49MB) if you don't already have it.

rick@Rick-E200HA:~/Coding/zj58/zj-58$ sudo apt install libcups2-dev libcupsimage2-dev
...blah blah...
rick@Rick-E200HA:~/Coding/zj58/zj-58/build$ sudo apt install cmake
...blah blah...

Now with all of that sorted, one can get on and build the thing.

rick@Rick-E200HA:~/Coding/zj58/zj-58$ mkdir build && cd build && cmake ~/Coding/zj58/zj-58
...blah blah...
rick@Rick-E200HA:~/Coding/zj58/zj-58/build$ cmake --build .
...lots of blah blah in pretty colours...

And, finally, to install it into cups...

rick@Rick-E200HA:~/Coding/zj58/zj-58/build$ sudo make install
...blah blah...

 

Now I can install the printer. Open the printer manager and add a new printer. It'll be shown as "APRT-D1S" which if you click it, will say it is connected via USB.

Dialogue for installing a new printer
Installing it as a new printer.

Wait while it fails to find a suitable driver. Scroll to the bottom of the list and choose "Ziajiang" (spelled incorrectly, but whatever).

In the next window, pick ZJ-58. The numerical suffix is the paper width, and the Lidl printer uses 58mm paper.
In the window after that, you can ignore the cash drawer and cutter options, the printer has neither.

Give the printer useful names and descriptions, and when offered you can print a test page.

A thermal printer printing from Linux.
A result!

 

Of course, whether or not it actually works is highly variable. It will print some things. For other things, it will print a black rectangle and then printing will stop because...

rick@Rick-E200HA:~$ dmesg
...epic loads of gibberish...
[ 1072.960852] rastertozj[6288]: segfault at 650632c9e000 ip 00006506129f45e5
sp 00007fff9b12e070 error 4 in rastertozj[6506129f4000+1000]
likely on CPU 1 (core 1, socket 0)

But, it's a step further ahead. It can now do something with Linux, but given the unreliability and the tendency to print black and then crash (driver bug?), I won't be using it. But it was worth a try... ☺

 

For basic plain text output, and I mean plain as it doesn't seem to support any text styles or fonts, you can do something like:

rick@Rick-E200HA:~$ sudo chmod 0666 /dev/usb/lp0
rick@Rick-E200HA:~$ sudo echo -e "I can get 32 chars on a line....This will be
 on a new line. ;)  And so will this! \r\n\r\n" > /dev/usb/lp0

The echo line is only split here so it doesn't mess up the blog formatting too much. When run, this happens:

Simple data dump to a thermal printer.
Dumping raw data causes some output too.

I am doing chmod to the raw file because adding myself to the lp group doesn't work, and you may need to periodically redo the chmod. I suspect CUPS might be fiddling with things in the background.

 

Befuddlement

That's the best word I can come up with for the mess that is currently trying to pass itself off as the Labour Party. Where ideas are planned, then a swift U-turn when people get in a tizzy over it. The opposition yelling about them not keeping their election promises if they raise tax, as if the opposition kept all of their promises (for example: they failed to abolish no-fault evictions, it's the current Labour government doing that; not to mention promising to end homelessness only to turn around and label it "a lifestyle choice"; or that only 10 of the promised 40 new hospitals have planning permission).
Asides from the fallout from the budget later this week, though one should remember that Rachel from accounts has been repeatedly warning about the huge fiscal black hole left by the previous government, one that rankles me is the desire to push for a digital citizen ID despite the government (in general) having a really lousy record when it comes to privacy and data security.

Let me clarify - I am not against ID cards. In fact, I think a lot of Britain's problems could be solved by the introduction of ID cards and making them necessary to go to hospital (except emergency treatments), social services, and the like. What I am against is a digital ID card, a stupid app on a stupid phone. Because I don't fancy participating in the slow-motion train wreck that it will become.

France has various bit of government happily talking to other bits, and via FranceConnect your tax login can be used to authenticate you with the medical service. Stuff just works, and the little green Carte Vitale is your access key to the health service, good luck doing anything medical without it.
Meanwhile over in England, local councils are going broke because - in something that ought to be a national scandal if anybody was paying attention - they are throwing away tens of millions, often to a certain American database provider, for a custom ERP system just for them that is so poorly specified that it'll never be finished and/or working correctly. Like, excuse me, why does each council need their own expensive custom setup when they basically do the exact same things? Oh, "because we've always done it like this and we don't want to change". Easy enough to go along with that sort of logic when it's other people's money being wasted.
The NHS is currently planning to sell "anonymised" patient data in order to fund the NHS. It should be noted that "name and address stripped" does not equal anonymous if there are enough data points to tie that information to an individual in other ways, and there will be enough data points because who is going to pay good money for worthless data?

This is why I don't participate in certain online crowd-sourced services. A number of them say "to make you anonymous we'll mess up your location by five hundred metres". Cool, you can still identify me from that. Even better, if the location is randomised each time, you just need to collect enough location points for a given user profile and plot them all, the actual location will be somewhere in the middle - and again in my case that uniquely identifies me. You need to think about all sorts of things that can identify a person without needing a name and address. Those can be determined later by matching up with other sources.

So given these sorts of things, and we'll gloss over the Covid app because that would make blood boil, do you really trust the government to sensibly handle and manage the sort of information that a digital ID card would require?
Make an actual physical ID card, I'm on board with that. But a digital one? Get lost, trust is woefully lacking.

 

The day the United States capitulated

Sorry, but we on this side of the ocean should stop seeing the United States as a friend. While there are, without doubt, many lovely American citizens, the administration is not just incompetent but actually hostile.

Big news yesterday, or was it Thursday?, is that Trump has been having closed door negotiations with Putin over ending the conflict in Ukraine. Negotiations that would involve Ukraine surrendering portions of its territory, and also being barred from joining NATO.
In other words, more or less what Putin wants.

In even more other words, the United States has capitulated. By doing what's best for the attacker rather than the country that was attacked (who aren't even a party to these so-called negotiations), the administration has shown their true colours. They are not our friends.

It is high time Europe (which may or may not include the UK) start to take sovereignty seriously - both in terms of law and respect for it, data sovereignty and who has access to EU data, and military in order to defend ourselves.
This should be the wake-up call that while we can certainly interact and work with friendly countries around the world, we should not have any dependence on any of them, and certainly not to the point where our rules, proposals, and laws get watered down to appease a foreign power, where foreign corporations can do whatever the hell they like and at best they'll get a token wrist slap so as not to upset the country they are in. Excuse me, but who is running the EU? Brussels or Washington? That's not sovereignty, that's being a vassal state.

Yes, they are big and powerful and hold all the cards. But that's only because we're letting them. Time to rethink this strategy. Just as the United States itself is rethinking the wisdom of sending all of its tech to China to be manufactured, it's time we rethink the wisdom of putting all of our information in the hands of American companies subject to the Patriot Act; and Microsoft has admitted in a French court that they would break EU laws and hand over the data if asked because respecting EU laws would mean breaking US laws and that would cause far greater problems. Like I said, that's not sovereignty.

 

Mental hiccup

The Express newspaper is is recommending that people close their curtains at 4pm in order to help keep the heat in as fuel costs rise.

They said:

Energy bills increased again in October, and are now 46% higher than they were in 2021, thanks to a combination of Brexit, Covid and Russia's invasion of Ukraine, while energy giants post record profits.

It's nice to see somebody finally acknowledge that, yes, Brexit has had an impact. But shouldn't the bigger disconnect here be "bills increased again [...] energy giants post record profits"? Maybe the government ought to be doing something about that?

 

Translating Mamie

I found translating Mamie to run under the SDL on Linux to be, actually, surprisingly simple. Especially considering that I had never used the SDL before.

Because of how the game was written, I could replace the screen_initialise() function with all of the code required to set up the SDL system, create a window, and a renderer for that window.
I had originally aimed for a native HD screen of 1280×720, but it was slow to get going due to the mode change and it sometimes went black screen on exit (a fault of Linux on my machine, not SDL, as it sometimes does the same coming out of standby). So I patched in to use a window, and then discovered that I could just say "full screen at the native resolution" and the renderer will scale between what the game thinks the screen size is and what it actually is.
A little later on, I realised that these were just the exact same function with different flags, so I decided to pick up command line options to let the user choose. Scaled is the default as it's the quickest to get going.

There were some interesting differences, such as the font drawing.

void font_draw(font_handle handle, int x, int y, char *msg)
{
   // Draws the specified text at the given location

   SDL_Surface *textsurface;
   SDL_Texture *texttexture;
   SDL_Rect textrect;

   textsurface = TTF_RenderText_Blended( handle, msg, font_getcolour(handle) );

   texttexture = SDL_CreateTextureFromSurface( renderer, textsurface );

   SDL_QueryTexture( texttexture, NULL, NULL, &textrect.w, &textrect.h );

   textrect.x = x;
   textrect.y = SCREENHEIGHT - y - textrect.h - FONTFUDGE;
   
   SDL_RenderCopy( renderer, texttexture, NULL, &textrect );

   SDL_FreeSurface( textsurface );
   SDL_DestroyTexture( texttexture );

   return;
}

In order to understand what is going on, we have to first understand the meaning of surface and texture.
A surface is basically a bitmap. It has a defined value, like RGBA with eight bits per element, and you can faff around inside it if you need to. A RISC OS Sprite or a Windows BMP is a 'surface'.
A texture is an opaque equivalent that has been converted into whatever form is most suitable for splatting onto your display. This may be the same thing, or it might be some weirdo RGB-646 sixteen-bit nonsense. Whatever, it's not for you to know or fiddle with.

Whereas RISC OS handles this by plotting the raw sprites using translation tables, SDL maintains the two (sprite data and what-goes-on-the-screen) as separate entities. It does mean if the screen mode changes you'll probably have to rebuild all of the textures, but that sort of thing doesn't happen so much these days and it is probably faster than going through a translation layer each and every time.

The font is 'printed' to a sprite, with a full alpha transparency mask. This sprite is then translated into a texture for plotting on the screen. We then obtain the dimensions in order to sort out where and how to plot it, and then it gets copied to the renderer (think of that as a screen buffer). Finally the surface and texture memory can be released as we're done with them.

 

When it comes to handling the screen updates, under RISC OS triple buffering is used. Three buffers are maintained and we're drawing to, say, screen #3 while displaying screen #1.
Typically one would use double buffering, that is to say draw into one screen buffer while showing the other one, and when done drawing wait for the video sync and then switch buffers. Because of a quirk of how the Pi works and the fact that the video sync seen by RISC OS is fake, things work better with triple buffering.

None of this applies to SDL. In SDL, you draw to the renderer, and then you tell SDL to bash that to the window. As such, it was fairly easy to translate between RISC OS and SDL...

void screen_switchbank(void)
{
   // SDL handles this so we don't need to.
   // We'll just call out to selectshowbank to
   // sync the display.

   screen_selectshowbank(0);

   return;
}


void screen_selectdrawbank(int which)
{
   // Does nothing.

   return;
}


void screen_selectshowbank(int which)
{
   // Just sync the screen.

   SDL_RenderPresent( renderer );

   return;
}

 

There were three primary challenges.

  1. Handling "sprites".
    The code makes a huge amount of use of the RISC OS SpriteOp call, to draw sprites from a large spritefile. Indeed, the entire screen is built up of tiles which have things (candles, spiderwebs, ghosts...) overlaid.
    So it seemed to me that the best way to handle this would be to write a very simple sprite manager that can load in all the assets (a little over two hundred sprites) and plot them by name.
  2. Handling the difference between RISC OS and SDL.
    This was handled in two ways. The first was to make copies of the parts of the code that use system-specific things, such as the 'draw' and 'keys' files. One is aimed at Linux, the other for RISC OS. I would like to look at merging the two into one single file, but that's something for another day.
    Other source files that aren't split by OS, like 'lucy' or 'ghost', use #ifdef in order to choose at compile time if it should present RISC OS or Linux code. This is for when the differences are smaller.
    The second way was to make a 'linriscos' source which contains various functions - predominantly ones from DeskLib such as Time_Monotonic() and GFX_RectangleFill() - that provide the function names expected by the source and perform the expected actions.
  3. Keyboard handling.
    I don't have a lot of nice things to say about the RISC OS keyboard handling. It's a mess of dumb OS_Byte calls due to its heritage. Enjoy that sometimes getting back '255' means a key IS pressed and sometimes it means it is NOT pressed. Enjoy also that most calls deal with internal key codes while a few others will return the ASCII value of the key. Enjoy even more that there is no legal API to translate between the two. Duh.
    The approach I took with the Linux port is to maintain a bitmap for all of the keypresses of interest, and track the key press and key release events, setting the bitmap as appropriate. Then when I'm looking to see if a key is pressed, I translate the RISC OS internal key number provided into "oh, this means cursor up" and then I just return the remembered state of the cursor up key. That's partly why redefining the keys is not an option under Linux, and there are no plans to do so. Far too much code is based around how RISC OS does it, for obvious reasons.

Mamie game with tiles highlighted.
Development screen with the tiles highlighted.

There are still things outstanding, but most of these are little things. For instance, the help texts, scenario texts, and ending (win/lose) texts are all screenshots from RISC OS rather than being rendered under Linux. There is also, at this time, no game state saving so it isn't possible to "resume from level X" roughly where you left off. I expect these to come in time.

For now, the game core works and is playable, with sprites and animations and sounds - just like the RISC OS one. The 'aether' levels even have the 'fireflies' moving in the background.

 

It wasn't all plain sailing, however, as some things changed in dumb ways between SDL2 and SDL3. Search engines aim for SDL3 by default as it's the latest one.
I spent a minor eternity trying to work out why SDL_BlitScaled() was failing. It kept on returning 0 but appeared to be doing what was asked of it.
It turns out that in SDL3, that function returns either TRUE (it worked) or FALSE (it didn't). However when reading the SDL2 documents, the function returns either a negative failure code, or 0 if it worked.
Zero and FALSE are the same thing, so essentially this upgrade flipped what '0' being returned actually means. This is asinine and really kind of dumb, and I can't help but wonder how many subtle bugs are liable to be introduced due to changes like this that might not get caught when updating a program from SDL2 to SDL3. Are there other calls that I'm not using that invert what the returned values mean?

A bigger pitfall was my one brave tester couldn't get the program working on his machine. It kept failing due to a function (Mixer_SetVolume) not existing. I suggested that he check he has the latest version of the SDL_Mixer library installed. Well, he "sort of did". You see, it appears that libraries are tied rather implicitly to the operating system version for some reason. So his slightly older Linux (based on Ubuntu Jammy 22) has libsdl-mixer version 2.0.4 as the latest available. I need 2.6.x. My Mint, based upon Ubuntu Noble 24, has 2.8.1 available. In order to run my game he had to update his Linux. He had been meaning to so this was an excuse to do an in-situ update, but still, coming from a RISC OS background the idea that a roughly three year old version of Linux can't (and probably won't) be capable of installing the necessary libraries is a completely bizarre and alien concept. Mamie will work just fine on a ten-year-old Pi2, and probably with a ten-year-old version of RISC OS.
Under emulation, it may even work on a RiscPC, a thirty one year old machine; but it won't work on real hardware due to insufficient video memory and just generally being way too slow. Obviously, I don't own the sort of PC that would run an emulator at a useful speed so I have never tested it; but it uses 256 colour sprites and a 256 colour screen and as far as I'm aware there shouldn't be anything in there other than 3×HD720p and loads of sprites being plotted that would prevent it from working on such a machine.
Meanwhile, Linux, two and a half years old... shrug, not interested. Ummm....

 

Yesterday evening I made myself Patak's tikka sauce over Uncle Ben's rice and wholemeal pasta (what wouldn't fit in the jar I was refilling), along with some chicken nuggets.
My digestion has actually taken this quite well, it is perturbed rather than Die human scum!, but even so I think crisps and bread will be today's meal. I'll try to convince it that bread is really just an alternative interpretation of linguine and crisps are just flat cold chips. Maybe it'll be content with that? ☺

 

 

Your comments:

Please note that while I check this page every so often, I am not able to control what users write; therefore I disclaim all liability for unpleasant and/or infringing and/or defamatory material. Undesired content will be removed as soon as it is noticed. By leaving a comment, you agree not to post material that is illegal or in bad taste, and you should be aware that the time and your IP address are both recorded, should it be necessary to find out who you are. Oh, and don't bother trying to inline HTML. I'm not that stupid! ☺
As of February 2025, commenting is no longer available to UK residents, following the implementation of the vague and overly broad Online Safety Act. You must tick the box below to verify that you are not a UK resident, and you expressly agree if you are in fact a UK resident that you will indemnify me (Richard Murray), as well as the person maintaining my site (Rob O'Donnell), the hosting providers, and so on. It's a shitty law, complain to your MP.
It's not that I don't want to hear from my British friends, it's because your country makes stupid laws.

 
You can now follow comment additions with the comment RSS feed. This is distinct from the b.log RSS feed, so you can subscribe to one or both as you wish.

C Ferris, 22nd November 2025, 21:19
Fake News - Someone says 'Peace in our Time'
jgh, 23rd November 2025, 01:45
Gawd, when I was doing IT rollout within the NHS the number of different mini-printers and drivers I had to struggle with. A label printer for sample bottles, a label printer for medicine capsules, a printer for prescriptions, a printer for document labels, and of course a printer for normal A4 paper. You'd think maybe they could customise all their labels to print on the same sticky label stock, but no, every label has to be printed on its own specialist label tape with its own sized label printer. 
 
digs through installation notes.... shudder! memories come flooding back. Ah yes, the one that claims to be the default printer, then you have to un-default it. The one where the installation always fails, then you modify the registry. The one where you have to rename it to the exact name the software expects it to be called.... 
jgh, 23rd November 2025, 01:56
"I spent a minor eternity trying to work out why SDL_BlitScaled()" 
 
When I was first doing some updates for Brandy Basic and BBC BASIC for SDL I spent a minor eternity not realising the differences between SDL 1.2 and SDL 2.0, and not realising that it wasn't just a later version, but a fundamental redesign. Just when I'd got a build environment working with SDL1.2 I applied that knowledge to another project and everything would hit a brick wall. I fixed that and found I'd killed the earlier project. I finally managed to realise 1.2 and 2.0 are TWO COMPLETELY DIFFERENT SYSTEMS and worked out how to set up two different build environments. 
C Ferris, 23rd November 2025, 10:43
What's SDL?
Rick, 23rd November 2025, 12:59
SDL is Simple DirectMedia Layer, a library that takes the stress out of "doing stuff". 
https://www.libsdl.org/ 
Rob, 25th November 2025, 11:32
I was listening to Newscast last night, and one of the comments was that the US brokered deal had aspects of it being translated directly from Russian. Plus, it gave them everything, and Ukraine nothing. Trump really is looking like Putin's Puppet..

Add a comment (v0.12) [help?] . . . try the comment feed!
Your name
Your email (optional)
Validation Are you real? Please type 31923 backwards.
UK resident
Your comment
French flagSpanish flagJapanese flag
Calendar
«   November 2025   »
MonTueWedThuFriSatSun
     
34567
111213141516
17182021
242526272829

(Felicity? Marte? Find out!)

Last 5 entries

List all b.log entries

Return to the site index

Geekery
 
Alphabetical:

Search

Search Rick's b.log!

PS: Don't try to be clever.
It's a simple substring match.

Etc...

Last read at 14:53 on 2025/12/14.

QR code


Valid HTML 4.01 Transitional
Valid CSS
Valid RSS 2.0

 

© 2025 Rick Murray
This web page is licenced for your personal, private, non-commercial use only. No automated processing by advertising systems is permitted.
RIPA notice: No consent is given for interception of page transmission.

 

Have you noticed the watermarks on pictures?
Next entry - 2025/11/23
Return to top of page