1297 lines
34 KiB
C++
1297 lines
34 KiB
C++
#include "SDBlock.h"
|
|
|
|
void SDBlock::begin(uint32_t dId) {
|
|
deviceId = dId;
|
|
|
|
// XXX Change to checking each is SECTOR_SIZE or report !
|
|
if (stream && debug) {
|
|
stream->println(F("# SDBlock sizes: "));
|
|
stream->print(F("# buffer: "));
|
|
stream->println(sizeof(buffer));
|
|
stream->print(F("# allocation: "));
|
|
stream->println(sizeof(SDBlock_Allocation));
|
|
stream->print(F("# metadata: "));
|
|
stream->println(sizeof(SDBlock_Metadata));
|
|
stream->print(F("# loglines: "));
|
|
stream->println(sizeof(SDBlock_LogLines));
|
|
stream->print(F("# queue: "));
|
|
stream->println(sizeof(SDBlock_Queue));
|
|
stream->print(F("# block: "));
|
|
stream->println(sizeof(SDBlock_Block));
|
|
|
|
stream->print(F("# SDBlock Address Defaults: "));
|
|
stream->print(F(" allocation: "));
|
|
stream->print((uint32_t)SDBLOCK_ACTUAL_ALLOCATION);
|
|
stream->print(F(" - "));
|
|
stream->print((uint32_t)SDBLOCK_ACTUAL_ALLOCATION + SDBLOCK_ALLOCATION_MAX);
|
|
stream->println();
|
|
|
|
stream->print(F("# metadata: "));
|
|
stream->print((uint32_t)SDBLOCK_ACTUAL_METADATA);
|
|
stream->print(F(" - "));
|
|
stream->print((uint32_t)SDBLOCK_ACTUAL_METADATA + SDBLOCK_METADATA_MAX);
|
|
stream->println();
|
|
|
|
stream->print(F("# single: "));
|
|
stream->print((uint32_t)SDBLOCK_ACTUAL_SINGLE);
|
|
stream->print(F(" - "));
|
|
stream->print((uint32_t)SDBLOCK_ACTUAL_SINGLE + SDBLOCK_SINGLE_MAX);
|
|
stream->println();
|
|
|
|
stream->print(F("# loglines: "));
|
|
stream->print((uint32_t)SDBLOCK_ACTUAL_LOGLINES);
|
|
stream->print(F(" - "));
|
|
stream->print((uint32_t)SDBLOCK_ACTUAL_LOGLINES + SDBLOCK_LOGLINES_MAX);
|
|
stream->println();
|
|
|
|
stream->print(F("# queue: "));
|
|
stream->print((uint32_t)SDBLOCK_ACTUAL_QUEUE);
|
|
stream->print(F(" - "));
|
|
stream->print((uint32_t)SDBLOCK_ACTUAL_QUEUE + SDBLOCK_QUEUE_MAX);
|
|
stream->println();
|
|
|
|
stream->print(F("# data: "));
|
|
stream->print((uint32_t)SDBLOCK_ACTUAL_DATA);
|
|
stream->print(F(" - "));
|
|
stream->print((uint32_t)SDBLOCK_ACTUAL_DATA + SDBLOCK_DATA_MAX);
|
|
stream->println();
|
|
|
|
stream->print(F("# max: "));
|
|
stream->print((uint32_t)SDBLOCK_MAX);
|
|
stream->println();
|
|
|
|
// Coming up as 3% but shoudl be 72%
|
|
// stream->print(F(" percent: "));
|
|
// stream->print((uint32_t)(((SDBLOCK_ACTUAL_DATA + SDBLOCK_DATA_MAX) * (uint32_t)100) / (uint32_t)SDBLOCK_MAX));
|
|
// stream->println("%");
|
|
}
|
|
|
|
autoFormat = false;
|
|
}
|
|
void SDBlock::end() {
|
|
// SPI.end() /?
|
|
}
|
|
|
|
void SDBlock::setAutoFormat(bool in) {
|
|
autoFormat = in;
|
|
}
|
|
bool SDBlock::getAutoFormat() {
|
|
return autoFormat;
|
|
}
|
|
|
|
void SDBlock::setDeviceId(uint32_t dId) {
|
|
deviceId = dId;
|
|
}
|
|
|
|
void SDBlock::setRecordId(uint32_t rId) {
|
|
recordId = rId;
|
|
}
|
|
|
|
bool SDBlock::cardIsOpen() {
|
|
return valid;
|
|
}
|
|
|
|
// Close off card, ignoreing any data, ie, it will all be lose
|
|
void SDBlock::cardForceClose() {
|
|
valid = false;
|
|
dataBlockCurrent = 0;
|
|
dataBlockStart = 0;
|
|
metadata_dataBlockStart = 0;
|
|
metadata_dataBlocks = 0;
|
|
metadata_resultsBlockStart = 0;
|
|
metadata_resultsBlocks = 0;
|
|
}
|
|
|
|
bool SDBlock::cardErase() {
|
|
#ifdef USE_SDFS
|
|
if (!_sdinit()) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock - Init card failed"));
|
|
return false;
|
|
}
|
|
|
|
if (stream)
|
|
stream->println(F("# SDBlock: erase started: "));
|
|
|
|
uint32_t firstBlock = 0;
|
|
uint32_t lastBlock;
|
|
uint16_t n = 0;
|
|
uint32_t cardSectorCount = sd.card()->sectorCount();
|
|
|
|
do {
|
|
lastBlock = firstBlock + ERASE_SIZE - 1;
|
|
if (lastBlock >= cardSectorCount) {
|
|
lastBlock = cardSectorCount - 1;
|
|
}
|
|
if (!sd.card()->erase(firstBlock, lastBlock)) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: ERROR - erase failed"));
|
|
return false;
|
|
}
|
|
if (stream)
|
|
stream->print('.');
|
|
if ((n++)%64 == 63) {
|
|
if (stream)
|
|
stream->println();
|
|
}
|
|
firstBlock += ERASE_SIZE;
|
|
} while (firstBlock < cardSectorCount);
|
|
stream->println();
|
|
|
|
if (!read(0)) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: ERROR - read block failed"));
|
|
return false;
|
|
}
|
|
if (stream)
|
|
stream->println(F("# SDBlock: erase done"));
|
|
return true;
|
|
#else
|
|
if (stream)
|
|
stream->println(F("# SDBlock: driver does not support erase"));
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool SDBlock::_sdinit() {
|
|
// Initialize SD Card
|
|
#ifdef USE_SDCORE
|
|
if (!SDCore::begin()) {
|
|
if (!SDCore::begin()) {
|
|
if (stream) {
|
|
stream->println(F("# SDBlock Initialization: FAILED - Make sure than you have your wiring correct and a compatible SD card inserted."));
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_SD2CARD
|
|
if (!sd.init()) {
|
|
if (!sd.init()) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock Initialization: FAILED - Make sure than you have your wiring correct and a compatible SD card inserted."));
|
|
return false;
|
|
}
|
|
}
|
|
// TODO Keep
|
|
size = sd.cardSize();
|
|
if (stream) {
|
|
stream->print(F("# SDBlock CardSize (blocks): "));
|
|
stream->print((uint32_t)size);
|
|
stream->println();
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_SDFS
|
|
SdCardFactory cardFactory;
|
|
m_card = cardFactory.newCard(SD_CONFIG);
|
|
|
|
/*
|
|
if (!sd.cardBegin(SD_CONFIG)) {
|
|
if (!sd.cardBegin(SD_CONFIG)) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock Initialization: FAILED - Make sure than you have your wiring correct and a compatible SD card inserted."));
|
|
return false;
|
|
}
|
|
}
|
|
*/
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SDBlock::cardOpen(uint32_t cId, bool format) {
|
|
checkInternals();
|
|
|
|
valid = false;
|
|
dataBlockCurrent = 0;
|
|
dataBlockStart = 0;
|
|
|
|
dataBlockNext = 0;
|
|
metadataBlockNext = 0;
|
|
singleBlockNext = 0;
|
|
loglinesBlockNext = 0;
|
|
queueBlockNext = 0;
|
|
metadata_dataBlockStart = 0;
|
|
metadata_dataBlocks = 0;
|
|
metadata_resultsBlockStart = 0;
|
|
metadata_resultsBlocks = 0;
|
|
|
|
// Setup pointers (can be done just once)
|
|
allocation = (SDBlock_Allocation*)&buffer;
|
|
metadata = (SDBlock_Metadata*)&buffer;
|
|
loglines = (SDBlock_LogLines*)&buffer;
|
|
block = (SDBlock_Block*)&buffer;
|
|
|
|
if (!_sdinit()) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock - Init card failed"));
|
|
return false;
|
|
}
|
|
|
|
cardId = cId;
|
|
|
|
if (format) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock - Format Requested"));
|
|
allocationDefault();
|
|
}
|
|
|
|
if (!allocationRead()) {
|
|
if (stream) {
|
|
stream->println(F("# SDBlock Initialization: Allocation Read Failed"));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
dataBlockNext = allocation->dataBlockNext; // Next, becasue first record is 0, so initilaly we write there
|
|
metadataBlockNext = allocation->metadataBlockNext; // And of course where is the Metadata
|
|
singleBlockNext = allocation->singleBlockNext; // And of course where is the Metadata
|
|
loglinesBlockNext = allocation->loglinesBlockNext; // And of course where is the Metadata
|
|
queueBlockNext = allocation->queueBlockNext; // And of course where is the Metadata
|
|
|
|
if (stream && debug) {
|
|
stream->print(F("# SDBlock next: "));
|
|
stream->print(F("; cardId: expected="));
|
|
stream->print(cardId);
|
|
stream->print(F(" allocated="));
|
|
stream->println(allocation->cardId);
|
|
stream->print(F("# metadata: next="));
|
|
stream->print(metadataBlockNext);
|
|
stream->print(F(" records="));
|
|
stream->print(metadataBlockNext - SDBLOCK_ACTUAL_METADATA);
|
|
|
|
stream->print(F("; data: next="));
|
|
stream->print(dataBlockNext);
|
|
stream->print(F(" records="));
|
|
stream->println(dataBlockNext - SDBLOCK_ACTUAL_DATA);
|
|
|
|
stream->print(F("# single: next="));
|
|
stream->print(singleBlockNext);
|
|
stream->print(F(" records="));
|
|
stream->print(singleBlockNext - SDBLOCK_ACTUAL_SINGLE);
|
|
|
|
stream->print(F("; loglines: next="));
|
|
stream->print(loglinesBlockNext);
|
|
stream->print(F(" records="));
|
|
stream->print(loglinesBlockNext - SDBLOCK_ACTUAL_LOGLINES);
|
|
|
|
stream->print(F("; queue: next="));
|
|
stream->print(queueBlockNext);
|
|
stream->print(F(" records="));
|
|
stream->print(queueBlockNext - SDBLOCK_ACTUAL_QUEUE);
|
|
stream->println();
|
|
|
|
}
|
|
|
|
valid = true;
|
|
return true;
|
|
}
|
|
|
|
void SDBlock::checkInternals() {
|
|
if (stream) {
|
|
if (sizeof(SDBlock_Allocation) != SDBLOCK_SECTOR_SIZE) {
|
|
stream->print(F("\n\n\n*********\nAllocation Wrong size: "));
|
|
stream->println(sizeof(SDBlock_Allocation));
|
|
}
|
|
if (sizeof(SDBlock_Metadata) != SDBLOCK_SECTOR_SIZE) {
|
|
stream->print(F("\n\n\n*********\nMetadata Wrong size: "));
|
|
stream->println(sizeof(SDBlock_Metadata));
|
|
}
|
|
if (sizeof(SDBlock_LogLines) != SDBLOCK_SECTOR_SIZE) {
|
|
stream->print(F("\n\n\n*********\nLogLines Wrong size: "));
|
|
stream->println(sizeof(SDBlock_LogLines));
|
|
}
|
|
if (sizeof(SDBlock_Queue) != SDBLOCK_SECTOR_SIZE) {
|
|
stream->print(F("\n\n\n*********\nQueue Wrong size: "));
|
|
stream->println(sizeof(SDBlock_Queue));
|
|
}
|
|
if (sizeof(SDBlock_Block) != SDBLOCK_SECTOR_SIZE) {
|
|
stream->print(F("\n\n\n*********\nBlock Wrong size: "));
|
|
stream->println(sizeof(SDBlock_Block));
|
|
}
|
|
}
|
|
}
|
|
|
|
bool SDBlock::cardClose() {
|
|
allocationUpdate();
|
|
allocationRead();
|
|
// XXX Write allocation changes
|
|
#ifdef USE_SDCORE
|
|
SDCore::end();
|
|
#endif
|
|
|
|
// SPI.end();
|
|
valid = false;
|
|
dataBlockCurrent = 0;
|
|
dataBlockStart = 0;
|
|
return true;
|
|
}
|
|
|
|
bool SDBlock::read(unsigned long address_in) {
|
|
#ifdef USE_SDCORE
|
|
if (!SDCore::read(address_in, buffer)) {
|
|
if (!SDCore::read(address_in, buffer)) {
|
|
if (stream) {
|
|
stream->print(F("# SDBlock: Failed to read at block: "));
|
|
stream->println(address_in);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_SD2CARD
|
|
if (!sd.readBlock(address_in, (byte*)buffer)) {
|
|
if (!sd.readBlock(address_in, (byte*)buffer)) {
|
|
if (stream) {
|
|
stream->print(F("# SDBlock: Failed to read at block: "));
|
|
stream->println(address_in);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_SDFS
|
|
if (!sd.card()->readSingle(address_in, (uint8_t*)&buffer)) {
|
|
if (!sd.card()->readSingle(address_in, (uint8_t*)&buffer)) {
|
|
if (stream) {
|
|
stream->print(F("# SDBlock: Failed to read at block: "));
|
|
stream->println(address_in);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SDBlock::write(unsigned long address_in) {
|
|
// XXX Check address_in in range !!!
|
|
#ifdef USE_SDCORE
|
|
if (!SDCore::write(address_in, buffer)) {
|
|
if (!SDCore::write(address_in, buffer)) {
|
|
if (stream) {
|
|
stream->print(F("# SDBlock: Failed to write at block: "));
|
|
stream->println(address_in);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef USE_SD2CARD
|
|
if (!sd.writeBlock(address_in, (byte*)buffer)) {
|
|
if (!sd.writeBlock(address_in, (byte*)buffer)) {
|
|
if (stream) {
|
|
stream->print(F("# SDBlock: Failed to write at block: "));
|
|
stream->println(address_in);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef USE_SDFS
|
|
if (!sd.card()->writeSingle(address_in, (uint8_t*)&buffer)) {
|
|
if (!sd.card()->writeSingle(address_in, (uint8_t*)&buffer)) {
|
|
if (stream) {
|
|
stream->print(F("# SDBlock: Failed to read at block: "));
|
|
stream->println(address_in);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
// Create a BRAND NEW DEVICE
|
|
bool SDBlock::allocationDefault() {
|
|
memset(buffer, 0, sizeof(buffer));
|
|
metadata->blockType = SDBLOCK_TYPE_ALLOCATION_FULL;
|
|
allocation->deviceId = deviceId;
|
|
allocation->recordId = recordId;
|
|
allocation->currentTime = now();
|
|
|
|
// First 2 blocks Allocaiton table
|
|
// Next = Metadata
|
|
allocation->metadataBlockNext = SDBLOCK_ACTUAL_METADATA;
|
|
// Next = Single
|
|
allocation->singleBlockNext = SDBLOCK_ACTUAL_SINGLE;
|
|
// Next = Log Lines
|
|
allocation->loglinesBlockNext = SDBLOCK_ACTUAL_LOGLINES;
|
|
// Next = Data
|
|
allocation->dataBlockNext = SDBLOCK_ACTUAL_DATA;
|
|
// Queue
|
|
allocation->queueBlockNext = SDBLOCK_ACTUAL_QUEUE;
|
|
|
|
|
|
// ESSENTAIL for alloction bloc, or this block will be rejected.
|
|
// I only keep one other copy
|
|
crcSet();
|
|
|
|
return allocationWrite();
|
|
}
|
|
|
|
// Special update in place
|
|
bool SDBlock::allocationUpdate() {
|
|
if (!allocationRead()) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Failed to update allocation table"));
|
|
return false;
|
|
}
|
|
|
|
if (stream) {
|
|
stream->println(F("# SDBlock: Allocation changes: "));
|
|
|
|
stream->print(F("# metadata: "));
|
|
stream->print(allocation->metadataBlockNext);
|
|
stream->print(F(" -> "));
|
|
stream->println(metadataBlockNext);
|
|
|
|
stream->print(F("# single: "));
|
|
stream->print(allocation->singleBlockNext);
|
|
stream->print(F(" -> "));
|
|
stream->println(singleBlockNext);
|
|
|
|
stream->print(F("# loglines: "));
|
|
stream->print(allocation->loglinesBlockNext);
|
|
stream->print(F(" -> "));
|
|
stream->println(loglinesBlockNext);
|
|
|
|
stream->print(F("# queue: "));
|
|
stream->print(allocation->queueBlockNext);
|
|
stream->print(F(" -> "));
|
|
stream->println(queueBlockNext);
|
|
|
|
stream->print(F("# data: "));
|
|
stream->print(allocation->dataBlockNext);
|
|
stream->print(F(" -> "));
|
|
stream->println(dataBlockNext);
|
|
}
|
|
|
|
allocation->dataBlockNext = dataBlockNext;
|
|
allocation->metadataBlockNext = metadataBlockNext;
|
|
allocation->singleBlockNext = singleBlockNext;
|
|
allocation->loglinesBlockNext = loglinesBlockNext;
|
|
allocation->queueBlockNext = queueBlockNext;
|
|
allocation->currentTime = now();
|
|
allocation->deviceId = deviceId;
|
|
allocation->recordId = recordId;
|
|
|
|
allocation->cardId = cardId;
|
|
|
|
// Update and set the CRC
|
|
crcSet();
|
|
|
|
return allocationWrite();
|
|
}
|
|
|
|
bool SDBlock::allocationWrite() {
|
|
response = write(SDBLOCK_OFFSET);
|
|
if (!response) {
|
|
response = write(SDBLOCK_OFFSET);
|
|
if (!response) {
|
|
if (stream) {
|
|
stream->println("# SDBlock: DISASTER: Failed to write allocation block 1");
|
|
}
|
|
}
|
|
}
|
|
|
|
response = write(SDBLOCK_OFFSET + 1);
|
|
if (!response) {
|
|
response = write(SDBLOCK_OFFSET + 1);
|
|
if (!response) {
|
|
if (stream) {
|
|
stream->println("# SDBlock: DISASTER: Failed to write allocation block 2");
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
bool SDBlock::metadataStatusBLK(uint32_t block, uint32_t status) {
|
|
response = read(block);
|
|
if (!response) {
|
|
response = read(block);
|
|
if (!response) {
|
|
stream->println(F("# SDBlock - metadataStatusBLK - Catastrophic Failure"));
|
|
return false;
|
|
}
|
|
}
|
|
metadata->status = status;
|
|
crcSet();
|
|
response = write(block);
|
|
if (!response) {
|
|
response = write(block);
|
|
if (!response) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: DISASTER: Can't write update BLK"));
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SDBlock::dataStatusBLK(uint32_t block, uint32_t status) {
|
|
response = read(block);
|
|
if (!response) {
|
|
response = read(block);
|
|
if (!response) {
|
|
stream->println(F("# SDBlock - dataStatusBLK - Catastrophic Failure"));
|
|
return false;
|
|
}
|
|
}
|
|
data->status = status;
|
|
response = write(block);
|
|
if (!response) {
|
|
response = write(block);
|
|
if (!response) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: DISASTER: Can't write update BLK"));
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
*/
|
|
|
|
uint32_t SDBlock::getDataNext() {
|
|
return dataBlockNext;
|
|
}
|
|
|
|
uint32_t SDBlock::getMetadataNext() {
|
|
return metadataBlockNext;
|
|
}
|
|
uint32_t SDBlock::getMetadataFirst() {
|
|
return SDBLOCK_ACTUAL_METADATA;
|
|
}
|
|
uint32_t SDBlock::getDataFirst() {
|
|
return SDBLOCK_ACTUAL_DATA;
|
|
}
|
|
uint8_t SDBlock::getCardId() {
|
|
return cardId;
|
|
}
|
|
bool SDBlock::validRange(char *str, uint32_t test, uint32_t start, uint32_t max) {
|
|
if (
|
|
(test < start)
|
|
|| ((test - start) > max)
|
|
) {
|
|
if (str && stream) {
|
|
stream->print(F("# SDBlock: ERROR "));
|
|
stream->print(str);
|
|
stream->print(F(" out of range: current="));
|
|
stream->print(test);
|
|
stream->print(F(", start="));
|
|
stream->print(start);
|
|
stream->print(F(", max="));
|
|
stream->print(max);
|
|
stream->println();
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// XXX Generalisation of Valid - e.g. CRC and Block type
|
|
bool SDBlock::allocationValid() {
|
|
if (!crcCheck()) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Allocation: CRC Failed"));
|
|
return false;
|
|
}
|
|
|
|
if (allocation->blockType != SDBLOCK_TYPE_ALLOCATION_FULL) {
|
|
if (stream && debug) {
|
|
stream->print(F("# SDBlock: BlockType: "));
|
|
stream->println(allocation->blockType);
|
|
stream->print(F("Expected: "));
|
|
stream->println(SDBLOCK_TYPE_ALLOCATION_FULL);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Example Special case - we can write some areas update ourselives
|
|
if (!validRange(NULL, allocation->queueBlockNext, SDBLOCK_ACTUAL_QUEUE, SDBLOCK_QUEUE_MAX)) {
|
|
if (stream)
|
|
stream->println("# SDBlock: NOTE: queueBlock automatically updated");
|
|
allocation->queueBlockNext = SDBLOCK_ACTUAL_QUEUE;
|
|
}
|
|
|
|
// XXX These could be improved ! Fully check range etc
|
|
if (
|
|
!validRange("metadataBlock", allocation->metadataBlockNext, SDBLOCK_ACTUAL_METADATA, SDBLOCK_METADATA_MAX)
|
|
|| !validRange("singleBlock", allocation->singleBlockNext, SDBLOCK_ACTUAL_SINGLE, SDBLOCK_SINGLE_MAX)
|
|
|| !validRange("loglinesBlock", allocation->loglinesBlockNext, SDBLOCK_ACTUAL_LOGLINES, SDBLOCK_LOGLINES_MAX)
|
|
|| !validRange("queueBlock", allocation->queueBlockNext, SDBLOCK_ACTUAL_QUEUE, SDBLOCK_QUEUE_MAX)
|
|
|| !validRange("dataBlock", allocation->dataBlockNext, SDBLOCK_ACTUAL_DATA, SDBLOCK_DATA_MAX)
|
|
) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Failed one or more dataBlock tests"));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SDBlock::allocationRead() {
|
|
// Read first record
|
|
response = read(SDBLOCK_OFFSET);
|
|
if (!response)
|
|
response = read(SDBLOCK_OFFSET);
|
|
|
|
// Read second record
|
|
if (!response || !crcCheck()) {
|
|
if (stream) {
|
|
stream->println(F("# SDBlock: Failed to read allocation block 1, trying block 2"));
|
|
}
|
|
response = read(SDBLOCK_OFFSET + 1);
|
|
if (!response)
|
|
response = read(SDBLOCK_OFFSET + 1);
|
|
}
|
|
|
|
// Check valid Allocation table, and CRC Valid.
|
|
if (!allocationValid()) {
|
|
// Time to assume this is a new disk (VERY DANGEROUS)
|
|
|
|
if (autoFormat) {
|
|
if (!allocationDefault()) {
|
|
// console.log
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Failed... like real bad - unable to make new allocation table!"));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
else {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Failed... like real bad - no allocation valid, and no autoFormat"));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void SDBlock::crcUpdate() {
|
|
// 512 byte buffer - whole thing, except the CRC (last 4 bytes);
|
|
crc = CRC32::calculate(buffer, 508);
|
|
}
|
|
|
|
bool SDBlock::crcCheck() {
|
|
// Update the CRC from Buffer
|
|
crcUpdate();
|
|
// Compare to what is stored in buffer
|
|
return (crc == block->crc);
|
|
}
|
|
|
|
void SDBlock::crcSet() {
|
|
crcUpdate();
|
|
block->crc = crc;
|
|
}
|
|
|
|
bool SDBlock::getMBR() {
|
|
// NOTE: Assumes openCard()
|
|
|
|
// XXX Keep the esentils.
|
|
|
|
// Read MBR
|
|
response = read(0);
|
|
if (!response) {
|
|
// console.log(LOG_INFO, F("MBR Reading: FAILED"));
|
|
stream->println(F("# SDBlock: Failed read MBR"));
|
|
return false;
|
|
}
|
|
|
|
// Check if MBR is valid (MBR Signature: 0x55AA at end of the sector)
|
|
if (buffer[0x1FE] != 0x55 || buffer[0x1FF] != 0xAA) {
|
|
stream->println(F("# SDBlock: This SD Card doesnt use MBR"));
|
|
return false;
|
|
}
|
|
|
|
// Show all information from MBR
|
|
// Reference for MBR Sector: https://en.wikipedia.org/wiki/Master_boot_record
|
|
stream->println(F("# SD Card Information:"));
|
|
|
|
// Original Physical Drive
|
|
stream->print(F("# Physical Drive: "));
|
|
stream->println(buffer[0x0DC], HEX);
|
|
|
|
// Timestamp
|
|
stream->print(F("# Timestamp: "));
|
|
stream->print(buffer[0x0DD]);
|
|
stream->print(F(":"));
|
|
stream->print(buffer[0x0DE]);
|
|
stream->print(F(":"));
|
|
stream->println(buffer[0x0DF]);
|
|
|
|
// Disk Signature
|
|
stream->print(F("# Disk Signature: "));
|
|
stream->print(buffer[0x1B8], HEX);
|
|
stream->print(buffer[0x1B9], HEX);
|
|
stream->print(buffer[0x1BA], HEX);
|
|
stream->print(buffer[0x1BB], HEX);
|
|
stream->print(buffer[0x1BC], HEX);
|
|
stream->println(buffer[0x1BD], HEX);
|
|
|
|
// Partition Entries
|
|
for (byte i = 0; i < 4; i++) {
|
|
|
|
// Calculate blocks count
|
|
unsigned long blocks = (unsigned long)buffer[0x1CA + (i * 16)]
|
|
| (unsigned long)buffer[0x1CB + (i * 16)] << 8
|
|
| (unsigned long)buffer[0x1CC + (i * 16)] << 16
|
|
| (unsigned long)buffer[0x1CD + (i * 16)] << 24;
|
|
|
|
// If its a partition with 0 blocks, its not a partition ;)
|
|
if (blocks == 0) {
|
|
continue;
|
|
}
|
|
|
|
// XXX Urgent - convert to console !
|
|
|
|
// Partition Number
|
|
stream->print(F("# Partition "));
|
|
stream->println(i + 1);
|
|
|
|
// Is bootable
|
|
stream->print(F("#\tBootable: "));
|
|
if (buffer[0x1BE + (i * 16)]) {
|
|
stream->println(F("YES"));
|
|
} else {
|
|
stream->println(F("NO"));
|
|
}
|
|
|
|
// Partition Type
|
|
stream->print(F("#\tPartition Type: "));
|
|
stream->println(buffer[0x1C2], HEX);
|
|
|
|
// LBA
|
|
stream->print(F("#\tLBA: "));
|
|
stream->print(buffer[0x1C9 + (i * 16)], HEX);
|
|
stream->print(buffer[0x1C8 + (i * 16)], HEX);
|
|
stream->print(buffer[0x1C7 + (i * 16)], HEX);
|
|
stream->println(buffer[0x1C6 + (i * 16)], HEX);
|
|
|
|
// Number of blocks
|
|
stream->print(F("#\tBlocks: "));
|
|
stream->println(blocks);
|
|
|
|
// Size
|
|
stream->print(F("#\tSize: "));
|
|
stream->print(blocks >> 11);
|
|
stream->println(F(" MB"));
|
|
}
|
|
}
|
|
|
|
bool SDBlock::dataIsOpen() {
|
|
return (valid && (dataBlockStart || dataBlockCurrent));
|
|
}
|
|
|
|
bool SDBlock::dataWrite(void* in, uint16_t size) {
|
|
if (!dataIsOpen()) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Data was never open. Nothing to do"));
|
|
return false;
|
|
}
|
|
|
|
// Helpful all in one write
|
|
if (size > 0) {
|
|
if (!dataPrepare(in, size)) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Failed inline prepare"));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Leave off for data blocs - just too slow (About 80% of the time in SDBlock)
|
|
// crcSet();
|
|
response = write(dataBlockCurrent);
|
|
if (!response) {
|
|
response = write(dataBlockCurrent);
|
|
if (!response) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: DISASTER: Can't write"));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
dataLast = dataBlockNext;
|
|
dataBlockCurrent++;
|
|
return true;
|
|
}
|
|
|
|
bool SDBlock::dataOpen(uint32_t recId) {
|
|
// Woops.... already started... Record to serial port then disreguard
|
|
if (dataIsOpen()) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Data was already started, that run will be lost (TODO record numbers)"));
|
|
}
|
|
|
|
dataBlockStart = dataBlockNext;
|
|
dataBlockCurrent = dataBlockNext;
|
|
dataBlockRecordId = recId;
|
|
recordId = recId; // XXX Both?
|
|
|
|
if (stream) {
|
|
stream->print(F("# SDBlock: dataOpen at "));
|
|
stream->println(dataBlockNext);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// dataClose - assumed to be input, but could also be output, only decide on close
|
|
bool SDBlock::dataClose(bool output) {
|
|
if (!dataIsOpen()) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Data was never open. Nothing to do"));
|
|
return false;
|
|
}
|
|
|
|
// Update our allocation table ready to save
|
|
dataBlockNext = dataBlockCurrent;
|
|
|
|
if (output) {
|
|
metadata_resultsBlockStart = dataBlockStart;
|
|
metadata_resultsBlocks = dataBlockCurrent - dataBlockStart;
|
|
if (stream) {
|
|
stream->print(F("# SDBlock: dataClose added "));
|
|
stream->println(metadata_resultsBlocks);
|
|
}
|
|
}
|
|
else {
|
|
metadata_dataBlockStart = dataBlockStart;
|
|
metadata_dataBlocks = dataBlockCurrent - dataBlockStart;
|
|
if (stream) {
|
|
stream->print(F("# SDBlock: dataClose added "));
|
|
stream->println(metadata_dataBlocks);
|
|
}
|
|
}
|
|
|
|
// Clear data
|
|
dataBlockStart = 0;
|
|
dataBlockCurrent = 0;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SDBlock::dataPrepare(void* in, uint16_t size) {
|
|
memset(buffer, 0, sizeof(buffer));
|
|
block->blockType = SDBLOCK_TYPE_BLOCK_FULL;
|
|
block->recordId = dataBlockRecordId;
|
|
|
|
if (size > 0) {
|
|
if (size > sizeof(block->data)) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: ERROR: Trying to set data beyond size"));
|
|
return false;
|
|
}
|
|
memcpy(block->data, in, size);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//bool SDBlock::dataRead(uint32_t fromEnd) {
|
|
//}
|
|
/*
|
|
void SDBlock::dataList(unsigned long address, Print* altstream = NULL, CallbackFunction metadata_cb = NULL, CallbackFunction data_cb = NULL) {
|
|
}
|
|
*/
|
|
|
|
bool SDBlock::metadataPrepare(void* in, uint16_t size) {
|
|
memset(buffer, 0, sizeof(buffer));
|
|
metadata->blockType = SDBLOCK_TYPE_METADATA_FULL;
|
|
metadata->status = 0;
|
|
metadata->deviceId = deviceId;
|
|
metadata->recordId = recordId;
|
|
metadata->dataBlockStart = metadata_dataBlockStart;
|
|
metadata->dataBlocks = metadata_dataBlocks;
|
|
metadata->resultsBlockStart = metadata_resultsBlockStart;
|
|
metadata->resultsBlocks = metadata_resultsBlocks;
|
|
|
|
// Clear the data blocks
|
|
metadata_dataBlockStart = 0;
|
|
metadata_dataBlocks = 0;
|
|
metadata_resultsBlockStart = 0;
|
|
metadata_resultsBlocks = 0;
|
|
|
|
if (size > 0) {
|
|
if (size > sizeof(metadata->data)) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: ERROR: Trying to set data beyond size"));
|
|
return false;
|
|
}
|
|
memcpy(metadata->data, in, size);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SDBlock::metadataWrite(void* in, uint16_t size) {
|
|
if (!cardIsOpen()) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Data was never open. Nothing to do"));
|
|
return false;
|
|
}
|
|
// Helpful all in one write
|
|
if (size > 0) {
|
|
if (!metadataPrepare(in, size)) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Failed inline prepare"));
|
|
return false;
|
|
}
|
|
}
|
|
crcSet();
|
|
response = write(metadataBlockNext);
|
|
if (!response) {
|
|
response = write(metadataBlockNext);
|
|
if (!response) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: DISASTER: Can't write metadata"));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
metadataLast = metadataBlockNext;
|
|
metadataBlockNext++;
|
|
return true;
|
|
}
|
|
|
|
uint32_t SDBlock::metadataCount() {
|
|
return metadataBlockNext - SDBLOCK_ACTUAL_METADATA;
|
|
}
|
|
|
|
// fromEnd is first, then num back from there
|
|
void SDBlock::metadataList(uint32_t fromEnd, uint32_t num, Print *altstream) {
|
|
if (!altstream)
|
|
altstream = stream;
|
|
|
|
if (debug) {
|
|
altstream->print(F("# SDBlock: metadataList - fromEnd/num= metadtaaBlockNext="));
|
|
altstream->print(fromEnd);
|
|
altstream->print("/");
|
|
altstream->print(num);
|
|
altstream->print(" ");
|
|
altstream->print(metadataBlockNext);
|
|
altstream->println();
|
|
}
|
|
|
|
altstream->println(F("# SDBlock: Start of metadata requested"));
|
|
for (count = 0; count < num; count++) {
|
|
if (metadataRead(fromEnd + count)) {
|
|
altstream->print(F("@SDBlock,metadata"));
|
|
altstream->print(F(",count="));
|
|
altstream->print(count);
|
|
altstream->print(F(",add="));
|
|
altstream->print(metadataBlockNext - (fromEnd + count) - 1); // NOTE: -1 because Next is next to use not this
|
|
altstream->print(F(",dev="));
|
|
altstream->print(metadata->deviceId);
|
|
altstream->print(F(",rec="));
|
|
altstream->print(metadata->recordId);
|
|
altstream->print(F(",bSt="));
|
|
altstream->print(metadata->dataBlockStart);
|
|
altstream->print(F(",bs="));
|
|
altstream->print(metadata->dataBlocks);
|
|
altstream->print(F(",rSt="));
|
|
altstream->print(metadata->resultsBlockStart);
|
|
altstream->print(F(",rs="));
|
|
altstream->print(metadata->resultsBlocks);
|
|
altstream->print(F(",status="));
|
|
altstream->print(metadata->status);
|
|
altstream->println();
|
|
}
|
|
else {
|
|
altstream->println(F("# SDBlock: End of metadata reached (before number requested)"));
|
|
break;
|
|
}
|
|
}
|
|
altstream->println(F("# SDBlock: End of metadata requested"));
|
|
}
|
|
|
|
bool SDBlock::metadataUpdateStatus(uint32_t address_in, uint32_t record_in, uint32_t status_in) {
|
|
if (!metadataReadBLK(address_in)) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Failed to update metadata status"));
|
|
return false;
|
|
}
|
|
|
|
// Check record is valid
|
|
if (metadata->recordId != record_in) {
|
|
if (stream) {
|
|
stream->print(F("# SDBlock: Failed to match record Id: Request="));
|
|
stream->print(record_in);
|
|
stream->print(F(", rec="));
|
|
stream->println(metadata->recordId);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (metadata->status == status_in) {
|
|
if (stream && debug)
|
|
stream->println(F("SDBlock: status not changed, not writing"));
|
|
return true;
|
|
}
|
|
metadata->status = status_in;
|
|
crcSet();
|
|
response = write(address_in);
|
|
if (!response) {
|
|
response = write(address_in);
|
|
if (!response) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: DISASTER: Can't write metadata"));
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SDBlock::metadataRead(uint32_t fromEnd) {
|
|
if (stream && debug) {
|
|
stream->print(F("# SDBlock: metadataRead - fromEnd="));
|
|
stream->print(fromEnd);
|
|
stream->println();
|
|
stream->print(F("# SDBlock: metadataRead - metadataBlockNext="));
|
|
stream->print(metadataBlockNext);
|
|
stream->println();
|
|
stream->print(F("# SDBlock: metadataBlockNext - fromEnd - 1="));
|
|
stream->print(metadataBlockNext - fromEnd - 1);
|
|
stream->println();
|
|
}
|
|
return metadataReadBLK(metadataBlockNext - fromEnd - 1);
|
|
}
|
|
|
|
bool SDBlock::metadataReadBLK(uint32_t address_in) {
|
|
if (stream && debug) {
|
|
stream->print(F("# SDBlock: metadataReadBLK - block/start "));
|
|
stream->print(address_in);
|
|
stream->print("/");
|
|
stream->print(SDBLOCK_ACTUAL_METADATA);
|
|
stream->println();
|
|
}
|
|
if (!cardIsOpen()) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Data was never open. Nothing to do"));
|
|
return false;
|
|
}
|
|
|
|
if (address_in >= SDBLOCK_ACTUAL_METADATA) {
|
|
return read(address_in);
|
|
// XXX crc check, record type check
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SDBlock::resultsRead(uint32_t fromEnd) {
|
|
return resultsReadBLK(dataBlockNext - fromEnd - 1);
|
|
}
|
|
|
|
bool SDBlock::resultsReadBLK(uint32_t address_in) {
|
|
if (!cardIsOpen()) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Data was never open. Nothing to do"));
|
|
return false;
|
|
}
|
|
|
|
if (address_in >= SDBLOCK_ACTUAL_DATA) {
|
|
return read(address_in);
|
|
// XXX crc check, record type check
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
|
|
bool SDBlock::metadataUpdate(uint32_t fromEnd) {
|
|
if (!metadataRead(fromEnd)) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Failed to read metadata block during update"));
|
|
return false;
|
|
}
|
|
|
|
// Allocation blocsk
|
|
|
|
// Update and set the CRC
|
|
crcSet();
|
|
|
|
response = write(metadataBlockNext);
|
|
if (!response) {
|
|
response = write(metadataBlockNext);
|
|
if (!response) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: DISASTER: Can't write metadata"));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
bool SDBlock::singlePrepare(void* in, uint16_t size) {
|
|
memset(buffer, 0, sizeof(buffer));
|
|
block->blockType = SDBLOCK_TYPE_SINGLE_FULL;
|
|
block->recordId = recordId;
|
|
if (size > 0) {
|
|
if (size > sizeof(block->data)) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: ERROR: Trying to set data beyond size"));
|
|
return false;
|
|
}
|
|
memcpy(block->data, in, size);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
uint32_t SDBlock::singleCount() {
|
|
return singleBlockNext - SDBLOCK_ACTUAL_SINGLE;
|
|
}
|
|
|
|
bool SDBlock::singleRead(uint32_t fromEnd) {
|
|
if (!cardIsOpen()) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Data was never open. Nothing to do"));
|
|
return false;
|
|
}
|
|
|
|
address_local = singleBlockNext - fromEnd - 1;
|
|
if (address_local >= SDBLOCK_ACTUAL_SINGLE) {
|
|
if (stream) {
|
|
stream->print("# SingleRead Address=");
|
|
stream->println(address_local);
|
|
}
|
|
return read(address_local);
|
|
// optional crc check, record type check
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SDBlock::singleWrite(void* in, uint16_t size) {
|
|
if (!cardIsOpen()) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Data was never open. Nothing to do"));
|
|
return false;
|
|
}
|
|
|
|
if (size > 0) {
|
|
if (!singlePrepare(in, size)) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Failed inline prepare"));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// crcSet();
|
|
response = write(singleBlockNext);
|
|
if (!response) {
|
|
response = write(singleBlockNext);
|
|
if (!response) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: DISASTER: Can't write single"));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
singleLast = singleBlockNext;
|
|
singleBlockNext++;
|
|
if (stream && debug) {
|
|
stream->print(F("# SDBlock: Single Write complete, nextblock="));
|
|
stream->println(singleBlockNext);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SDBlock::queuePrepare(uint32_t status, void* in, uint16_t in_size, void* out, uint16_t out_size) {
|
|
memset(buffer, 0, sizeof(buffer));
|
|
block->blockType = SDBLOCK_TYPE_QUEUE_FULL;
|
|
block->recordId = recordId;
|
|
if (in_size > 0) {
|
|
if (in_size > sizeof(queue->dataIn)) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: ERROR: Trying to set data beyond size"));
|
|
}
|
|
else {
|
|
memcpy(queue->dataIn, in, in_size);
|
|
}
|
|
}
|
|
if (out_size > 0) {
|
|
if (out_size > sizeof(queue->dataOut)) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: ERROR: Trying to set data beyond size"));
|
|
}
|
|
else {
|
|
memcpy(queue->dataOut, out, out_size);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
uint32_t SDBlock::queueCount() {
|
|
return queueBlockNext - SDBLOCK_ACTUAL_SINGLE;
|
|
}
|
|
|
|
bool queueUpdate(uint32_t fromEnd, uint32_t status, void* out = NULL, uint16_t out_size = 0);
|
|
bool queueRead(uint32_t fromEnd);
|
|
uint32_t queueCount();
|
|
|
|
bool SDBlock::queueRead(uint32_t fromEnd) {
|
|
if (!cardIsOpen()) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Data was never open. Nothing to do"));
|
|
return false;
|
|
}
|
|
|
|
address_local = queueBlockNext - fromEnd - 1;
|
|
if (address_local >= SDBLOCK_ACTUAL_SINGLE) {
|
|
if (stream) {
|
|
stream->print("SingleRead Address=");
|
|
stream->println(address_local);
|
|
}
|
|
return read(address_local);
|
|
// optional crc check, record type check
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SDBlock::queueWrite(uint32_t status, void* in, uint16_t in_size, void* out, uint16_t out_size) {
|
|
if (!cardIsOpen()) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Data was never open. Nothing to do"));
|
|
return false;
|
|
}
|
|
|
|
if (size > 0) {
|
|
if (!queuePrepare(in, size)) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: Failed inline prepare"));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (status > 0)
|
|
queue->status = status;
|
|
|
|
// (slow) crcSet();
|
|
response = write(queueBlockNext);
|
|
if (!response) {
|
|
response = write(queueBlockNext);
|
|
if (!response) {
|
|
if (stream)
|
|
stream->println(F("# SDBlock: DISASTER: Can't write queue"));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
queueLast = queueBlockNext;
|
|
queueBlockNext++;
|
|
if (stream && debug) {
|
|
stream->print(F("# SDBlock: Single Write complete, nextblock="));
|
|
stream->println(queueBlockNext);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
SDBlock sdBlock;
|