본문 바로가기

파이어몽키

RFID 리더(한미IT RF Prisma) 연동하기 - 델파이에서 JAR 이용

(아래 내용은 델파이 10.2 도쿄 릴리즈 1과 릴리즈 2에서 작성된 내용으로 다른 버전에서는 일부 내용이 다를 수 있습니다.)


개발 컨설팅을 통해 의뢰한 작업 중 RFID 리더 연동한 내용 공유합니다.

(3일간의 개발 컨설팅으로 RFID 리더, TMAP 연동, 원격 데이터 연동 기술을 전파하는 작업을 진행했습니다.)


RFID 리더와 연동은 제조사에서 제공하는 라이브러리(안드로이드 JAR)를 이용했습니다.

이 과정을 통해 델파이에서 JAR 파일 연동하는 내용을 확인할 수 있습니다.


RFID 리더 연동



위 영상의 RFID 리더는 RFID 태그의 값을 읽고, 바코드의 값을 읽어 안드로이드 앱에 데이터를 전달합니다.

안드로이드 앱은 장비를 구동 및 설정하고, 장비가 읽은 데이터를 받아 화면에 표시합니다.


안드로이드 앱은 델파이(파이어몽키)를 이용해 개발했으며, 장비와 연동하는 부분은 제조사에서 제공한 JAR 형태의 라이브러리를 이용했습니다.


델파이에서 JAR 파일 연동 과정은 아래와 같습니다

1, 작업 준비

2, 델파이용 JAR 브릿지 파일 생성

3, 델파이 프로젝트에 JAR 파일 추가

4, 브릿지 파일로 JAR 연동 코드 작성


기타  참고사항

 - 안드로이드 연동 시 참고사항

 - 프레임을 이용해 재사용 가능한 화면 제작

샘플 프로젝트


작업 준비

대상 장비 - 한미IT RF Prisma


한미IT RF Prisma

제품 링크 : http://www.hanmiit.co.kr/hanmiit/handler/Main-Start


제품 문의

한미IT영업 임상기과장 skyoflsk@hanmi.co.kr


라이브러리 준비 및 분석

위 제품 링크 페이지에서 SDK Download 메뉴를 이용해 SDK 관련 파일을 제공합니다.

(안드로이드, iOS, 윈도우용 라이브러리를 제공합니다. 이글에서는 안드로이드 라이브러리만 다룹니다.)


다운로드 받은 압축파일에는 SDK 파일과 문서, 샘플이 포함되어 있습니다.

(앱스토어에서 RFPrisma로 검색 해 샘플 앱을 설치할 수 있습니다.)

문서와 샘플을 통해 제공하는 기능을 확인하고, 대략적인 사용법을 익히도록 합니다. 특히 라이브러리를 호출하는 부분은 정확히 숙지해야 합니다.


델파이용 JAR 브릿지 파일 생성

델파이에서 JAR 파일을 연동하기 위해 브릿지 파일(JAR 파일에 대한 델파이 인터페이스)을 생성해야 합니다.

브릿지 파일 생성

Java2OP.exe를 이용 델파이 브릿지 파일을 생성합니다. Java2OP는 JAR 파일 또는 Java 소스파일을 호출할 수 있는 델파이 코드를 생성합니다.(참고: 파이어몽키에서 외부 라이브러리 연동하기(jar. so, a))


아래 커맨드를 이용 브리지 파일(Androidapi.JNI.rfidreaderapi.pas)을 생성합니다.
set path=%PATH%;"c:\Program Files (x86)\Embarcadero\Studio\19.0\bin\converters\java2op"

java2op -jar ..\SDK\rfid.reader.api.jar -unit Androidapi.JNI.rfidreaderapi
위 코드를 명령 프롬프트에서 바로 입력 및 실행하거나, 배치파일(*.bat)로 실행할 수 있습니다.
(*.jar 파일의 경로를 상대경로로 입력 시 주의하시기 바랍니다. 절대경로를 이용해도 됩니다.)

델파이 프로젝트에 JAR 파일 추가

라이브러리 추가

멀티-디바이스 애플리케이션(파이어몽키) 프로젝트에서 타겟 플랫폼을 안드로이드로 설정 후 트리를 펼쳐 Libraries 항목에 JAR 파일을 추가해야 합니다.

델파이 브릿지 파일 추가

JAR와 연동하기 위해 델파이 브릿지 파일(Androidapi.JNI.rfidreaderapi.pas)을 프로젝트에 추가합니다.

브릿지 파일 확인을 위해 컴파일 후 오류를 조치합니다.


만약, 컴파일 시 E2029 오류 발생 시 다음을 참고해 조치합니다.

E2029 오류 조치방법

E2029 오류는 예약어를 용도와 다른 곳에서 사용할 경우 발생합니다.

오류가 발생하는 예약어 키워드 앞에 "&"을 추가해 해결합니다.

(예> type -> &type, in -> &in)

(참고: http://tech.devgear.co.kr/delphi_qna/420082)


브릿지 파일로 JAR 연동 코드 작성

JAR와 연동하는 코드는 아래와 같이 클래스를 이용해 작성했습니다.

FMX.HanmiIT.RFIDReader.pas


구현한 내용 중 다음 내용을 살펴보겠습니다.

1, 인스턴스 메소드와 클래스 메소드 접근

2, 자바 이벤트 리스너 설정


인스턴스 메소드와 클래스 메소드 접근

RF Prisma JAR 라이브러리에는 독특하게 클래스 메소드를 많이 사용하도록 구현되어 있습니다.


연동 시 델파이 클래스(TJATRfidManager)는 클래스 인터페이스(JATRfidManagerClass)와 인스턴스 인터페이스(JATRfidManager) 쌍으로 이뤄집니다. 

클래스 인터페이스(JATRfidManagerClass)는 객체를 생성하기 전의 클래스를 통해 접근하는 함수, 속성, 상수를 제공합니다. 자바코드를 사용하는 경우 "델파이클래스명.JavaClass.클래스메소드" 형식으로 JavaClass 속성을 통해 자바 클래스에 접근해야 합니다.

인스턴스 인터페이스(JATRfidManager)는 객체 생성 후 사용가능한 인스턴스 함수와 속성 상수를 제공합니다.

이 라이브러리에는 객체(JATRfidReader 등) 생성 시 아래와 클래스 메소드를 이용합니다. 해당 객체의 추가 기능은 인스턴스 메소드로 제공합니다.
var
  FReader: JATRfidReader;
...
  FReader := TJATRfidManager.JavaClass.getInstance;

  FReader.setEventListener(FEventListener);
  FReader.connectDevice(StringToJString(AAddress));
  FReader.setStoredMode(Value);
  FReader.setReportMode(Value);

자바 이벤트 리스너 설정

연동 시 가장 우려하던 부분입니다. RFID 태그를 읽거나 연결상태 가 변경되는 등 장비에서 동작해 발생하는 이벤트 정보를 리스너(JATRfidEventListener)를 통해 앱에서 받습니다.


리스너 구현시 메인 클래스(TRfidReader)에서 바로 리스너 인터페이스를 위임받아 구현해도 되지만, 복잡해 지기 때문에 별도의 클래스에서 이벤트 리스너를 구현하고 필요한 정보만 받도록  분리해 구현했습니다.


이벤트 리스너 구현 선언부

type
  TRfidEventListner = class(TJavaLocal, JATRfidEventListener)
  private
    FHandler: IRfidEventHandler;
  public
    constructor Create(AHandler: IRfidEventHandler);

    { JATRfidEventListenerClass }
    procedure onAccessResult(P1: JATRfidReader; P2: Jtype_ResultCode; P3: JActionState; P4: JString; P5: JString; P6: Single; P7: Single); cdecl;
    procedure onActionChanged(P1: JATRfidReader; P2: JActionState); cdecl;
    procedure onCommandComplete(P1: JATRfidReader; P2: JCommandType); cdecl;
    procedure onDebugMessage(P1: JATRfidReader; P2: JString); cdecl;
    procedure onDetactBarcode(P1: JATRfidReader; P2: JBarcodeType; P3: JString; P4: JString); cdecl;
    procedure onLoadTag(P1: JATRfidReader; P2: JString); cdecl;
    procedure onReadedTag(P1: JATRfidReader; P2: JActionState; P3: JString; P4: Single; P5: Single); cdecl;
    procedure onRemoteKeyStateChanged(P1: JATRfidReader; P2: JRemoteKeyState); cdecl;
    procedure onStateChanged(P1: JATRfidReader; P2: JConnectionState); cdecl;
  end;

위와 같이 JTARfidEventListener 인터페이스를 위임받고, 해당 인터페이스의 함수를 정의합니다.


주의할 사항은 Create 메소드의 파라메터로 IRfidEventHandler 인터페이스를 받아 FHandler에 저장하도록 구현합니다.


델파이 이벤트 인터페이스 선언부

IRfidEventHandler는 아래와 같이 필요한 메소드만 정의했습니다. 특히 파라메터는 사용하기 편하도록 델파이 자료형으로 재정의 했습니다.

type
  IRfidEventHandler = interface
  ['{FFEB910C-3BB8-48CA-BE11-B09CC07E53AC}']
    // Rfid Reader
    procedure ReadedTag(AReader: JATRfidReader; ATag: string);
    procedure StateChagned(AReader: JATRfidReader; AState: TConnectionState);

    // Barcode
    procedure ActionChagned(AReader: JATRfidReader; AState: TActionState);
    procedure DetactBarcode(AReader: JATRfidReader; ABarcodeType, ACodeId, ABarcode: string);
  end;


메인 클래스에서 델파이 이벤트 인터페이스 위임
위 인터페이스는 메인 클래스에서 위임받았고, 이벤트 핸들러 생성 시 파라메터로 전달합니다.
그리고, FReader 객체에 이벤트 리스너를 설정(setEventListener)합니다.
type
  TRFIDReader = class(TInterfacedObject, IRfidEventHandler)
...
procedure TRFIDReader.InitReader;
begin
...
  FEventListener := TRfidEventListner.Create(Self);
...
  FReader := TJATRfidManager.JavaClass.getInstance;
  FReader.setEventListener(FEventListener);
end;

이벤트 발생 시 델파이 이벤트 인터페스를 통해 전달
JATRfidEventListener에서 이벤트 발생 시 IRfidEventHandler에 이벤트를 전달하도록 구현했습니다.
procedure TRfidEventListner.onStateChanged(P1: JATRfidReader;
  P2: JConnectionState);
var
  State: TConnectionState;
begin
  if Assigned(FHandler) then
  begin
    State := TConnectionState.Disconnected;
    if P2.getState = TJConnectionState.JavaClass.Connected.getState then
      State := TConnectionState.Connected
    else if P2.getState = TJConnectionState.JavaClass.Connecting.getState then
      State := TConnectionState.Connecting
    else if P2.getState = TJConnectionState.JavaClass.Listen.getState then
      State := TConnectionState.Listen
    ;

    FHandler.StateChagned(P1, State);
  end;
end;

이후 이벤트 정보를 받은 메인 클래스에서 비지니스 로직을 수행하도록 구현합니다.

기타 참고사항

안드로이드 연동 시 참고사항

가장 좋은 참고자료는 파이어몽키에 구현된 안드로이드 연동한 내용을 참고하는 것입니다.

(델파이 정품 설치 시 설치경로 하위의 source 디렉토리에는 파이어몽키 라이브러리 소스코들이 포함되어 있습니다.)


그중 다음 소스코드들을 참고하면 아주 좋습니다.

안드로이드 SDK 브릿지 파일

기본 안드로이드 SDK 델파이 브릿지 파일이 아래 경로에 포함되어 있습니다.
  • C:\Program Files (x86)\Embarcadero\Studio\19.0\source\rtl\android - 10.2 도쿄 기준

파이어몽키 라이브러리

파이어몽키 컴포넌트와 라이브러리 등을 어떻게 구현했는지 아래 경로의 파일들에서 살펴볼 수 있습니다.

  • C:\Program Files (x86)\Embarcadero\Studio\19.0\source\fmx - 10.2 도쿄 기준


프레임을 이용해 재사용 가능한 화면 제작

일부 기능적인 화면들이 필요한데 다른 프로젝트에서도 활용할 만한 기능들이어서 재사용 가능하도록 구현해봤습니다.

libs 디렉토리에 포함된 3개의 프레임입니다.

  • FMX.UI.OverflowMenu.pas - 메인 화면의 우측 상단의 연결 팝업 메뉴 구현
  • FMX.UI.SelectBluetoothDeviceDialog.pas - 블루투스 장비를 탐색 후 장비 선택 정보 제공하도록 구현
  • FMX.UI.WaitDialog.pas - 비동기로 진행하는 블루투스 장비 연결을 기다리는 화면
프레임을 사용한 이유는 화면의 일부 영역을 표현하기 위함입니다.
프레임은 화면을 포함한 객체입니다.(Create, Destroy, Show, Hide 이벤트 등을 제공하지 않아 필요한 경우 직접 구현해야 합니다.)
화면등에서 객채 생성하는 코드를 줄이기 위해 클래스 메소드로 기능 호출하도록 구현했습니다.

클래스 메소드로 기능화면 호출
위 유닛 파일을 유즈절(uses)에 추가 후 아래와 같이 기능을 호출할 수 있습니다.
  TWaitDialog.Show('블루투스를 활성화 합니다.', 2000);

  TOverflowMenu.Settings.Top := ToolBar1.Height + 1;
  TOverflowMenu.Settings.Width := Width * 0.9;
  TOverflowMenu.Settings.RightPadding := 10;
  TOverflowMenu.ShowMenu([
      'Connect to last bluetooth device',
      'Connect to new bluetooth device'],
    procedure(AIndex: Integer; AText: string)
    begin
      case AIndex of
        0: ConnectToLastDevice;
        1: ConnectToNewDevice;
      end;
    end);

자세한 별도의 글을 통해 소개하도록 하겠습니다.(그 전에는 직접 소스코드를 통해 내용을 확인하시기 바랍니다.)

기타 궁금한 내용은 댓글 또는 http://blog.hjf.pe.kr/482의 댓글을 참고하거나 등록해 주세요.