/*
    File Name : main.c
    Created   : 2025/10/15
    Author    : K.Uchibori
    Compiler  : X32 (v4.30)
*/

// *****************************************************************************
// *****************************************************************************
// Section: Included Files
// *****************************************************************************
// *****************************************************************************

#include <stddef.h>                     // Defines NULL
#include <stdbool.h>                    // Defines true
#include <stdlib.h>                     // Defines EXIT_FAILURE
#include "pickle.h"

#define SDCARD_MOUNT_NAME    "/mnt/mydrive"
#define SDCARD_DEV_NAME      "/dev/mmcblka1"

// delay
#define CCLK			(50000000L)		// system clock
#define PBCLK		(CCLK / 2)		// peripheral bus clock

const char VERSION[] = "5.01";
char buf[270];
BYTE p_f;

/*
 * pickle session
 */
struct pickle p = {0};

void PIC_RESET(void) {
SYSKEY = 0x00000000; //write invalid key to force lock
SYSKEY = 0xAA996655; //write key1 to SYSKEY
SYSKEY = 0x556699AA; //write key2 to SYSKEY
RSWRSTbits.SWRST = 1;
volatile unsigned char dummy;
dummy = RSWRST;

while (1);
}

void software_reset() {
  //PIC_RESET();
  gpio_bb_set_vpp(VPPLOW);
  gpio_bb_set_pgc(LOW);
  gpio_bb_set_pgd(LOW);
  gpio_bb_set_run(LOW);
  return;
}

/*
 * p12 help
 */
void
usage_p12(char *msg)
{
  if (msg) {
    sprintf(buf, "Error: %s.\n\n", msg);
    myprintf(buf);
  }

  sprintf(buf,
    " p12 SELECT DEVICE OPERATION [ARG]\n");
  myprintf(buf);
  sprintf(buf,
    "\t\t12-bit word PIC10F/12F/16F operations.\n");
  myprintf(buf);
  sprintf(buf,
    "\n");
  myprintf(buf);

  sprintf(buf, "EXAMPLES:\n");
  myprintf(buf);
  sprintf(buf, " p12 select\n"
    "\t\tShow supported devices.\n");
  myprintf(buf);
  sprintf(buf, " p12 select PIC1XFXXX blank\n"
    "\t\tBlank device (disable protection and bulk erase).\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " p12 select PIC1XFXXX config\n"
    "\t\tDisplay device configuration.\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " p12 select PIC1XFXXX data\n"
    "\t\tDisplay data flash content.\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " p12 select PIC1XFXXX dump\n"
    "\t\tDump device content (INHX32 format).\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " p12 select PIC1XFXXX flash [n] [address]\n"
    "\t\tDisplay all or n words of program flash content from address.\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " p12 select PIC1XFXXX id\n"
    "\t\tDisplay device identification.\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " p12 select PIC1XFXXX osccal\n"
    "\t\tDisplay oscillator calibration.\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " p12 select PIC1XFXXX osccal 0x0c1a\n"
    "\t\tRestore oscillator calibration as 0x0c1a.\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " p12 select PIC1XFXXX program [file.hex] [noblank]\n"
    "\t\tBlank and program file.hex or stdin to flash (INHX32 format).\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " p12 select PIC1XFXXX verify [file.hex]\n"
    "\t\tVerify file.hex or stdin in flash (INHX32 format).\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " p12 select PIC1XFXXX view [file.hex] [raw]\n"
    "\t\tView file.hex or stdin (INHX32 format).\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, "\n");
  myprintf(buf);

  sprintf(buf, "VERSION:\n %s\n", VERSION);
  myprintf(buf);
  rxEND();
}

/*
 * p14 help
 */
void
usage_p14(char *msg)
{
  if (msg) {
    sprintf(buf, "Error: %s.\n\n", msg);
    myprintf(buf);
  }

  sprintf(buf,
    " p14 [SELECT DEVICE] [LVP] OPERATION [ARG]\n");
  myprintf(buf);
  sprintf(buf,
    "\t\t14-bit word PIC10F/12F/16F operations.\n");
  myprintf(buf);
  sprintf(buf,
    "\n");
  myprintf(buf);

  sprintf(buf, "EXAMPLES:\n");
  myprintf(buf);
  sprintf(buf, " p14 select\n"
    "\t\tShow supported devices.\n");
  myprintf(buf);
  sprintf(buf, " p14 select 16F84 OPERATION [ARG]\n"
    "\t\tSelect device PIC16F84.\n");
  myprintf(buf);
  sprintf(buf, " p14 lvp OPERATION [ARG]\n"
    "\t\tLVP 32-bit key entry.\n");
  myprintf(buf);
  sprintf(buf, " p14 blank\n"
    "\t\tBlank device (disable protection and bulk erase).\n");
  myprintf(buf);
  sprintf(buf, " p14 config 0x3000\n"
    "\t\tRestore band-gap configuration as 0x3000.\n");
  myprintf(buf);
  sprintf(buf, " p14 data\n"
    "\t\tDisplay data EEPROM content.\n");
  myprintf(buf);
  sprintf(buf, " p14 dump\n"
    "\t\tDump device content (INHX32 format).\n");
  myprintf(buf);
  sprintf(buf, " p14 erase eeprom | flash | id | row [n]\n"
    "\t\tErase EEPROM, flash, id or flash at row for n rows.\n");
  myprintf(buf);
  sprintf(buf, " p14 id\n"
    "\t\tDisplay device identification.\n");
  myprintf(buf);
  sprintf(buf, " p14 osccal\n"
    "\t\tDisplay oscillator calibration.\n");
  myprintf(buf);
  sprintf(buf, " p14 osccal 0x343c\n"
    "\t\tRestore oscillator calibration as 0x343c.\n");
  myprintf(buf);
  sprintf(buf, " p14 program [file.hex] [noblank]\n"
    "\t\tBlank and program file.hex or stdin to flash (INHX32 format).\n");
  myprintf(buf);
  sprintf(buf, " p14 verify [file.hex]\n"
    "\t\tVerify file.hex or stdin in flash (INHX32 format).\n");
  myprintf(buf);
  sprintf(buf, " p14 view [file.hex] [raw]\n"
    "\t\tView file.hex or stdin (INHX32 format).\n");
  myprintf(buf);
  sprintf(buf, "\n");
  myprintf(buf);

  sprintf(buf, "VERSION:\n %s\n", VERSION);
  myprintf(buf);
  rxEND();
}

/*
 * n14 help
 */
void
usage_n14(char *msg)
{
  if (msg) {
    sprintf(buf, "Error: %s.\n\n", msg);
    myprintf(buf);
  }

  sprintf(buf,
    " n14 [LVP] OPERATION [ARG]\n");
  myprintf(buf);
  sprintf(buf,
    "\t\t14-bit word PIC16F operations.\n");
  myprintf(buf);
  sprintf(buf,
    "\n");
  myprintf(buf);

  sprintf(buf, "EXAMPLES:\n");
  myprintf(buf);
  sprintf(buf, " n14 select\n"
    "\t\tShow supported devices.\n");
  myprintf(buf);
  sprintf(buf, " n14 lvp OPERATION [ARG]\n"
    "\t\tLVP 32-bit key entry.\n");
  myprintf(buf);
  sprintf(buf, " n14 blank\n"
    "\t\tBlank device (disable protection and bulk erase).\n");
  myprintf(buf);
  sprintf(buf, " n14 config\n"
    "\t\tDisplay device configuration.\n");
  myprintf(buf);
  sprintf(buf, " n14 data\n"
    "\t\tDisplay data EEPROM content.\n");
  myprintf(buf);
  sprintf(buf, " n14 dump\n"
    "\t\tDump device content (INHX32 format).\n");
  myprintf(buf);
  sprintf(buf, " n14 erase eeprom | flash | id | row [n]\n"
    "\t\tErase EEPROM, flash, id or flash at row for n rows.\n");
  myprintf(buf);
  sprintf(buf, " n14 flash [n] [address]\n"
    "\t\tDisplay all or n words of program flash content from address.\n");
  myprintf(buf);
  sprintf(buf, " n14 id\n"
    "\t\tDisplay device identification.\n");
  myprintf(buf);
  sprintf(buf, " n14 program [file.hex] [noblank]\n"
    "\t\tBlank and program file.hex or stdin to flash (INHX32 format).\n");
  myprintf(buf);
  sprintf(buf, " n14 verify [file.hex]\n"
    "\t\tVerify file.hex or stdin in flash (INHX32 format).\n");
  myprintf(buf);
  sprintf(buf, " n14 view [file.hex] [raw]\n"
    "\t\tView file.hex or stdin (INHX32 format).\n");
  myprintf(buf);
  sprintf(buf, "\n");
  myprintf(buf);

  sprintf(buf, "VERSION:\n %s\n", VERSION);
  myprintf(buf);
  rxEND();
}

/*
 * p16 help
 */
void
usage_p16(char *msg)
{
  if (msg) {
    sprintf(buf, "Error: %s.\n\n", msg);
    myprintf(buf);
  }

  sprintf(buf,
    " p16 [SELECT DEVICE] [LVP|HVP] OPERATION [ARG]\n");
  myprintf(buf);
  sprintf(buf,
    "\t\t16-bit word PIC18F operations.\n");
  myprintf(buf);
  sprintf(buf,
    "\n");
  myprintf(buf);

  sprintf(buf, "EXAMPLES:\n");
  myprintf(buf);
  sprintf(buf, " p16 select\n"
    "\t\tShow supported devices.\n");
  myprintf(buf);
  sprintf(buf, " p16 select 18LF2539 OPERATION [ARG]\n"
    "\t\tSelect device PIC18LF2539.\n");
  myprintf(buf);
  sprintf(buf, " p16 lvp OPERATION [ARG]\n"
    "\t\tLVP 32-bit key entry.\n");
  myprintf(buf);
  sprintf(buf, " p16 hvp OPERATION [ARG]\n"
    "\t\tHVP 32-bit key entry.\n");
  myprintf(buf);
  sprintf(buf, " p16 blank\n"
    "\t\tBlank device (disable protection and bulk erase).\n");
  myprintf(buf);
  sprintf(buf, " p16 config\n"
    "\t\tDisplay device configuration.\n");
  myprintf(buf);
  sprintf(buf, " p16 data\n"
    "\t\tDisplay data EEPROM content.\n");
  myprintf(buf);
  sprintf(buf, " p16 dump\n"
    "\t\tDump device content (INHX32 format).\n");
  myprintf(buf);
  sprintf(buf, " p16 erase eeprom | flash | id | row [n]\n"
    "\t\tErase EEPROM, flash, id or flash at row for n rows.\n");
  myprintf(buf);
  sprintf(buf, " p16 flash [n] [address]\n"
    "\t\tDisplay all or n words of program flash content from address.\n");
  myprintf(buf);
  sprintf(buf, " p16 id\n"
    "\t\tDisplay device identification.\n");
  myprintf(buf);
  sprintf(buf, " p16 program [file.hex] [noblank]\n"
    "\t\tBlank and program file.hex or stdin to flash (INHX32 format).\n");
  myprintf(buf);
  sprintf(buf, " p16 verify [file.hex]\n"
    "\t\tVerify file.hex or stdin in flash (INHX32 format).\n");
  myprintf(buf);
  sprintf(buf, " p16 view [file.hex] [raw]\n"
    "\t\tView file.hex or stdin (INHX32 format).\n");
  myprintf(buf);
  sprintf(buf, "\n");
  myprintf(buf);
  
  sprintf(buf, "VERSION:\n %s\n", VERSION);
  myprintf(buf);
  rxEND();
}

/*
 * n16 help
 */
void
usage_n16(char *msg)
{
  if (msg) {
    sprintf(buf, "Error: %s.\n\n", msg);
    myprintf(buf);
  }

  sprintf(buf,
    " n16 [LVP] OPERATION [ARG]\n");
  myprintf(buf);
  sprintf(buf,
    "\t\t16-bit word PIC18F operations.\n");
  myprintf(buf);
  sprintf(buf,
    "\n");
  myprintf(buf);

  sprintf(buf, "EXAMPLES:\n");
  myprintf(buf);
  sprintf(buf, " n16 select\n"
    "\t\tShow supported devices.\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " n16 lvp OPERATION [ARG]\n"
    "\t\tLVP 32-bit key entry.\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " n16 blank\n"
    "\t\tBlank device (disable protection and bulk erase).\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " n16 config\n"
    "\t\tDisplay device configuration.\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " n16 data\n"
    "\t\tDisplay data EEPROM content.\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " n16 dump\n"
    "\t\tDump device content (INHX32 format).\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " n16 erase eeprom | flash | id | row [n]\n"
    "\t\tErase EEPROM, flash, id or flash at row for n rows.\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " n16 flash [n] [address]\n"
    "\t\tDisplay all or n words of program flash content from address.\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " n16 id\n"
    "\t\tDisplay device identification.\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " n16 program [file.hex] [noblank]\n"
    "\t\tBlank and program file.hex or stdin to flash (INHX32 format).\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " n16 verify [file.hex]\n"
    "\t\tVerify file.hex or stdin in flash (INHX32 format).\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, " n16 view [file.hex] [raw]\n"
    "\t\tView file.hex or stdin (INHX32 format).\n", UL_ON, UL_OFF);
  myprintf(buf);
  sprintf(buf, "\n");
  myprintf(buf);

  sprintf(buf, "VERSION:\n %s\n", VERSION);
  myprintf(buf);
  rxEND();
}

/*
 * p24 help
 */
void
usage_p24(char *msg)
{
  if (msg) {
    sprintf(buf, "Error: %s.\n\n", msg);
    myprintf(buf);
  }

  sprintf(buf,
    " p24 [SELECT|PARTITION DEVICE] [LVP|HVP] OPERATION [ARG]\n");
  myprintf(buf);
  sprintf(buf,
    "\t\t24-bit word PIC24/dsPIC operations.\n");
  myprintf(buf);
  sprintf(buf,
    "\n");
  myprintf(buf);

	sprintf(buf, "EXAMPLES:\n");
	myprintf(buf);
	sprintf(buf, " p24 select\n"
		"\t\tShow supported devices.\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p24 select 33EP128GP502 OPERATION [ARG]\n"
		"\t\tSelect device dsPIC33EP128GP502.\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p24 select 24FJ128GB202 OPERATION [ARG]\n"
		"\t\tSelect device PIC24FJ128GB202.\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p24 partition 33EP64GS502 OPERATION [ARG]\n"
		"\t\tSelect and partition device dsPIC33EP64GS502.\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p24 lvp OPERATION [ARG]\n"
		"\t\tLVP 32-bit key entry.\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p24 hvp OPERATION [ARG]\n"
		"\t\tHVP 32-bit key entry.\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p24 blank\n"
		"\t\tBlank device (disable protection and bulk erase).\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p24 config\n"
		"\t\tDisplay device configuration.\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p24 data\n"
		"\t\tDisplay data EEPROM content.\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p24 dump\n"
		"\t\tDump device content (INHX32 format).\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p24 exec [n] [address]\n"
		"\t\tDisplay all or n words of executive flash content from address.\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p24 flash [n] [address]\n"
		"\t\tDisplay all or n words of program flash content from address.\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p24 id\n"
		"\t\tDisplay device identification.\n", UL_ON, UL_OFF);
    myprintf(buf);
    sprintf(buf, " p24 program [file.hex] [noblank]\n"
		"\t\tBlank and program file.hex or stdin to flash (INHX32 format).\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p24 verify [file.hex]\n"
		"\t\tVerify file.hex or stdin in flash (INHX32 format).\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p24 view [file.hex] [raw]\n"
		"\t\tView file.hex or stdin (INHX32 format).\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, "\n");
	myprintf(buf);
	
	sprintf(buf, "VERSION:\n %s\n", VERSION);
	myprintf(buf);
    rxEND();
}

/*
 * p32 help
 */
void
usage_p32(char *msg)
{
  if (msg) {
    sprintf(buf, "Error: %s.\n\n", msg);
    myprintf(buf);
  }

  sprintf(buf,
    " p32 OPERATION [ARG]\n");
  myprintf(buf);
  sprintf(buf,
    "\t\t32-bit word PIC32 operations.\n");
  myprintf(buf);
  sprintf(buf,
    "\n");
  myprintf(buf);

	sprintf(buf, "EXAMPLES:\n");
	myprintf(buf);
	sprintf(buf, " p32 select\n"
		"\t\tShow supported devices.\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p32 boot [n] [address]\n"
		"\t\tDisplay all or n words of boot flash content from address.\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p32 blank\n"
		"\t\tBlank device (erase).\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p32 config\n"
		"\t\tDisplay device configuration.\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p32 dump\n"
		"\t\tDump device content (INHX32 format).\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p32 flash [n] [address]\n"
		"\t\tDisplay all or n words of program flash content from address.\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p32 program [file.hex] [noblank]\n"
		"\t\tBlank and program file.hex or stdin to flash (INHX32 format).\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p32 verify [file.hex]\n"
		"\t\tVerify file.hex or stdin in flash (INHX32 format).\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, " p32 view [file.hex] [raw]\n"
		"\t\tView file.hex or stdin (INHX32 format).\n", UL_ON, UL_OFF);
	myprintf(buf);
	sprintf(buf, "\n");
	myprintf(buf);
	
	sprintf(buf, "VERSION:\n %s\n", VERSION);
	myprintf(buf);
    rxEND();
}

/*
 * p12/p14/p16/p24/p32 help
 */
void
usage(char *execname, char *msg)
{
  //if (strcmp("p12", execname) == 0)
  //  usage_p12(msg);
  //if (strcmp("p14", execname) == 0)
  //  usage_p14(msg);
  //if (strcmp("n14", execname) == 0)
  //  usage_n14(msg);
  //if (strcmp("p16", execname) == 0)
  //  usage_p16(msg);
  //if (strcmp("n16", execname) == 0)
  //  usage_n16(msg);
  //if (strcmp("p24", execname) == 0)
  //  usage_p24(msg);
  if (strcmp("p32", execname) == 0)
    usage_p32(msg);
  rxEND();
}

/*
 * full help
 */
void
usage_full()
{
	sprintf(buf, " p32 help   : help\n");
	myprintf(buf);
	sprintf(buf, " p32 select : Show supported devices.\n");
	myprintf(buf);
	sprintf(buf, "\n");
	myprintf(buf);
	
	sprintf(buf, "VERSION:\n %s\n", VERSION);
	myprintf(buf);
    rxEND();
}

/*
 * useless
 */
void
usage_useless()
{
	sprintf(buf, "p12 x useless\n");
	myprintf(buf);
	sprintf(buf, "p14 x useless\n");
	myprintf(buf);
	sprintf(buf, "n14 x useless\n");
	myprintf(buf);
	sprintf(buf, "p16 x useless\n");
	myprintf(buf);
	sprintf(buf, "n16 x useless\n");
	myprintf(buf);
	sprintf(buf, "p24 x useless\n");
	myprintf(buf);
	sprintf(buf, "p32 o useful\n");
	myprintf(buf);
    rxEND();
}

void SdFileList() {
    SYS_FS_HANDLE dirHandle;
    SYS_FS_FSTAT stat;
    int i;
    char str_null[] = "-";
    char *ext;
    int max_fn = 0;
    char str_n[10];

    dirHandle = SYS_FS_DirOpen("/mnt/mydrive/");
    if (dirHandle != SYS_FS_HANDLE_INVALID) {
	    for(;;) {
            for(i=0;i<10;i++){SYS_Tasks();CORETIMER_DelayMs(1);};
            if (SYS_FS_DirRead(dirHandle, &stat) == SYS_FS_RES_FAILURE) break;
		    if (stat.fname[0]=='\0') break;
            ext = strstr(stat.fname, ".");
            if (ext == NULL) ext = str_null;
            if ((stat.fattrib != SYS_FS_ATTR_DIR) && (strcmp(ext,".hex")==0) && !(strcmp(stat.fname,"temp.hex")==0)) {
                if (max_fn < strlen(stat.fname)) max_fn = strlen(stat.fname);
            }
	    }
    }
    SYS_FS_DirClose(dirHandle);

    buf[0]='\0';
    for(i = 0; i < max_fn + 12; i++){
        strcat(buf,"-");
    }
    strcat(buf,"\n");
    myprintf(buf);    

    dirHandle = SYS_FS_DirOpen("/mnt/mydrive/");
    if (dirHandle != SYS_FS_HANDLE_INVALID) {
	    for(;;) {
            for(i=0;i<10;i++){SYS_Tasks();CORETIMER_DelayMs(1);};
            if (SYS_FS_DirRead(dirHandle, &stat) == SYS_FS_RES_FAILURE) break;
		    if (stat.fname[0]=='\0') break;
            ext = strstr(stat.fname, ".");
            if (ext == NULL) ext = str_null;
            if ((stat.fattrib != SYS_FS_ATTR_DIR) && (strcmp(ext,".hex")==0) && !(strcmp(stat.fname,"temp.hex")==0)) {
                sprintf(buf, "  %s", stat.fname);
                for(i = 0; i < max_fn - strlen(stat.fname); i++){
                    strcat(buf," ");
                }
                sprintf(str_n, "%10u\n", stat.fsize);
                strcat(buf,str_n);
                myprintf(buf);
            }
	    }
    }
    SYS_FS_DirClose(dirHandle);
    
    buf[0]='\0';
    for(i = 0; i < max_fn + 12; i++){
        strcat(buf,"-");
    }
    strcat(buf,"\n");
    myprintf(buf);
}

void
serial_read() {
    int i = 0;
    uint8_t *rdBuf;
    uint32_t rdCnt;
    SYS_FS_HANDLE fileHandle;
    uint8_t *wrBuf;

    fileHandle = SYS_FS_FileOpen("/mnt/mydrive/temp.hex", (SYS_FS_FILE_OPEN_WRITE));
 
    rdCnt=0;
    while(1){
      myprintf("~");
      USBCDC_finishGetData();
      while(1){
        if (rdCnt!=0) USBCDC_finishGetData();
        USBCDC_getData(&rdBuf, &rdCnt);
        if (rdCnt!=0) {
            for(i=0;i<rdCnt;i++){
                if ( *(rdBuf+i) == 126) break; //'~'
                SYS_FS_FilePrintf(fileHandle, "%c", *(rdBuf+i));
                if ( *(rdBuf+i) == 10 ) break;
            }
            if ( *(rdBuf+i) == 126) break; //'~'
            if ( *(rdBuf+i) == 10 ) break;
        }
      }
      if ( *rdBuf == 126) break; //'~'
    }
	SYS_FS_FileClose(fileHandle);
}

int
SD_read(SYS_FS_HANDLE fp,char* r) {
    int count = 0;  // 文字数のカウンタ
    uint8_t *rdBuf;
    uint32_t rdCnt;
    size_t res;
    char buf[1];
    
    if(fp != SYS_FS_HANDLE_INVALID){
        //---1byteずつ読み込んだ文字を結合
        r[0] = 0;
        while (1) {
            res = SYS_FS_FileRead(fp, buf,1);
            if(res == 0) break;
            r[count]=buf[0];
            if(count > STRLEN-2 || buf[0] == 0x0a){
                r[count++]=0;
                break;
            }
            count++;
        }
    } else {
        myprintf("~");
        USBCDC_finishGetData();
        while(1){
            if (rdCnt!=0) USBCDC_finishGetData();
            USBCDC_getData(&rdBuf, &rdCnt);
            if (rdCnt!=0) {
                for(count=0;count<rdCnt;count++){
                    if ( *(rdBuf+count) == 126) break; //'~'
                    r[count]=*(rdBuf+count);
                    if ( *(rdBuf+count) == 0x0a ) break;
                }
                if ( *(rdBuf+count) == 126){ //'~'
                    r[count]=0;
                    break; 
                }
                if ( *(rdBuf+count) == 0x0a ){
                    r[count]=0;
                    break;
                }
            }
            CORETIMER_DelayMs(1);
        }
    }
    return count;
}

void myprintf(char *buf)
{
    uint8_t *wrBuf;
    uint16_t wrBufSize;
    
    CORETIMER_DelayMs(1);
    if(USBCDC_getPutBuf(&wrBuf, &wrBufSize)){
        memcpy((void*)wrBuf, (void*)buf, strlen(buf));
        USBCDC_putData(wrBuf, strlen(buf));
    }
}

void rxSTART()
{
    LED_On();
    gpio_bb_set_vpp(VPPLOW);
}

void rxEND()
{
    serialWriteOneWord(0x0D0D);
    sprintf(buf, "\n");
    myprintf(buf);
}

// *****************************************************************************
// *****************************************************************************
// Section: Main Entry Point
// *****************************************************************************
// *****************************************************************************

int main ( void )
{
    uint8_t *rdBuf;
    uint32_t rdCnt;
    uint8_t dat[200];
    unsigned int command;
    unsigned int data1;
    int  argc = 0;
    char *argv[10];
    int count;      // 文字数のカウンタ
    int rc;
    int i;
    int flag_arch;
    pic_data data;
    SYS_FS_HANDLE fp;
    /* Initialize all modules */
    SYS_Initialize ( NULL );
    SYS_Tasks ( );
    /* Config defaults */
    io_config();
    /* Determine back-end */
    io_backend();

    gpio_bb_set_vpp(VPPLOW);
    gpio_bb_set_pgc(LOW);
    gpio_bb_set_pgd(LOW);
    gpio_bb_set_run(LOW);
    
    while(SYS_FS_Mount(SDCARD_DEV_NAME, SDCARD_MOUNT_NAME, FAT, 0, NULL) != 0){LED_On();for(i=1;i<= 250;i++){SYS_Tasks();CORETIMER_DelayMs(1);};LED_Off();for(i=1;i<= 250;i++){SYS_Tasks();CORETIMER_DelayMs(1);};};
    LED_Off();
    SYS_FS_CurrentDriveSet(SDCARD_MOUNT_NAME);
    USBCDC_finishGetData();
    for(;;){
        inhx32_get(fp, &data, 1);
        pic_write_panel(0, 0, 0, 1);
        pic_dumpaddr(0, 0, 1);
		argc = 0;

        /* Maintain state machines of all polled MPLAB Harmony modules. */
        SYS_Tasks ( );
       
        if (rdCnt!=0) USBCDC_finishGetData();
        USBCDC_getData(&rdBuf, &rdCnt);
        // ===============シリアル通信===============
        if (rdCnt!=0) {
            count = 0;    
            while( count < rdCnt ) {
                dat[count]=*(rdBuf+count);
                count++;      // 文字数インクリメント
            }
            dat[count]=0;
            strncpy(p.devicename, "", sizeof(p.devicename));
            if (dat[0]==0x80 || dat[0]==0x81 || dat[0]==0x82 || dat[0]==0x83 || dat[0]==0x84 || dat[0]==0x85 || dat[0]==0x86) {
                /* Determine arch: 12 | 14 | 16 | 24 | 32 */
                if (dat[0]==0x80) continue;
                if (dat[0]==0x81) continue;
                if (dat[0]==0x82) continue;
                if (dat[0]==0x83) continue;
                if (dat[0]==0x84) continue;
                if (dat[0]==0x85) continue;
                if (dat[0]==0x86) pic_arch("p32");
                /* No key entry */
                /* ARCH12BIT || ARCH14BIT || ARCH16BIT || ARCH24BIT */
                if (dat[0]==0x85) p.key = LVPKEY; else p.key = NOKEY;
                dat[0]=0x80;
                
                command=(((unsigned int)dat[0])<<8)|((unsigned int)dat[1]);
                
                rxSTART();
                switch(command) {
                    case COMMAND_ERASE:
                        pic_erase(0, UINT32_MAX);
                        break;
                    case COMMAND_BLANK:
                        data1=serialReadOneWordBlock();
                        pic_blank(data1);
                        break;
                    case COMMAND_WRITE_PROGRAM:
                        data1=serialReadOneWordBlock();
                        serial_read();
                        //pic_program("temp.hex", data1);
                        break;
                    case COMMAND_VIEW_FILE:
                        data1=serialReadOneWordBlock();
                        serial_read();
                        //pic_view("temp.hex", data1);
                        break;
                    case COMMAND_VERIFY_PROGRAM:
                        serial_read();
                        //pic_verify("temp.hex");
                        break;
                    case COMMAND_READ_PROGRAM:
                        pic_dumpdevice();
                        break;
                    case COMMAND_READ_ID_AND_CONFIG:
                        pic_dumpdeviceid();
                        break;
                    case COMMAND_READ_CONFIG:
                        pic_dumpconfig();
                        break;
                }
                LED_Off();
                USBCDC_finishGetData();
                continue;
            }

            if (strlen(dat) > 0) {                  // 文字数が1バイト以上の場合
                char *pntr = strchr(dat, '\n');  
                if(pntr != NULL) {  
                    *pntr = '\0';  
                }
                argv[argc]=strtok(dat," ");
                do
                {
                    argv[++argc] = strtok(NULL, " ");
                } while ( (argc < 10) && (argv[argc] != NULL));

                /* Determine arch: 12 | 14 | 16 | 24 | 32 */
                flag_arch = 0;
                if (strcmp(argv[0], "p12")==0) {flag_arch = 1;};
                if (strcmp(argv[0], "p14")==0) {flag_arch = 1;};
                if (strcmp(argv[0], "n14")==0) {flag_arch = 1;};
                if (strcmp(argv[0], "p16")==0) {flag_arch = 1;};
                if (strcmp(argv[0], "n16")==0) {flag_arch = 1;};
                if (strcmp(argv[0], "p24")==0) {flag_arch = 1;};
                if (strcmp(argv[0], "p32")==0) {pic_arch("p32");flag_arch = 2;};
                if (flag_arch == 1) {
                  usage_useless();
                  continue;
                }
                if (flag_arch == 0) {
                  usage_full();
                  continue;
                }

                /* No key entry */
                /* ARCH12BIT || ARCH14BIT || ARCH16BIT || ARCH24BIT */
                p.key = NOKEY;
      
                /* Check args */
                if (argc < 2) {
                    usage(argv[0], "Missing arg(s)");
                    continue;
                }

                /*
                * Get args & perform operation
                */

                /* Device selection and partition */
                int argv1 = tolower((int)argv[1][0]);
                int argv11 = tolower((int)argv[1][1]);
                if (argv1 == 'h') {    /* HELP */
                    if (argv11 == 'e') {
                        usage(argv[0], 0);
                        continue;
                    }
                }
                if (argv1 == 's' || (argv1 == 'p' && argv11 == 'a')) {
                    /* Select or partition device */
                    if (argc < 3) {
                        pic_selector();
                        rxEND();
                        continue;
                    }
                    p.partition = (argv1 == 'p') ? TRUE : FALSE;
                    if (mystrcasestr(argv[2], "dspic") == argv[2]) {
                        strncpy(p.devicename, argv[2], STRLEN);
                    } else if (mystrcasestr(argv[2], "pic") == argv[2]) {
                        strncpy(p.devicename, argv[2], STRLEN);
                    } else {
                        int32_t temp = strtol(argv[2], NULL, 0);
                        if (temp < 10 || temp > 33) {
                            usage(argv[0], "Invalid arg [select]");
                            continue;
                        }
                        if (temp == 30 || temp == 33) {
                            strcpy(p.devicename, "dspic");
                            strncpy(&p.devicename[5], argv[2], STRLEN - 5);
                        } else {
                            strcpy(p.devicename, "pic");
                            strncpy(&p.devicename[3], argv[2], STRLEN - 3);
                        }
                    }
                    argc -= 2;
                    for (i=1;i<8;i++) {argv[i]=argv[i+2];}
                    argv[8]="";argv[9]=""; 
                    if (argc < 2) {
                        usage(argv[0], "Missing arg(s)");
                        continue;
                    }
                } else if (p.pic->arch == ARCH12BIT && argv1 != 'f') {
                    usage(argv[0], "Missing select");
                    continue;
                }

                /* Key entry or loader output */
                argv1 = tolower((int)argv[1][0]);
                if (argv1 == 'l') {     /* LVP 32-bit key entry or loader output */
                    if (argv11 == 'o') {		/* LOADER OUTPUT */
                        if (argc > 2) {
                            usage(argv[0], "Too many args [loader]");
                            continue;
                        }
                        pic_bootloader();
                        rxEND();
                        continue;
                    }
                    if (p.pic->arch == ARCH12BIT) {
                        /* NOT SUPPORTED */
                        usage(argv[0], "Invalid arg [lvp]");
                        continue;
                    }
                    /* ARCH14BIT || ARCH16BIT || ARCH24BIT || ARCH32BIT */
                    p.key = LVPKEY;
                    argc -= 1;
                    for (i=1;i<9;i++) {argv[i]=argv[i+1];}
                    argv[9]=""; 
                    if (argc < 2) {
                        usage(argv[0], "Missing arg(s)");
                        continue;
                    }
                }
                else if (argv1 == 'h') {    /* HVP 32-bit key entry */
                    if (p.pic->arch == ARCH12BIT || p.pic->arch == ARCH14BIT || p.pic->arch == ARCH32BIT) {
                        /* NOT SUPPORTED */
                        usage(argv[0], "Invalid arg [hvp]");
                        continue;
                    }
                    /* ARCH16BIT || ARCH24BIT */
                    p.key = HVPKEY;
                    argc -= 1;
                    for (i=1;i<9;i++) {argv[i]=argv[i+1];}
                    argv[9]=""; 
                    if (argc < 2) {
                        usage(argv[0], "Missing arg(s)");
                        continue;
                    }
                }
                else if (p.pic->arch == ARCH32BIT) {  /* LVP 32-bit key entry */
                    /* ARCH32BIT */
                    p.key = LVPKEY;
                }
                else {          /* No key entry */
                    /* ARCH12BIT || ARCH14BIT || ARCH16BIT || ARCH24BIT */
                    p.key = NOKEY;
                }

                /* Command */
                rxSTART();
                argv1 = tolower((int)argv[1][0]);
                argv11 = tolower((int)argv[1][1]);
                switch (argv1) {
                    case 'b': if (argv11 == 'o') {    /* BOOT */
                            uint32_t addr = UINT32_MAX, words = UINT32_MAX;
                            if (argc > 4) {
                                usage(argv[0], "Too many args [boot]");
                                continue;
                            }
                            if (argc >= 3) {
                                words = strtoul(argv[2], NULL, 0);
                                if (words == 0) {
                                    usage(argv[0], "Invalid arg [boot]");
                                    continue;
                                }
                            }
                            if (argc == 4) {
                                addr = strtoul(argv[3], NULL, 0);
                            }
                            pic_dumpboot(addr, words);
                        } else {      /* BLANK */
                            int config = 1;
                            if (argc > 3) {
                                usage(argv[0], "Too many args [blank]");
                                continue;
                            }
                            if (argc == 3) switch (argv[2][0]) {
                                    case 'n':
                                    case 'N':
                                    case '0': config = 0;
                                        break;
                                    case 'y':
                                    case 'Y':
                                    case '1': config = 1;
                                        break;
                                    default:usage(argv[0], "invalid arg [blank]");
                                        continue;
                                        break;
                                }
                            pic_blank(config);
                            sprintf(buf,"OK\n");
                            myprintf(buf);
                        }
                        break;
        
                    case 'c': if (argc > 3) {
                            usage(argv[0], "Too many args [config]");
                            continue;
                        }
                        if (argc == 2)
                            pic_dumpconfig();
                        else
                            pic_writebandgap(strtoul(argv[2], NULL, 0));
                        break;

                    case 'd': if (argv11 == 'a') {    /* DATA */
                            if (argc > 2) {
                                usage(argv[0], "Too many args [data]");
                                continue;
                            }
                            pic_dumpdata();
                        } else if (argv11 == 'e') {   /* DEBUG */
                            pic_debug();
                        } else {      /* DUMP */
                            if (argc > 2) {
                                usage(argv[0], "Too many args [dump]");
                                continue;
                            }
                            unsigned long startTime = _CP0_GET_COUNT();  // 開始時刻を記録
                            pic_dumpdevice();
                            unsigned long stopTime = _CP0_GET_COUNT();   // 終了時刻を記録する
                            float s=(float)(stopTime - startTime)/((float) PBCLK);        //経過時間（秒）を算出
                            sprintf(buf,"%.4fs\n",s);                    //少数点以下4桁で表示
                            myprintf(buf);
                        }
                        break;

                    case 'e': if (argv11 == 'r') {    /* ERASE FLASH | ID | ROW[NROWS] */
                            uint32_t row = 0, nrows = 1;
                            char prompt[STRLEN] = {0}, *endptr = NULL;

                            if (argc < 3) {
                                usage(argv[0], "Missing arg [erase]");
                                continue;
                            }
                            if (argc > 4) {
                                usage(argv[0], "Too many args [erase]");
                                continue;
                            }
        
                            int argv2 = tolower((int)argv[2][0]);
                            switch (argv2) {
                                case 'i': /* IDLOCATION    */
                                case 'u': /* USERID/CONFIG */
                                    row = PIC_ERASE_ID;
                                    strncpy(prompt, "Erase id", STRLEN);
                                    break;
                                case 'c': /* CONFIG */
                                    row = PIC_ERASE_CONFIG;
                                    strncpy(prompt, "Erase config", STRLEN);
                                    break;
                                case 'e': /* EEPROM */
                                    row = PIC_ERASE_EEPROM;
                                    strncpy(prompt, "Erase EEPROM", STRLEN);
                                    break;
                                case 'f': /* FLASH */
                                    nrows = UINT32_MAX;
                                    strncpy(prompt, "Erase program flash", STRLEN);
                                    break;
                                default:  /* FLASH ROW */
                                    {
                                        row = strtoul(argv[2], &endptr, 0);
                                        if (endptr == argv[2]) {
                                            usage(argv[0], "Invalid arg [erase]");
                                            continue;
                                        }
                                        if (argc == 4) {
                                            nrows = strtoul(argv[3], NULL, 0);
                                            if (nrows == 0) {
                                                usage(argv[0], "Invalid arg [erase]");
                                                continue;
                                            }
                                        }
                                        int _rc = snprintf(prompt, STRLEN, "Erase %u row(s) at row %u", nrows, row);
                                        if (_rc < 0) {
                                            sprintf(buf,"%s: fatal error: snprintf failed\n", __func__);
                                            myprintf(buf);
                                            continue;
                                        } else if (_rc >= STRLEN) {
                                            sprintf(buf,"%s: fatal error: snprintf overrun\n", __func__);
                                            myprintf(buf);
                                            continue;
                                        }
                                    }
                                    break;
                            }
                            //if (areyousure(prompt))
                                pic_erase(row, nrows);
                            sprintf(buf,"OK\n");
                            myprintf(buf);
                        } else if (argv11 == 'x') { /* EXECUTIVE */
                            uint32_t addr = UINT32_MAX, words = UINT32_MAX;
                            if (argc > 4) {
                                usage(argv[0], "Too many args [executive]");
                                continue;
                            }
                            if (argc >= 3) {
                                words = strtoul(argv[2], NULL, 0);
                                if (words == 0) {
                                    usage(argv[0], "Invalid arg [executive]");
                                    continue;
                                }
                            }
                            if (argc == 4) {
                                addr = strtoul(argv[3], NULL, 0);
                            }
                            pic_dumpexec(addr, words);
                        } else {      /* EEPROM */
                            if (argc > 2) {
                                usage(argv[0], "Too many args [eeprom]");
                                continue;
                            }
                            pic_dumpdata();
                        }
                        break;

                    case 'f': if (argv11 == 'l') {    /* flash */
                      uint32_t words = UINT32_MAX, addr = UINT32_MAX;
                      if (argc > 4) {
                        usage(argv[0], "Too many args [program flash]");
                        continue;
                      }
                      if (argc >= 3) {
                        words = strtoul(argv[2], NULL, 0);
                        if (words == 0) {
                          usage(argv[0], "Invalid arg [program flash]");
                          continue;
                        }
                      }
                      if (argc == 4) {
                        addr = strtoul(argv[3], NULL, 0);
                      }
                      pic_dumpprogram(addr, words);
                    } else {      /* file */
                        if (argc > 2) {
                            usage(argv[0], "too many args [file]");
                            continue;
                        }
                        SdFileList();
                    }
                    break;

                    case 'i': if (argc > 2) {
                            usage(argv[0], "too many args [id]");
                            continue;
                        }
                        pic_dumpdeviceid();
                        break;

                    case 'o': if (argc > 3) {
                            usage(argv[0], "Too many args [osccal]");
                            continue;
                        }
                        if (argc == 2)
                            pic_dumposccal();
                        else
                            pic_writeosccal(strtoul(argv[2], NULL, 0));
                        break;

                    case 'p': {
                            int blank = 1;
                            if (argc > 4) {
                                usage(argv[0], "Too many args [program]");
                                continue;
                            }
                            if (argc == 4) switch (argv[3][0]) {
                                    case 'n':
                                    case 'N':
                                    case '0': blank = 0;
                                        break;
                                    case 'y':
                                    case 'Y':
                                    case '1': blank = 1;
                                        break;
                                    default:usage(argv[0], "invalid arg [program]");
                                        continue;
                                        break;
                                }
                            unsigned long startTime = _CP0_GET_COUNT();  // 開始時刻を記録
                            pic_program(argv[2], blank);
                            unsigned long stopTime = _CP0_GET_COUNT();   // 終了時刻を記録する
                            float s=(float)(stopTime - startTime)/((float) PBCLK);        //経過時間（秒）を算出
                            sprintf(buf,"%.4fs\n",s);                    //少数点以下4桁で表示
                            myprintf(buf);
                        }
                        break;

                    case 'v': if (argv11 == 'i') {    /* VIEW */
                            int raw = 0;
                            if (argc > 4) {
                                usage(argv[0], "Too many args [view]");
                                continue;
                            }
                            if (argc == 4) switch (argv[3][0]) {
                                    case 'r':
                                    case 'R': raw = 1;
                                        break;
                                    default:usage(argv[0], "invalid arg [view]");
                                        continue;
                                        break;
                            }
                            if (argc > 2)
                                pic_view(argv[2], raw);
                        } else {      /* VERIFY */
                            if (argv11 == 'p') {
                                gpio_bb_set_vpp(VPPHIGH);
                                sprintf(buf,"OK\n");
                                myprintf(buf);
                            } else {
                                if (argc > 3) {
                                    usage(argv[0], "Too many args [verify]");
                                    continue;
                                }
                                if (argc == 3)
                                    rc = 0 - pic_verify(argv[2]);
                            }
                        }
                        break;

                    default:  usage(argv[0], "Unknown operation");
                        continue;
                        break;
                }
                LED_Off();
                rxEND();
                continue;
            }
        }
        CORETIMER_DelayMs(1);
	}
    
    /* Execution should not come here during normal operation */

    return ( EXIT_FAILURE );
}


/*******************************************************************************
 End of File
*/

