Index: apps/plugins/mem_mon.c
===================================================================
--- apps/plugins/mem_mon.c	(revision 0)
+++ apps/plugins/mem_mon.c	(revision 0)
@@ -0,0 +1,383 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id: helloworld.c 8349 2006-01-15 18:20:18Z amiconn $
+ *
+ * Copyright (C) 2007 Matthias Wientapper
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+/*
+ * This is a simple memory monitor/editor application.
+ *
+ * TODO:
+ *       * Use lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
+ *         for inverse printing selected characters
+ *
+ *       * Do something about using proportional fonts
+ *
+ *       * Make this work for other models
+ *
+ */
+
+#include "plugin.h"
+#include "pluginlib_actions.h"
+
+PLUGIN_HEADER
+
+#define MEM_MON_UP        PLA_UP
+#define MEM_MON_UP_REP    PLA_UP_REPEAT
+#define MEM_MON_DOWN      PLA_DOWN
+#define MEM_MON_DOWN_REP  PLA_DOWN_REPEAT
+#define MEM_MON_RIGHT     PLA_RIGHT
+#define MEM_MON_RIGHT_REP PLA_RIGHT_REPEAT
+#define MEM_MON_LEFT      PLA_LEFT
+#define MEM_MON_LEFT_REP  PLA_LEFT_REPEAT
+#define MEM_MON_QUIT      PLA_QUIT
+#define MEM_MON_UPDATE    PLA_FIRE
+#define MEM_MON_MODE      PLA_FIRE_REPEAT
+
+/* ui-mode, selected by pressing and holding MEM_MON_MODE */
+#define MODE_PAGE   0
+#define MODE_SELECT 1
+#define MODE_EDIT   2
+
+static struct plugin_api* rb;
+
+#ifdef SIMULATOR
+char sim_mem[]="<- This is a memory areas to play around ->";
+#endif
+
+char *addr;
+char *byte_addr = 0;
+char new_mem_val = 0;
+
+int max_rows = 0;
+int max_cols = 0;
+int ui_mode  = 0;
+
+int fh, fw;
+int sel_row = 1;
+int sel_col = 0;
+
+void get_screen_properties(void){
+  rb->lcd_clear_display();
+  rb->lcd_update();
+  rb->font_getstringsize( "0", &fw, &fh, FONT_UI );
+  max_rows = (int) (LCD_HEIGHT / fh);
+  max_cols = (int) (LCD_WIDTH  / fw);
+}
+
+int get_start_address(void){
+  const struct button_mapping *plugin_contexts[]
+    = {generic_directions, generic_actions};
+  char buf[31];
+  char *i;
+  int digit = 7; /* start with leftmost digit */
+  int button, got_address = 0;
+  int done = 0;
+
+#ifdef SIMULATOR
+  i = sim_mem;
+#else
+  i = 0;
+#endif
+
+  /* TODO:
+   * At this point we could
+   * read mem_mon.dat if available      
+   * with a line like "addr=0x12345678" 
+   * and set addr to this value.
+   */
+
+  rb->lcd_clear_display();
+  rb->snprintf(buf, sizeof(buf), "address:");
+  rb->lcd_puts(0, 0, buf);
+
+
+  /* edit value */
+  while(!done) {
+
+    rb->snprintf(buf, sizeof(buf), "%08x", i);
+    rb->lcd_puts(0, 1, buf);
+
+    /* put a "cursor" under selected cell */
+    rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
+    rb->lcd_fillrect((7-digit)*fw, 2*fh-1, fw, 1);
+    rb->lcd_set_drawmode(DRMODE_SOLID);
+
+    rb->lcd_update();
+
+    button = pluginlib_getaction(rb, 0, plugin_contexts, 2);
+    switch(button) {
+    case MEM_MON_DOWN:
+    case MEM_MON_DOWN_REP:
+      i-= 1<<(digit*4);
+      break;
+    case MEM_MON_UP:
+    case MEM_MON_UP_REP:
+      i+= 1<<(digit*4);
+      break;
+    case MEM_MON_RIGHT:
+    case MEM_MON_RIGHT_REP:
+      if(digit > 0)
+        digit -= 1;
+      break;
+    case MEM_MON_LEFT:      
+    case MEM_MON_LEFT_REP:      
+      if(digit < 7)
+        digit += 1;
+      break;
+    case  MEM_MON_UPDATE:
+      done = true;
+      got_address = true;
+      addr = i;
+      break;
+    case MEM_MON_QUIT:
+      done = true;
+      got_address = false;
+    }
+  }
+  return got_address;
+}
+
+void dump_screen(char *address){
+  char line[35]; /* 35 characters per line */
+  char buf[35];
+  char ch;
+  char mem_val;
+  int i;
+  char row = 0;
+  char col = 0;
+
+  /* status line in row 0 */
+  if(ui_mode == MODE_PAGE){
+    /* display page address */
+    rb->snprintf(line,sizeof(line), "%08x", address);
+    rb->lcd_puts(col, row, line);
+  } else {
+    /* display currently selected address */
+    byte_addr = addr + (sel_row-1)*8 + sel_col;
+    rb->snprintf(buf, sizeof(buf), "%08x", byte_addr);
+    rb->lcd_puts(0, 0, buf);
+  }
+
+  /* do the hex/char part */
+  for(row=1; row<max_rows; row++){
+    /*  
+     *  HHHHHHHHHHHHHHHH:CCCCCCCC
+     *  012345678901234567890123456789012345
+     *            1         2         3
+     */
+
+    /* hex numbers and characters */
+    for(i=0;i<8;i++){
+      mem_val = *(address+i);
+      rb->snprintf(buf+i*2, sizeof(buf), "%02x", mem_val); 
+      if (mem_val>31 && mem_val<127)
+        ch=mem_val;
+      else
+        ch='.';
+      rb->snprintf(buf+20+i, sizeof(buf), "%c", ch); 
+    }
+    /* copy hex and char parts from buf to line */
+    /* FIXME: this is ugly code! */
+    rb->strncpy(line, buf, 16);
+    rb->strncpy(line+17, buf+20, 8);
+    line[16]=':';
+    line[25]='\0';
+
+    rb->lcd_puts(col, row, line);
+   
+    address = address + 8; /* 8 bytes per line */
+  } 
+
+  switch(ui_mode) {
+  case MODE_SELECT:
+    /* invert selected cell */
+    rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
+    rb->lcd_fillrect(sel_col*fw*2, sel_row*fh, fw*2, fh);
+    rb->lcd_set_drawmode(DRMODE_SOLID);
+    break;
+  case MODE_EDIT:
+    /*print changed value */
+    rb->snprintf(buf, sizeof(buf), "->%02x", new_mem_val);
+    rb->lcd_puts(9, 0, buf);
+
+    /* put a "cursor" under selected cell */
+    rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
+    rb->lcd_fillrect(sel_col*fw*2, sel_row*fh+fh-1, fw*2, 1);
+    rb->lcd_set_drawmode(DRMODE_SOLID);
+    break;
+  }
+
+  rb->lcd_update();
+}
+
+/**********************************/
+/* this is the plugin entry point */
+/**********************************/
+enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
+{
+  int button_curr = 0;
+  int quit = 0;
+  int button_prev = 0;
+  const struct button_mapping *plugin_contexts[]
+    = {generic_directions, generic_actions};
+
+  (void)parameter;
+  rb = api;
+
+  /* give me something to play with */
+#ifdef SIMULATOR   
+  addr = sim_mem;
+#endif
+
+  get_screen_properties();
+  if(!get_start_address())
+    return PLUGIN_OK;
+
+  dump_screen(addr);
+
+  while(!quit) {
+    button_prev = button_curr;
+    button_curr = pluginlib_getaction(rb, TIMEOUT_BLOCK, plugin_contexts, 2);
+
+    switch(button_curr) {
+    case MEM_MON_DOWN:
+    case MEM_MON_DOWN_REP:
+      /* what mode are we in* */
+      switch(ui_mode) {
+      case MODE_PAGE:
+        /* page down */
+        addr = addr + 8*(max_rows-1);
+        break;
+      case MODE_SELECT:
+        /* row down */
+        if (sel_row < max_rows - 1)
+          sel_row++;
+        else
+          addr = addr + 8; /* scroll down one line */
+        break;
+      case MODE_EDIT:
+        /* decrement value */
+        new_mem_val--;
+        break;
+      }
+      break;
+
+    case MEM_MON_UP:
+    case MEM_MON_UP_REP:
+      /* what mode are we in* */
+      switch(ui_mode) {
+      case MODE_PAGE:
+        /* page up */
+        addr = addr - 8*(max_rows-1);
+        break;
+      case MODE_SELECT:
+        /* row up */
+        if (sel_row > 1) 
+          sel_row--;
+        else
+          addr = addr - 8; /*scroll up one line */
+        break;
+      case MODE_EDIT:
+        /* decrement value */
+        new_mem_val++;
+        break;
+      }
+      break;
+
+    case MEM_MON_RIGHT:
+    case MEM_MON_RIGHT_REP:
+      /* what mode are we in* */
+      switch(ui_mode) {
+      case MODE_PAGE:
+        /* page up plus 64kB */
+        addr = addr + 0x10000; 
+        break;
+      case MODE_SELECT:
+        /* move right */
+        if (sel_col < 7) /* limited to hex field */
+          sel_col++;
+        break;
+      case MODE_EDIT:
+        break;
+      }
+      break;
+
+    case MEM_MON_LEFT:
+    case MEM_MON_LEFT_REP:
+      /* what mode are we in* */
+      switch(ui_mode) {
+      case MODE_PAGE:
+        /* page down minus 64kB */
+        addr = addr - 0x10000;
+        break;
+      case MODE_SELECT:
+        /* move left */
+        if (sel_col > 0)
+          sel_col--;
+        break;
+      case MODE_EDIT:
+        break;
+      }
+      break;
+
+    case MEM_MON_UPDATE:
+      /* update page */
+      if(ui_mode == MODE_EDIT){
+        /* commit changed value to memory, 
+           and return from edit mode */
+        *(addr+(sel_row-1)*8+sel_col) = new_mem_val;
+        ui_mode = MODE_PAGE;
+      }
+      break;
+
+    case MEM_MON_MODE:
+      /* toggle ui mode to next state */
+      if(button_curr != button_prev){
+        ui_mode = (ui_mode +1)%3;
+        if(ui_mode == MODE_EDIT)
+          new_mem_val = *(addr+(sel_row-1)*8+sel_col);
+      }
+      break;
+
+    case MEM_MON_QUIT:
+      switch (ui_mode){
+      case MODE_PAGE:
+        /* quit plugin */
+        quit=true;
+        return PLUGIN_OK;
+        break;
+      case MODE_SELECT:
+        /* goto page mode */
+        ui_mode = MODE_PAGE;
+        break;
+      case MODE_EDIT:
+        /* goto select mode */
+        ui_mode = MODE_SELECT;
+        break;
+      }
+
+    default:
+      if (rb->default_event_handler(button_curr) == SYS_USB_CONNECTED) {
+        return PLUGIN_USB_CONNECTED;
+      }
+      break;
+    }
+    dump_screen(addr);
+  }
+  return PLUGIN_OK;
+}
+
