/*
 *
 *  ALL03
 *
 *  26.07.2002
 *
 *  by Fabio Sturman
 *
 *  fabio.sturman@tiscali.it
 *
 *  89cx051.c
 *
 *  main module for 89cx051 x=1,2,4
 *
 */

/* 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.
 */

#define DEBUG

#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 "89cx051.h"

#define PAGE_LEN 23
void dump_diff(unsigned char *buf, unsigned char *abuf, unsigned short int m);

/* vars used only at level 2 */
unsigned char flash[0x5000];
unsigned char aflash[0x5000];

unsigned short int max_flash_addr=0x400;
int lock_bit_1=1;
int lock_bit_2=1;
unsigned char signature[2];
char flash_file_name[256]="test.bin";
int micro_controller_model=2;

/*- ATMEL 89CX051 Level1--------------------------------------*/

/* writes 8bit data to P1 of uC
 */
void wr_data(unsigned char ub)
{
  int i;

  for(i=0;i<8;i++) all03_wr_pin(22+i,ub & BIT(i) ? 1 : 0 );
}

/* reads 8 bit data from P1 of uC
 */
unsigned char rd_data(void)
{
  unsigned char tb2, tb3, br;
  int i;

  wr_data(0xff);
  i=2;
  tb2=all03_rd(ALL03_TTL_ID+i);
  
  i=3;
  tb3=all03_rd(ALL03_TTL_ID+i);

  br=0;
  if(tb2 & BIT(5)) br|=BIT(0);
  if(tb2 & BIT(6)) br|=BIT(1);
  if(tb2 & BIT(7)) br|=BIT(2);
  if(tb3 & BIT(0)) br|=BIT(3);
  if(tb3 & BIT(1)) br|=BIT(4);
  if(tb3 & BIT(2)) br|=BIT(5);
  if(tb3 & BIT(3)) br|=BIT(6);
  if(tb3 & BIT(4)) br|=BIT(7);
  return(br);
}

/* negative pulse /prog
 */
void pulse_nprog(void)
{
  wr_nprog(0);
  wr_nprog(1);
}

/* negative pulse /prog for x ms
 */
void pulse_nprog_x(float x)
{
  wr_nprog(0);
  wait(x);
  wr_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);
}

/* pulse chip address
   increments addres
 */
void inc_address(void)
{
  wr_xtal1(0);
  wr_xtal1(1);
  wr_xtal1(1);
  wr_xtal1(0);
}

void set_rst(int state)
{
  switch(state)
  {
    case VIL: // 0
      all03_set_vhh_pin(RST,0);
      all03_wr_pin(RST,0);
    break;
    case VIH: // 1
      all03_set_vhh_pin(RST,0);
      all03_wr_pin(RST,1);
    break;
    case VPP: // 12V
      //all03_wr_pin(RST,1);
      all03_set_vhh_pin(RST,1);
    break;
  }
}

/* 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_30();
  all03_wr_pin(RDY,1);
  set_rst(VIL);
  wr_xtal1(VIL);
  wait(0.1);
  set_rst(VIH);
  wr_nprog(VIH);
  wr_data(0xff);
  wait(0.1);
  all03_wr_pin(1,1);
}

void msg_wait_enter(void)
{
  printf("Press <ENTER>");
  wait_enter();
}

/*- ATMEL 98CX051 Level2--------------------------------------*/


void set_model_at89c1051(void)
{
  micro_controller_model=1;
  max_flash_addr=0x400;
}

void set_model_at89c2051(void)
{
  micro_controller_model=2;
  max_flash_addr=0x800;
}

void set_model_at89c4051(void)
{
  micro_controller_model=4;
  max_flash_addr=0x1000;
}

/* edit chip model, programming voltage
   and programming pulse width
*/
void edit_model_and_voltage(void)
{
  int c;
  
  for(;;)
  {
    clear_screen();
    printf("*** EDIT MODEL ***\n\n");
    print_model();
    printf("\n");
    printf("A) AT89C1051     B) AT89C2051\n");
    printf("C) AT89C4051\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': set_model_at89c1051(); break;
      case 'B': set_model_at89c2051(); break;
      case 'C': set_model_at89c4051(); 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);
}

/*
 *  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("\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 '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(!lock_bit_1)
  {
    printf("WRITING LOCK BIT 1\n");
    wr_fpm(COMMAND_WRITE_LOCK_BIT_1);
    wr_data(0xff);
    set_rst(VPP);
    wait(0.05);
    pulse_nprog_10ms();
    wait(0.05);
    set_rst(VIH);
    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_data(0xff);
    set_rst(VPP);
    wait(0.05);
    pulse_nprog_10ms();
    wait(0.05);
    set_rst(VIH);
    if(wait_rdy())
    {
      printf("\n\007* ALL03 Error - Timeout in writing lock bits!\n");
      goto write_lock_bits_q;
    }
  }

write_lock_bits_q:
    
  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();

  wr_fpm(COMMAND_CHIP_ERASE);
  set_rst(VPP);
  //pulse_nprog_10ms();
  wr_nprog(0);
  if (micro_controller_model==4) wait(20.0);
  else wait(10.0);
  wr_nprog(1);
  set_rst(VIH);

  all03_init_h();
}

/*
 *  read_signature()
 *
 *  reads signature
 *
 *  AT89C1051
 *    SIG0=0x1e Atmel
 *    SIG1=0x?? 89C1051
 *
 *  AT89C2051
 *    SIG0=0x1e Atmel
 *    SIG1=0x21 89C2051
 *
 *  AT89C4051
 *    SIG0=0x1e Atmel
 *    SIG1=0x41 89C4051
 *
 */
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);
  signature[0]=rd_data();
  inc_address();
  signature[1]=rd_data();
  all03_init_h();

  for(i=0;i<2;i++)
    printf("Signature[%d]=%02x\n",i,signature[i]);

  msg_wait_enter();
}

/*
 *  write()
 *
 *  writes flash buffer to uC flash memory
 *
 */
void write(void)
{
  unsigned short int addr, pc;
  int err, notprog;

  clear_screen();
  if(test_if_timer()) return;
  printf("*** WRITE FLASH ***\n\n");
  printf(PROC_STRING);
  wait_enter();

  printf("WRITING...\n");
  chip_init();
  if (micro_controller_model==4) wait(10.0);
  err=0;
  for(addr=0; addr<max_flash_addr; addr++)
  {
    pc=0;
    notprog=1;
    while(notprog)
    {
      printf("Address: %04X [PC=%02d]\r", addr,pc);
      wr_fpm(COMMAND_WRITE_CODE_DATA);
      wr_data(flash[addr]);
      set_rst(VPP);
      if (micro_controller_model!=4) wait(0.05);
      pulse_nprog();
      if (micro_controller_model!=4) wait(0.05);
      set_rst(VIH);
      if(wait_rdy())
      {
        printf("\n\007* ALL03 Error - Timeout in writing flash at address %04x!\n",addr);
        goto write_flash_q;
      }
      wr_fpm(COMMAND_READ_CODE_DATA);
      if(rd_data()!=flash[addr])
      {
        pc++;
        if(pc>20) notprog=0;
      }
      else notprog=0;
    }
    inc_address();
  }

  chip_init();
  printf("VERIFYING...            \n");
  err=0;
  wr_fpm(COMMAND_READ_CODE_DATA);
  for(addr=0; addr<max_flash_addr; addr++)
  {
    printf("Address: %04X\r", addr);
    if((aflash[addr]=rd_data())!=flash[addr]) err++;
    inc_address();
  }

write_flash_q:

  all03_init_h();
  //printf("\n");
  if(err) printf("Errors: %d          \n",err);
  else    printf("OK!                 \n");
  if(err) dump_diff(flash, aflash, max_flash_addr);
  msg_wait_enter();
}

/*
 *  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);    
    flash[addr]=rd_data();
    inc_address();
  }

  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);
    if(rd_data()!=0xff) err++;
    inc_address();
  }

  all03_init_h();
  printf("\n");
  if(err) printf("Flash not blank - %d errors!\n", err);
  else printf("Flash is blank\n");
  msg_wait_enter();
}

void dump_diff(unsigned char *buf, unsigned char *abuf, unsigned short int m)
{
  unsigned short int i, l;

  l=0;
  for(i=0;i<m;i++)
  {
    if(buf[i]!=abuf[i])
    {
      printf("%04X: %02X %02X\n",i,buf[i],abuf[i]);
      l++;
    }
    if(l>PAGE_LEN)
    {
      printf("Press Q to quit <Enter> to continue:");
      l=key_get();
      if((l='q') || (l=='Q'))
      {
        printf("\n");
        return;
      }
      printf("\n");
      l=0;
    }
  }
}

/*
 *  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);
    if((aflash[addr]=rd_data())!=flash[addr]) err++;
    inc_address();
  }

  all03_init_h();
  printf("\n");

  if(err) printf("Errors: %d\n",err);
  else printf("No errors!\n");
  if(err) dump_diff(flash, aflash,max_flash_addr);
  msg_wait_enter();
}

/* 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: 89CX051 [<option>] [<file_name>]\n");
  printf("option\n");
  printf(" -s, -S        skip processor speed test\n");
  printf(" -10, -20, -40 set microcontroller type\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();
  set_model_at89c2051();

  ac=argc-1;
  skip=0;
  while(ac)
  {
    if     (!strcmp(argv[ac],"-s") || !strcmp(argv[ac],"-S")) skip=1;
    else if(!strcmp(argv[ac],"-10")) set_model_at89c1051();
    else if(!strcmp(argv[ac],"-20"))  set_model_at89c2051();
    else if(!strcmp(argv[ac],"-40"))  set_model_at89c4051();
    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("***********  AT89CX051 PROGRAMMING MODULE\n");
    printf("** ALL03 **  "); print_version(); printf("\n");
    printf("***********  by FaSt\n");
    printf("\n");
    print_model();
    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();
         msg_wait_enter();
      break;
      case '3':
        write_flash_buf_to_file();
        msg_wait_enter();
      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);
}

