# Biblioteka interfejsu kasy POSNET COMBO oraz POSNET NEO

### 1.0.2

Spis Treści

- Wprowadzenie
- Przepływ informacji
- Zdarzenia asynchroniczne i bufor paragonowy
  - Zdarzenia asynchroniczne
  - Bufor pozycji paragonowych
  - Obsługa modemu
- Przykładowa sekwencja poleceń
- Wykorzystanie w językach programowania
- Wersja dla systemu Linux

Zgodnie z INSTRUKCJĄ PROGRAMISTY COMBO 1.01, v. 1.6.61.1 oraz SPECYFIKACJĄ PROTOKOŁU KASY POSNET NEO 1.01 v. 006 oraz SPECYFIKACJĄ PROTOKOŁU KAS POSNET NEO 1.02 ORAZ POSNET COMBO 1.02 v.004

## Wprowadzenie

Podstawowe założenia, które zostały przyjęte przy projektowaniu biblioteki dla kasy POSNET COMBO są następujące:

- komunikacja za pośrednictwem RS-232, USB (VCP lub DXX), Ethernet
- wielowątkowość i wielo-urządzeniowość biblioteki (brak zmiennych globalnych)
- obsługa zdarzeń asynchronicznych (karta rabatowa)
- kolejkowanie rozkazów w celu przyspieszenia wymiany danych
- wykorzystanie z różnych języków programowania (konwencja wywołań __stdcall zgodna z WINAPI)
- minimalna zależność od systemu operacyjnego w zakresie interfejsu biblioteki - praktycznie tylko 2 funkcja są typowo dedykowane dla Windows - POS_GetEvent i POS_SetMessageParams.
- interfejs śledzenia (Ustawienie poziomu śledzenia (informacyjności) biblioteki)
- natywny port dla systemu Linux

Ze względu na to, że ilość rozkazów wykorzystywanych w komunikacji z kasą jest ogromna przy projektowaniu biblioteki zrezygnowano z literalnej realizacji każdego rozkazu jako osobnej funkcji. Grupowanie rozkazów w/g rodzaju parametrów także nie jest dobrym rozwiązaniem. W tej sytuacji został zastosowany model "obiektu rozkazowego (Request)", wraz z zestawem funkcji umożliwiających ustawianie parametrów (Obsługa parametrów rozkazu).

Zastosowanie takiego rozwiązania ma dodatkową zaletę. Drobne korekty w rozkazach obsługi kasy w tym dodanie nowych czy zmiana ilości i rodzaju parametrów nie wymagają wtedy zmian w bibliotece komunikacyjnej, a jedynie dostosowania aplikacji do tych zmian.

Po wykonaniu takiego obiektu rozkazowego przez kasę (por. Przepływ informacji) wyniki dostępne są w analogiczny sposób - przez zestaw funkcji pobierających je kolejno z obiektu rozkazowego.

Cztery niezależne kolejki rozkazowe (rozkazy oczekujące, rozkazy wykonane, zdarzenia asynchroniczne i pozycje paragonowe) umożliwiają jednocześnie dużą swobodę przy tworzeniu aplikacji klienckiej zostawiając znaczną swobodę wybory sposobu obsługi kasy jej twórcy.

## Przepływ informacji

W aplikacji istnieją 4 kolejki rozkazowe, pomiędzy którymi następuje przepływ danych jak w grafie poniżej.

Całość transmisji obsługiwana jest przez dwa niezależne wątki, jeden transmisyjny, drugi odbiorczy operujące na odpowiednich kolejkach rozkazów.

## Zdarzenia asynchroniczne i bufor paragonowy

### Zdarzenia asynchroniczne

Kasa POSNET COMBO posiada możliwość generacji pewnych zdarzeń w sposób asynchroniczny w stosunku do wykonywanych poleceń wydawanych przez nadzorującą ją aplikację sterująco-magazynową.

Do obsługi zdarzeń w tym trybie został przygotowany zestaw funkcji opisany w module Obsługa zdarzeń asynchronicznych. Przychodzące zdarzenia asynchroniczne gromadzone są w osobnej kolejce zdarzeń, w której oczekują na obsługę. Aplikacja główna może zostac powiadomiona o przyjściu nowego zdarzenia za pomocą:

- zdarzenia IPC typu "Event" systemu Windows,
- komunikatu Windows wysłanego do wskazanego okna aplikacji

Aplikacja może też cyklicznie sprawdzać, czy w kolejce znajdują się nowe zdarzenia asynchroniczne (polling).

### Bufor pozycji paragonowych

Aby uprościć obsługę pozycji paragonowych tak, aby nie kolidowała z główną kolejką zdarzeń i w efekcie mogła być obsługiwana za pośrednictwem osobnego watku aplikacji została stworzona osobna kolejka zdarzeń zbierająca wyniki poleceń czytających pozycje paragonowe patrz Obsługa bufora pozycji paragonowych.

W ten sposób wątek odbioru danych paragonowych może wysyłać zapytania o pozycje paragonowe w standadowy sposób (do głównej kolejki rozkazów). Główna kolejka rozkazów do wysłania może równolegle otrzymywać rozkazy przygotowywane przez różne wątki (jest w pełni wielowątkowa), serializować je i wysyłac w kolejności otrzymania do kasy.

Odpowiedzi są natomiast rozdzielane od siebie i trafiają do dwóch osobnych kolejek odbiorczych. W kolejce pozycji paragonowych umieszczane są wyłącznie wyniki wysyłanych rozkazów dotyczących pozycji paragonowych.

Mogą to być własciwe pozycje paragonowe lub informacje o błędach wykonania tych rozkazów.

## Obsługa modemu

Obsługa modemu w bibliotece COMBO/NEO jest realizowana poprzez trzy dodatkowe funkcje biblioteczne oraz trzy dodatkowe parametry dla urządzenia typu RS232. Umożliwia realizację zarówno połączeń wychodzących (wybieranie numeru telefonu) jak i przyjmowanie połączeń przychodzących (odbieranie telefonu). Stanowi ona integralną część urządzenia typu RS232.

Aby włączyć tryb modemowy należy ustawić parametr urządzenia RS232 POSNET_DEV_PARAM_MODEMMODE na wartość 1. Po wykonaniu tej czynności urządzenie nie będzie wykonywało zleconych poleceń do momentu nawiązania połączenia modemowego. Urządzenie jest także gotowe do przyjmowania połączeń przychodzących. W przypadku pojawienia się sygnału RING na modemie zostanie automatycznie odebrana rozmowa.

UWAGA: W trybie odbioru rozmowy nie ma możliwości ustawienia modemu ciągiem inicjującym bezpośrednio (tryb zaczyna się pasywnie) – można to jednak zrobić za pośrednictwem polecenia dzwonienia bez ustawiania numeru telefonu (polecenie to zakończy się błędem POSNET_STATUS_MODEM_BADDIAL) ale wyśle do modemu ciąg inicjujący.

Dla urządzenia modemowego można ustawić dwa ciągi:

- ciąg inicjujący modem wraz z początkowym ciągiem „AT” np. AT&S0=0 – parametr POSNET_DEV_PARAM_MODEMINIT
- ciąg dzwonienia wraz z początkowym ATD np. ATDT022123456789 – parametr POSNET_DEV_PARAM_MODEMDIAL

Urządzenie modemowe NIGDY samo nie wybiera numeru i nie ponawia przerwanych połączeń – ta operacja pozostawiona jest w gestii aplikacji zarządzającej kasami.

Do obsługi trybu modemowego służą następujące funkcje

- Do wykonania połączenia służy funkcja: POS_ModemDial , która wymaga dwóch parametrów – uchwytu globalnego urządzenia (nie uchwytu widoku lokalnego) oraz flagi „wait” oczekiwania na wykonanie połączenia (0 – nie czekaj, 1 – czekaj na zakończenie operacji). W przypadku wyboru trybu bez oczekiwania postęp procesu można monitorować z wykorzystaniem funkcji POS_ModemStatus – poprawne połączenie jest sygnalizowane statusem POSNET_STATUS_MODEM_CONNECTED.
- Do rozłączenia trwającego połączenia służy funkcja: POS_ModemDisconnect , która przyjmuje takie same parametry jak polecenie dzwonienia i wykonuje procedurę rozłączania połączenia,
- Do sprawdzania bieżącego statusu modemu służy funkcja: POS_ModemStatus , która zwraca zestaw flag zależnych od aktualnego stanu połączenia modemowego:

Przykład użycia – patrz demo demo_modem.exe.

## Przykładowa sekwencja poleceń

Obsługa kasy wymaga wykonania pewnego zestawu standardowych operacji. Poniższy opis przedstawia jedną z możliwości na przykładzie polecenia DSPPARAMGET. Przykład jest w języku C++, pominięto obsługę sytuacji wyjątkowych.

            // Deklaracje zmiennych
            POSNET_HANDLE hDevice;
            POSNET_HANDLE hGlobalDevice;
            POSNET_HANDLE hRequest;

            // Wyniki
            unsigned char kontrast;
            unsigned char podswietlenie;
            unsigned char tryb;

            // Utworzenie obiektu urządzenia
            hGlobalDevice = POS_CreateDeviceHandle(POSNET_INTERFACE_RS232);

            // Ustawienie parametrów urządzenia
            POS_SetDeviceParam(hGlobalDevice, POSNET_DEV_PARAM_COMSETTINGS,"COM1,19200,8,N,1,H");

            // Otwarcie urządzenia
            hDevice = POS_OpenDevice(hGlobalDevice);

            // Przygotowanie polecenia
            // Numer polecenia DSPPARAMGET = 101
            hRequest = POS_CreateRequest(hDevice,POSNET_CMDID_DSPPARAMGET);

            // Przygotowanie parametrów polecenia
            // Pobierz dane dla wyświetlacza operatora
            // Wymagany 1 paramter typu 'B' o wartości 0
            POS_PushRequestParamByte(hRequest,0);

            // Wyślij rozkaz do kasy w trybie interaktywnym
            POS_PostRequest(hRequest,POSNET_REQMODE_IMMEDIATE);

            // Oczekuj na wykonanie
            POS_WaitForRequestCompleted(hRequest,INFINITE);

            // Sprawdź czy zakończyło się sukcesem
            if (POS_GetRequestStatus(hRequest) == POSNET_STATUS_OK)
            {
                    // Pobranie wyników, polecenie zwraca 3 wartości typu byte
                    unsigned char kontrast,podswietlenie,tryb;
                    POS_PopResponseValueByte(hRequest,&kontrast);
                    POS_PopResponseValueByte(hRequest,&podswietlenie);
                    POS_PopResponseValueByte(hRequest,&tryb);
            }

            // Usuń stworzone zapytanie
            POS_DestroyRequest(hRequest);

            // Zamknij urządzenie
            POS_CloseDevice(hDevice);

## Wykorzystanie w językach programowania

W wersji prototypowej biblioteka została przetestowana w:

- VisualC++ .NET 2003
- Borland C++ Builder 4
- Delphi 7
- Visual Basic for Applications (MS Excel)
- Ch (http://www.softintegration.com)

Poniżej przedstawiono przykładowy kod dla VBA.

    	Private Declare Function POS_PopSalesQueue Lib "posnet.dll" (ByVal H As Long, ByVal P As Long) As Long

Podobny kod dla Delphi 7

    	function POS_PopSalesQueue (hDevice : THandle; k: longint) : THandle; stdcall; external 'posnet.dll'

## Wersja dla systemu Linux

Natywny port dla systemu Linux składa się z bibliotek:

libposnet.so.1.0

libhlapi.so.1.0

oraz

libptypes.so.2.0.2 (http://www.melikyan.com/ptypes/)

Biblioteki te są zależne także od dostępnych na licencji LGPL bibliotek obsługujących podsystem USB:

libusb - w wersji 0.1.11+ dostępnej standardowo w większości dystrybucji (http://libusb.sourceforge.net/)

oraz

libftdi w wersji 0.7+ (http://www.intra2net.com/de/produkte/opensource/ftdi/index.php) do obsługi konwertera FTDI zastosowanego w urządzeniu.

UWAGA!!! W przypadku korzystania z trybu natywnego USB (POSNET_INTERFACE_USB) do poprawnego działania kasy niezbędne jest zablokowanie automatycznego ładowania i usunięcie jesli jest załadowany modułu jądra ftdi_sio. W przeciwnym razie połączenie z kasą nie będzie możliwe (w pliku logu zgłaszany będzie błąd o kodzie -5), gdyż moduł ten przejmuje kontrolę nad konwerterem FTDI tworząc wirtualny port szeregowy (/dev/ttyUSBx).

W przypadku korzystania w trybie wirtualnego portu szeregowego, sterownik ftdi_sio jest potrzebny.