Skip to content

Commit 82e3bf9

Browse files
committed
Add File::availableForWrite API
1 parent b8a78d4 commit 82e3bf9

File tree

7 files changed

+126
-28
lines changed

7 files changed

+126
-28
lines changed

src/File.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ size_t File::write(const uint8_t *buf, size_t size) {
7373
return t;
7474
}
7575

76+
int File::availableForWrite() {
77+
if (_file) {
78+
return _file->availableForWrite();
79+
}
80+
return 0;
81+
}
82+
7683
int File::peek() {
7784
if (! _file) {
7885
return 0;

src/SD.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ namespace SDLib {
3535
File(void); // 'empty' constructor
3636
virtual size_t write(uint8_t);
3737
virtual size_t write(const uint8_t *buf, size_t size);
38+
virtual int availableForWrite();
3839
virtual int read();
3940
virtual int peek();
4041
virtual int available();

src/utility/Sd2Card.cpp

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -608,10 +608,11 @@ uint8_t Sd2Card::waitStartBlock(void) {
608608
609609
\param[in] blockNumber Logical block to be written.
610610
\param[in] src Pointer to the location of the data to be written.
611+
\param[in] blocking If the write should be blocking.
611612
\return The value one, true, is returned for success and
612613
the value zero, false, is returned for failure.
613614
*/
614-
uint8_t Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
615+
uint8_t Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src, uint8_t blocking) {
615616
#if SD_PROTECT_BLOCK_ZERO
616617
// don't allow write to first block
617618
if (blockNumber == 0) {
@@ -631,16 +632,17 @@ uint8_t Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
631632
if (!writeData(DATA_START_BLOCK, src)) {
632633
goto fail;
633634
}
634-
635-
// wait for flash programming to complete
636-
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
637-
error(SD_CARD_ERROR_WRITE_TIMEOUT);
638-
goto fail;
639-
}
640-
// response is r2 so get and check two bytes for nonzero
641-
if (cardCommand(CMD13, 0) || spiRec()) {
642-
error(SD_CARD_ERROR_WRITE_PROGRAMMING);
643-
goto fail;
635+
if (blocking) {
636+
// wait for flash programming to complete
637+
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
638+
error(SD_CARD_ERROR_WRITE_TIMEOUT);
639+
goto fail;
640+
}
641+
// response is r2 so get and check two bytes for nonzero
642+
if (cardCommand(CMD13, 0) || spiRec()) {
643+
error(SD_CARD_ERROR_WRITE_PROGRAMMING);
644+
goto fail;
645+
}
644646
}
645647
chipSelectHigh();
646648
return true;
@@ -760,3 +762,16 @@ uint8_t Sd2Card::writeStop(void) {
760762
chipSelectHigh();
761763
return false;
762764
}
765+
//------------------------------------------------------------------------------
766+
/** Check if the SD card is busy
767+
768+
\return The value one, true, is returned when is busy and
769+
the value zero, false, is returned for when is NOT busy.
770+
*/
771+
uint8_t Sd2Card::isBusy(void) {
772+
chipSelectLow();
773+
byte b = spiRec();
774+
chipSelectHigh();
775+
776+
return (b != 0XFF);
777+
}

src/utility/Sd2Card.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,11 @@ class Sd2Card {
236236
uint8_t type(void) const {
237237
return type_;
238238
}
239-
uint8_t writeBlock(uint32_t blockNumber, const uint8_t* src);
239+
uint8_t writeBlock(uint32_t blockNumber, const uint8_t* src, uint8_t blocking = 1);
240240
uint8_t writeData(const uint8_t* src);
241241
uint8_t writeStart(uint32_t blockNumber, uint32_t eraseCount);
242242
uint8_t writeStop(void);
243+
uint8_t isBusy(void);
243244
private:
244245
uint32_t block_;
245246
uint8_t chipSelectPin_;

src/utility/SdFat.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ class SdFile : public Print {
295295
}
296296
uint8_t timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day,
297297
uint8_t hour, uint8_t minute, uint8_t second);
298-
uint8_t sync(void);
298+
uint8_t sync(uint8_t blocking = 1);
299299
/** Type of this SdFile. You should use isFile() or isDir() instead of type()
300300
if possible.
301301
@@ -320,6 +320,7 @@ class SdFile : public Print {
320320
void write_P(PGM_P str);
321321
void writeln_P(PGM_P str);
322322
#endif
323+
int availableForWrite(void);
323324
//------------------------------------------------------------------------------
324325
#if ALLOW_DEPRECATED_FUNCTIONS
325326
// Deprecated functions - suppress cpplint warnings with NOLINT comment
@@ -407,14 +408,16 @@ class SdFile : public Print {
407408
// should be 0XF
408409
static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC);
409410
// available bits
410-
static uint8_t const F_UNUSED = 0X30;
411+
static uint8_t const F_FILE_NON_BLOCKING_WRITE = 0X10;
412+
// a new cluster was added to the file
413+
static uint8_t const F_FILE_CLUSTER_ADDED = 0X20;
411414
// use unbuffered SD read
412415
static uint8_t const F_FILE_UNBUFFERED_READ = 0X40;
413416
// sync of directory entry required
414417
static uint8_t const F_FILE_DIR_DIRTY = 0X80;
415418

416419
// make sure F_OFLAG is ok
417-
#if ((F_UNUSED | F_FILE_UNBUFFERED_READ | F_FILE_DIR_DIRTY) & F_OFLAG)
420+
#if ((F_FILE_NON_BLOCKING_WRITE | F_FILE_CLUSTER_ADDED | F_FILE_UNBUFFERED_READ | F_FILE_DIR_DIRTY) & F_OFLAG)
418421
#error flags_ bits conflict
419422
#endif // flags_ bits
420423

@@ -587,7 +590,8 @@ class SdVolume {
587590
uint32_t blockNumber(uint32_t cluster, uint32_t position) const {
588591
return clusterStartBlock(cluster) + blockOfCluster(position);
589592
}
590-
static uint8_t cacheFlush(void);
593+
static uint8_t cacheFlush(uint8_t blocking = 1);
594+
static uint8_t cacheMirrorBlockFlush(uint8_t blocking);
591595
static uint8_t cacheRawBlock(uint32_t blockNumber, uint8_t action);
592596
static void cacheSetDirty(void) {
593597
cacheDirty_ |= CACHE_FOR_WRITE;
@@ -610,8 +614,14 @@ class SdVolume {
610614
uint16_t count, uint8_t* dst) {
611615
return sdCard_->readData(block, offset, count, dst);
612616
}
613-
uint8_t writeBlock(uint32_t block, const uint8_t* dst) {
614-
return sdCard_->writeBlock(block, dst);
617+
uint8_t writeBlock(uint32_t block, const uint8_t* dst, uint8_t blocking = 1) {
618+
return sdCard_->writeBlock(block, dst, blocking);
619+
}
620+
uint8_t isBusy(void) {
621+
return sdCard_->isBusy();
622+
}
623+
uint8_t isCacheMirrorBlockDirty(void) {
624+
return (cacheMirrorBlock_ != 0);
615625
}
616626
};
617627
#endif // SdFat_h

src/utility/SdFile.cpp

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ uint8_t SdFile::addCluster() {
4242
firstCluster_ = curCluster_;
4343
flags_ |= F_FILE_DIR_DIRTY;
4444
}
45+
flags_ |= F_FILE_CLUSTER_ADDED;
4546
return true;
4647
}
4748
//------------------------------------------------------------------------------
@@ -1121,12 +1122,14 @@ uint8_t SdFile::seekSet(uint32_t pos) {
11211122
The sync() call causes all modified data and directory fields
11221123
to be written to the storage device.
11231124
1125+
\param[in] blocking If the sync should block until fully complete.
1126+
11241127
\return The value one, true, is returned for success and
11251128
the value zero, false, is returned for failure.
11261129
Reasons for failure include a call to sync() before a file has been
11271130
opened or an I/O error.
11281131
*/
1129-
uint8_t SdFile::sync(void) {
1132+
uint8_t SdFile::sync(uint8_t blocking) {
11301133
// only allow open files and directories
11311134
if (!isOpen()) {
11321135
return false;
@@ -1155,7 +1158,12 @@ uint8_t SdFile::sync(void) {
11551158
// clear directory dirty
11561159
flags_ &= ~F_FILE_DIR_DIRTY;
11571160
}
1158-
return SdVolume::cacheFlush();
1161+
1162+
if (!blocking) {
1163+
flags_ &= ~F_FILE_NON_BLOCKING_WRITE;
1164+
}
1165+
1166+
return SdVolume::cacheFlush(blocking);
11591167
}
11601168
//------------------------------------------------------------------------------
11611169
/**
@@ -1325,6 +1333,8 @@ size_t SdFile::write(const void* buf, uint16_t nbyte) {
13251333

13261334
// number of bytes left to write - must be before goto statements
13271335
uint16_t nToWrite = nbyte;
1336+
// if blocking writes should be used
1337+
uint8_t blocking = (flags_ & F_FILE_NON_BLOCKING_WRITE) == 0x00;
13281338

13291339
// error if not a normal file or is read-only
13301340
if (!isFile() || !(flags_ & O_WRITE)) {
@@ -1383,7 +1393,7 @@ size_t SdFile::write(const void* buf, uint16_t nbyte) {
13831393
if (SdVolume::cacheBlockNumber_ == block) {
13841394
SdVolume::cacheBlockNumber_ = 0XFFFFFFFF;
13851395
}
1386-
if (!vol_->writeBlock(block, src)) {
1396+
if (!vol_->writeBlock(block, src, blocking)) {
13871397
goto writeErrorReturn;
13881398
}
13891399
src += 512;
@@ -1473,3 +1483,45 @@ void SdFile::writeln_P(PGM_P str) {
14731483
println();
14741484
}
14751485
#endif
1486+
//------------------------------------------------------------------------------
1487+
/**
1488+
Check how many bytes can be written without blocking.
1489+
1490+
\return The number of bytes that can be written without blocking.
1491+
*/
1492+
int SdFile::availableForWrite() {
1493+
if (!isFile() || !(flags_ & O_WRITE)) {
1494+
return 0;
1495+
}
1496+
1497+
// seek to end of file if append flag
1498+
if ((flags_ & O_APPEND) && curPosition_ != fileSize_) {
1499+
if (!seekEnd()) {
1500+
return 0;
1501+
}
1502+
}
1503+
1504+
if (vol_->isBusy()) {
1505+
return 0;
1506+
}
1507+
1508+
if (flags_ & F_FILE_CLUSTER_ADDED) {
1509+
// new cluster added, trigger a non-blocking sync
1510+
sync(0);
1511+
flags_ &= ~F_FILE_CLUSTER_ADDED;
1512+
return 0;
1513+
}
1514+
1515+
if (vol_->isCacheMirrorBlockDirty()) {
1516+
// cache mirror block is dirty, trigger a non-blocking sync
1517+
vol_->cacheMirrorBlockFlush(0);
1518+
return 0;
1519+
}
1520+
1521+
flags_ |= F_FILE_NON_BLOCKING_WRITE;
1522+
1523+
uint16_t blockOffset = curPosition_ & 0X1FF;
1524+
uint16_t n = 512 - blockOffset;
1525+
1526+
return n;
1527+
}

src/utility/SdVolume.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,23 +108,35 @@ uint8_t SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) {
108108
return true;
109109
}
110110
//------------------------------------------------------------------------------
111-
uint8_t SdVolume::cacheFlush(void) {
111+
uint8_t SdVolume::cacheFlush(uint8_t blocking) {
112112
if (cacheDirty_) {
113-
if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) {
113+
if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data, blocking)) {
114114
return false;
115115
}
116+
117+
if (!blocking) {
118+
return true;
119+
}
120+
116121
// mirror FAT tables
117-
if (cacheMirrorBlock_) {
118-
if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) {
119-
return false;
120-
}
121-
cacheMirrorBlock_ = 0;
122+
if (!cacheMirrorBlockFlush(blocking)) {
123+
return false;
122124
}
123125
cacheDirty_ = 0;
124126
}
125127
return true;
126128
}
127129
//------------------------------------------------------------------------------
130+
uint8_t SdVolume::cacheMirrorBlockFlush(uint8_t blocking) {
131+
if (cacheMirrorBlock_) {
132+
if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data, blocking)) {
133+
return false;
134+
}
135+
cacheMirrorBlock_ = 0;
136+
}
137+
return true;
138+
}
139+
//------------------------------------------------------------------------------
128140
uint8_t SdVolume::cacheRawBlock(uint32_t blockNumber, uint8_t action) {
129141
if (cacheBlockNumber_ != blockNumber) {
130142
if (!cacheFlush()) {

0 commit comments

Comments
 (0)