Index: apps/plugins/mem_mon.c
===================================================================
--- apps/plugins/mem_mon.c	(revision 0)
+++ apps/plugins/mem_mon.c	(revision 0)
@@ -0,0 +1,362 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   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"
+
+PLUGIN_HEADER
+/* variable button definitions */
+/* not completed yet for all models */
+#if CONFIG_KEYPAD == RECORDER_PAD
+#define MEM_MON_UP      BUTTON_UP
+#define MEM_MON_UP_REP (BUTTON_UP | BUTTON_REPEAT)
+#define MEM_MON_DOWN      BUTTON_DOWN
+#define MEM_MON_DOWN_REP (BUTTON_DOWN | BUTTON_REPEAT)
+#define MEM_MON_RIGHT      BUTTON_RIGHT
+#define MEM_MON_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
+#define MEM_MON_LEFT      BUTTON_LEFT
+#define MEM_MON_LEFT_REP (BUTTON_LEFT | BUTTON_REPEAT)
+#define MEM_MON_QUIT   BUTTON_OFF
+#define MEM_MON_UPDATE BUTTON_PLAY
+#define MEM_MON_MODE   (BUTTON_PLAY | BUTTON_REPEAT)
+#define MEM_MON_FR     (BUTTON_RIGHT | BUTTON_ON)
+#define MEM_MON_FR_REP (BUTTON_RIGHT | BUTTON_ON | BUTTON_REPEAT)
+#define MEM_MON_FL     (BUTTON_LEFT | BUTTON_ON)
+#define MEM_MON_FL_REP (BUTTON_LEFT | BUTTON_ON | BUTTON_REPEAT)
+#define MEM_MON_FU     (BUTTON_UP | BUTTON_ON)
+#define MEM_MON_FU_REP (BUTTON_UP | BUTTON_ON | BUTTON_REPEAT)
+#define MEM_MON_FD     (BUTTON_DOWN | BUTTON_ON)
+#define MEM_MON_FD_REP (BUTTON_DOWN | BUTTON_ON | BUTTON_REPEAT)
+
+#elif CONFIG_KEYPAD == SANSA_E200_PAD
+#define MEM_MON_UP BUTTON_UP
+#define MEM_MON_UP_REP (BUTTON_UP | BUTTON_REPEAT)
+#define MEM_MON_DOWN BUTTON_DOWN
+#define MEM_MON_DOWN_REP (BUTTON_DOWN | BUTTON_REPEAT)
+#define MEM_MON_RIGHT BUTTON_RIGHT
+#define MEM_MON_RIGHT_REP (BUTTON_RIGHT | BUTTON_REPEAT)
+#define MEM_MON_LEFT BUTTON_LEFT
+#define MEM_MON_LEFT_REP (BUTTON_LEFT | BUTTON_REPEAT)
+#define MEM_MON_QUIT BUTTON_POWER
+#define MEM_MON_UPDATE BUTTON_SELECT
+#define MEM_MON_MODE (BUTTON_SELECT | BUTTON_REPEAT)
+#define MEM_MON_FR (BUTTON_RIGHT | BUTTON_REC)
+#define MEM_MON_FR_REP (BUTTON_RIGHT | BUTTON_REC | BUTTON_REPEAT)
+#define MEM_MON_FL (BUTTON_LEFT | BUTTON_REC)
+#define MEM_MON_FL_REP (BUTTON_LEFT | BUTTON_REC | BUTTON_REPEAT)
+#define MEM_MON_FU (BUTTON_UP | BUTTON_REC)
+#define MEM_MON_FU_REP (BUTTON_UP | BUTTON_REC | BUTTON_REPEAT)
+#define MEM_MON_FD (BUTTON_DOWN | BUTTON_REC)
+#define MEM_MON_FD_REP (BUTTON_DOWN | BUTTON_REC | BUTTON_REPEAT)
+#endif
+
+/* 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;
+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;
+
+/*
+ * for testing on simulator
+ */
+char sim_mem[]="<- This is a memory areas to play around ->";
+
+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);
+}
+
+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 */
+
+    /*
+     * FIXME: When inserting with lcd_puts() the rest of the line being erased, why?
+     *
+     * rb->snprintf(buf, sizeof(buf), "%02x", new_mem_val);
+     * rb->lcd_puts(sel_col*2, sel_row, buf);
+     *
+     * Display the new value in the upper right corner meanwhile...
+     */
+    rb->snprintf(buf, sizeof(buf), "->%02x", new_mem_val);
+    rb->lcd_puts(max_cols - 4, 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, quit = 0;
+   int button_pre = 0;
+
+   (void)parameter;
+    rb = api;
+
+    /* give me something to play with */
+    addr = sim_mem;
+
+    get_screen_properties();
+    dump_screen(addr);
+  
+    while(!quit) {
+      button=rb->button_get(true);
+      switch(button) {
+      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;
+
+	/* fast paging modes */
+      case MEM_MON_FR:
+      case MEM_MON_FR_REP:
+	if(ui_mode == MODE_PAGE)
+	  addr = addr + 0x1000000;
+	break;
+      case MEM_MON_FL:
+      case MEM_MON_FL_REP:
+	if(ui_mode == MODE_PAGE)
+	  addr = addr - 0x1000000;
+	break;
+      case MEM_MON_FU:
+      case MEM_MON_FU_REP:
+	if(ui_mode == MODE_PAGE)
+	  addr = addr + 0x100;
+	break;
+      case MEM_MON_FD:
+      case MEM_MON_FD_REP:
+ 	if(ui_mode == MODE_PAGE)
+	  addr = addr - 0x100;
+	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_pre != MEM_MON_MODE){
+	  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) == SYS_USB_CONNECTED) {
+	  return PLUGIN_USB_CONNECTED;
+        }
+        break;
+      }
+      dump_screen(addr);
+      button_pre = button;
+    }
+    return PLUGIN_OK;
+}
