📄 p30logp.nc
字号:
} /* * Invariant should be that everytime after an append completes, * nextFreeRecord should point to a valid free record slot. Uses * nextFreeRecord to append. */ command error_t Write.append[ storage_volume_t block ](void* buf, storage_len_t len) { record_meta_t recordMeta; myMount(block); // error check if(len > L_RECORD_DATA_SIZE) return EINVAL; // if non circular log, fail if((!call Circular.get[block]()) && (lastBlock[block] == (L_PARTITIONS(block) - 1)) && (nextFreeRecord[block] == (L_MAX_RECORDS_PER_BLOCK - 1))) return FAIL; m_state = S_APPEND; clientId = block; clientBuf = buf; clientLen = len; // if you try to log 0, just immediately succeed, this really shouldn't happen if(len == 0) { clientResult = SUCCESS; post signalDoneTask(); return SUCCESS; } // if readCookie was on SEEK_EOL, adjust it back to here if(readCookieOffset[block] == SEEK_EOL) readCookieOffset[block] = L_RAW_OFFSET(block, lastBlock[block], nextFreeRecord[block]) + sizeof(record_meta_t); // use next free record, write the INVALID, write the data, write the VALID recordMeta.status = RECORD_INVALID; recordMeta.length = len; call Flash.write(L_RAW_OFFSET(block, lastBlock[block], nextFreeRecord[block]), (uint8_t*) &recordMeta, sizeof(record_meta_t)); call Flash.write(L_RAW_OFFSET(block, lastBlock[block], nextFreeRecord[block]) + sizeof(record_meta_t), (uint8_t*) buf, len); recordMeta.status = RECORD_VALID; call Flash.write(L_RAW_OFFSET(block, lastBlock[block], nextFreeRecord[block]), (uint8_t*) &recordMeta, sizeof(record_meta_t)); nextFreeRecord[block]++; // see if you need to adjust blocks or shuffle if(nextFreeRecord[block] == L_MAX_RECORDS_PER_BLOCK) shuffleBlocks(block); clientResult = SUCCESS; post signalDoneTask(); return SUCCESS; } /* * We use nextFreeRecord to get the cookie */ command storage_cookie_t Write.currentOffset[ storage_volume_t block ]() { myMount(block); return L_RAW_OFFSET(block, lastBlock[block], nextFreeRecord[block]) + sizeof(record_meta_t); } /* * First we erase all the log data blocks so that they can be * reused. Then we zero the cookies and then write them to our * partitions like the append operation. If we crash in the middle, * you may have to erase again. However, if an erase does fail, at * least all your data will still be there, so that you can try * again. */ command error_t Write.erase[storage_volume_t block]() { uint32_t i; for(i = 0; i < L_PARTITIONS(block); i++) { call Flash.erase(L_BASE_BLOCK(block) + (i * P30_BLOCK_SIZE)); } mountBits[block] = 0; myMount(block); // ... starting block implicitly written by mount m_state = S_ERASE; clientId = block; clientResult = SUCCESS; post signalDoneTask(); return SUCCESS; } /* * Sync does nothing really because unlike the AT45DB, Intel P30 * writes directly through. */ command error_t Write.sync[storage_volume_t block]() { myMount(block); m_state = S_SYNC; clientId = block; clientResult = SUCCESS; post signalDoneTask(); return SUCCESS; } /* * Sanity check the read cookie and adjust for any other special * cookies. Because you can seek to the byte, must it is saved in * flash as records, you have to do a lot of tricky seeking, but * it's done here. Also has to handle any pages that are spilled * over. */ command error_t Read.read[ storage_volume_t block ](void* buf, storage_len_t len) { record_meta_t recordMeta; uint32_t recordCounter; uint32_t pageCounter; uint32_t offset; clientId = block; clientBuf = buf; clientResult = SUCCESS; myMount(block); m_state = S_READ; if(len == 0 || readCookieOffset[block] == SEEK_EOL) { clientResult = SUCCESS; clientLen = 0; post signalDoneTask(); return SUCCESS; } // adjust SEEK_BEGINNING to a real offset if(readCookieOffset[block] == SEEK_BEGINNING) { readCookieOffset[block] = L_RAW_OFFSET(block, firstBlock[block], 1) + sizeof(record_meta_t); } // convert the cookie to something useful cookieToTuple(readCookieOffset[block], block, &pageCounter, &recordCounter, &offset); // sanity check readCookie call Flash.read(L_RAW_OFFSET(block, pageCounter, recordCounter), (uint8_t*) &recordMeta, sizeof(record_meta_t)); if((recordMeta.status == RECORD_VALID) && (offset > len)) { readCookieOffset[block] = L_RAW_OFFSET(block, firstBlock[block], 0) + sizeof(record_meta_t); cookieToTuple(readCookieOffset[block], block, &pageCounter, &recordCounter, &offset); } clientLen = 0; // reset how much actually read and count up while(len != 0) { call Flash.read(L_RAW_OFFSET(block, pageCounter, recordCounter), (uint8_t*) &recordMeta, sizeof(record_meta_t)); if(recordMeta.status == RECORD_INVALID) { goto advance_counter; } if(recordMeta.status == RECORD_EMPTY) { readCookieOffset[block] = SEEK_EOL; post signalDoneTask(); return SUCCESS; } // read partial block and finish if(len < recordMeta.length + offset) { call Flash.read(L_RAW_OFFSET(block, pageCounter, recordCounter) + offset + sizeof(record_meta_t), buf, len); offset = len; buf = buf + len; len = 0; } else { call Flash.read(L_RAW_OFFSET(block, pageCounter, recordCounter) + offset + sizeof(record_meta_t), buf, recordMeta.length - offset); clientLen = clientLen + recordMeta.length - offset; len -= recordMeta.length - offset; buf = buf + recordMeta.length - offset; offset = 0; advance_counter: recordCounter++; if((recordCounter >= L_MAX_RECORDS_PER_BLOCK) && (pageCounter == lastBlock[block])) { readCookieOffset[block] = SEEK_EOL; post signalDoneTask(); return SUCCESS; } // need to adjust page possibly if spills // also need to check if reached end of log (lastBlock[block] or RECORD_AVAILABLE) if(recordCounter >= L_MAX_RECORDS_PER_BLOCK) { pageCounter = (pageCounter + 1) % L_PARTITIONS(block); recordCounter = 1; } } } readCookieOffset[block] = L_RAW_OFFSET(block, pageCounter, recordCounter) + sizeof(record_meta_t) + offset; post signalDoneTask(); return SUCCESS; } command storage_cookie_t Read.currentOffset[ storage_volume_t block ]() { myMount(block); return readCookieOffset[block]; } /* * Just set the cookie. If you seek into an invalid area, just set * it at SEEK_BEGINNING. */ command error_t Read.seek[ storage_volume_t block ](storage_cookie_t offset) { uint32_t page; uint32_t record; uint32_t recordOffset; record_meta_t recordMeta; myMount(block); clientId = block; clientResult = SUCCESS; m_state = S_SEEK; readCookieOffset[block] = offset; post signalDoneTask(); return SUCCESS; } /* * Go through all the pages, if it's a free page, count whatever is * available left. Add them all up. */ command storage_len_t Read.getSize[ storage_volume_t block ]() { storage_len_t len = 0; uint32_t i; uint32_t j; page_meta_t pageMeta; record_meta_t recordMeta; myMount(block); for(i = 0; i < L_PARTITIONS(block); i++) { call Flash.read(L_RAW_OFFSET(block, i, j), (uint8_t*) &pageMeta, sizeof(page_meta_t)); if(pageMeta.header != PAGE_AVAILABLE) { len = len + (sizeof(record_data_t) * L_MAX_RECORDS_PER_BLOCK); continue; } for(j = 1; j < L_MAX_RECORDS_PER_BLOCK; j++) { call Flash.read(L_RAW_OFFSET(block, i, j), (uint8_t*) &recordMeta, sizeof(record_meta_t)); if(recordMeta.status == RECORD_EMPTY) { len = len + ((L_MAX_RECORDS_PER_BLOCK - j) * sizeof(record_meta_t)); break; } } } return len; } default event void Read.readDone[ storage_volume_t block ](void* buf, storage_len_t len, error_t error) {} default event void Read.seekDone[ storage_volume_t block ](error_t error) {} default event void Write.appendDone[ storage_volume_t block ](void* buf, storage_len_t len, bool recordsLost, error_t error) {} default event void Write.eraseDone[ storage_volume_t block ](error_t error) {} default event void Write.syncDone[ storage_volume_t block ](error_t error) {} default command bool Circular.get[ uint8_t id ]() { return FALSE; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -