[Tinyos-contrib-commits] CVS: tinyos-1.x/contrib/rincon/apps/Blackbook5/core NodeShopM.nc, NONE, 1.1 GenericCrcM.nc, NONE, 1.1 WriteAllocM.nc, NONE, 1.1 BFileDeleteC.nc, NONE, 1.1 BDictionary.h, NONE, 1.1 CheckpointM.nc, NONE, 1.1 UtilM.nc, NONE, 1.1 BFileDirC.nc, NONE, 1.1 NodeMapC.nc, NONE, 1.1 FileioC.nc, NONE, 1.1 BFileReadM.nc, NONE, 1.1 BDictionaryM.nc, NONE, 1.1 UtilC.nc, NONE, 1.1 BCleanC.nc, NONE, 1.1 Blackbook.h, NONE, 1.1 BDictionaryC.nc, NONE, 1.1 CheckpointC.nc, NONE, 1.1 BCleanM.nc, NONE, 1.1 SectorMapC.nc, NONE, 1.1 NodeShopC.nc, NONE, 1.1 BFileWriteM.nc, NONE, 1.1 SectorMapM.nc, NONE, 1.1 WriteAllocC.nc, NONE, 1.1 BFileDirM.nc, NONE, 1.1 GenericCrcC.nc, NONE, 1.1 NodeMapM.nc, NONE, 1.1 BFileDeleteM.nc, NONE, 1.1 CheckpointDummyM.nc, NONE, 1.1 BlackbookConst.h, NONE, 1.1 BFileReadC.nc, NONE, 1.1 BFileWriteC.nc, NONE, 1.1 FileioM.nc, NONE, 1.1

dmm rincon at users.sourceforge.net
Thu May 18 15:34:22 PDT 2006


Update of /cvsroot/tinyos/tinyos-1.x/contrib/rincon/apps/Blackbook5/core
In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv14770/contrib/rincon/apps/Blackbook5/core

Added Files:
	NodeShopM.nc GenericCrcM.nc WriteAllocM.nc BFileDeleteC.nc 
	BDictionary.h CheckpointM.nc UtilM.nc BFileDirC.nc NodeMapC.nc 
	FileioC.nc BFileReadM.nc BDictionaryM.nc UtilC.nc BCleanC.nc 
	Blackbook.h BDictionaryC.nc CheckpointC.nc BCleanM.nc 
	SectorMapC.nc NodeShopC.nc BFileWriteM.nc SectorMapM.nc 
	WriteAllocC.nc BFileDirM.nc GenericCrcC.nc NodeMapM.nc 
	BFileDeleteM.nc CheckpointDummyM.nc BlackbookConst.h 
	BFileReadC.nc BFileWriteC.nc FileioM.nc 
Log Message:
Uploaded Initial Blackbook5

--- NEW FILE: NodeShopM.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Blackbook NodeShop Configuration
 *
 * NodeShop writes metadata for nodes and files to flash.
 *
 * @author David Moss (dmm at rincon.com)
 */
 
includes Blackbook;

module NodeShopM {
  provides {
    interface NodeShop;
  }
  
  uses {
    interface NodeMap;
    interface Util;
    interface State;
    interface SectorMap;
    interface FlashBridge;
  }
}

implementation {

  /** Pointer to the current node */
  node *currentNode;
  
  /** Pointer to the current file */
  file *currentFile;
  
  /** Filename pointer */
  filename *currentFilename;
  
  /** Node meta to write to flash */
  nodemeta currentNodeMeta;
  
  
  enum { 
    S_IDLE = 0,
    S_WRITE_NODEMETA,
    S_WRITE_FILEMETA,
    S_NODEMETA_DELETE,
    S_GET_FILENAME,
    S_CRC,
  };
  
  
  /***************** Prototypes ****************/
  /** Delete the current node */
  task void deleteMyNode();
  
  /** Write the nodemeta for the current node to flash */
  task void writeNodemeta();
  
  /** Write the filemeta for the current node to flash */
  task void writeFilemeta();
    
  /** Flush all changes to flash */
  task void flush();
  
  /** Get the CRC of the data in the current node */
  task void getMyNodeCrc();
  
  /** Signal completion for the current state */ 
  task void signalDone(); 
  
  /** Read the filename of a file from flash */
  task void readFilename();
 
  /***************** NodeShop Commands ****************/
  /**
   * Write the nodemeta to flash for the given node
   * @param focusedFile - the file
   * @param focusedNode - the node to write the nodemeta for
   * @param name - pointer to the filename
   */
  command result_t NodeShop.writeNodemeta(file *focusedFile, node *focusedNode, filename *name) {
    if(!call State.requestState(S_WRITE_NODEMETA)) {
      return FAIL;
    }
  
    currentNode = focusedNode;
    currentFile = focusedFile;
    currentFilename = name;
    
    currentNodeMeta.filenameCrc = currentNode->filenameCrc;
    currentNodeMeta.reserveLength = currentNode->reserveLength;
    currentNodeMeta.fileElement = currentNode->fileElement;
    
    if(focusedNode->state == NODE_CONSTRUCTING) {
      currentNodeMeta.magicNumber = META_CONSTRUCTING;
    } else {
      currentNodeMeta.magicNumber = META_VALID;
    }
    
    call SectorMap.freeSector(call SectorMap.getSectorAtAddress(currentNode->flashAddress));
    
    post writeNodemeta();
    
    return SUCCESS;
  }

  /**
   * Delete a node on flash. This will not erase the
   * data from flash, but it will simply mark the magic
   * number of the node to make it invalid.
   * 
   * After the command is called and executed, a metaDeleted
   * event will be signaled.
   *
   * @return SUCCESS if the magic number will be marked
   */
  command result_t NodeShop.deleteNode(node *focusedNode) { 
    if(!call State.requestState(S_NODEMETA_DELETE)) {
      return FAIL;
    }

    currentNode = focusedNode;

    post deleteMyNode();
    return SUCCESS;
  }
  
  /**
   * Get the CRC of a node on flash.
   *
   * After the command is called and executed, a crcCalculated
   * event will be signaled.
   *
   * @param focusedNode - the node to read and calculate a CRC for
   * @param focusedFile - the file belonging to the node
   * @return SUCCESS if the CRC will be calculated.
   */
  command result_t NodeShop.getCrc(node *focusedNode, file *focusedFile) {
    if(!call State.requestState(S_CRC)) {
      return FAIL;
    }
    
    currentNode = focusedNode;
    currentFile = focusedFile;
    
    post getMyNodeCrc();
    return SUCCESS;
  }

  /**
   * Get the filename for a file
   * @param focusedFile - the file to obtain the filename for
   * @param *name - pointer to store the filename
   */
  command result_t NodeShop.getFilename(file *focusedFile, filename *name) {
    if(!call State.requestState(S_GET_FILENAME)) {
      return FAIL;
    }
    
    currentFile = focusedFile;
    currentFilename = name;
    
    post readFilename();
    return SUCCESS;
  }
  
  /***************** FlashBridge Events ****************/
  /**
   * Write is complete
   * @param addr - the address to write to
   * @param *buf - the buffer to write from
   * @param len - the amount to write
   * @return SUCCESS if the bytes will be written
   */
  event void FlashBridge.writeDone(uint32_t addr, void *buf, uint32_t len, result_t result) {
    if(call State.getState() == S_WRITE_NODEMETA) {

      if(currentFile != NULL) {
        if(currentFile->firstNode == currentNode) {
          post writeFilemeta();
          return; 
        }
      }
      
      if(currentNode->state != NODE_CONSTRUCTING) {
        currentNode->state = NODE_VALID;
      }
      call SectorMap.documentNode(currentNode);
      
    } else if(call State.getState() == S_WRITE_FILEMETA) {      
      if(currentNode->state != NODE_CONSTRUCTING) {
        currentNode->state = NODE_VALID;
      }
      call SectorMap.documentNode(currentNode);

    } else if(call State.getState() == S_NODEMETA_DELETE) {
      call SectorMap.removeNode(currentNode);
      currentNode->state = NODE_DELETED;

    }
    
    post flush();
    return;
  }
  
  /**
   * Flush is complete
   * @param result - SUCCESS if the flash was flushed
   */
  event void FlashBridge.flushDone(result_t result) {
    post signalDone();
  }
  
  /**
   * CRC-16 is computed
   * @param crc - the computed CRC.
   * @param addr - the address to start the CRC computation
   * @param len - the amount of data to obtain the CRC for
   * @return SUCCESS if the CRC will be computed.
   */
  event void FlashBridge.crcDone(uint16_t calculatedCrc, uint32_t addr, uint32_t len, result_t result) {
    call State.toIdle();
    signal NodeShop.crcCalculated(calculatedCrc, result);
  }
  
  /**
   * Read is complete
   * @param addr - the address to read from
   * @param *buf - the buffer to read into
   * @param len - the amount to read
   * @return SUCCESS if the bytes will be read
   */
  event void FlashBridge.readDone(uint32_t addr, void *buf, uint32_t len, result_t result) {
    post signalDone();
  }
  
  
  /**
   * Erase is complete
   * @param sector - the sector id to erase
   * @return SUCCESS if the sector will be erased
   */
  event void FlashBridge.eraseDone(uint16_t sector, result_t result) {
  }
  
  
  /**
   * Signaled when the flash is ready to be used
   * @param result - SUCCESS if we can use the flash.
   */
  event void FlashBridge.ready(result_t result) {
  }
  


  /***************** Tasks ****************/
  /**
   * Write the magic number to flash to invalidate "currentNode"
   */
  task void deleteMyNode() {
    currentNodeMeta.magicNumber = META_INVALID;
    
    // Here we only want to write the new magicNumber to flash
    // Very nodemeta dependant.
    if(!call FlashBridge.write(currentNode->flashAddress, &currentNodeMeta.magicNumber, sizeof(currentNodeMeta.magicNumber))) {
      post deleteMyNode();
    }
  }
  
  /**
   * Write the nodemeta to flash
   */
  task void writeNodemeta() {
    if(!call FlashBridge.write(currentNode->flashAddress, &currentNodeMeta, sizeof(nodemeta))) {
      post writeNodemeta();
    }
  }

  /**
   * Write the filemeta to "currentNode"
   */
  task void writeFilemeta() {
    call State.forceState(S_WRITE_FILEMETA);
    if(!call FlashBridge.write(currentNode->flashAddress + sizeof(nodemeta), currentFilename, sizeof(filemeta))) {
      post writeFilemeta();
    }
  }
  
  /**
   * Get the CRC of all the data in the current node
   * It is assumed that currentNodeMeta.fileElement 
   * contains the element number of the current node.
   */
  task void getMyNodeCrc() {
    uint32_t dataStartAddress = currentNode->flashAddress + sizeof(nodemeta);
    if(currentFile->firstNode == currentNode) {
      dataStartAddress += sizeof(filemeta);
    }
    
    if(!call FlashBridge.crc(dataStartAddress, currentNode->dataLength)) {
      post getMyNodeCrc();
    }
  }
  
  /**
   * Read the currentFile's filename from flash
   */
  task void readFilename() {
    if(!call FlashBridge.read(currentFile->firstNode->flashAddress + sizeof(nodemeta), currentFilename, sizeof(filename))) {
      post readFilename();
    }
  }
  
  /** 
   * Flush changes to flash 
   */
  task void flush() {
    if(!call FlashBridge.flush()) {
      post flush();
    }
  }
  
  
  /** 
   * Signal task completion after
   * everything is set and finished and checkpointed.
   */
  task void signalDone() {
    uint8_t state = call State.getState();
    call State.toIdle();
    
    switch(state) {
      case S_WRITE_NODEMETA:
      case S_WRITE_FILEMETA:
        signal NodeShop.metaWritten(currentNode, SUCCESS);
        break;
        
      case S_NODEMETA_DELETE:
        signal NodeShop.metaDeleted(currentNode, SUCCESS);
        break;

      case S_GET_FILENAME:
        signal NodeShop.filenameRetrieved(currentFile, currentFilename, SUCCESS);
        break;
        
      default:
    }
  }
}


--- NEW FILE: GenericCrcM.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */


/**
 * GenericCrc configuration
 * Uses the same CRC algorithm as BlockStorage.
 * @author David Moss (dmm at rincon.com)
 */
 
includes crc;

module GenericCrcM {
  provides {
    interface GenericCrc;
  }
}

implementation {
  
  /**
   * Calculate the CRC from a buffer of data
   * of size len, starting with the crc given in 
   * startCrc. This uses the CRC algorithm found
   * in /tos/crc.h.
   *
   * @param startCrc - the starting crc value
   * @param *buf - the buffer of data to take a crc of
   * @param len - the amount of data to calculate the crc for
   * @return the crc.
   */
  command uint16_t GenericCrc.crc16(uint16_t startCrc, void *buf, uint32_t len) {
    uint8_t *buffer = (uint8_t *) buf;
    for ( ; len > 0; len--) {
      startCrc = crcByte(startCrc, *buffer++);
    }
    
    return startCrc;
  }

}


--- NEW FILE: WriteAllocM.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Blackbook File Write Allocator
 * This component allows you to open a file with the given name and minimum
 * size, and the given type for writing.  If the file already exists,
 * it will be opened and if needed, more space will be allocated to the file
 * to meet the new minimum space requirements.  If the file doesn't exist,
 * it will be allocated in both the NodeMap and on flash and created.
 * In the end, if enough space exists and the file is created successfully,
 * the node that can be written to in the file will be passed back.
 * When whatever component fills that node completely and wants to keep
 * writing, it will need to load up the next node in the file if it exists.
 * @author David Moss - dmm at rincon.com
 */
 
module WriteAllocM {
  provides {
    interface WriteAlloc;
  }
  
  uses {
    interface SectorMap;
    interface NodeMap;
    interface NodeBooter;
    interface NodeShop;
    interface State;
    interface BClean;
    interface Util;
  }
}

implementation {

  /** The file we're trying to open for writing */
  file *currentFile;
  
  /** The node we're working on */
  node *currentNode;
  
  /** The current sector we're looking at */
  flashsector *currentSector;
  
  /** Filename buffer */
  filename currentFilename;
  
  /** The minimum size to create the file */
  uint32_t minSize;
  
  /** The total size allocated to the file */
  uint32_t totalSize;
  
  /** Result to finish with */
  result_t finishResult;
  
  /** TRUE if this open write file is to be deleted if the mote reboots */
  bool constructing;
  
  /** TRUE if we are to only allocate one node for the file */
  bool onlyOneNode;
  
  /** The element number to set for the next allocated node */
  uint8_t nextElement;
  
  enum {
    S_IDLE = 0,
    S_OPEN,
  };

  /***************** Prototypes ****************/
  /** Set the 'finishResult' variable and call finish to signal completion */
  task void finish();
  
  /** Allocate space on flash for the currentNode */
  task void allocate();
  
  
  /** Allocate and test a single sector to the currentNode */
  result_t allocateOneSector();
  
  /** Function that deconstructs the file, sets the finishResult to fail, and completes */
  void fail();
  
  /** Deconstruct the current file */
  void closeCurrentFile();
 
  /** Find and unfinalize (if necessary) the first writable node of a file */
  void getWritableNode(); 
  
  
  /***************** WriteAlloc Commands ****************/
  /**
   * Open a file for writing
   * Create a file with the given name and the specified minimum length
   * @return SUCCESS if the file will be opened for writing.
   */
  command result_t WriteAlloc.openForWriting(char *fileName, uint32_t minimumSize, bool forceConstruction, bool oneNode) {
    node *lastNode;
    if(!call State.requestState(S_OPEN)) {
      return FAIL;
    }

    minSize = minimumSize;
    totalSize = 0;
    constructing = forceConstruction;
    onlyOneNode = oneNode;
    nextElement = 0;
       
    call Util.filenameCpy(&currentFilename, fileName);
    currentFile = call NodeMap.getFile(&currentFilename);
    
    if(currentFile == NULL || forceConstruction) {
      // The file does not exist and needs to be created
      if((currentFile = call NodeBooter.requestAddFile()) == NULL) {
        call State.toIdle();
        return FAIL;
      }
      
      if((currentNode = call NodeBooter.requestAddNode()) == NULL) {
        call State.toIdle();
        return FAIL;
      }
      
      currentFile->state = FILE_TEMPORARY;
      currentFile->filenameCrc = call Util.filenameCrc(&currentFilename);
      currentFile->firstNode = currentNode;

      currentNode->filenameCrc = currentFile->filenameCrc;
      currentNode->state = NODE_TEMPORARY;
      
      post allocate();
      return SUCCESS;
      
    } else {
      // The file already exists.

      if(currentFile->state != FILE_IDLE) {
        call State.toIdle();
        return FAIL;
      }

      currentNode = currentFile->firstNode;

      // Traverse through each existing node of the file.
      do {
        if(oneNode) {
          // This is a dictionary file, add up its reserveLength
          // because the dataLength isn't set when Checkpoint opens this up
          // during boot
          totalSize += currentNode->reserveLength;  
        } else {
          totalSize += currentNode->dataLength;
          minSize -= currentNode->dataLength;
        }
        
        lastNode = currentNode;
        nextElement++;
      } while((currentNode = currentNode->nextNode) != NULL);
      
      // 'lastNode' now contains the last node of the file.
      // 'currentNode' now contains NULL
      
      if((totalSize < minSize || lastNode->state == NODE_LOCKED) && !oneNode) {
        
        // Allocate more nodes to this file.
        if((currentNode = call NodeBooter.requestAddNode()) == NULL) {
          // Can't - we're out of nodes in our NodeMap.
          closeCurrentFile();
          return FAIL;
          
        } else {
          lastNode->nextNode = currentNode;
          currentNode->filenameCrc = currentFile->filenameCrc;
          currentNode->state = NODE_TEMPORARY;
          post allocate();
          return SUCCESS;
        }
        
      } else {
        // Enough reserve space exists already, hand it over.
        getWritableNode();
        return SUCCESS;
        
      }
    } 
    
    return SUCCESS;
  }
  
  /***************** NodeShop Events ****************/
  /** 
   * The node's metadata was written to flash
   * @param focusedNode - the node that metadata was written for
   * @param result - SUCCESS if it was written
   */
  event void NodeShop.metaWritten(node *focusedNode, result_t result) {
    if(call State.getState() == S_OPEN) {
      finishResult = SUCCESS;
      post finish();
    }
  }

  /**
   * The filename was retrieved from flash
   * @param focusedFile - the file that we obtained the filename for
   * @param *name - pointer to where the filename was stored
   * @param result - SUCCESS if the filename was retrieved
   */
  event void NodeShop.filenameRetrieved(file *focusedFile, filename *name, result_t result) {
  }
  
  /**
   * A node was deleted from flash by marking its magic number
   * invalid in the metadata.
   * @param focusedNode - the node that was deleted.
   * @param result - SUCCESS if the node was deleted successfully.
   */
  event void NodeShop.metaDeleted(node *focusedNode, result_t result) {
  }
 
  /**
   * A crc was calculated from node data on flash
   * @param dataCrc - the crc of the data read from the node on flash.
   * @param result - SUCCESS if the crc is valid
   */
  event void NodeShop.crcCalculated(uint16_t dataCrc, result_t result) {
  }
  
  
  /***************** BClean Tasks ****************/ 
  /**
   * Garbage Collection is complete
   * @return SUCCESS if any sectors were erased.
   */
  event void BClean.gcDone(result_t result) {
    if(call State.getState() == S_OPEN) {
      if(!allocateOneSector()) {
        fail();
      }
    }
  }
  
  event void BClean.erasing() {
  }
  
  /***************** Tasks ****************/
  /**
   * A node has already been reserved in the NodeMap,
   * this task will allocate space on flash for the node.
   */
  task void allocate() {
    if(!allocateOneSector()) {
      call BClean.gc();
    }
  }
  
  /**
   * Finish with the result stored in 'finishResult'
   */
  task void finish() {
    call State.toIdle(); 
    
    if(onlyOneNode) {
      // Dictionary nodes only use one node, and their dataLength is always full.
      currentNode->dataLength = currentNode->reserveLength;
    }
    
    totalSize += currentNode->reserveLength;
    
    // The totalSize here is actually the append address in the file,
    // if we're finishing successfully.
    signal WriteAlloc.openedForWriting(currentFile, currentNode, totalSize, finishResult);
  }

  
  /***************** Functions ****************/
  /**
   * This function will allocate one sector for the currentNode
   * and determine if we need to allocate more sectors
   * for binary files.  When enough space is allocated, it finishes
   * up and returns the first writable node.  If it can't find enough
   * space, it returns FAIL, which will either run the garbage collector
   * or stop the allocation process.
   */
  result_t allocateOneSector() {
    node *lastNode;
    uint8_t metaSize = sizeof(nodemeta);
    
    
    if((currentSector = call SectorMap.nextLargestIdleSector()) == NULL) {
      // No free sectors
      return FAIL;
      
    } else {
      call SectorMap.reserveSector(currentSector);
      currentNode->flashAddress = call SectorMap.getSectorWriteAddress(currentSector);
      currentNode->dataLength = 0;
      currentNode->dataCrc = 0;
      currentNode->fileElement = nextElement;
      nextElement++;
            
      if(currentFile->firstNode == currentNode) {
        metaSize += sizeof(filemeta);
      }
      
      currentNode->reserveLength = call SectorMap.bytesRemaining(currentSector);  
      
      if(call Util.convertBytesToPages(currentNode->reserveLength) > call Util.convertBytesToPages(minSize + metaSize - totalSize)) {
        // Too much space was allocated from the sector, back it off
        currentNode->reserveLength = call Util.convertPagesToBytes(call Util.convertBytesToPages(minSize + metaSize - totalSize));
      }

      currentNode->reserveLength -= metaSize;
      totalSize += currentNode->reserveLength;
      
      if(totalSize < minSize) {
        // Need to allocate more space
        lastNode = currentNode;
        if(onlyOneNode || (currentNode = call NodeBooter.requestAddNode()) == NULL) {
          // We're out of nodes in our NodeMap, or we're trying to
          // create a dictionary file that requires a single node.
          fail();
      
        } else {
          lastNode->nextNode = currentNode;
          currentNode->filenameCrc = currentFile->filenameCrc;
          currentNode->state = NODE_TEMPORARY;
          post allocate();
          return SUCCESS;
          
        }
      
      } else {
        // Enough space is allocated - unfinalize the first temporary node
        getWritableNode();
      }
        
      return SUCCESS;
    }
  }
  
  /**
   * Find the first writable node of the file. If it needs
   * to be unfinalized, unfinalize it.  Finish up by
   * signaling completion with the first writable unfinalized node.
   * The app will write to the node after the node's dataLength
   * location.
   */
  void getWritableNode() {
    totalSize = 0;  // here, totalSize is used in the signal to reflect the append address 
    currentNode = currentFile->firstNode;
    currentFile->state = FILE_WRITING;
    
    do {
      totalSize += currentNode->dataLength;
      
      // Traverse through each existing node of the file.
      // Find the first writable node.
      // Checkpoint files, on boot, will still be in state NODE_BOOTING,
      // So change them over.
      if(currentNode->state == NODE_VALID || currentNode->state == NODE_BOOTING) {
        currentNode->state = NODE_VALID;
        finishResult = SUCCESS;
        post finish();
        return;
        
      } else if(currentNode->state == NODE_TEMPORARY) {
        if(constructing) {
          currentNode->state = NODE_CONSTRUCTING;
        }
        
        call NodeShop.writeNodemeta(currentFile, currentNode, &currentFilename);
        return;
        
      }
    } while((currentNode = currentNode->nextNode) != NULL);
    
    fail();  // Something bad happened. We should have succeeded.
  }
  
  
  /**
   * This operation failed.
   */
  void fail() {
    closeCurrentFile();
    finishResult = FAIL;
    post finish();
  }
  
  /**
   * Deallocate and close all nodes for the current
   * binary file - this happens before any interaction
   * outside of WriteAlloc so no changes need to be
   * made to flash.
   */
  void closeCurrentFile() {
    if(currentFile->state == FILE_TEMPORARY) {
      currentFile->state = FILE_EMPTY;
      
    } else if(currentFile->state == FILE_WRITING) {
      currentFile->state = FILE_IDLE;
      
    }
    
    currentNode = currentFile->firstNode;
    
    do {
      if(currentNode->state == NODE_TEMPORARY) {
        call SectorMap.freeSector(call SectorMap.getSectorAtAddress(currentNode->flashAddress));
        currentNode->state = NODE_EMPTY;
      }
    } while((currentNode = currentNode->nextNode) != NULL);
  }
}


--- NEW FILE: BFileDeleteC.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Blackbook Delete Configuration
 * Invalidate a file on flash
 * 
 * @author David Moss - dmm at rincon.com
 */
 
includes Blackbook;

configuration BFileDeleteC {
  provides {
    interface BFileDelete[uint8_t id];
  }
  
  uses {
    interface Checkpoint;
  }
}

implementation {
  components BFileDeleteM, NodeShopC, NodeMapC, StateC, UtilC;
  
  BFileDelete = BFileDeleteM;
  
  Checkpoint = BFileDeleteM;
  
  BFileDeleteM.NodeShop -> NodeShopC;
  BFileDeleteM.NodeMap -> NodeMapC;
  BFileDeleteM.BlackbookState -> StateC.State[BLACKBOOK_STATE];
  BFileDeleteM.Util -> UtilC;
}


--- NEW FILE: BDictionary.h ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Keeping the most recently used keys from a file in memory 
 * decreases search time at the expense of RAM.
 */
typedef struct keycache {

  /** The key */
  uint32_t key;
  
  /** 
   * The data offset in the file to reach the beginning of the key
   * 0xFFFF means this entire cache key is invalid 
   */
  uint32_t keyOffset;
  
} keycache;


/**
 * Each client can have an open dictionary
 * simultaneously.  This structure keeps
 * track of the client's dictionary information
 * and state 
 */
typedef struct clientDictionary {

  /** Pointer to the node containing this client's dictionary */
  file *dictionaryFile;
  
  /** The data offset to the location of the next key write address */
  uint32_t writeOffset;

  /** The latest written keys in the file */
  keycache recent[MAX_KEY_CACHE];

  /** The name of the client's dictionary file to store in RAM */
  filename fname;
  
} clientDictionary;
  

/**
 * This is a key-value pair to be inserted into
 * a Dictionary file.  The value can be any size,
 * and the address of the valueStart variable
 * is where to start writing the data
 */
typedef struct keymeta {
  
  /** The magic number for a valid key-value pair entry */
  uint16_t magicNumber;
  
  /** The key */
  uint32_t key;
  
  /** The CRC of the value */
  uint16_t valueCrc;
    
  /** The length of the value */
  uint16_t valueLength;

} keymeta;



/**
 * Dictionary Magic Words
 */
enum {
  KEY_EMPTY = 0xFFFF,      // binary 1111
  KEY_VALID = 0xAAAA,      // binary 1010
  KEY_INVALID = 0x8888,    // binary 1000
  
  ENTRY_INVALID = 0xFFFFFFFF,
  
  DICTIONARY_HEADER = 0xD1C7,
};









--- NEW FILE: CheckpointM.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Blackbook Checkpoint Module
 * Saves the state of open binary nodes to a Checkpoint
 * dicationary file on flash for catastrophic failure recovery.
 *
 * Use unique("Checkpoint") when connecting to a parameterized interface
 *
 * @author David Moss - dmm at rincon.com
 */
 
includes BDictionary;
 
module CheckpointM {
  provides {
    interface Checkpoint;
    interface StdControl;
  }
  
  uses {
    interface NodeMap;
    interface NodeShop; 
    interface BDictionary;
    interface InternalDictionary;
    interface State;
    interface Util;
  }
}

implementation {
  
  /** TRUE if we currently have a checkpoint file open for interaction */
  bool checkpointFileOpened;
  
  /** The current checkpoint information being read or written to flash */
  checkpoint currentCheckpoint;
  
  /** Buffer to store a dictionary magic header */
  uint16_t dictionaryHeaderBuffer;

  /** Current node to repair */  
  node *currentNode;
 
  /** Checkpoint States */
  enum {
    S_IDLE = 0,
    S_OPEN,
    S_UPDATE,
    S_RECOVER,
  };
  
  /***************** Prototypes ****************/
  /** Verify all bytes in the last recovered point in a node are blank */
  task void verifyRecoveryPoint();
  
  /** Delete the current page on flash */
  task void deleteOnePage();
  
  /** Perform a full sector verification, marking off all unclean pages */
  task void fullVerify();
  
  /** Mark the attempted recover node as deleted */
  void markNodeDeleted();
  
  /***************** StdControl ****************/
  command result_t StdControl.init() {
    checkpointFileOpened = FALSE;
    return SUCCESS;
  }
  
  command result_t StdControl.start() {
    return SUCCESS;
  }
  
  command result_t StdControl.stop() {
    return SUCCESS;
  }
  
  /***************** Checkpoint Commands ****************/
  /**
   * After boot is complete, open the checkpoint file
   * in the BDictionary
   * @return SUCCESS if the checkpoint file will be 
   *     created and/or opened.
   */
  command result_t Checkpoint.openCheckpoint() {
    if(!checkpointFileOpened) {
      if(!call State.requestState(S_OPEN)) {
        return FAIL;
      }
      
      if(!call BDictionary.open("chkpoint.bb_", call Util.convertPagesToBytes(CHECKPOINT_DEDICATED_PAGES))) {
        call State.toIdle();
        return FAIL;
      }
      
    } else {
      call State.toIdle();
      signal Checkpoint.checkpointOpened(SUCCESS);
    }

    return SUCCESS;
  }
  
  /**
   * Update a node.
   * @param focusedNode - the node to save or delete
   * @return SUCCESS if the information will be updated
   */
  command result_t Checkpoint.update(node *focusedNode) {
    if(!call State.requestState(S_UPDATE)) {
      return FAIL;
    }
    
    currentNode = focusedNode;
    
    if(currentNode == NULL) {
      call State.toIdle();
      return FAIL;
    }
    
    if(currentNode->state == NODE_VALID) {
      // This node needs to be saved.
      currentCheckpoint.filenameCrc = currentNode->filenameCrc;
      currentCheckpoint.dataCrc = currentNode->dataCrc;
      currentCheckpoint.dataLength = currentNode->dataLength;
      
      if(currentNode->nextNode->state == NODE_VALID) {
        currentNode->state = NODE_LOCKED;
      }
      
      if(!call BDictionary.insert(currentNode->flashAddress, &currentCheckpoint, sizeof(checkpoint))) {
        call State.toIdle();
        return FAIL;
      }
      
    } else if(currentNode->state == NODE_DELETED) {
      // This node should be removed from the Checkpoint.
      if(!call BDictionary.remove(currentNode->flashAddress)) {
        call State.toIdle();
        return FAIL;
      }
            
    } else {
      // Nothing to do. Signal and complete.
      call State.toIdle();
      signal Checkpoint.updated(currentNode, SUCCESS);
    }
    
    return SUCCESS;
  }
  
  /**
   * Recover a node's dataLength and dataCrc
   * from the Checkpoint.
   *
   * If the node cannot be recovered, it is deleted.
   *
   * @param focusedNode - the node to recover, with client set to its element number
   * @return SUCCESS if recovery will proceed
   */
  command result_t Checkpoint.recover(node *focusedNode) {
    if(!call State.requestState(S_RECOVER)) {
      return FAIL;
    }
    
    currentNode = focusedNode;
    call BDictionary.retrieve(currentNode->flashAddress, &currentCheckpoint, sizeof(currentCheckpoint));
    return SUCCESS;
  }
  
  /***************** BDictionary Events ****************/
  
  /**
   * A Dictionary file was opened successfully.
   * @param totalSize - the total amount of flash space dedicated to storing
   *     key-value pairs in the file
   * @param remainingBytes - the remaining amount of space left to write to
   * @param result - SUCCESS if the file was successfully opened.
   */
  event void BDictionary.opened(uint32_t totalSize, uint32_t remainingBytes, result_t result) {
    checkpointFileOpened = TRUE;
    call State.toIdle();
    signal Checkpoint.checkpointOpened(result);
  }
  
  /** 
   * The opened Dictionary file is now closed
   * @param result - SUCCSESS if there are no open files
   */
  event void BDictionary.closed(result_t result) {
    checkpointFileOpened = FALSE;
  }
  
  /**
   * A key-value pair was inserted into the currently opened Dictionary file.
   * @param key - the key used to insert the value
   * @param value - pointer to the buffer containing the value.
   * @param valueSize - the amount of bytes copied from the buffer into flash
   * @param result - SUCCESS if the key was written successfully.
   */
  event void BDictionary.inserted(uint32_t key, void *value, uint16_t valueSize, result_t result) {
    call State.toIdle();
    signal Checkpoint.updated(currentNode, result);
  }
  
  /**
   * A value was retrieved from the given key.
   * @param key - the key used to find the value
   * @param valueHolder - pointer to the buffer where the value was stored
   * @param valueSize - the actual size of the value.
   * @param result - SUCCESS if the value was pulled out and is uncorrupted
   */
  event void BDictionary.retrieved(uint32_t key, void *valueHolder, uint16_t valueSize, result_t result) {
    if(result) {
      if(currentNode->filenameCrc == currentCheckpoint.filenameCrc) {
        currentNode->state = NODE_LOCKED;
        currentNode->dataLength = currentCheckpoint.dataLength;
        currentNode->dataCrc = currentCheckpoint.dataCrc;
        call State.toIdle();
        signal Checkpoint.recovered(currentNode, SUCCESS);
        return;
      }
    }
      
    // Recovery failed
    if(currentNode->fileElement == 0) {
      if(call InternalDictionary.isFileDictionary(call NodeMap.getFileFromNode(currentNode))) {
        return;
      }
    }
    
    call NodeShop.deleteNode(currentNode); 
    
  }
  
  /**
   * A key-value pair was removed
   * @param key - the key that should no longer exist
   * @param result - SUCCESS if the key was really removed
   */
  event void BDictionary.removed(uint32_t key, result_t result) {
    if(call State.getState() == S_UPDATE) {
      call State.toIdle();
      signal Checkpoint.updated(currentNode, result);
      
    } else if(call State.getState() == S_RECOVER) {
      call State.toIdle();
      signal Checkpoint.recovered(currentNode, result);
    }
  }
  
  /**
   * The next key in the open Dictionary file
   * @param key - the next key
   * @param result - SUCCESS if this information is valid
   */
  event void BDictionary.nextKey(uint32_t nextKey, result_t result) {
  }
  
  event void BDictionary.fileIsDictionary(bool isDictionary, result_t result) {
    if(call State.getState() == S_RECOVER) {
      if(result && isDictionary) {
        currentNode->dataLength = currentNode->reserveLength;
        currentNode->state = NODE_VALID;
        call State.toIdle();
        signal Checkpoint.recovered(currentNode, result);
      
      } else {
        call NodeShop.deleteNode(currentNode);
      }
    }
  }
  
  /***************** NodeShop Events ****************/
  
  /** 
   * The node's metadata was written to flash
   * @param focusedNode - the node that metadata was written for
   * @param result - SUCCESS if it was written
   */
  event void NodeShop.metaWritten(node *focusedNode, result_t result) {
  }
  
  /**
   * The filename was retrieved from flash
   * @param focusedFile - the file that we obtained the filename for
   * @param *name - pointer to where the filename was stored
   * @param result - SUCCESS if the filename was retrieved
   */
  event void NodeShop.filenameRetrieved(file *focusedFile, filename *name, result_t result) {
  }
  
  /**
   * A node was deleted from flash by marking its magic number
   * invalid in the metadata.
   * @param focusedNode - the node that was deleted.
   * @param result - SUCCESS if the node was deleted successfully.
   */
  event void NodeShop.metaDeleted(node *focusedNode, result_t result) {
    file *focusedFile;
    
    if(call State.getState() == S_RECOVER) {
      if((focusedFile = call NodeMap.getFileFromNode(focusedNode)) != NULL) {
        if(focusedFile->firstNode == focusedNode) {
          focusedFile->state = FILE_EMPTY;
        }
      }
      focusedNode->state = NODE_EMPTY;
      call BDictionary.remove(currentNode->flashAddress);
      return; 
    }
  }
 
  /**
   * A crc was calculated from node data on flash
   * @param dataCrc - the crc of the data read from the node on flash.
   * @param result - SUCCESS if the crc is valid
   */
  event void NodeShop.crcCalculated(uint16_t dataCrc, result_t result) {
  }
  

}



--- NEW FILE: UtilM.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Blackbook Utilities
 * @author dmm
 */

includes Blackbook;
includes FlashSettings;
includes Storage;

module UtilM {
  provides {
    interface Util;
  }
  uses {
    interface GenericCrc;
  }
}

implementation {
  
  /***************** Util Commands ****************/
  /**
   * Convert the specified length of data
   * into number of flash pages. This always rounds up except
   * when it's right on.
   * @return the number of pages on flash required
   *     to hold the data
   */
  command uint16_t Util.convertBytesToPages(uint32_t bytes) {
    return (bytes >> FLASH_PAGE_SIZE_LOG2) + 1;
  }
    
  /**
   * Convert the specified number of flash pages
   * to bytes
   * @return the number of bytes in the given number of flash pages
   */
  command uint32_t Util.convertPagesToBytes(uint16_t pages) {
    return pages * FLASH_PAGE_LENGTH;
  }
  
  /**
   * Get the address of the first byte of the next page  
   * based on a given address
   * @param currentAddress -
   */
  command uint32_t Util.getNextPageAddress(uint32_t currentAddress) {
    return FLASH_PAGE_LENGTH * ((currentAddress >> FLASH_PAGE_SIZE_LOG2) + 1);
  }
  
  /**
   * Get the address of the first byte of the next sector
   * @param currentAddress -
   * @return the base address of the next flash sector
   */
  command uint32_t Util.getNextSectorAddress(uint32_t currentAddress) {
    return FLASH_SECTOR_LENGTH * ((currentAddress >> FLASH_SECTOR_SIZE_LOG2) + 1);
  }
  
  /**
   * Copy a string filename from one char
   * array to a filename
   */
  command void Util.filenameCpy(filename *to, char *from) {
    int i;
    char *destPtr = (char *) to->getName;
    memset(destPtr, '\0', FILENAME_LENGTH);
 
    for(i = 0; i < FILENAME_LENGTH-1; i++) {
      if(!(*destPtr++ = *from++)) {
        return;
      }
    }
    *destPtr = '\0';
  }
  
  /**
   * @return the crc-16 of a a given filename
   */
  command uint16_t Util.filenameCrc(filename *focusedFilename) {
    return call GenericCrc.crc16(0, focusedFilename, FILENAME_LENGTH);
  }
}


--- NEW FILE: BFileDirC.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Blackbook File Dir Configuration
 * Allows the application to find out information about the
 * file system and flash usage.
 * @author David Moss - dmm at rincon.com
 */

includes Blackbook;

configuration BFileDirC {
  provides { 
    interface BFileDir[uint8_t id];
  }
}

implementation {
  components BFileDirM, NodeMapC, SectorMapC, NodeShopC, BDictionaryC, UtilC, StateC;
  
  BFileDir = BFileDirM;
  
  BFileDirM.SectorMap -> SectorMapC;
  BFileDirM.NodeMap -> NodeMapC;
  BFileDirM.NodeShop -> NodeShopC;
  BFileDirM.BlackbookState -> StateC.State[BLACKBOOK_STATE];
  BFileDirM.BDictionary -> BDictionaryC.BDictionary[INTERNAL_DICTIONARY];
  BFileDirM.InternalDictionary -> BDictionaryC.InternalDictionary[INTERNAL_DICTIONARY];
  BFileDirM.Util -> UtilC;
  
}


--- NEW FILE: NodeMapC.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

 
/**
 * Blackbook NodeMap Configuration
 * Maintains a record of all the files and nodes existing on flash in memory.
 * Allows access to general file system information through NodeMap interface
 * File system modifications through NodeBooter interface
 * @author David Moss (dmm at rincon.com)
 */
 
includes Blackbook;

configuration NodeMapC {
  provides {
    interface NodeMap;
    interface NodeBooter;
    interface StdControl;
  }
}

implementation {
  components NodeMapM, StateC, SectorMapC, UtilC;
  
  NodeMap = NodeMapM;
  NodeBooter = NodeMapM;
  
  StdControl = NodeMapM;
  
  NodeMapM.SectorMap -> SectorMapC;
  NodeMapM.Util -> UtilC;
}



--- NEW FILE: FileioC.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Blackbook Fileio Configuration
 * Writes data to an address in a file, fills up each node
 * and automatically loads the next node for writing.
 *
 * @author David Moss - dmm at rincon.com
 */
 
configuration FileioC {
  provides {
    interface StdControl;
    interface Fileio;
  }
}

implementation {
  components FileioM, FlashBridgeC, NodeShopC, NodeMapC, StateC, GenericCrcC;
  
  Fileio = FileioM;
  StdControl = FlashBridgeC;
  
  FileioM.FlashBridge -> FlashBridgeC.FlashBridge[unique("FlashBridge")];
  FileioM.GenericCrc -> GenericCrcC;
  FileioM.NodeShop -> NodeShopC;
  FileioM.NodeMap -> NodeMapC; 
  FileioM.State -> StateC.State[unique("State")];

}

--- NEW FILE: BFileReadM.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Blackbook BFileRead Configuration
 * Open, Read, Close Blackbook files.
 * Use unique("BFileRead") when connecting to a parameterized
 * interface.
 * @author David Moss - dmm at rincon.com
 */

includes Blackbook;

module BFileReadM {
  provides {
    interface BFileRead[uint8_t id];
    interface StdControl;
  }
  
  uses {
    interface State as BlackbookState;
    interface Fileio;
    interface NodeMap;
    interface Util;
  }
}

implementation {

  /**Each client's current read information */
  struct filereader {

    /** The current file open for writing, NULL if no file is open */
    file *openFile;
    
    /** The position to read from in the current open node */
    uint32_t readAddress;
  
  } readers[uniqueCount("BFileRead")];


  /** The current client we're working with */
  uint8_t currentClient;
  
  /***************** Prototypes ****************/  

  
  /***************** StdControl Commands ****************/
  command result_t StdControl.init() {
    int i;
    for(i = 0; i < uniqueCount("BFileRead"); i++) {
      readers[i].openFile = NULL;
    }
    return SUCCESS;
  }
  
  command result_t StdControl.start() {
    return SUCCESS;
  }
  
  command result_t StdControl.stop() {
    return SUCCESS;
  }
  
  
  /***************** BFileRead Commands ****************/
  /**
   * Open a file for reading
   * @param fileName - name of the file to open
   * @return SUCCESS if the attempt to open for reading proceeds
   */ 
  command result_t BFileRead.open[uint8_t id](char *fileName) {
    filename currentFilename;
    
    if(!call BlackbookState.requestState(S_READ_BUSY)) {
      return FAIL;
    }

    currentClient = id;
    call Util.filenameCpy(&currentFilename, fileName);
    
    if(readers[currentClient].openFile == NULL) {
      if((readers[currentClient].openFile = call NodeMap.getFile(&currentFilename)) != NULL) {
        readers[currentClient].openFile->state = FILE_READING;
        readers[currentClient].readAddress = 0;
        call BlackbookState.toIdle();    
        signal BFileRead.opened[currentClient](call NodeMap.getDataLength(readers[currentClient].openFile), SUCCESS);
        return SUCCESS;
      }
    }    
    
    call BlackbookState.toIdle();
    return FAIL;
  }

  /**
   * Close any currently opened file
   */
  command result_t BFileRead.close[uint8_t id]() {
    if(readers[currentClient].openFile != NULL) {
      readers[currentClient].openFile->state = FILE_IDLE;
    }
    
    readers[currentClient].openFile = NULL;
    signal BFileRead.closed[id](SUCCESS);
    return SUCCESS;
  }

  /**
   * Read a specified amount of data from the open
   * file into the given buffer
   * @param *dataBuffer - the buffer to read data into
   * @param amount - the amount of data to read
   * @return SUCCESS if the command goes through
   */
  command result_t BFileRead.read[uint8_t id](void *dataBuffer, uint16_t amount) {
    if(!call BlackbookState.requestState(S_READ_BUSY)) {
      return FAIL;
    }
    
    currentClient = id;

    if((readers[currentClient].openFile == NULL) 
        || !call Fileio.readData(readers[currentClient].openFile, readers[currentClient].readAddress, dataBuffer, amount)) {
      call BlackbookState.toIdle();
      return FAIL;
    }
    
    return SUCCESS;
  }

  /**
   * Seek a given address to read from in the file.
   *
   * @param fileAddress - the address to seek
   * @return SUCCESS if the read pointer is adjusted,
   *         FAIL if the read pointer didn't change
   */
  command result_t BFileRead.seek[uint8_t id](uint32_t fileAddress) {
    readers[id].readAddress = fileAddress;
    return SUCCESS;
  }

  /**
   * Skip the specified number of bytes in the file
   * @param skipLength - number of bytes to skip
   * @return SUCCESS if the internal read pointer was adjusted
   */
  command result_t BFileRead.skip[uint8_t id](uint16_t skipLength) {
    readers[id].readAddress += skipLength;
    return SUCCESS;
  }

  /**
   * Get the remaining bytes available to read from this file.
   * This is the total size of the file minus your current position.
   * @return the number of remaining bytes in this file 
   */
  command uint32_t BFileRead.getRemaining[uint8_t id]() {
    if(readers[id].openFile == NULL) {
      return 0;
    } 
    
    return (call NodeMap.getDataLength(readers[id].openFile)) - readers[id].readAddress;
  }

  /***************** Fileio Events ****************/
  /**
   * Data was read from the file
   * @param *readBuffer - pointer to the location where the data was stored
   * @param amountRead - the amount of data actually read
   * @param result - SUCCESS if the data was successfully read
   */
  event void Fileio.readDone(void *readBuffer, uint32_t amountRead, result_t result) {
    if(call BlackbookState.getState() == S_READ_BUSY) {
      readers[currentClient].readAddress += amountRead;
      call BlackbookState.toIdle();
      signal BFileRead.readDone[currentClient](readBuffer, amountRead, result);
    }
  }
  
  /**
   * Data was appended to the node in the flash.
   * @param writeBuffer - pointer to the buffer containing the data written
   * @param amountWritten - the amount of data appended to the node.
   * @param result - SUCCESS if the data was successfully written
   */
  event void Fileio.writeDone(void *writeBuffer, uint32_t amountWritten, result_t result) {
  }

  /**
   * Data was flushed to flash
   * @param result - SUCCESS if the data was flushed
   */
  event void Fileio.flushDone(result_t result) {
  }
    
  /***************** Defaults ****************/
  default event void BFileRead.opened[uint8_t id](uint32_t amount, result_t result) {
  }

  default event void BFileRead.closed[uint8_t id](result_t result) {
  }

  default event void BFileRead.readDone[uint8_t id](void *buf, uint16_t amount, result_t result) {
  }
  
}




--- NEW FILE: BDictionaryM.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
[...1392 lines suppressed...]

  default event void BDictionary.closed[uint8_t id](result_t result) {
  }

  default event void BDictionary.inserted[uint8_t id](uint32_t key, void *value, uint16_t valueSize, result_t result) {
  }

  default event void BDictionary.retrieved[uint8_t id](uint32_t key, void *valueHolder, uint16_t valueSize, result_t result) {
  }

  default event void BDictionary.removed[uint8_t id](uint32_t key, result_t result) {
  }
  
  default event void BDictionary.nextKey[uint8_t id](uint32_t nextKey, result_t result) {
  }
  
  default event void BDictionary.fileIsDictionary[uint8_t id](bool isDictionary, result_t result) {
  } 
}


--- NEW FILE: UtilC.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

 
/**
 * Blackbook Util Configuration
 * Provides basic tools for Blackbook operation
 * @author David Moss (dmm at rincon.com)
 */
 
includes Blackbook;

configuration UtilC {
  provides {
    interface Util;
  }
}

implementation {
  components UtilM, GenericCrcC;
  
  Util = UtilM;
  
  UtilM.GenericCrc -> GenericCrcC;
}




--- NEW FILE: BCleanC.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Blackbook BClean configuration
 * This is the garbage collector
 * @author David Moss - dmm at rincon.com
 */
 
configuration BCleanC {
  provides {
    interface BClean;
  }
}

implementation {
  components BCleanM, FlashBridgeC, SectorMapC;
 
  BClean = BCleanM;
 
  BCleanM.FlashBridge -> FlashBridgeC.FlashBridge[unique("FlashBridge")];
  BCleanM.SectorMap -> SectorMapC;

}



--- NEW FILE: Blackbook.h ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Blackbook Definitions v.3
 * @author David Moss (dmm at rincon.com)
 */

#include "BlackbookConst.h"

/** 
 * This is a complete name of a file that we can pass around Blackbook
 * and not worry about whether or not enough bytes were allocated for
 * the filename.
 */
typedef struct filename {

  /** The name of a file */
  char getName[FILENAME_LENGTH];

} filename;


/** 
 * This is the nodemeta information kept at the start of each 
 * node on flash
 */
typedef struct nodemeta {

  /** Magic number to detect valid metadata. This is after dataCrc for finalizing */
  uint16_t magicNumber;
  
  /** Length of the space reserved for this node on flash */
  uint32_t reserveLength;
  
  /** The CRC of the filename this node is associated with */
  uint16_t filenameCrc;
  
  /** The element of the file this node represents, 0 for the first node */
  uint8_t fileElement;

} nodemeta;


/** 
 * This is the filemeta information located directly after nodemeta
 * information for the first node of a file on flash
 */
typedef struct filemeta {

  /** Name of the file */
  struct filename name;
  
} filemeta;


/** 
 * This is the node information kept in memory for each node
 */
typedef struct node {
  /** The address of this node on flash */
  uint32_t flashAddress;
  
  /** The next node in the file after this one */
  struct node *nextNode;
  
  /** The total length of valid data written to this node */
  uint16_t dataLength;

  /** The total length of space reserved for this node */
  uint32_t reserveLength;
  
  /** The current CRC of the node */
  uint16_t dataCrc;

  /** The CRC of the filename from the file this node is associated with */
  uint16_t filenameCrc;
  
  /** The state of the node */
  uint8_t state;

  /** The index this node belongs to in its entire file */
  uint8_t fileElement;

} node;


/** 
 * This is the information kept for each file in RAM memory 
 */
typedef struct file {

  /** The first node of this file */
  node *firstNode;
  
  /** The calculated crc of the file, so we don't have to calculate it every time */
  uint16_t filenameCrc;
  
  /** The state of this file */
  uint8_t state;
  
} file;


/**
 * This is the sector information kept
 * in RAM for every sector on flash.
 */
typedef struct flashsector {
  
  /** Next page number available for writing */
  uint16_t writePage;
  
  /** Total amount of valid nodes on this sector */
  uint8_t totalNodes;
  
  /** This sector's volume ID, and start address from calculation */
  uint8_t index;
  
  /** FALSE if this sector has no open write files */
  bool inUse;
  
} flashsector;



/**
 * This is the checkpoint struct that is inserted
 * into a key-value pair in the Checkpoint file
 */
typedef struct checkpoint {

  /** Node's filename CRC for verification */
  uint16_t filenameCrc;
  
  /** The CRC of the data contained up to the dataLength of the node */
  uint16_t dataCrc;

  /** Length of the node's data */ 
  uint16_t dataLength;
  
  /** TRUE if this node is still available for writing */
  bool writable;
  
} checkpoint;


/** Possible node States */
enum {
  /** The node can be used by anything needed a node */
  NODE_EMPTY,
  
  /** This is a special constructing node that is to be deleted if the mote is rebooted */
  NODE_CONSTRUCTING,
  
  /** The node is valid and can be written to */
  NODE_VALID,

  /** This node is valid and cannot be written to */
  NODE_LOCKED,
  
  /** This node exists virtually, but no info has been written to flash */
  NODE_TEMPORARY,
  
  /** This node was found on flash, but is not valid */
  NODE_DELETED,
  
  /** This node is valid and booting */
  NODE_BOOTING,
};

/** Possible node States */
enum {
  /** This file index is empty and can be used by anybody */
  FILE_EMPTY,
  
  /** This file exists virtually, but no info has been written to flash */
  FILE_TEMPORARY,
  
  /** This file is valid but not being used */
  FILE_IDLE,
  
  /** The nodes in this file is open for reading */
  FILE_READING,
  
  /** The nodes in this file are open for writing */
  FILE_WRITING,

};


/** Magic Words */
enum {
  /** No node exists at this point in the flash */
  META_EMPTY = 0xFFFF,             // binary 1111

  /** This node is being constructed. If this is found on boot, delete the node */
  META_CONSTRUCTING = 0x7777,      // binary 0111
  
  /** This node is finalized on flash and all information is local */
  META_VALID = 0x3333,             // binary 0011
  
  /** This node is deleted, mark up the SectorMap and move on */
  META_INVALID = 0x1111,           // binary 0001
  
  /** This is the type of data you'll find when a dataCrc is unfinalized */
  UNFINALIZED_CRC = 0xFFFF,
  
  /** This is the type of data you'll find when a dataLength is unfinalized */
  UNFINALIZED_DATA = 0xFFFF,
};

/** Global state machine for blackbook */
enum {
  S_IDLE = 0,
  
  /** The file system is booting */
  S_BOOT_BUSY,
  
  /** The file system is recovering nodes */
  S_BOOT_RECOVERING_BUSY,
  
  /** The dictionary is in use */
  S_DICTIONARY_BUSY,
  
  /** Write: The general file writer is in use */
  S_WRITE_BUSY,
  
  /** Write: The file writer is saving */
  S_WRITE_SAVE_BUSY,
  
  /** Write: The file writer is closing */
  S_WRITE_CLOSE_BUSY,
  
  /** The file reader is in use */
  S_READ_BUSY,
  
  /** The file dir is in use */
  S_DIR_BUSY,
  
  /** The file delete is in use */
  S_DELETE_BUSY,
  
  
  BLACKBOOK_STATE = unique("State"),
};


enum {
  INTERNAL_DICTIONARY = unique("BDictionary"),
};





--- NEW FILE: BDictionaryC.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Blackbook BDictionary configuration
 * Allows an application to store and retrieve key-value pairs on flash.
 * @author David Moss - dmm at rincon.com
 */

configuration BDictionaryC {
  provides {
    interface StdControl;
    interface BDictionary[uint8_t id];
    interface InternalDictionary[uint8_t id];
  }
}

implementation {
  components BDictionaryM, GenericCrcC, WriteAllocC, NodeMapC, NodeShopC, StateC, UtilC, FileioC;
  
  StdControl = BDictionaryM;
  
  BDictionary = BDictionaryM;
  InternalDictionary = BDictionaryM;
  
  BDictionaryM.Fileio -> FileioC;
  BDictionaryM.NodeMap -> NodeMapC;
  BDictionaryM.NodeShop -> NodeShopC;
  BDictionaryM.GenericCrc -> GenericCrcC;
  BDictionaryM.WriteAlloc -> WriteAllocC;
  BDictionaryM.BlackbookState -> StateC.State[BLACKBOOK_STATE];
  BDictionaryM.CommandState -> StateC.State[unique("State")];
  BDictionaryM.DictionaryState -> StateC.State[unique("State")];
  BDictionaryM.SearchState -> StateC.State[unique("State")];
  BDictionaryM.Util -> UtilC;
}



--- NEW FILE: CheckpointC.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Blackbook Checkpoint Configuration
 * Saves the state of open binary nodes to a Checkpoint
 * dicationary file on flash for catastrophic failure recovery.
 *
 * @author David Moss - dmm at rincon.com
 */
 
includes Blackbook;

configuration CheckpointC {
  provides {
    interface StdControl;
    interface Checkpoint;
  }
}

implementation {
  components CheckpointM, BDictionaryM, NodeShopC, NodeMapC, StateC;
  components UtilC;
  
  StdControl = CheckpointM;
  
  Checkpoint = CheckpointM;
  
  CheckpointM.BDictionary -> BDictionaryM.BDictionary[INTERNAL_DICTIONARY];
  CheckpointM.InternalDictionary -> BDictionaryM.InternalDictionary[INTERNAL_DICTIONARY];
  CheckpointM.NodeMap -> NodeMapC;
  CheckpointM.NodeShop -> NodeShopC;
  CheckpointM.State -> StateC.State[unique("State")];
  CheckpointM.Util -> UtilC;
}



--- NEW FILE: BCleanM.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Blackbook BClean Module
 * This is the garbage collector.
 * @author David Moss - dmm at rincon.com
 */
 
includes FlashSettings;

module BCleanM {
  provides {
    interface BClean;
  }
  
  uses {
    interface FlashBridge;
    interface SectorMap;
  }
}

implementation {

  /** The current sector index we're looking at */
  uint8_t currentSectorIndex;
  
  /** TRUE if we erased one sector on the last run */
  bool erased = FALSE;
  
  /***************** Prototypes *****************/
  /** Loop to search and destroy erasable sectors */
  task void garbageLoop();
  
  task void eraseComplete();
  
  /***************** BClean Commands ****************/
  /**
   * If the free space on the file system is over a threshold
   * then we should go ahead and defrag and garbage collect.
   * This should be run when the mote has some time and energy
   * to spare in its application.
   * @return SUCCESS if the file system will defrag and gc itself
   */
  command result_t BClean.performCheckup() {
    if(call SectorMap.getFreeSpace() < (FLASH_SECTOR_LENGTH * FLASH_TOTAL_SECTORS) * 0.75) {
      return call BClean.gc();
    }
    return FAIL;
  }
  
  /**  
   * Run the garbage collector, erasing any sectors that 
   * contain any data with 0 valid nodes.
   * @return SUCCESS if the garbage collector is run
   */
  command result_t BClean.gc() {
    currentSectorIndex = 0;
    erased = FALSE;
    post garbageLoop();
    return SUCCESS;
  }
  
  /***************** FlashBridge Events ****************/
  /**
   * Read is complete
   * @param addr - the address to read from
   * @param *buf - the buffer to read into
   * @param len - the amount to read
   * @return SUCCESS if the bytes will be read
   */
  event void FlashBridge.readDone(uint32_t addr, void *buf, uint32_t len, result_t result) {
  }
  
  /**
   * Write is complete
   * @param addr - the address to write to
   * @param *buf - the buffer to write from
   * @param len - the amount to write
   * @return SUCCESS if the bytes will be written
   */
  event void FlashBridge.writeDone(uint32_t addr, void *buf, uint32_t len, result_t result) {
  }
  
  /**
   * Erase is complete
   * @param sector - the sector id to erase
   * @return SUCCESS if the sector will be erased
   */
  event void FlashBridge.eraseDone(uint16_t sector, result_t result) {
    call SectorMap.eraseComplete(currentSectorIndex);
    currentSectorIndex++;
    erased = TRUE;
    post garbageLoop();
  }
  
  /**
   * Flush is complete
   * @param result - SUCCESS if the flash was flushed
   */
  event void FlashBridge.flushDone(result_t result) {
    post eraseComplete();
  }
  
  /**
   * CRC-16 is computed
   * @param crc - the computed CRC.
   * @param addr - the address to start the CRC computation
   * @param len - the amount of data to obtain the CRC for
   * @return SUCCESS if the CRC will be computed.
   */
  event void FlashBridge.crcDone(uint16_t calculatedCrc, uint32_t addr, uint32_t len, result_t result) {
  }

  /**
   * Signaled when the flash is ready to be used
   * @param result - SUCCESS if we can use the flash.
   */
  event void FlashBridge.ready(result_t result) {
  }
  
  /***************** Tasks ****************/
  /** 
   * When entering the garbageLoop for the first time,
   * make sure the currentSectorIndex = 0
   */
  task void garbageLoop() {
    if(currentSectorIndex <= FLASH_LAST_BLACKBOOK_SECTOR) {
      if(call SectorMap.canErase(currentSectorIndex)) {
        signal BClean.erasing();
        call FlashBridge.erase(currentSectorIndex);
        
      } else {
        currentSectorIndex++;
        post garbageLoop();
        return;
      }
      
    } else {
      call FlashBridge.flush();
    }
  }
  
  /**
   * Erase is complete
   */
  task void eraseComplete() {
    signal BClean.gcDone(erased);
  }
}



--- NEW FILE: SectorMapC.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

 
/**
 * Blackbook SectorMap Configuration
 * Keeps track of memory usage and reserves sectors for
 * writing, helps decide where to place new nodes.
 * @author David Moss (dmm at rincon.com)
 */
 
includes Blackbook;

configuration SectorMapC {
  provides {
    interface SectorMap;
    interface StdControl;
  }
}

implementation {
  components SectorMapM, NodeMapC, UtilC;
  
  SectorMap = SectorMapM;
  StdControl = SectorMapM;
  
  SectorMapM.NodeMap -> NodeMapC;
  SectorMapM.Util -> UtilC;
}


--- NEW FILE: NodeShopC.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

 
/**
 * Blackbook NodeShop Configuration
 *
 * NodeShop writes metadata for nodes and files to flash.
 *
 * @author David Moss (dmm at rincon.com)
 */
 
includes Blackbook;

configuration NodeShopC {
  provides {
    interface NodeShop;
  }
}

implementation {
  components NodeShopM, NodeMapC, SectorMapC, StateC, UtilC;
  components FlashBridgeC;
  
  NodeShop = NodeShopM;
 
  NodeShopM.SectorMap -> SectorMapC;
  NodeShopM.NodeMap -> NodeMapC; 
  NodeShopM.Util -> UtilC;
  NodeShopM.State -> StateC.State[unique("State")];
  NodeShopM.FlashBridge -> FlashBridgeC.FlashBridge[unique("FlashBridge")];
}



--- NEW FILE: BFileWriteM.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */


/**
 * Blackbook BFileWrite Configuration
 * Open, Write, Save, Close Blackbook files.
 * Use unique("BFileWrite") when connecting to a parameterized
 * interface.
 * @author David Moss - dmm at rincon.com
 */
 
includes Blackbook;

module BFileWriteM {
  provides {
    interface StdControl;
    interface BFileWrite[uint8_t id];
  }
  
  uses {
    interface State as BlackbookState;
    interface WriteAlloc;
    interface NodeMap;
    interface Fileio; 
    interface Checkpoint;
    interface Util;
  }
}

implementation {

  /** Each client's file writing information */
  file *writers[uniqueCount("BFileWrite")];
  
  /** The current client we're working with */
  uint8_t currentClient;
  
  /** Current node we're closing or checkpointing */
  node *currentNode;
  
  
  /** Command States */
  enum {
    S_IDLE = 0,
    S_COMMAND_OPEN,
    S_COMMAND_CLOSE,
    S_COMMAND_SAVE,
    S_COMMAND_APPEND,
    
  };
  
  
  /***************** Prototypes ****************/
  /** Close all nodes in the current client's open file */
  task void closeFile();
  
  /** Finalize the current client's open node */
  task void finalizeNode();
  
  /** Unfinalize the current client's open node to flash */
  task void unfinalizeNewNode();
  
  /** Checkpoint the current client's open file */
  task void checkpointNode();
  
  /** Append data to the current client's file until all nodes are full */
  task void appendFile();
  
  /** Output the appendAmount of data to the current client's open node */
  task void outputData();
  
  
  /***************** StdControl Commands ****************/
  command result_t StdControl.init() {
    int i;
    for(i = 0; i < uniqueCount("BFileWrite"); i++) {
      writers[i] = NULL;
    }
    return SUCCESS;
  }
  
  command result_t StdControl.start() {
    return SUCCESS;
  }
  
  command result_t StdControl.stop() {
    return SUCCESS;
  }
  
  
  /***************** BFileWrite Commands ****************/
  /**
   * Open a file for writing. 
   * @param fileName - name of the file to write to
   * @param minimumSize The minimum requested amount of total data space
   *            to reserve in the file.  The physical amount of flash 
   *            consumed by the file may be more.
   */
  command result_t BFileWrite.open[uint8_t id](char *fileName, uint32_t minimumSize) {
    if(!call BlackbookState.requestState(S_WRITE_BUSY)) {
      return FAIL;
    }
    
    currentClient = id;
    
    if(writers[currentClient] == NULL) {
      if(call WriteAlloc.openForWriting(fileName, minimumSize, FALSE, FALSE)) {
        return SUCCESS;
      }
    }
    
    call BlackbookState.toIdle();
    return FAIL;
  }

  /**
   * Close any currently opened write file.
   */
  command result_t BFileWrite.close[uint8_t id]() {
    if(!call BlackbookState.requestState(S_WRITE_CLOSE_BUSY)) {
      return FAIL;
    }
    
    currentClient = id;

    if(writers[currentClient] == NULL) {
      call BlackbookState.toIdle();
      signal BFileWrite.closed[currentClient](SUCCESS);
      return SUCCESS;
    }
    
    currentNode = writers[currentClient]->firstNode;
    post checkpointNode();
    return SUCCESS;
  }

  /**
   * Save the current state of the file, guaranteeing the next time
   * we experience a catastrophic failure, we will at least be able to
   * recover data from the open write file up to the point
   * where save was called.
   *
   * If data is simply being logged for a long time, use save() 
   * periodically but probably more infrequently.
   *
   * @return SUCCESS if the currently open file will be saved.
   */
  command result_t BFileWrite.save[uint8_t id]() {
    if(!call BlackbookState.requestState(S_WRITE_SAVE_BUSY)) {
      return FAIL;
    }
    
    currentClient = id;
    
    if(writers[currentClient] == NULL) {
      call BlackbookState.toIdle();
      return FAIL;
    }
    
    currentNode = writers[currentClient]->firstNode;
    post checkpointNode();
    return SUCCESS;
  }

  /**
   * Append the specified amount of data from a given buffer
   * to the open write file.  
   *
   * @param buf - the buffer of data to append
   * @param amount - the amount of data in the buffer to write.
   * @return SUCCESS if the data will be written, FAIL if there
   *     is no open file to write to.
   */ 
  command result_t BFileWrite.append[uint8_t id](void *data, uint16_t amount) {
    if(!call BlackbookState.requestState(S_WRITE_BUSY)) {
      return FAIL;
    }
    
    currentClient = id;
    
    if(writers[currentClient] != NULL) {
      if(call Fileio.writeData(writers[currentClient], call NodeMap.getDataLength(writers[currentClient]), data, amount)) {
        return SUCCESS;
      }
    }
    
    call BlackbookState.toIdle();
    return FAIL;
  }

  /**
   * Obtain the remaining bytes available to be written in this file
   * @return the remaining length of the file.
   */
  command uint32_t BFileWrite.getRemaining[uint8_t id]() {
    node *focusedNode;
    uint32_t remaining = 0;
    
    if(writers[id] != NULL) {
      for(focusedNode = writers[id]->firstNode; focusedNode != NULL ; focusedNode = focusedNode->nextNode) {
        if(focusedNode->state != NODE_LOCKED) {
          remaining += focusedNode->reserveLength - focusedNode->dataLength;
        }
      }
    }
    
    return remaining;
  }


  /***************** WriteAlloc Events ****************/
  /**
   * The write open process completed
   * @param openFile - the file that was opened for writing 
   * @param writeNode - the node to write to
   * @param result - SUCCESS if the file was correctly opened
   */
  event void WriteAlloc.openedForWriting(file *openFile, node *writeNode, uint32_t totalSize, result_t result) {
    if(call BlackbookState.getState() == S_WRITE_BUSY) {
      if(result) {
        writers[currentClient] = openFile;
      }
      

      call BlackbookState.toIdle();
      signal BFileWrite.opened[currentClient](totalSize, SUCCESS);
    }
  }
  
  
  /***************** Fileio Events ****************/
  /**
   * Data was appended to the node in the flash.
   * @param writeBuffer - pointer to the buffer containing the data written
   * @param amountWritten - the amount of data appended to the node.
   * @param result - SUCCESS if the data was successfully written
   */
  event void Fileio.writeDone(void *writeBuffer, uint32_t amountWritten, result_t result) {
    if(call BlackbookState.getState() == S_WRITE_BUSY) {
      call BlackbookState.toIdle();
      signal BFileWrite.appended[currentClient](writeBuffer, amountWritten, result);
    }
  }
  
  /**
   * Data was read from the file
   * @param *readBuffer - pointer to the location where the data was stored
   * @param amountRead - the amount of data actually read
   * @param result - SUCCESS if the data was successfully read
   */
  event void Fileio.readDone(void *readBuffer, uint32_t amountRead, result_t result) {
  }
  
  /**
   * Data was flushed to flash
   * @param result - SUCCESS if the data was flushed
   */
  event void Fileio.flushDone(result_t result) {
  }
  
  /***************** Checkpoint Events ****************/
  /**
   * The given node was updated in the Checkpoint
   * @param focusedNode - the node that was updated
   * @param result - SUCCESS if everything's ok
   */
  event void Checkpoint.updated(node *focusedNode, result_t result) {
    node *previousNode;
    if(call BlackbookState.getState() == S_WRITE_SAVE_BUSY) {
      currentNode = currentNode->nextNode;
      if(currentNode != NULL) {
        if(currentNode->state != NODE_TEMPORARY) {
          post checkpointNode();
          return;
        }
      }
      
      call BlackbookState.toIdle();
      signal BFileWrite.saved[currentClient](result);
     
    } else if(call BlackbookState.getState() == S_WRITE_CLOSE_BUSY) {
      currentNode = currentNode->nextNode;
      if(currentNode != NULL) {
        if(currentNode->state != NODE_TEMPORARY) {
          post checkpointNode();
          return;
        }
      }
      
      currentNode = writers[currentClient]->firstNode;
      for(previousNode = currentNode; currentNode != NULL; currentNode = currentNode->nextNode) {
        if(currentNode->state == NODE_TEMPORARY) {
          previousNode->nextNode = NULL;
          currentNode->state = NODE_EMPTY;
        
        } else if(currentNode->state == NODE_VALID) {
          // Prevent this node from ever being written to again
          currentNode->state = NODE_LOCKED;
        }
      }
      
      writers[currentClient]->state = FILE_IDLE;
      writers[currentClient] = NULL;
      call BlackbookState.toIdle();
      signal BFileWrite.closed[currentClient](SUCCESS);
    }
  }
  
  /**
   * The checkpoint file was opened.
   * @param result - SUCCESS if it was opened successfully
   */
  event void Checkpoint.checkpointOpened(result_t result) {
  }
  
  /** 
   * A node was recovered.
   * @param result - SUCCESS if it was handled correctly.
   */
  event void Checkpoint.recovered(node *focusedNode, result_t result) {
  }
  
  /***************** Tasks ****************/
  /**
   * Checkpoint the open node from the current client
   */
  task void checkpointNode() {
    if(!call Checkpoint.update(currentNode)) {
      post checkpointNode();
    }
  }
  
  
  /***************** Functions ****************/
  
  /***************** Defaults ****************/  
  default event void BFileWrite.opened[uint8_t id](uint32_t len, result_t result) {
  }

  default event void BFileWrite.closed[uint8_t id](result_t result) {
  }

  default event void BFileWrite.saved[uint8_t id](result_t result) {
  }

  default event void BFileWrite.appended[uint8_t id](void *data, uint16_t amountWritten, result_t result) {
  }
}


--- NEW FILE: SectorMapM.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Blackbook SectorMap Module
 * Keeps track of memory usage and reserves sectors for
 * writing, helps decide where to place new nodes.
 * @author David Moss (dmm at rincon.com)
 */
 
includes Blackbook;
includes FlashSettings;

module SectorMapM {
  provides {
    interface SectorMap;
    interface StdControl;
  }
  
  uses {
    interface Util;
    interface NodeMap;
  }
}

implementation {

  /** Array of flashSectors on the flash */
  flashsector flashSectors[FLASH_TOTAL_SECTORS];
  
  /** Contains the last sector index we allocated new nodes to, to spread them around */
  uint8_t currentSectorIndex;
  
  /***************** StdControl Commands ****************/
  command result_t StdControl.init() {
    int i;
    for(i = 0; i < call SectorMap.getTotalSectors(); i++) {
      flashSectors[i].index = i;
      flashSectors[i].writePage = 0;
      flashSectors[i].inUse = FALSE;
      flashSectors[i].totalNodes = 0;
    }
    
    currentSectorIndex = FLASH_FIRST_BLACKBOOK_SECTOR;
    return SUCCESS;
  }
  
  command result_t StdControl.start() {
    return SUCCESS;
  }
  
  command result_t StdControl.stop() {
    return SUCCESS;
  }
  
  
  /***************** SectorMap Commands ****************/
  /**
   * @return the total sectors on flash
   */
  command uint8_t SectorMap.getTotalSectors() {
    return FLASH_LAST_BLACKBOOK_SECTOR - FLASH_FIRST_BLACKBOOK_SECTOR + 1;
  }
  
  /**
   * Obtain the largest sector that is not in use
   * on the flash.  We use a global to store the
   * current sector index we're evaluating
   * so that each call to this function will
   * spread nodes more evenly around the flash.
   * @return the largest available sector to write to 
   */
  command flashsector *SectorMap.nextLargestIdleSector() {
    int leastPages; 
    int sectorIndex;
    flashsector *largestSector = NULL;
   
    leastPages = FLASH_PAGES_PER_SECTOR;
    
    for(sectorIndex = FLASH_FIRST_BLACKBOOK_SECTOR; sectorIndex <= FLASH_LAST_BLACKBOOK_SECTOR; sectorIndex++) {
      currentSectorIndex++;
      if(currentSectorIndex > FLASH_LAST_BLACKBOOK_SECTOR) {
        currentSectorIndex = FLASH_FIRST_BLACKBOOK_SECTOR;
      }
      
      if(!flashSectors[currentSectorIndex].inUse && flashSectors[currentSectorIndex].writePage != FLASH_PAGES_PER_SECTOR && flashSectors[currentSectorIndex].writePage < leastPages) {
        leastPages = flashSectors[currentSectorIndex].writePage;
        largestSector = &flashSectors[currentSectorIndex];
      }
    }
    
    currentSectorIndex = largestSector->index;
    return largestSector;
  }
  
  /**
   * @return the total nodes in the given sector
   */
  command uint8_t SectorMap.getNodesInSector(flashsector *focusedSector) {
    return focusedSector->totalNodes;
  }
  
  /**
   * Get the flashsector at the specified address in flash.
   * @return the flashsector that exists at the given address
   *     NULL if the flashAddress is out of bounds.
   */
  command flashsector *SectorMap.getSectorAtAddress(uint32_t flashAddress) {
    return &flashSectors[flashAddress / FLASH_SECTOR_LENGTH];
  }
  
  /**
   * Get the sector at a specified volume index
   */
  command flashsector *SectorMap.getSectorAtVolume(uint8_t volume) {
    return &flashSectors[volume];
  }
  
  /**
   * @return TRUE if the sector can be erased
   */
  command bool SectorMap.canErase(uint8_t volume) {
    return flashSectors[volume].totalNodes == 0 && call SectorMap.getSectorWriteAddress(&flashSectors[volume]) != call SectorMap.getSectorBaseAddress(&flashSectors[volume]);
  }
  
  
  /**
   * Document the existence of a node in a sector on flash.
   * @param focusedNode - the node to document
   */
  command void SectorMap.documentNode(node *focusedNode) {
    flashsector *mySector;
    uint32_t finalNodeAddress;

    mySector = call SectorMap.getSectorAtAddress(focusedNode->flashAddress);

    if(call SectorMap.getSectorWriteAddress(mySector) <= focusedNode->flashAddress) {      
      // Note the address check above - if this node was already registered,
      // then totalUnfinalizedNodes can't be incremented twice.
      // Unfinalized 
      if(focusedNode->state != NODE_DELETED) {
        mySector->totalNodes++;
      }
    }
    
    if((call NodeMap.getFileFromNode(focusedNode))->firstNode == focusedNode) {
      finalNodeAddress = focusedNode->flashAddress + call Util.getNextPageAddress(focusedNode->reserveLength + sizeof(nodemeta) + sizeof(filemeta) - 1);
    } else {
      finalNodeAddress = focusedNode->flashAddress + call Util.getNextPageAddress(focusedNode->reserveLength + sizeof(nodemeta) - 1);
    }
    
    if(call SectorMap.getSectorWriteAddress(mySector) < finalNodeAddress) {
      mySector->writePage = call Util.convertBytesToPages(finalNodeAddress - call SectorMap.getSectorBaseAddress(mySector) - 1);
    }
  }
  
  
  /**
   * Remove a valid node from its sector. 
   * This helps the garbage collector know which sectors to erase.
   */
  command void SectorMap.removeNode(node *focusedNode) { 
    if(call SectorMap.getSectorWriteAddress(call SectorMap.getSectorAtAddress(focusedNode->flashAddress)) > focusedNode->flashAddress) {      
      (call SectorMap.getSectorAtAddress(focusedNode->flashAddress))->totalNodes--;
    }
  }
  
  /**
   * @return TRUE if the given node is within the bounds of the given sector
   */
  command bool SectorMap.isInSector(flashsector *focusedSector, node *focusedNode) {
    return (call SectorMap.getSectorBaseAddress(focusedSector) <= focusedNode->flashAddress)
        && focusedNode->flashAddress < (call SectorMap.getSectorBaseAddress(focusedSector) + FLASH_SECTOR_LENGTH);
  }
  
  /**
   * Retreive the earliest available write address in a given sector.
   * @return the write address of the sector relative to 0x0
   */
  command uint32_t SectorMap.getSectorWriteAddress(flashsector *focusedSector) {
    return call Util.convertPagesToBytes(focusedSector->writePage) + call SectorMap.getSectorBaseAddress(focusedSector);
  }
  
  /**
   * Retrieve the base address of the flashsector relative to 0x0.
   * @return the relative address of the flashsector from 0x0
   */
  command uint32_t SectorMap.getSectorBaseAddress(flashsector *focusedSector) {
    return focusedSector->index * FLASH_SECTOR_LENGTH;
  }
  
  /**
   * Obtain the remaining free bytes in a specified
   * flashsector
   * @param focusedSector - the flashsector to find the free bytes in
   * @return the number of free page bytes in the flashsector
   */
  command uint32_t SectorMap.bytesRemaining(flashsector *focusedSector) {
    if(focusedSector->writePage < FLASH_PAGES_PER_SECTOR) {
      return FLASH_SECTOR_LENGTH - call Util.convertPagesToBytes(focusedSector->writePage);
      
    } else {
      return 0;
    }
  }

  /**
   * Obtain the total amount of free space on the flash.
   * @return the total amount of free space on the flash
   */
  command uint32_t SectorMap.getFreeSpace() {
    uint8_t sectorIndex;
    uint32_t totalSpace;
    
    sectorIndex = 0;
    totalSpace = 0;

    // This performs a size estimate of the biggest single file we can create on flash.
    for(sectorIndex = 0; sectorIndex < FLASH_TOTAL_SECTORS; sectorIndex++) {
      if(!flashSectors[sectorIndex].inUse && flashSectors[sectorIndex].writePage < FLASH_PAGES_PER_SECTOR) {
        totalSpace += call SectorMap.bytesRemaining(&flashSectors[sectorIndex]);
        totalSpace -= sizeof(nodemeta);
      }
    }
    
    if(totalSpace > 0) {
      totalSpace -= sizeof(filemeta);
    }
    
    return totalSpace;
  }

  /**
   * The sector was erased by the garbage collector
   * @param sectorIndex - the sector erased
   */
  command void SectorMap.eraseComplete(uint8_t sectorIndex) {
    flashSectors[sectorIndex].writePage = 0;
    flashSectors[sectorIndex].totalNodes = 0;
    flashSectors[sectorIndex].inUse = FALSE;
  } 
  
  /** 
   * Reserve a sector for writing
   * @param *focusedSector pointer to the sector we want to reserve
   */
  command void SectorMap.reserveSector(flashsector *focusedSector) {
    focusedSector->inUse = TRUE;
  }
  
  /**
   * Free a sector that was reserved for writing
   * @param *focusedSector pointer to the sector we want to free
   */
  command void SectorMap.freeSector(flashsector *focusedSector) {
    focusedSector->inUse = FALSE;
  }
}


--- NEW FILE: WriteAllocC.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Blackbook File Write Allocator
 * @author David Moss - dmm at rincon.com
 */
 
configuration WriteAllocC {
  provides {
    interface WriteAlloc;
  }
}

implementation {
  components WriteAllocM, SectorMapC, NodeMapC, NodeShopC, StateC, UtilC, BCleanC;

  WriteAlloc = WriteAllocM;
  
  WriteAllocM.SectorMap -> SectorMapC;
  WriteAllocM.NodeMap -> NodeMapC;
  WriteAllocM.NodeBooter -> NodeMapC;
  WriteAllocM.NodeShop -> NodeShopC;
  WriteAllocM.State -> StateC.State[unique("State")];
  WriteAllocM.BClean -> BCleanC;
  WriteAllocM.Util -> UtilC;
}




--- NEW FILE: BFileDirM.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * Blackbook File Dir Configuration
 * Allows the application to find out information about the
 * file system and flash usage.
 * @author David Moss - dmm at rincon.com
 */

includes Blackbook;

module BFileDirM {
  provides { 
    interface BFileDir[uint8_t id];
  }
  
  uses {
    interface State as BlackbookState;
    interface NodeMap;
    interface SectorMap;
    interface NodeShop;
    interface BDictionary;
    interface InternalDictionary;
    interface Util;
  }
}

implementation {

  /** The current node to verify the CRC for */
  node *crcNode;
  
  /** The current file to verify the CRC for */
  file *crcFile;
  
  /** The current client we're working with */
  uint8_t currentClient;
  
  /** Storage for a filename */  
  filename filenameBuffer;

  /***************** Prototypes ****************/
  /** Get the CRC of the current crcNode */
  task void getCrc();
  
  
  /***************** BFileDir Commands ****************/
  /**
   * @return the total number of files in the file system
   */
  command uint8_t BFileDir.getTotalFiles[uint8_t id]() {
    return call NodeMap.getTotalFiles();
  }
  
  /**
   * @return the total number of nodes in the file system
   */
  command uint16_t BFileDir.getTotalNodes[uint8_t id]() {
    return call NodeMap.getTotalNodes();
  }

  /**
   * @return the approximate free space on the flash 
   */
  command uint32_t BFileDir.getFreeSpace[uint8_t id]() {
    return call SectorMap.getFreeSpace();
  }
  
  /**
   * Returns TRUE if the file exists, FALSE if it doesn't
   */
  command result_t BFileDir.checkExists[uint8_t id](char *fileName) {
    file *currentFile;
    
    call Util.filenameCpy(&filenameBuffer, fileName);
    currentFile = call NodeMap.getFile(&filenameBuffer);
    
    signal BFileDir.existsCheckDone[id]((char *) &filenameBuffer, currentFile != NULL, SUCCESS);
    return SUCCESS;
  }

  /**
   * An optional way to read the first filename of
   * the system. This is exactly the same as calling
   * BFileDir.readNext(NULL).
   */ 
  command result_t BFileDir.readFirst[uint8_t id]() {
    return call BFileDir.readNext[id](NULL);
  }
 
  /**
   * Read the next file in the file system, based on the
   * current filename.  If you want to find the first
   * file in the file system, pass in NULL.
   *
   * If the next file exists, it will be returned in the
   * nextFile event with result SUCCESS
   *
   * If there is no next file, the nextFile event will
   * signal with the filename passed in and FAIL.
   *
   * If the present filename passed in doesn't exist,
   * then this command returns FAIL and no signal is given.
   *
   * @param presentFilename - the name of the current file,
   *     of which you want to find the next valid file after.
   */
  command result_t BFileDir.readNext[uint8_t id](char *presentFilename) {
    int i;
    uint16_t targetCrc;

    if(!call BlackbookState.requestState(S_DIR_BUSY)) {
      return FAIL;
    }

    currentClient = id;
 
    if(presentFilename != NULL) {
      call Util.filenameCpy(&filenameBuffer, presentFilename);
      targetCrc = call Util.filenameCrc(&filenameBuffer);
      
      for(i = 0; i < call NodeMap.getMaxFiles(); i++) {
        if((call NodeMap.getFileAtIndex(i))->filenameCrc == targetCrc) {
          // The index of the present filename was found
          for(i += 1; i < call NodeMap.getMaxFiles(); i++) {
            if((call NodeMap.getFileAtIndex(i))->state != FILE_EMPTY) {
              // This is the next file after the index of the present file
              call NodeShop.getFilename(call NodeMap.getFileAtIndex(i), &filenameBuffer);
              return SUCCESS;
            }
          }
        
          // There is no next file
          call BlackbookState.toIdle();
          signal BFileDir.nextFile[id](presentFilename, FAIL);
          return SUCCESS;
        }
      }
    
      // The present filename does not exist
      call BlackbookState.toIdle();
      return FAIL;
      
    } else {
      for(i = 0 ; i < call NodeMap.getMaxFiles(); i++) {
        if((call NodeMap.getFileAtIndex(i))->state != FILE_EMPTY) {
          // This is the first file
          call NodeShop.getFilename(call NodeMap.getFileAtIndex(i), &filenameBuffer);
          return SUCCESS;
        }
      }
      
      // There are no files on this file system
      call BlackbookState.toIdle();
      signal BFileDir.nextFile[id](presentFilename, FAIL);
      return SUCCESS;
    }
  }

  /**
   * Get the total reserved bytes of an existing file
   * @param fileName - the name of the file to pull the reservedLength from.
   * @return the reservedLength of the file, 0 if it doesn't exist
   */
  command uint32_t BFileDir.getReservedLength[uint8_t id](char *fileName) {
    filename currentFilename;
    file *currentFile;
    
    call Util.filenameCpy(&currentFilename, fileName);
    if((currentFile = call NodeMap.getFile(&currentFilename)) == NULL) {
      return 0;
    }
    
    return call NodeMap.getReserveLength(currentFile);
  }
  
  /**
   * Get the total amount of data written to the file with
   * the given fileName.
   * @param fileName - name of the file to pull the dataLength from.
   * @return the dataLength of the file, 0 if it doesn't exist
   */
  command uint32_t BFileDir.getDataLength[uint8_t id](char *fileName) {
    filename currentFilename;
    file *currentFile;
    
    call Util.filenameCpy(&currentFilename, fileName);
    if((currentFile = call NodeMap.getFile(&currentFilename)) == NULL) {
      return 0;
    }
    
    return call NodeMap.getDataLength(currentFile);
  }
 
  /**
   * Find if a file is corrupt. This will read each node
   * from the file and verify it against its dataCrc.
   * If the calculated data CRC from a node does
   * not match the node's recorded CRC, the file is corrupt.
   * @return SUCCESS if the corrupt check will proceed.
   */
  command result_t BFileDir.checkCorruption[uint8_t id](char *fileName) {
    filename currentFilename;
    
    if(!call BlackbookState.requestState(S_DIR_BUSY)) {
      return FAIL;
    }
    
    currentClient = id;
    
    call Util.filenameCpy(&currentFilename, fileName);
    if((crcFile = call NodeMap.getFile(&currentFilename)) == NULL) {
      call BlackbookState.toIdle();
      return FAIL;
    }
    
    
    crcNode = crcFile->firstNode;
    call InternalDictionary.isFileDictionary(crcFile);
    return SUCCESS;
  }


  /***************** BDictionary Events ****************/
  
  /**
   * @param isDictionary - TRUE if the file is a dictionary
   * @param result - SUCCESS if the reading is valid
   */
  event void BDictionary.fileIsDictionary(bool isDictionary, result_t result) {
    if(call BlackbookState.getState() == S_DIR_BUSY) {
      if(result && isDictionary) {
        // This is a dictionary file - it is not corrupted
        call BlackbookState.toIdle();
        signal BFileDir.corruptionCheckDone[currentClient]((char *) (&filenameBuffer), FALSE, SUCCESS);
        
      } else {
        // This is not a dictionary file - verify it
        post getCrc();
      }   
    }
  }
  
  /**
   * A Dictionary file was opened successfully.
   * @param totalSize - the total amount of flash space dedicated to storing
   *     key-value pairs in the file
   * @param remainingBytes - the remaining amount of space left to write to
   * @param result - SUCCESS if the file was successfully opened.
   */
  event void BDictionary.opened(uint32_t totalSize, uint32_t remainingBytes, result_t result) {
  }
  
  /** 
   * The opened Dictionary file is now closed
   * @param result - SUCCSESS if there are no open files
   */
  event void BDictionary.closed(result_t result) {
  }
  
  /**
   * A key-value pair was inserted into the currently opened Dictionary file.
   * @param key - the key used to insert the value
   * @param value - pointer to the buffer containing the value.
   * @param valueSize - the amount of bytes copied from the buffer into flash
   * @param result - SUCCESS if the key was written successfully.
   */
  event void BDictionary.inserted(uint32_t key, void *value, uint16_t valueSize, result_t result) {
  }
  
  /**
   * A value was retrieved from the given key.
   * @param key - the key used to find the value
   * @param valueHolder - pointer to the buffer where the value was stored
   * @param valueSize - the actual size of the value.
   * @param result - SUCCESS if the value was pulled out and is uncorrupted
   */
  event void BDictionary.retrieved(uint32_t key, void *valueHolder, uint16_t valueSize, result_t result) {
  }
  
  /**
   * A key-value pair was removed
   * @param key - the key that should no longer exist
   * @param result - SUCCESS if the key was really removed
   */
  event void BDictionary.removed(uint32_t key, result_t result) {
  }
  
  /**
   * The next key in the open Dictionary file
   * @param nextKey - the next key
   * @param result - SUCCESS if this is the really the next key,
   *     FAIL if the presentKey was invalid or there is no next key.
   */
  event void BDictionary.nextKey(uint32_t nextKey, result_t result) {
  }

  
  /***************** NodeShop Events ****************/ 
  /**
   * A crc was calculated from node data on flash
   * @param dataCrc - the crc of the data read from the node on flash.
   * @param result - SUCCESS if the crc is valid
   */
  event void NodeShop.crcCalculated(uint16_t dataCrc, result_t result) {
    if(dataCrc == crcNode->dataCrc) {
      if((crcNode = crcNode->nextNode) != NULL) {
        // More nodes in this file to verify
        post getCrc();
        
      } else {
        // No more nodes to verify, all are ok.
        call BlackbookState.toIdle();
        signal BFileDir.corruptionCheckDone[currentClient]((char *) (&filenameBuffer), FALSE, SUCCESS);
      }
         
    } else {
      // This node is corrupted, so the whole file is corrupt.
      call BlackbookState.toIdle();
      signal BFileDir.corruptionCheckDone[currentClient]((char *) (&filenameBuffer), TRUE, SUCCESS);
    }
  }
  
  /**
   * The filename was retrieved from flash
   * @param focusedFile - the file that we obtained the filename for
   * @param *name - pointer to where the filename was stored
   * @param result - SUCCESS if the filename was retrieved
   */
  event void NodeShop.filenameRetrieved(file *focusedFile, filename *name, result_t result) {
    call BlackbookState.toIdle();
    signal BFileDir.nextFile[currentClient]((char *) name->getName, result);
  }
  
  /** 
   * The node's metadata was written to flash
   * @param focusedNode - the node that metadata was written for
   * @param result - SUCCESS if it was written
   */
  event void NodeShop.metaWritten(node *focusedNode, result_t result) {
  }
  
  /**
   * A node was deleted from flash by marking its magic number
   * invalid in the metadata.
   * @param focusedNode - the node that was deleted.
   * @param result - SUCCESS if the node was deleted successfully.
   */
  event void NodeShop.metaDeleted(node *focusedNode, result_t result) {
  }
  
  /***************** Tasks ****************/
  /**
   * Get the CRC of the data in the current crcNode
   */
  task void getCrc() {
    if(!call NodeShop.getCrc(crcNode, crcFile)) {
      post getCrc();
    }
  }
  
  
  /***************** Defaults ****************/

  default event void BFileDir.corruptionCheckDone[uint8_t id](char *fileName, bool isCorrupt, result_t result) {
  }

  default event void BFileDir.existsCheckDone[uint8_t id](char *fileName, bool doesExist, result_t result) {
  }
    
  default event void BFileDir.nextFile[uint8_t id](char *fileName, result_t result) {
  }
  
}





--- NEW FILE: GenericCrcC.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */


/**
 * GenericCrc configuration
 * @author David Moss (dmm at rincon.com)
 */
 
configuration GenericCrcC {
  provides {
    interface GenericCrc;
  }
}

implementation {
  components GenericCrcM;
  
  GenericCrc = GenericCrcM;
}


--- NEW FILE: NodeMapM.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject