From 5b7c5a9996333d882376cd45ebf4d590812ccecd Mon Sep 17 00:00:00 2001
From: NIIBE Yutaka <gniibe@fsij.org>
Date: Wed, 27 Sep 2017 19:24:08 +0900
Subject: Use flash routines in example-cdc-gnu-linux.

---
 example-cdc-gnu-linux/Makefile  |  15 +-
 example-cdc-gnu-linux/README    |   6 +
 example-cdc-gnu-linux/command.c | 579 ++++++++++++++++++++++++++++++++++++++++
 example-cdc-gnu-linux/command.h |   2 +
 example-cdc-gnu-linux/config.h  |   2 +
 example-cdc-gnu-linux/sample.c  |  80 +++---
 6 files changed, 640 insertions(+), 44 deletions(-)
 create mode 100644 example-cdc-gnu-linux/command.c
 create mode 100644 example-cdc-gnu-linux/command.h
 create mode 100644 example-cdc-gnu-linux/config.h

diff --git a/example-cdc-gnu-linux/Makefile b/example-cdc-gnu-linux/Makefile
index 9fbb2fe..28896aa 100644
--- a/example-cdc-gnu-linux/Makefile
+++ b/example-cdc-gnu-linux/Makefile
@@ -6,12 +6,12 @@ PROJECT = sample
 
 CHOPSTX = ..
 LDSCRIPT=
-CSRC = sample.c usb-cdc.c
+CSRC = sample.c usb-cdc.c command.c
 
 CHIP=gnu-linux
-# USE_SYS = yes
-USE_SYS =
+USE_SYS = yes
 USE_USB = yes
+USE_ADC = yes
 EMULATION=yes
 
 ###################################
@@ -22,7 +22,7 @@ OBJCOPY   = $(CROSS)objcopy
 
 MCU   = none
 CWARN = -Wall -Wextra -Wstrict-prototypes
-DEFS  = -DGNU_LINUX_EMULATION
+DEFS  = -DGNU_LINUX_EMULATION -DUSE_SYS_BOARD_ID
 OPT   = -g # -O3 -Os
 LIBS  = -lpthread
 
@@ -34,3 +34,10 @@ board.h:
 	@exit 1
 
 distclean: clean
+
+build/flash.data: Makefile
+	@echo 'Generating 8192-byte flash.data'
+	@/bin/echo -n -e '\xff\xff\xff\xff\xff\xff\xff\xff' >$@
+	@for i in $(shell seq 1023); do /bin/echo -n -e '\xff\xff\xff\xff\xff\xff\xff\xff' >>$@; done
+
+
diff --git a/example-cdc-gnu-linux/README b/example-cdc-gnu-linux/README
index 34d21bc..d726009 100644
--- a/example-cdc-gnu-linux/README
+++ b/example-cdc-gnu-linux/README
@@ -1,3 +1,9 @@
+(0) Build and generate initial flash data
+
+$ make
+$ make build/flash.data
+
+
 (1) preparation as root 
 
 Don't run ModemManager
diff --git a/example-cdc-gnu-linux/command.c b/example-cdc-gnu-linux/command.c
new file mode 100644
index 0000000..9c14b08
--- /dev/null
+++ b/example-cdc-gnu-linux/command.c
@@ -0,0 +1,579 @@
+#include <string.h>
+#include <stdint.h>
+#include <chopstx.h>
+#include "tty.h"
+#include "config.h"
+#ifdef ADC_SUPPORT
+#include "adc.h"
+static int adc_initialized = 0;
+#endif
+#include "board.h"
+#include "sys.h"
+
+struct command_table
+{
+  const char *name;
+  void (*handler) (struct tty *tty, const char *line);
+};
+
+/*
+ * Put a line (or lines) to TTY.
+ * LINE should be terminated with newline.
+ */
+static void
+put_line (struct tty *tty, const char *line)
+{
+  tty_send (tty, line, strlen (line));
+}
+
+static const char *help_string = 
+  "mdb ADDR [COUNT];       memory display byte\r\n"
+  "mwh ADDR VALUE [COUNT]; memory write halfword\r\n"
+  "fes ADDR [COUNT];       flash erase sector\r\n"
+  "fwh ADDR VALUE [COUNT]; flash write halfword\r\n"
+#ifdef CRC32_SUPPORT
+  "crc32 string;           CRC32 calc string\r\n"
+#endif
+#ifdef ADC_SUPPORT
+  "adc;                    get 256-byte from ADC\r\n"
+#endif
+  "sysinfo;                system information\r\n"
+  "help\r\n";
+
+static char hexchar (uint8_t x)
+{
+  x &= 0x0f;
+  if (x <= 0x09)
+    return '0' + x;
+  else if (x <= 0x0f)
+    return 'a' + x - 10;
+  else
+    return '?';
+}
+
+#ifdef TOUCH_SUPPORT
+static char *
+compose_decimal (char *s, int value)
+{
+  uint32_t v;
+  int col = 1000000000;
+  int d;
+  int digit_output = 0;
+
+  if (value < 0)
+    {
+      *s++ = '-';
+      v = 1 + ~((uint32_t)value);
+    }
+  else
+    v = (uint32_t)value;
+
+  while (col >= 10)
+    {
+      if (v >= (uint32_t)col)
+	{
+	  d = v / col;
+	  v = v - d * col;
+	  *s++ = d + '0';
+	  digit_output = 1;
+	}
+      else if (digit_output)
+	*s++ = '0';
+
+      col = col / 10;
+    }
+
+  *s++ = v + '0';
+
+  return s;
+}
+#endif
+
+
+char *
+compose_hex_ptr (char *s, uintptr_t v)
+{
+  s[0] = hexchar (v >> 60);
+  s[1] = hexchar (v >> 56);
+  s[2] = hexchar (v >> 52);
+  s[3] = hexchar (v >> 48);
+  s[4] = hexchar (v >> 44);
+  s[5] = hexchar (v >> 40);
+  s[6] = hexchar (v >> 36);
+  s[7] = hexchar (v >> 32);
+  s[8] = hexchar (v >> 28);
+  s[9] = hexchar (v >> 24);
+  s[10] = hexchar (v >> 20);
+  s[11] = hexchar (v >> 16);
+  s[12] = hexchar (v >> 12);
+  s[13] = hexchar (v >> 8);
+  s[14] = hexchar (v >> 4);
+  s[15] = hexchar (v);
+  return s+16;
+}
+
+static char *
+compose_hex (char *s, uint32_t v)
+{
+  s[0] = hexchar (v >> 28);
+  s[1] = hexchar (v >> 24);
+  s[2] = hexchar (v >> 20);
+  s[3] = hexchar (v >> 16);
+  s[4] = hexchar (v >> 12);
+  s[5] = hexchar (v >> 8);
+  s[6] = hexchar (v >> 4);
+  s[7] = hexchar (v);
+  return s+8;
+}
+
+static char *
+compose_hex_byte (char *s, uint8_t v)
+{
+  s[0] = hexchar (v >> 4);
+  s[1] = hexchar (v);
+  return s+2;
+}
+
+static const char *
+get_hex (struct tty *tty, const char *s, uintptr_t *v_p)
+{
+  uintptr_t v = 0;
+  char c;
+
+  if (s[0] == '0' && s[1] == 'x')
+    s = s + 2;
+  while (1)
+    {
+      c = *s++;
+
+      if (c == 0)
+	{
+	  s--;
+	  break;
+	}
+
+      if (c == ' ')
+	break;
+
+      v = (v << 4);
+      if (c >= '0' && c <= '9')
+	v += (c - '0');
+      else if (c >= 'a' && c <= 'f')
+	v += (c - 'a') + 10;
+      else if (c >= 'A' && c <= 'F')
+	v += (c - 'A') + 10;
+      else
+	{
+	  put_line (tty, "hex error\r\n");
+	  return NULL;
+	}
+    }
+
+  *v_p = v;
+  return s;
+}
+
+
+#ifdef TOUCH_SUPPORT
+#define TOUCH_VALUE_HIGH 100
+#define TOUCH_VALUE_LOW  50
+static void
+cmd_button (struct tty *tty, const char *line)
+{
+  int i = 0;
+  extern uint16_t touch_get (void);
+  uint16_t v0 = 0;
+  int touched = 0;
+
+  (void)line;
+  put_line (tty, "Please touch the bear.\r\n");
+
+  while (i < 16)
+    {
+      uint16_t v = touch_get ();
+      v0 = (v0 * 2 + v)/3;
+
+      if (touched == 0 && v0 > TOUCH_VALUE_HIGH)
+	{
+	  tty_send (tty, "!", 1);
+	  touched = 1;
+	}
+      else if (touched == 1 && v0 < TOUCH_VALUE_LOW)
+	{
+	  tty_send (tty, ".", 1);
+	  touched = 0;
+	  i++;
+	}
+
+      chopstx_usec_wait (10*1000);
+    }
+
+  tty_send (tty, "\r\n", 2);
+}
+
+static void
+cmd_touch (struct tty *tty, const char *line)
+{
+  int i;
+  extern uint16_t touch_get (void);
+
+  (void)line;
+  put_line (tty, "Please touch the bear.\r\n");
+
+  for (i = 0; i < 20; i++)
+    {
+      uint16_t v;
+      char output[8];
+      char *s;
+
+      chopstx_usec_wait (1000*1000);
+      v = touch_get ();
+      s = compose_decimal (output, v);
+      *s++ = '\r';
+      *s++ = '\n';
+      tty_send (tty, output, s - output);
+    }
+}
+#endif
+
+
+static void
+cmd_mdb (struct tty *tty, const char *line)
+{
+  int i;
+  uintptr_t addr = 0;
+  int count = 0;
+  char c;
+  const char *s = line;
+  
+  s = get_hex (tty, s, &addr);
+  addr &= ~3;
+  if (s == NULL)
+    return;
+
+  if (*s == 0)
+    count = 1;
+  else
+    {
+      while (1)
+	{
+	  c = *s++;
+
+	  if (c == 0 || c == ' ')
+	    break;
+
+	  count = count * 10;
+	  if (c >= '0' && c <= '9')
+	    count += c - '0';
+	  else
+	    {
+	      put_line (tty, "mdb error\r\n");
+	      return;
+	    }
+	}
+    }
+
+  i = 0;
+  while (i < count)
+    {
+      uint8_t v;
+      char output[68];
+      char *s;
+
+      s = compose_hex_ptr (output, addr);
+      *s++ = ':';
+      *s++ = ' ';
+
+      while (1)
+	{
+	  v = *(uint8_t *)addr;
+	  s = compose_hex_byte (s, v);
+	  i++;
+	  addr += 1;
+	  if (i >= count || (i % 16) == 0)
+	    break;
+	  *s++ = ' ';
+	}
+
+      *s++ = '\r';
+      *s++ = '\n';
+      tty_send (tty, output, s - output);
+    }
+}
+
+static void
+cmd_mwh (struct tty *tty, const char *line)
+{
+  (void)tty;
+  (void)line;
+  put_line (tty, "mwh not yet supported\r\n");
+}
+
+static void
+cmd_fes (struct tty *tty, const char *line)
+{
+  int i;
+  uintptr_t addr = 0;
+  int count = 0;
+  char c;
+  const char *s = line;
+  
+  s = get_hex (tty, s, &addr);
+  if (s == NULL)
+    return;
+
+  if (*s == 0)
+    count = 1;
+  else
+    {
+      while (1)
+	{
+	  c = *s++;
+
+	  if (c == 0 || c == ' ')
+	    break;
+
+	  count = count * 10;
+	  if (c >= '0' && c <= '9')
+	    count += c - '0';
+	  else
+	    {
+	      put_line (tty, "fww error\r\n");
+	      return;
+	    }
+	}
+    }
+
+  for (i = 0; i < count; i++)
+    {
+      flash_erase_page (addr);
+      addr += 1024;
+    }
+}
+
+static void
+cmd_fwh (struct tty *tty, const char *line)
+{
+  int i;
+  uintptr_t addr = 0;
+  uintptr_t d;
+  uint16_t value = 0;
+  int count = 0;
+  char c;
+  const char *s = line;
+  
+  s = get_hex (tty, s, &addr);
+  if (s == NULL)
+    return;
+
+  if (*s == 0)
+    return;
+
+  s = get_hex (tty, s, &d);
+  value = (uint16_t)d;
+  if (s == NULL)
+    return;
+
+  if (*s == 0)
+    count = 1;
+  else
+    {
+      while (1)
+	{
+	  c = *s++;
+
+	  if (c == 0 || c == ' ')
+	    break;
+
+	  count = count * 10;
+	  if (c >= '0' && c <= '9')
+	    count += c - '0';
+	  else
+	    {
+	      put_line (tty, "fww error\r\n");
+	      return;
+	    }
+	}
+    }
+
+  for (i = 0; i < count; i++)
+    {
+      flash_program_halfword (addr, value);
+      addr += 4;
+    }
+}
+
+
+#ifdef CRC32_SUPPORT
+static unsigned int crc_value;
+
+static void
+cmd_crc32  (struct tty *tty, const char *line)
+{
+  uint32_t v;
+  char string[10];
+  char *s;
+
+  crc32_init (&crc_value);
+  while (*line)
+    crc32_u8 (&crc_value, *line++);
+  v = crc_value ^ 0xffffffff;
+
+  s = compose_hex (string, v);
+  *s++ = '\r';
+  *s++ = '\n';
+  tty_send (tty, string, sizeof (string));
+}
+#endif
+
+#ifdef ADC_SUPPORT
+static void
+cmd_adc  (struct tty *tty, const char *line)
+{
+  int i;
+  char output[73];
+  char *s;
+
+  (void)line;
+
+  if (!adc_initialized)
+    {
+      if (adc_init ())
+	{
+	  put_line (tty, "adc_init error\r\n");
+	  return;
+	}
+      else
+	{
+	  adc_start ();
+	  adc_initialized = 1;
+	}
+    }
+
+  adc_start_conversion (0, 64);
+  adc_wait_completion ();
+
+  i = 0;
+  s = output;
+  while (1)
+    {
+      s = compose_hex (s, adc_buf[i]);
+      i++;
+      if ((i % 8))
+	*s++ = ' ';
+      else
+	{
+	  *s++ = '\r';
+	  *s++ = '\n';
+	  tty_send (tty, output, s - output);
+	  s = output;
+	  if (i >= 64)
+	    break;
+	}
+    }
+}
+#endif
+
+static void
+cmd_sysinfo (struct tty *tty, const char *line)
+{
+  char output[73];
+  char *s;
+  int i;
+
+  (void)line;
+  memcpy (output, "SYS version: ", 13);
+  s = output + 13; 
+  *s++ = sys_version[2];
+  *s++ = sys_version[4];
+  *s++ = sys_version[6];
+  *s++ = '\r';
+  *s++ = '\n';
+  tty_send (tty, output, s - output);
+
+  memcpy (output, "Board ID: ", 10);
+  s = output + 10; 
+  s = compose_hex (s, sys_board_id);
+  *s++ = '\r';
+  *s++ = '\n';
+  tty_send (tty, output, s - output);
+
+  memcpy (output, "Board name: ", 12);
+  s = output + 12; 
+  for (i = 0; i < (int)sizeof (output) - 2; i ++)
+    if ((*s = sys_board_name[i]) == 0)
+      break;
+    else
+      s++;
+
+  *s++ = '\r';
+  *s++ = '\n';
+  tty_send (tty, output, s - output);
+}
+
+
+static void
+cmd_help (struct tty *tty, const char *line)
+{
+  (void)line;
+  put_line (tty, help_string);
+}
+
+
+struct command_table command_table[] = {
+#ifdef TOUCH_SUPPORT
+  { "button", cmd_button },
+  { "touch", cmd_touch },
+#endif
+  { "mdb", cmd_mdb },
+  { "mwh", cmd_mwh },
+  { "fes", cmd_fes },
+  { "fwh", cmd_fwh },
+#ifdef CRC32_SUPPORT
+  { "crc32", cmd_crc32 },
+#endif
+#ifdef ADC_SUPPORT
+  { "adc", cmd_adc },
+#endif
+  { "sysinfo", cmd_sysinfo },
+  { "help", cmd_help },
+};
+
+#define N_CMDS (int)(sizeof (command_table) / sizeof (struct command_table))
+
+
+/*
+ * Dispatch a command parsing LINE.
+ * Line is NULL terminated with no newline.
+ */
+void
+cmd_dispatch (struct tty *tty, const char *line)
+{
+  int i;
+  const char *p;
+  unsigned int n = 0;
+
+  p = line;
+  while (*p)
+    {
+      if (*p++ == ' ')
+	break;
+      n++;
+    }
+
+  for (i = 0; i < N_CMDS; i++)
+    if (n == strlen (command_table[i].name)
+	&& strncmp ((const char *)line, command_table[i].name, n) == 0)
+      break;
+
+  if (i != N_CMDS)
+    (*command_table[i].handler) (tty, p);
+  else
+    {
+      char crlf[] = { '\r', '\n' };
+
+      put_line (tty, "No such command: ");
+      tty_send (tty, line, n);
+      tty_send (tty, crlf, sizeof (crlf));
+    }
+}
diff --git a/example-cdc-gnu-linux/command.h b/example-cdc-gnu-linux/command.h
new file mode 100644
index 0000000..f4309b8
--- /dev/null
+++ b/example-cdc-gnu-linux/command.h
@@ -0,0 +1,2 @@
+void cmd_dispatch (struct tty *tty, const char *line);
+char * compose_hex_ptr (char *s, uintptr_t v);
diff --git a/example-cdc-gnu-linux/config.h b/example-cdc-gnu-linux/config.h
new file mode 100644
index 0000000..3305d04
--- /dev/null
+++ b/example-cdc-gnu-linux/config.h
@@ -0,0 +1,2 @@
+#undef CRC32_SUPPORT
+#define ADC_SUPPORT
diff --git a/example-cdc-gnu-linux/sample.c b/example-cdc-gnu-linux/sample.c
index fd80f78..e343f7d 100644
--- a/example-cdc-gnu-linux/sample.c
+++ b/example-cdc-gnu-linux/sample.c
@@ -5,33 +5,15 @@
 
 #include <chopstx.h>
 
+#include "sys.h"
+
 #include "usb_lld.h"
 #include "tty.h"
+#include "command.h"
 
 #include <unistd.h>
 #include <stdio.h>
 
-static void
-set_led (int on)
-{
-#if 0
-  /* For debugging, no output of LED.  */
-#if 1
-  if (on)
-    write (1, "********\x08\x08\x08\x08\x08\x08\x08\x08", 16);
-  else
-    write (1, "        \x08\x08\x08\x08\x08\x08\x08\x08", 16);
-#else
-  if (on)
-    puts ("!");
-  else
-    puts ("");
-#endif
-#else
-  (void)on;
-#endif
-}
-
 static chopstx_mutex_t mtx;
 static chopstx_cond_t cnd0;
 static chopstx_cond_t cnd1;
@@ -114,6 +96,7 @@ main (int argc, const char *argv[])
 {
   struct tty *tty;
   uint8_t count;
+  uintptr_t addr;
 
   (void)argc;
   (void)argv;
@@ -134,6 +117,9 @@ main (int argc, const char *argv[])
   chopstx_cond_signal (&cnd1);
   chopstx_mutex_unlock (&mtx);
 
+  addr = flash_init ("flash.data");
+  flash_unlock ();
+
   u = 1;
 
   tty = tty_open ();
@@ -145,6 +131,7 @@ main (int argc, const char *argv[])
     {
       char s[LINEBUFSIZE];
 
+    connection_loop:
       u = 1;
       tty_wait_connection (tty);
 
@@ -157,39 +144,52 @@ main (int argc, const char *argv[])
       memcpy (s, "xx: Hello, World with Chopstx!\r\n", 32);
       s[0] = hexchar (count >> 4);
       s[1] = hexchar (count & 0x0f);
-      count++;
 
       puts("send hello");
       if (tty_send (tty, s, 32) < 0)
 	continue;
 
+      s[0] = hexchar (count >> 4);
+      s[1] = hexchar (count & 0x0f);
+      s[2] = ':';
+      s[3] = ' ';
+      compose_hex_ptr (s+4, addr);
+      s[20] = '\r';
+      s[21] = '\n';
+
+      count++;
+
+      if (tty_send (tty, s, 22) < 0)
+	continue;
+
       while (1)
 	{
-	  int size;
 	  uint32_t usec;
 
-	  puts("recv msg");
-	  usec = 3000000;	/* 3.0 seconds */
-	  size = tty_recv (tty, s + 4, &usec);
-	  if (size < 0)
+	  /* Prompt */
+	  if (tty_send (tty, "> ", 2) < 0)
 	    break;
 
-	  if (size)
+	  usec = 3000000;	/* 3.0 seconds */
+	  while (1)
 	    {
-	      size--;
-
-	      puts("send msg");
-	      s[0] = hexchar (size >> 4);
-	      s[1] = hexchar (size & 0x0f);
-	      s[2] = ':';
-	      s[3] = ' ';
-	      s[size + 4] = '\r';
-	      s[size + 5] = '\n';
-	      if (tty_send (tty, s, size + 6) < 0)
+	      int size = tty_recv (tty, s, &usec);
+	      u ^= 1;
+
+	      if (size < 0)
+		goto connection_loop;
+
+	      if (size == 1)
+		/* Do nothing but prompt again.  */
 		break;
+	      else if (size)
+		{
+		  /* Newline into NUL */
+		  s[size - 1] = 0;
+		  cmd_dispatch (tty, (char *)s);
+		  break;
+		}
 	    }
-
-	  u ^= 1;
 	}
     }
 
-- 
cgit v1.2.3