Yanis MacAnas benalla
Published

Colibry Forest Sentinel

Ultra-low-power AI device that detects chainsaw sounds in forests to fight illegal logging.

IntermediateWork in progress145
Colibry Forest Sentinel

Things used in this project

Hardware components

ColibryNPU
×1
MIKROE LR IoT Click
×1
SenseCAP M2 Multi-Platform LoRaWAN Indoor Gateway(SX1302) - EU868
Seeed Studio SenseCAP M2 Multi-Platform LoRaWAN Indoor Gateway(SX1302) - EU868
×1

Software apps and online services

Helium LoRa Network
Optional

Story

Read more

Code

main.c

C/C++
"driver_colibry.h" is provided by the board manufacturer
#include "lriot_chainsaw.h"
#include "driver_colibry.h"
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

#define AUDIO_BLOCK_SIZE 128
#define FFT_SIZE         256
#define NPU_THRESHOLD    0.5f

// --- Circular buffer for DMA I2S ---
float audio_circ_buffer[FFT_SIZE];
volatile int dma_write_index = 0;  // Updated by DMA ISR
volatile bool fft_ready = false;    // Set by DMA ISR when buffer is full

float fft_output[FFT_SIZE];

// --- DMA callback stub ---
// This function should be called by the DMA interrupt
void i2s_dma_half_full_callback(const float *dma_buffer, int len)
{
    // Copy new samples into the circular buffer
    for (int i = 0; i < len; i++) {
        audio_circ_buffer[dma_write_index++] = dma_buffer[i];
        if (dma_write_index >= FFT_SIZE) {
            dma_write_index = 0;
            fft_ready = true;  // Full buffer ready for FFT
        }
    }
}

// --- Main ---
int main(void)
{
    // --- Initialize peripherals ---
    i2s_init_dma(audio_circ_buffer, FFT_SIZE); // DMA-based I2S, double-buffering
    fft_init(FFT_SIZE);
    npu_init();
    if (npu_load_model("chainsaw.nnpa") != 0) {
        printf("[NPU] Failed to load model\n");
        return -1;
    }

    if (lriot_chainsaw_init() != 0) {
        printf("[LoRaWAN] Init failed\n");
        return -1;
    }

    printf("[System] DMA-based pipeline initialized\n");

    // --- Main loop ---
    while (1)
    {
        // Check if FFT buffer is ready (set by DMA ISR)
        if (fft_ready)
        {
            fft_ready = false;

            // 1. Compute FFT on the full buffer
            fft_compute(audio_circ_buffer, fft_output, FFT_SIZE);

            // 2. Run NPU detection
            float detection_score = npu_process(fft_output, FFT_SIZE);

            // 3. Fire-and-forget LoRaWAN send if detected
            if (detection_score > NPU_THRESHOLD) {
                int ret = lriot_chainsaw_send_hex();
                if (ret == 0)
                    printf("[LoRaWAN] Event sent\n");
                else
                    printf("[LoRaWAN] Send failed\n");
            }
        }
        Delay_ms(1);
    }

    return 0;
}

lriot_chainsaw.h

C/C++
#ifndef LRIOT_CHAINSaw_H
#define LRIOT_CHAINSaw_H

#include "lriot.h"

// Initialize the LoRaWAN module
// Returns 0 on success, -1 on error
int lriot_chainsaw_init(void);

// Send "chainsaw" payload in HEX
// Returns 0 on success, -1 on error
int lriot_chainsaw_send_hex(void);

#endif // LRIOT_CHAINSaw_H

lriot_chainsaw.c

C/C++
#include "lriot_chainsaw.h"
#include <stdio.h>

static lriot_t lriot;
static lriot_cfg_t cfg;

int lriot_chainsaw_init(void)
{
    lriot_cfg_setup(&cfg);
    LRIOT_MAP_MIKROBUS(cfg, MIKROBUS_1);

    if (lriot_init(&lriot, &cfg) == LRIOT_ERROR) {
        return -1;
    }

    lriot_reset(&lriot);
    Delay_ms(2000);

    lriot_cmd(&lriot, "mac set deveui 0011223344556677");
    lriot_cmd(&lriot, "mac set appeui 0011223344556677");
    lriot_cmd(&lriot, "mac set appkey 00112233445566778899AABBCCDDEEFF");

    if (lriot_cmd(&lriot, "mac join otaa") != LRIOT_OK) {
        return -1;
    }

    return 0;
}

int lriot_chainsaw_send_hex(void)
{
    const char *payload_hex = "636861696e736177"; // "chainsaw" in hex
    char cmd_buf[64];
    snprintf(cmd_buf, sizeof(cmd_buf), "mac tx uncnf 1 %s", payload_hex);

    if (lriot_cmd(&lriot, cmd_buf) != LRIOT_OK) {
        return -1;
    }

    return 0;
}

Credits

Yanis Mac
1 project • 1 follower
Anas benalla
1 project • 1 follower

Comments