📄 nwprogp.nc
字号:
#include <Storage.h>
#include <Shell.h>
#include "imgNum2volumeId.h"
#include "Deluge.h"
#include "PrintfUART.h"
module NWProgP {
provides interface BootImage;
uses {
interface Boot;
interface UDP as Recv;
interface StorageMap[uint8_t imag_num];
interface NetProg;
interface BlockRead[uint8_t img_num];
interface BlockWrite[uint8_t img_num];
interface Resource;
interface DelugeMetadata;
interface Timer<TMilli> as RebootTimer;
event void storageReady();
interface ShellCommand;
}
} implementation {
enum {
S_IDLE,
S_BUSY,
};
uint8_t state;
struct sockaddr_in6 endpoint;
prog_reply_t reply;
prog_reply_t *read_buffer;
// SDH : if this is defined, we read back each packet after we write
// it and check that it matches. It turns out that this doesn't
// actually guarantee you much, due to buffering.
#undef PARANOID
#ifdef PARANOID
bool paranoid_read;
uint16_t cmp_len;
uint8_t cmp_img;
uint32_t cmp_off;
uint8_t cmp_buf[256];
#endif
// Begin-added by Jaein Jeong
command error_t BootImage.erase(uint8_t img_num) {
error_t error = call BlockWrite.erase[img_num]();
return error;
}
// End-added
command void BootImage.reboot() {
call NetProg.reboot();
}
command error_t BootImage.boot(uint8_t img_num) {
return call NetProg.programImageAndReboot(call StorageMap.getPhysicalAddress[img_num](0));
}
event void Boot.booted() {
#ifdef PARANOID
paranoid_read = FALSE;
#endif
state = S_IDLE;
call Recv.bind(5213);
}
void sendDone(error_t error) {
reply.error = error;
call Recv.sendto(&endpoint, &reply, sizeof(prog_reply_t));
}
event void Recv.recvfrom(struct sockaddr_in6 *from,
void *payload, uint16_t len,
struct ip_metadata *meta) {
prog_req_t *req = (prog_req_t *)payload;
uint8_t imgNum = imgNum2volumeId(req->imgno);
error_t error = FAIL;
void *buffer;
// just copy the payload out and write it into flash
// we'll send the ack from the write done event.
if (state != S_IDLE) return;
memcpy(&endpoint, from, sizeof(struct sockaddr_in6));
memcpy(&reply.req, req, sizeof(prog_req_t));
if (!call Resource.isOwner()) {
error = call Resource.immediateRequest();
}
if (error == SUCCESS) {
switch (req->cmd) {
case NWPROG_CMD_ERASE:
error = call BlockWrite.erase[imgNum]();
break;
case NWPROG_CMD_WRITE:
len -= sizeof(prog_req_t);
#ifdef PARANOID
if (len > sizeof(cmp_buf)) {
error = ENOMEM;
break;
}
memcpy(cmp_buf, req->data, len);
cmp_len = len;
cmp_off = req->cmd_data.offset;
cmp_img = imgNum;
#endif
buffer = ip_malloc(len);
if (buffer == NULL) {
error = ENOMEM;
break;
}
memcpy(buffer, req->data, len);
error = call BlockWrite.write[imgNum](req->cmd_data.offset,
buffer,
len);
if (error != SUCCESS) ip_free(buffer);
break;
case NWPROG_CMD_READ: {
read_buffer = (prog_reply_t *)ip_malloc(64 + sizeof(prog_reply_t));
if (read_buffer == NULL) {
error = ENOMEM;
break;
}
memcpy(&read_buffer->req, req, sizeof(prog_req_t));
error = call BlockRead.read[imgNum](req->cmd_data.offset,
read_buffer->req.data,
64);
if (error != SUCCESS) {
ip_free(read_buffer);
}
break;
}
default:
error = FAIL;
}
}
if (error != SUCCESS) {
sendDone(error);
if (call Resource.isOwner()) {
call Resource.release();
}
} else {
state = S_BUSY;
}
}
event void BlockWrite.writeDone[uint8_t img_num](storage_addr_t addr, void* buf, storage_len_t len, error_t error) {
if (state != S_BUSY) return;
#ifdef PARANOID
if (len != cmp_len) {
printfUART("WARNING: write length changed from %i to %lu!\n", cmp_len, len);
}
if (addr != cmp_off) {
printfUART("WARNING: write address changed from %li to %li!\n", cmp_off, addr);
}
if (img_num != cmp_img) {
printfUART("WARNING: write volume changed from %i to %i\n", cmp_img, img_num);
}
if (memcmp(buf, cmp_buf, cmp_len) != 0) {
printfUART("WARNING: write data changed during call!\n");
}
memset(buf, 0, cmp_len);
if (call BlockRead.read[cmp_img](cmp_off, buf, cmp_len) == SUCCESS) {
paranoid_read = TRUE;
return;
}
#else
ip_free(buf);
#endif
if (error == SUCCESS) {
call BlockWrite.sync[img_num]();
} else {
state = S_IDLE;
call Resource.release();
sendDone(error);
}
}
event void BlockRead.readDone[uint8_t img_num](storage_addr_t addr, void* buf, storage_len_t len, error_t error) {
#ifdef PARANOID
if (paranoid_read) {
if (len != cmp_len) {
printfUART("WARNING: read length changed from %u to %lu!\n", cmp_len, len);
}
if (addr != cmp_off) {
printfUART("WARNING: read address changed from %li to %li!\n", cmp_off, addr);
}
if (img_num != cmp_img) {
printfUART("WARNING: read volume changed from %i to %i\n", cmp_img, img_num);
}
if (memcmp(buf, cmp_buf, cmp_len) != 0) {
printfUART("WARNING: write data changed during call!\n");
} else {
printfUART("SUCCESS: write verified!\n");
}
paranoid_read = FALSE;
ip_free(buf);
if (error == SUCCESS) {
call BlockWrite.sync[img_num]();
} else {
call Resource.release();
state = S_IDLE;
sendDone(error);
}
return;
}
#endif
if (state != S_BUSY || buf != read_buffer->req.data) return;
call Resource.release();
read_buffer->error = error;
call Recv.sendto(&endpoint, read_buffer, sizeof(prog_reply_t) + 64);
ip_free(read_buffer);
state = S_IDLE;
}
event void BlockWrite.eraseDone[uint8_t img_num](error_t error) {
if (state != S_BUSY) return;
if (error == SUCCESS)
call BlockWrite.sync[img_num]();
else {
sendDone(error);
state = S_IDLE;
call Resource.release();
}
}
event void BlockWrite.syncDone[uint8_t img_num](error_t error) {
if (state != S_BUSY) return;
sendDone(error);
state = S_IDLE;
call Resource.release();
}
event void Resource.granted() {
}
/*
* Shell command implementation
*/
uint8_t nwprog_currentvol, nwprog_validvols;
uint8_t boot_image;
uint8_t volumeID2imgNum(uint8_t volumeID) {
switch(volumeID) {
case VOLUME_GOLDENIMAGE: return 0;
case VOLUME_DELUGE1: return 1;
case VOLUME_DELUGE2: return 2;
case VOLUME_DELUGE3: return 3;
}
}
event void DelugeMetadata.readDone(uint8_t imgNum, DelugeIdent* ident, error_t error) {
int len;
char *reply_buf = call ShellCommand.getBuffer(MAX_REPLY_LEN);
if (error == SUCCESS) {
if (ident->uidhash != DELUGE_INVALID_UID) {
len = snprintf(reply_buf, MAX_REPLY_LEN,
"image: %i\n\t[size: %li]\n\t[app: %s]\n\t[user: %s]\n\t[host: %s]\n\t[arch: %s]\n\t[time: 0x%lx]\n",
volumeID2imgNum(imgNum), ident->size, (char *)ident->appname, (char *) ident->username,
(char *)ident->hostname, (char *)ident->platform, (uint32_t)ident->timestamp);
nwprog_validvols++;
call ShellCommand.write(reply_buf, len);
}
}
if (++nwprog_currentvol < DELUGE_NUM_VOLUMES) {
call DelugeMetadata.read(imgNum2volumeId(nwprog_currentvol));
} else {
len = snprintf(reply_buf, MAX_REPLY_LEN,
"%i valid image(s)\n", nwprog_validvols);
call ShellCommand.write(reply_buf, len);
}
}
event void RebootTimer.fired() {
call BootImage.boot(boot_image);
}
event char *ShellCommand.eval(int argc, char **argv) {
char *nwprog_help_str = "nwprog [list | boot <imgno> [when] | reboot]\n";
if (argc >= 2) {
if (memcmp(argv[1], "list", 4) == 0) {
nwprog_currentvol = 0;
nwprog_validvols = 0;
call DelugeMetadata.read(imgNum2volumeId(nwprog_currentvol));
return NULL;
} else if (memcmp(argv[1], "boot", 4) == 0 && (argc == 3 || argc == 4)) {
uint32_t when = 15;
boot_image = atoi(argv[2]),
boot_image = imgNum2volumeId(boot_image);
if (argc == 4)
when = atoi(argv[3]);
if (when == 0)
call RebootTimer.stop();
else {
char *ack = call ShellCommand.getBuffer(15);
snprintf(ack, 15, "REBOOT %li\n", when);
call RebootTimer.startOneShot(when);
return ack;
}
return NULL;
} else if (memcmp(argv[1], "reboot", 6) == 0) {
call BootImage.reboot();
return NULL;
}
}
return nwprog_help_str;
}
default command error_t BlockWrite.write[uint8_t imgNum](storage_addr_t addr, void* buf, storage_len_t len) { return FAIL; }
default command error_t BlockWrite.erase[uint8_t imgNum]() { return FAIL; }
default command error_t BlockWrite.sync[uint8_t imgNum]() { return FAIL; }
default command error_t BlockRead.read[uint8_t imgNum](storage_addr_t addr, void* buf, storage_len_t len) {return FAIL;}
event void BlockRead.computeCrcDone[uint8_t imgNum](storage_addr_t addr, storage_len_t len,uint16_t crc, error_t error) {}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -