Перейти к содержанию
Fire Monkey от А до Я
  • 0

Изменение типа чтения данных с встроенного сканера Honeywell


Kast2k

Вопрос

Добрый день!

Пишу программу для обработки результатов работы сканера Honeywell CT50 (Android 6).

Сразу прошу прощения за простыни кода, упрощал изо всех сил.

Главная форма:

  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);  //правильный ли вызов? надо ли Free при выходе?
  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.pas

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
//  PSVars.Barcode.ReceivedBarcodeData := JNIStringToString(PEnv, BarCode);
  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('Завершить приемку материалов на склад?');
  TDialogService.MessageDialog(
    'Завершить приемку материалов на склад?',
    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+' невозможно распознать.');
      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');

      frmScanTakeOnStore.btnManual.OnClick(frmScanTakeOnStore.btnManual);
      Sleep(1000);
      frmScanTakeOnStore.btnContinuous.OnClick(frmScanTakeOnStore.btnContinuous);

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

end.

 

Итак, при запуске основной формы сканер активируется и появляется возможность чтения.

Для получения и обработки данных я открываю форму frmScanTakeOnStore и выставляю статус ручное сканирование.

Процедуры TJNASC.Start, TJNASC.Stop отвечают за Автоматическое сканирование ВКЛ и Выкл соответственно. Автоматическое = сканер постоянно пытается считать баркод. Ручное = чтение по триггеру (кнопке на аппарате).

Поступила задача, если сканер в Автоматическом режиме, то после каждого скнаирования надо делать паузу в 1-несколько секунд и выключать сканер, а потом активировать снова.

Я решил сделать это через штатный таймер. Он отрабатывает нормально, но симуляция нажатия кнопок (знаю что так себе решение, но см дальше) не происходит. Т.е. если я закомментирую строку в OnTimer

      Sleep(1000);      frmScanTakeOnStore.btnContinuous.OnClick(frmScanTakeOnStore.btnContinuous);

то кнопка btnManual станет подсвеченной. Если раскомментирую, то автоматическое чтение не активируется. НО! Если просто нажать на кнопку btnContinuous, то сканер запускает постоянное чтение.

Пробовал сделать так, но результат также был нулевой (постоянное чтение не запускается программно, только через клик по кнопке):

  TJNASC.Stop;
  MainForm.AutomaticMode:=False;
  TJNASC.Start;
  MainForm.AutomaticMode:=True;

Пробовал через CallInUIThread() = тоже самое

 

Коллеги,

Подскажите, пожалуйста, что я делаю не так? Может быть необходимо методы по иному вызывать или я упускаю какие-то пункты?

 

 

Спасибо!

Изменено пользователем Kast2k
Ссылка на комментарий

Рекомендуемые сообщения

  • 0

Вследствие асинхронной обработки железным сканером вызовов TJNASC.Stop и TJNASC.Stop проблема была решена добавлением 2 TTimer выполняющих эти вызовы.

Возможно решение кривое, но работает чётко.

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...