Example using the support package for LPC4088 DisplayModule

Dependencies:   DMBasicGUI DMSupport

Example using a lot of the features in the software package for the LPC4088 Display Module.

This project can be selected as a template when creating a new project based on the LPC4088 Display Module.

Information

This project works on the 4.3" display modules.

Some of the apps works on the 5" display modules. The ImageViewer and Slideshow app will show the images distorted as it does not take the resolution into consideration.

Information

The USB Status app is disabled. The Image viewer looks for images in the root of SD cards, USB memory sticks or the file system on the QSPI flash. The Slideshow app expects to find a slideshow script in /mci/elec14/ea_logo.txt.

This is what it looks like on the 4.3" display:

/media/uploads/embeddedartists/everything_cap_000.png /media/uploads/embeddedartists/everything_cap_001.png /media/uploads/embeddedartists/everything_cap_003.png /media/uploads/embeddedartists/everything_cap_004.png /media/uploads/embeddedartists/everything_cap_006.png /media/uploads/embeddedartists/everything_cap_008.png

main.cpp

Committer:
embeddedartists
Date:
2019-11-04
Revision:
30:e1cded731965
Parent:
27:4fe24decabf9

File content as of revision 30:e1cded731965:

/******************************************************************************
 * Includes
 *****************************************************************************/
 
#include "mbed.h"
#include "mbed_interface.h"
#include "rtos.h"

#include "dm_board_config.h"

#if defined(DM_BOARD_USE_ETHERNET)
  #include "EthernetInterface.h"
  #include "HTTPServer.h"
#endif
#if defined(DM_BOARD_USE_USB_DEVICE)
  #include "USBMSD_RAMFS.h"
  #include "USBSerial.h"
  #include "USBKeyboard.h"
  #include "AppUSBMouse.h"
#endif
#if defined(DM_BOARD_USE_USB_HOST)
  #include "USBHostMSD.h"
  #include "USBHostMouse.h"
  #include "USBHostKeyboard.h"
#endif
#include "DMBoard.h"

#include "AppLauncher.h"
#include "meas.h"

#include "AppNetworkSettings.h"
#include "AppStatus.h"
#include "AppTouchCalibration.h"
#include "AppColorPicker.h"
#include "AppImageViewer.h"
#include "AppSlideShow.h"
#include "AppRTCSettings.h"
//#include "AppUSBStatus.h"
#include "AppDraw.h"
#include "image_data.h"
#include "Resource.h"


/******************************************************************************
 * Typedefs and defines
 *****************************************************************************/

/* Size of RAM file system exposed to PC as USB MassStorage */
#define RAM_FS_SIZE (20*1024*1024)

/******************************************************************************
 * Local variables
 *****************************************************************************/

static Resource resOkButton(img_ok, img_size_ok, 40, 40);
static Resource resRepeatButton(img_repeat, img_size_repeat, 40, 40);

/******************************************************************************
 * Global variables
 *****************************************************************************/

#if defined(DM_BOARD_USE_ETHERNET)
  EthernetInterface eth;
  bool ethInitialized = false;
  bool ethUsingDHCP = true;
#endif
#if defined(DM_BOARD_USE_USB_HOST)
  bool haveUSBMSD = false;
#endif

#if defined(DM_BOARD_USE_USB_DEVICE)
  //#define DEMO_USB_DEVICE_MOUSE
  //#define DEMO_USB_DEVICE_SERIAL
  #define DEMO_USB_DEVICE_MSD
#endif

/******************************************************************************
 * Local functions
 *****************************************************************************/

void aliveTask(void)
{
  DMBoard* board = &DMBoard::instance();
    
  while(true)
  {
    board->setLED(DMBoard::Led4, false);
    board->setLED(DMBoard::Led1, true);
    ThisThread::sleep_for(300);
    board->setLED(DMBoard::Led1, false);
    board->setLED(DMBoard::Led2, true);
    ThisThread::sleep_for(300);
    board->setLED(DMBoard::Led2, false);
    board->setLED(DMBoard::Led3, true);
    ThisThread::sleep_for(300);
    board->setLED(DMBoard::Led3, false);
    board->setLED(DMBoard::Led4, true);
    ThisThread::sleep_for(300);
  }
}

#if defined(DM_BOARD_USE_DISPLAY)

typedef enum {
    ColorPickerApp,
    ImageViewerApp,
    SlideshowApp,
    SettingsApp, 
    StatusApp, 
    TouchTestApp,
    RtcApp,
    USBStatusApp,
    DrawingApp,
    USBMouseApp,
    CalibrationApp =  AppLauncher::CalibrationApp,
    Placeholder,
} myapps_t;

static App* launchApp(uint32_t id)
{
  App* a = NULL;
  switch ((myapps_t)id) {
      case CalibrationApp:
          a = new AppTouchCalibration();
         ((AppTouchCalibration*)a)->addResource(AppTouchCalibration::Resource_Ok_button, &resOkButton);
          break;
      case SettingsApp:
          a = new AppNetworkSettings();
          break;
      case ColorPickerApp:
          a = new AppColorPicker();
         ((AppColorPicker*)a)->addResource(AppColorPicker::Resource_Ok_button, &resOkButton);
          break;
      case ImageViewerApp:
          a = new AppImageViewer();
          break;
      case SlideshowApp:
          a = new AppSlideShow("/mci/elec14/ea_logo.txt", "/mci/elec14", 0, 0);
         ((AppSlideShow*)a)->addResource(AppSlideShow::Resource_Ok_button, &resOkButton);
         ((AppSlideShow*)a)->addResource(AppSlideShow::Resource_Repeat_button, &resRepeatButton);
          break;
      case StatusApp:
          a = new AppStatus();
          break;
      case RtcApp:
          a = new AppRTCSettings();
          break;
      case USBStatusApp:
          //a = new AppUSBStatus();
          break;
      case DrawingApp:
          a = new AppDraw();
          break;
#if defined(DM_BOARD_USE_USB_DEVICE) && defined(DEMO_USB_DEVICE_MOUSE)
      case USBMouseApp:
          a = new AppUSBMouse();
          break;
#endif
      default:
          break;
  }
  return a;
}

#define SWIM_TASK_PREFIX  "[SWIM] "
void swimTask(void)
{
  RtosLog* log = DMBoard::instance().logger();
    
  log->printf(SWIM_TASK_PREFIX"swimTask started\n");
  
  AppLauncher launcher;
    
    
  if (launcher.setup()) {
    launcher.addImageButton(SettingsApp, "Network", WHITE,  img_preferences_system_network, img_size_preferences_system_network);
    launcher.addImageButton(DrawingApp, "Drawing", WHITE, img_bijiben, img_size_bijiben);
    launcher.addImageButton(SlideshowApp, "Slideshow", WHITE, img_multimedia_photo_manager, img_size_multimedia_photo_manager);
    //launcher.addImageButton(TouchGFXApp,  "TouchGFX");
    //launcher.addImageButton(EmWinApp,     "emWin");
    launcher.addImageButton(ColorPickerApp, "Color Picker", WHITE,  img_preferences_color, img_size_preferences_color);
    launcher.addImageButton(ImageViewerApp, "Image Viewer", WHITE,  img_multimedia_photo_manager, img_size_multimedia_photo_manager);
    launcher.addImageButton(StatusApp, "About", WHITE,  img_utilities_system_monitor, img_size_utilities_system_monitor);
#if defined(DM_BOARD_USE_USB_DEVICE) && defined(DEMO_USB_DEVICE_MOUSE)
    launcher.addImageButton(USBMouseApp, "USB Mouse", WHITE,  img_unetbootin, img_size_unetbootin);
#else
    launcher.addImageButton(Placeholder, "USB Status", WHITE,  img_unetbootin, img_size_unetbootin);
#endif
    launcher.addImageButton(RtcApp, "Clock", WHITE,  img_preferences_system_time, img_size_preferences_system_time);
      
    launcher.setAppCreatorFunc(launchApp);
    log->printf(SWIM_TASK_PREFIX"Starting menu system\n");
    launcher.runToCompletion();
    launcher.teardown();
  } else {
    log->printf(SWIM_TASK_PREFIX"Failed to prepare menu system\n");
  }
  
  // Should never end up here  
  mbed_die();
}

#endif //DM_BOARD_USE_DISPLAY

#if defined(DM_BOARD_USE_ETHERNET)

  #define NET_TASK_PREFIX  "[NET] "  
  void netTask(void)
  {
    RtosLog* log = DMBoard::instance().logger();
    log->printf(NET_TASK_PREFIX"EthernetInterface Setting up...\r\n"); 

	nsapi_error_t net_err = eth.connect();

	if (net_err != NSAPI_ERROR_OK) {
		log->printf(NET_TASK_PREFIX"EthernetInterface connect Error %d\r\n", net_err);
	}
	else {

    	ethInitialized = true;
    	ethUsingDHCP = true;
    
    	log->printf(NET_TASK_PREFIX"IP Address is %s\r\n", eth.get_ip_address());
    	log->printf(NET_TASK_PREFIX"NetMask is %s\r\n", eth.get_netmask());
    	log->printf(NET_TASK_PREFIX"Gateway Address is %s\r\n", eth.get_gateway());
    	log->printf(NET_TASK_PREFIX"Ethernet Setup OK\r\n");
  
    	HTTPServerAddHandler<SimpleHandler>("/hello"); //Default handler
    	FSHandler::mount("/mci", "/");
    	HTTPServerAddHandler<FSHandler>("/");
    	//lcd.locate(0,0);
    	//lcd.printf("%s",eth.getIPAddress());
    	HTTPServerStart(80);

	}    
    

  }
#endif //DM_BOARD_USE_ETHERNET

#if defined(DM_BOARD_USE_USB_HOST)
static volatile int mouse_button, mouse_x, mouse_y, mouse_z;
static uint16_t cursor_x=0, cursor_y=0;
void mouseEvent(uint8_t buttons, int8_t x, int8_t y, int8_t z)
{
    mouse_button = buttons;
    mouse_x = x;
    mouse_y = y;
    mouse_z = z;
    
    if (x < 0) {
        if (cursor_x > -x) {
            cursor_x += x;
        } else {
            cursor_x = 0;
        }
    } else {
        if ((cursor_x + x) >= 480) {
            cursor_x = 479;
        } else {
            cursor_x += x;
        }
    }

    if (y < 0) {
        if (cursor_y > -y) {
            cursor_y += y;
        } else {
            cursor_y = 0;
        }
    } else {
        if ((cursor_y + y) >= 272) {
            cursor_y = 271;
        } else {
            cursor_y += y;
        }
    }
    
    //Chip_LCD_Cursor_SetPos(LPC_LCD, cursor_x, cursor_y);
    LPC_LCD->CRSR_XY = (cursor_x & 0x3FF) | ((cursor_y & 0x3FF) << 16);
}

#define LCD_CURSOR_32x32 0
#define LCD_CURSOR_64x64 1
#define CURSOR_SIZE  LCD_CURSOR_32x32
#define CURSOR_H_SIZE 32
#define CURSOR_V_SIZE 32
#define CURSOR_NUM   0    
#define CURSOR_H_OFS (10)
#define CURSOR_V_OFS (6)

const unsigned char __attribute__ ((aligned(4))) Cursor[(CURSOR_H_SIZE / 4) * CURSOR_V_SIZE] =
{
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xFA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFE, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFE, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFE, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFE, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFF, 0xEA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFF, 0xFF, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFF, 0xFF, 0xFA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFF, 0xFF, 0xFE, 0xAA, 0xAA,
	0xAA, 0xAB, 0xFB, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA,
	0xAA, 0xAB, 0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA,
	0xAA, 0xAB, 0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA,
	0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA,
	0xAA, 0xAA, 0xBF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA,
	0xAA, 0xAA, 0xBF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAF, 0xFF, 0xFF, 0xFE, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFF, 0xFF, 0xFE, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAB, 0xFF, 0xFF, 0xFE, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA
};

void prepareCursor(bool enable) {
    //Chip_LCD_Cursor_Disable(LPC_LCD, 0);
    LPC_LCD->CRSR_CTRL = (CURSOR_NUM << 4);
    
    if (enable) {
        //Chip_LCD_Cursor_Config(LPC_LCD, LCD_CURSOR_32x32, true);
        LPC_LCD->CRSR_CFG = ((true ? 1 : 0) << 1) | CURSOR_SIZE;
        
        //Chip_LCD_Cursor_WriteImage(LPC_LCD, 0, (void *) Cursor);
        {
            int i, j;
            uint32_t *fifoptr, *crsr_ptr = (uint32_t *) Cursor;

            /* Check if Cursor Size was configured as 32x32 or 64x64*/
            if (CURSOR_SIZE == LCD_CURSOR_32x32) {
                i = CURSOR_NUM * 64;
                j = i + 64;
            }
            else {
                i = 0;
                j = 256;
            }
            fifoptr = (uint32_t *) &(LPC_LCD->CRSR_IMG[0]);

            /* Copy Cursor Image content to FIFO */
            for (; i < j; i++) {

                *fifoptr = *crsr_ptr;
                crsr_ptr++;
                fifoptr++;
            }
        }
        
        //Chip_LCD_Cursor_SetClip(LPC_LCD, CURSOR_H_OFS, CURSOR_V_OFS);
        LPC_LCD->CRSR_CLIP = (CURSOR_H_OFS & 0x3F) | ((CURSOR_V_OFS & 0x3F) << 8);
        
        //Chip_LCD_Cursor_SetPos(LPC_LCD, cursor_x, cursor_y);
        
        //Chip_LCD_Cursor_Enable(LPC_LCD, 0);
        LPC_LCD->CRSR_CTRL = (CURSOR_NUM << 4) | 1;
    }
}


#define CIRCBUFF_SIZE 256
static volatile uint8_t circbuff[CIRCBUFF_SIZE];
static volatile uint32_t circbuff_read = 0;
static uint32_t circbuff_write = 0;
void keyEvent(uint8_t key)
{
    circbuff[circbuff_write%CIRCBUFF_SIZE] = key;
    circbuff_write++;
}


#define USBH_TASK_PREFIX  "[USBH] "
#define USBH_CONNECTION_EVENT   (1<<4)
void usbHostTask(void)
{
  bool msdConnected = false;
  bool keyboardConnected = false;
  bool mouseConnected = false;

  USBHostMSD* msd = new USBHostMSD("usb");
  USBHostKeyboard* keyboard = new USBHostKeyboard();
  USBHostMouse* mouse = new USBHostMouse();
  USBHost* host = USBHost::getHostInst();
  EventFlags connectionEvent;
  host->signalOnConnections(&connectionEvent, USBH_CONNECTION_EVENT);

  RtosLog* log = DMBoard::instance().logger();
    
  log->printf(USBH_TASK_PREFIX"Started\n");
    
  prepareCursor(false);

  while (true) {

    // wait for connect/disconnect message from USBHost
    connectionEvent.wait_any(USBH_CONNECTION_EVENT);
    log->printf(USBH_TASK_PREFIX"got USB event\n");

    if (msd->connected()) {
      if (!msdConnected) {
        msdConnected = true;
        haveUSBMSD = true;
        log->printf(USBH_TASK_PREFIX"USB MassStorage Device - Connected\n");
      }
    } else {
      if (msdConnected) {
        msdConnected = false;
        haveUSBMSD = false;
        log->printf(USBH_TASK_PREFIX"USB MassStorage Device - Ejected\n");
      }
      
      if (msd->connect()) {
        msdConnected = true;
        haveUSBMSD = true;
        log->printf(USBH_TASK_PREFIX"USB MassStorage Device - Connected\n");
      }      
    }
    
    if (keyboard->connected()) {
      if (!keyboardConnected) {
        keyboardConnected = true;
        log->printf(USBH_TASK_PREFIX"USB Keyboard - Connected\n");
        keyboard->attach(keyEvent);
      }
    } else {
      if (keyboardConnected) {
        keyboardConnected = false;
        log->printf(USBH_TASK_PREFIX"USB Keyboard - Ejected\n");
      }
      if (keyboard->connect()) {
        keyboardConnected = true;
        log->printf(USBH_TASK_PREFIX"USB Keyboard - Connected\n");
        keyboard->attach(keyEvent);
      }
    }
    
    if (mouse->connected()) {
      if (!mouseConnected) {
        mouseConnected = true;
        log->printf(USBH_TASK_PREFIX"USB Mouse - Connected\n");
        mouse->attachEvent(mouseEvent);
        prepareCursor(true);
      }
    } else {
      if (mouseConnected) {
        prepareCursor(false);
        mouseConnected = false;
        log->printf(USBH_TASK_PREFIX"USB Mouse - Ejected\n");
      }
      if (mouse->connect()) {
        mouseConnected = true;
        log->printf(USBH_TASK_PREFIX"USB Mouse - Connected\n");
        mouse->attachEvent(mouseEvent);
        prepareCursor(true);
      }
    }

  }
}

#endif //DM_BOARD_USE_USB_HOST

#if defined(DM_BOARD_USE_USB_DEVICE)

  #define USBD_TASK_PREFIX  "[USBD] "
  //#define USBD_CONNECTION_EVENT   (1<<4)
  void usbDeviceTask(void)
  {
    DMBoard* board = &DMBoard::instance();
    RtosLog* log = board->logger();
      
    log->printf(USBD_TASK_PREFIX"Started\n");
  
    // Possibilities:
    // - MassStorage
    //    * RAM file system
    //        a) For editing of settings or registry
    //        b) To give user an html file with information
    //        c) For BIOS updating
    //    * Expose MCI file system
    // - Serial
    //    * Let RtosLogger use the USBDevice serial port instead to 
    //      allow prints during debugging
    // - Mouse
    //    * Use the display as a "trackpad"
    // - Keyboard
    //    * Could be used by the RtosLogger (for fun)
    //    * Write our logo in ASCII art (for fun)
    // - Audio?
    // - CDC?
      
#if defined(DEMO_USB_DEVICE_MSD)
    // USBDevice: MassStorage - Expose a 5MB RAM file system
    //
    // Notes: 
    //    * Copying the large file to the PC at ca 512Kbyte per second
    //    * Copying a large file to the board at ca 800Kbyte per second
    void* fsmem = malloc(RAM_FS_SIZE);
    if (fsmem == NULL) {
      log->printf("Failed to allocate memory for RAM file system\n");
      mbed_die();
    }
    RAMFileSystem ramfs((uint32_t)fsmem, RAM_FS_SIZE, "ram");
    USBMSD_RAMFS usbmsd(&ramfs);  
    ramfs.format();
    
    // Create test file that user can modify
    FILE* f = fopen("/ram/message.txt", "w");
    if (f != NULL) {
      fwrite("Hello World!\n", 1, 13, f);
      fclose(f);
    }
    
    // Create benchmark file
    uint32_t benchSize = RAM_FS_SIZE - 1*1024*1024;
    log->printf(USBD_TASK_PREFIX"Generating %dMB benchmarking file...\n", benchSize/(1024*1024));
    char buff[512+1] = {0};
    for (int i = 0; i < 512; i++) {
      buff[i] = i;
    }
    f = fopen("/ram/bench.bin", "w");
    if (f != NULL) {
      for (int i = 0; i < (benchSize/512); i++) {
        fwrite(buff, 1, 512, f);
      }
      fclose(f);
    }
    log->printf(USBD_TASK_PREFIX"Finished generating /ram/bench.bin\n");
    
    while (true) {
      if (usbmsd.connect()) {
        log->printf(USBD_TASK_PREFIX"USB MassStorage - Connected\n");
        log->printf(USBD_TASK_PREFIX"Press USER button to disconnect USB MassStorage!\n");
        while (!board->buttonPressed()) {
          Thread::wait(50);
        }
        log->printf(USBD_TASK_PREFIX"User requested USB disconnect\n");
        usbmsd.disconnect();
        while (board->buttonPressed()) {
          Thread::wait(50);
        }
        log->printf(USBD_TASK_PREFIX"USB disconnected\n");
        
        {
          log->printf("Reading /ram/message.txt:\n");
          f = fopen("/ram/message.txt", "r");
          if (f != NULL) {
            while (true) {
              size_t num = fread(buff, 1, 512, f);
              if (num > 0) {
                buff[num] = '\0';
                log->printf(buff);
              } else {
                break;
              }
            }
            fclose(f);
            log->printf("\nEOF\n");
          } else {
            log->printf("Failed to read /ram/message.txt\n");
          }
        }
        
        log->printf("\n"USBD_TASK_PREFIX"Press USER button to connect USB MassStorage again!\n");
        while (!board->buttonPressed()) {
          Thread::wait(50);
        }
        while (board->buttonPressed()) {
          Thread::wait(50);
        }
        log->printf(USBD_TASK_PREFIX"User requested to connect USB again\n");
      } 
    }
#endif // #if defined(DEMO_USB_DEVICE_MSD)
    
#if defined(DEMO_USB_DEVICE_SERIAL)
    // USBDevice: Serial  (see http://developer.mbed.org/handbook/USBSerial)
    // http://developer.mbed.org/questions/5872/User-Friendly-Installation-of-USBSerial-/
    //
    // Notes: 
    //    * Works, but a reset (e.g. Alt-B) requires the USB cable to be ejected+inserted 
    //      for the PC to see the COM port again. It does not help to restart the Terminal
    //      program
    //    * Unplugging the USB cable after the terminal program on the PC has connected
    //      and then plugging it in again does not work. The terminal program will not see
    //      the port until after a bord reset. 
    //      Update: This seems to be the Terminal Program's fault. Restarting the terminal
    //      program will make the port appear again.
    //    * It is possible to have the cable connected before powering up as well as connecting
    //      the cable after powering up.
  #if defined(DM_BOARD_USE_USBSERIAL_IN_RTOSLOG)
    int counter = 0;
    while(true) {
        Thread::wait(1000);
        log->printf(USBD_TASK_PREFIX"Counter %3d\n", counter++);
    }
  #else
    USBSerial s;
    int counter = 0;
    while(true) {
        Thread::wait(1000);
        s.printf(USBD_TASK_PREFIX"Counter %3d\n", counter++);
    }
  #endif
#endif // #if defined(DEMO_USB_DEVICE_SERIAL)
    
#if defined(DEMO_USB_DEVICE_MOUSE)
    // Notes: 
    //    * If the USBMouse class is used after this then the USBKeyboard stops working.
    //      if both are to be used then the USBMouseKeyboard class must be used instead.
    USBKeyboard keyb;
    while(true) {
      while (!board->buttonPressed()) {
        Thread::wait(50);
      }
      keyb.printf("Hello World!\n");
      while (board->buttonPressed()) {
        Thread::wait(50);
      }
    }
#endif // #if defined(DEMO_USB_DEVICE_MOUSE)    
  }
#endif


#define REGTEST "[REG] "
static void testRegistry()
{
  Registry* reg = DMBoard::instance().registry();
  RtosLog* log = DMBoard::instance().logger();
  char* key;
  char* val;
  Registry::RegistryError err;
    
  log->printf(REGTEST"Before:\n");
  for (int i = 0; i < reg->numEntries(); i++) {
    err = reg->entryAt(i, &key, &val);
    if (err == Registry::Ok) {
      log->printf(REGTEST"   [%2d] '%s' = '%s'\n", i, key, val);
      free(key);
      free(val);
    } else {
      log->printf(REGTEST"   [%2d] got error %d\n", i, err);
    }
  }
  
  log->printf(REGTEST"Getting existing value:\n");
  err = reg->getValue("IP Address", &val);
  if (err == Registry::Ok) {
    log->printf(REGTEST"   Existing 'IP Address' = '%s'\n", val);
    free(val);
  } else {
    log->printf(REGTEST"   Existing 'IP Address' got error %d\n", err);
  }
  
  log->printf(REGTEST"Getting missing value:\n");
  err = reg->getValue("X78g4dfwx", &val);
  if (err == Registry::Ok) {
    log->printf(REGTEST"   Missing 'X78g4dfwx' = '%s'\n", val);
    free(val);
  } else if (err == Registry::NoSuchKeyError) {
    log->printf(REGTEST"   Missing 'X78g4dfwx' was missing.\n", err);
  } else {
    log->printf(REGTEST"   Existing 'X78g4dfwx' got error %d\n", err);
  }

  log->printf(REGTEST"Updating value:\n");
  err = reg->getValue("EATest", &val);
  if (err == Registry::Ok) {
    log->printf(REGTEST"   Old value for 'EATest' = '%s'\n", val);
    char buf[32];
    sprintf(buf, "%d", atoi(val)+1);
    free(val);
    err = reg->setValue("EATest", buf);
    if (err == Registry::Ok) {
      log->printf(REGTEST"   Updated 'EATest' to '%s'\n", buf);
    } else {
      log->printf(REGTEST"   Failed to update 'EATest', got error %d\n", err);
    }
  } else if (err == Registry::NoSuchKeyError) {
    log->printf(REGTEST"   No value for 'EATest', adding one\n", err);
    err = reg->setValue("EATest", "-3");
    if (err == Registry::Ok) {
      log->printf(REGTEST"   Set 'EATest' to '0'\n");
    } else {
      log->printf(REGTEST"   Failed to set 'EATest', got error %d\n", err);
    }
  } else {
    log->printf(REGTEST"   Failed to read 'EATest' got error %d\n", err);
  }
  
  log->printf(REGTEST"Storing values persistently\n");
  err = reg->store();
  if (err != Registry::Ok) {
    log->printf(REGTEST"   Failed to store values, got error %d\n", err);
  }

  log->printf(REGTEST"After:\n");
  for (int i = 0; i < reg->numEntries(); i++) {
    err = reg->entryAt(i, &key, &val);
    if (err == Registry::Ok) {
      log->printf(REGTEST"   [%2d] '%s' = '%s'\n", i, key, val);
      free(key);
      free(val);
    } else {
      log->printf(REGTEST"   [%2d] got error %d\n", i, err);
    }
  }  
}

/******************************************************************************
 * Main function
 *****************************************************************************/
int main()
{
  DMBoard::BoardError err;
  DMBoard* board = &DMBoard::instance();
  RtosLog* log = board->logger();
  err = board->init();
  if (err != DMBoard::Ok) {
    log->printf("Failed to initialize the board, got error %d\r\n", err);
    log->printf("\nTERMINATING\n");
    ThisThread::sleep_for(2000); // allow RtosLog to flush messages
    mbed_die();
  }

  board->buzzer(440,50);
  wait_ms(30);
  board->buzzer(660,50);
  wait_ms(30);
  board->buzzer(440,50);
  
  log->printf("\n\n---\nMulti-threaded demo\nBuilt: " __DATE__ " at " __TIME__ "\n\n");
  
  //testRegistry();
  
  
  Thread tAlive;
  tAlive.start(aliveTask);
#if defined(DM_BOARD_USE_DISPLAY)
  Thread tSwim(osPriorityNormal, 8192);
  tSwim.start(swimTask);
#endif



#if defined(DM_BOARD_USE_ETHERNET)  
  Thread tNetwork(osPriorityNormal, 8192);
  tNetwork.start(netTask);
#endif

#if defined(DM_BOARD_USE_USB_HOST)
  Thread tUSBHandler(osPriorityNormal, 8192);
  tUSBHandler.start(usbHostTask);
#elif defined(DM_BOARD_USE_USB_DEVICE)
  Thread tUSBDev(osPriorityNormal, 8192);
  tUSBDev.start(usbDeviceTask);
#endif

  while(1) { 
    ThisThread::sleep_for(5000);
    time_t seconds = time(NULL);

    log->printf("Time: %s\n", ctime(&seconds));
  }
}