Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First attempt to adding hardware support for NRF52 SPI SD Card #5561

Open
wants to merge 9 commits into
base: store-and-forward
Choose a base branch
from
76 changes: 48 additions & 28 deletions src/FSCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@
#ifdef HAS_SDCARD
#include <SD.h>
#include <SPI.h>

#ifdef SDCARD_USE_SPI1
#ifdef ARCH_ESP32 //when using esp32, using esp32 specific libary for SD Card
SPIClass SPI1(HSPI);
#endif //ARCH_ESP32
#define SDHandler SPI1
#else
#define SDHandler SPI
#endif
#endif //SDCARD_USE_SPI1

#endif // HAS_SDCARD

Expand All @@ -46,7 +47,7 @@ void OSFS::writeNBytes(uint16_t address, unsigned int num, const byte *input)
input++;
}
}
#endif
#endif //ARCH_STM32WL

bool lfs_assert_failed =
false; // Note: we use this global on all platforms, though it can only be set true on nrf52 (in our modified lfs_util.h)
Expand Down Expand Up @@ -356,31 +357,50 @@ void fsInit()
void setupSDCard()
{
#ifdef HAS_SDCARD
SDHandler.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
#if defined(ARCH_ESP32)
SDHandler.begin(SPI_SCK, SPI_MISO, SPI_MOSI);

if (!SD.begin(SDCARD_CS, SDHandler)) {
LOG_DEBUG("No SD_MMC card detected");
return;
}
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE) {
LOG_DEBUG("No SD_MMC card attached");
return;
}
LOG_DEBUG("SD_MMC Card Type: ");
if (cardType == CARD_MMC) {
LOG_DEBUG("MMC");
} else if (cardType == CARD_SD) {
LOG_DEBUG("SDSC");
} else if (cardType == CARD_SDHC) {
LOG_DEBUG("SDHC");
} else {
LOG_DEBUG("UNKNOWN");
}
if (!SD.begin(SDCARD_CS, SDHandler)) {
LOG_DEBUG("No SD_MMC card detected");
return;
}
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE) {
LOG_DEBUG("No SD_MMC card attached");
return;
}
LOG_DEBUG("SD_MMC Card Type: ");
if (cardType == CARD_MMC) {
LOG_DEBUG("MMC");
} else if (cardType == CARD_SD) {
LOG_DEBUG("SDSC");
} else if (cardType == CARD_SDHC) {
LOG_DEBUG("SDHC");
} else {
LOG_DEBUG("UNKNOWN");
}

uint64_t cardSize = SD.cardSize() / (1024 * 1024);
LOG_DEBUG("SD Card Size: %lu MB", (uint32_t)cardSize);
LOG_DEBUG("Total space: %lu MB", (uint32_t)(SD.totalBytes() / (1024 * 1024)));
LOG_DEBUG("Used space: %lu MB", (uint32_t)(SD.usedBytes() / (1024 * 1024)));
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
LOG_DEBUG("SD Card Size: %lu MB", (uint32_t)cardSize);
LOG_DEBUG("Total space: %lu MB", (uint32_t)(SD.totalBytes() / (1024 * 1024)));
LOG_DEBUG("Used space: %lu MB", (uint32_t)(SD.usedBytes() / (1024 * 1024)));
#endif
#if defined(ARCH_NRF52)
if (!SD.begin(SDCARD_CS))
{
LOG_DEBUG("Could not initialize SD Card");
return;
}
else
{
LOG_DEBUG("Succesfully initialized SD Card");
LOG_DEBUG("SD Card size: %d MB", (SD.getVolumeSize() / 1024 ));
SDFile testfile = SD.open("initFile.txt", FILE_WRITE);
testfile.print("SD card initialized at: ");
testfile.println(millis());
testfile.close();
return;
}
#endif
#endif
}
}
4 changes: 2 additions & 2 deletions src/memGet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ uint32_t MemGet::getFreePsram()
{
#ifdef ARCH_ESP32
return ESP.getFreePsram();
#elif defined(HAS_SDCARD)
#elif (defined(HAS_SDCARD) && defined(ARCH_ESP32))
return SD.totalBytes() - SD.usedBytes();
#elif defined(ARCH_PORTDUINO)
return 4194252;
Expand All @@ -75,7 +75,7 @@ uint32_t MemGet::getPsramSize()
{
#ifdef ARCH_ESP32
return ESP.getPsramSize();
#elif defined(HAS_SDCARD)
#elif (defined(HAS_SDCARD) && defined(ARCH_ESP32))
return SD.totalBytes();
#elif defined(ARCH_PORTDUINO)
return 4194252;
Expand Down
163 changes: 93 additions & 70 deletions src/modules/StoreForwardModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,18 +98,35 @@ void StoreForwardModule::populatePSRAM()
void StoreForwardModule::populateSDCard()
{
#if defined(HAS_SDCARD)
if (SD.cardType() != CARD_NONE) {
if (!SD.exists("/storeforward")) {
LOG_INFO("Creating StoreForward directory");
SD.mkdir("/storeforward");
#if defined(ARCH_ESP32)
if (SD.cardType() != CARD_NONE) {
if (!SD.exists("/storeforward")) {
LOG_INFO("Creating StoreForward directory");
SD.mkdir("/storeforward");
}
this->storageType = StorageType::ST_SDCARD;
uint32_t numberOfPackets = (this->records ? this->records : (((SD.totalBytes() / 3) * 2) / sizeof(PacketHistoryStruct)));
// only allocate space for one temp copy
this->packetHistory = (PacketHistoryStruct *)malloc(sizeof(PacketHistoryStruct));
LOG_DEBUG("numberOfPackets for packetHistory - %u", numberOfPackets);
}
this->storageType = StorageType::ST_SDCARD;
uint32_t numberOfPackets = (this->records ? this->records : (((SD.totalBytes() / 3) * 2) / sizeof(PacketHistoryStruct)));
// only allocate space for one temp copy
this->packetHistory = (PacketHistoryStruct *)malloc(sizeof(PacketHistoryStruct));
LOG_DEBUG("numberOfPackets for packetHistory - %u", numberOfPackets);
}
#endif
#endif //ARCH_ESP32
#if defined(ARCH_NRF52)
if(SD.getCardType() != 0)
{
if(!SD.exists("/storeforward"))
{
SD.mkdir("/storeforward");
LOG_INFO("Creating StoreForward directory");
}
this->storageType = StorageType::ST_SDCARD;
uint32_t numberOfPackets = (this->records ? this->records : (((SD.getVolumeSize() / 3) * 2 * 1024) / sizeof(PacketHistoryStruct))); //getVolumeSize returns size in kB
// only allocate space for one temp copy
this->packetHistory = (PacketHistoryStruct *)malloc(sizeof(PacketHistoryStruct));
LOG_DEBUG("numberOfPackets for packetHistory - %u", numberOfPackets);
}
#endif //ARCH_NRF52
#endif //HAS_SDCARD
}

/**
Expand Down Expand Up @@ -166,18 +183,20 @@ uint32_t StoreForwardModule::getNumAvailablePackets(NodeNum dest, uint32_t last_
}
} else if (this->storageType == StorageType::ST_SDCARD) {
#if defined(HAS_SDCARD)
auto handler = SD.open("/storeforward/" + String(i), FILE_READ);
if (handler) {
handler.read((uint8_t *)&this->packetHistory[0], sizeof(PacketHistoryStruct));
handler.close();
if (this->packetHistory[0].time && (this->packetHistory[0].time > last_time)) {
// Client is only interested in packets not from itself and only in broadcast packets or packets towards it.
if (this->packetHistory[0].from != dest &&
(this->packetHistory[0].to == NODENUM_BROADCAST || this->packetHistory[0].to == dest)) {
count++;
#if defined(ARCH_ESP32) || defined(ARCH_NRF52)
auto handler = SD.open("/storeforward/" + String(i), FILE_READ);
if (handler) {
handler.read((uint8_t *)&this->packetHistory[0], sizeof(PacketHistoryStruct));
handler.close();
if (this->packetHistory[0].time && (this->packetHistory[0].time > last_time)) {
// Client is only interested in packets not from itself and only in broadcast packets or packets towards it.
if (this->packetHistory[0].from != dest &&
(this->packetHistory[0].to == NODENUM_BROADCAST || this->packetHistory[0].to == dest)) {
count++;
}
}
}
}
#endif
#endif
} else {
LOG_ERROR("S&F: Unknown storage type");
Expand Down Expand Up @@ -248,18 +267,20 @@ void StoreForwardModule::historyAdd(const meshtastic_MeshPacket &mp)
} else if (this->storageType == StorageType::ST_SDCARD) {
// Save to SDCARD
#if defined(HAS_SDCARD)
this->packetHistory[0].time = getTime();
this->packetHistory[0].to = mp.to;
this->packetHistory[0].channel = mp.channel;
this->packetHistory[0].from = getFrom(&mp);
this->packetHistory[0].id = mp.id;
this->packetHistory[0].reply_id = p.reply_id;
this->packetHistory[0].emoji = (bool)p.emoji;
this->packetHistory[0].payload_size = p.payload.size;
memcpy(this->packetHistory[0].payload, p.payload.bytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
auto handler = SD.open("/storeforward/" + String(this->packetHistoryTotalCount), FILE_WRITE);
handler.write((uint8_t *)&this->packetHistory, sizeof(PacketHistoryStruct));
handler.close();
#if defined (ARCH_ESP32) || defined(ARCH_NRF52)
this->packetHistory[0].time = getTime();
this->packetHistory[0].to = mp.to;
this->packetHistory[0].channel = mp.channel;
this->packetHistory[0].from = getFrom(&mp);
this->packetHistory[0].id = mp.id;
this->packetHistory[0].reply_id = p.reply_id;
this->packetHistory[0].emoji = (bool)p.emoji;
this->packetHistory[0].payload_size = p.payload.size;
memcpy(this->packetHistory[0].payload, p.payload.bytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
auto handler = SD.open("/storeforward/" + String(this->packetHistoryTotalCount), FILE_WRITE);
handler.write((uint8_t *)&this->packetHistory, sizeof(PacketHistoryStruct));
handler.close();
#endif
#endif
} else {
LOG_ERROR("S&F: Unknown storage type");
Expand Down Expand Up @@ -346,49 +367,51 @@ meshtastic_MeshPacket *StoreForwardModule::preparePayload(NodeNum dest, uint32_t
}
} else if (this->storageType == StorageType::ST_SDCARD) {
#if defined(HAS_SDCARD)
auto handler = SD.open("/storeforward/" + String(i), FILE_READ);
if (handler) {
handler.read((uint8_t *)&this->packetHistory[0], sizeof(PacketHistoryStruct));
handler.close();
if (this->packetHistory[0].time && (this->packetHistory[0].time > last_time)) {
if (this->packetHistory[0].from != dest &&
(this->packetHistory[0].to == NODENUM_BROADCAST || this->packetHistory[0].to == dest)) {

meshtastic_MeshPacket *p = allocDataPacket();

p->to = local ? this->packetHistory[0].to : dest; // PhoneAPI can handle original `to`
p->from = this->packetHistory[0].from;
p->channel = this->packetHistory[0].channel;
p->rx_time = this->packetHistory[0].time;

// Let's assume that if the server received the S&F request that the client is in range.
p->want_ack = false;

if (local) { // PhoneAPI gets normal TEXT_MESSAGE_APP
p->decoded.portnum = meshtastic_PortNum_TEXT_MESSAGE_APP;
memcpy(p->decoded.payload.bytes, this->packetHistory[0].payload, this->packetHistory[0].payload_size);
p->decoded.payload.size = this->packetHistory[0].payload_size;
} else {
meshtastic_StoreAndForward sf = meshtastic_StoreAndForward_init_zero;
sf.which_variant = meshtastic_StoreAndForward_text_tag;
sf.variant.text.size = this->packetHistory[0].payload_size;
memcpy(sf.variant.text.bytes, this->packetHistory[0].payload, this->packetHistory[0].payload_size);
if (this->packetHistory[0].to == NODENUM_BROADCAST) {
sf.rr = meshtastic_StoreAndForward_RequestResponse_ROUTER_TEXT_BROADCAST;
#if defined(ARCH_ESP32) || defined(ARCH_NRF52)
auto handler = SD.open("/storeforward/" + String(i), FILE_READ);
if (handler) {
handler.read((uint8_t *)&this->packetHistory[0], sizeof(PacketHistoryStruct));
handler.close();
if (this->packetHistory[0].time && (this->packetHistory[0].time > last_time)) {
if (this->packetHistory[0].from != dest &&
(this->packetHistory[0].to == NODENUM_BROADCAST || this->packetHistory[0].to == dest)) {

meshtastic_MeshPacket *p = allocDataPacket();

p->to = local ? this->packetHistory[0].to : dest; // PhoneAPI can handle original `to`
p->from = this->packetHistory[0].from;
p->channel = this->packetHistory[0].channel;
p->rx_time = this->packetHistory[0].time;

// Let's assume that if the server received the S&F request that the client is in range.
p->want_ack = false;

if (local) { // PhoneAPI gets normal TEXT_MESSAGE_APP
p->decoded.portnum = meshtastic_PortNum_TEXT_MESSAGE_APP;
memcpy(p->decoded.payload.bytes, this->packetHistory[0].payload, this->packetHistory[0].payload_size);
p->decoded.payload.size = this->packetHistory[0].payload_size;
} else {
sf.rr = meshtastic_StoreAndForward_RequestResponse_ROUTER_TEXT_DIRECT;
meshtastic_StoreAndForward sf = meshtastic_StoreAndForward_init_zero;
sf.which_variant = meshtastic_StoreAndForward_text_tag;
sf.variant.text.size = this->packetHistory[0].payload_size;
memcpy(sf.variant.text.bytes, this->packetHistory[0].payload, this->packetHistory[0].payload_size);
if (this->packetHistory[0].to == NODENUM_BROADCAST) {
sf.rr = meshtastic_StoreAndForward_RequestResponse_ROUTER_TEXT_BROADCAST;
} else {
sf.rr = meshtastic_StoreAndForward_RequestResponse_ROUTER_TEXT_DIRECT;
}

p->decoded.payload.size = pb_encode_to_bytes(
p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_StoreAndForward_msg, &sf);
}

p->decoded.payload.size = pb_encode_to_bytes(
p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_StoreAndForward_msg, &sf);
}

lastRequest[dest] = i + 1; // Update the last request index for the client device
lastRequest[dest] = i + 1; // Update the last request index for the client device

return p;
return p;
}
}
}
}
#endif
#endif
} else {
LOG_ERROR("S&F: Unknown storage type");
Expand Down
2 changes: 1 addition & 1 deletion src/xmodem.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class XModemAdapter
uint16_t packetno = 0;

#if defined(ARCH_NRF52) || defined(ARCH_STM32WL)
File file = File(FSCom);
Adafruit_LittleFS_Namespace::File file = Adafruit_LittleFS_Namespace::File(FSCom);
#else
File file;
#endif
Expand Down
1 change: 1 addition & 0 deletions variants/rak4631/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ lib_deps =
https://github.com/RAKWireless/RAK13800-W5100S.git#1.0.2
rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2
https://github.com/RAKWireless/RAK12034-BMX160.git#dcead07ffa267d3c906e9ca4a1330ab989e957e2
https://github.com/Woutvstk/arduino_SD.git #library to acces SD card

; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds
Expand Down
16 changes: 16 additions & 0 deletions variants/rak4631/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,22 @@ static const uint8_t MOSI = PIN_SPI_MOSI;
static const uint8_t MISO = PIN_SPI_MISO;
static const uint8_t SCK = PIN_SPI_SCK;


//SD card SPI pin definitions

#define HAS_SDCARD 1
#define SDCARD_USE_SPI1 1

#ifdef SDCARD_USE_SPI1
#define SDCARD_SPI SPI1
#endif
#define SPI_MOSI PIN_SPI1_MOSI
#define SPI_SCK PIN_SPI1_SCK
#define SPI_MISO PIN_SPI1_MISO
#define SDCARD_CS (26)



/*
* eink display pins
*/
Expand Down
Loading