#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;