Jump to content
Kast2k

Programmatically change reading mode of HoneyWell scanner (Android 6)

Recommended Posts

Good day, dear colleagues!

I'm writing a software for QR data parsing from Honeywell CT50 (Android 6).

I'm sorry for may be big lists of code but i was simplifiying as much as possible.

Main form:

TMainForm = class(TForm)
    Label1: TLabel;
    btnSaveToStore: TButton;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    FAutomaticMode:Boolean;

    procedure ActivateScanner;
  public
    property AutomaticMode: Boolean read FAutomaticMode write FAutomaticMode;

    procedure onBarCodeCompleteThreadSwitcher;
    procedure onBarCodeFailThreadSwitcher;

    procedure ShowInformationMessage(const AText:string);
    { Public declarations }
  end;

uses
  FMX.Helpers.Android,  Androidapi.NativeActivity,  Androidapi.JNI.Widget,
  formScanTakeOnStore, PSTypes, PSVars;

procedure TMainForm.ActivateScanner;
begin
  RegisterDelphiNativeMethods;
  TJNASC.Activate;
  Log.d('Scanner ready');
end;

procedure TMainForm.btnSaveToStoreClick(Sender: TObject);
begin
  Barcode.DelayInSeconds:=2;
  frmScanTakeOnStore:=TfrmScanTakeOnStore.Create(Application);  //is it correct declaration or may be i need Free on Close?
  frmScanTakeOnStore.Show;
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  Barcode:=TBarcode.Create;
  Barcode.DelayInSeconds:=2;
  ActivateScanner; 
end;

procedure TMainForm.onBarCodeCompleteThreadSwitcher;
begin
  if AutomaticMode then
    TJNASC.Start
  else
    TJNASC.Stop;
end;

procedure TMainForm.onBarCodeFailThreadSwitcher;
begin

end;

procedure TMainForm.ShowInformationMessage(const AText: string);
begin
  CallInUiThread (
        procedure
        begin
          TJToast.JavaClass.makeText (TAndroidHelper.Context,
              StrToJCharSequence(AText), TJToast.JavaClass.LENGTH_LONG).show;
        end
  );
end;

PSTypes

unit PSTypes;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.ScrollBox,
  FMX.Memo, FMX.Controls.Presentation, FMX.StdCtrls,
  Androidapi.JNI.App,  Androidapi.JNI,  Androidapi.JNIBridge,  Androidapi.JNI.JavaTypes,
  DateUtils,  System.Character;

type
  JNativeActivitySubclass = interface;

  JNativeActivitySubclassClass = interface(JActivityClass)
  ['{361C7073-E0A2-4A0D-B5E4-8403E5214275}']
    {Methods}
    //function init: JFMXNativeActivity; cdecl;
  end;

  [JavaSignature('com/winarhi/nativeactivitysubclass/NativeActivitySubclass')]
  JNativeActivitySubclass = interface(JActivity)
  ['{7141B1C4-508D-46F3-A767-E0BFCE22C9CE}']
    {Methods}
//    procedure WA_75e_DoScan(paramBoolean :JBoolean);
    procedure WA_75e_Create_aidcManager;
    procedure WA_75e_Destroy_aidcManager;
    procedure WA_75eStart;
    procedure WA_75eStop;
  end;
  TJNativeActivitySubclass = class(TJavaGenericImport<JNativeActivitySubclassClass, JNativeActivitySubclass>)
  public
    procedure Activate;
    procedure DeActivate;
    procedure Start;
    procedure Stop;
  end;

  TBarcodeData=record
  end;

  TBarcodeResult=procedure(const BarcodeData:TBarcodeData) of object;

  TBarcode=class
  private
    FBarcodeData : TBarcodeData;
    FOnBarcodeResult : TBarcodeResult;

    procedure SetReceivedBarcodeData(const Value: string);
  public
    property OnBarcodeResult: TBarcodeResult read FOnBarcodeResult write FOnBarcodeResult;
  end;

procedure RegisterDelphiNativeMethods;

implementation

uses
  FMX.Helpers.Android,
  Androidapi.NativeActivity, PSVars, formMain;

{ TJNativeActivitySubclass }

procedure onBarCodeCompleteNative(PEnv: PJNIEnv; This: JNIObject; BarCode: JNIString); cdecl;
begin
  PSVars.Barcode.ReceivedBarcodeData := JNIStringToString(PEnv, BarCode);
  TThread.Synchronize(TThread.CurrentThread, MainForm.onBarCodeCompleteThreadSwitcher);
end;

procedure onBarCodeFailNative(PEnv: PJNIEnv; This: JNIObject; BarCode: JNIString); cdecl;
begin
  TThread.Synchronize(TThread.CurrentThread, MainForm.onBarCodeFailThreadSwitcher);
end;

procedure RegisterDelphiNativeMethods;
var
  PEnv: PJNIEnv;
  ActivityClass: JNIClass;
  NativeMethods: array[0..1] of JNINativeMethod;
begin
  Log.d('Starting the registration JNI stuff');

  PEnv := TJNIResolver.GetJNIEnv;

  Log.d('Registering interop methods');

  NativeMethods[0].Name := 'onBarCodeCompleteNative';
  NativeMethods[0].Signature := '(Ljava/lang/String;)V';
  NativeMethods[0].FnPtr := @onBarCodeCompleteNative;

  NativeMethods[1].Name := 'onBarCodeFailNative';
  NativeMethods[1].Signature := '()V';
  NativeMethods[1].FnPtr := @onBarCodeFailNative;

  ActivityClass := PEnv^.GetObjectClass(
    PEnv, PANativeActivity(System.DelphiActivity).clazz);

  PEnv^.RegisterNatives(PEnv, ActivityClass, @NativeMethods[0], 2);

  PEnv^.DeleteLocalRef(PEnv, ActivityClass);

  Log.d('Interop Methods Registered');
end;

procedure TJNativeActivitySubclass.Activate;
begin
  Wrap(PANativeActivity(System.DelphiActivity)^.clazz).WA_75e_Create_aidcManager;
end;

procedure TJNativeActivitySubclass.DeActivate;
begin
  Wrap(PANativeActivity(System.DelphiActivity)^.clazz).WA_75e_Destroy_aidcManager;
end;

procedure TJNativeActivitySubclass.Start;
begin
  Wrap(PANativeActivity(System.DelphiActivity)^.clazz).WA_75eStart;
end;

procedure TJNativeActivitySubclass.Stop;
begin
  Wrap(PANativeActivity(System.DelphiActivity)^.clazz).WA_75eStop;
end;

end.

PSVars

unit PSVars;

interface

uses
  PSTypes ;

var
  Barcode:TBarcode;
  TJNASC:TJNativeActivitySubclass;

implementation

end.

formScanTakeOnStore

unit formScanTakeOnStore;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.Controls.Presentation, FMX.StdCtrls, FMX.ScrollBox, FMX.Memo,
  Androidapi.JNI.App,  Androidapi.JNI,  Androidapi.JNIBridge,  Androidapi.JNI.JavaTypes,
  Androidapi.Helpers, FMX.DialogService, System.Rtti, FMX.Grid.Style,
  FMX.Grid, FMX.TextLayout, DateUtils, PSTypes, FMX.Objects;

type
  TfrmScanTakeOnStore = class(TForm)
    Label1: TLabel;
    btnFinish: TButton;
    Panel1: TPanel;
    Panel2: TPanel;
    Panel3: TPanel;
    btnContinuous: TButton;
    btnManual: TButton;
    Panel4: TPanel;
    lblReceived: TLabel;
    StyleBook1: TStyleBook;
    btnTable: TButton;
    lblMaterial: TLabel;
    lblBankaCounts: TLabel;
    lblTotalLeft: TLabel;
    tmrSleep: TTimer;
    rectStatus: TRectangle;
    Button1: TButton;
    procedure btnFinishClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure btnContinuousClick(Sender: TObject);
    procedure btnManualClick(Sender: TObject);
    procedure btnTableClick(Sender: TObject);
    procedure tmrSleepTimer(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    FNewDataExist:Boolean;

    BarcodeData:TBarcodeData;

    procedure OnBarcodeResult(const ABarcodeData:TBarcodeData);
    procedure CloseFrm(Sender: TObject; const AResult: TModalResult);
    procedure MaterialAddedNG(Sender: TObject; const AResult: TModalResult);
    procedure MaterialAddedOK(Sender: TObject; const AResult: TModalResult);
    procedure StopScannerAndColor(CL:Cardinal);
  public
    { Public declarations }
  end;

var
  frmScanTakeOnStore: TfrmScanTakeOnStore;

implementation

uses
  FMX.Helpers.Android,  Androidapi.NativeActivity, formScanComplete, dmData, formAgreeAction,
  formScanTakeOnStoreTable, PSVars, formMain;

{$R *.fmx}

procedure TfrmScanTakeOnStore.btnContinuousClick(Sender: TObject);
begin
  TJNASC.Start;
  btnContinuous.StyleLookup:='btnContinuousStyle1';
  btnManual.StyleLookup:='';
  MainForm.AutomaticMode:=True;
  MainForm.ShowInformationMessage('Automatic mode');
end;

procedure TfrmScanTakeOnStore.btnFinishClick(Sender: TObject);
begin
//  MainForm.SayTextToSpeech('Stop data reading process and exit?');
  TDialogService.MessageDialog(
    'Stop data reading process and exit?',
    TMsgDlgType.mtWarning,
    [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo],
    TMsgDlgBtn.mbNo,
    0,
    CloseFrm);
end;

procedure TfrmScanTakeOnStore.btnManualClick(Sender: TObject);
begin
  TJNASC.Stop;
  btnManual.StyleLookup:='btnContinuousStyle1';
  btnContinuous.StyleLookup:='';
  MainForm.AutomaticMode:=False;
end;

procedure TfrmScanTakeOnStore.btnTableClick(Sender: TObject);
begin
  CallInUIThread(procedure begin
    frmScanTakeOnStoreTable:=TfrmScanTakeOnStoreTable.Create(Application); //Free ???
    frmScanTakeOnStoreTable.Show;
  end);
end;

procedure TfrmScanTakeOnStore.Button1Click(Sender: TObject); //simulation
var
  bc: TBarcodeData;
begin
  bc.Parsed:=True;
  bc.KPJCode:='80604358';
  bc.LotName:='testlot';
  OnBarcodeResult(bc);
end;

procedure TfrmScanTakeOnStore.CloseFrm(Sender: TObject; const AResult: TModalResult);
begin
  if AResult = mrYes then
    begin
      TJNASC.Stop;
      MainForm.AutomaticMode:=False;
      Close;
    end;
end;

procedure TfrmScanTakeOnStore.FormShow(Sender: TObject);
begin
  Log.d('Pre-activate');
  tmrSleep.Interval:=Barcode.DelayInSeconds*1000;

  Barcode.LastScanTimeUnix:=DateTimeToUnix(Now);
  Barcode.OnBarcodeResult:=OnBarcodeResult;
end;

procedure TfrmScanTakeOnStore.MaterialAddedNG(Sender: TObject;
  const AResult: TModalResult);
begin
  if AResult = mrYes then
    begin
      ///NG result parse
    end;
end;

procedure TfrmScanTakeOnStore.MaterialAddedOK(Sender: TObject;
  const AResult: TModalResult);
begin

end;

procedure TfrmScanTakeOnStore.OnBarcodeResult(const ABarcodeData: TBarcodeData);
begin
  if ABarcodeData.Parsed then
    begin
      StopScannerAndColor(TAlphaColors.Green);
    end
  else
    begin
      MainForm.ShowInformationMessage(ARNBarCode+' not recognized.');
      StopScannerAndColor(TAlphaColors.Red);
    end;
end;

procedure TfrmScanTakeOnStore.StopScannerAndColor(CL: Cardinal);
begin
  rectStatus.Fill.Color:=CL;
  TJNASC.Stop;
  TJNASC.DeActivate;
  Log.d('Scanner DeActivate');
  tmrSleep.Enabled:=True;
end;

procedure TfrmScanTakeOnStore.tmrSleepTimer(Sender: TObject);
begin
  TJNASC.Activate;
  Log.d('Scanner ready');
  if MainForm.AutomaticMode then
    begin
      MainForm.ShowInformationMessage('Starting scanner');

////NG
      {frmScanTakeOnStore.btnManual.OnClick(frmScanTakeOnStore.btnManual);
      Sleep(1000);
      frmScanTakeOnStore.btnContinuous.OnClick(frmScanTakeOnStore.btnContinuous);}
////NG
      {TJNASC.Stop;
      MainForm.AutomaticMode:=False;
      TJNASC.Start;
      MainForm.AutomaticMode:=True;}

      MainForm.ShowInformationMessage('Automatic mode');
    end;
  rectStatus.Fill.Color:=StrToInt('$FFE0E0E0');
  tmrSleep.Enabled:=False;
end;

end.

So after mainform show Honeywell is activated and possible to read QRs

After that i'm opening "frmScanTakeOnStore " and select Manual (btnManual) or Automatic (btnContinuous) scanning mode. Manual = operator presses HW button, Automatic = reading laser is always active

TJNASC.Start, TJNASC.Stop are responsible for Automatic scanning mode: Stop = Manual, Start = Automatic On

 

Now i have a request from user that when scanning in Automatic then after QR code reading and parsing device need to shutdown scanner on some interval (1-3 seconds) and re-activate it and continue scanning

 

Temporary i decided to do via FMX TTimer. It works normally, notification messages are shown, BUT! scanner is not running automatic mode until i press btnContinuous.

 

I tried 2 variants but same NG result. Also tried via CallInUIThread = same result.

 

So the problem is that i cant start Automatic reading without manual clicking on button

 

Dear collagues, may be i not fully understand FMX logic or doing\missing something wrong?

 

 

Edited by Kast2k
change of title

Share this post


Link to post

Problem was fixed by addition 2 new TTimer for async calls of TJNASC.Stop and TJNASC.Start parsing by HW scanner.

 

Topic can be closed.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×