Error Handling in Rust

Unrecoverable errors

These errors are a sign that the developer made a mistake. An example of this, could be trying to access an index that is out of bounds. For example:

1
2
3
4
5
6
7
8
fn get_number() -> usize {
    return 5;
}

fn main() {
    let numbers = [1, 2];
    println!("{}", numbers[get_number()]);
}
Read More

Sending E-mails From Rust With Brevo

I’m building a little web server with Rust and as part of it, I’m going to need to send some e-mails to my users. I found a few services that offer an e-mail API with a free tier, and decided to go with Brevo.

Authenticating our domain

In order for our e-mails to reach our users’ inboxes, we need to correctly configure our DKIM and DMARC records so they can be used by Brevo.

We can’t authenticate e-mails from free email providers like Gmail. So, before we can authenticate our domain, we need to own a domain. I’m going to use my blog’s domain (ncona.com).

Read More

Voltage Dividers for Logic Level Shifting

I’m building a project for an ESP32 microcontroller (which works with 3.3v logic), and my project needs to get information from a 5v sensor.

Connecting the 5v directly to a GPIO (General Purpose Input/Output) pin would probably damage the chip. To prevent this, we can use a voltage divider to lower the voltage.

Voltage dividers

A voltage divider is a simple circuit that given an input voltage, it produces a lower output voltage. A simple representation looks like this:

Simple voltage divider

Read More

Open Collector Output

I’m working on a circuit where I need to use a sensor that mentions using an open collector (Also known as: open drain, open emitter or open source) output. In this post, we are going to learn what this is and how to use open collector components.

The term open in open collector refers to an “open” digital circuit. Which means that a pin in our component is not connected to a HIGH or a LOW signal. It is, effectively, undefined.

When we have an open collector output, the output will toggle between LOW and undefined. This happens, because of the way the component is connected internally, which often looks like this:

Read More

Handling Interrupts With ESP-IDF

Interrupts

Interrupts are a way to achieve concurrency when working with microcontrollers.

An interrupt allows us to “interrupt” the current execution of a program in order to do a different task. This is usually achieved by instructing the microcontroller to look for level changes (From high to low or from low to high) on a GPIO pin and executing a function when that happens.

Interrupt Service Routines (ISR)

ISRs are callback functions that are executed when an interrupt is triggered. They should be made very fast and simple, because they block the execution of other parts of the system.

They are special in that they can’t block execution waiting for a lock and then resume when the lock is available. If we try to hold a mutex within an ISR, the program will crash. For this reason, many ESP-IDF functions (e.g. ESP_LOG functions) can’t be used inside an ISR.

Read More

Pull Up and Pull Down Resistors

If you need a reminder about resistors in general, you can take a look at my resistors article.

Floating pins

Pull resistors are used to solve the problem of floating pins, so let’s briefly explain what that is.

In the following diagram, we have a simple IC (Integrated Circuit) that works with 5V and has a single GPIO (General Purpose Input/Output) pin:

Floating Pin IC

Read More

Unit Testing Code for ESP32

In my previous article, we learned how to build a stand-alone library for esp-idf. In this article we are going to learn how to write unit tests for our code so we can have confidence it does what we want it to do.

There are a few ways we can go about unit testing code written for ESP32:

  • Run tests directly on ESP32 board
  • Run tests using an emulator
  • Run tests on Linux host using mocks

We are going to learn how to write tests that can run on a Linux host, so it’s easy to plug them to a CI system.

Read More

Building a Stand-Alone Library for ESP-IDF

In a previous post, we learned how to modularize software written with esp-idf. The article mentions how we can use the components folder to create different modules.

In this article, we are going to use that knowledge to build a stand-alone library that can live in an independent git repo and can be consumed by different projects.

Example project

ESP-IDF doesn’t support building libraries by themselves, so the only way we can make sure our library is built is by shipping the library with an example project that depends on our library.

Since we also want our library to be easily consumable by other projects, our repo should follow this layout:

1
2
3
4
5
6
7
8
9
10
11
12
13
library-root/
├─ CMakeLists.txt
├─ src/
│  ├─ library.cpp
│
├─ include/
│  ├─ library.hpp
│
├─ example/
│  ├─ CMakeLists.txt
│  ├─ main/
│     ├─ CMakeLists.txt
│     ├─ example.cpp
Read More

Configuring ESP32 to act as Access Point

In a previous article we learned how to use ESP32 as a WiFi client. If you haven’t I recommend you take a look at that article, since there are some steps in common that I’m not going to cover in much depth here.

Initialize WiFi

When we are creating a client or and Access Point, we need to initialize NETIF and create the default event loop:

1
2
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());

To initialize our WiFi interface as an Access Point, we need to call:

1
esp_netif_create_default_wifi_ap();
Read More

B-Trees - Database storage internals

Some of the most popular databases out there (PostgreSQL, MySQL, MongoDB, etc) use b-trees for their indexes. In this article, we’re going to learn how they work and understand why they are used.

Files

Before we understand how databases store information, we need to understand how computers store information.

When we want to persist data, we use the file system API. This API allows us to open files for reading, writing or appending. When a file is opened, it’s loaded into memory. Once the data is in memory, we can access bytes sequentially or in any order we desire (Random Access).

Read More