FEP 004 - FujiNetWIFI/fujinet-firmware GitHub Wiki

The FujiNet Protocol

Name Value
FEP ID 004
Title FujiNet Protocol
Author Andrew Diller / AI
Status Draft
Type Informational
Created 2025-07-20
Version 1.0
Input CO, OS (Discord)

Abstract

This document outlines a structured, packet-based communication protocol designed specifically for efficient command and response exchanges between the RP2350 Programmable I/O (PIO) subsystem and an ESP32 microcontroller within a FujiNet system. The protocol utilizes a clearly defined packet structure with little-endian byte ordering to optimize parsing efficiency on embedded hardware. Each packet includes synchronization bytes, command identifiers, sequence numbering for tracking, payload length indicators, and an optional CRC16 checksum to ensure data integrity. This design facilitates robust, error-resistant, and extensible communication suited for embedded device interactions.

Current FN Protocol Definitions:

FujiNet RP2350–ESP32 Communication Protocol

Packet Structure

#pragma pack(push, 1)
typedef struct {
    uint8_t start_byte;       // 0xAA for packet synchronization
    uint8_t packet_type;      // Command = 0x01, Response = 0x02
    uint8_t command_id;       // Command identifier
    uint8_t sequence_num;     // Incremental packet sequence number
    uint16_t payload_length;  // Length of payload (little-endian)
    uint8_t payload[];        // Variable-length payload
    // uint16_t crc;          // CRC16 checksum follows payload
} FujiNet_packet;
#pragma pack(pop)

Explanation of Fields

  • start_byte (0xAA): Packet synchronization.
  • packet_type: Command (0x01), Response (0x02).
  • command_id: Identifies command type.
  • sequence_num: Matches commands and responses.
  • payload_length: Length of payload (little-endian).
  • payload: Data payload (little-endian).
  • crc: CRC16 checksum (optional but recommended).

Packet Examples

Command Packet (status request, command_id = 0x10):

| start_byte     | AA |
| packet_type    | 01 |
| command_id     | 10 |
| sequence_num   | 05 |
| payload_length | 00 00 |
| crc            | CRC16 |

Response Packet (with 4-byte payload):

| start_byte     | AA |
| packet_type    | 02 |
| command_id     | 10 |
| sequence_num   | 05 |
| payload_length | 04 00 |
| payload        | [status data] |
| crc            | CRC16 |

Synchronization & Integrity

  • Start byte (0xAA) for packet framing.
  • CRC16 checksum recommended.

Implementation Steps

  1. Define packet structure.
  2. Implement serialization/deserialization.
  3. CRC16 checksum validation.
  4. Thorough synchronization tests.
  5. Incremental command extensions.

Serialization Example in C

void serialize_packet(uint8_t *buffer, FujiNet_packet *pkt) {
    buffer[0] = pkt->start_byte;
    buffer[1] = pkt->packet_type;
    buffer[2] = pkt->command_id;
    buffer[3] = pkt->sequence_num;
    buffer[4] = pkt->payload_length & 0xFF;
    buffer[5] = (pkt->payload_length >> 8) & 0xFF;
    memcpy(&buffer[6], pkt->payload, pkt->payload_length);
    uint16_t crc = crc16_ccitt(buffer, 6 + pkt->payload_length);
    buffer[6 + pkt->payload_length] = crc & 0xFF;
    buffer[7 + pkt->payload_length] = (crc >> 8) & 0xFF;
}

Benefits

  • Structured, efficient, and maintainable.
  • Robust parsing and error checking.
  • Extensible design.

FujiNet Command Examples using the New Protocol

This document shows how existing FujiNet commands from fujiCmd.h can be recreated using the newly defined packet structure.

New Protocol Packet Structure

#pragma pack(push, 1)
typedef struct {
    uint8_t start_byte;       // 0xAA packet sync byte
    uint8_t packet_type;      // Command (0x01), Response (0x02)
    uint8_t command_id;       // Command identifier
    uint8_t sequence_num;     // Sequence number
    uint16_t payload_length;  // Payload length in bytes (little-endian)
    uint8_t payload[];        // Payload data (little-endian)
    // CRC16 checksum appended after payload
} FujiNet_packet;
#pragma pack(pop)

Example 1: FN_CMD_GET_STATUS (existing command ID: 0x01)

// Creating a packet to request device status
FujiNet_packet pkt_status_request = {
    .start_byte = 0xAA,
    .packet_type = 0x01,
    .command_id = 0x01,       // FN_CMD_GET_STATUS
    .sequence_num = 0x01,
    .payload_length = 0x0000, // no payload
    // crc calculated dynamically
};

Example 2: FN_CMD_SET_WIFI (existing command ID: 0x02)

// Example payload for setting WiFi (SSID and password)
uint8_t wifi_payload[] = {
    'm', 'y', '_', 's', 's', 'i', 'd', 0x00,        // SSID null-terminated
    'm', 'y', '_', 'p', 'a', 's', 's', 0x00         // Password null-terminated
};

FujiNet_packet pkt_set_wifi = {
    .start_byte = 0xAA,
    .packet_type = 0x01,
    .command_id = 0x02,       // FN_CMD_SET_WIFI
    .sequence_num = 0x02,
    .payload_length = sizeof(wifi_payload),
    .payload = wifi_payload,  // payload points to wifi_payload
    // crc calculated dynamically
};

Example 3: FN_CMD_REBOOT (new command ID: 0x30)

// Creating a packet to request reboot
FujiNet_packet pkt_reboot = {
    .start_byte = 0xAA,
    .packet_type = 0x01,
    .command_id = 0x30,       // FN_CMD_REBOOT (newly defined)
    .sequence_num = 0x03,
    .payload_length = 0x0000, // no payload
    // crc calculated dynamically
};

CRC16 Calculation Example (pseudo-code)

uint16_t crc16_ccitt(const uint8_t *data, size_t len);

void serialize_and_send(FujiNet_packet *pkt) {
    size_t buffer_size = 6 + pkt->payload_length + 2; // header + payload + crc
    uint8_t buffer[buffer_size];

    buffer[0] = pkt->start_byte;
    buffer[1] = pkt->packet_type;
    buffer[2] = pkt->command_id;
    buffer[3] = pkt->sequence_num;
    buffer[4] = pkt->payload_length & 0xFF;
    buffer[5] = (pkt->payload_length >> 8) & 0xFF;

    memcpy(&buffer[6], pkt->payload, pkt->payload_length);

    uint16_t crc = crc16_ccitt(buffer, 6 + pkt->payload_length);
    buffer[6 + pkt->payload_length] = crc & 0xFF;
    buffer[7 + pkt->payload_length] = (crc >> 8) & 0xFF;

    // Send buffer via UART/SPI or other interface to ESP32
}