unit dlerase;

{$mode objfpc}

interface

uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  StdCtrls, ExtCtrls, Grids,
  StrUtils,  //AnsiMidStr
  header_utils;

type

  { TFormDLErase }

  TFormDLErase = class(TForm)
    EraseAllButton: TButton;
    CancelButton: TButton;
    MessageLabel: TLabel;
    StringGrid1: TStringGrid;
    Timer1: TTimer;
    procedure CancelButtonClick(Sender: TObject);
    procedure EraseAllButtonClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure FormShow(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { private declarations }
    procedure EraseChecker();
  public
    { public declarations }
  end;

function DLEGetMID(): Integer;//Get Datalogger EEPROM manufacturer name and part number ID
function DLEGetCapacity(): LongInt;//Get Datalogger EEPROM manufacturer name and part number ID

var
  FormDLErase: TFormDLErase;
  EraseElapsedTime: Integer = 0;
  DLEEraseTimeMin, DLEEraseTimeMax: Integer;//Datalogger EEPROM specified erase times
  DLEManufacturer, DLEPartNo: String;//Datalogger EEPROM Manufacturer and Part Number
  DLEStorageCapacity: LongInt; //Datalogger EEPROM Storage capacity of chip
  DLEStoredRecords: LongInt; //Number of records stored in the DL FLASH EEPROM

implementation

uses
  Unit1;

{ TFormDLErase }

procedure TFormDLErase.FormShow(Sender: TObject);
var
  pieces: TStringList;
  result: AnsiString;
  TriggerModeNumber: Integer;
begin
   StringGrid1.Clean;
   DLEStoredRecords:=0;
   MessageLabel.Caption:='Warning! All recorded data in meter will be erased!';

   //Set up parsing
   pieces := TStringList.Create;
   pieces.Delimiter := ',';
   pieces.StrictDelimiter := False; //Parse spaces also

   //Ensure that continuous logging mode has not been selected
   result:=sendget('Lmx');
   TriggerModeNumber:=StrToInt(AnsiMidStr(result,4,1));
   if ((TriggerModeNumber=1) or (TriggerModeNumber=2)) then //Warn user that erase cannot be done
     begin
      StringGrid1.Cells[0,0]:='Warning';
      StringGrid1.Cells[1,0]:='Cannot erase database while in continuous trigger mode.';
      StringGrid1.Cells[1,1]:='Select trigger mode = Off,';
      StringGrid1.Cells[1,2]:=' or one of the "Every x on the hour" modes.';
      EraseAllButton.Enabled:=False;
     end
   else
     begin
       EraseAllButton.Enabled:=True;
       EraseAllButton.Visible:=True;

       // Get number of stored records
       pieces.DelimitedText := sendget('L1x');
       if (pieces.Count=2) then
         DLEStoredRecords:=StrToIntDef(pieces.Strings[1],0);

       //Get EEPROM chip Manufacturer and Device Identification
       if ((DLEGetCapacity()=0)  and (DLEGetMID()=0)) then
         begin//get eeprom id was successful
           StringGrid1.Cells[0,0]:='Stored record(s)';
           StringGrid1.Cells[1,0]:=Format('%d records',[DLEStoredRecords]);
           StringGrid1.Cells[0,1]:='Storage capacity';
           StringGrid1.Cells[1,1]:=Format('%d records',[DLEStorageCapacity]);
               //writeln('DLEStorageCapacity:=',DLEStorageCapacity);
               //
           StringGrid1.Cells[0,2]:='Erase time';
           if StrToInt(SelectedFeature)>=27 then
             StringGrid1.Cells[1,2]:=Format('%d to %d seconds',[DLEEraseTimeMin, DLEEraseTimeMax])
             else
               StringGrid1.Cells[1,2]:=Format('%d seconds',[DLEEraseTimeMax]);
         end
       else//get eeprom id failed
           begin
            StringGrid1.Cells[0,0]:='Error';
            StringGrid1.Cells[1,0]:=Format('No EEPROM found, %d parameters.',[DLEPartNo]);
           end;

     end; //End of checking for continuous trigger modes that prevent erasing
   if Assigned(pieces) then FreeAndNil(pieces);
end;

procedure TFormDLErase.EraseChecker();
var
  result:String;
  pieces: TStringList;
begin

   if StrToInt(SelectedFeature)>=27 then
   begin
    pieces := TStringList.Create;
    pieces.Delimiter := ',';
    pieces.StrictDelimiter := False; //Parse spaces also

    //Check chip erase status after chip erase has been requested
    result:=SendGet('L6x');//Get status
    pieces.DelimitedText := result;
    pieces.StrictDelimiter := False; //Parse spaces also
      if EraseElapsedTime<=DLEEraseTimeMax then
        if pieces.Count = 2 then
          begin
            begin
             if (StrToIntDef(pieces.Strings[1],0) and 1 ) > 0 then //still busy
               begin
                StringGrid1.Cells[0,1]:='Progress';
                StringGrid1.Cells[1,1]:=Format('Elapsed time of: %d out of %d to %d seconds.',[EraseElapsedTime,DLEEraseTimeMin, DLEEraseTimeMax]);
               end
             else
               begin
                Timer1.Enabled:=False;
                StringGrid1.Clean;
                StringGrid1.Cells[0,0]:='Status';
                StringGrid1.Cells[1,0]:=Format('Finished erasing meter database in %d seconds.',[EraseElapsedTime]);
                MessageLabel.Caption:='Finished erasing meter database';
                EraseAllButton.Visible:=False;
                EraseAllButton.Enabled:=True;
                CancelButton.Enabled:=True;
               end;
             end
          end // end of checking pieces count (reponse from L6x)
          else
          begin
            StringGrid1.Cells[0,1]:='Progress';
            StringGrid1.Cells[1,1]:=Format('No reponse. Elapsed time of: %d out of %d to %d seconds.',[EraseElapsedTime,DLEEraseTimeMin, DLEEraseTimeMax]);
          end
      else
        begin
          StringGrid1.Clean;
          StringGrid1.Cells[0,0]:='Status';
          StringGrid1.Cells[1,0]:=Format('Erase time too long: (%d seconds) has elapsed, try again.',[EraseElapsedTime]);
          Timer1.Enabled:=False;
          EraseAllButton.Enabled:=True;
          CancelButton.Enabled:=True;
        end;
    end
   else
   begin
     if EraseElapsedTime<DLEEraseTimeMax then
      begin
       StringGrid1.Cells[0,1]:='Progress';
       StringGrid1.Cells[1,1]:=Format('Elapsed time of : %d out of %d seconds.',[EraseElapsedTime,DLEEraseTimeMax]);
      end
     else
       begin
         StringGrid1.Clean;
         StringGrid1.Cells[0,0]:='Status';
         StringGrid1.Cells[1,0]:=Format('%d seconds elapsed, Meter database should be erased.',[EraseElapsedTime]);
         Timer1.Enabled:=False;
         EraseAllButton.Enabled:=True;
         CancelButton.Enabled:=True;
       end;
   end;
   if Assigned(pieces) then FreeAndNil(pieces);
end;

procedure TFormDLErase.Timer1Timer(Sender: TObject);
begin
  inc(EraseElapsedTime);
  EraseChecker();
end;

procedure TFormDLErase.CancelButtonClick(Sender: TObject);
begin
  FormDLErase.Close;
end;

//Proceed to erasing the entire data logging EEPROM
procedure TFormDLErase.EraseAllButtonClick(Sender: TObject);
begin
  EraseAllButton.Enabled:=False;
  CancelButton.Enabled:=False;
  StringGrid1.Clean;
  StringGrid1.Cells[0,0]:='Status';
  StringGrid1.Cells[1,0]:='Database erasure in the meter is being requested ...';
  MessageLabel.Caption:='Erasing meter database';
  StatusMessage('Erasing meter database.');
  if StrToInt(SelectedFeature)>=27 then
    begin
     if SendGet('L2x') = 'L2' then //Initiate erasure and check response.
       begin
        StringGrid1.Clean;
        StringGrid1.Cells[0,0]:='Status';
        StringGrid1.Cells[1,0]:='Database in the meter is being erased ...';
       end
     else
       begin
         StringGrid1.Clean;
         StringGrid1.Cells[0,0]:='Status';
        StringGrid1.Cells[1,0]:='Database erasure command not accepted, please try again.';
       end;
     EraseElapsedTime:=0; //preset timer
     EraseChecker();

     //The remainder of the erasure phase will be asynchronously performed by the timer.
     Timer1.Enabled:=True;
    end
  else //firmware too old to respond properly
    begin
      SendGet('L2x',False,1,False);//Initiate erasure, but don't wait for response
      StringGrid1.Clean;
      StringGrid1.Cells[0,0]:='Status';
      StringGrid1.Cells[1,0]:='Old firmware prevents accurate status update, install feature 27 or greater.';
      StringGrid1.Cells[0,1]:='Erase Status';
      StringGrid1.Cells[1,1]:='Database in the meter is being erased ...';
      EraseElapsedTime:=0; //preset timer
      EraseChecker();

      //The remainder of the erasure phase will be asynchronously performed by the timer.
      Timer1.Enabled:=True;
    end;
end;

procedure TFormDLErase.FormClose(Sender: TObject; var CloseAction: TCloseAction
  );
begin
  //cannot remove "close window icon", just prevent it from being closed.
  //CloseAction:=caNone;
end;
function DLEGetCapacity(): Integer;//Get Datalogger EEPROM manufacturer name and part number ID
var
  pieces: TStringList;
begin
  //Set up parsing
  pieces := TStringList.Create;
  pieces.Delimiter := ',';
  pieces.StrictDelimiter := False; //Parse spaces also

  DLEGetCapacity:=0;//Default to no error
  DLEStorageCapacity:=0;;//Default to no capacity

  if StrToInt(SelectedFeature)>=27 then
    begin
     pieces.DelimitedText := SendGet('LZx'); //Available on in firmware version 27+
     if (pieces.Count=2) then
       DLEStorageCapacity:=StrToIntDef(pieces.Strings[1],0)
     else
       begin
        DLEGetCapacity:=-1; //Indicate error.
       end;
    end
    else
      DLEStorageCapacity:=32768; //Old firmware only had 32768 record capactity.
  if Assigned(pieces) then FreeAndNil(pieces);
end;
function DLEGetMID(): Integer;//Get Datalogger EEPROM manufacturer name and part number ID
var
  pieces: TStringList;
begin
   //Set up parsing
   pieces := TStringList.Create;
   pieces.Delimiter := ',';
   pieces.StrictDelimiter := False; //Parse spaces also


   DLEGetMID:=0;//Assume no errors unless they are found

  pieces.DelimitedText := SendGet('L0x');
  if (pieces.Count=3) then
    begin
      case StrToIntDef(pieces.Strings[1],0) of
         239: begin
                DLEManufacturer:='Winbond Serial Flash';
                case StrToIntDef(pieces.Strings[2],0) of
                   23: begin
                         DLEPartNo:='W25Q128FV';
                         //DLEStorageCapacity:=Round((2**24) / bytesperrecord);
                         DLEEraseTimeMin:=40;
                         DLEEraseTimeMax:=200;
                       end;
                   19: begin
                         DLEPartNo:='W25Q80BV';
                         //DLEStorageCapacity:=Round((2**20) / bytesperrecord);
                         DLEEraseTimeMin:=2;
                         DLEEraseTimeMax:=6;
                       end;
                   else begin
                         DLEPartNo:='Unknown';
                         DLEGetMID:=-1;
                        end;
                end;
         end
         else
           begin
             DLEManufacturer:='Unknown';
             DLEGetMID:=-1;
           end;
      end;
    end
  else
  begin
    DLEGetMID:=-1;
  end;
  if Assigned(pieces) then FreeAndNil(pieces);
end;


initialization
  {$I dlerase.lrs}

end.

