<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[My Random Adventures]]></title><description><![CDATA[I'm a dedicated software engineer with a passion for bringing hardware and software together to create robust solutions. I thrive on optimizing performance, and ensuring the reliability of devices.]]></description><link>https://blog.asankasovis.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1752905208799/9a7bf29d-6cc8-4dec-aa71-81396ae122da.png</url><title>My Random Adventures</title><link>https://blog.asankasovis.com</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 14 Aug 2026 13:12:32 GMT</lastBuildDate><atom:link href="https://blog.asankasovis.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[12.1. Pong - The Simplest Game to Implement]]></title><description><![CDATA[I recently got the idea to recreate the classic arcade game of Pong. Pong is a relatively simple game with little programming required to get it up and running. In this article, we will see how the co]]></description><link>https://blog.asankasovis.com/12-1-pong-the-simplest-game-to-implement</link><guid isPermaLink="true">https://blog.asankasovis.com/12-1-pong-the-simplest-game-to-implement</guid><category><![CDATA[Processing]]></category><category><![CDATA[pong]]></category><category><![CDATA[arcade]]></category><category><![CDATA[game]]></category><category><![CDATA[Game Development]]></category><category><![CDATA[#Game Design]]></category><category><![CDATA[ArcadeGameClone]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Tue, 30 Jun 2026 15:51:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/61a2243af0cb2e37690c63e1/f2e24808-5722-4e45-8756-cefdaf14a5fc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I recently got the idea to recreate the classic arcade game of Pong. Pong is a relatively simple game with little programming required to get it up and running. In this article, we will see how the code works.</p>
<p>As usual, we will start with the <code>setup()</code>. This is available in <code>Pong.pde</code>, the project's main file.</p>
<pre><code class="language-java">void setup() {
    size(1000, 600);
    frameRate(60);

    PFont font = loadFont("font.vlw");
    textFont(font);

    rectMode(CENTER);

    player_one = new Paddle("1", 100, height / 2, 0, height, 10, 100);
    player_two = new Paddle("2", width - 100, height / 2, 0, height, 10, 100);

    ball = new Ball(width / 2, height / 2, 10, 10, width, height);
    ball.reset();
}
</code></pre>
<p>This is pretty standard: Set the canvas size, frame rate, load fonts, set the rectangle mode and set up the objects for the players and ball. I have discussed loading the fonts in the previous article, so I will not go through it here. You can also refer to the <a href="https://github.com/asankaSovis/Pong">GitHub repo</a> for the instructions.</p>
<p>The font I chose was <code>Bitwise Font</code> by <em>Digital Graphics Labs</em>. You can find it at <a href="https://www.fontspace.com/bitwise-font-f5077">www.fontspace.com</a>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/61a2243af0cb2e37690c63e1/4e19c17e-8dcb-43f4-86ac-a7c2938e91e7.png" alt="Bitwise Font" style="display:block;margin:0 auto" />

<p>The <code>draw()</code> function is also quite simple.</p>
<pre><code class="language-java">void draw() {
    background(0);
    backgroundDraw();

    render();

    if (!pause) {
        update();
    }
}
</code></pre>
<p>We first draw a black background, draw the background items and then render the dynamic items. If we're not on pause, we also update the physics.</p>
<p>The <code>keyPressed()</code> function is also quite simple.</p>
<pre><code class="language-java">void keyPressed() {
    if (key == 'w') { player_one.up(); }
    if (key == 's') { player_one.dn(); }

    if (key == 'p') { player_two.up(); }
    if (key == 'l') { player_two.dn(); }

    if (key == 'r') { reset(); }

    if (key == ' ') {
        if ((player_one.score(0) &gt; over) || (player_two.score(0) &gt; over)) {
            reset();
        }

        pause = !pause;
    }
}
</code></pre>
<p>Pressing the keys <code>w</code> and <code>s</code> will move player one up and down. <code>p</code> and <code>l</code> for player two. <code>r</code> will reset the game, and the space will reset the game if either player has completed the scores, and pause either way. <code>mousePressed()</code> is also the same as pressing the space.</p>
<pre><code class="language-java">void mousePressed() {
    if ((player_one.score(0) &gt; over) || (player_two.score(0) &gt; over)) {
        reset();
    }

    pause = !pause;
}
</code></pre>
<p>Background draw is long, but it pretty much does some basic shape drawing as well.</p>
<pre><code class="language-java">void backgroundDraw() {
    fill(255);

    rect(width / 2, height / 2, 5, height);

    textAlign(CENTER, CENTER);
    textSize(32);

    text(player_one.score(0), 50, 100);
    text(player_two.score(0), width - 50, 100);

    if (pause) {
        if ((player_one.score(0) &gt; over) || (player_two.score(0) &gt; over)) {
            String p = "1";
            if (player_two.score(0) &gt; over) {
                p = "2";
            }

            text("GAME   OVER\n   PLAYER " + p + "      HAS  WON\n   CLICK OR PRESS   SPACE TO START", width / 2, 400);
        } else {
            text("PO  NG\n   CLICK OR PRESS   SPACE TO START", width / 2, 400);
        }
    }
}
</code></pre>
<p>The colour we use for drawing is white. We first draw a divider in the centre of the screen. Then we draw the scores of each player. If paused, we also draw some text on the screen. If either of the player has exceeded the winning score, we display the winner; if not, we show instructions to play the game.</p>
<p><code>reset()</code> and <code>render()</code> also perform similar functions.</p>
<pre><code class="language-java">void reset() {
    ball.reset();

    player_one.reset();
    player_two.reset();
}

void render() {
    ball.render();

    player_one.render();
    player_two.render();
}
</code></pre>
<p>We either reset or render the two players and ball.</p>
<p><code>update()</code> function handles all the physics.</p>
<pre><code class="language-java">void update() {
    if (frameCount % 2 == 0) {
        int upd = ball.update();

        if (upd &gt; 0) {
            if (upd == 1) { player_one.score(1); }
            if (upd == 2) { player_two.score(1); }

            if ((player_one.score(0) &gt; over) || (player_two.score(0) &gt; over)) {
                pause = true;
            }

            ball.reset();
        }
    }
}
</code></pre>
<p>Here, for every two frames, we perform a physics update. First, the ball is updated. It will return if either of the players scored. 0 means no score, and either 1 or 2 represents the player who scored. So, if we have a return greater than 0, we check if it's 1 or 2 and increase the score of the respective player. We also check if any of the players have reached the winning score and pause if so. We also reset the ball.</p>
<p>Now, we will move on to the next file: <code>Game.pde</code>. This has all the classes related to the ball and player.</p>
<p>The first one we will look at is the player: the <code>Paddle</code> class.</p>
<pre><code class="language-java">public class Paddle {
    private String id;

    private int start_x, start_y;

    private int x, y;

    private int width, height;

    private int up_x, dn_x;

    private int score = 0;

    private int SPEED = 10;
    
    public Paddle(String id, int x, int y, int up_x, int dn_x, int width, int height) {
        this.id = id;
        this.start_x = x; this.start_y = y;
        this.x = x; this.y = y;
        this.up_x = up_x; this.dn_x = dn_x;
        this.width = width; this.height = height;
    }

    public String id();
    
    public void render();

    public void reset();

    public void up();

    public void dn();

    public int score(int sc);
}
</code></pre>
<p>We have a few private variables that are quite simple. <code>id</code> holds a unique identifier for the player. <code>start_x</code> and <code>start_y</code> represent the initial positions of the paddle. <code>x</code> and <code>y</code> relate to where the paddle is now. <code>width</code> and <code>height</code> are the width and height of the paddle. <code>up_</code> and <code>dn_x</code> are the limits when moving the paddle up and down. <code>score</code> is the score of the player, and <code>SPEED</code> is the speed of the paddle. The constructor sets these up.</p>
<p><code>id()</code> returns the ID of the player.</p>
<pre><code class="language-java">public String id() {
    return id;
}
</code></pre>
<p><code>render()</code> renders the paddle.</p>
<pre><code class="language-java">public void render() {
    fill(255);
    rect(this.x, this.y, this.width, this.height);
}
</code></pre>
<p><code>reset()</code> resets the paddle to its initial position.</p>
<pre><code class="language-java">public void reset() {
    this.x = this.start_x; this.y = this.start_y;
    score = 0;
}
</code></pre>
<p><code>up()</code> and <code>dn()</code> move the paddle up or down by the <code>SPEED</code>.</p>
<pre><code class="language-java">public void up() {
    if (this.y &gt; up_x) {
        this.y -= SPEED;
    }
}

public void dn() {
    if (this.y &lt; dn_x) {
        this.y += SPEED;
    }
}
</code></pre>
<p><code>score()</code> will increase the score and return the current score.</p>
<pre><code class="language-java">public int score(int sc) {
    this.score += sc;

    return this.score;
}
</code></pre>
<p>The other class we have is the <code>Ball</code> class. This class will be used to create the ball object that will be rendered on the screen.</p>
<pre><code class="language-java">public class Ball {
    private int start_x, start_y;
    private int x, y;

    private int width, height;

    private int speed_x, speed_y;

    private int window_w, window_h;

    private int hits = 0;

    public Ball(int x, int y, int width, int height, int window_w, int window_h) {
        this.start_x = x; this.start_y = y;
        this.x = x; this.y = y;
        this.width = width; this.height = height;
        this.window_w = window_w; this.window_h = window_h;

        this.speed_x = 2 - (4 * round(random(0, 1))); this.speed_y = 2 - (4 * round(random(0, 1)));
    }

    public void reset();

    public void render();

    public int update();
}
</code></pre>
<p>The <code>start_x</code> and <code>start_y</code> variables hold the initial start position of the ball. <code>x</code> and <code>y</code> will hold the current position. <code>width</code> and <code>height</code> determine the size of the ball. <code>speed_x</code> and <code>speed_y</code> hold the current speed of the ball. <code>window_w</code> and <code>window_h</code> hold the total width and height of the screen. <code>hits</code> hold the number of hits the ball has with the paddles. The initialiser function handles setting up these variables. It also sets the speed to either direction randomly to create a sense of randomness when passing the ball.</p>
<p>The <code>reset()</code> function is also similar to the paddle. It just resets the position of the ball.</p>
<pre><code class="language-java">public void reset() {
    this.x = start_x; this.y = start_y;
}
</code></pre>
<p><code>render()</code> is also the same. It just resets the ball to the initial position.</p>
<pre><code class="language-java">public void render() {
    fill(255);
    rect(this.x, this.y, this.width, this.height);
}
</code></pre>
<p>The <code>update()</code> function performs the physics-related tasks.</p>
<pre><code class="language-java">public int update() {
    this.x += this.speed_x; this.y += this.speed_y;

    if ((this.y &lt;= this.height / 2) || (this.y &gt;= this.window_h - (this.height / 2))) {
        this.speed_y = -(this.speed_y);
    }

    if (((this.x &lt;= player_one.x) &amp;&amp; (this.y &gt;= (player_one.y - (player_one.height / 2))) &amp;&amp; (this.y &lt;= (player_one.y + (player_one.height / 2))))
    ||  ((this.x &gt;= player_two.x) &amp;&amp; (this.y &gt;= (player_two.y - (player_two.height / 2))) &amp;&amp; (this.y &lt;= (player_two.y + (player_two.height / 2))))) {
        int speed_offset = 0;
        int speed_max = 0;

        if (this.x &lt;= player_one.x) {
            speed_offset = this.y - player_one.y;
            speed_max = player_one.height / 2;
        } else {
            speed_offset = this.y - player_two.y;
            speed_max = player_two.height / 2;
        }

        this.speed_y = speed_offset * 5 / speed_max;
        this.speed_x = -(this.speed_x);
        hits++;

        if (hits % 4 == 0) {
            this.speed_x += (this.speed_x / abs(this.speed_x));

            if (this.speed_y == 0) {
                this.speed_y = 1 - (2 * round(random(0, 1)));
            }
        }
    } else {
        if (this.x &lt; player_one.x) {
            return 2;
        } else if (this.x &gt; player_two.x) {
            return 1;
        }
    }

    return 0;
}
</code></pre>
<p>The first thing this task does is move the ball at the speed. If the ball has reached the top or bottom of the screen, the speed in the y-axis is flipped to <em>simulate</em> a bounce. Next, it will check if the ball reached each of the paddle's x positions. If so, we check if we reached away from the paddle's surface. If so, we return the opposite paddle to which it reached the end to indicate a score for the opposing player. If not, we check in which region of the paddle we reached, and we update the y speed accordingly.</p>
<p>For example, if the ball reached the end of the paddle, the angle at which it reflects will be higher, and if it's in the middle, the ball will directly reflect. We will also oppose the x speed while also increasing the hit count. The reason why we keep track of the hits is that the classic arcade game used to increase the speed with every four hits. Here, we're doing the same thing.</p>
<p>This creates the classic arcade Pong game with almost similar mechanics.</p>
<img src="https://cdn.hashnode.com/uploads/covers/61a2243af0cb2e37690c63e1/4f4ced50-e1e1-4497-b7ec-aec69563d346.gif" alt="Pong" style="display:block;margin:0 auto" />

<p>The reason why I wanted to create this is that I have another idea I want to pursue with this project. I will post a follow-up article to this with the other ideas I have. Till then, enjoy... 👋</p>
<p>External Links:</p>
<ul>
<li><p>GitHub Repository with the Processing Code: <a href="https://github.com/asankaSovis/Pong">Github Repository</a></p>
</li>
<li><p>Wikipedia article on Pong: <a href="https://en.wikipedia.org/wiki/Pong">Pong</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[11. The Matrix - Enter into the Matrix]]></title><description><![CDATA[Do you ever wake up in the morning and think, 'I should make the digital rain effect from the Matrix franchise? Well, I did, and so here we go. For those of you who don't know, the Matrix franchise ha]]></description><link>https://blog.asankasovis.com/11-the-matrix-enter-into-the-matrix</link><guid isPermaLink="true">https://blog.asankasovis.com/11-the-matrix-enter-into-the-matrix</guid><category><![CDATA[Processing]]></category><category><![CDATA[Matrix]]></category><category><![CDATA[digital art]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Fri, 26 Jun 2026 11:05:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/61a2243af0cb2e37690c63e1/7fc4f906-ac93-4262-a427-f163f83f0b1b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Do you ever wake up in the morning and think, 'I should make the digital rain effect from the Matrix franchise? Well, I did, and so here we go. For those of you who don't know, the Matrix franchise had a well-known effect called the 'Digital Rain'. This effect features random sets of characters falling across a black terminal. Sort of like in <a href="https://youtu.be/ZIjfK4MGrGI?list=RDZIjfK4MGrGI">this video</a>. Let's see how to make an animation like this on Processing...</p>
<p>First step, of course, would be to find the correct font, obviously 😐. I checked several options, but the one that stood out for me was the font called <code>Matrix Code NFI Font</code> by <em>Norfok Incredible Font Design</em>. You can find it at <a href="https://www.fontspace.com/matrix-code-nfi-font-f11467">www.fontspace.com</a>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/61a2243af0cb2e37690c63e1/5006f6f8-324f-4b09-bf32-bbc824bb3e21.png" alt="" style="display:block;margin:0 auto" />

<p>I downloaded the font and converted it to be used in Processing. This is pretty straightforward. Just download the font, and you will get a zipped archive.</p>
<ol>
<li><p>Extract the archive, and you will see a font file called <code>MatrixCodeNfi-YPPj.otf</code> inside.</p>
</li>
<li><p>Double-click and install this font to the system.</p>
</li>
<li><p>Create a folder titled <code>data</code> in the root folder of our sketch.</p>
</li>
<li><p>Open the Processing application.</p>
</li>
<li><p>Go to <em>Tools</em> -&gt; <em>Create Font...</em>.</p>
</li>
<li><p>Scroll through the list of fonts and select the font we just installed. (<code>MatrixCodeNFI</code>)</p>
</li>
<li><p>Change the filename to <code>font.vlw</code>.</p>
</li>
<li><p>Click on <em>OK</em>.</p>
</li>
<li><p>A file called <code>font.vlw</code> will be created in the <code>data</code> directory. If it's created somewhere else, copy it to the <code>data</code> directory.</p>
</li>
</ol>
<p>Now that the fonts are ready, we will move on to the actual sketch. First, we'll start with some settings. Here, we will set up the canvas size, load the font, prepare the sizes and counts and create a copy of the charset.</p>
<pre><code class="language-java">void settings() {
  size(1800, 1000);
  font = loadFont("font.vlw");

  column_size = width/COLUMN_COUNT;
  row_size = column_size;
  row_count = ceil((height * 1.0) / row_size);
  text_size = column_size - (TEXT_OFFSET * 2);

  System.arraycopy(CHARACTER_SET, 0, characters, 0, CHARACTER_SET.length);
}
</code></pre>
<p>The column size is calculated with the width and number of columns we have defined to be included. I've also approximated the row size to be the column size. The number of rows is defined by the height and the size of the row that we're defined. Here, we take the ceiling to allow for an extra row below instead of keeping an empty row. This creates a seamless visual that spans the whole window.</p>
<p>I've also defined the <code>CHARACTER_SET</code> that will be used for text streaks. The set is as below.</p>
<pre><code class="language-java">char[] CHARACTER_SET = {
  '!',      '"',      '#',      '$',      '%',      '&amp;',      '\'',
  '(',      ')',      '*',      '+',      ',',      '-',      '.',      '/',
  '0',      '1',      '2',      '3',      '4',      '5',      '6',      '7',
  '8',      '9',      ':',      ';',      '&lt;',      '=',      '&gt;',      '?',
  'A',      'B',      'C',      'D',      'E',      'F',      'G',
  'H',      'I',      'J',      'K',      'L',      'M',      'N',      'O',
  'P',      'Q',      'R',      'S',      'T',      'U',      'V',      'W',
  'X',      'Y',      'Z',      '[',      '\\',     ']',      '^',      '_',
  'a',      'b',      'c',      'd',      'e',      'f',      'g',
  'h',      'i',      'j',      'k',      'l',      'm',      'n',      'o',
  'p',      'q',      'r',      's',      't',      'u',      'v',      'w',
  'x',      'y',      'z',      '{',      '|',      '}',      '~'
};
</code></pre>
<p>This is copied to a temporary buffer called <code>characters</code>. The reason is that we intend to inject <em>glitches</em> into the streaks, which will be apparent later. This makes sure the original list stays intact without worrying about losing characters. Of course, you can modify the original character set according to your requirements and font.</p>
<p>Next, we will move into the setup.</p>
<pre><code class="language-java">void setup() {
  background(BACKGROUND);
  frameRate(FRAMERATE);
  textFont(font);

  for (int i = 0; i &lt; (int)random(0, COLUMN_COUNT); i++) {
    buffer.add(new Streak((int)random(0, COLUMN_COUNT), (int)random(0, row_count)));
  }

  textSize(MESSAGE_SIZE);
  fill(STATIC);
  textAlign(CENTER);
  text(message, width/2, MESSAGE_Y);

  delay(MESSAGE_DELAY);
}
</code></pre>
<p>We set the background colour, set the frame rate, and set the text font. The hallmark feature of the digital rain animation is the streaks of characters that fall from the top of the screen. To define the behaviour of such a <em>streak</em>, we will define a class called a <code>Streak</code>. We will see how this works later. A critical feature is to have a buffer of such streaks to allow them to appear and disappear on the screen. To do this, we have a <code>buffer</code> variable that will hold the streaks that are visible on the screen at any given time. At the start, we will add a random number of <em>streaks</em> to the buffer at random x and y positions.</p>
<p>This is followed by the text size, defining a static font, aligning to the centre, and printing an initial message defined in <code>message</code> variable. This is followed by a delay. The message is as follows:</p>
<pre><code class="language-java">String message = "PRESS THE SPACE KEY TO EXIT THE MATRIX\nCLICK ANYWHERE TO GENERATE A GLITCH";
</code></pre>
<p>Before moving into the draw function, we will look at the <code>Streak</code> class. The structure is as follows:</p>
<pre><code class="language-java">public class Streak {
  private int x, y;
  private int cursor = (int)random(0, characters.length/2);
  private int lives = STREAK_LIVES;
  private int state = 0;
  private int floor = cursor;
  private int ceiling = (int)random(cursor + 1, characters.length);

  public Streak(int x, int y) {
    this.x = x; this.y = y;
  }

  public void draw();

  public boolean dead();

  private void draw_char(int j, color colour);
}
</code></pre>
<p>There are a few private variables defining the characteristics of the <em>streak</em>. The x, y coordinates, cursor position at the start, number of lives remaining, current state, floor and ceiling: which define the subset of characters from the main character set that are utilised in this streak.</p>
<p>I believe x and y are self-explanatory. Also, floor and ceiling. A streak has two main states: alive and dead. The alive state is when the streak is visible on the screen. Dead is when it disappears from the screen.</p>
<p>An alive streak will be in two main states: active and passive. The streak starts its life with the <code>cursor</code> at the first character of the sub-characters buffer. The <code>lives</code> will be at maximum and <code>state</code> will be 0. (alive) If you check the animation, a streak starts with nothing. Then one after the other, characters from the buffer appear one after the other until the end of its buffer is reached. The <code>cursor</code> is the last character displayed by the streak. Once it reaches the end of its buffer, the <code>cursor</code> is gone.</p>
<p>To emulate this, for each time the <code>draw()</code> function is called, we increase the <code>cursor</code>. When the end of the buffer is reached, we keep the <code>cursor</code> in place, but start decreasing the <code>lives</code>. This leaves the streak visible on the screen until the <code>lives</code> reach zero, at which point we change the <code>state</code> to 1. (dead) While the <code>cursor</code> is not at the <code>ceiling</code>, we draw the <em>cursor</em> or the last character currently visible on the buffer as white. The characters we print are from the <code>floor</code> to the <code>cursor</code> only. The rest of the visible characters are left as green. When the <code>ceiling</code> is reached, we display all characters as green. When dead, we do not print the characters.</p>
<p>You can see this behaviour in the following code snippet:</p>
<pre><code class="language-java">  public void draw() {
    if (this.state == 0) {
      if (this.cursor &gt;= this.ceiling) {
        draw_char(this.cursor - 1, STATIC);
        this.lives--;

        if (this.lives &lt;= 0) {
          this.state = 1;
        }
      } else {
        draw_char(this.cursor, CURSOR);
        this.cursor++;
      }

      for (int j = this.floor; j &lt; this.cursor - 1; j++) {
        draw_char(j, STATIC);
      }
    }
  }
</code></pre>
<p>The <code>dead()</code> function is simply there to return whether the streak is dead or alive.</p>
<pre><code class="language-java">  public boolean dead() {
    return (this.state == 1);
  }
</code></pre>
<p>The <code>draw_char()</code> function draws the characters to the screen according to the logic we discussed under <code>draw()</code>.</p>
<pre><code class="language-java">  private void draw_char(int j, color colour) {
    textSize(text_size);
    fill(colour);
    textAlign(CENTER);

    if (this.y + j &gt;= row_count) {
      text(characters[j], (this.x * column_size) + (column_size / 2), (this.y + 1 + j - this.floor - row_count) * row_size);
    } else {
      text(characters[j], (this.x * column_size) + (column_size / 2), (this.y + 1 + j - this.floor) * row_size);
    }
  }
</code></pre>
<p>Now that we understand how the <em>streaks</em> work, we will move into one of the most critical functions of the code. The <code>glitch()</code> function.</p>
<pre><code class="language-java">void glitch() {
  for (int i = 0; i &lt; character_glitch.length; i++) {
    if (character_glitch[i]) {
      characters[i] = CHARACTER_SET[(int)random(0, CHARACTER_SET.length)];
    }
  }

  if ((int)random(0, GLITCH_ENTROPY) == 4) {
    int pos = (int)random(0, character_glitch.length);
    character_glitch[pos] = !character_glitch[pos];
  }
}
</code></pre>
<p>The purpose of this function is to introduce <em>glitches</em> into the streaks. Remember we discussed that we need a separate copy of the original charset. This is why. We have a separate array which defines if each char in the charset is glitched.</p>
<pre><code class="language-java">char[] characters = new char[CHARACTER_SET.length];
boolean[] character_glitch = new boolean[characters.length];
</code></pre>
<p>What we do in the <code>glitch()</code> function is, we first go through each char of the <code>characters</code>. We check if the corresponding <code>character_glitch</code> is enabled or not. If a glitch is enabled, we <em>glitch</em> that specific character. IE, we pick a random character from the <code>CHARACTER_SET</code> and replace this character with that.</p>
<p>Next, we randomly pick some characters from the <code>character_glitch</code> and flip their state: stable or glitched. This is what creates the iconic <strong>glitching</strong> effect of the streaks.</p>
<p>Since each streak in the buffer is tied to the <code>characters</code>, when a glitch is introduced, this is visible across all streaks.</p>
<p>Next, we will move on to the <code>draw()</code> function. This is pretty straightforward.</p>
<pre><code class="language-java">void draw() {
  fill(BACKGROUND &gt;&gt; 16 &amp; 0xFF, BACKGROUND &gt;&gt; 8 &amp; 0xFF, BACKGROUND &amp; 0xFF, FADE);
  rect(0, 0, width, height);

  if ((random(0, 10) &lt; STREAK_ENTROPY) &amp;&amp; (matrix)) {
    buffer.add(new Streak((int)random(0, COLUMN_COUNT), (int)random(0, row_count)));
  }

  for (int i = 0; i &lt; buffer.size(); i++) {
    Streak streak = buffer.get(i);

    if (streak.dead()) {
      buffer.remove(i);
      i--;
    } else {
      streak.draw();
    }
  }

  glitch();
  
  drawTopic();
}
</code></pre>
<p>We first fill the screen with black accompanied by an alpha value. This allows the dead streaks to fade away smoothly. We also make sure to add some new streaks to the buffer to replenish any that have gone dead. Then for each streak, we remove it from the buffer if it's dead, and <code>draw()</code> it if it's alive. Then we introduce the <code>glitch()</code>.</p>
<p>We also draw the topic using the <code>drawTopic()</code> function.</p>
<pre><code class="language-java">void drawTopic() {
  String topic_str = "";
  for (int i = 0; i &lt; topic.length; i++) {
    topic_str += characters[topic[i]];
  }

  fill(0, 0, 0, TOPIC_FADE);
  rect(0, (TOPIC_Y / 2) + 5, width, TOPIC_SIZE);

  textSize(TOPIC_SIZE);
  fill(STATIC);
  textAlign(CENTER);
  text(topic_str, width/2, TOPIC_Y);
}
</code></pre>
<p>Notice how the topic is described by the position of each character of the text <strong>THE_MATRIX</strong>.</p>
<pre><code class="language-java">int[] topic = {50, 38, 35, 61, 43, 31, 50, 48, 39, 54};
</code></pre>
<p>When displaying, the text is reconstructed using the <code>characters</code>. This introduces the glitching effect to the topic too.</p>
<p>That is pretty much the guts of this demo. We also have two supporting functions.</p>
<pre><code class="language-java">void keyPressed() {
  if (key == PAUSE_KEY) {
    matrix = !matrix;
  }
}
</code></pre>
<p>Here, when the space bar is pressed, the matrix effect is paused; essentially stops spawning new streaks in the buffer. And vice versa if pressed again.</p>
<pre><code class="language-java">void mouseClicked() {
  int x = (mouseX * COLUMN_COUNT) / width;
  int y = (mouseY * row_count) / height;

  fill(STATIC);
  rect(x * column_size, y * row_size, column_size, row_size, 5);

  buffer.add(new Streak(x, y));
}
</code></pre>
<p>Also, when the mouse is clicked on the screen, using the x and y coordinates of the cursor, a new streak is created in that specific location.</p>
<img src="https://cdn.hashnode.com/uploads/covers/61a2243af0cb2e37690c63e1/0971b9d0-b1e2-4b4c-9f3c-b940898688f0.gif" alt="Matrix animation" style="display:block;margin:0 auto" />

<p>Combined, this simple code creates an amazing and sophisticated visual effect created for the movie screen. You can tweak some of the parameters to see how that affects the animation.</p>
<p>External Links:</p>
<ul>
<li><p>GitHub Repository with the Processing Code: <a href="https://github.com/asankaSovis/Matrix">Github Repository</a></p>
</li>
<li><p>Wikipedia article on Digital Rain: <a href="https://en.wikipedia.org/wiki/Digital_rain">Digital Rain</a></p>
</li>
<li><p>Reference animation: <a href="https://youtu.be/ZIjfK4MGrGI?list=RDZIjfK4MGrGI">YouTube</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How to do Better Logging]]></title><description><![CDATA[When you're working on Embedded firmware or low level development, it's important to have a proper logging system in place. Logging helps with debugging, tracking values and monitoring the system for ]]></description><link>https://blog.asankasovis.com/how-to-do-better-logging</link><guid isPermaLink="true">https://blog.asankasovis.com/how-to-do-better-logging</guid><category><![CDATA[C]]></category><category><![CDATA[C++]]></category><category><![CDATA[printf]]></category><category><![CDATA[logging]]></category><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Programming Tips]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Fri, 27 Feb 2026 04:24:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/61a2243af0cb2e37690c63e1/d3d49fab-6d1b-4fab-96d4-89d4496e0021.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When you're working on Embedded firmware or low level development, it's important to have a proper logging system in place. Logging helps with debugging, tracking values and monitoring the system for the health. But there are situations where we need to disable all logs; let's say for a release or for performance benchmarking.</p>
<p>What easily comes to mind is to comment out all the <code>printf</code> statements and recompiling. But, imagine a codebase with hundreds of thousands of logs. It will get quite tedious to get rid of all the logs, and it's also easy to miss some.</p>
<p>Another option would be to wrap all <code>printf</code> statements with an <code>ifdef</code>. For example:</p>
<pre><code class="language-c">#include &lt;stdio.h&gt;

#define DEBUG

int main() {
#ifdef DEBUG
    printf("Hello...");
#endif
}
</code></pre>
<p>If <code>DEBUG</code> is defined, <code>printf</code> will be there and when it's not, the <code>printf</code> will not be there in the final compiled binary.</p>
<p>But this is also quite inefficient. Imagine having to write three lines instead of one for a simple print statement, not to mention the complication of a trivial task like printing a message. The reason that I'm telling this is that there's a better option.</p>
<p>What if instead of directly using <code>printf</code>, we create a macro to transform it into some other form, but then we use another macro to select which form that we're using? This is exactly where the optimum way to do logging lies. Here's a sample code:</p>
<pre><code class="language-c">#include &lt;stdio.h&gt;

#define DEBUG 1

#if DEBUG
    #define LOG(fmt, ...) printf(fmt "\n", ##__VA_ARGS__)
#else
    #define LOG(fmt, ...) 
#endif

int main() {
    int connection_count = 5;
    
    LOG("Server started successfully.");
    LOG("Current connections: %d", connection_count);

    return 0;
}
</code></pre>
<p>Notice how there's an <code>if</code> macro which chooses between two forms for a function we define as <code>LOG(fmt, ...)</code>. In case <code>DEBUG</code> is <code>1</code>, it automatically turns into <code>printf(fmt "\n", ##__VA_ARGS__)</code>, the <code>printf</code> we know and love. But if it's <code>0</code>, it turns into nothing. This creates a simple, efficient and clean way to enable and disable logs. You just have to write <code>LOG(...)</code> like you're used to and then define <code>DEBUG</code> as <code>1</code> or <code>0</code> to enable or disable the logging.</p>
<p>The keen eyed among you might worry if this might end up with unwanted instructions in your code. The thing is, modern compilers will happily compile this code without any overhead. Still don't believe me? Checkout this sample code in <a href="https://godbolt.org/">Compiler Explorer</a>: <a href="https://godbolt.org/z/3c4qfvM3E">https://godbolt.org/z/3c4qfvM3E</a>.</p>
<p>The assembly for the case of <code>DEBUG</code> is <code>1</code> turns out to be:</p>
<pre><code class="language-c">.LC0:
        .string "Server started successfully."
.LC1:
        .string "Current connections: %d\n"
main:
        sub     rsp, 8
        mov     edi, OFFSET FLAT:.LC0
        call    puts
        mov     esi, 5
        mov     edi, OFFSET FLAT:.LC1
        xor     eax, eax
        call    printf
        xor     eax, eax
        add     rsp, 8
        ret
</code></pre>
<p>Try turning <code>DEBUG</code> to <code>0</code> and see the compilation. It will turn out to be:</p>
<pre><code class="language-c">main:
        xor     eax, eax
        ret
</code></pre>
<p>As you can see, the whole logging statements disappeared without any residual code.</p>
<p>Thus, we can see that this eliminates all the issues we had with the previous two methods. In fact most modern code uses this technique for logging. So make sure to use this in your next project.</p>
]]></content:encoded></item><item><title><![CDATA[The C Runtime?]]></title><description><![CDATA[I always thought that when we compile a C code, it ‘just works’. No other fancy code runs to make our code function, like in the case for Java and Python. But turns out, it’s not exactly true. There are some work that happens behind the scenes when w...]]></description><link>https://blog.asankasovis.com/the-c-runtime</link><guid isPermaLink="true">https://blog.asankasovis.com/the-c-runtime</guid><category><![CDATA[C]]></category><category><![CDATA[C++]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Fri, 13 Feb 2026 14:02:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1770991234992/ca38fd27-95af-4b59-832d-3f18585434ce.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I always thought that when we compile a C code, it <em>‘just works’</em>. No other fancy code runs to make our code function, like in the case for Java and Python. But turns out, it’s not <em>exactly</em> true. There are some work that happens behind the scenes when we run a binary written in C.</p>
<p>This code is called the <strong>C Runtime (CRT)</strong>, but don’t confuse this with the Java Runtime Environment (JRE) or the Python Runtime Environment (PRE). Unlike Java and Python code, C code directly runs on the bare-metal, but there does exist some work that needs to be done before, while and after our code runs. This is handled by the C Runtime. Let’s dive a bit deeper…</p>
<p>The CRT consists of four main components:</p>
<ul>
<li><p><strong>Startup Sequence:</strong> Before our <code>main()</code> function even runs, the CRT performs initialization. It sets up the stack, initializes global variables, and gathers command-line arguments.</p>
</li>
<li><p><strong>Memory Management:</strong> It provides the logic for functions like <code>malloc()</code> and <code>free()</code>, managing the "Heap" memory, so our program can request space dynamically.</p>
</li>
<li><p><strong>Standard Library (<em>libc</em>):</strong> This is the bulk of the CRT. It includes the math functions, string manipulation tools, and input/output handlers (like <code>printf()</code> and <code>scanf()</code>).</p>
</li>
<li><p><strong>The Stack and Heap:</strong> The CRT manages the memory layout. The Stack handles local variables and function calls, while the Heap handles dynamic data.</p>
</li>
</ul>
<p>Let’s dive a little bit deeper into these four tasks of the CRT.</p>
<h1 id="heading-the-startup-sequence-the-c-bootstrap">The Startup Sequence (The "C Bootstrap")</h1>
<p>When we click "Run," the Operating System doesn't jump straight to our <code>int main()</code>. It jumps to an entry point provided by the CRT (often called <code>_start</code> or <code>mainCRTStartup</code>).</p>
<ul>
<li><p><strong>Setting the Environment:</strong> The CRT retrieves the Environment Variables (like <em>PATH</em>) and the Command Line Arguments from the OS. It parses them into the <code>argc</code> and <code>argv</code> parameters we see in <code>main()</code>.</p>
</li>
<li><p><strong>Initialization of Statics:</strong> It clears the BSS segment (setting un-initialized global variables to zero) and copies initial values into the Data segment for variables like <code>int x = 10;</code>.</p>
</li>
<li><p><strong>Constructors:</strong> In C++ (or C with specific compiler extensions), the CRT calls "global constructors" before main starts.</p>
</li>
<li><p><strong>The Handshake:</strong> Finally, it calls <code>main()</code>. When <code>main()</code> finishes, the CRT takes the return value (e.g., 0) and passes it back to the OS via an <code>exit()</code> system call.</p>
</li>
</ul>
<h1 id="heading-memory-management-malloc-and-free">Memory Management (<code>malloc</code> and <code>free</code>)</h1>
<p>The Operating System is strict; it only gives memory to programs in large "pages" (usually 4KB). If we only need 20 bytes, asking the OS directly is incredibly slow and wasteful.</p>
<ul>
<li><p><strong>The Middleman:</strong> The CRT maintains a "pool" of memory. When we call <code>malloc(20)</code>, the CRT looks at its pool, carves out 20 bytes, marks them as "in use," and gives you the pointer.</p>
</li>
<li><p><strong>Bookkeeping:</strong> The CRT keeps a hidden header just before our pointer that stores the size of the block. This is how <code>free()</code> knows exactly how much memory to release without us telling it the size.</p>
</li>
<li><p><strong>Heap Expansion:</strong> If the CRT runs out of memory in its pool, it issues a system call (like <code>sbrk</code> on Linux or <code>VirtualAlloc</code> on Windows) to ask the OS for another big chunk of RAM.</p>
</li>
</ul>
<h1 id="heading-the-stack-vs-the-heap">The Stack vs. The Heap</h1>
<p>These are the two primary ways a program uses RAM, and the CRT (along with the CPU) manages the boundary between them.</p>
<ul>
<li><p><strong>The Stack:</strong> Every time we call a function, the CRT pushes a "Frame" onto the stack. This frame holds our local variables and the "return address" (where to go when the function ends).</p>
</li>
<li><p><strong>The Heap:</strong> The "pile" of memory used for data that needs to live a long time or is too big for the stack (like a high-resolution image).</p>
</li>
</ul>
<h1 id="heading-the-standard-library-libc">The Standard Library (<code>libc</code>)</h1>
<p>This is the "toolbox" of C. It is a collection of pre-compiled code that performs common tasks that would be hard to write from scratch.</p>
<ul>
<li><p><strong>System Call Wrappers:</strong> Functions like <code>printf()</code> or <code>fopen()</code> are wrappers. They take our high-level request, format it, and then perform a System Call to ask the OS kernel to actually write pixels to a screen or bits to a disk.</p>
</li>
<li><p><strong>Portability Layer:</strong> <code>libc</code> is the reason our code can run on both Windows and Linux. On Windows, <code>printf()</code> might call <code>WriteFile</code>, while on Linux, it calls <code>write</code>. We don't have to care; the CRT handles the translation.</p>
</li>
<li><p><strong>Utility Functions:</strong> These are pure logic. Things like <code>sqrt()</code>, <code>strlen()</code>, or <code>sort()</code>. They don't talk to the OS; they just provide optimized algorithms so we don't have to reinvent the wheel.</p>
</li>
</ul>
<h1 id="heading-the-code">The Code</h1>
<p>Curious as to how these are managed? Checkout the <a target="_blank" href="https://github.com/bminor/glibc/tree/master">glibc repository</a> to see these components in action. The <code>_start</code> code is under <code>sysdeps/x86_64/start.S</code>. This is in Assembly to facilitate the required low-level work. The memory allocation logic is under <code>malloc/malloc.c</code>. This is quite a complicated bit of code.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>So what did we learn? Even C is not about compile and run. There’s a lot more happening under the hood than what we’re doing ourselves. It’s quite interesting how far these tools have come. So next time you write a new <code>main()</code>, think of all the work happening under the hood that keeps your code running correctly.</p>
]]></content:encoded></item><item><title><![CDATA[Are Switch Statements Better than If-else?]]></title><description><![CDATA[Ever heard tech bros say, ‘switch statements are more efficient than if-else statements’? I certainly have. But have you thought of whether this is actually true? Well, is it actually true? The answer is that ‘it’s complicated!’ Let’s discuss.
While ...]]></description><link>https://blog.asankasovis.com/are-switch-statements-better-than-if-else</link><guid isPermaLink="true">https://blog.asankasovis.com/are-switch-statements-better-than-if-else</guid><category><![CDATA[C]]></category><category><![CDATA[C++]]></category><category><![CDATA[compiler]]></category><category><![CDATA[Computer Science]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Fri, 23 Jan 2026 09:01:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769158778749/52f1e08a-b568-4c47-a299-414f2dac663c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ever heard tech bros say, ‘switch statements are more efficient than if-else statements’? I certainly have. But have you thought of whether this is actually true? Well, is it actually true? The answer is that ‘it’s complicated!’ Let’s discuss.</p>
<p>While this statement has a good technical value to it, this is not always the case. Switch statements are highly optimized and can outperform regular if-else statements under specific conditions. Let’s start with the basics: what is a switch statement?</p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">use_if_else</span><span class="hljs-params">(<span class="hljs-keyword">int</span> value)</span> </span>{
    <span class="hljs-keyword">if</span> (value == <span class="hljs-number">1</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-number">102</span>;
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (value == <span class="hljs-number">2</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-number">15</span>;
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (value == <span class="hljs-number">3</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-number">888</span>;
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (value == <span class="hljs-number">4</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-number">42</span>;
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (value == <span class="hljs-number">5</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-number">7</span>;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    }
}
</code></pre>
<p>You might be familiar with the above code. This is a simple example of an if-else statement. But a switch statement for the same task looks like this:</p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">use_switch</span><span class="hljs-params">(<span class="hljs-keyword">int</span> value)</span> </span>{
    <span class="hljs-keyword">switch</span> (value) {
        <span class="hljs-keyword">case</span> <span class="hljs-number">1</span>:
            <span class="hljs-keyword">return</span> <span class="hljs-number">102</span>;
        <span class="hljs-keyword">case</span> <span class="hljs-number">2</span>:
            <span class="hljs-keyword">return</span> <span class="hljs-number">15</span>;
        <span class="hljs-keyword">case</span> <span class="hljs-number">3</span>:
            <span class="hljs-keyword">return</span> <span class="hljs-number">888</span>;
        <span class="hljs-keyword">case</span> <span class="hljs-number">4</span>:
            <span class="hljs-keyword">return</span> <span class="hljs-number">42</span>;
        <span class="hljs-keyword">case</span> <span class="hljs-number">5</span>:
            <span class="hljs-keyword">return</span> <span class="hljs-number">7</span>;
        <span class="hljs-keyword">default</span>:
            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    }
}
</code></pre>
<p>But how can this be more efficient than an if-else statement? The answer is actually in the underlying assembly interpretation. Let’s compare the compiled assembly representation of the two functions.</p>
<pre><code class="lang-c">use_if_else:
        cmp     edi, <span class="hljs-number">1</span>
        je      .L3
        cmp     edi, <span class="hljs-number">2</span>
        je      .L4
        cmp     edi, <span class="hljs-number">3</span>
        je      .L5
        cmp     edi, <span class="hljs-number">4</span>
        je      .L6
        cmp     edi, <span class="hljs-number">5</span>
        mov     eax, <span class="hljs-number">0</span>
        mov     edx, <span class="hljs-number">7</span>
        cmove   eax, edx
        ret
.L3:
        mov     eax, <span class="hljs-number">102</span>
        ret
.L4:
        mov     eax, <span class="hljs-number">15</span>
        ret
.L5:
        mov     eax, <span class="hljs-number">888</span>
        ret
.L6:
        mov     eax, <span class="hljs-number">42</span>
        ret
</code></pre>
<p>This is how the compiled Assembly looks like for the if-else code. Below is for the switch statement. You can see it in compiler explorer: <a target="_blank" href="https://godbolt.org/z/K9MzEjK77">https://godbolt.org/z/K9MzEjK77</a></p>
<pre><code class="lang-c">use_switch:
        cmp     edi, <span class="hljs-number">5</span>
        ja      .L2
        mov     edi, edi
        jmp     [QWORD PTR .L4[<span class="hljs-number">0</span>+rdi*<span class="hljs-number">8</span>]]
.L4:
        .quad   .L2
        .quad   .L8
        .quad   .L9
        .quad   .L6
        .quad   .L5
        .quad   .L3
.L8:
        mov     eax, <span class="hljs-number">102</span>
        ret
.L6:
        mov     eax, <span class="hljs-number">888</span>
        ret
.L5:
        mov     eax, <span class="hljs-number">42</span>
        ret
.L3:
        mov     eax, <span class="hljs-number">7</span>
        ret
.L2:
        mov     eax, <span class="hljs-number">0</span>
        ret
.L9:
        mov     eax, <span class="hljs-number">15</span>
        ret
</code></pre>
<p>As we can see, the two codes produce completely different Assembly code. But still, both of them seem to be close to the same length. How can one be more optimized than the other? It’s all about how the code is executed. Imagine the scenario of receiving <code>value = 5</code> in the if-else statement. It has to go through all the <code>cmp</code> and <code>jmp</code> instructions before we reach the <code>value = 5</code> situation. But in case of the switch statement, it multiplies the value of <code>value</code> with 8, (because each address in the table is 8 bytes long) and jump that amount forward. Which lands us immediately at the <code>mov</code> and <code>ret</code> commands for the value of <code>7</code>. This is called a <strong>‘Jump Table’</strong>.</p>
<p>So, while the if-else statement was looking one after the other for the condition of <code>value = 5</code>, the switch statement <em>mathematically</em> moved execution to the <strong>5th</strong> instruction. See below for a simplified breakdown.</p>
<pre><code class="lang-plaintext">if-else:
is 1 = 5? --&gt; no, then is 2 = 5? --&gt; no, then is 3 = 5? --&gt; no, then is 4 = 5 no, then is 5 = 5, yes, then return 7
</code></pre>
<pre><code class="lang-plaintext">switch:
move 5 steps below --&gt; return the value there
</code></pre>
<p>Now imagine hundreds of possible <code>value</code>s. The execution time saved can be staggering. For those of you curious, the if-else statement gave us <em>O(n)</em> and the switch statement gave us <em>O(1)</em>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769157779874/b2b929d1-74be-47fe-8347-ff44d136a3e9.png" alt class="image--center mx-auto" /></p>
<p>However, this is not always the case. If the conditions don’t follow a mathematical pattern, this falls apart and we don’t see much difference.</p>
<p>However, if you paid close attention, you see that I used a compiler flag called <code>-fno-jump-tables</code> in the if-else statement. This is because modern compilers are smart to identify the existence of a jump table, even in an if-else statement.</p>
<p>But, does this mean that it’s not useful to use a switch statement instead of the if-else? Well, not exactly. The switch statement is a lot more elegant in certain code patterns. Also, sometimes the compiler might not be able to identify the pattern and be able to optimize an if-else statement unless you use a switch statement.</p>
<p>In conclusion, switch statements are awesome! But still, with modern smart compilers, it is not always the case that if-else statements are bad. So next time you use an if-else statement for checking an integer, maybe consider using a switch statement.</p>
]]></content:encoded></item><item><title><![CDATA[Fixing the Issue of Failing to Flash Devices Using Arduino on Ubuntu]]></title><description><![CDATA[I recently came across an issue where Arduino, installed under Ubuntu, refused to upload to my ESP32 device stating that ‘/dev/ttyUSB0 is not available or accessible’. This might sound absurd, and after digging into this issue a bit, I think I found ...]]></description><link>https://blog.asankasovis.com/fixing-the-issue-of-failing-to-flash-devices-using-arduino-on-ubuntu</link><guid isPermaLink="true">https://blog.asankasovis.com/fixing-the-issue-of-failing-to-flash-devices-using-arduino-on-ubuntu</guid><category><![CDATA[Ubuntu]]></category><category><![CDATA[arduino]]></category><category><![CDATA[ESP32]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Mon, 01 Sep 2025 16:09:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1756742829794/93f84367-57f1-44a0-ac12-ca758d4018d2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I recently came across an issue where Arduino, installed under Ubuntu, refused to upload to my ESP32 device stating that ‘<em>/dev/ttyUSB0 is not available or accessible’</em>. This might sound absurd, and after digging into this issue a bit, I think I found the issue. This is a security feature implemented by modern Ubuntu. But, the usual suggestion of adding the current user to the <code>dialout</code> user group didn’t work.</p>
<pre><code class="lang-bash">sudo usermod -a -G dialout <span class="hljs-variable">$USER</span>
</code></pre>
<p>This might be a new security feature but, I will give a few pointers on how to actually setup Arduino on your Ubuntu machine.</p>
<h1 id="heading-installation">Installation</h1>
<p>The recommended, and the method I also use, is to install the Arduino IDE through the Flatpak repo. You can install the Classic IDE or the modern IDE. If you do not have Flatpak setup, you can follow the simple <a target="_blank" href="https://flatpak.org/setup/Ubuntu">guide</a> given by the Flatpak developers. Then, you can open the Gnome Software Centre, search for ‘<em>Arduino</em>’, and install the IDE.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756742026783/24bda070-b2fc-4738-877f-076cc92197c8.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-uninstalling-brltty">Uninstalling <code>brltty</code></h1>
<p><code>brltty</code> is a preinstalled program on Ubuntu that’s known to cause problems with serial devices. So uninstall it using the following command. Unless you heavily rely on accessibility inputs, this program should not be important to you.</p>
<pre><code class="lang-bash">sudo apt remove brltty
</code></pre>
<h1 id="heading-changing-user-access-to-serial-port">Changing User Access to Serial Port</h1>
<p>This actual fix is to give permission to the current user to access <code>/dev/ttyUSB0</code> or whatever device that you have connected to Arduino. You can see the serial port that Arduino is trying to connect to. Use the following command to give your user the access to this device. Note that every time you disconnect and reconnect the device, you have to run this command.</p>
<pre><code class="lang-bash">sudo chmod a+rw /dev/ttyUSB0
</code></pre>
<p>Here, <code>/dev/ttyUSB0</code> is the device that I want to connect to, yours may vary, and you have to add this here instead of <code>/dev/ttyUSB0</code>. <code>sudo</code> provides admin privileges to the current command, <code>chmod</code> asks the device to edit access, <code>a</code> indicates the current user, <code>+rw</code> indicates read + write access and finally, <code>/dev/ttyUSB0</code> is the device.</p>
<p>Not sure which device to connect to? An easy way is to use the following command.</p>
<pre><code class="lang-bash">ls /dev/tty*
</code></pre>
<p>This lists all the serial devices currently connected to your computer. In most cases, the device might be called <code>ttyUSB0</code> or any other variant of <code>ttyUSB…</code>. First run this command without the device attached, then run again WITH the device attached and see which device appeared. This is the serial device. You can use that to upload your code.</p>
<p>Hope this helps, I will continue to update this post with any further information I find on this matter, including any permanent fixes as well.</p>
]]></content:encoded></item><item><title><![CDATA[Kernel Driver Not Installed Issue with VirtualBox]]></title><description><![CDATA[There’s a nasty issue in VirtualBox where you won’t be able to run virtual machines on Linux distros. The error shows something similar to:
Kernel driver not installed (rc=-1908)

The VirtualBox Linux kernel driver is either not loaded or not set up ...]]></description><link>https://blog.asankasovis.com/kernel-driver-not-installed-issue-with-virtualbox</link><guid isPermaLink="true">https://blog.asankasovis.com/kernel-driver-not-installed-issue-with-virtualbox</guid><category><![CDATA[VirtualBox ]]></category><category><![CDATA[Ubuntu]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Fri, 22 Aug 2025 08:12:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1755850286536/ca7ebed2-bfd8-4e53-8b06-61b518f59528.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There’s a nasty issue in VirtualBox where you won’t be able to run virtual machines on Linux distros. The error shows something similar to:</p>
<pre><code class="lang-plaintext">Kernel driver not installed (rc=-1908)

The VirtualBox Linux kernel driver is either not loaded or not set up correctly. Please reinstall virtualbox-dkms package and load the kernel module by executing

'modprobe vboxdrv'

as root.

If your system has EFI Secure Boot enabled you may also need to sign the kernel modules (vboxdrv, vboxnetflt, vboxnetadp, vboxpci) before you can load them. Please see your Linux system's documentation for more information.

where: suplibosinit what: 3
VERR_VM_DRIVER_NOT_INSTALLED (-1908) - The support driver is not installed. On linux, open returned ENOENT.
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755833442985/a6b13e21-5705-46fb-8895-5b689b04d339.png" alt class="image--center mx-auto" /></p>
<p>The error suggests running <code>modprobe vboxdrv</code> as root, but this shows an error similar to the following:</p>
<pre><code class="lang-bash">modprobe: ERROR: could not insert <span class="hljs-string">'vboxdrv'</span>: Key was rejected by service
</code></pre>
<h1 id="heading-the-issue">The Issue</h1>
<p>The issue lies in Secure Boot. Your computer might have secure boot enabled, as is in most modern computers. Secure Boot is a security feature designed to prevent malicious software from loading during the boot process. It works by ensuring that every piece of code, including the operating system and its drivers, is signed with a trusted digital signature. Secure boot requires that any kernel module loaded be signed with a key that your system's Secure Boot trusts.</p>
<h1 id="heading-the-easiest-solution-not-recommended">The Easiest Solution (Not Recommended)</h1>
<p>The easiest solution is to go to your computer’s BIOS and disable secure boot. But this is both a security risk and a potential issue. It is important to not mess around with security, so do this option if you want to take the risk.</p>
<h1 id="heading-the-actual-fix">The Actual Fix</h1>
<h2 id="heading-setup">Setup</h2>
<p>Before we begin, it is important that we install the latest VirtualBox program. You can find it in the <a target="_blank" href="https://www.virtualbox.org/wiki/Downloads">Downloads</a> page of the VirtualBox website. Download the appropriate package for your distribution and install it using:</p>
<pre><code class="lang-plaintext">sudo apt install ./virtualbox-7.2_7.2.0-170228~Ubuntu~oracular_amd64.deb
</code></pre>
<p>The package name might be different in your situation, so make sure you modify the command accordingly.</p>
<h2 id="heading-applying-the-fix">Applying the Fix</h2>
<p>The first step is to install the <code>mokutil</code> package. <code>mokutil</code> is a command-line utility for Linux that provides a user-friendly way to manage the <strong>Machine Owner Key (MOK)</strong> list, which is a crucial component for systems with UEFI Secure Boot enabled. It allows you to import, delete, and list cryptographic keys that are used to sign bootloaders and kernel modules, like the VirtualBox driver. This tool acts as a bridge between the Linux user space and the firmware's Secure Boot key databases, allowing you to add new trusted keys without having to disable Secure Boot entirely.</p>
<p>To install <code>mokutil</code>, use the following command. This is given to align with the <code>apt</code> package manager which is common in most Debian based distributions such as Ubuntu and Cinnamon. Make sure to look into how you can install the same thing, if you do not have a Debian based system.</p>
<pre><code class="lang-bash">sudo apt-get update
sudo apt-get install mokutil
</code></pre>
<p>Follow the usual way that you install a package on Linux and you should be good.</p>
<p>Next, we will create an RSA key. To do this, first let’s switch to the root user using the following command.</p>
<pre><code class="lang-bash">sudo su
</code></pre>
<p>Once you have root user access, we will create a new folder to handle key signing related work and move into it.</p>
<pre><code class="lang-bash">mkdir /root/signed-modules
<span class="hljs-built_in">cd</span> /root/signed-modules
</code></pre>
<p>Now we’re ready to create the RSA key. Use the following command to create the RSA key.</p>
<pre><code class="lang-bash">openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -nodes -days 36500 -subj <span class="hljs-string">"/CN=VirtualBox/"</span>
chmod 600 MOK.priv
</code></pre>
<p>Next, we will install this key to the kernel using the following command. This will ask for a password. Make sure to remember the password you provided, as this comes in handy later.</p>
<pre><code class="lang-bash">mokutil --import MOK.der
</code></pre>
<p>Now reboot your computer and on reboot, you will see a blue screen which ask for the certificate. Move through this menu as <code>Enroll MOK</code> &gt; <code>Continue</code> &gt; <code>&lt;previous password&gt;</code>. The computer will now turn on as expected.</p>
<p>Once rebooted, we will log back in as the root to do the signing.</p>
<pre><code class="lang-bash">sudo su
</code></pre>
<p>Enter the following command to find where the file signing command is.</p>
<pre><code class="lang-bash">find /usr/src -name sign-file
</code></pre>
<p>Now we will move into our working folder and create a new script to automate our signing.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> /root/signed-modules
nano sign-virtual-box
</code></pre>
<p>In the file, paste the following script.</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-keyword">for</span> modfile <span class="hljs-keyword">in</span> $(dirname $(modinfo -n vboxdrv))/*.ko; <span class="hljs-keyword">do</span>
  <span class="hljs-built_in">echo</span> <span class="hljs-string">"Signing <span class="hljs-variable">$modfile</span>"</span>
  /usr/src/linux-headers-6.14.0-28-generic/scripts/sign-file sha254 \
                                /root/signed-modules/MOK.priv \
                                /root/signed-modules/MOK.der <span class="hljs-string">"<span class="hljs-variable">$modfile</span>"</span>
<span class="hljs-keyword">done</span>
</code></pre>
<p>Here, the path <code>/usr/src/linux-headers-6.14.0-28-generic/scripts/sign-file</code> should match the output you got before with <code>find /usr/src -name sign-file</code>.</p>
<p>Now run the script after modifying the execution privileges.</p>
<pre><code class="lang-bash">chmod 700 sign-virtual-box
./sign-virtual-box
</code></pre>
<p>This should allow you to now run any virtual machines without any issues.</p>
<h2 id="heading-an-additional-issue">An Additional Issue</h2>
<p>However, I also did run into another issue where I had to run the following command after every reboot to get the virtual machines to run, other than the above fix. This might or might not be the case.</p>
<pre><code class="lang-bash">sudo modprobe -r kvm_intel
</code></pre>
<p>This is used to unload the <code>kvm_intel</code> kernel module, which is a driver that allows the KVM (Kernel-based Virtual Machine) hypervisor to leverage the virtualization extensions found in Intel CPUs. The <code>modprobe -r</code> part of the command specifically tells the system to remove (or unload) the specified module.</p>
<h1 id="heading-reference">Reference</h1>
<ul>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/61248315/sign-virtual-box-modules-vboxdrv-vboxnetflt-vboxnetadp-vboxpci-centos-8">https://stackoverflow.com/questions/61248315/sign-virtual-box-modules-vboxdrv-vboxnetflt-vboxnetadp-vboxpci-centos-8</a></p>
</li>
<li><p><a target="_blank" href="https://askubuntu.com/questions/1537180/modprobe-vboxdrv-could-not-insert-vboxdrv-key-was-rejected-by-service">https://askubuntu.com/questions/1537180/modprobe-vboxdrv-could-not-insert-vboxdrv-key-was-rejected-by-service</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Pixel Graphics Engine - Introduction]]></title><description><![CDATA[So, I was wondering about making a very basic graphics engine… So I made one! The project is called Pixel Graphics Engine. Pixel Graphics Engine is a Processing-based pixel art animation framework. It allows you to create, animate, and interact with ...]]></description><link>https://blog.asankasovis.com/pixel-graphics-engine-introduction</link><guid isPermaLink="true">https://blog.asankasovis.com/pixel-graphics-engine-introduction</guid><category><![CDATA[Graphics Engine]]></category><category><![CDATA[Processing]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Wed, 06 Aug 2025 15:33:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1754494167368/fdd371f3-8a18-4439-9ee8-3d7dc76d7965.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>So, I was wondering about making a very basic graphics engine… So I made one! The project is called <a target="_blank" href="https://github.com/asankaSovis/Pixel_Graphics_Engine">Pixel Graphics Engine</a>. Pixel Graphics Engine is a <a target="_blank" href="https://processing.org/">Processing</a>-based pixel art animation framework. It allows you to create, animate, and interact with pixel-based sprites on a customizable grid. The engine supports sprite movement, collision detection, animation, and various background effects, making it suitable for pixel art experiments and basic game development.</p>
<h1 id="heading-how-do-you-start-working">How do you start working?</h1>
<ul>
<li><p>Clone the Pixel Graphics Engine repository, or download a release ZIP.</p>
</li>
<li><p>Rename the project to whatever you prefer.</p>
</li>
<li><p>Open the project in Processing.</p>
</li>
<li><p>Edit the code and run.</p>
</li>
</ul>
<p>There’s already placeholder functions provided for ease of development. You can simply replace the dummy code with your own.</p>
<h1 id="heading-development-structure">Development Structure</h1>
<ul>
<li><p>Add Sprites: Modify <code>CreateSprites()</code> in <code>contents.pde</code></p>
</li>
<li><p>Custom Patterns: Create new Pattern objects for different shapes/animations.</p>
</li>
<li><p>Logic: Add game or animation logic in <code>PerformLogic</code></p>
</li>
</ul>
<h1 id="heading-main-components">Main Components</h1>
<ol>
<li><h2 id="heading-pixel-grid">Pixel Grid</h2>
</li>
</ol>
<ul>
<li><p>Resolution: Set via pixel_res (PVector(x, y))</p>
</li>
<li><p>Pixel Size: Set via pixel_size (PVector(x, y))</p>
</li>
<li><p>Offset: Set via pixel_offset (PVector(x, y))</p>
</li>
</ul>
<ol start="2">
<li><h2 id="heading-sprites">Sprites</h2>
</li>
</ol>
<p>Defined in <code>contents.pde</code> Created using the Sprite class (<code>driver.pde</code>) Example: Five ball sprites with random colours and movement</p>
<ol start="3">
<li><h2 id="heading-driver">Driver</h2>
</li>
</ol>
<p>Manages pixel updates, rendering, and sprite interactions See Driver</p>
<ol start="4">
<li><h2 id="heading-animation-amp-patterns">Animation &amp; Patterns</h2>
</li>
</ol>
<p>Sprites use Pattern objects for animation frames Supports rotation, flipping, and key frame control</p>
<ol start="5">
<li><h2 id="heading-custom-logic">Custom Logic</h2>
</li>
</ol>
<p>Add per-frame behaviours in <code>PerformLogic</code></p>
<p>Make sure to mention the Pixel Graph Engine when sharing things you made with it. Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[All About Shutting Down Your Computer]]></title><description><![CDATA[Do you think you know how to shut down your Linux computer? Think again! There are more ways in which you can shut down your system than the control panel. All you need is the terminal and sudo privileges. Here’s a break-down of the shutdown command ...]]></description><link>https://blog.asankasovis.com/all-about-shutting-down-your-computer</link><guid isPermaLink="true">https://blog.asankasovis.com/all-about-shutting-down-your-computer</guid><category><![CDATA[Ubuntu]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[desktop]]></category><category><![CDATA[shutdown]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Tue, 29 Jul 2025 15:58:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753804494861/64ccc7d3-63f6-4f35-a7ae-eab706aaaa75.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Do you think you know how to shut down your Linux computer? Think again! There are more ways in which you can shut down your system than the control panel. All you need is the terminal and sudo privileges. Here’s a break-down of the <code>shutdown</code> command in Linux.</p>
<p>The <code>shutdown</code> command in Linux (Bash) is a powerful utility used to safely halt, power off, or reboot the system. It allows administrators to schedule these actions and notify logged-in users. The general structure of this command is as below:</p>
<pre><code class="lang-bash">shutdown [OPTIONS...] [TIME] [MESSAGE]
</code></pre>
<ul>
<li><p><em>[OPTIONS...]</em> - Controls the specific action (halt, power off, reboot) and other behaviours.</p>
</li>
<li><p><em>[TIME]</em> - Specifies when to perform the shutdown. This is often a mandatory argument if you want to specify a message or schedule the shutdown.</p>
</li>
<li><p><em>[MESSAGE]</em> - An optional message to be broadcast to all logged-in users.</p>
</li>
</ul>
<p>Under [OPTIONS...], the shutdown command allows several options for the shutdown process.</p>
<ul>
<li><p><code>-H</code>/<code>--halt</code> - Halts the machine. This stops all CPU functions but leaves the power on.</p>
</li>
<li><p><code>-P</code>/<code>--poweroff</code> - Powers off the machine. This is often the default behaviour if neither <code>-h</code> (legacy option to override the previous command unless the previous command is —halt) nor <code>-r</code> is specified, completely cutting power.</p>
</li>
<li><p><code>-r</code>/<code>--reboot</code> - Reboots the system.</p>
</li>
<li><p><code>-k</code> - Do not actually shut down, power off, or reboot. Instead, just send the wall message to all logged-in users. This is useful for testing scripts or broadcasting warnings without performing the action.</p>
</li>
<li><p><code>-c</code> - Cancels a pending shutdown. This can only be used if a time argument was specified previously to schedule a shutdown. You cannot specify a <code>TIME</code> or <code>MESSAGE</code> with this option.</p>
</li>
<li><p><code>--no-wall</code> - Do not send a wall message before halting, powering off, or rebooting.</p>
</li>
<li><p><code>--show</code> - Shows a pending shutdown action and time if there is any.</p>
</li>
<li><p><code>-t SEC</code> - Tells <code>init</code> (or <code>systemd</code>) to wait <code>SEC</code> seconds between sending warning messages and the kill signal to processes. Defaults to 5 seconds.</p>
</li>
<li><p><code>-f</code> - Skips the file system check (<code>fsck</code>) on the next reboot. Use with caution as it can lead to data inconsistencies if not used properly.</p>
</li>
<li><p><code>-F</code> - Forces the file system check (<code>fsck</code>) on the next reboot. Useful after an unclean shutdown.</p>
</li>
</ul>
<p>Under the [TIME] argument, you can provide a timeout for the shutdown to occur.</p>
<ul>
<li><p><code>now</code> - Triggers an immediate shutdown. This is an alias for <code>+0</code>.</p>
</li>
<li><p><code>+m</code> - Specifies a shutdown in m minutes from now. For example, <code>+10</code> means shutdown in 10 minutes.</p>
</li>
<li><p><code>hh:mm</code> - Specifies an absolute time in 24-hour format. For example, <code>17:30</code> means shutdown at 5:30 PM.</p>
</li>
</ul>
<p>Under [MESSAGE] argument, you can specify a message to be broadcasted to all logged-in users of the device before shutting down.</p>
<p>Here are a few examples with descriptions as to what they do:</p>
<pre><code class="lang-bash">sudo shutdown now
</code></pre>
<blockquote>
<p>Shuts down the system immediately.</p>
</blockquote>
<pre><code class="lang-bash">sudo shutdown -r +5 <span class="hljs-string">"System rebooting for maintenance. Please save your work."</span>
</code></pre>
<blockquote>
<p>Reboots the system in 5 minutes with the message <em>‘System rebooting for maintenance. Please save your work.’</em></p>
</blockquote>
<pre><code class="lang-bash">sudo shutdown -P 23:00
</code></pre>
<blockquote>
<p>Shut down the system at 11:00 PM.</p>
</blockquote>
<pre><code class="lang-bash">sudo shutdown -c
</code></pre>
<blockquote>
<p>Cancel any pending shut-downs.</p>
</blockquote>
<pre><code class="lang-bash">sudo shutdown -k <span class="hljs-string">"The system will not be going down for maintenance."</span>
</code></pre>
<blockquote>
<p>Do not shut down or reboot but only display the message <code>‘The system will not be going down for maintenance.’</code></p>
</blockquote>
<p>It is important to remember that the <code>shutdown</code> command require administrator privileges. Thus, it is important to run the <code>shutdown</code> command with <code>sudo</code>. Although not that important to remember, if a shutdown is scheduled, it sends warning messages to logged-in users, allowing them to save their work. A file <code>/run/nologin</code> is created (usually 5 minutes before the scheduled time) to prevent further logins.</p>
<p>On modern Linux distributions using <code>systemd</code>, <code>shutdown</code> often acts as a compatibility wrapper, internally invoking equivalent <code>systemctl</code> commands (e.g., <code>systemctl poweroff</code>, <code>systemctl reboot</code>, <code>systemctl halt</code>). While <code>systemctl</code> offers more granular control over system states, <code>shutdown</code> remains a convenient and widely used command, especially for scheduled actions.</p>
<p>While shutdown is the most common command, the following aliases are also available to simplify the specific commands:</p>
<pre><code class="lang-bash">reboot
</code></pre>
<p>Simply reboots the system, similar to the command <code>shutdown -r now</code>.</p>
<pre><code class="lang-bash">halt
</code></pre>
<p>Simply halts the system, similar to the command <code>shutdown -H now</code>.</p>
<pre><code class="lang-bash">poweroff
</code></pre>
<p>Simply powers off the system, similar to the command <code>shutdown now</code>.</p>
<p>Other than this, the underlying <code>systemctl</code> provide a lot more options should you choose to use the underlying commands:</p>
<ul>
<li><p><code>sudo systemctl poweroff</code> - Powers off the system immediately.</p>
</li>
<li><p><code>sudo systemctl reboot</code> - Reboots the system immediately.</p>
</li>
<li><p><code>sudo systemctl halt</code> - Halts the system immediately (may or may not power off, depending on system configuration).</p>
</li>
<li><p><code>sudo systemctl suspend</code>: -Puts the system into a low-power state, keeping memory powered (like sleep mode).</p>
</li>
<li><p><code>sudo systemctl hibernate</code> - Saves the system's state to disk and powers off, allowing a full restore upon next boot.</p>
</li>
<li><p><code>sudo systemctl hybrid-sleep</code> - Attempts to suspend to RAM and disk (combines suspend and hibernate).</p>
</li>
</ul>
<p>The <code>systemctl</code> commands are graceful shutdown commands, meaning that they will attempt a graceful shutdown, stopping processes and syncing file systems before the final action. Using <code>-f</code> or <code>--force</code> with any of them can bypass these graceful steps, potentially leading to data loss if not used carefully.</p>
<h1 id="heading-reference">Reference</h1>
<ul>
<li><p><a target="_blank" href="https://man.archlinux.org/man/shutdown.8.en">https://man.archlinux.org/man/shutdown.8.en</a></p>
</li>
<li><p><a target="_blank" href="https://man.archlinux.org/man/reboot.8">https://man.archlinux.org/man/reboot.8</a></p>
</li>
<li><p><a target="_blank" href="https://man.archlinux.org/man/core/systemd-sysvcompat/poweroff.8.en">https://man.archlinux.org/man/core/systemd-sysvcompat/poweroff.8.en</a></p>
</li>
<li><p><a target="_blank" href="https://man.archlinux.org/man/halt.8">https://man.archlinux.org/man/halt.8</a></p>
</li>
<li><p><a target="_blank" href="https://man.archlinux.org/man/systemctl.1">https://man.archlinux.org/man/systemctl.1</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Creating Bootable Windows ISOs on Linux]]></title><description><![CDATA[Recently, I had to create a bootable Windows pen drive for a friend. As a Linux user, I found that the typical tools we use to create bootable pen drives for Linux, like Disks and Impression, does not work on Windows ISOs. Tools like Rufus that work ...]]></description><link>https://blog.asankasovis.com/creating-bootable-windows-isos-on-linux</link><guid isPermaLink="true">https://blog.asankasovis.com/creating-bootable-windows-isos-on-linux</guid><category><![CDATA[Windows]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Ubuntu]]></category><category><![CDATA[ISO]]></category><category><![CDATA[Installation]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Wed, 16 Jul 2025 15:36:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752680121324/23fbc3db-4edb-44c1-a1cd-7a5ffc7945be.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, I had to create a bootable Windows pen drive for a friend. As a Linux user, I found that the typical tools we use to create bootable pen drives for Linux, like <a target="_blank" href="https://gitlab.gnome.org/GNOME/gnome-disk-utility">Disks</a> and <a target="_blank" href="https://apps.gnome.org/Impression/">Impression</a>, does not work on Windows ISOs. Tools like <a target="_blank" href="https://rufus.ie/en/">Rufus</a> that work on Windows, doesn’t work on Linux, so I had to look into other alternatives. The only option that I found, other than creating a Windows VM, is the <a target="_blank" href="https://woeusb.com/#faq">WOEUSB tool</a>.</p>
<p>The WOEUSB tool managed to create a bootable Windows pen drive with minimal effort. It is developed specifically for this purpose, and it manages to do it really well. This quick article will guide you on creating a Windows ISO on Linux using WOEUSB.</p>
<h1 id="heading-downloading-an-iso">Downloading an ISO</h1>
<p>It is important to download a valid Windows ISO. They can be found through Microsoft’s official website. Given below are quick links to download Windows ISOs. Note that Microsoft might change these URLs.</p>
<ul>
<li><p><a target="_blank" href="https://www.microsoft.com/en-us/software-download/windows11">Windows 11</a></p>
</li>
<li><p><a target="_blank" href="https://www.microsoft.com/en-us/software-download/windows10ISO">Windows 10</a></p>
</li>
</ul>
<h1 id="heading-installing-woeusb-tool">Installing WOEUSB Tool</h1>
<p>First you need to install the required libraries.</p>
<pre><code class="lang-bash">sudo apt install git p7zip-full python3-pip python3-wxgtk4.0 grub2-common grub-pc-bin parted dosfstools ntfs-3g
</code></pre>
<p>Next, we can install the WOEUSB tool through Python.</p>
<pre><code class="lang-bash">sudo pip3 install WoeUSB-ng --break-system-packages
</code></pre>
<p>Next, we will clone the WOEUSB Repo.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/WoeUSB/WoeUSB-ng.git
<span class="hljs-built_in">cd</span> WoeUSB-ng
</code></pre>
<p>After this, we can run the tool from the terminal.</p>
<pre><code class="lang-bash">./WoeUSB/woeusbgui
</code></pre>
<p>It will ask for the admin password, which should be provided. In certain cases, WOEUSB will immediately close after first install, stating that policy is updated. In this case, you have to open it again using the same command.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752678665343/c3696404-cb3c-497e-987a-52bb57a311b4.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-creating-the-iso">Creating the ISO</h1>
<p>Select ‘<em>From a disk image (iso)</em>’ and use the file picker to choose your downloaded ISO. Select the target device under ‘<em>Target device</em>’ and click on ‘<em>Install</em>’. A warning will pop up for confirmation. Make sure that you’ve selected the correct device from the Target devices. Also note that the device will be completely wiped. If you’re OK with this, click on ‘<em>Yes</em>’ to start the process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752679059545/bd6d62dd-2867-4817-bc23-138c600f057a.png" alt class="image--center mx-auto" /></p>
<p>This will start the installation process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752679106258/b43d43b3-3eaa-45ed-806d-2e1d53f5abdd.png" alt class="image--center mx-auto" /></p>
<p>Once installation is done, you will see an ‘<em>Installation Successful</em>’ Message.</p>
<p>Remove the installation media from your computer and use it to install Windows.</p>
<h1 id="heading-uninstalling-woeusb">Uninstalling WOEUSB</h1>
<p>WOEUSB can be uninstalled using the following commands.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ..
rm -rf ./WoeUSB-ng/
sudo pip3 uninstall WoeUSB-ng --break-system-packages
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752679550664/7f508f3b-b716-4455-96e3-a5d11e0eeb73.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>While it is hard to create a Windows installation media on Linux, it is not impossible. With the use of WOEUSB, we can relatively easily create a Windows installation media. The steps outlined in this article will be quite helpful in this matter.</p>
]]></content:encoded></item><item><title><![CDATA[The Call Stack - Hidden Foundation of Functional Programming]]></title><description><![CDATA[In computer science, the stack is an important concept. In reality also, the stack is a crucial part of the execution of an assembly program written in a higher-level language. From clicking a button on screen to sending a payload to space, the conce...]]></description><link>https://blog.asankasovis.com/the-call-stack-hidden-foundation-of-functional-programming</link><guid isPermaLink="true">https://blog.asankasovis.com/the-call-stack-hidden-foundation-of-functional-programming</guid><category><![CDATA[Computer Science]]></category><category><![CDATA[#StackDataStructure]]></category><category><![CDATA[stack memory]]></category><category><![CDATA[explained]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Tue, 08 Jul 2025 16:56:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1751993551796/db426b29-1dc6-46ee-96bb-dddf842de956.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In computer science, the stack is an important concept. In reality also, the stack is a crucial part of the execution of an assembly program written in a higher-level language. From clicking a button on screen to sending a payload to space, the concept of a stack plays a major part. Pioneered and popularized by brilliant minds like Edsger Dijkstra in the mid-20th century, it provided a robust and efficient way for compilers to handle memory and control.</p>
<p>Let's start with the concept of a stack. Imagine a stack of plates in your house: you can only add a new plate to the top, and you can only take the top plate off. This "Last-In, First-Out" (LIFO) principle is how the stack works. In your computer, a similar thing happens every time you call a new function, declare a variable, or return from a function.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751984819945/b22a52dc-9c92-456a-b3d0-c7af58e22a9c.jpeg" alt="A stack of plates [AI generated]" class="image--center mx-auto" /></p>
<blockquote>
<p>A stack of plates [AI generated]</p>
</blockquote>
<p>We can visualize the memory as a tall shelf with thousands of tiny drawers that can hold a 'byte' of data. Now, it is important to manage this memory efficiently to take the best out of the system and to mitigate mistakes. This is where memory management comes into play.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751986707076/9f5d1cf9-08c8-4d7b-a124-eca254ca7754.jpeg" alt="A stack of drawers [AI generated]" class="image--center mx-auto" /></p>
<blockquote>
<p>A stack of drawers [AI generated]</p>
</blockquote>
<p>The Stack, in the sense of computer memory management, is one such strategy. Now think of the plate analogy we discussed before, and the assign the same ruleset to the tall 'memory' shelf. You have to start from the bottom most drawer. You can only put a 'byte' into the drawer above the one last filled. And you can only take the topmost one at a time.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751987770307/a71b99b7-388f-4151-aa8d-efd2e0ac3d96.png" alt="Typical SRAM structure of the ARM memory" class="image--center mx-auto" /></p>
<blockquote>
<p>Typical SRAM structure of the ARM memory</p>
</blockquote>
<p>Just like that, the memory allocated to the stack is only accessible in the above discussed way. Think of the stack as a dedicated workspace for managing critical information. The stack is crucial to handle:</p>
<ul>
<li><p>Function Calls: Every time a function is called, its details are 'pushed' onto the stack. When the function finishes, its information is 'popped' off.</p>
</li>
<li><p>Local Variables: The temporary data a function needs to do its job is stored right there on the stack.</p>
</li>
<li><p>Program Flow: It's the stack that ensures your program returns to the exact spot it left off after completing a task or jumping to a different part of the code.</p>
</li>
</ul>
<p>Now we will see how the Stack works. In real memory, the stack starts from the highest available memory address and move down. To further understand how the stack behaves, we will use a sample C code as an example.</p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">square</span><span class="hljs-params">(<span class="hljs-keyword">int</span> num)</span> </span>{
    <span class="hljs-keyword">int</span> result = num * num;
    <span class="hljs-keyword">return</span> result;
}

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">int</span> x = <span class="hljs-number">2</span>;
    square(x);
}
</code></pre>
<p>The compiled x86-64 Clang Assembly code is as below.</p>
<pre><code class="lang-plaintext">square:
    push rbp
    mov rbp, rsp
    mov dword ptr [rbp - 4], edi
    mov eax, dword ptr [rbp - 4]
    imul eax, dword ptr [rbp - 4]
    mov dword ptr [rbp - 8], eax
    mov eax, dword ptr [rbp - 8]
    pop rbp
    ret

main:
    push rbp
    mov rbp, rsp
    sub rsp, 16
    mov dword ptr [rbp - 4], 2
    mov edi, dword ptr [rbp - 4]
    call square
    xor eax, eax
    add rsp, 16
    pop rbp
    ret
</code></pre>
<p>If you analyse the code, every time we switch functions, we're pushing the Base Pointer (RBP) onto the stack. Then we change the RBP to the current Stack Pointer (RSP). This way, we know where to return to after the function executes and returns. On the other hand, we create space for all the local variables of that function within the stack as soon as we're done with it. After execution, the stack pops all of that data and move back to where we started.</p>
<p>This is better visualized in the below animation.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751903741545/b5ad6073-4a32-4ca3-8488-101e825ddd2a.gif" alt class="image--center mx-auto" /></p>
<p>From the simplest script to the most complex operating system, the stack is silently working behind the scenes, ensuring that our digital world runs smoothly and predictably. It's a testament to how some of the most powerful and enduring ideas in computing are rooted in simple, yet effective, abstractions.</p>
<p>Reference:</p>
<ul>
<li><p>Wikipedia article on the Stack data type: <a target="_blank" href="https://en.wikipedia.org/wiki/Stack_\(abstract_data_type\)">https://en.wikipedia.org/wiki/Stack_(abstract_data_type)</a></p>
</li>
<li><p>Wikipedia article on the Call Stack: <a target="_blank" href="https://en.wikipedia.org/wiki/Call_stack">https://en.wikipedia.org/wiki/Call_stack</a></p>
</li>
<li><p>Code sample on Compiler Explorer: <a target="_blank" href="https://godbolt.org/z/1vddacPM3">https://godbolt.org/z/1vddacPM3</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Easy Steps to Create Your Development Environment]]></title><description><![CDATA[Setting up the development environment for your requirements is pretty straightforward. nRF provides an intuitive and easy-to-use development environment that is easy to set up and develop programs with. First, we will start our development journey b...]]></description><link>https://blog.asankasovis.com/easy-steps-to-create-your-development-environment-nrf-toolchain</link><guid isPermaLink="true">https://blog.asankasovis.com/easy-steps-to-create-your-development-environment-nrf-toolchain</guid><category><![CDATA[Nordic Semiconductor]]></category><category><![CDATA[toolchain]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Sat, 22 Mar 2025 18:30:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1742632556210/efbdf1da-6421-4272-872a-0c33bf87e359.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Setting up the development environment for your requirements is pretty straightforward. nRF provides an intuitive and easy-to-use development environment that is easy to set up and develop programs with. First, we will start our development journey by setting up the nRF development environment. I will be using Ubuntu 23.10 but any version above 22.04 will be more or less the same. For Windows, though I ran into a bunch of errors while setting up so I recommend setting up an Ubuntu environment such as WSL in Windows.</p>
<h1 id="heading-installing-the-nrf-connect-for-desktop-application">Installing the nRF Connect for Desktop Application</h1>
<p>The first thing is to install the <a target="_blank" href="https://www.nordicsemi.com/Products/Development-tools/nrf-connect-for-desktop">nRF Connect for Desktop</a> application. Go to the <a target="_blank" href="https://www.nordicsemi.com/Products/Development-tools/nRF-Connect-for-Desktop/Download#infotabs">Downloads</a> section. First of all, download the latest package for your preferred operating system.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703562048021/fd55b409-c112-4672-bc81-46c1d0415883.png" alt="Download page for nRF Commect for Desktop application" class="image--center mx-auto" /></p>
<p>For Windows, the application comes as an exe installer. Simply double-clicking the downloaded exe and following the given instructions will be ideal. For Linux though, the application comes as an AppImage. AppImage is a packaging format which bundles all the dependencies and libraries as one single executable which can just be run by double-clicking. However, the AppImage version that Nordic has used to bundle the application is outdated and for modern systems, just double-clicking will not help. In such a case, I'd recommend you follow this tutorial to set up the application. Even if it works for you, this method will be faster and more reliable as it sets up the program to run without mounting itself. <mark>DO NOT ATTEMPT TO INSTALL </mark> <code>libfuse2</code><mark>as it WILL BREAK YOUR SYSTEM</mark>.</p>
<p>Now that we have the nRF Connect for Desktop ready, we can open the application by double-clicking the AppImage or from the app launcher. This will open the nRF Connect for Desktop application.</p>
<h1 id="heading-installing-a-preferred-toolchain">Installing a Preferred Toolchain</h1>
<p>The next important thing to do is the install the preferred toolchain. In the Apps tab of the nRF Connect, you will find an entry called Toolchain Manager. Toolchain Manager allows you to manage the different toolchains we need for microcontroller development. We will start by installing the Toolchain Manager. Click on the Install button next to the Toolchain Manager entry and wait for the entry to complete the installation.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703587376660/9890b137-44c6-400c-86fb-090c59603088.png" alt="nRF Connect for Desktop application" class="image--center mx-auto" /></p>
<p>If the installation succeeds, the Install button will be replaced by an Open button. Click on the Open button to open the Toolchain Manager. Now we will install a preferred toolchain. It's suggested to install the latest toolchain available unless you have a specific reason to use another version. To do this, click on the Install button as usual. This will prompt a small window asking you to confirm the install directory.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703587685961/a1a548ed-1cfa-4498-9e83-a863b82d9ca8.png" alt="Message prompting to select the toolchain installation directory" class="image--center mx-auto" /></p>
<p>The default path would be the ideal location to leave the toolchains however, if you want to install in a different location, you can click on the Change directory button and choose the location. Note that once installed, changing the toolchain location will be hard, so choose the proper place to install your toolchain. Once complete, click on Continue installation to install the selected toolchain. Installing a toolchain will take a considerable amount of time depending on your hardware and network connection. Once complete, you will get a window similar to below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703587938558/a242e44e-074a-4578-adfe-43f341b28d5b.png" alt="Toolchain Manager application" class="image--center mx-auto" /></p>
<h1 id="heading-installing-the-vs-code-editor">Installing the VS Code Editor</h1>
<p>For development, nRF Connect supports the VS Code code editor. If you already have VS Code installed, you can continue with installing the extensions. However, if you don't have VS Code installed, you can install it by downloading the package from the <a target="_blank" href="https://code.visualstudio.com/download">official website</a>. It is recommended to use the official website to install VS Code rather than other methods like Flatpaks or 3rd party websites. The installation method should be pretty typical and does not need any explanation.</p>
<h1 id="heading-installing-the-nrf-command-line-tools">Installing the nRF Command Line Tools</h1>
<p>Once VS Code is done installing, you can click on the Open VS Code button that appears after the installation of the toolchain. However, this will prompt a message asking you to install <a target="_blank" href="https://www.nordicsemi.com/Products/Development-tools/nrf-command-line-tools/download">nRF Command Line Tools</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703588715346/4fc24286-ef68-41ea-a7c4-611411a078e7.png" alt="Install nRF Command Line Tools" class="image--center mx-auto" /></p>
<p>Click on the provided link to open the download location. From the website, download the correct installer for your preferred operating system. As usual, the installation will be typical and you can follow the instructions provided. For Windows, it will be a standard installer as an exe while for Linux, it will be a deb file.</p>
<h1 id="heading-installing-the-environment-variables">Installing the Environment Variables</h1>
<p>It is a good practise to also setup the required environment variables for the development to go smoothly. For this, in the Toolchain Manager, click on the drop down button next to Open VS Code button. This will show multiple options that include Generate environment script.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703590504077/7356d229-2871-4dcb-8f9b-1d4ddca2157c.png" alt="Installing environment variables" class="image--center mx-auto" /></p>
<p>Clicking on this will prompt you to select a place to save the generated script. Save it anywhere you want and navigate to that location with your file explorer. For Windows, this will create a cmd file that can be double-click to install. Provide the Administrator password if prompted. For Linux, you can right-click in the file explorer and click on Open in Terminal. This will open a terminal window with the path as the directory in which you have the bash script file. Enter the below two commands to run this script.</p>
<pre><code class="lang-bash">chmod +x ./env.sh
./env.sh
</code></pre>
<p>This will install the environment variables in the operating system. It is recommended to restart your operating system before proceeding with the next steps.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703590818519/e073de38-5142-45a5-82a1-65d02b5e95db.png" alt="Installing environment variables" class="image--center mx-auto" /></p>
<h1 id="heading-setting-up-the-vs-code-development-environment-for-nrf">Setting up the VS Code Development Environment for nRF</h1>
<p>Once complete, it is recommended to restart the operating system before proceeding. Now you can open the toolchain manager again and click on Open VS Code. Now you will see a new message asking you to install the VS Code extensions.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703589199445/d40d1715-ea2f-42e9-afbe-60ca146c5901.jpeg" alt="Installing VS Code extensions" class="image--center mx-auto" /></p>
<p>Clicking on Install missing extensions button will install all the extensions one by one. Once all the installations are complete, you can click on Open VS Code again to open the VS Code editor. This will open the VS Code where you can start your development. On how to start development, you can refer to this link.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703589427237/643a2d3a-0277-4796-99ef-029b4e820b3d.png" alt="VS Code after setting up nRF Toolchain" class="image--center mx-auto" /></p>
<h1 id="heading-fixing-the-jlinkarm-dll-load-failed-error">Fixing the JLinkARM DLL load failed Error</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703589523191/5e5d51cf-2fb1-4d51-bace-d96dd6ded2f3.png" alt="Fixing the JLinkARM DLL load failed Error" class="image--center mx-auto" /></p>
<p>Sometimes when trying to flash the code to your Nordic device, you might end up with an error that looks like above. In this case, the issue might be an out-of-date JLink driver installed. Go to the <a target="_blank" href="https://www.segger.com/downloads/jlink/">SEGGER JLink download page</a> and download the latest driver for your operating system. As usual, the installation is straightforward and does not need any explanation. Once done, the Flashing should work as expected.</p>
<p>The nRF development environment is a powerful and versatile ecosystem for creating applications for Nordic Semiconductor's nRF series of low-power wireless SoCs. It caters to developers of all skill levels, offering options for both beginners and seasoned professionals. So enjoy coding with your new nRF development board.</p>
<h1 id="heading-references">References</h1>
<ul>
<li><p><a target="_blank" href="https://www.nordicsemi.com/Products/Development-tools/nRF-Connect-for-Desktop/Download#infotabs">nRF Connect for Desktop download page</a></p>
</li>
<li><p><a target="_blank" href="https://code.visualstudio.com/download">VS Code download page</a></p>
</li>
<li><p><a target="_blank" href="https://www.nordicsemi.com/Products/Development-tools/nrf-command-line-tools/download">nRF Command Line Tools download page</a></p>
</li>
<li><p><a target="_blank" href="https://www.segger.com/downloads/jlink/">SEGGER JLink tool download page</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Introduction]]></title><description><![CDATA[The nRF development environment is a powerful and user-friendly platform that makes creating innovative and low-power wireless applications with Nordic SoCs easy. So, whether you're a seasoned developer or just starting, the nRF ecosystem has somethi...]]></description><link>https://blog.asankasovis.com/introduction-nrf-toolchain</link><guid isPermaLink="true">https://blog.asankasovis.com/introduction-nrf-toolchain</guid><category><![CDATA[Nordic Semiconductor]]></category><category><![CDATA[toolchain]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Sat, 22 Mar 2025 08:28:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1742631596266/b29c5086-18d5-441b-a809-da3d5f18fe7f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The nRF development environment is a powerful and user-friendly platform that makes creating innovative and low-power wireless applications with Nordic SoCs easy. So, whether you're a seasoned developer or just starting, the nRF ecosystem has something to offer you. It’s primarily centred around Nordic Semiconductor's nRF series of System-on-Chips (SoCs) and is designed to facilitate the creation of wireless applications, particularly those utilizing Bluetooth Low Energy (BLE) and other low-power wireless technologies. It features the following components:</p>
<ul>
<li><p><strong>nRF Series SoCs:</strong> These are the core of the development environment. Nordic Semiconductor offers a range of nRF chips (like the nRF51, nRF52, nRF53, and nRF91 series), each with varying capabilities in terms of processing power, wireless protocol support, and features. These SoCs are designed for low-power operation, making them ideal for battery-powered IoT devices.</p>
</li>
<li><p><strong>nRF Connect SDK (Software Development Kit):</strong> This is a crucial software tool for developing applications for nRF devices. It provides a comprehensive set of tools, libraries, and examples for building firmware. The nRF Connect SDK is based on the Zephyr RTOS (Real-Time Operating System), which offers a robust and scalable platform for embedded development.</p>
</li>
<li><p><strong>nRF Connect for Desktop:</strong> This is a PC-based application that provides various tools for testing, programming, and debugging nRF devices.</p>
</li>
<li><p><strong>nRF Connect for VS Code:</strong> This Visual Studio Code extension streamlines nRF Connect SDK development within the popular VS Code IDE. It simplifies tasks like building, flashing, and debugging.</p>
</li>
<li><p><strong>Development Kits (DKs):</strong> Nordic Semiconductor provides development kits that allow developers to prototype and test their applications. These kits typically include an nRF SoC, along with other necessary components.</p>
</li>
</ul>
<p>The reason for starting this article series is to share the knowledge I received about the nRF development flow. Sometimes it can get overwhelming to enter into the nRF toolchain because of the lack of sources online. However, I can recommend the <a target="_blank" href="https://academy.nordicsemi.com/">Nordic Dev Academy</a> as it is a good starting point for further information on the Nordic toolchain and SDKs.</p>
]]></content:encoded></item><item><title><![CDATA[Making Your Own Website for Free]]></title><description><![CDATA[Having your own website can be an advantage, whether you’re a small business owner, a freelancer, or even a student. A personal website will allow you to stand out from the rest of the crowd while giving you the freedom to express yourself however yo...]]></description><link>https://blog.asankasovis.com/making-your-own-website-for-free</link><guid isPermaLink="true">https://blog.asankasovis.com/making-your-own-website-for-free</guid><category><![CDATA[website]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Sun, 16 Mar 2025 17:01:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1742630610459/86dd3ace-bad4-4915-ac3a-4ea8a802a94a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Having your own website can be an advantage, whether you’re a small business owner, a freelancer, or even a student. A personal website will allow you to stand out from the rest of the crowd while giving you the freedom to express yourself however you want. However, most people don’t consider making their own personal website, sometimes due to a lack of time, money or even technical know-how. But the thing is, there are modern ways to make a website quickly and efficiently, so it doesn’t matter what technical background you have.</p>
<h1 id="heading-making-the-website-itself">Making the Website Itself</h1>
<p>There are multiple ways to make a website. You can use <a target="_blank" href="https://wordpress.com/">WordPress</a>, download a website from the internet or even make one yourself from scratch. If you want to go with WordPress, you can follow the <a target="_blank" href="https://wordpress.com/go/">online resources</a> and get a working website up quickly. If you prefer to develop your own website from scratch, it might be a bit more complicated; I’d suggest you go on this route only if you know what you’re doing. An easy way is to download a sample website from the internet. There are great sites like <a target="_blank" href="http://www.free-css.com">www.free-css.com</a>. Simply download one and modify it according to your liking.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742135955511/61d42fd1-00d6-4bd0-ac73-7cf026d70d94.png" alt="www.free-css.com website" class="image--center mx-auto" /></p>
<h1 id="heading-hosting-the-website">Hosting the Website</h1>
<p>This is where most people get confused. While there are so many hosting providers - <a target="_blank" href="https://azure.microsoft.com/en-us/">Microsoft Azure</a>, <a target="_blank" href="https://firebase.google.com/">Google Firebase</a>, <a target="_blank" href="https://aws.amazon.com/">Amazon AWS</a>, <a target="_blank" href="https://www.hostinger.com/">Hostinger</a>, etc, there’s one hosting provider that you might not be considered or even know about: <a target="_blank" href="https://github.com/">GitHub</a>. That’s right, you can host your personal website on Github with little to no effort, costing zero money.</p>
<p>What you have to do is go to your GitHub account and create a new repository. This repository should be named <strong><em>&lt;your-github-name&gt;.github.io</em></strong>. Here <em>&lt;your-github-name&gt;</em> refers to your Github profile name. For example, my GitHub name is <a target="_blank" href="https://github.com/asankaSovis">asankaSovis</a>, so I have my repository titled <a target="_blank" href="https://github.com/asankaSovis/asankaSovis.github.io"><strong><em>asankaSovis.github.io</em></strong></a><strong>.</strong> Make sure that the repository is <strong>Public</strong>. You can choose to initialize the repo with a README, add a .gitignore file or even choose a license; it doesn’t matter.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742136740163/12c79d76-0557-497f-ae63-12018a20d1df.png" alt="Creating a new repository on Github with asankaSovis.github.io as the Repository name (Note that I already have this repository created)" class="image--center mx-auto" /></p>
<p>Once the repository is created, you can clone the repo to your computer. For this, you can use the <strong>Code &gt; Clone &gt; HTTPS</strong> option as below. Under this, click on the copy button to copy the URL and paste it into your terminal with the below command. Note that <em>&lt;URL&gt;</em> refers to the URL that we copied before.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> &lt;URL&gt;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742137230199/f8208498-0460-4aae-bbd6-96869618bb16.png" alt="Clone URL under the git repo." class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742137242228/3546a992-ebc3-4fe3-adb9-67d00e281394.png" alt="Cloning the Github repo." class="image--center mx-auto" /></p>
<p>If you’re using Mac or Linux, you will have <a target="_blank" href="https://git-scm.com/">Git</a> installed by default, so providing the above command would be sufficient. If you’re using Windows, you might need to <a target="_blank" href="https://git-scm.com/downloads">install Git</a>. Refer to the <a target="_blank" href="https://git-scm.com/doc">official documentation</a> for how you can install Git. Also, you have to make sure that Git is initialized with your GitHub username and password. Refer to the <a target="_blank" href="https://git-scm.com/docs/gittutorial">Github documentation</a> for this.</p>
<p>Once cloned, open the directory in your file browser. Copy your website to this directory while making sure that the <em>index.html</em> file is at the root of this cloned directory.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742137523270/7c4a288a-dd0c-412c-ad5c-cdb0d6972b0b.png" alt="Cloned directory with the contents of the website. Note the index.html in the root of this directory." class="image--center mx-auto" /></p>
<p>Now, we have to commit the changes and sync the changes to the source. To do this, you can use the following commands in order.</p>
<pre><code class="lang-bash">git add .
git commit -m <span class="hljs-string">"Initial Commit"</span>
git push &amp;&amp; git pull
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742137866272/1e26d5d1-228b-46fa-b90a-2d5b6c96a82b.png" alt="Committing the website to Github." class="image--center mx-auto" /></p>
<p>Now if you open the GitHub repo on your browser, you will see a yellow dot in the interface. Clicking on this will reveal the status of publishing your website. When this yellow dot turns into a green checkmark, the website is online.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742138060599/151ee5b1-62fd-4d36-b423-aa94ffae55f8.png" alt="Completed deploying of the website." class="image--center mx-auto" /></p>
<p>That’s it, your website is now online. Visiting the <strong><em>&lt;your-github-name&gt;.github.io</em></strong> website will reveal your very own personal website. Here <em>&lt;your-github-name&gt;</em> refers to your Github profile name, as mentioned before.</p>
<h1 id="heading-adding-our-own-custom-domain">Adding Our Own Custom Domain</h1>
<p>You don’t have to stop here; you can host the website on your own URL as well, with no need for the <strong><em>&lt;your-github-name&gt;.github.io</em></strong> URL at all. To do this, we need our very own domain, and it will cost you a bit. You can use any domain provider: <a target="_blank" href="https://www.godaddy.com/en-in">GoDaddy</a>, <a target="_blank" href="https://www.hostinger.com/domain-name-search">Hostinger</a>, <a target="_blank" href="https://www.bluehost.com/">Bluehost</a>, etc. Here, I will be using <a target="_blank" href="https://www.namecheap.com/">Namecheap</a>.</p>
<p>Visit the Namecheap website and create your account. After logging back into your account, go to the homepage. Here, you can search for whatever domain name you want.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742138565431/1786d900-27d0-475f-b611-e1e17935e7eb.png" alt="Namecheap website with the domain search open." class="image--center mx-auto" /></p>
<p>Once you search for a name for your domain, Namecheap will show you a list of domains available for your purchase. Double-check carefully and choose a domain that suits you well. You must consider the intended audience, initial cost, yearly payment, etc. when you buy a domain.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742138740375/432289d0-bd83-4fee-8e62-1ec35d3d8c00.png" alt="Namecheap search results." class="image--center mx-auto" /></p>
<p>Once you have the right domain, add it to the cart, go to checkout and buy it. You will need to provide your card details at checkout. After you complete your transaction, go to <strong>Your Account &gt; Dashboard</strong> to view the newly registered domain. Under <strong>Dashboard &gt; Recently Active in Your Account</strong>, you will see the domain.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742139238514/5e1b8989-5f9b-489a-8526-4aed48cfad2e.png" alt="Registered domain under Dashboard." class="image--center mx-auto" /></p>
<p>Click on <strong>Manage,</strong> and under this, you have to click on <strong>Advanced DNS</strong>. Here, add the following under <strong>Host Records</strong>. You can use the <strong>ADD NEW RECORD</strong> button.</p>
<pre><code class="lang-plaintext">A Record         @        185.199.108.153                30 min
A Record         @        185.199.109.153                Automatic
A Record         @        185.199.110.153                Automatic
A Record         @        185.199.111.153                Automatic
CNAME Record     www    &lt;your-github-name&gt;.github.io.    Automatic
</code></pre>
<p>Once this is done, go to your website’s Github repository again. Here, go to <strong>Settings &gt; Pages &gt; Custom Domain</strong>. In the textbox, enter the domain you just registered. Under this, a yellow dot will appear, followed by a text that reads <em>‘DNS Check in Progress. ’</em> Wait for a few minutes and if all is well, this will turn into a green tick mark followed by a text that reads <em>‘DNS check successful’</em>. If not, review the steps again to see if you have followed everything correctly. Sometimes, it will take several hours for domains to start working correctly, so consider giving it some time.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742140067579/9c86fedc-e03c-43a9-98da-28fef90d3b34.png" alt="Custom domain option under Settings in the Github repo of the website." class="image--center mx-auto" /></p>
<p>Now if you visit your domain on your browser, you will see your website hosted. The following variations of the URL will be working as expected.</p>
<pre><code class="lang-plaintext">http://&lt;your-domain&gt;.&lt;TLD-domain&gt;
http://www.&lt;your-domain&gt;.&lt;TLD-domain&gt;
https://&lt;your-domain&gt;.&lt;TLD-domain&gt;
https://www.&lt;your-domain&gt;.&lt;TLD-domain&gt;
&lt;your-domain&gt;.&lt;TLD-domain&gt;
www.&lt;your-domain&gt;.&lt;TLD-domain&gt;
</code></pre>
<p>Here, <em>&lt;your-domain&gt;</em> refers to your registered domain and the <em>&lt;TLD-domain&gt;</em>. refers to the Top Level Domain (TLD) you registered it under. For example, .com, .org, .it, etc.</p>
<h1 id="heading-extending-the-domain-to-your-hashnode-blog">Extending the Domain to Your Hashnode Blog</h1>
<p>If you have an active blog in <a target="_blank" href="https://hashnode.com/">Hashnode</a>, you can do the same thing to host your blog under your custom domain. Go to your Hashnode profile and go to the dashboard of your blog. Under <strong>Blog Dashboard &gt; Domain</strong>, you will find the required settings. Click on <strong>Custom domain</strong> and in the text box, enter a variant of <em>&lt;sub-domain&gt;.&lt;your-domain&gt;.&lt;TLD-domain&gt;</em>. A good option would be <em>blog.&lt;your-domain&gt;.&lt;TLD-domain&gt;</em>. Click on <strong>Add domain</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742140888573/05e57e36-90f3-4dec-8b0f-6b109cde56f7.png" alt="Adding custom domain under Hashnode." class="image--center mx-auto" /></p>
<p>Now you have to go back to you Namecheap Dashboard, and update the <strong>Host Records</strong> again as we did before to include the blog URL as well.</p>
<pre><code class="lang-plaintext">A Record         @        185.199.108.153                30 min
A Record         @        185.199.109.153                Automatic
A Record         @        185.199.110.153                Automatic
A Record         @        185.199.111.153                Automatic
CNAME Record     www    &lt;your-github-name&gt;.github.io.    Automatic
CNAME Record     blog    hashnode.network.               Automatic
</code></pre>
<p>Once updated, you can visit the Hashnode settings page we were in before and it should show a green check mark followed by <strong>Valid</strong> under the <strong>Status</strong> tab as below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742141249080/edf8e0b8-2a39-4ba6-864f-fc8fc22ac382.png" alt="Status shown as Valid under Domain settings in Hashnode." class="image--center mx-auto" /></p>
<p>This indicates that the new domain is ready to be used. Visiting <em>blog.&lt;your-domain&gt;.&lt;TLD-domain&gt;</em> or whatever you chose before will show your Hashnode blog. If not, review the steps again to see if you have followed everything correctly. Sometimes, it will take several hours for domains to start working correctly, so consider giving it some time.</p>
<h1 id="heading-create-redirects-to-your-socials">Create Redirects to Your Socials</h1>
<p>We do not have to end there. You can also create redirects to your social media as well using your custom domain. To do this, instead of <strong>Advanced DNS</strong>, go to <strong>Domain</strong> under your Domains List in Namecheap like we did for the personal website. Here, under <strong>Redirect Domain</strong>, you can set URLs to redirect from your domain. For example, let’s say you want the URL <em>facebook.&lt;your-domain&gt;.&lt;TLD-domain&gt;</em> to automatically redirect to your Facebook profile, simply click on <strong>ADD REDIRECT</strong> and enter <em>facebook.&lt;your-domain&gt;.&lt;TLD-domain&gt;</em> as the Source URL and the URL to your Facebook profile under Destination URL. Now if you visit, <em>facebook.&lt;your-domain&gt;.&lt;TLD-domain&gt;</em>, the URL will be automatically forwarded to your Facebook profile. You can add as many redirects as you want like this.</p>
<h1 id="heading-create-custom-email-redirects">Create Custom Email Redirects</h1>
<p>Another awesome feature you will get is the option to redirect emails. No need to use your personal email to advertise yourself. You can create your email address using your domain. Note that this will not be a brand-new email address but rather a <em>forwarding</em> email address. You will still need a proper email address set up to receive emails.</p>
<p>Under the same setting <strong>Domain</strong> we were in before, go to <strong>Redirect Email</strong>. Here, click on <strong>ADD FORWARDER</strong> and add an alias under <strong>Alias</strong> and your email address under <strong>Forward to</strong>. An alias could be, for example, contact, hello, or enquiries. Let’s say you entered ‘<em>contact’</em> as an alias. Any emails sent to <em>contact@&lt;your-domain&gt;.&lt;TLD-domain&gt;</em> will be forwarded to the personal email you entered under <strong>Forward to</strong>. You can add as many aliases to as many emails as you want like this.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Having your own website is important to increase your reach and advertise yourself as an individual on this ever-expanding internet. Here, I discussed a way you can make your small home in this vast network. On the other hand, buying your domain will also have its advantages, as we discussed. So, make the best out of this great opportunity.</p>
<h1 id="heading-reference">Reference</h1>
<ul>
<li><p>Github Homepage: <a target="_blank" href="https://github.com/">https://github.com/</a></p>
</li>
<li><p>Namecheap Homepage: <a target="_blank" href="https://www.namecheap.com/">https://www.namecheap.com/</a></p>
</li>
<li><p>Hashnode Homepage: <a target="_blank" href="https://hashnode.com/">https://hashnode.com/</a></p>
</li>
<li><p>Git Homepage: <a target="_blank" href="https://git-scm.com/">https://git-scm.com/</a></p>
</li>
<li><p>Git Documentation: <a target="_blank" href="https://git-scm.com/doc">https://git-scm.com/doc</a></p>
</li>
<li><p>Git Tutorials: <a target="_blank" href="https://git-scm.com/docs/gittutorial">https://git-scm.com/docs/gittutorial</a></p>
</li>
<li><p>Configuring a custom domain for your GitHub Pages site: <a target="_blank" href="https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site">https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site</a></p>
</li>
<li><p>How to Map a Custom Domain?: <a target="_blank" href="https://docs.hashnode.com/help-center/blog-domain/how-to-map-a-custom-domain">https://docs.hashnode.com/help-center/blog-domain/how-to-map-a-custom-domain</a></p>
</li>
<li><p>Free CSS: <a target="_blank" href="https://www.free-css.com/">https://www.free-css.com/</a></p>
</li>
<li><p>WordPress Builder: <a target="_blank" href="https://wordpress.com/go/">https://wordpress.com/go/</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Wallpaper Slideshows on Linux]]></title><description><![CDATA[So, I was binge-watching YouTube videos and a random thought came to my mind, like most people: What if I write a bash script to change the wallpaper every minute? I will be like the wallpaper slideshow in Windows. So I got into writing a script. I w...]]></description><link>https://blog.asankasovis.com/wallpaper-slideshows-on-linux</link><guid isPermaLink="true">https://blog.asankasovis.com/wallpaper-slideshows-on-linux</guid><category><![CDATA[Linux]]></category><category><![CDATA[opensource]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Sun, 09 Feb 2025 15:38:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1739115305610/cdf806b1-cdb3-4744-9350-492a99a5983f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>So, I was binge-watching YouTube videos and a random thought came to my mind, like most people: <em>What if I write a bash script to change the wallpaper every minute?</em> I will be like the wallpaper slideshow in Windows. So I got into writing a script. I was quite straightforward. And you can find the final script in my <a target="_blank" href="https://github.com/asankaSovis/Wallpaper_Changer">GitHub Repository</a>.</p>
<p>So first off, how do you change the wallpaper in Linux? Well, it depends on the distro! Since Ubuntu is a common distro and it’s based on Gnome, you can use the Settings app to change the wallpaper. The same goes for most other famous distros.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739113507110/d416f7c6-cddd-48ca-ba8a-efbcf6790ba2.png" alt="Gnome Settings app in Ubuntu 24.10" class="image--center mx-auto" /></p>
<p>But this lacks the option to time the changing of the wallpaper, which is kind of boring. Now I’ve got to admit, there might be better options for wallpaper slideshows in Linux. Having a script is not at all optimized let alone elegant. But I like the simplicity of the idea.</p>
<p>Now if we want to automate the wallpaper creation, we must first have a command that can change the wallpaper. In fact, we do!</p>
<pre><code class="lang-bash">gsettings <span class="hljs-built_in">set</span> org.gnome.desktop.background picture-uri-dark /path/to/wallpaper.jpg
</code></pre>
<p>Now this is for the dark theme, for the light theme, it’s the same but as below.</p>
<pre><code class="lang-bash">gsettings <span class="hljs-built_in">set</span> org.gnome.desktop.background picture-uri /path/to/wallpaper.jpg
</code></pre>
<p>Now it’s a matter of adding the sleep and an indefinite loop.</p>
<p>We want to be able to run this script automatically on startup. Clone the components from the <a target="_blank" href="https://github.com/asankaSovis/Wallpaper_Changer">GitHub repo</a>. If you do not know how to clone the repo, you can also download a release from <a target="_blank" href="https://github.com/asankaSovis/Wallpaper_Changer/releases">Releases</a>. It is recommended to download the latest version.</p>
<p>Create a directory in <code>~/Pictures/</code> called <code>Wallpapers</code>. Copy the required wallpapers to this directory.</p>
<p>Copy the <code>change_wallpaper.sh</code> to a convenient location, possibly to your <em>home (</em><code>~</code>) directory. Open a terminal from the copied location. Enter the following command to make the script run automatically on startup.</p>
<pre><code class="lang-bash">SCRIPT_PATH=<span class="hljs-string">"<span class="hljs-variable">$PWD</span>/change_wallpaper.sh"</span>; SERVICE_NAME=<span class="hljs-string">"change_wallpaper.service"</span>; chmod +x <span class="hljs-variable">$SCRIPT_PATH</span>; <span class="hljs-built_in">echo</span> <span class="hljs-string">"[Unit]
Description=My Script
After=network.target

[Service]
ExecStart=<span class="hljs-variable">$SCRIPT_PATH</span>

[Install]
WantedBy=default.target
"</span> | tee ~/.config/systemd/user/<span class="hljs-string">"<span class="hljs-variable">$SERVICE_NAME</span>"</span>; systemctl --user daemon-reload; systemctl --user <span class="hljs-built_in">enable</span> <span class="hljs-string">"<span class="hljs-variable">$SERVICE_NAME</span>"</span>; systemctl --user start <span class="hljs-string">"<span class="hljs-variable">$SERVICE_NAME</span>"</span>
</code></pre>
<p>You have to make sure <strong>not</strong> to run this command with <code>sudo</code> privileges. That should give you a wallpaper slideshow!</p>
<p>Now it would be boring to have a script that doesn’t have any customization options, so I included additional features to the script as well. Adding additional wallpapers is as simple as copying them to the <code>Wallpapers</code> directory. Both JPEG and PNG wallpapers are supported.</p>
<p>You can also customize the script to your liking. Simply open the script in a text editor and change the following variables:</p>
<ol>
<li><p><code>wallpaper_path="/home/$USER/Pictures/Wallpapers"</code> - Wallpaper path: The wallpapers must be in a directory. Enter the directory path here between double quotes. Do <strong>not</strong> enter the path to a file. Make sure to provide an absolute path relative to the root.</p>
</li>
<li><p><code>update_wallpaper_every=10m</code> - Time to update the wallpaper: Replace <code>10m</code> with your own value. This can be given as: s or (no suffix): seconds (default), m: minutes, h: hours, d: days. Decimals and combinations are also accepted. For example: <code>update_wallpaper_every=5</code> : 5 seconds, <code>update_wallpaper_every=5s</code> : 5 seconds, <code>update_wallpaper_every=2m</code> : 2 minutes, <code>update_wallpaper_every=1.5h</code> : 1.5 hours, <code>update_wallpaper_every=7d</code> : 7 days, <code>update_wallpaper_every=1h30m</code> : 1 hour and 30 minutes. It is recommended to provide a time greater than 5 seconds. The script is also not set to persist time every reboot. Therefore might not change the wallpapers properly for higher timeframes.</p>
</li>
<li><p><code>update_list_every=5</code> - Number of times to wait to update the list of images: This will wait until the given number of times of wallpaper updates to update the list of images in the wallpaper path. For example if <code>update_wallpaper_every=10m</code> and <code>update_list_every=5</code>, the list of wallpapers will be updated every 50 minutes.</p>
</li>
</ol>
<p>Further modifications can be done to the script itself if needed.</p>
<p>Now there are cases where you might want to temporarily stop the script or permanently get rid of it. So:</p>
<ol>
<li><p>In case you want to pause the changing of wallpapers, you can create a file called <code>.override</code> inside the same <code>Wallpapers</code> directory which will pause the slideshow indefinitely until the file is deleted again.</p>
</li>
<li><p>You can check the status of the script by using the following command.</p>
</li>
</ol>
<pre><code class="lang-bash">systemctl --user status <span class="hljs-string">"change_wallpaper.service"</span>
</code></pre>
<blockquote>
<p>NOTE: <strong>Do not</strong> run this command with <code>sudo</code>.</p>
</blockquote>
<ol start="3">
<li>The script can be temporarily stopped by killing the script.</li>
</ol>
<pre><code class="lang-bash">sudo <span class="hljs-built_in">kill</span> -9 $(ps -eo pid,<span class="hljs-built_in">command</span> | grep /bin/bash | grep live_wallpaper_script.sh | tr -d <span class="hljs-string">" "</span> | tr <span class="hljs-string">"/"</span> <span class="hljs-string">"\n"</span> | head -n 1)
</code></pre>
<blockquote>
<p>NOTE: <strong>Have to</strong> run this command with <code>sudo</code>.</p>
</blockquote>
<ol start="4">
<li>The script can be permanently stopped and removed by deleting the service file.</li>
</ol>
<pre><code class="lang-bash">SERVICE_NAME=<span class="hljs-string">"change_wallpaper.service"</span>; systemctl --user stop <span class="hljs-variable">$SERVICE_NAME</span>; systemctl --user <span class="hljs-built_in">disable</span> <span class="hljs-variable">$SERVICE_NAME</span>; rm ~/.config/systemd/user/<span class="hljs-string">"<span class="hljs-variable">$SERVICE_NAME</span>"</span>
</code></pre>
<blockquote>
<p>NOTE: <strong>Do not</strong> run this command with <code>sudo</code>.</p>
</blockquote>
<ol start="5">
<li>In case the script is modified, the service can be restarted to pull updates to the script.</li>
</ol>
<pre><code class="lang-bash">systemctl --user restart <span class="hljs-string">"change_wallpaper.service"</span>
</code></pre>
<blockquote>
<p>NOTE: <strong>Do not</strong> run this command with <code>sudo</code>.</p>
</blockquote>
<p>To report bugs and request features, go to <a target="_blank" href="https://github.com/asankaSovis/Wallpaper_Changer/issues">GitHub issues</a> and create a new Issue. Make sure to include the terminal output and a clear explanation of what you were trying to do and what happened. Also, include device information such as the distro and install path. It will take some time to provide support.</p>
<p>Anyone can contribute to this project. If you're a bash programmer, any new features or bug fixes are greatly appreciated. Any suggestions are also appreciated along with documentation improvements. The same goes for any bug reporting and feature suggestions. Also, if you're willing to, consider trying all features of this script in your distro and providing any feedback; especially if you're on a different distro.</p>
<p>I ran the script on Ubuntu 24.10.</p>
]]></content:encoded></item><item><title><![CDATA[Screensavers on Linux - A Nostalgic Revival]]></title><description><![CDATA[A Bit of Context
Whether Linux or Windows, most of us are nostalgic for screensavers. They were not just there to provide any technical requirements but were also a form of art that we loved to enjoy. With time, the requirement for screensavers has f...]]></description><link>https://blog.asankasovis.com/screensavers-on-linux-a-nostalgic-revival</link><guid isPermaLink="true">https://blog.asankasovis.com/screensavers-on-linux-a-nostalgic-revival</guid><category><![CDATA[Screensavers]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Sun, 25 Feb 2024 08:32:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1708849813849/223231ce-3632-47cc-93a3-776dfa074a58.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-a-bit-of-context">A Bit of Context</h1>
<p>Whether Linux or Windows, most of us are nostalgic for screensavers. They were not just there to provide any technical requirements but were also a form of art that we loved to enjoy. With time, the requirement for screensavers has faded away; of course, it's simply better to just blank the screen out anyway. But some of us still love the prospect of the screen turning into a lovely display of electronic art whenever we leave the computer for some time. If you're someone like me, then this tutorial will explain to you how to re-enable screensavers on Linux.</p>
<p>Before we proceed, I'd like to point out that in modern systems, it's probably useless to use a screensaver anyway. Most, if not all displays nowadays will turn themselves off when no signal is present. It's probably better for its durability anyway. On the other hand, it's much safer to just turn off the screen from a cybersecurity perspective. Therefore, please proceed with your caution and responsibility with this tutorial as we're dealing with old technology and we can't guarantee security or reliability. If you're unsure, leave your system as is. But for those of you who are willing to take the risk, let's proceed.</p>
<h1 id="heading-the-xscreensaver">The XScreenSaver</h1>
<p>Since its heydays, Linux has used XScreenSaver to provide the system with screensaver support. However, in 2011, gnome-screensaver version 3 dropped support for screensavers completely, supporting only simple screen blanking. Since then, we simply see the screen blanking itself after the allocated timeout.</p>
<p>However, development for XScreenSaver is still underway and can be easily done on Linux with just a few steps.</p>
<h2 id="heading-installing-the-xscreensaver">Installing the XScreenSaver</h2>
<p>The first step is to install the XScreenSaver on your OS. I am using Ubuntu 23.10 and other Linux distros might have similar steps to what I'm following. In some Ubuntu distros, a program called <code>gnome-screensaver</code> might be present to handle screen blanking. It is important to remove this as it might interfere with the XScreenSaver. To do this, use the following command. In most modern distros, this simply will not even exist; but still, it's better to make sure.</p>
<pre><code class="lang-bash">sudo apt-get remove gnome-screensaver
</code></pre>
<p>The next step is to install the XScreenSaver along with its dependencies.</p>
<pre><code class="lang-bash">sudo apt-get install xscreensaver xscreensaver-data-extra xscreensaver-gl-extra
</code></pre>
<p>This is it! Now the OS will have screensaver support. However, some configurations might need to be done before we call it a day.</p>
<h2 id="heading-changing-a-few-settings">Changing a Few Settings</h2>
<p>If your computer is set to blank after a certain time even when the screensaver is present, is not a good idea. So we will delay the screen blanking time. Go to <strong>Settings &gt; Power</strong> and set the <strong>Screen Blank</strong> to <strong>15 minutes</strong>. This will ensure that the screensaver has plenty of time before the system kicks in and turns off the screen. You can also set it to <strong>Never</strong> but I do not recommend it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708844916826/541e399a-1e19-45e2-ad88-147d8234f25f.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-configuring-the-xscreensaver">Configuring the XScreenSaver</h2>
<p>Out-of-the-box, XScreenSaver is set to start the screensaver after 10 minutes. It will choose a random screensaver and display it on the screen. We'd like to choose the screensaver we like to set as the screensaver. Doing this is easy! If you now check your app drawer, you will see a new app titled <strong>Screensaver.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708845207381/ed6225ee-460a-484a-8be1-5b448dde7b44.png" alt class="image--center mx-auto" /></p>
<p>Open this and you will see the XScreenSaver configuration page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708845255021/b4ec9bfd-b50c-488d-812e-75a6b2bf2d0a.png" alt class="image--center mx-auto" /></p>
<p>Sometimes, you might get a Warning such as the one given below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708845274178/69465130-6920-45b3-a514-25ab9ab5e264.png" alt class="image--center mx-auto" /></p>
<p>Hit <strong>OK</strong> and you will see a prompt like below:</p>
<p><img src="https://i.stack.imgur.com/ViUpu.png" alt="Awful font" class="image--center mx-auto" /></p>
<p>This indicates that the screensaver daemon started.</p>
<p>On the <strong>Screensaver Preferences</strong> page, we can change the preferences for our screensavers. Under <strong>Blank After</strong>, set the number of minutes after which to turn on the screensaver. Also, make sure to uncheck the <strong>Fade to Black when Blanking</strong> and <strong>Fade from Black When Unblanking</strong> options under <strong>Advanced &gt; Blanking</strong> tab. Also, set the <strong>Fade Duration</strong> to 1 second or it takes too much time to show the screensaver.</p>
<p>The most important option, however, is the <strong>Mode:</strong> in the <strong>Display Modes</strong> tab. Change it to <strong>Only One Screen Saver</strong> to enable the screensaver selection. Now in the list below, you can choose your favourite screensaver as the default. Go through them and choose the ones that you prefer.</p>
<p>For me, the <strong>Preview</strong> button does not seem to do anything, however, if you prefer to preview the screensaver, simply click <strong>File &gt; Blank Screen Now</strong> and the screensaver will be displayed on the display.</p>
<p>Optionally, you can change settings on certain screensavers by clicking on <strong>Settings...</strong>. Note that some screensavers might not have the option to change their settings.</p>
<h2 id="heading-starting-the-xscreensaver-daemon-at-startup">Starting the XScreenSaver Daemon at Startup</h2>
<p>If you restart your computer, you'll notice that even after the timeout, the screensaver might not start. The reason is that every time the computer restarts, the XScreenSaver daemon does not run automatically. We will do this by adding a startup entry.</p>
<p>To do this, open the <strong>Startup Applications</strong> from the app drawer and click on <strong>Add</strong> to create a new entry.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708847197955/30b5ff00-106e-4556-9e3f-4bbf0b63da6a.png" alt class="image--center mx-auto" /></p>
<p>Under <strong>Name:</strong> give <code>XScreensaver</code>. Under <strong>Command:</strong> give <code>xscreensaver -no-splash</code> and under <strong>Comment:</strong> give <code>Start screensaver daemon</code>.Press <strong>Add</strong> and then <strong>Close</strong> to close the application.</p>
<p>Now, every time you restart the device, the XScreenSaver daemon will run automatically.</p>
<h2 id="heading-fix-a-little-inconvenience">Fix a Little Inconvenience</h2>
<p>If you use the screensaver for some time, you will notice that even when you watch a movie or a YouTube video, the screensaver starts. This can end up being annoying. Unfortunately, there's no proper way to prevent this. But, there's a small hack that we can do to make sure this doesn't happen in most cases.</p>
<p>The trick is to create a bash script that checks if an application is running full screen and disable the daemon if it sees one. This is only a partial fix as whenever you're playing a video without going full-screen, the screensaver will turn on regardless. We will have to deal with it, unfortunately. However, in most cases, we will be doing something on our computer while something is playing without the full-screen mode and it should be fine.</p>
<p>All kudos should go to <a target="_blank" href="https://askubuntu.com/users/231142/terrance">Terrance</a> on <a target="_blank" href="https://askubuntu.com">askubuntu.com</a> for coming up with this ideal solution. The workaround below is from the answer he gave to a question titled <a target="_blank" href="https://askubuntu.com/questions/778688/when-i-watch-a-video-online-the-screen-turns-off-after-a-few-minutes/778817#778817">When I watch a video online the screen turns off after a few minutes</a>, with a few modifications on the terminal.</p>
<p>First, we will install <code>xdotool</code>.</p>
<pre><code class="lang-bash">sudo apt install xdotool
</code></pre>
<p>Then, we will create a folder to save our script.</p>
<pre><code class="lang-bash">mkdir -p ~/.scripts
</code></pre>
<p>In this folder, we will create a bash script file.</p>
<pre><code class="lang-bash">nano ~/.scripts/check_full.bsh
</code></pre>
<p>This will open a nano terminal to type the bash script. In it, paste the following script:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-comment">#Get DPMS settings</span>
dpms_set=$(xset -q | awk <span class="hljs-string">'/DPMS is/ {print $NF}'</span>)

<span class="hljs-comment">#Get screensaver type and command</span>
scrnsvr=<span class="hljs-string">'/usr/bin/xscreensaver'</span>
scrnsvrcmd=<span class="hljs-string">'/usr/bin/xscreensaver -no-splash'</span>

<span class="hljs-comment">#Sleep Timer in seconds.</span>
SL=300

<span class="hljs-keyword">while</span> <span class="hljs-literal">true</span>;
<span class="hljs-keyword">do</span>
result=()
<span class="hljs-comment">#Get all window geometries</span>
all=($(xdotool search --name - | <span class="hljs-keyword">while</span> <span class="hljs-built_in">read</span> win; <span class="hljs-keyword">do</span> xdotool getwindowgeometry <span class="hljs-variable">$win</span> | awk <span class="hljs-string">'/Geometry/ {print $2}'</span>; <span class="hljs-keyword">done</span>))

<span class="hljs-comment">#Get all screen resolutions detected and build array.</span>
SCREENS=($(xrandr | awk <span class="hljs-string">'/\*/ {print $1}'</span>))

SCRN=<span class="hljs-string">" <span class="hljs-variable">${SCREENS[*]}</span> "</span>

<span class="hljs-comment">#Get result of all windows and match</span>

<span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> <span class="hljs-variable">${all[@]}</span>; <span class="hljs-keyword">do</span> <span class="hljs-keyword">if</span> [[ <span class="hljs-variable">$SCRN</span> =~ <span class="hljs-string">" <span class="hljs-variable">$item</span> "</span> ]] ; <span class="hljs-keyword">then</span> result+=(<span class="hljs-variable">$item</span>); <span class="hljs-keyword">fi</span>; <span class="hljs-keyword">done</span>

<span class="hljs-comment">#If a result exists disable power management and screensaver</span>
<span class="hljs-keyword">if</span> [[ <span class="hljs-variable">${result[@]}</span> ]]; <span class="hljs-keyword">then</span>
    ps -ef | grep <span class="hljs-variable">$scrnsvr</span> | grep -v grep &gt;/dev/null
    <span class="hljs-keyword">if</span> [[ $? == 0 ]]; <span class="hljs-keyword">then</span> 
    <span class="hljs-built_in">kill</span> $(ps -ef | grep <span class="hljs-variable">$scrnsvr</span> | grep -v grep | awk <span class="hljs-string">'{print $2}'</span>)
    <span class="hljs-keyword">fi</span>
    <span class="hljs-keyword">if</span> [[ <span class="hljs-variable">$dpms_set</span> == <span class="hljs-string">"Enabled"</span> ]];<span class="hljs-keyword">then</span>
    xset -dpms
    <span class="hljs-keyword">fi</span>
<span class="hljs-keyword">else</span>    
    ps -ef | grep <span class="hljs-variable">$scrnsvr</span> | grep -v grep &gt;/dev/null
    <span class="hljs-keyword">if</span> [[ $? == 1 ]]; <span class="hljs-keyword">then</span>
    <span class="hljs-variable">${scrnsvrcmd}</span> &amp;
    <span class="hljs-keyword">fi</span>
    <span class="hljs-keyword">if</span> [[ <span class="hljs-variable">$dpms_set</span> != <span class="hljs-string">"Disabled"</span> ]];<span class="hljs-keyword">then</span>
        xset dpms
        <span class="hljs-keyword">fi</span>
<span class="hljs-keyword">fi</span>
result=()
sleep <span class="hljs-variable">$SL</span>
<span class="hljs-keyword">done</span>
</code></pre>
<p>You might need to change the <code>SL=300</code> value depending on what the screensaver start time is set to. I have set it as 10 minutes; which is 600 seconds. So I chose this value to be 300 as it's half the screensaver start time. This allows the script to correctly detect the presence of a full-screen app without compromising performance.</p>
<p>Save this by pressing the key sequence <strong>Ctrl + X &gt; Y &gt; Enter</strong>.</p>
<p>Try running the script by entering the following command:</p>
<pre><code class="lang-bash">~/.scripts/check_full.bsh
</code></pre>
<p>If you get an error that looks like below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708848738447/33ae05c0-a0bc-4d94-98a7-77f22f9296f1.png" alt class="image--center mx-auto" /></p>
<p>Enter the command:</p>
<pre><code class="lang-bash">chmod +x ~/.scripts/check_full.bsh
</code></pre>
<p>This will mark the script as executable. Now run the script again from the previous command and it should show like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708848838215/61eb1f5b-25c5-4b52-9364-192881e20ec5.png" alt class="image--center mx-auto" /></p>
<p>This indicates that the script is running and working. If it throws any errors, you will need to double-check the script.</p>
<p>You can press <strong>Ctrl + C</strong> and close the terminal.</p>
<p>Next, we will set this script to also start automatically every time we turn on the computer. As before, open the <strong>Startup Applications</strong> from the app drawer and click on <strong>Add</strong> to create a new entry. Under <strong>Name:</strong> give <code>Check_Full</code>. Under <strong>Command:</strong> give <code>bash -c 'sleep 5 &amp;&amp; /home/asanka/.scripts/check_full.bsh'</code> and under <strong>Comment:</strong> give <code>Prevent screensaver from activating when full screen video is playing</code>. Press <strong>Add</strong> and then <strong>Close</strong> to close the application.</p>
<p>Now, every time you restart the device, the script to check for full-screen applications will run automatically.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Screensavers, once a well-known feature of retro computers, have seen their role fade away in the modern days. While their original purpose of preventing screen burn-in on CRT monitors is no longer relevant with today's displays, screensavers still have some benefits and will always hold a nostalgic charm for many of us enthusiasts.</p>
<h1 id="heading-resources">Resources</h1>
<ul>
<li><p><a target="_blank" href="https://askubuntu.com/questions/778688/when-i-watch-a-video-online-the-screen-turns-off-after-a-few-minutes/778817#778817">'When I watch a video online the screen turns off after a few minutes' post on askubuntu.com</a></p>
</li>
<li><p><a target="_blank" href="https://www.unixmen.com/installing-xscreensaver-ubuntu/">Installing XScreenSaver In Ubuntu article on Unixmen</a></p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/XScreenSaver">Article about XScreenSaver on wikipedia.org</a></p>
</li>
<li><p><a target="_blank" href="https://www.jwz.org/xscreensaver/">Official XScreenSaver homepage</a></p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Screensaver">Article about screensavers on wikipedia.org</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Fixing the Issue with Some AppImages not Running on Modern Linux]]></title><description><![CDATA[A Bit of Context
Nowadays, Linux has several packaging methods that allow cross-compatibility among different Linux distros. All of them come with their ups and downs and choosing the one that chooses you is important. But sometimes, we don't have an...]]></description><link>https://blog.asankasovis.com/fixing-the-issue-with-some-appimages-not-running-on-modern-linux</link><guid isPermaLink="true">https://blog.asankasovis.com/fixing-the-issue-with-some-appimages-not-running-on-modern-linux</guid><category><![CDATA[Ubuntu]]></category><category><![CDATA[Linux]]></category><category><![CDATA[appimage]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Sun, 21 Jan 2024 15:22:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1705850457568/00e42df8-e34c-42fd-b329-eabd925e9056.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-a-bit-of-context">A Bit of Context</h1>
<p>Nowadays, Linux has several packaging methods that allow cross-compatibility among different Linux distros. All of them come with their ups and downs and choosing the one that chooses you is important. But sometimes, we don't have any other option but to use an application that comes in a specific packaging format.</p>
<h1 id="heading-appimages-a-powerful-packaging-format-but-with-a-flaw">AppImages - A Powerful Packaging Format... But with a Flaw</h1>
<p>AppImages are one such format for distributing software on Linux that doesn't require installation. They're essentially self-contained applications that run on most Linux distributions without needing superuser privileges. This makes them a great option for users who want to try out new software without having to worry about messing up their system, or for developers who want to distribute their software more easily.</p>
<p>AppImages are a powerful packaging format but a major issue exists with its use of the <code>libfuse2</code> library. <code>libfuse2</code> is a library that allows user-space programs to interact with the Linux kernel's filesystem. Some AppImages rely on it for features like virtual filesystems or encrypted storage. However, starting with Ubuntu 22.04 and other distributions <code>libfuse2</code> is no longer included by default. This is due to security concerns and technical limitations of the older library version.</p>
<p>Developers are encouraged to upgrade to the latest libfuse3 but some programs have still not upgraded their programs to the <code>libfuse3</code> library. This makes these AppImages unusable in modern Linux versions.</p>
<h1 id="heading-the-problem">The Problem</h1>
<p>If you try to double-click these AppImages, you might notice that they do not result in anything. In this article, I will use the <a target="_blank" href="https://www.nordicsemi.com/Products/Development-tools/nrf-connect-for-desktop"><strong>nRF Connect for Desktop</strong></a> as an example since as of writing this article, it still doesn't work for modern distributions such as mine: Ubuntu 23.10. We can see the actual problem by running it in the terminal.</p>
<p>To do this, navigate to the folder with the downloaded AppImage from Nautilus and right-click on it to select <em>Open in Terminal</em>. On the terminal, typing the name of the package and pressing enter will attempt to run the program from the terminal which will throw the following error.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703482256835/4cc9c1fd-5fbf-4816-8190-c426ad1b4369.png" alt="libfuse2 Error" class="image--center mx-auto" /></p>
<h1 id="heading-the-solution">The Solution</h1>
<p>The solution provided in this message is to install <code>libfuse2</code> using the following command.</p>
<pre><code class="lang-bash">sudo add-apt-repository universe
sudo apt install libfuse2
</code></pre>
<p>However, if you're on an Ubuntu version on or above 22.04 <strong><mark>DO NOT ATTEMPT TO DO THIS</mark></strong> as it <strong><mark>WILL BREAK YOUR SYSTEM</mark></strong>. If done, you will have to reinstall the whole desktop environment as well as all the installed applications. At this point, reinstalling the system is the best option.</p>
<p>But there is a simple and elegant workaround for this issue. This is to unpack the AppImage and run it by executing the script. This has the added advantage of bypassing the need for the operating system to mount a separate filesystem to extract and run the AppImage every time it's executed.</p>
<p>The way you can do this is to enter the following command after opening the terminal in the folder with the AppImage.</p>
<pre><code class="lang-bash">chmod +x ./nrfconnect-4.3.0-x86_64.appimage
./nrfconnect-4.3.0-x86_64.appimage --appimage-extract
</code></pre>
<p>I'd recommend creating a new folder in your home directory like '<em>AppImages'</em> and copying the AppImage there before extracting the AppImage in this folder using the above command. Now within this extracted folder, you will find the contents of the app.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703427102357/3c426b06-3935-4586-853d-32bb730e7a6b.png" alt="Extracted folder of the AppImage" class="image--center mx-auto" /></p>
<p>Now first open another terminal in this folder and enter the following command to execute the program.</p>
<pre><code class="lang-bash">./AppRun
</code></pre>
<p>If this results in the file opening in a text editor, enter the following command first to change the file to executable.</p>
<pre><code class="lang-bash">sudo chown +x ./AppRun
</code></pre>
<p>You will see that the app runs without an issue.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703427497022/968badec-234d-49af-913f-5fda86850c41.png" alt="App Running after the Extraction" class="image--center mx-auto" /></p>
<h1 id="heading-make-an-elegant-way-to-launch-the-application">Make an Elegant way to Launch the Application</h1>
<p>We can also make the application appear in the App Launcher menu as an entry. To do this, we will rename the folder in which the <em>AppRun</em> file exists to something convenient. In this case, I have already renamed it to <em>nRF</em>.</p>
<p>Now navigate to User Home &gt; <em>.local</em> &gt; <em>share</em> &gt; <em>applications</em>. If <em>.local</em> is not visible, press CTRL + H to reveal hidden files and folders. In this, open a terminal window and use the following command to create a new desktop entry.</p>
<pre><code class="lang-bash">sudo nano <span class="hljs-string">'nRF Connect.desktop'</span>
</code></pre>
<p>You can use any name for the application name. Make sure to use only letters and numbers along with spaces to reduce conflicts and end the name with <em>.desktop</em> as given. This will open the nano text editor. In it, paste the following. Make sure that the paths in <code>Exec</code> and <code>Icon</code> point to the correct locations.</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/usr/bin/env xdg-open</span>
[Desktop Entry]
Version=1.0
Type=Application
Terminal=<span class="hljs-literal">false</span>
Exec=/home/asanka/AppImages/nRF/AppRun
Name=nRF Connect Desktop
Comment=nRF Connect Desktop
Icon=/home/asanka/AppImages/nRF/nrfconnect.png
</code></pre>
<p>Here, you can include the path to the AppRun file of your specific application under <code>Exec</code>. The <code>Name</code> and <code>Comment</code> should be the app name that should appear in the launcher. The Icon should point to a PNG of the application. The AppImages usually come with an icon, however, if you do not have one, simply download the logo of the application as a PNG image and copy it into that application directory.</p>
<p>Now save the file by pressing CTRL + X &gt; <em>Y</em> &gt; Enter. Then if you check your launcher, you will see the application icon. Clicking on it will run the program.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703429291241/0165acba-7692-4cc3-970f-55ae039bae21.png" alt="nRF Connect Desktop on the App Launcher" class="image--center mx-auto" /></p>
<h1 id="heading-reference">Reference</h1>
<ul>
<li><p><a target="_blank" href="https://www.nordicsemi.com/Products/Development-tools/nRF-Connect-for-Desktop/Download#infotabs">nRF Connect Desktop Download</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/AppImage/AppImageKit/wiki/FUSE">AppImage FUSE Requirement Details</a></p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Filesystem_in_Userspace">Wikipedia Article on FUSE</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/libfuse/libfuse">libfuse GitHub Repository</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/OpenShot/openshot-qt/issues/4789">Ubuntu 22.04: Appimage doesn't start : libfuse.so.2: cannot open shared object file: No such file or directory - Issue on openshot-qt Github Repository</a></p>
</li>
<li><p><a target="_blank" href="https://linuxconfig.org/how-to-create-desktop-shortcut-launcher-on-ubuntu-22-04-jammy-jellyfish-linux">How to create desktop shortcut launcher on Ubuntu 22.04 Jammy Jellyfish Linux - LinuxConfig.org</a></p>
</li>
<li><p><a target="_blank" href="https://appimage.org/">Official AppImages Site</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Setting Up the Sinhala Keyboard on Ubuntu/Linux]]></title><description><![CDATA[As the native language of Sri Lanka, Sinhala typesetting is crucial to any Sri Lankan. However, Sinhala language support had been minimal in most operating systems until recently. However, Sinhala support in Windows has improved considerably with Win...]]></description><link>https://blog.asankasovis.com/setting-up-the-sinhala-keyboard-on-ubuntulinux</link><guid isPermaLink="true">https://blog.asankasovis.com/setting-up-the-sinhala-keyboard-on-ubuntulinux</guid><category><![CDATA[Ubuntu]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Sat, 20 Jan 2024 13:39:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1705757848880/0aeac1aa-62d0-465e-a7c6-c84ae1750fd2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As the native language of Sri Lanka, Sinhala typesetting is crucial to any Sri Lankan. However, Sinhala language support had been minimal in most operating systems until recently. However, Sinhala support in Windows has improved considerably with Windows 10. However when it comes to Linux, even though the support is appreciatable, the typesetting in Sinhala is still a bit clunky. But even though the out-of-the-box experience for Sinhala is imperfect, we can still use external methods to easily set Sinhala language support perfectly. In this short article, we will discuss how.</p>
<h1 id="heading-installing-the-helakuru-sinhala-package">Installing the Helakuru Sinhala Package</h1>
<p>From my experience, the Helakuru package contains the best Sinhala support at the moment, and it's also straightforward to set up. Simply visit the <a target="_blank" href="https://www.helakuru.lk/download/?fid=bGludXhfcA==&amp;key=1703386486-key65879d764b5c82.92017782">link given</a> here to download the Debian package. For other Linux packaging types, visit <a target="_blank" href="https://www.helakuru.lk/">this link</a> and choose your preferred distribution.</p>
<p>Extract the downloaded zip file and within this, you will find the Debian installer as '<em>helakuru.deb</em>' or like.</p>
<p>Now you can double-click this Debian package to open the software centre. If it doesn't open the package in the software centre, right-click and choose '<em>Open With...</em>' Now choose '<em>Software Install</em>' and click <em>Open</em>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703392966084/12e43aad-225a-4a00-9e0d-d6eaa290b8c3.png" alt="Open File Dialog Box - Ubuntu 23.10" class="image--center mx-auto" /></p>
<p>Click on Install and it will deploy Sinhala keyboard support on Linux.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703393457203/1aed3d98-b04f-4077-b496-4cc079c6b782.png" alt="Software Install after the Helakuru Debian file is installed" class="image--center mx-auto" /></p>
<p>Now log out of the device and log back in to activate the changes on the device. Now if you go into <em>Settings</em> &gt; <em>Keyboard</em> &gt; <em>Input Sources</em> &gt; <em>Add an Input Source</em> (+ Sign), you will see <em>Sinhala</em> as an input method.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703393695575/d98db402-d25a-4b99-a97e-bb9fc19b5850.png" alt="Sinhala as an option in Keyboard" class="image--center mx-auto" /></p>
<p>If you click on <em>Sinhala</em>, you will find multiple entries of Sinhala language installed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703393879861/b92375ab-0dad-41c7-a3e0-36402e53e4d6.png" alt="Sinhala entries in Input Sources" class="image--center mx-auto" /></p>
<p>The most familiar options out of these would be Wijesekara (<em>Sinhala (si-helakuru-wijesekara (m17n)</em>) and Phonetic (<em>Sinhala (si-helakuru-phonetic (m17n)</em>). Clicking on either of these and clicking on <em>Add</em> will add these as an input language. Now if you click on the small language icon that appears on the command panel, you will find the selected language preferences appear.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703393949339/dcdb060b-ac17-4049-8db8-289b0f5580ae.png" alt="Language Selection on Command Panel" class="image--center mx-auto" /></p>
<p>You can add, remove or change these keyboard layouts by clicking on <em>Keyboard Settings</em> in the above menu. Unfortunately, clicking on Show <em>Keyboard Layout</em> will only display the English (US) keyboard layout. However, in case you need to manually select characters from a menu, you can use the <em>Character Map</em> application. This is generally installed by default on major Linux distributions. If not, you can find it in your respective Application Store.</p>
<p>Launching this application and selecting Sinhala under Scripts, will allow you to select and copy any Sinhala character to your clipboard.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703394565011/04bf72e2-9351-41f0-bddb-f617daf551c3.png" alt="Character Map" class="image--center mx-auto" /></p>
<p>With this, you can type in Sinhala.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703394681525/40708d01-c668-4b61-a8bf-1965da7fcef9.png" alt="Typing in Sinhala" class="image--center mx-auto" /></p>
<h1 id="heading-lk-slug-sinhala-language-pack">LK-SLUG Sinhala Language Pack</h1>
<p>However, there exists another method to set up Sinhala language support used in the past. This is the LK-SLUG language pack. This comes with fonts as well as the keyboard layout. However in my experience, for modern Ubuntu systems, this method is not that applicable. The layout is a bit different from the modern Sinhala layouts we find today such as Singlish, Phonetic and Wijesekara. But if required, this option is also available.</p>
<p>To install the LK-SLUG Sinhala language pack, enter the following command in the terminal.</p>
<pre><code class="lang-bash">sudo apt-get install fonts-lklug-sinhala ibus im-switch ibus-m17n m17n-db m17n-contrib language-pack-si-base
</code></pre>
<p>Enter your password if prompted and press enter. Once installed, you can log out; log back in and go to settings as we discussed before. If all goes well, you will see similar layouts under <em>Add an Input Source</em> including a few more options.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703422697313/091cdf81-fa69-4b09-acf7-be6c2b2e8808.png" alt="Add an Input Source Menu" class="image--center mx-auto" /></p>
<p>This will conclude the Sinhala language setup in modern Ubuntu systems. සිංහල භාෂාව සමඟ ඉදිරියට ලේඛන කරන ඔබට සුභ දවසක්.</p>
<h1 id="heading-references">References</h1>
<ul>
<li><p><a target="_blank" href="https://askubuntu.com/questions/105544/install-sinhala-unicode-pack">install sinhala unicode pack - AskUbuntu</a></p>
</li>
<li><p><a target="_blank" href="https://askubuntu.com/questions/459349/sinhala-unicode-wijesekara-keyboard-in-ibus-on-ubuntu-14-04-not-working">Sinhala unicode (Wijesekara keyboard) in iBus on Ubuntu 14.04 not working - AskUbuntu</a></p>
</li>
<li><p><a target="_blank" href="https://askubuntu.com/questions/1275466/how-to-install-wijesekara-sinhala-keyboard">How to install WIjesekara Sinhala keyboard? - AskUbuntu</a></p>
</li>
<li><p><a target="_blank" href="https://pariganakalipi.blogspot.com/2014/08/InstallingSinhalaFORUbuntu.html">Ubuntu සදහා සිංහල Install කරමු - පරිගණක ලිපි</a></p>
</li>
<li><p><a target="_blank" href="https://groups.google.com/g/Sinhala-Unicode/c/TEozgIPIIaY?pli=1">Sinhala input on Ubuntu 20.04 - Google Groups</a></p>
</li>
<li><p><a target="_blank" href="https://www.helakuru.lk/">Helakuru Download</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[A Bit of Context...]]></title><description><![CDATA[Hello 👋,
I have been a huge proponent of open-source software. Yet, I have always used Windows as my operating system. However, I tried several times to switch to Ubuntu, but they all failed due to a lack of experience and my workflows being too rel...]]></description><link>https://blog.asankasovis.com/a-bit-of-context</link><guid isPermaLink="true">https://blog.asankasovis.com/a-bit-of-context</guid><category><![CDATA[Linux]]></category><category><![CDATA[Windows]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Sun, 22 Oct 2023 16:47:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1697992664014/9642a12e-3735-40f6-8e9f-6dfd011ab185.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello 👋,</p>
<p>I have been a huge proponent of open-source software. Yet, I have always used Windows as my operating system. However, I tried several times to switch to Ubuntu, but they all failed due to a lack of experience and my workflows being too reliant on Windows. Times have changed and I find it even more important to switch to the Linux ecosystem.</p>
<p>When I first started, I found it hard to find any detailed resources for anyone willing to make the switch. However, with time I have acquired a substantial amount of experience on Linux and the project has improved quite a lot to accommodate new users; not to mention the ever-growing ecosystem of compatible software.</p>
<h1 id="heading-but-why-now">But Why Now?</h1>
<p>There are several reasons why I wanted to take the decision. An important one is the fact that Windows has become more and more cluttered over time. I use Windows 11 and it feels so heavy on my hardware. Even after cleaning the hard disk and making sure not to have any virus or malware, the OS starts to feel laggy. With support for Windows 10 coming to an end soon; and the fact that I hate the aesthetics of Windows 10, I do not like to switch to Windows 10.</p>
<p>Another point to make is the interface design. Windows 11 is much better compared to the Windows 10 interface, however, I still find these inconsistencies not pleasing to the eye. Maybe I simply need a change to a different experience altogether. I have always loved the gnome interface and the new Ubuntu 23.10 design caught my eye. This is also a reason why I am willing to try again.</p>
<p>Windows XP and 7 were great operating systems at the time. But since then, Microsoft continued to disappoint. They've diverted into different business models that are harder and harder for me to keep up. With rumours of a subscription-based OS, it's not going to be affordable for me to continue using Windows. Overall, I don't find the philosophy behind Windows appealing anymore.</p>
<h1 id="heading-a-bit-of-context">A Bit of Context</h1>
<p>I have worked with Linux for quite a while now. Even my work laptop is running Linux and my office workflows have become completely reliant on Ubuntu. Still, my personal laptop had always been Windows. The biggest issue had been the workflows that I've been used to. Some of these require programs running only on Linux. On the other hand, I've been used to the interface since my childhood. Breaking these habits will need time.</p>
<h1 id="heading-the-approach">The Approach</h1>
<p>I have several key workflows that I follow. The first step would be to identify these workflows. This allows me to identify programs that require alternatives on Linux. Next would be to try replacing them on Windows itself. If not possible, I'll have to identify ways to run them on Linux.</p>
<p>Once This step is complete, I'll prepare the laptop by moving all my data out of the Windows partition into another partition and linking those paths to Windows libraries. This allows me to install Ubuntu into a new partition and share the data between both OS. This way, I will not run into document issues.</p>
<p>With both OS available, I'll try to move each workflow into Ubuntu. Once I'm confident that the transition is complete, I'll remove Windows completing the transition.</p>
<h1 id="heading-final-thoughts">Final Thoughts</h1>
<p>This is just an idea that I've been having for quite some time. The reason that I started this series is to document all the steps I follow in this journey. Maybe I might succeed, or maybe I won't, but either way, I have a feeling that some of the research I'll provide will be helpful to someone in the future. I don't have a deadline for this series and I prefer to take as much time as I require. Thus, I'm not sure when the next update will arrive. Until then...</p>
<p>Cheers 🎉</p>
]]></content:encoded></item><item><title><![CDATA[#2 The nRF7002, Zephyr and the Nordic Platform - Prometheus v2.0 Devlog]]></title><description><![CDATA[Hello 👋,
Before getting too carried away with the project, I wanted to do a bit of research on the platform that I'm dealing with. So I did a bit of research on the nRF development kits and the Nordic SoCs. The results I found were interesting and I...]]></description><link>https://blog.asankasovis.com/2-the-nrf7002-zephyr-and-the-nordic-platform-prometheus-v20-devlog</link><guid isPermaLink="true">https://blog.asankasovis.com/2-the-nrf7002-zephyr-and-the-nordic-platform-prometheus-v20-devlog</guid><category><![CDATA[Matter]]></category><category><![CDATA[fire extinguisher]]></category><category><![CDATA[iot]]></category><category><![CDATA[Nordic Semiconductor]]></category><category><![CDATA[hackster.io]]></category><dc:creator><![CDATA[Asanka Akash Sovis]]></dc:creator><pubDate>Sat, 21 Oct 2023 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1699195375667/85c99c67-7cae-46fa-91e7-c67d541c17a3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello 👋,</p>
<p>Before getting too carried away with the project, I wanted to do a bit of research on the platform that I'm dealing with. So I did a bit of research on the nRF development kits and the Nordic SoCs. The results I found were interesting and I wanted to share them.</p>
<p>The first is about nRF. I managed to get the nRF development environment up and running which I consider to be a huge milestone. The process was quite simple and required little to no effort. I simply followed the <a target="_blank" href="https://www.nordicsemi.com/Products/Development-hardware/nRF7002-DK/GetStarted">tutorial</a> provided by Nordic themselves.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699193418892/59b3dcc0-0297-423d-8d0e-25a7d76eee7e.png" alt class="image--center mx-auto" /></p>
<p>After this, my next plan was to get the blinky LED sample from Zephyr up and running. This was also not that complicated. I did follow a small <a target="_blank" href="https://youtu.be/rvDdev18PAI?si=WIrH7iT6G-aEPwPf">tutorial</a> which helped to understand what I'm doing, especially since I don't have prior experience with Zephyr. This worked out well and I had the LED blinking.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699194172693/7906e994-4881-453d-9be7-feeab3c41934.png" alt class="image--center mx-auto" /></p>
<p>There are several ways to program the nRF board but I decided to go with the device tree and Zephyr OS method. This is much simpler and platform-independent which is ideal in my scenario.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699194702031/7ae78c8f-9541-41e5-a3f1-cae40723c7d9.gif" alt class="image--center mx-auto" /></p>
<p>In the next article, I plan to discuss a bit about the hardware design.</p>
<p>Until then... Cheers! 🎉</p>
<h1 id="heading-reference">Reference</h1>
<ul>
<li><p><a target="_blank" href="https://www.nordicsemi.com/Products/Development-hardware/nRF7002-DK/GetStarted">Getting Started guide for nRF7002 DK</a></p>
</li>
<li><p><a target="_blank" href="https://youtu.be/rvDdev18PAI?si=WIrH7iT6G-aEPwPf">Zephyr/nRF Blinky Tutorial</a></p>
</li>
<li><p><a target="_blank" href="https://youtube.com/playlist?list=PLoKOKJqgqHs9mReagSVnB8FAQBJuRMCEt&amp;si=-6g6zJYnovS3XYu0">Zephyr and nRF Connect SDK</a></p>
</li>
<li><p><a target="_blank" href="https://youtube.com/playlist?list=PLJKv3qSDEE-nZi9wWubnpYUiUBRTyRPrN&amp;si=_kjNp_sdAmete2XT">Zephyr: Tidbits</a></p>
</li>
</ul>
]]></content:encoded></item></channel></rss>