📄 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 + -