Subdirectory provided by Embedded Artists

Dependencies:   DM_FATFileSystem DM_HttpServer DM_USBHost EthernetInterface USBDevice mbed-rpc mbed-rtos mbed-src

Dependents:   lpc4088_displaymodule_hello_world_Sept_2018

Fork of DMSupport by Embedded Artists

Files at this revision

API Documentation at this revision

Comitter:
embeddedartists
Date:
Mon Mar 09 11:15:56 2015 +0100
Parent:
33:8a0a99d54bf8
Child:
35:d45a38606a7f
Commit message:
- Added size guards in InternalEEPROM
- Added documentation in missing classes
- Added option to redirect RtosLog to USBSerial (a USB Device Serial port)
- Moved the mbed_mac_address function from the SDK to the BIOS

Changed in this revision

Bios/BiosLoader.cpp Show annotated file Show diff for this revision Revisions of this file
DMBoard.cpp Show annotated file Show diff for this revision Revisions of this file
FileSystems/RAMFileSystem.cpp Show annotated file Show diff for this revision Revisions of this file
Memory/InternalEEPROM.cpp Show annotated file Show diff for this revision Revisions of this file
Memory/InternalEEPROM.h Show annotated file Show diff for this revision Revisions of this file
Registry.h Show annotated file Show diff for this revision Revisions of this file
RtosLog.cpp Show annotated file Show diff for this revision Revisions of this file
RtosLog.h Show annotated file Show diff for this revision Revisions of this file
dm_board_config.h.txt Show annotated file Show diff for this revision Revisions of this file
--- a/Bios/BiosLoader.cpp	Thu Feb 19 14:41:14 2015 +0100
+++ b/Bios/BiosLoader.cpp	Mon Mar 09 11:15:56 2015 +0100
@@ -57,7 +57,7 @@
 #define SUPPORTED_BIOS_MASK  0xff0000  // only look at the Major component
 #define SUPPORTED_VERSION(__ver) (((__ver)&SUPPORTED_BIOS_MASK) == SUPPORTED_BIOS_VER)
 
-#define MAC_IN_SDK
+//#define MAC_IN_SDK
 
 /******************************************************************************
  * Local variables
--- a/DMBoard.cpp	Thu Feb 19 14:41:14 2015 +0100
+++ b/DMBoard.cpp	Mon Mar 09 11:15:56 2015 +0100
@@ -35,6 +35,10 @@
 #if defined(DM_BOARD_USE_USB_DEVICE) && defined(DM_BOARD_USE_USB_HOST)
   #error The hardware supports either USB Device or USB Host - not both at the same time
 #endif
+  
+#if defined(DM_BOARD_USE_USBSERIAL_IN_RTOSLOG) && !defined(DM_BOARD_USE_USB_DEVICE)
+  #error Cannot use USBSerial in RtosLog without DM_BOARD_USE_USB_DEVICE
+#endif
 
 #if defined(DM_BOARD_USE_TOUCH) && !defined(DM_BOARD_USE_DISPLAY)
   #error Cannot have touch controller without a display!
--- a/FileSystems/RAMFileSystem.cpp	Thu Feb 19 14:41:14 2015 +0100
+++ b/FileSystems/RAMFileSystem.cpp	Mon Mar 09 11:15:56 2015 +0100
@@ -15,9 +15,11 @@
  */
 
 #include "RAMFileSystem.h"
-#include "mbed_debug.h"
+#include "DMBoard.h"
+
 
-#define RAMFS_DBG       0
+#define RAMFS_DBG(...)
+//#define RAMFS_DBG(...) DMBoard::instance().logger()->isr_printf(__VA_ARGS__)
 
 #define SECTOR_SIZE   512
 
@@ -29,13 +31,13 @@
 }
 
 int RAMFileSystem::disk_initialize() {
-    debug_if(RAMFS_DBG, "init RAM fs\n");
+    RAMFS_DBG("init RAM fs\n");
     status = 0; //OK
     return status;
 }
 
 int RAMFileSystem::disk_write(const uint8_t *buffer, uint64_t sector, uint8_t count) {
-    debug_if(RAMFS_DBG, "write to sector(s) %llu..%llu\n", sector, sector+count);
+    RAMFS_DBG("write to sector(s) %llu..%llu\n", sector, sector+count);
     if ((sector+count-1) >= disk_sectors()) {
         return 1;
     }
@@ -45,7 +47,7 @@
 }
 
 int RAMFileSystem::disk_read(uint8_t *buffer, uint64_t sector, uint8_t count) {
-    debug_if(RAMFS_DBG, "read from sector(s) %llu..%llu\n", sector, sector+count);
+    RAMFS_DBG("read from sector(s) %llu..%llu\n", sector, sector+count);
     if ((sector+count-1) >= disk_sectors()) {
         return 1;
     }
@@ -55,14 +57,14 @@
 }
 
 int RAMFileSystem::disk_status() { 
-    debug_if(RAMFS_DBG, "disk status %d\n", status);
+    RAMFS_DBG("disk status %d\n", status);
     return status; 
 }
 int RAMFileSystem::disk_sync() { 
     return 0; 
 }
 uint64_t RAMFileSystem::disk_sectors() { 
-    debug_if(RAMFS_DBG, "returning fs has %u sectors\n", memSize/SECTOR_SIZE);
+    RAMFS_DBG("returning fs has %u sectors\n", memSize/SECTOR_SIZE);
     return memSize/SECTOR_SIZE; 
 }
 
--- a/Memory/InternalEEPROM.cpp	Thu Feb 19 14:41:14 2015 +0100
+++ b/Memory/InternalEEPROM.cpp	Mon Mar 09 11:15:56 2015 +0100
@@ -152,6 +152,14 @@
   uint32_t pageAddr = addr/EEPROM_PAGE_SIZE;
   uint32_t readOffset = (addr & (EEPROM_PAGE_SIZE - 1));
   uint32_t readSize = EEPROM_PAGE_SIZE - readOffset;
+  
+  // Prevent reading past the end of the memory
+  if (addr >= EEPROM_MEMORY_SIZE) {
+    return 0;
+  }
+  if ((size + addr) > EEPROM_MEMORY_SIZE) {
+    size = EEPROM_MEMORY_SIZE - addr;
+  }
 
   powerUp();
 
@@ -181,6 +189,14 @@
   uint32_t writeOffset = (addr & (EEPROM_PAGE_SIZE - 1));
   uint32_t writeSize = EEPROM_PAGE_SIZE - writeOffset;
 
+  // Prevent writing past the end of the memory
+  if (addr >= EEPROM_MEMORY_SIZE) {
+    return 0;
+  }
+  if ((size + addr) > EEPROM_MEMORY_SIZE) {
+    size = EEPROM_MEMORY_SIZE - addr;
+  }
+
   powerUp();
 
   // Read and store data in buffer
@@ -202,17 +218,3 @@
   }
   return numWritten;
 }
-
-//void InternalEEPROM::erasePage(uint32_t pageAddr)
-//{
-//  powerUp();
-//
-//  clearInterrupt(EEPROM_INT_ENDOFRW);
-//  setCmd(EEPROM_CMD_32BITS_WRITE);
-//  setAddr(pageAddr, 0);
-//  for (int i = 0; i < EEPROM_PAGE_SIZE; i+=4) {
-//    LPC_EEPROM->WDATA = 0;
-//    waitForInterrupt(EEPROM_INT_ENDOFRW);
-//  }
-//  eraseOrProgramPage(pageAddr);
-//}
--- a/Memory/InternalEEPROM.h	Thu Feb 19 14:41:14 2015 +0100
+++ b/Memory/InternalEEPROM.h	Mon Mar 09 11:15:56 2015 +0100
@@ -42,9 +42,36 @@
      */
     void init();
     
+    /** Put the internal EEPROM in a low power state
+     */
     void powerDown();
     
+    /** Reads size bytes from offset addr
+     *
+     *  Note that this function will power up the EEPROM so it is
+     *  recommended to call powerDown() when finished reading.
+     *
+     *  @param addr  the offset to read from
+     *  @param data  buffer to store the read data in
+     *  @param size  number of bytes to read
+     *
+     *  @returns
+     *       The number of bytes read
+     */
     int read(uint32_t addr, uint8_t* data, uint32_t size);
+
+    /** Writes size bytes to offset addr
+     *
+     *  Note that this function will power up the EEPROM so it is
+     *  recommended to call powerDown() when finished writing.
+     *
+     *  @param addr  the offset to write to
+     *  @param data  the data to write
+     *  @param size  number of bytes to write
+     *
+     *  @returns
+     *       The number of bytes written
+     */
     int write(uint32_t addr, const uint8_t* data, uint32_t size);
   
     /** Returns the size (in bytes) of the internal EEPROM
@@ -54,20 +81,6 @@
      */
     uint32_t memorySize() { return EEPROM_MEMORY_SIZE; }
   
-    /** Returns the size of a page (in bytes) of the internal EEPROM
-     *
-     *  @returns
-     *       The page size in bytes
-     */
-    //uint32_t pageSize() { return EEPROM_PAGE_SIZE; }
-  
-    /** Returns the number of pages in the internal EEPROM
-     *
-     *  @returns
-     *       The number of pages
-     */
-    //uint32_t numPages() { return EEPROM_NUM_PAGES; }
-  
 private:
 
     bool _initialized;
--- a/Registry.h	Thu Feb 19 14:41:14 2015 +0100
+++ b/Registry.h	Mon Mar 09 11:15:56 2015 +0100
@@ -70,10 +70,56 @@
      */
     RegistryError load();
 
+    /** Sets (or replaces if existing) the value for the key
+     *
+     *  The key/value parameters are copied so it is ok to free them
+     *  after calling this function.
+     *
+     *  @param key  the key to create or update
+     *  @param val  the value to store for the key
+     *
+     *  @returns
+     *       Ok on success
+     *       An error code on failure
+     */
     RegistryError setValue(const char* key, const char* val);
+    
+    /** Gets (if any) the the value for the key
+     *
+     *  If Ok is returned then pVal will point to allocated memory
+     *  that must be deallocated with free() by the caller.
+     *
+     *  @param key   the key to look for
+     *  @param pVal  will hold the value if successful
+     *
+     *  @returns
+     *       Ok on success
+     *       NoSuchKeyError if there is no value for the key
+     *       An error code on failure
+     */
     RegistryError getValue(const char* key, char** pVal);
+    
+    /** Retrieves the key-value pair at the specified index
+     *
+     *  If Ok is returned then pKey and pVal will point to allocated 
+     *  memory that must be deallocated with free() by the caller.
+     *
+     *  @param pos   the index to look for
+     *  @param pKey  will hold the key if successful
+     *  @param pVal  will hold the value if successful
+     *
+     *  @returns
+     *       Ok on success
+     *       An error code on failure
+     */
     RegistryError entryAt(int pos, char** pKey, char** pVal);
+    
+    /** Returns the number of key-value pairs in the registry
+     *
+     *  @returns the number of key-value pairs
+     */
     int numEntries() { return _numEntries; }
+    
     RegistryError registerListener();
 
     /** Stores the registry in the internal EEPROM
--- a/RtosLog.cpp	Thu Feb 19 14:41:14 2015 +0100
+++ b/RtosLog.cpp	Mon Mar 09 11:15:56 2015 +0100
@@ -58,6 +58,12 @@
  * Public Functions
  *****************************************************************************/
 
+#if defined(DM_BOARD_USE_USBSERIAL_IN_RTOSLOG)
+    RtosLog::RtosLog() :
+        _sem(NumMessages), _serial(), _thr(NULL)
+    {
+    }
+#else
 RtosLog::RtosLog() :
     _sem(NumMessages), _serial(USBTX, USBRX), _thr(NULL)
 {
@@ -68,6 +74,7 @@
     _serial.baud(115200);
 #endif
 }
+#endif
 
 RtosLog::~RtosLog()
 {
@@ -124,3 +131,46 @@
     return ret;
 }
 
+int RtosLog::isr_printf(const char* format, ...)
+{
+    // The pool has no "wait for free message" so we use a Sempahore
+    // to keep track of the number of free messages and, if needed,
+    // block the caller until a message is free
+    int available = _sem.wait(0);
+    if (available <= 0) {
+      // no free messages and it is not good to wait in an ISR so
+      // we discard the message
+      return 0;
+    }
+    
+    // Allocate a null terminated message. Will always succeed due to
+    // the semaphore above
+    message_t *message = _mpool.calloc();
+    
+    // Write the callers formatted message 
+    std::va_list args;
+    va_start(args, format);
+    int ret = vsnprintf(message->msg, MessageLen, format, args);
+    va_end(args);
+    
+    // If the entire message could not fit in the preallocated buffer
+    // then allocate a new one and try again.
+    if (ret > MessageLen) {
+        message->ptr = (char*)malloc(ret + 1);
+        if (message->ptr != NULL) {
+            va_start(args, format);
+            ret = vsnprintf(message->ptr, ret + 1, format, args);
+            va_end(args);
+        }
+    }
+    
+    // Send message
+    _queue.put(message);
+    
+    // Note that the Semaphore is not released here, that is done after
+    // the message has been processed and released into the pool by
+    // logTask()
+    //_sem.release();
+    
+    return ret;
+}
--- a/RtosLog.h	Thu Feb 19 14:41:14 2015 +0100
+++ b/RtosLog.h	Mon Mar 09 11:15:56 2015 +0100
@@ -21,6 +21,10 @@
 #include "rtos.h"
 #include "dm_board_config.h"
 
+#if defined(DM_BOARD_USE_USBSERIAL_IN_RTOSLOG)
+  #include "USBSerial.h"
+#endif
+
 /**
  * All threads can independantly call the printf function in the RtosLog class
  * without risk of getting the output tangled up.
@@ -53,11 +57,40 @@
     RtosLog();
     ~RtosLog();
     
-    /** Starts the logger thread
+    /** Starts the logger thread, called from DMBoard::instance().init()
      */
     void init();
     
+    /** Printf that works in an RTOS
+     *
+     *  This function will create a string from the specified format and
+     *  optional extra arguments and put it into a message that the RtosLog
+     *  thread will write to the log.
+     *
+     *  Note that if the underlying queue is full then this function
+     *  will block until an entry becomes available. This is required to 
+     *  make sure that all printf calls actually get printed. If this happens
+     *  too often then increase the priority of the RtosLog thread or reduce
+     *  the number of printed messages.
+     *
+     *  @param format  format string
+     *  @param ...     optional extra arguments
+     */
     int printf(const char* format, ...);
+    
+    /** Printf that works in an RTOS
+     *
+     *  This function will create a string from the specified format and
+     *  optional extra arguments and put it into a message that the RtosLog
+     *  thread will write to the log.
+     *
+     *  Note that if the underlying queue is full then this function
+     *  discards the message and returns immediately.
+     *
+     *  @param format  format string
+     *  @param ...     optional extra arguments
+     */
+    int isr_printf(const char* format, ...);
   
 private:
     
@@ -69,7 +102,11 @@
     MemoryPool<message_t, NumMessages> _mpool;
     Queue<message_t, NumMessages> _queue;
     Semaphore _sem;
+#if defined(DM_BOARD_USE_USBSERIAL_IN_RTOSLOG)
+    USBSerial _serial;
+#else
     Serial _serial;
+#endif
     Thread* _thr;
     
     static void logTask(void const* args);
--- a/dm_board_config.h.txt	Thu Feb 19 14:41:14 2015 +0100
+++ b/dm_board_config.h.txt	Mon Mar 09 11:15:56 2015 +0100
@@ -29,10 +29,10 @@
 // #define DM_BOARD_USE_TOUCH
 // #define DM_BOARD_USE_ETHERNET
 #define DM_BOARD_USE_FAST_UART
+// #define DM_BOARD_USE_USBSERIAL_IN_RTOSLOG
 // #define DM_BOARD_DISABLE_STANDARD_PRINTF
 // #define DM_BOARD_ENABLE_MEASSURING_PINS
-// #define DM_BOARD_BIOS_DEVELOPMENT
-#define DM_BOARD_USE_REGISTRY
-#define DM_BOARD_USE_BUILTIN_IMAGES
+// #define DM_BOARD_USE_REGISTRY
+// #define DM_BOARD_USE_BUILTIN_IMAGES
 
 #endif