Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
 FMX. Изменение типа чтения данных со cканера Android программно  [new]
Kast2K
Member

Откуда: Санкт-Петербург
Сообщений: 512
Добрый день!

Пишу программу для обработки результатов работы сканера 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');
//// не работает
      TJNASC.Stop;
      MainForm.AutomaticMode:=False;
      TJNASC.Start;
      MainForm.AutomaticMode:=True;
//// не работает
      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 и выставляю статус либо ручное сканирование (btnManual) либо Автоматическое (btnContinuous) .

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

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

Я решил сделать это через штатный таймер. Он отрабатывает нормально, но ни TJNASC.Start, TJNASC.Stop ни симуляция нажатия кнопок в процедуре OnTimer не запускают режим автоматического скана. НО! Если просто нажать на кнопку btnContinuous, то сканер запускает постоянное чтение.

Проблема: постоянное чтение не запускается программно, только через клик по кнопке.

Коллеги,
Подскажите, пожалуйста, что я делаю не так? Может быть необходимо методы по иному вызывать или я упускаю какие-то пункты?
17 июл 20, 17:36    [22169429]     Ответить | Цитировать Сообщить модератору
 Re: FMX. Изменение типа чтения данных со cканера Android программно  [new]
white_nigger
Member

Откуда: Тула
Сообщений: 2367
Мало что понял, но... вызов btnContinuousClick в обработчике таймера срабатывает или нет? Помимо этого перенеси отключение таймера в его обработчиках из конца метода в самое начало.
18 июл 20, 00:09    [22169564]     Ответить | Цитировать Сообщить модератору
 Re: FMX. Изменение типа чтения данных со cканера Android программно  [new]
Kast2K
Member

Откуда: Санкт-Петербург
Сообщений: 512
white_nigger,

Спасибо за идею, но не помогает :(

Может станет понятнее:
1. Открыл форму formScanTakeOnStore,
2.нажал кнопку btnContinuos, хардварный сканер включился и светит своим лазером, выполняется TJASC.Start
3. Считываю баркод
4. Программа деактивирует сканер, чтобы
а) автоматический режим выключился
б) не было возможности нажать железную кнопку для сканирования.
5. Запускается Timer
6. По прошествии 3 секунд отрабатывает OnTimer
7. Если в п.2. был активирован режим Автоматического сканирования, то должна отработать процедура TJASC.Start или симулироваться нажатие кнопки btnContinuous.

Проблема: в П.7 происходит вход и якобы выполнение данных процедур, но хардварный сканер не включается. Он включится если пальцем нажать на кнопку btnContinuous.
18 июл 20, 05:50    [22169603]     Ответить | Цитировать Сообщить модератору
 Re: FMX. Изменение типа чтения данных со cканера Android программно  [new]
wadman
Member

Откуда: Санкт-Петербург
Сообщений: 26714
Kast2K,

сканер скорее всего выполняет команды асинхронно и не берется за следующую, пока предыдущая не выполнена. Потому кнопками работает, а в коде - нет.
И sleep в основном потоке - дурной тон.
18 июл 20, 11:03    [22169649]     Ответить | Цитировать Сообщить модератору
 Re: FMX. Изменение типа чтения данных со cканера Android программно  [new]
Kast2K
Member

Откуда: Санкт-Петербург
Сообщений: 512
wadman,

Спасибо.
Sleep было просто для теста.
18 июл 20, 13:33    [22169696]     Ответить | Цитировать Сообщить модератору
 Re: FMX. Изменение типа чтения данных со cканера Android программно  [new]
Kast2K
Member

Откуда: Санкт-Петербург
Сообщений: 512
Kast2K,
TThread.synchronize?
18 июл 20, 13:35    [22169697]     Ответить | Цитировать Сообщить модератору
 Re: FMX. Изменение типа чтения данных со cканера Android программно  [new]
wadman
Member

Откуда: Санкт-Петербург
Сообщений: 26714
Kast2K
Kast2K,
TThread.synchronize?

Это-то тут при чем? В коде потоков нет.

Нужно выяснить какой период нужен сканеру для выполнения команд. Хотя-бы с теми же таймерами. Начни с задержки 100мс. То есть серия нужных команд с такой задержкой.
Не получится, увеличивай.
18 июл 20, 20:21    [22169826]     Ответить | Цитировать Сообщить модератору
 Re: FMX. Изменение типа чтения данных со cканера Android программно  [new]
Cobalt747
Member

Откуда:
Сообщений: 2183
wadman
Нужно выяснить какой период нужен сканеру для выполнения команд. Хотя-бы с теми же таймерами. Начни с задержки 100мс.

Или можно начать с чтения документации на оборудование )))
19 июл 20, 00:00    [22169856]     Ответить | Цитировать Сообщить модератору
 Re: FMX. Изменение типа чтения данных со cканера Android программно  [new]
Kast2K
Member

Откуда: Санкт-Петербург
Сообщений: 512
wadman,

Спасибо.
Идея с таймерами (100 мс) помогла, всё работает без проблем.

Cobalt747,
В документации всё нормально расписано и работает в FMX. Вопрос был в подходе.
20 июл 20, 10:03    [22170234]     Ответить | Цитировать Сообщить модератору
Все форумы / Delphi Ответить