/**********************************************************************/
/*                                                                    */
/* File name: PP18.cpp                                                */
/*                                                                    */
/* Since:     2002/12/01                                              */
/*                                                                    */
/* Version:   2.02                                                     */
/*                                                                    */
/* Author:    MONTAGNE Xavier [XM] {link xavier.montagne@wanadoo.fr}  */
/*                                                                    */
/* Purpose: File containing all the functions of the Main Window.     */
/*          All the functionnalities(except those included in the DLL)*/
/*          are located in this file.                                 */
/*                                                                    */
/* Distribution: This file is part of PP18.                           */
/*               PP18 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, or (at your option)    */
/*               any later version.                                   */
/*                                                                    */
/*               PP18 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 PP18; see the file         */
/*               COPYING.txt. If not, write to the Free Software      */
/*               Foundation, 59 Temple Place - Suite 330,             */
/*               Boston, MA 02111-1307, USA.                          */
/*                                                                    */
/* History:                                                           */
/*      2002/12/01  [XM] Create this file                             */
/*      2002/12/03  [XM] Modify SelectPICClick to display the Filename*/
/*                       of the DLL into the StatusBar.               */
/*                       Modify ScrollBar1Change to manage any memory */
/*                       size of PIC18.                               */
/*                       Modify SpeedButton4Click to allow PopupMenu  */
/*                       to display Configuration menu item.          */
/*      2003/05/01  [XM] Adapt PP18 for Nano Technology PIC18 family  */
/*                       Added verif processing after programming     */
/*                       Added commentaries in StatusBar (chip access)*/
/*      2003/07/24  [XM] Added new way to verify if the WRITE failed  */
/*      2003/12/29  [XM] Changed the autodetect behavior :            */
/*                        - if enabled  => timer2 detects the chip    */
/*                        - if disabled => chip concidered as detected*/
/*      2003/12/29  [XM] Added an autorun after programing (LVP mode).*/
/*                                                                    */
/**********************************************************************/

/***********************************************************************
 * INCLUDES
 **********************************************************************/
#include <vcl.h>
#include <alloc.h>
#include <vcl\Registry.hpp>

#include "PP18.h"
#include "DLL_interface.h"
#pragma hdrstop

/***********************************************************************
 * Function prototypes.
 **********************************************************************/
void EnterCritical(void);
void ExitCritical(void);
void InitializeInterface(HINSTANCE dllInstance);
unsigned char HexToChar(unsigned char H_val, unsigned char L_val);
unsigned char HexaConvert(unsigned char value);
void OpenDLL(AnsiString a_string);

/***********************************************************************
 * Global variables.
 **********************************************************************/
#pragma package(smart_init)
#pragma resource "*.dfm"
TMainWindow *MainWindow;

extern TForm *AboutWindow;

unsigned short *usMemoryPIC;
unsigned short *usMemoryFile;
unsigned short *usMemory;

HINSTANCE dllInstance;
static TRegistry *regKey;

static unsigned int action;

/***********************************************************************
 * Initialyse the content of the grid containing memory data.
 * Entry of the application.
 *
 * @param  TComponent* Owner  IN  Parent object reference
 * @return none
 **********************************************************************/
__fastcall TMainWindow::TMainWindow(TComponent* Owner)
    : TForm(Owner)
{
    unsigned short index;

    StringGrid1->ColWidths[0]  = 67;
    StringGrid1->RowHeights[0] = 16;

    for (index = 0; index < 8; index++)
    {
        StringGrid1->Cells[index+1][0] = " W" + IntToStr(index+1);
        StringGrid1->ColWidths[index+1] = 40;
    }

    StringGrid1->ColWidths[9] = 134;
    StringGrid1->Cells[9][0] = "     ASCII";

    for (index = 0; index < StringGrid1->RowCount - 1; index++)
        StringGrid1->Cells[0][index+1] = ("0x" + IntToHex(index*8*2, 5));

    ScrollBar1->Max = (0x4000 / (8*8)) - 1;
    ScrollBar1->Min = 0;
    ScrollBar1->Enabled = false;

    usMemory = NULL;
    usMemoryPIC = NULL;
    usMemoryFile = NULL;

    regKey = new TRegistry();
    if ( (regKey->OpenKey("\\Software\\PP18", false)) && \
         (regKey->ReadString("release") == "PP18 v2.02") )
    {
      regKey->OpenKey("\\Software\\PP18", false);
    }
    else
    {
      regKey->CreateKey("\\Software\\PP18");
      regKey->CreateKey("\\Software\\PP18\\MainWindow");
      regKey->CreateKey("\\Software\\PP18\\DLL");
      regKey->CreateKey("\\Software\\PP18\\DLL\\Settings");

      regKey->OpenKey("\\Software\\PP18", false);
      regKey->WriteString("release", "PP18 v2.02");
      regKey->WriteString("author", "Xavier MONTAGNE");

      regKey->OpenKey("\\Software\\PP18\\MainWindow", false);
      regKey->WriteString("open", "");
      regKey->WriteString("save", "");

      regKey->OpenKey("\\Software\\PP18\\DLL", false);
      regKey->WriteString("filename", "");

      regKey->WriteString("autorun", "NO");

      regKey->OpenKey("\\Software\\PP18\\DLL\\Settings", false);
      regKey->WriteInteger("CLOCK_MASK", 0x02);
      regKey->WriteInteger("DATA_FROM_PIC_MASK", 0x80);
      regKey->WriteInteger("DATA_TO_PIC_MASK", 0x01);
      regKey->WriteInteger("VPP_MASK", 0x04);
      regKey->WriteInteger("VCC_MASK", 0x08);
      regKey->WriteInteger("CLOCK_INV", 0x20);
      regKey->WriteInteger("DATA_FROM_PIC_INV", 0x10);
      regKey->WriteInteger("DATA_TO_PIC_INV", 0x20);
      regKey->WriteInteger("VPP_INV", 0x10);
      regKey->WriteInteger("VCC_INV", 0x10);
      regKey->WriteInteger("DelayIO", 0xFF);
      regKey->WriteInteger("DelayProg", 0x10);
      regKey->WriteInteger("LPT_port_@", 0x0378);
    }

    MainWindow->Show();
    regKey->OpenKey("\\Software\\PP18\\DLL", false);
    if (regKey->ReadString("filename") != "")
      OpenDLL(regKey->ReadString("filename"));

    action = ACTION_READ;
}

/***********************************************************************
 * Action executed by the LOAD button.
 * Parse the HEX file selected, get the memory, the ID and the Checksum.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void               
 **********************************************************************/
void __fastcall TMainWindow::SB_loadClick(TObject *Sender)
{
  char filename[256];
  unsigned int uiSize;
  unsigned char ID_loop;
  unsigned short Checksum;
  unsigned char Value;

  EnterCritical();

  OpenDialog1->Filter = "*.hex|*.hex";
  regKey->OpenKey("\\Software\\PP18\\MainWindow", false);
  OpenDialog1->FileName = regKey->ReadString("open");
  OpenDialog1->Title = "Select an HEX file";
  if (OpenDialog1->Execute())
  {
    regKey->WriteString("open", OpenDialog1->FileName);
    strcpy(filename, OpenDialog1->FileName.c_str());
    StatusBar1->Panels->Items[1]->Text = "OPENING : " + OpenDialog1->FileName;

    ScrollBar1->Position = 0;

    if (ParseFile(filename) == FILE_ERROR)
    {
      Application->MessageBox("File corrupted or not dedicated to this chip !", \
                              "Hex file error", MB_ICONERROR + MB_OK);
      return;
    }
    GetMemorySize(&uiSize, FromFile);

    if (usMemoryFile != NULL)
      free(usMemoryFile);
    usMemoryFile = (unsigned short*)(malloc(uiSize * sizeof(unsigned short)));
    GetMemoryBuffer(usMemoryFile, FromFile);

    usMemory = usMemoryFile;
    ScrollBar1->Enabled = true;    
    ScrollBar1->Max = (uiSize / (8*8)) - 1;
    MainWindow->ScrollBar1Change(Sender);

    SB_save->Enabled = true;
    SB_upload->Enabled = true;
    DisplayCombo->Enabled = true;
    DisplayCombo->ItemIndex = 0;

    ComputeGeneralChecksum(&Checksum, FromFile);
    ChecksumCaption->Caption = "0x" + IntToHex(Checksum, 4);
    IDEdit->Text = "";
    for (ID_loop = 0; ID_loop < 8; ID_loop++)
    {
      GetIDValue(&Value, ID_loop, FromFile);
      IDEdit->Text = IDEdit->Text + IntToHex(Value, 2);
    }
    IDEdit_tmp->Text = IDEdit->Text;
    PopupMenu1->Items->Items[1]->Enabled = true;
  }

  ExitCritical();
}

/***********************************************************************
 * Quit the application.
 * See the FormClose() function for the rest of actions.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void
 **********************************************************************/
void __fastcall TMainWindow::SB_exitClick(TObject *Sender)
{
  Application->Terminate();
}

/***********************************************************************
 * Action executed by the SAVE button.
 * Save the PIC or FILE buffer into the selected file.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void
 **********************************************************************/
void __fastcall TMainWindow::SB_saveClick(TObject *Sender)
{
  char filename[256];

  EnterCritical();

  SaveDialog1->DefaultExt = "HEX";
  regKey->OpenKey("\\Software\\PP18\\MainWindow", false);
  SaveDialog1->FileName = regKey->ReadString("save");
  SaveDialog1->Title = "Save the selected buffer as HEX file";
  if (SaveDialog1->Execute())
  {
    regKey->WriteString("save", SaveDialog1->FileName);
    strcpy(filename, SaveDialog1->FileName.c_str());
    StatusBar1->Panels->Items[1]->Text = "SAVING  : " + SaveDialog1->FileName;
  }
  else
  {
    ExitCritical();
    return;
  }

  if (DisplayCombo->ItemIndex == 0)
  {
    SetMemoryBuffer(usMemory, FromFile);
    if (UnParseFile(filename, FromFile) == FILE_ERROR)
    {
      Application->MessageBox("Not able to creat or save the file !", \
                              "Hex file error", MB_ICONERROR + MB_OK);
      return;
    }
  }
  
  if (DisplayCombo->ItemIndex == 1)
  {
    SetMemoryBuffer(usMemory, FromPIC);
    if (UnParseFile(filename, FromPIC) == FILE_ERROR)
    {
      Application->MessageBox("Not able to creat or save the file !", \
                              "Hex file error", MB_ICONERROR + MB_OK);
      return;
    }
  }

  ExitCritical();
}

/***********************************************************************
 * Call everytime the ScrollBar is clicked.
 * Update the content of the Memory Grid.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void
 **********************************************************************/
void __fastcall TMainWindow::ScrollBar1Change(TObject *Sender)
{
    unsigned short index;
    unsigned int start, adress, size;
    unsigned char ascii_str[16];
    String string1;
    int I, J;

    start = ScrollBar1->Position * 8 * 8;
    if (usMemory == usMemoryPIC)
      GetMemorySize(&size, FromPIC);
    else
      GetMemorySize(&size, FromFile);

    for (index = 0; index < StringGrid1->RowCount - 1; index++)
    {
      adress = start + index*8;
      if (adress < size)
        StringGrid1->Cells[0][index+1] = ("0x" + IntToHex(int(adress*2), 5));
      else
        StringGrid1->Cells[0][index+1] = "";

      I = index + 1;
      StringGrid1->Cells[StringGrid1->ColCount-1][I] = "";
      for (J = 1; J < StringGrid1->ColCount - 1; J++)
      {
        if ((adress+J-1) < size)
        {
           StringGrid1->Cells[J][I] = ("" + IntToHex(usMemory[(adress+J-1)], 4));
           ascii_str[(J*2)-2] = (unsigned char)(usMemory[(adress+J-1)] & 0x00FF);
           ascii_str[(J*2)-1] = (unsigned char)((usMemory[(adress+J-1)] & 0xFF00) >> 8);
        }
        else
           StringGrid1->Cells[J][I] = "";
      }

      for (J = 0; J < 16; J++)
      {
        if ((ascii_str[J] < 0x20) || (ascii_str[J] > 0x7E))
        StringGrid1->Cells[StringGrid1->ColCount-1][I] = \
          StringGrid1->Cells[StringGrid1->ColCount-1][I] + ".";
        else
        StringGrid1->Cells[StringGrid1->ColCount-1][I] = \
          StringGrid1->Cells[StringGrid1->ColCount-1][I] + \
          string1.StringOfChar(ascii_str[J], 1);
        if ((adress) >= size)
           StringGrid1->Cells[StringGrid1->ColCount-1][I] = "";
      }
    }
}

/***********************************************************************
 * Not used.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void               
 **********************************************************************/
void __fastcall TMainWindow::SelectHWClick(TObject *Sender)
{
  OpenDialog1->Filter = "*.dll|*.dll";

  if (OpenDialog1->Execute())
  {
    StatusBar1->Panels->Items[1]->Text = "SCHAER+";
    PopupMenu1->Items->Items[0]->Enabled = true;
    PopupMenu1->Items->Items[4]->Enabled = true;
    PopupMenu1->Items->Items[5]->Enabled = false;
  }
}

/***********************************************************************
 * Load the selected DLL into RAM.
 * Initialize the interface by calling InitializeInterface().
 * Check if hardware is present.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void
 **********************************************************************/
void __fastcall TMainWindow::SelectPICClick(TObject *Sender)
{
  OpenDialog1->Filter = "*.dll|*.dll";
  regKey->OpenKey("\\Software\\PP18\\DLL", false);
  OpenDialog1->FileName = regKey->ReadString("filename");

  if (OpenDialog1->Execute())
  {
    OpenDLL(OpenDialog1->FileName);
    regKey->WriteString("filename", OpenDialog1->FileName);
  }
}

/***********************************************************************
 * Open the DLL.
 *
 * @param  AnsiString a_string IN  Path and filename of the DLL
 * @return void
 **********************************************************************/
void OpenDLL(AnsiString a_string)
{
  char filename[256], delimiter;

  delimiter = (char)(a_string.LastDelimiter("\\" ));
  strcpy(filename, a_string.c_str());
  strcpy(filename, &filename[delimiter]);
  MainWindow->StatusBar1->Panels->Items[0]->Text = "DLL : " + (AnsiString)(filename);

  strcpy(filename, a_string.c_str());
  if (ShowDLL != NULL)
    FreeLibrary(dllInstance);
  dllInstance = LoadLibrary(filename);
  InitializeInterface(dllInstance);
  if (ShowDLL != NULL)
  {
    ShowDLL(Application->Handle);
    MainWindow->SB_load->Enabled = true;
    MainWindow->PopupMenu1->Items->Items[4]->Enabled = true;
    MainWindow->PopupMenu1->Items->Items[4]->Checked = true;

    InitHardware();
    MainWindow->PopupMenu1->Items->Items[0]->Enabled = true;
  }
  else
  {
    MainWindow->PopupMenu1->Items->Items[0]->Enabled = false;
    MainWindow->SB_load->Enabled = false;
    MainWindow->PopupMenu1->Items->Items[4]->Enabled = false;
    MainWindow->PopupMenu1->Items->Items[4]->Checked = false;
    FreeLibrary(dllInstance);
    Application->MessageBox \
     ("             DLL interface error !\n Download a newer version of the DLL.", \
      "DLL message ...", MB_ICONERROR + MB_OK);
  }
}

/***********************************************************************
 * Download all the data from the PIC (memory + ID loc + config).
 * Display the result into the Main Window.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void               
 **********************************************************************/
void __fastcall TMainWindow::SB_downloadClick(TObject *Sender)
{
  unsigned int uiSize;
  unsigned short Checksum;
  unsigned char Value;
  unsigned char ID_loop;
  Status_t Result;

  EnterCritical();

  StatusBar1->Panels->Items[1]->Text = "CHIP ACCESS :   READING ";

  /* The WRITE process check the memory then we don't need to reload */
  if (action == ACTION_WRITE)
  {
    action = ACTION_READ;
    GetMemorySize(&uiSize, FromPIC);

    /* From FILE to PIC */
    if (DisplayCombo->ItemIndex == 0)
    {
      if (usMemoryPIC != NULL)
        free(usMemoryPIC);
      usMemoryPIC = (unsigned short*)(malloc(uiSize * sizeof(unsigned short)));
      /* We copy the PP18 FILE buffer into the DLL PIC buffer */
      GetMemoryBuffer(usMemoryPIC, FromFile);
      SetMemoryBuffer(usMemoryPIC, FromPIC);
      usMemory = usMemoryPIC;
    }
    /* From PIC to PIC */
    /* Do nothing ... */
  }
  else
  {
    InitHardware();
    PowerOn();
    Result = ReadMem();
    if (Result == BLANK)
    {
      Application->MessageBox("Device is blanked !", "DLL message ...", \
                               MB_ICONEXCLAMATION + MB_OK);
    }

    if (Result == 10) /* ABORTED */
    {
      StatusBar1->Panels->Items[1]->Text = "CHIP ACCESS :   ABORTED ";
      action = ACTION_READ;
      return;
    }

    GetMemorySize(&uiSize, FromPIC);

    if (usMemoryPIC != NULL)
      free(usMemoryPIC);
    usMemoryPIC = (unsigned short*)(malloc(uiSize * sizeof(unsigned short)));
    GetMemoryBuffer(usMemoryPIC, FromPIC);
    usMemory = usMemoryPIC;
  }

  InitHardware();
  PowerOn();
  if (ReadConfig() == LOCKED)
  {
    Application->MessageBox("    Device is locked  !   ", "DLL message ...", \
                             MB_ICONEXCLAMATION + MB_OK);
  }
  ReadID();
  PowerOff();

  StatusBar1->Panels->Items[1]->Text = "CHIP ACCESS :   READ COMPLETE ";

  ComputeGeneralChecksum(&Checksum, FromPIC);
  ChecksumCaption->Caption = "0x" + IntToHex(Checksum, 4);

  IDEdit->Text = "";
  for (ID_loop = 0; ID_loop < 8; ID_loop++)
  {
    GetIDValue(&Value, ID_loop, FromPIC);
    IDEdit->Text = IDEdit->Text + IntToHex(Value, 2);
  }
  IDEdit_tmp->Text = IDEdit->Text;

  ScrollBar1->Enabled = true;
  ScrollBar1->Max = (uiSize / (8*8)) - 1;
  ScrollBar1Change(Sender);
  DisplayCombo->Enabled = true;
  DisplayCombo->ItemIndex = 1;
  SB_save->Enabled = true;
  SB_upload->Enabled = true;
  PopupMenu1->Items->Items[1]->Enabled = true;

  ExitCritical();
}

/***********************************************************************
 * Activate the About timer (Timer1).
 * This one calls the SplashScreen for 3 secondes.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void               
 **********************************************************************/
void __fastcall TMainWindow::AboutClick(TObject *Sender)
{
  MainWindow->Enabled = false;
  EnterCritical();
  Timer1->Enabled = true;
}

/***********************************************************************
 * Show the SplashScreen for 3 secondes as a modal window.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void               
 **********************************************************************/
void __fastcall TMainWindow::Timer1Timer(TObject *Sender)
{
  static int open_close = 0;

  if (open_close == 0)
  {
    Timer1->Interval = 5000;
    Timer1->Enabled = true;
    AboutWindow->Show();
    open_close = 1;
  }
  else
  {
    Timer1->Enabled = false;
    Timer1->Interval = 100;
    AboutWindow->Close();
    MainWindow->Enabled = true;
    open_close = 0;
    ExitCritical();
  }
}

/***********************************************************************
 * Switch ON / OFF the Autodetect mode (Timer2).
 * This mode detects the present of a PIC18 on the hardware programmer.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void
 **********************************************************************/
void __fastcall TMainWindow::AutotectPICClick(TObject *Sender)
{
  if (PopupMenu1->Items->Items[4]->Checked == false)
  {
    Timer2->Enabled = true;
    PopupMenu1->Items->Items[4]->Checked = true;
    PopupMenu1->Items->Items[5]->Enabled = false;
  }
  else
  {
    Timer2->Enabled = false;
    PopupMenu1->Items->Items[4]->Checked = false;
    PopupMenu1->Items->Items[5]->Enabled = true;
    PopupMenu1->Items->Items[3]->Enabled = true;
    SB_download->Enabled = true;
    SB_upload->Enabled = true;
  }
}

/***********************************************************************
 * Toggle the RunStart feature.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void
 **********************************************************************/
void __fastcall TMainWindow::AutorunPICClick(TObject *Sender)
{
  if (AutorunPIC->Checked == true)
  {
    AutorunPIC->Checked = false;
    PopupMenu1->Items->Items[4]->Enabled = true;
    regKey->WriteString("autorun", "NO");
  }
  else
  {
    AutorunPIC->Checked = true;
    PopupMenu1->Items->Items[4]->Checked = false;
    PopupMenu1->Items->Items[4]->Enabled = false;
    regKey->WriteString("autorun", "YES");
  }
}

/***********************************************************************
 * Update the content of the Main Window according to the user choise.
 * Calls the ScrollBar1Change() function.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void               
 **********************************************************************/
void __fastcall TMainWindow::DisplayComboChange(TObject *Sender)
{
  unsigned short Checksum;
  unsigned char Value;
  unsigned char ID_loop;
  EnterCritical();

  if (DisplayCombo->ItemIndex == 0)
  {
    if (usMemoryFile != NULL)
    {
      usMemory = usMemoryFile;
      ComputeGeneralChecksum(&Checksum, FromFile);
      ChecksumCaption->Caption = "0x" + IntToHex(Checksum, 4);
      IDEdit->Text = "";
      for (ID_loop = 0; ID_loop < 8; ID_loop++)
      {
        GetIDValue(&Value, ID_loop, FromFile);
        IDEdit->Text = IDEdit->Text + IntToHex(Value, 2);
      }
      IDEdit_tmp->Text = IDEdit->Text;
    }
    else
      DisplayCombo->ItemIndex = 1;
    MainWindow->ScrollBar1Change(Sender);
  }
  else
  {
    if (usMemoryPIC != NULL)
    {
      usMemory = usMemoryPIC;
      ComputeGeneralChecksum(&Checksum, FromPIC);
      ChecksumCaption->Caption = "0x" + IntToHex(Checksum, 4);
      IDEdit->Text = "";
      for (ID_loop = 0; ID_loop < 8; ID_loop++)
      {
        GetIDValue(&Value, ID_loop, FromPIC);
        IDEdit->Text = IDEdit->Text + IntToHex(Value, 2);
      }
      IDEdit_tmp->Text = IDEdit->Text;
    }
    else
      DisplayCombo->ItemIndex = 0;
    MainWindow->ScrollBar1Change(Sender);
  }

  ExitCritical();
}

/***********************************************************************
 * Process a verification of the REV & DEV number of the PIC18 inserted.
 * If the numbers match then the DLL return PIC_DETECTED.
 * This is done every 0.5 secondes.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void
 **********************************************************************/
void __fastcall TMainWindow::Timer2Timer(TObject *Sender)
{
  unsigned unsigned int uiDetected;
  char PICname[10];

  if (PopupMenu1->Items->Items[4]->Checked == false)
    return;

  InitHardware();
  if (IsHWPresent() != HARDWARE_ERROR)
  {
    MainWindow->StatusBar1->Panels->Items[2]->Text = "HW detected";
  }
  else
  {
    MainWindow->StatusBar1->Panels->Items[2]->Text = "HW not detected";
  }

  InitHardware();
  PowerOn();
  if (ReadRevDev(PICname) == PIC_DETECTED)
    uiDetected = 1;
  else
    uiDetected = 0;
  PowerOff();

  if (uiDetected)
  {
    Image2->Visible = true;
    Image1->Visible = false;
    if ((usMemoryFile != NULL) || (usMemoryPIC != NULL))
      SB_upload->Enabled = true;
    SB_download->Enabled = true;
    PopupMenu1->Items->Items[3]->Enabled = true;
    PopupMenu1->Items->Items[4]->Enabled = true;
    PopupMenu1->Items->Items[5]->Enabled = true;
  }
  else
  {
    Image1->Visible = true;
    Image2->Visible = false;
    SB_download->Enabled = false;
    SB_upload->Enabled = false;
    PopupMenu1->Items->Items[3]->Enabled = false;
    PopupMenu1->Items->Items[4]->Enabled = false;
    PopupMenu1->Items->Items[5]->Enabled = false;
  }
}

/***********************************************************************
 * Upload the current content of the Main Window to the PIC18 detected.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void
 **********************************************************************/
void __fastcall TMainWindow::SB_uploadClick(TObject *Sender)
{
  AnsiString string;
  Status_t Result;

  action = ACTION_WRITE;

  string = ChecksumCaption->Caption;

  EnterCritical();
  StatusBar1->Panels->Items[1]->Text = "CHIP ACCESS :   WRITING ";

  InitHardware();
  PowerOn();

  /* Multiple PowerOn / PowerOff to manage
   * nano Watt Technology PIC18
   */
  if (DisplayCombo->ItemIndex == 0)
  {
    Result = ProgramMem(FromFile);
    PowerOff();
    InitHardware();
    PowerOn();
    ProgramConfig(FromFile);
    PowerOff();
    InitHardware();
    PowerOn();
    ProgramID(FromFile);
  }
  else
  {
    Result = ProgramMem(FromPIC);
    PowerOff();
    InitHardware();
    PowerOn();
    ProgramConfig(FromPIC);
    PowerOff();
    InitHardware();
    PowerOn();
    ProgramID(FromPIC);
  }
  PowerOff();
  ExitCritical();

  if (Result == 10) /* ABORTED */
  {
    StatusBar1->Panels->Items[1]->Text = "CHIP ACCESS :   ABORTED ";
    action = ACTION_READ;
    return;
  }

  SB_downloadClick(Sender);

  /* Check if the memory transfer complete successfully */
  StatusBar1->Panels->Items[1]->Text = "CHIP ACCESS :   VERIFYING ";

  if (Result == BAD_PROGRAMMED)
  {
     Application->MessageBox \
     ("Verification failed !\n Check hardware please.", \
      "DLL message ...", MB_ICONERROR + MB_OK);

     /* The final result is displayed in a message box */
     StatusBar1->Panels->Items[1]->Text = "CHIP ACCESS :   WRITE FAILED ";
  }
  else
  {
     Application->MessageBox \
     ("Device successfully programmed !", \
      "DLL message ...", MB_ICONWARNING + MB_OK);

     /* The final result is displayed in a message box */
     StatusBar1->Panels->Items[1]->Text = "CHIP ACCESS :   WRITE COMPLETE ";

     if (PopupMenu1->Items->Items[5]->Checked == true)
     {
       EnterCritical();
       RunTarget();
       ExitCritical();
     }
  }
}

/***********************************************************************
 * Deny the TIMER2 access to the chip.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void
 **********************************************************************/
void EnterCritical(void)
{
  if (MainWindow->Timer2->Enabled == true)
    MainWindow->Timer2->Tag = true;
  MainWindow->Timer2->Enabled = false;
}

/***********************************************************************
 * Allow periodical access to the chip (TIMER2).
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void
 **********************************************************************/
void ExitCritical(void)
{
  if (MainWindow->Timer2->Tag == true)
    MainWindow->Timer2->Enabled = true;
  MainWindow->Timer2->Tag = false;
}

/***********************************************************************
 * Call the Settings Window of the DLL.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void
 **********************************************************************/
void __fastcall TMainWindow::settingsClick(TObject *Sender)
{
  EnterCritical();
  ShowSettings(Application->Handle);
  ExitCritical();
}

/***********************************************************************
 * Disable the timers and free the allocated memories.
 *
 * @param  TObject *Sender      IN  Caller object reference
 * @param  TCloseAction &Action IN  Action object reference
 * @return void
 **********************************************************************/
void __fastcall TMainWindow::FormClose(TObject *Sender, TCloseAction &Action)
{
  EnterCritical();
  Timer1->Enabled = false;
  Timer2->Enabled = false;
  if (InitHardware != NULL)
  {
    InitHardware();
    FreeLibrary(dllInstance);
  }
  free(usMemoryPIC);
  free(usMemoryFile);
  delete regKey;
}

/***********************************************************************
 * Call the Configuration Window of the DLL.
 *
 * @param  TObject *Sender      IN  Caller object reference
 * @return void
 **********************************************************************/
void __fastcall TMainWindow::configClick(TObject *Sender)
{
  unsigned short Checksum;
  
  EnterCritical();
  if (DisplayCombo->ItemIndex == 0)
  {
    ShowConfig(Application->Handle, FromFile);
    ComputeGeneralChecksum(&Checksum, FromFile);
    ChecksumCaption->Caption = "0x" + IntToHex(Checksum, 4);
  }
  else
  {
    ShowConfig(Application->Handle, FromPIC);
    ComputeGeneralChecksum(&Checksum, FromPIC);
    ChecksumCaption->Caption = "0x" + IntToHex(Checksum, 4);
  }
  ExitCritical();
}

/***********************************************************************
 * Erase all the programmable bits of the PIC18.
 *
 * @param  TObject *Sender    IN  Caller object reference
 * @return void
 **********************************************************************/
void __fastcall TMainWindow::EraseClick(TObject *Sender)
{
  EnterCritical();
  InitHardware();
  PowerOn();
  BulkErase(Application->Handle);
  PowerOff();
  SB_downloadClick(Sender);
  ExitCritical();
}

/***********************************************************************
 * Update the ID values displayed at the Main Window.
 *
 * @param  TObject *Sender      IN  Caller object reference
 * @return void
 **********************************************************************/
void __fastcall TMainWindow::IDEditChange(TObject *Sender)
{
  unsigned char ID_index;
  unsigned char ID_value[16];
  unsigned short Checksum;

  if (IDEdit->Modified == false)
    return;

  memcpy(ID_value, (IDEdit->Text).c_str(), 16);

  for (ID_index = 0; ID_index < 16; ID_index++)
  {
    if (((ID_value[ID_index] >= '0') && (ID_value[ID_index] <= '9')) ||
        ((ID_value[ID_index] >= 'a') && (ID_value[ID_index] <= 'z')) ||
        ((ID_value[ID_index] >= 'A') && (ID_value[ID_index] <= 'Z')) )
    {
  //    continue;
    }
    else
    {
      IDEdit->Text = IDEdit_tmp->Text;
      return;
    }
  }

  for (ID_index = 0; ID_index < 16; ID_index = (unsigned char)(ID_index + 2))
  {
    if (DisplayCombo->ItemIndex == 0)
    {
      SetIDValue((unsigned char)(ID_index/2), \
                 HexToChar(ID_value[ID_index], ID_value[ID_index+1]), FromFile);
      ComputeGeneralChecksum(&Checksum, FromFile);
      ChecksumCaption->Caption = "0x" + IntToHex(Checksum, 4);
    }
    if (DisplayCombo->ItemIndex == 1)
    {
      SetIDValue((unsigned char)(ID_index/2), \
                 HexToChar(ID_value[ID_index], ID_value[ID_index+1]), FromPIC);
      ComputeGeneralChecksum(&Checksum, FromPIC);
      ChecksumCaption->Caption = "0x" + IntToHex(Checksum, 4);
    }
  }

  IDEdit_tmp->Text = IDEdit->Text;
}

/***********************************************************************
 * Convert a HEX string (0xFF) into a char (255).
 *
 * @param  u_char H_val       IN  Upper bits of the 8 bits word
 * @param  u_char L_val       IN  Lower bits of the 8 bits word
 * @return unsigned char          Result of the process
 **********************************************************************/
unsigned char HexToChar(unsigned char H_val, unsigned char L_val)
{
  unsigned char result;

  result = (unsigned char)((HexaConvert(H_val) << 4) + HexaConvert(L_val));
  return(result);
}

/***********************************************************************
 * Convert the ASCII format into a decimal number ('F' -> 15).
 *
 * @param  u_char value       IN  Value in ASCII format
 * @return void
 **********************************************************************/
unsigned char HexaConvert(unsigned char value)
{
  if ((value >= '0') && (value <= '9'))
	return ((unsigned char)(value - '0'));
  if ((value >= 'a') && (value <= 'f'))
  	return ((unsigned char)(value - 'a' + 10));
  if ((value >= 'A') && (value <= 'F'))
  	return ((unsigned char)(value - 'A' + 10));

  return(value);
}

/***********************************************************************
 * Initialize the interface between the Main Window and the specific
 * PIC18 functions located in a DLL.
 *
 * @param  HINSTANCE dllInstance IN  Reference of the selected DLL
 * @return void
 **********************************************************************/
void InitializeInterface(HINSTANCE dllInstance)
{
  ShowDLL = (Status_t(*)(HWND)) \
             GetProcAddress(dllInstance, "_ShowDLL");
    
  ParseFile = (Status_t(*)(char *)) GetProcAddress(dllInstance, "_ParseFile");
  if (ParseFile == NULL)
    ShowDLL = NULL;

  GetMemorySize = (Status_t(*)(unsigned int *, unsigned int)) \
                   GetProcAddress(dllInstance, "_GetMemorySize");
  if (GetMemorySize == NULL)
    ShowDLL = NULL;

  GetMemoryBuffer = (Status_t(*)(unsigned short *, unsigned int)) \
                     GetProcAddress(dllInstance, "_GetMemoryBuffer");
  if (GetMemoryBuffer == NULL)
    ShowDLL = NULL;

  SetMemoryBuffer = (Status_t(*)(unsigned short *, unsigned int)) \
                     GetProcAddress(dllInstance, "_SetMemoryBuffer");
  if (SetMemoryBuffer == NULL)
    ShowDLL = NULL;

  UnParseFile = (Status_t(*)(char *, unsigned int)) \
                 GetProcAddress(dllInstance, "_UnParseFile");
  if (UnParseFile == NULL)
    ShowDLL = NULL;

  ProgramMem = (Status_t(*)(unsigned int)) \
                GetProcAddress(dllInstance, "_ProgramMem");
  if (ProgramMem == NULL)
    ShowDLL = NULL;

  ProgramConfig = (Status_t(*)(unsigned int)) \
                   GetProcAddress(dllInstance, "_ProgramConfig");
  if (ProgramConfig == NULL)
    ShowDLL = NULL;

  ProgramID = (Status_t(*)(unsigned int)) \
               GetProcAddress(dllInstance, "_ProgramID");
  if (ProgramID == NULL)
    ShowDLL = NULL;

  ReadMem = (Status_t(*)(void)) \
             GetProcAddress(dllInstance, "_ReadMem");
  if (ReadMem == NULL)
    ShowDLL = NULL;

  ReadConfig = (Status_t(*)(void)) \
                GetProcAddress(dllInstance, "_ReadConfig");
  if (ReadConfig == NULL)
    ShowDLL = NULL;

  ReadID = (Status_t(*)(void)) \
            GetProcAddress(dllInstance, "_ReadID");
  if (ReadID == NULL)
    ShowDLL = NULL;

  ReadRevDev = (Status_t(*)(char *)) \
                GetProcAddress(dllInstance, "_ReadRevDev");
  if (ReadRevDev == NULL)
    ShowDLL = NULL;

  GetIDValue = (Status_t(*)(unsigned char *, unsigned char, unsigned int)) \
                GetProcAddress(dllInstance, "_GetIDValue");
  if (GetIDValue == NULL)
    ShowDLL = NULL;

  SetIDValue = (Status_t(*)(unsigned char, unsigned char, unsigned int)) \
                GetProcAddress(dllInstance, "_SetIDValue");
  if (SetIDValue == NULL)
    ShowDLL = NULL;

  ComputeGeneralChecksum = (Status_t(*)(unsigned short *, unsigned int)) \
                            GetProcAddress(dllInstance, "_ComputeGeneralChecksum");
  if (ComputeGeneralChecksum == NULL)
    ShowDLL = NULL;

  IsHWPresent = (Status_t(*)(void)) \
                 GetProcAddress(dllInstance, "_IsHWPresent");
  if (IsHWPresent == NULL)
    ShowDLL = NULL;

  InitHardware = (Status_t(*)(void)) \
                  GetProcAddress(dllInstance, "_InitHardware");
  if (InitHardware == NULL)
    ShowDLL = NULL;

  PowerOn = (Status_t(*)(void)) \
             GetProcAddress(dllInstance, "_PowerOn");
  if (PowerOn == NULL)
    ShowDLL = NULL;

  PowerOff = (Status_t(*)(void)) \
              GetProcAddress(dllInstance, "_PowerOff");
  if (PowerOff == NULL)
    ShowDLL = NULL;

  ShowSettings = (Status_t(*)(HWND)) \
                  GetProcAddress(dllInstance, "_ShowSettings");
  if (ShowSettings == NULL)
    ShowDLL = NULL;

  ShowConfig = (Status_t(*)(HWND, unsigned int)) \
                GetProcAddress(dllInstance, "_ShowConfig");
  if (ShowConfig == NULL)
    ShowDLL = NULL;

  BulkErase = (Status_t(*)(HWND)) \
                GetProcAddress(dllInstance, "_DoBulkErase");
  if (BulkErase == NULL)
    ShowDLL = NULL;

  RunTarget = (Status_t(*)(void)) \
                GetProcAddress(dllInstance, "_RunTarget");
  if (RunTarget == NULL)
    ShowDLL = NULL;
}


/* End of file */











