Fast skipping of large comment blocks
This is an extension/optimization of PR #2956. It uses the cached 512B block buffer to avoid heavy-weight read() in SdBaseFile. Even though this principle allowed the AVR to skip ~600KB of data within ~5 seconds, the impact on code base is huge, especially into well proven and long-term stable parts like reading a file from the SD card. The sole purpose of this PR is to show/verify the possibility of the AVR CPU in relation to adding thumbnails into MK3 G-codes. Moreover, this PR shall not be merged unless the missing/commented features are restored - especially file seeking and M84 search. PFW-1175
This commit is contained in:
parent
dcc6605809
commit
c3758d350e
8 changed files with 243 additions and 22 deletions
Firmware
|
@ -530,9 +530,21 @@ bool SdBaseFile::mkdir(SdBaseFile* parent, const uint8_t dname[11]) {
|
|||
* \return The value one, true, is returned for success and
|
||||
* the value zero, false, is returned for failure.
|
||||
*/
|
||||
bool SdBaseFile::open(const char* path, uint8_t oflag) {
|
||||
return open(cwd_, path, oflag);
|
||||
}
|
||||
bool SdBaseFile::open(const char* path, uint8_t oflag) {
|
||||
return open(cwd_, path, oflag);
|
||||
}
|
||||
|
||||
bool SdBaseFile::openFilteredGcode(SdBaseFile* dirFile, const char* path){
|
||||
if( open(dirFile, path, O_READ) ){
|
||||
gf.reset(0,0);
|
||||
// compute the block to start with
|
||||
if( ! computeNextFileBlock(&gf.block, &gf.offset) )
|
||||
return false;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Open a file or directory by name.
|
||||
*
|
||||
|
@ -1030,6 +1042,112 @@ int16_t SdBaseFile::read() {
|
|||
uint8_t b;
|
||||
return read(&b, 1) == 1 ? b : -1;
|
||||
}
|
||||
|
||||
int16_t SdBaseFile::readFilteredGcode() {
|
||||
// avoid calling the default heavy-weight read() for just one byte
|
||||
return gf.read_byte();
|
||||
}
|
||||
|
||||
void GCodeInputFilter::reset(uint32_t blk, uint16_t ofs){
|
||||
// @@TODO clean up
|
||||
block = blk;
|
||||
offset = ofs;
|
||||
cachePBegin = sd->vol_->cache()->data;
|
||||
// reset cache read ptr to its begin
|
||||
cacheP = cachePBegin;
|
||||
}
|
||||
|
||||
int16_t GCodeInputFilter::read_byte(){
|
||||
EnsureBlock(); // this is unfortunate :( ... other calls are using the cache and we can loose the data block of our gcode file
|
||||
|
||||
// assume, we have the 512B block cache filled and terminated with a '\n'
|
||||
// SERIAL_PROTOCOLPGM("read_byte enter:");
|
||||
// for(uint8_t i = 0; i < 16; ++i){
|
||||
// SERIAL_PROTOCOL( cacheP[i] );
|
||||
// }
|
||||
|
||||
const uint8_t *start = cacheP;
|
||||
uint8_t consecutiveCommentLines = 0;
|
||||
while( *cacheP == ';' ){
|
||||
for(;;){
|
||||
while( *(++cacheP) != '\n' ); // skip until a newline is found
|
||||
// found a newline, prepare the next block if block cache end reached
|
||||
if( cacheP - cachePBegin >= 512 ){
|
||||
// at the end of block cache, fill new data in
|
||||
sd->curPosition_ += cacheP - start;
|
||||
if( ! sd->computeNextFileBlock(&block, &offset) )goto fail;
|
||||
EnsureBlock(); // fetch it into RAM
|
||||
cacheP = start = cachePBegin;
|
||||
} else {
|
||||
if(++consecutiveCommentLines == 255){
|
||||
// SERIAL_PROTOCOLLN(sd->curPosition_);
|
||||
goto forceExit;
|
||||
}
|
||||
// peek the next byte - we are inside the block at least at 511th index - still safe
|
||||
if( *(cacheP+1) == ';' ){
|
||||
// consecutive comment
|
||||
++cacheP;
|
||||
++consecutiveCommentLines;
|
||||
}
|
||||
break; // found the real end of the line even across many blocks
|
||||
}
|
||||
}
|
||||
}
|
||||
forceExit:
|
||||
sd->curPosition_ += cacheP - start + 1;
|
||||
{
|
||||
int16_t rv = *cacheP++;
|
||||
|
||||
// prepare next block if needed
|
||||
if( cacheP - cachePBegin >= 512 ){
|
||||
// SERIAL_PROTOCOLLN(sd->curPosition_);
|
||||
if( ! sd->computeNextFileBlock(&block, &offset) )goto fail;
|
||||
// don't need to force fetch the block here, it will get loaded on the next call
|
||||
cacheP = cachePBegin;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
fail:
|
||||
// SERIAL_PROTOCOLLNPGM("CacheFAIL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool GCodeInputFilter::EnsureBlock(){
|
||||
if ( sd->vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_READ)){
|
||||
// terminate with a '\n'
|
||||
const uint16_t terminateOfs = (sd->fileSize_ - offset) < 512 ? (sd->fileSize_ - offset) : 512;
|
||||
sd->vol_->cache()->data[ terminateOfs ] = '\n';
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SdBaseFile::computeNextFileBlock(uint32_t *block, uint16_t *offset) {
|
||||
// error if not open or write only
|
||||
if (!isOpen() || !(flags_ & O_READ)) return false;
|
||||
|
||||
*offset = curPosition_ & 0X1FF; // offset in block
|
||||
if (type_ == FAT_FILE_TYPE_ROOT_FIXED) {
|
||||
*block = vol_->rootDirStart() + (curPosition_ >> 9);
|
||||
} else {
|
||||
uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_);
|
||||
if (*offset == 0 && blockOfCluster == 0) {
|
||||
// start of new cluster
|
||||
if (curPosition_ == 0) {
|
||||
// use first cluster in file
|
||||
curCluster_ = firstCluster_;
|
||||
} else {
|
||||
// get next cluster from FAT
|
||||
if (!vol_->fatGet(curCluster_, &curCluster_)) return false;
|
||||
}
|
||||
}
|
||||
*block = vol_->clusterStartBlock(curCluster_) + blockOfCluster;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/** Read data from a file starting at the current position.
|
||||
*
|
||||
|
@ -1443,7 +1561,7 @@ bool SdBaseFile::rmRfStar() {
|
|||
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
|
||||
* OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t).
|
||||
*/
|
||||
SdBaseFile::SdBaseFile(const char* path, uint8_t oflag) {
|
||||
SdBaseFile::SdBaseFile(const char* path, uint8_t oflag):gf(this) {
|
||||
type_ = FAT_FILE_TYPE_CLOSED;
|
||||
writeError = false;
|
||||
open(path, oflag);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue