/*
 *
 *  ALL03
 *
 *  26.07.2002
 *
 *  by Fabio Sturman
 *
 *  fabio.sturman@tiscali.it
 *
 *  89c52.c
 *
 *  main module for 89c52
 *
 */

/* Copyright (c) 2002 Fabio Sturman (fabio.sturman@tiscali.it)
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <ctype.h>
#include <string.h>
#include "../include/all03.h"
#include "../include/all03ft.h"
#include "../include/keys.h"
#include "../include/sleep.h"
#include "../include/binmask.h"
#include "89c5x.h"

/* vars used only at level 2 */
unsigned char flash[0x5000];
unsigned short int max_flash_addr=0x2000; /* 89c52 */

int lock_bit_1=1;
int lock_bit_2=1;
int lock_bit_3=1;

unsigned char signature[3];

char flash_file_name[256]="flash89.bin";

int micro_controller_model=2; /* 80C52 */
int programming_voltage=12;

/* 0 programming pulse of 100us */
/* 1 programming pulse of  10ms */
int long_delay=0;

/*- ATMEL 89C52 Level1--------------------------------------*/

/* writes 8bit data to P0 of uC */
void wr_chip_data(unsigned char ub)
{
  int i;

  for(i=0;i<8;i++) all03_wr_pin(39-i,ub & BIT(i) ? 1 : 0 );
}

/* reads 8 bit data from P0 of uC */
unsigned char rd_chip_data(void)
{
  unsigned char tb, tb0, br;
  int i;

  wr_chip_data(0xff);

  i=4;
  tb=all03_rd(ALL03_TTL_ID+i);
  
  i=3;
  tb0=all03_rd(ALL03_TTL_ID+i);

  br=0;
  if(tb  & BIT(0)) br|=BIT(6); 
  if(tb  & BIT(1)) br|=BIT(5); 
  if(tb  & BIT(2)) br|=BIT(4); 
  if(tb  & BIT(3)) br|=BIT(3); 
  if(tb  & BIT(4)) br|=BIT(2); 
  if(tb  & BIT(5)) br|=BIT(1); 
  if(tb  & BIT(6)) br|=BIT(0); 
  if(tb0 & BIT(7)) br|=BIT(7);
  return(br);
}

/* negative pulse /prog */
void pulse_nprog(void)
{
  all03_wr_pin(NPROG,0);
  all03_wr_pin(NPROG,1);
}

/* negative pulse /prog for x ms */
void pulse_nprog_x(float x)
{
  all03_wr_pin(NPROG,0);
  wait(x);
  all03_wr_pin(NPROG,1);
}

/* writes flash programming mode */
void wr_fpm(unsigned char fpm)
{
  if(fpm & BIT(0)) wr_fpm0(1); else wr_fpm0(0);
  if(fpm & BIT(1)) wr_fpm1(1); else wr_fpm1(0);
  if(fpm & BIT(2)) wr_fpm2(1); else wr_fpm2(0);
  if(fpm & BIT(3)) wr_fpm3(1); else wr_fpm3(0);
}

/* writes address-low -> P1 and address-high -> P2.0-P2.4 */
void wr_chip_address(unsigned short address)
{
  int i=0;

  all03_wr_ttl_buf(i, address & 0x00ff);
  all03_wr(ALL03_TTL_ID+i, all03_rd_ttl_buf(i));
  for(i=0;i<5;i++) all03_wr_pin(21+i,address & BIT(8+i) ? 1 : 0 );
}

/* waits while rdy=0 with timeout */
int wait_rdy(void)
{
  unsigned long t, dt;

  dt=get_one_ms()*5;
  for(t=0;t<dt;t++)
  {
    if(rd_rdy()) return(0);
  }
  return(1);
}

/* put uC in programming mode */
void chip_init(void)
{
  all03_set_gnd_20();
  all03_set_vcc(5.0);
  all03_set_vhh(12.0);
  all03_set_vcc_40();
  set_clock();

  wr_rst(0);
  wait(0.1);
  wr_rst(1);
  
  wr_npsen(0);
  wr_nprog(1);
  wr_nea(1);
  wr_chip_data(0xff);
  wr_chip_address(0xffff);
}

/*- ATMEL 98C52 Level2--------------------------------------*/

/* edit chip model, programming voltage
   and programming pulse width
*/
void edit_model_and_voltage(void)
{
  int c;
  
  for(;;)
  {
    clear_screen();
    printf("*** EDIT MODEL -  Vpp - Tp ***\n\n");
    print_model_and_voltage();
    printf("\n");
    printf("A) 89C51     B) 89C52\n");
    printf("D) Vpp=5V    E) Vpp=12V\n");
    printf("F) Tp=100us  G) Tp=10ms\n");
    printf("\n");
    printf("Q) QUIT\n");
    printf("\n");
    printf("Enter command: ");
    flush_out();

    c=key_get();
    if((c>=32) && (c<127)) printf("%c\n",c);
    if(islower(c)) c=toupper(c);

    switch(c)
    {
      case 'A':
        micro_controller_model=1;
        max_flash_addr=0x1000;
      break;
      case 'B':
        micro_controller_model=2;
        max_flash_addr=0x2000;
      break;
      case 'D': programming_voltage=5; break;
      case 'E': programming_voltage=12; break;
      case 'F': long_delay=0; break;
      case 'G': long_delay=1; break;

      case 'Q': return; break;
    }
  }
}

/* LOCK BITS ----------------------------------------------*/

/* prints lock bits */
void print_lock_bits(void)
{
  printf("Lock bits:\n\n");
  printf("LOCK BIT 1= %d\n",lock_bit_1);
  printf("LOCK BIT 2= %d\n",lock_bit_2);
  printf("LOCK BIT 3= %d\n",lock_bit_3);
}

/*
 *  edit_lock_bits()
 *
 *  edit lock bits
 *
 */
void edit_lock_bits(void)
{
  int c;
  
  for(;;)
  {
    clear_screen();
    printf("*** EDIT LOCK BITS ***\n\n");
    print_lock_bits();
    printf("\n");
    printf("A) LOCK BIT 1 <- 0     B) LOCK BIT 1 <- 1\n");
    printf("C) LOCK BIT 2 <- 0     D) LOCK BIT 2 <- 1\n");
    printf("E) LOCK BIT 3 <- 0     F) LOCK BIT 3 <- 1\n");
    printf("\n");
    printf("Q) QUIT\n");
    printf("\n");
    printf("Enter command: ");
    flush_out();

    c=key_get();
    if((c>=32) && (c<127)) printf("%c\n",c);
    if(islower(c)) c=toupper(c);

    switch(c)
    {
      case 'A': lock_bit_1=0; break;
      case 'B': lock_bit_1=1; break;
      case 'C': lock_bit_2=0; break;
      case 'D': lock_bit_2=1; break;
      case 'E': lock_bit_3=0; break;
      case 'F': lock_bit_3=1; break;
      case 'Q': return; break;
    }
  }
}

/*
 *  write_lock_bits()
 *
 *  writes lock bits to uC
 *
 */
void write_lock_bits(void)
{
  clear_screen();
  if(test_if_timer()) return;
  printf("*** WRITE LOCK BITS ***\n\n");
  printf(PROC_STRING);
  wait_enter();

  printf("WRITING...\n");
  chip_init();

  /* */
  if(programming_voltage==12) set_nea_12v();

  if(!lock_bit_1)
  {
    printf("WRITING LOCK BIT 1\n");
    wr_fpm(COMMAND_WRITE_LOCK_BIT_1);
    wr_chip_address(0x0030);
    short_delay();
    (long_delay? pulse_nprog_10ms(): pulse_nprog_100us());
    if(wait_rdy())
    {
      printf("\n\007* ALL03 Error - Timeout in writing lock bits!\n");
      goto write_lock_bits_q;
    }
  }

  if(!lock_bit_2)
  {
    printf("WRITING LOCK BIT 2\n");
    wr_fpm(COMMAND_WRITE_LOCK_BIT_2);
    wr_chip_address(0x0030);
    short_delay();
    (long_delay? pulse_nprog_10ms(): pulse_nprog_100us());
    if(wait_rdy())
    {
      printf("\n\007* ALL03 Error - Timeout in writing lock bits!\n");
      goto write_lock_bits_q;
    }
  }

  if(!lock_bit_3)
  {
    printf("WRITING LOCK BIT 3\n");
    wr_fpm(COMMAND_WRITE_LOCK_BIT_3);
    wr_chip_address(0x0030);
    short_delay();
    (long_delay? pulse_nprog_10ms(): pulse_nprog_100us());
    if(wait_rdy())
    {
      printf("\n\007* ALL03 Error - Timeout in writing lock bits!\n");
      goto write_lock_bits_q;
    }
  }

write_lock_bits_q:
    
  if(programming_voltage==12) reset_nea_12v();
  /* */

  all03_init_h();

  printf("OK\n");
}

/*
 *  erase()
 *
 *  erase uC flash memory and lock bits
 *
 */
void erase(void)
{
  clear_screen();
  if(test_if_timer()) return;
  printf("*** CHIP ERASE ***\n\n");
  printf(PROC_STRING);
  wait_enter();

  printf("ERASING...\n");
  chip_init();

  /* */
  if(programming_voltage==12) set_nea_12v();

  wr_fpm(COMMAND_CHIP_ERASE);
  short_delay();
  pulse_nprog_10ms();
  
  if(programming_voltage==12) reset_nea_12v();
  /* */
  
  all03_init_h();

  printf("OK\n");
}

/*
 *  read_signature()
 *
 *  reads signature
 *
 *  AT89C51 Vpp=12V
 *    SIG0=0x1e Atmel
 *    SIG1=0x51 Type
 *    SIG2=0xff Vpp
 *
 *  AT89C51 Vpp=5V
 *    SIG0=0x1e Atmel
 *    SIG1=0x51 Type
 *    SIG2=0x05 Vpp
 *
 *
 *  AT89C52 Vpp=12V
 *    SIG0=0x1e Atmel
 *    SIG1=0x52 Type
 *    SIG2=0xff Vpp
 *
 *  AT89C52 Vpp=5V
 *    SIG0=0x1e Atmel
 *    SIG1=0x52 Type
 *    SIG2=0x05 Vpp
 *
 */
void read_signature(void)
{
  int i;

  clear_screen();
  if(test_if_timer()) return;
  printf("*** READ SIGNATURE ***\n\n");
  printf(PROC_STRING);
  wait_enter();

  printf("READING...\n");
  chip_init();

  /* */
  wr_fpm(COMMAND_READ_SIGNATURE_BYTE);
  
  wr_chip_address(0x0030);
  short_delay();
  signature[0]=rd_chip_data();
  
  wr_chip_address(0x0031);
  short_delay();
  signature[1]=rd_chip_data();
  
  wr_chip_address(0x0032);
  short_delay();
  signature[2]=rd_chip_data();
  /* */

  all03_init_h();

  for(i=0;i<3;i++)
    printf("Signature[%d]=%02x\n",i,signature[i]);

  printf("OK\n");
}

/*
 *  write()
 *
 *  writes flash buffer to uC flash memory
 *
 */
void write(void)
{
  unsigned short int addr;

  clear_screen();
  if(test_if_timer()) return;
  printf("*** WRITE FLASH ***\n\n");
  printf(PROC_STRING);
  wait_enter();

  printf("WRITING...\n");
  chip_init();

  /* */
  if(programming_voltage==12) set_nea_12v();
  
  wr_fpm(COMMAND_WRITE_CODE_DATA);

  for(addr=0; addr<max_flash_addr; addr++)
  {
    printf("Address: %04x\r", addr);
    if(flash[addr]!=0xff)
    {    
      wr_chip_address(addr);
      wr_chip_data(flash[addr]);
      short_delay();
      (long_delay? pulse_nprog_10ms(): pulse_nprog_100us());
      if(wait_rdy())
      {
        printf("\n\007* ALL03 Error - Timeout in writing flash at address %04x!\n",addr);
        goto write_flash_q;
      }
    }
  }

write_flash_q:

  if(programming_voltage==12) reset_nea_12v();
  /* */
  
  all03_init_h();
  printf("\n");

  printf("OK\n");
}

/*
 *  read()
 *
 *  reads uC flash memory to flash buffer
 *
 */
void read(void)
{
  unsigned short int addr;

  clear_screen();
  if(test_if_timer()) return;
  printf("*** READ FLASH ***\n\n");
  printf(PROC_STRING);
  wait_enter();

  printf("READING...\n");
  chip_init();

  /* */
  wr_fpm(COMMAND_READ_CODE_DATA);

  for(addr=0; addr<max_flash_addr; addr++)
  {
    printf("Address: %04x\r",addr);    
    wr_chip_address(addr);
    short_delay();
    flash[addr]=rd_chip_data();
  }
  /* */

  all03_init_h();
  printf("\n");

  printf("OK\n");
}

/*
 *  blank_check()
 *
 *  blank check uC flash
 *
 */
void blank_check(void)
{
  int err;
  unsigned short int addr;

  err=0;
  clear_screen();
  if(test_if_timer()) return;
  printf("*** BLANK CHECK ***\n\n");
  printf(PROC_STRING);
  wait_enter();

  printf("CHECKING...\n");
  chip_init();

  /* */
  wr_fpm(COMMAND_READ_CODE_DATA);

  for(addr=0; addr<max_flash_addr; addr++)
  {
    printf("Address: %04x\r",addr);
    wr_chip_address(addr);
    short_delay();
    if(rd_chip_data()!=0xff) err++;
  }
  /* */

  all03_init_h();
  printf("\n");

  if(err) printf("Flash not blank - %d errors!\n", err);
  else printf("Flash is blank\n");

  printf("OK\n");
}

/*
 *  verify()
 *
 *  verifies uC flash and flash buffer
 *
 */
void verify(void)
{
  int err;
  unsigned short int addr;

  err=0;
  clear_screen();
  if(test_if_timer()) return;
  printf("*** VERIFY ***\n\n");
  printf(PROC_STRING);
  wait_enter();

  printf("VERIFYING...\n");
  chip_init();

  /* */
  wr_fpm(COMMAND_READ_CODE_DATA);

  for(addr=0; addr<max_flash_addr; addr++)
  {
    printf("Address: %04x\r",addr);    
    wr_chip_address(addr);
    short_delay();
    if(rd_chip_data()!=flash[addr]) err++;
  }
  /* */
  
  all03_init_h();
  printf("\n");

  printf("Errors: %d\n",err);
  
  printf("OK\n");
}

/* read file to flash buffer */
void read_flash_buf_from_file(void)
{
  clear_screen();
  printf("*** READ FILE TO FLASH BUFFER ***\n\n");
  read_file_to_buf("ENTER FILE NAME:  ",\
    flash_file_name, flash, max_flash_addr, 0xff);
}

/* write flash buffer to file */
void write_flash_buf_to_file(void)
{
  clear_screen();
  printf("*** WRITE FLASH BUFFER TO FILE ***\n\n");
  write_buf_to_file("ENTER FILE NAME:  ",\
    flash_file_name, flash, max_flash_addr);
}

/* display help screen */
void display_help(void)
{
  printf("use: 89c52 [<option>] [<file_name>]\n");
  printf("option\n");
  printf(" -L, -l        enable 10ms programming pulse (default 100us)\n");
  printf(" -s, -S        skip processor speed test\n");
  //printf(" -51, -52 -55  set microcontroller type\n");
  printf(" -51, -52      set microcontroller type\n");
  printf(" -5v, -5V      set programming voltage to 5V\n");
  printf(" -12v, -12V    set programming voltage to 12V\n");
  printf(" -h, -H        display this screen\n");
  printf(" -bxxx, -Bxxx  set all03 base address\n");
  exit(1);
}

/* main program */
int main(int argc, char *argv[])
{
  int c, ac, skip, tbase;

  all03_init_h();
  disable_ctrl_c_break();

  ac=argc-1;
  skip=0;
  while(ac)
  {
    if(!strcmp(argv[ac],"-l") || !strcmp(argv[ac],"-L")) long_delay=1;
    else if(!strcmp(argv[ac],"-s") || !strcmp(argv[ac],"-S")) skip=1;
    else if(!strcmp(argv[ac],"-51"))
    {
      max_flash_addr=0x1000;
      micro_controller_model=1;
    }
    else if(!strcmp(argv[ac],"-52"))
    {
      max_flash_addr=0x2000;
      micro_controller_model=2;
    }
    //else if(!strcmp(argv[ac],"-55"))
    //{
    //  max_flash_addr=0x3000;
    //  micro_controller_model=5;
    //}
    else if(!strcmp(argv[ac],"-5v") || !strcmp(argv[ac],"-5V") ) programming_voltage=5;
    else if(!strcmp(argv[ac],"-12v") || !strcmp(argv[ac],"-12V")) programming_voltage=12;
    else if(!strcmp(argv[ac],"-h") || !strcmp(argv[ac],"-H")) display_help();
    else if(!strncmp(argv[ac],"-b",2) || !strncmp(argv[ac],"-B",2))
    {
      sscanf(&argv[ac][2],"%x",&tbase);
      all03_set_base_address(tbase);
    }
    else strcpy(flash_file_name,argv[ac]);
    ac--;
  }  

  if(!skip)
  {
    printf("TESTING SPEED...\n");
    if(!test_timer()) printf("TIMER OK\n");
    else
    {
      printf("\n\007* ALL03 Error - Timing not OK!\n");
      printf("Press <ENTER>\n");
      wait_enter();
    }
  }

  if(all03_test_base_address())
  {
    printf("\n\007* ALL03 Error - Programmer not found at base address %04x!\n",all03_get_base_address());
    printf("Press <ENTER>\n");
    wait_enter();
  }

  for(;;)
  {
    clear_screen();
    printf("---------------------------------------------\n");
    printf("-- ALL03 - AT89C5x PROGRAMMING MODULE -------\n");
    printf("------------------V 1.0BETA4--by FaSt--------\n");
    printf("\n");
    print_model_and_voltage();
    printf("\n");
    printf("    Menu:\n");
    printf("2 - Read file\n");
    printf("3 - Save file\n");
    printf("6 - Edit base address\n");
    printf("B - Blank check\n");
    printf("R - Read flash\n");
    printf("P - Program flash\n");
    printf("I - Write lock bits\n");
    printf("S - Read signature\n");
    printf("E - Erase\n");
    printf("K - Edit lock bits\n");
    printf("V - Verify flash\n");
    printf("T - Change model\n");
    //printf("{ - Test 30000ms\n");
    //printf("} - Dump ALL03 registers\n");
    printf("\n");
    printf("Q - Quit\n");
    printf("\n");
    printf("Enter command: ");
    flush_out();

    c=key_get();
    if((c>=32) && (c<127)) printf("%c\n",c);
    if(islower(c)) c=toupper(c);
    
    switch(c)
    {
      case '2': read_flash_buf_from_file(); break;
      case '3': write_flash_buf_to_file(); break;
      case '6': all03_edit_base(); break;

      case 'B': blank_check(); break;
      case 'R': read(); break;
      case 'S': read_signature(); break;
      case 'P': write(); break;
      case 'I': write_lock_bits(); break;
      case 'E': erase(); break;
      case 'K': edit_lock_bits(); break;
      case 'V': verify(); break;
      case 'T': edit_model_and_voltage(); break;

      case '{': test(); break;
      case '}': all03_dump(); break;
      case 'Q':
        enable_ctrl_c_break();
        return(0);
      break;
    }
    
    printf("Press <ENTER>\n");
    wait_enter();
  }
  return(0);
}

