Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
abae48d
Initial Commit
OceancattUCSC Oct 14, 2025
7fca79c
added Libary dependency and some basic methods
OceancattUCSC Oct 14, 2025
6ffd79c
update gitignore
OceancattUCSC Oct 14, 2025
edf819e
added basic functions and headers
OceancattUCSC Oct 21, 2025
46ad0b5
combining prateeks old code
prateekgupta5 Oct 27, 2025
b0fdd99
Mostly complete with spiflash additional layers (no tick, read, write)
prateekgupta5 Nov 3, 2025
4830c73
added function call checks for buffer and kLog
OceancattUCSC Nov 13, 2025
7d3682a
updated read function with error handling
OceancattUCSC Nov 21, 2025
99c71e0
added file for writing unittests
OceancattUCSC Dec 1, 2025
3688621
made changes to lib file and moved untitest files
OceancattUCSC Dec 1, 2025
d4ee06e
Update spiFlash.h
OceancattUCSC Jan 5, 2026
cd98ae9
added actual hardare interaction (v1) -Prateek
prateekgupta5 Jan 12, 2026
08111a5
link fail
OceancattUCSC Jan 13, 2026
d91ffe6
in spiFlash.cpp: Modify spiFlash::startUp to return boolean status --…
prateekgupta5 Feb 9, 2026
76c630b
Change startUp method return type to bool -- Prateek
prateekgupta5 Feb 9, 2026
77db70d
made splitflash.h be alphbetical, and spliflashtester also made
fkhabur Feb 9, 2026
de35981
Modify spiFlash constructor, remove spiflash::setCS_PIN
prateekgupta5 Feb 12, 2026
8f62f96
Refactor spiFlash class constructor and methods
prateekgupta5 Feb 12, 2026
38d4421
Add NOBOARD_TEST definition for stdio unit tests
prateekgupta5 Feb 12, 2026
bb2b5ca
Delete blaze-lite/core/lib/spi_flash/flash_config.h
prateekgupta5 Feb 12, 2026
0d17d35
Delete .vscode/c_cpp_properties.json
prateekgupta5 Feb 12, 2026
039d5f1
Merge branch 'main' into feature/spi-flash
prateekgupta5 Feb 12, 2026
20c1bce
Refactor spliFlashTester to make constructor/destructor more concise,…
prateekgupta5 Feb 12, 2026
ed36f30
Rename spliFlashTester to SpiFlashTester, made the file include a test
prateekgupta5 Feb 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 199 additions & 0 deletions blaze-lite/core/lib/spi_flash/spiFlash.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/*
* spiFlash.cpp - SPI Flash library for Blaze
* To use:
include the corresponding header file in your main program, DO NOT directly call this cpp file
*/
#include "spiFlash.h"

#include <queue>
#include <tuple>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <cmath>
#include <vector>
#include <fstream>
#include <iostream>
#include <fcntl.h>


const uint8_t CS_PIN = PB8;
Adafruit_FlashTransport_SPI flash_Transport(CS_PIN, SPI);
Adafruit_SPIFlash flash_(&flash_Transport);

FatVolume fatfs;

// File32 root;
// File32 file;
File32 fd, kfd;

//TODO: Make private methods to simplify code

//Constructor:
spiFlash::spiFlash (const size_t buffer_size, const size_t k_buffer_size)
: buffer_size(buffer_size), k_buffer_size(k_buffer_size), buffer_offset(0), k_buffer_offset(0) {
obuff = new char[ buffer_size];
kbuff = new char[k_buffer_size];
queuedos = std::priority_queue<std::tuple<char, size_t, char*>, std::vector<std::tuple<char, size_t, char*>>, cmp_io_priority>();
}

spiFlash::~spiFlash () {
kflush();
flush();

#ifdef NOBOARD_TEST
::close(fd);
::close(kfd);
#endif

delete[] obuff;
delete[] kbuff;

}

//hardware setup function (this should be called in the main file setup loop):
//https://github.com/adafruit/Adafruit_SPIFlash/blob/master/examples/SdFat_datalogging/SdFat_datalogging.ino
bool spiFlash::startUp() {
if (!flash_.begin()) {
Serial.println("Error, failed to initialize flash_ chip!");
// while (1) {
// delay(1);
// }
return false;
}
Serial.print("Flash chip JEDEC ID: 0x");
Serial.println(flash_.getJEDECID(), HEX);

// First call begin to mount the filesystem. Check that it returns true
// to make sure the filesystem was mounted.
if (!fatfs.begin(&flash_)) {
Serial.println("Error, failed to mount newly formatted filesystem!");
Serial.println("Was the flash_ chip formatted with the fatfs_format example?");
// while (1) delay(1);
return false;
}
Serial.println("Mounted filesystem!");
return true;
}

//Get Methods:
uint8_t spiFlash::getCS_PIN() { return CS_PIN; }

// //Set Methods:
// void spiFlash::setCS_PIN(const uint8_t pin) { CS_PIN = pin; }

//functionality methods:
ssize_t spiFlash::read(const size_t offset, const size_t bytes, char* buffer){
// //error handling
// if (bytes == 0) return 0; //no bytes to read
// if (buffer == nullptr) return -1; //null data pointer
// if (lseek(fd, offset, SEEK_SET) == -1 ) return -2; //seek error

// ssize_t bytes_read = ::read(fd, buffer, bytes);

// return bytes_read;
}

char spiFlash::queue(size_t bytes, char* data, char priority) {
queuedos.push(std::tie<char, size_t, char*>(priority, bytes, data));
return 0;
}

char spiFlash::buffer (const size_t bytes, const char* data) {
//function call error handling
if (bytes == 0) return 0; //no bytes to write
if (data == nullptr) return -1; //null data pointer
if (obuff == nullptr) return -2; //null buffer pointer

ssize_t err = 0;
size_t offset = 0, temp = 0;

memcpy(obuff + buffer_offset, data, temp = std::min(bytes, buffer_size - buffer_offset));
buffer_offset += (offset += temp);

while ((bytes - offset > 0) && (err == 0)) {
if (err = flush() < 0) return err;
flush();

memcpy(obuff, data + offset, temp = std::min(bytes - offset, buffer_size));
buffer_offset += temp;
offset += temp;
}

return err;
}

//return value < 0 means error
ssize_t spiFlash::write (const size_t bytes, const char* data) {
#ifdef NOBOARD_TEST
return ::write(fd, data, bytes);
#else
return fd.write(data, bytes);
#endif
}

ssize_t spiFlash::kwrite (const size_t bytes, const char* data) {
#ifdef NOBOARD_TEST
return ::write(kfd, data, bytes);
#else
return kfd.write(data, bytes);
#endif
}

char spiFlash::flush (void) {
ssize_t err = write(buffer_offset, obuff);
if (err < 0) return err;

memset(obuff, 0, buffer_size);
buffer_offset = 0;

return 0;
}

ssize_t spiFlash::kLog (const size_t bytes, const char* data) {
//function call error handling
if (bytes == 0) return 0; //no bytes to write
if (data == nullptr) return -1; //null data pointer
if (kbuff == nullptr) return -2; //null buffer pointer

ssize_t err = 0;
size_t offset = 0, temp = 0;

memcpy(kbuff + k_buffer_offset, data, temp = std::min(bytes, k_buffer_size - k_buffer_offset));
k_buffer_offset += (offset += temp);

while (bytes - offset > 0) {
if (err = kflush() < 0) return err;
memcpy(kbuff, data + offset, temp = std::min(bytes - offset, k_buffer_size - k_buffer_offset));
k_buffer_offset += temp;
offset += temp;
}

return err;
}

char spiFlash::kflush (void) {
ssize_t err = kwrite (k_buffer_offset, kbuff);
if (err < 0) return err;
memset(kbuff, 0, k_buffer_size);
k_buffer_offset = 0;
return err;
}

//TODO: implement error tracking
ssize_t spiFlash::tick (void) {
if(queuedos.empty()) return 0;

bool isMandatory = std::get<0>(queuedos.top()) == spiFlash::P_MANDATORY;
ssize_t numBytes = this->buffer(std::get<1>(queuedos.top()), std::get<2>(queuedos.top()));
queuedos.pop();

for(; std::get<0>(queuedos.top()) == spiFlash::P_MANDATORY; queuedos.pop()) numBytes += this->buffer(std::get<1>(queuedos.top()), std::get<2>(queuedos.top()));

if(isMandatory) this->flush();
return numBytes;
}

bool spiFlash::cmp_io_priority:: operator()(const std::tuple<char, size_t, char*>& l, const std::tuple<char, size_t, char*>& r) const {
return std::get<0>(l) > std::get<0>(r);
}
93 changes: 93 additions & 0 deletions blaze-lite/core/lib/spi_flash/spiFlash.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#ifndef SPI_FLASH_H
#define SPI_FLASH_H

#include <Arduino.h>
#include <SPI.h>
#include <SdFat.h>

#include <Adafruit_SPIFlash.h>

#include <queue>
#include <tuple>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <cmath>
#include <vector>
#include <fstream>
#include <iostream>

//TODO: Documentation
class spiFlash {
public:

static constexpr const char
P_MANDATORY = 0, //just force writes this at next tick
P_URGENT = 1,
P_IMPORTANT = 2,
P_STD = 3,
P_UNIMPORTANT = 4,
P_OPTIONAL = 5
;
//Constructor:
spiFlash (const size_t buffer_size = 512, const size_t k_buffer_size = 512) ;

//destructor:
~spiFlash();

//setup function:
bool startUp();

//Get Methods:
uint8_t getCS_PIN();

//functionality methods:

char buffer (const size_t bytes, const char* data);

char flush (void);

ssize_t kLog (const size_t bytes, const char* data);

char kflush (void);

ssize_t kwrite (const size_t bytes, const char* data);

char queue (size_t bytes, char* data, char priority = P_UNIMPORTANT);

ssize_t read (const size_t offset, const size_t bytes, char* buffer);

ssize_t tick (void);

ssize_t write (const size_t bytes, const char* data);

//types
struct cmp_io_priority {
bool operator()(const std::tuple<char, size_t, char*>& l, const std::tuple<char, size_t, char*>& r) const ;
};

const size_t buffer_size;
const size_t k_buffer_size;

private:
uint8_t CS_PIN;

std::priority_queue<
// priority size data
std::tuple<char, size_t, char*>,
std::vector<std::tuple<char, size_t, char*>>,
cmp_io_priority
> queuedos;

char* obuff;
size_t buffer_offset;

char* kbuff;
size_t k_buffer_offset;

#ifdef NOBOARD_TEST
int fd, kfd;
#endif
};

#endif
93 changes: 93 additions & 0 deletions blaze-lite/core/lib/spi_flash/spliFlashTester.cpp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to blaze-lite/core/test

Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#include "spiFlash.h"
#include <string.h>

class SpiFlashTester{
private:
void printResult(const char* testName, bool passed) {
Serial.print(testName);
Serial.print(": ");
Serial.println(passed ? "PASS" : "FAIL");
}

void testStartUp(){
spiFlash spiFlash(256, 128);
bool ok = spiFlash.startUp();
printResult("StartUp test: ", ok);
}

void testReadWrite(){
spiFlash spiFlash(256, 128);
spiFlash.startUp();

const char msg = "HELLO ROCKET TEAM!!";
char readback[sizeof(msg)] = {0}; // open memory for our data

ssize_t written = spiFlash.write(sizeof(msg), msg); // save what the flash interprets from our message
ssize_t read = spiFlash.read(0, sizeof(msg), readback); // read the data into space we opened for it

bool test = ((written == sizeof(msg)) && (read == sizeof(msg)) && !std::memcmp(written, read, sizeof(msg)));
printResult("Basic Read Write test: ", ok);
}

void testBufferFlush() {
spiFlash spiFlash(256, 128);
spiFlash.startUp();

const char msg[] = "BUFFERED";
char out[sizeof(msg)] = {0};

spiFlash.buffer(sizeof(msg), msg);
spiFlash.flush();
spiFlash.read(0, sizeof(msg), out);

bool ok = !std::memcmp(msg, out, sizeof(msg));
printResult("Buffer flush: ", ok);
}

void testQueuePriority() {
spiFlash spiFlash(256, 128);
spiFlash.startUp();

char low[] = "LOW";
char high[] = "HIGH";

spiFlash.queue(sizeof(low), low, spiFlash::P_UNIMPORTANT);
spiFlash.queue(sizeof(high), high, spiFlash::P_URGENT);

while (spiFlash.tick() > 0) {}

char out1[5] = {0};
char out2[4] = {0};

spiFlash.read(0, sizeof(high), out1);
spiFlash.read(sizeof(high), sizeof(low), out2);

bool ok = (std::strcmp(out1, "HIGH") == 0 && std::strcmp(out2, "LOW") == 0);
printResult("Queue priority: ", ok);
}


public:
void run() {
Serial.println("SPI Flash Tester: start");
testStartup();
testReadWrite();
testBufferFlush();
testQueuePriority();
Serial.println("SPI Flash Tester: done");
}
~SpiFlashTester();

};

SpiFlashTester:: SpiFlashTester() = default;
SpiFlashTester::~SpiFlashTester() = default;

void setup () {
auto tester = SpiFlashTester();
tester.run();
}

void loop () {
delay(100); //so we dont fry the arduino
}
Loading