João Costa shared 12 hours ago
João Costa shared 3 days ago

Working a bit more on Scala Native + Raspberry PI GPIO .

I have some code to:

  • Display arbitrary images to an OLED
  • Perform an action (e.g. change an image) when a button is pushed
  • Control a LED
  • Fetch data from an HTTP server (OK, this part is not yet working because I run out of RAM while compiling)

So, I have all the building blocks for a small project:

  • Periodically fetch notifications from a server
  • Turn the LED on when there are unread notifications
  • Show some details about the OLED screen
  • Clear the notifications with a button press

But, I just noticed that I don't have any concrete project like that in mind. 😐

It also doesn't help that the screen is tiny (128x64 and about the size of my thumb), so the amount of text I can show is a bit limited unless I use a font for ants. 😂

So I think I'll let things simmer for a bit until I figure out what to do with this.

I'm back from some two weeks in Mexico, so I can go back to playing with my Raspberry.

Got I2C communications to work and rendering to a SSD1306 with Scala Native.

I admit that I'm a bit confused about the coordinate system (and the way pixels are sent to the screen in vertical batches along the horizontal axis doesn't help), but it works, and I think if I play around with some initialization flags things should be more intuitive.

For now, I'm happy that it's working. 🙂

João Costa shared a month ago
João Costa shared a month ago

Got some Scala bindings for WiringPi thanks to SN-Bindgen (plus some manual adjustments)

https://gist.github.com/JD557/c81ad69f7506c70a5c26e9ddec24db27

Took me quite some time to get things to work... but at least I got a blinking LED today 😅 :

import wiringpi.all.*

println("Starting")
wiringPiSetup()

val led = 25

pinMode(led, OUTPUT)

while(true) {
  println("ON")
  digitalWrite(led, HIGH)
  Thread.sleep(1000)
  println("OFF")
  digitalWrite(led, LOW)
  Thread.sleep(1000)
}

I do need to figure out how to cross compile before I try something more complex... Scala Native compilation on a Raspberry Pi 3 B is SLOW! 😬

GIF

I've been flashing some Raspberry Pis recently and damn, this new Raspberry Pi Imager 2 (https://www.raspberrypi.com/news/a-new-raspberry-pi-imager/) is awesome.

Not only does the wizard includes a bunch of images (so no more searching for ISOs of common distros) it let's me configure credentials, SSH and Wi-Fi from the get go. That's a huge time saver for the initial setup. 🔥

João Costa shared a month ago
João Costa shared a month ago

I know that this is kind of creepy in the "being spied sense", but I kind of love how, after searching/buying any maker adjacent thing (e.g. 3d printer filament, smart home devices...), ad networks start treating me like the coolest guy ever. 😎

I buy a couple of small things and immediately start getting ads like:

  • "Buy this CNC mill!"
  • "What you need is a laser engraver. Perfect for all your projects!"
  • "Replace your soldering iron with our fully featured soldering kit!"
  • "Look at this pocket radiation detector/spectrometer!"
  • "Call us to print your PCBs!"

As if I had a huge workshop and my latest "big project" wasn't "adding a switch to a LED strip". 😅

João Costa shared a month ago
João Costa shared a month ago

This weekend I was playing a bit with displacement filters, with the help of https://www.smashingmagazine.com/2021/09/deep-dive-wonderful-world-svg-displacement-filtering/

It's actually not that hard to get some cool effects from this. However, it's a bit of a shame that nice distortions require some big gaussian blur kernel... I need to see if I can get similar effects by precomputing the blured images and just blending them with transparency.

GIF
João Costa shared 2 months ago
João Costa shared 3 months ago

I've been dusting off my PS2 lately - the DVD player was a goner a long time ago, but with the new PSBBN patches it's trivial to launch some of the old games from an SSD for that nostalgia hit.

One thing that I don't remember being as annoying is the lack of a "Quit" button in games and a "Shutdown" button in the main menu.

I remember finding it odd when the next generation of consoles added a home button (it's not a PC, why would you want to go back to the main menu?), but in hindsight, that's super helpful 😄 .

(I know that there's some homebrew to add a shutdown button to the main menu, but it's kind of useless if I need to reset the console to get back to it)

  • Want to stop playing? Get up!
  • Want to change games? Get up! (To be fair, back then you would have to do that anyway)
  • Want to load a different save file? Get up!
  • Want to change settings? Get up!

Scastie finally supports Scala 3 libraries with Scala.js.🔥

I was playing around with the idea of interactive-ish graphic tutorials: https://scastie.scala-lang.org/JD557/sXkQ2yQsSpqoQgXounejXQ/4

Playing around with Ordered Dithering and Bayer Matrices.

Interactive demo with multiple dithering sizes (2x2, 4x4, 8x8 and 16x16): https://joaocosta.eu/Demos/Dither/

This was much simpler than I thought. The whole dithering logic is just:

def buildBayerMatrix(n: Int): Vector[Vector[Int]] =
  if (n <= 1) Vector(Vector(0))
  else {
    val mn2 = buildBayerMatrix(n / 2) // M_(n/2)

    val q1 = mn2.map(_.map(_ * 4)) // 4*M_(n/2)
    val q2 = q1.map(_.map(_ + 2)) // 4*M_(n/2) + 2*J_(n/2)
    val q3 = q1.map(_.map(_ + 3)) // 4*M_(n/2) + 3*J_(n/2)
    val q4 = q1.map(_.map(_ + 1)) // 4*M_(n/2) + 1*J_(n/2)

    q1.zip(q2).map(_ ++ _) ++ q3.zip(q4).map(_ ++ _)
  }

def buildDitherSurface(n: Int): RamSurface = {
  val mask = buildBayerMatrix(n)
  val max  = n * n
  RamSurface(mask.map(_.map(x => Color.grayscale((x * 255) / max))))
}

def ditherImage(image: Surface, ditherMask: Surface): Surface =
  image.view.zipWith(
    ditherMask.view.repeating,
    (color, mask) =>
      Color(
        if (color.r >= mask.r) 255 else 0,
        if (color.g >= mask.g) 255 else 0,
        if (color.b >= mask.b) 255 else 0
      )
  )
Ordered Dithering Demo joaocosta.eu

More on updates.

This time I wrote an InterIm backend for AthenaEnv.

I also had to work a bit on InterIm's performance to get it to work, as I can't really use Doubles and my text layout algorithm was a bit inneficient. The frame rate still gets a bit choppy when there's a ton of text on screen, but it kind of works.

To test the whole thing, I ported my Quiz game example. This part was quite easy - just had to replace the HTTP calls with hard coded questions/answers and reimplement the RNG (I'm still not sure why scala.util.Random doesn't work... I suspect it's something related to Long math).

However, after testing this for so long on PCSX2, I was quite shocked on how bad things looked on real hardware. I know I'm using a crappy €20 HDMI converter instead of a propper upscaler, but god damn, the text is pretty much unreadable. 😬

Something to keep in mind in the future, I guess.