/** * \ingroup sd_raw * Writes a continuous data stream obtained from a callback function. * * This function starts writing at the specified offset. To obtain the * next bytes to write, it calls the callback function. The callback fills the * provided data buffer and returns the number of bytes it has put into the buffer. * * By returning zero, the callback may stop writing. * * \param[in] offset Offset where to start writing. * \param[in] buffer Pointer to a buffer which is used for the callback function. * \param[in] length Number of bytes to write in total. May be zero for endless writes. * \param[in] callback The function used to obtain the bytes to write. * \param[in] p An opaque pointer directly passed to the callback function. * \returns 0 on failure, 1 on success * \see sd_raw_read_interval, sd_raw_write, sd_raw_read */ uint8_t sd_raw_write_interval(offset_t offset, uint8_t* buffer, uintptr_t length, sd_raw_write_interval_handler_t callback, void* p) { #if SD_RAW_SAVE_RAM #error "SD_RAW_WRITE_SUPPORT is not supported together with SD_RAW_SAVE_RAM" #endif if(!buffer || !callback) return 0; uint8_t endless = (length == 0); while(endless || length > 0) { uint16_t bytes_to_write = callback(buffer, offset, p); if(!bytes_to_write) break; if(!endless && bytes_to_write > length) return 0; /* as writing is always buffered, we directly * hand over the request to sd_raw_write() */ if(!sd_raw_write(offset, buffer, bytes_to_write)) return 0; offset += bytes_to_write; length -= bytes_to_write; } return 1; }
/** * \ingroup sd_raw * Writes a continuous data stream obtained from a callback function. * * This function starts writing at the specified offset. To obtain the * next bytes to write, it calls the callback function. The callback fills the * provided data buffer and returns the number of bytes it has put into the buffer. * * By returning zero, the callback may stop writing. * * \param[in] offset Offset where to start writing. * \param[in] buffer Pointer to a buffer which is used for the callback function. * \param[in] length Number of bytes to write in total. May be zero for endless writes. * \param[in] callback The function used to obtain the bytes to write. * \param[in] p An opaque pointer directly passed to the callback function. * \returns 0 on failure, 1 on success * \see sd_raw_read_interval, sd_raw_write, sd_raw_read */ uint8_t sd_raw_write_interval(offset_t offset, uint8_t* buffer, uintptr_t length, sd_raw_write_interval_handler_t callback, void* p) { if(!buffer || !callback) return 0; uint8_t endless = (length == 0); while(endless || length > 0) { uint16_t bytes_to_write = callback(buffer, offset, p); if(!bytes_to_write) break; if(!endless && bytes_to_write > length) return 0; /* as writing is always buffered, we directly * hand over the request to sd_raw_write() */ if(!sd_raw_write(offset, buffer, bytes_to_write)) return 0; offset += bytes_to_write; length -= bytes_to_write; } return 1; }
/** * \ingroup sd_raw * Writes the write buffer's content to the card. * * \note When write buffering is enabled, you should * call this function before disconnecting the * card to ensure all remaining data has been * written. * * \returns 0 on failure, 1 on success. * \see sd_raw_write */ uint8_t sd_raw_sync() { #if SD_RAW_WRITE_BUFFERING if(raw_block_written) return 1; if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block))) return 0; raw_block_written = 1; #endif return 1; }
/** * \ingroup sd_raw * Writes raw data to the card. * * \note If write buffering is enabled, you might have to * call sd_raw_sync() before disconnecting the card * to ensure all remaining data has been written. * * \param[in] offset The offset where to start writing. * \param[in] buffer The buffer containing the data to be written. * \param[in] length The number of bytes to write. * \returns 0 on failure, 1 on success. * \see sd_raw_write_interval, sd_raw_read, sd_raw_read_interval */ uint8_t sd_raw_write(uint32_t offset, const uint8_t* buffer, uint16_t length) { #if SD_RAW_WRITE_SUPPORT if(get_pin_locked()) return 0; uint32_t block_address; uint16_t block_offset; uint16_t write_length; uint16_t i; while(length > 0) { /* determine byte count to write at once */ block_address = offset & 0xfffffe00; block_offset = offset & 0x01ff; write_length = 512 - block_offset; /* write up to block border */ if(write_length > length) write_length = length; /* Merge the data to write with the content of the block. * Use the cached block if available. */ if(block_address != raw_block_address) { #if SD_RAW_WRITE_BUFFERING if(!raw_block_written) { if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block))) return 0; } #endif if(block_offset || write_length < 512) { if(!sd_raw_read(block_address, raw_block, sizeof(raw_block))) return 0; } raw_block_address = block_address; } if(buffer != raw_block) { memcpy(raw_block + block_offset, buffer, write_length); #if SD_RAW_WRITE_BUFFERING raw_block_written = 0; if(length == write_length) return 1; #endif } buffer += write_length; /* address card */ select_card(); /* send single block request */ if(sd_raw_send_command_r1(CMD_WRITE_SINGLE_BLOCK, block_address)) { unselect_card(); return 0; } /* send start byte */ sd_raw_send_byte(0xfe); /* write byte block */ uint8_t* cache = raw_block; for(i = 0; i < 512; ++i) sd_raw_send_byte(*cache++); /* write dummy crc16 */ sd_raw_send_byte(0xff); sd_raw_send_byte(0xff); /* wait while card is busy */ while(sd_raw_rec_byte() != 0xff); sd_raw_rec_byte(); /* deaddress card */ unselect_card(); length -= write_length; offset += write_length; #if SD_RAW_WRITE_BUFFERING raw_block_written = 1; #endif } return 1; #else return 0; #endif }
/** * \ingroup sd_raw * Reads raw data from the card. * * \param[in] offset The offset from which to read. * \param[out] buffer The buffer into which to write the data. * \param[in] length The number of bytes to read. * \returns 0 on failure, 1 on success. * \see sd_raw_read_interval, sd_raw_write, sd_raw_write_interval */ uint8_t sd_raw_read(uint32_t offset, uint8_t* buffer, uint16_t length) { uint32_t block_address; uint16_t block_offset; uint16_t read_length; uint16_t i; while(length > 0) { /* determine byte count to read at once */ block_address = offset & 0xfffffe00; block_offset = offset & 0x01ff; read_length = 512 - block_offset; /* read up to block border */ if(read_length > length) read_length = length; #if !SD_RAW_SAVE_RAM /* check if the requested data is cached */ if(block_address != raw_block_address) #endif { #if SD_RAW_WRITE_BUFFERING if(!raw_block_written) { if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block))) return 0; } #endif /* address card */ select_card(); /* send single block request */ if(sd_raw_send_command_r1(CMD_READ_SINGLE_BLOCK, block_address)) { unselect_card(); return 0; } /* wait for data block (start byte 0xfe) */ i = 0; while(sd_raw_rec_byte() != 0xfe) { i++; if (i == 0) { unselect_card(); return 0; } } #if SD_RAW_SAVE_RAM /* read byte block */ uint16_t read_to = block_offset + read_length; for(i = 0; i < 512; ++i) { uint8_t b = sd_raw_rec_byte(); if(i >= block_offset && i < read_to) *buffer++ = b; } #else /* read byte block */ uint8_t* cache = raw_block; for(i = 0; i < 512; ++i) *cache++ = sd_raw_rec_byte(); raw_block_address = block_address; memcpy(buffer, raw_block + block_offset, read_length); buffer += read_length; #endif /* read crc16 */ sd_raw_rec_byte(); sd_raw_rec_byte(); /* deaddress card */ unselect_card(); /* let card some time to finish */ sd_raw_rec_byte(); } #if !SD_RAW_SAVE_RAM else { /* use cached data */ memcpy(buffer, raw_block + block_offset, read_length); buffer += read_length; } #endif length -= read_length; offset += read_length; } return 1; }