Drukarka fiskalna INNOVA Profit, drukowanie paragonów.

0

Trafiło mi się napisanie malutkiego programu drukującego paragony na drukarce Innova Profit. Ze strony producenta pozyskałem instrukcję programisty (gdyby ktoś chciał rzucić okiem to proszę:
http://www.innova-sa.pl/innova/images/upload/Instrukcja%20programisty%20-%20INNOVA%20PROFIT.pdf, trochę poczytałem i zabrałem się za pisanie. (mam drukarkę na czas pisania),(nie robiłem tego wcześniej).

Na początku postanowiłem wydrukować jakiś przykładowy paragon, żeby sprawdzić czy wszystko ze sobą gada.
Zgodnie z instrukcjami posłałem na port takie coś:

s:= Chr($1B) + Chr($50) +'0'$h1$lNAZWA TOWARU<CR>1<CR>B/1.30/1.30/'+'1;0$e001<CR>110.80/110.80/';

//poniżej liczę sumę kontrolną zgodnie z instrukcjami. Wzór znalazłem też w niektórych źródłach w sieci. Generalnie syntaktyka rozkazów jest chyba taka sama lub podobna do posnetu ze tego co zauważyłem.

begin 
  check := 255;
  for i:= 3 to length(s) do
    check := check xor byte(s[i]);
  result:=byte_to_hex(check); //oczywiście mam wcześniej w kodzie zadeklarowane check, result itd
end;

  s:= s+result +Chr($1B) + '\';
  serialportng1.sendstring(s); // do komunikacji z urządzeniem używam serialportng

Program się kompiluje bezbłędnie, sygnał na port jest wysyłany (sprawdzałem port monitorem) i dochodzi do drukarki, ale na wyświetlaczu urządzenia pojawia się komunikat BŁĄD ROZKAZU: $h

Nie mam pojęcia co tu jest nie tak. $h jest wpisane zgodnie z instrukcjami programisty. Jest to sekwencja otwierająca transakcję. Próbowałem na różne sposoby. Usunąłem nawet $h, to z kolei błąd pojawił się na $l .
Drukarka podłączona jest do laptopa poprzez port usb. Jest sprawna w 100%.

Czy ktoś mógłby mi coś podpowiedzieć w tej sytuacji? Dalej sobie ze wszystkim poradzę, ale drukarka musi zachcieć gadać z moim programem.

0

Witam, nie wiem czy dobrze kojarzę ale innova ma chyba zaimplementowany strikte protokół posneta to możesz skorzystać z oryginalnej biblioteki dostępnej na stronie posnet-u.

0

ale to co wysyłasz ma się nijak do tego co jest w instrukcji. Popatrz dokładnie co tam pisze

0

Misiek naprowadź mnie jakoś bo polegnę. Na tobie to jeszcze się tutaj nie zawiodłem, zawsze mnie jakoś pokierowałeś, mam nadzieję że tym razem też tak będzie, bo to ważny temat dla mnie.

0

pokaże Ci jak drukować paragon online
ESC - to znak o kodzie 27
<check> - to suma kontrolna tego co jest pomiędzy ESC P a <check>
CR - to znak o kodzie 13
spacje są tylko dla czytelności zapisu

  1. trzeba najpierw rozpocząć paragon
    ESC P 0 $h <check> ESC\

  2. potem drukujesz linie paragonu
    for n := 0 to x do
    ESC P n $l <nazwa> CR <ilość> CR <ptu>/ CENA/ BRUTTO/ <check> ESC
    uwaga: brutto musi być równe cena*ilość zaokrąglone do dwóch miejsc po przecinku

  3. o na koniec trzeba zatwierdzić paragon
    ESC P 1; 0 $e <kod> CR WPLATA/TOTAL/ <check> ESC
    total musi się zgadzać z sumą poszczególnych wartości brutto.

Przykład paragonu z jedną linią

#27'P0$h' + check + #27'\';
#27'P0$lDelphi 2009'#13'2 szt'#13'0001/999/1998/' + check + #27'\';
#27'P1;0$e001'#13'2000/1998/' + check + #13'\';

Jest to najprostszy schemat - nie ma rabatów, sprawdzania odpowiedzi itp. Dokumentacja jes naprawdę czytelna a oprogramowanie tego wcale nie jest takie trudne. Całkiem niedawno pisałem to samo ale nie mogę dać Ci kodu bo wziąłem za to pieniądze i było by to nie fair w stosunku do zleceniodawcy

BTW to jest protokół posnet

0

Dzięki wielkie misiek za szybką odpowiedź, ale po wysłaniu linii podanych przez ciebie, powstaje ten sam problem na $h i drukarka sygnalizuje ten sam błąd, o którym pisałem w moim pierwszym poście.

Dla pewności: wysyłam linia po linii czyli najpierw sendstring(pierwsza linia), potem sendstring(druga) i sendstring(trzecia) i oczywiście dla każdej linii liczę sumy. Zapewne nadal robię coś nie tak?

A może źle liczę sumę?

  s:=#27'P0$h';

  begin
  check := 255; 
  for i:= 3 to length(s) do
  check := check xor byte(s[i]);
  result:=byte_to_hex(check);
  end;

  s:=s + result + #27'\';

Próbowałem też tak:

  s:='P0$h';

  begin
  check := 255; 
  for i:= 0 to length(s) do
  check := check xor byte(s[i]);
  result:=byte_to_hex(check);
  end;

  s:=#27+s + result + #27'\';
0

Wykonaj najpierw raport dobowy np. programem serwisowym, a jak nie chcesz walczyć to tak jak pisałem weź gotową bibliotekę z posnet-u.

0

Wydrukowanie raportu dobowego nie pomogło. Chcę walczyć :)

0

co to jest byte_to_hex?
jak wysyłasz ciąg na coma?

kod, który działa z posnetem

function TPosNetThermal.CalcCRC(Data: string): string;
var
  CRC: byte;
  i: integer;
begin
  CRC := 255;
  for i := 1 to Length(Data) do
    CRC := CRC xor byte(Data[i]);
  Result := IntToHex(CRC, 2);
end;

procedure TPosNetThermal.SendCommand(const Data: string);
begin
  FComPort.WriteStr(#27 + 'P' + Data + CalcCRC(Data) + #27 + '\');
end;

procedure TPosNetThermal.BeginTransaction;
begin
  SendCommand('0$h');
end;
0

byte_to_hex to funkcja, którą znalazłem gdzieś na tym forum, ale już zmieniłem metodę liczenia sumy na twoją i pod buttona podpinam:

serialportng1.active:=true;
data:='P0$hP0$lDelphi 2009'#13'2 szt'#13'0001/999/1998/P1;0$e001'#13'2000/1998/';
serialportng1.sendstring(#27 + 'P' + Data + CalcCRC(Data) + #27 + '\');
serialportng1.active:=false;

i teraz pojawia się na wyświetlaczu błąd rozkazu 'P0', pewnie słusznie, ale niestety moja głowa nie wie dlaczego. Może błędem jest wysyłanie tego w jednej linii?

0

po porostu spróbuj w trzech...

0

Poszło w ten sposób:

serialportng1.active:=true;
data:='P0$h';
serialportng1.sendstring(#27 + 'P' + Data + CalcCRC(Data) + #27 + '\');
data:='P0$lDelphi 2009'#13'2 szt'#13'0001/999/1998/';
serialportng1.sendstring(#27 + 'P' + Data + CalcCRC(Data) + #27 + '\');
data:='P1;0$e001'#13'2000/1998/';
serialportng1.sendstring(#27 + 'P' + Data + CalcCRC(Data) + #27 + '\');

serialportng1.active:=false;

i nadal błąd rozkazu 'P0' .

0

ręce opadają...
#27'P0$lDelphi 2009'#13'2 szt'#13'0001/999/1998/' + check + #27'';
#27'PP0$lDelphi 2009'#13'2 szt'#13'0001/999/1998/' + CalcCRC(Data) + #27 + ''

widzisz różnicę?

0

Jasne, że widzę: 2xP i check w jednej linii i calccrc w drugiej ale za czorta nie mam pojęcia jakie wnioski z tego wyciągnąć? W kodzie ma być 'PP0'? A może bez P? Głupieje już normalnie. Przepraszam misiek, że cię męczę, ale czuję, że jesteśmy już blisko.

0

jedno...
Podałem Ci przykładowy ciąg do wysłania - ile tam masz P
Podałem Ci kod w delphi
Masz opis komunikacji po polsku
Weź rzesz to złóż do kupy

0

Składam i złożyć nie mogę.

W którym miejscu w takim razie w tym co wysyłam na port jest błąd? Nie wiem nie wiem nie wiem nie wiem. Misiek zlituj się! :) Pokaż mi proszę palcem przyczynę błędu bo jak widzisz za słaby jestem, żeby ją znaleźć.

Skoro taki zapis jest błędny:

#27'P0$lDelphi 2009'#13'2 szt'#13'0001/999/1998/' + CalcCRC(Data) + #27 + '\'

to jaki zatem będzie poprawny?

Hmmmmm...... Czyżby zamiast P0 P1 itp mają być po prostu 0, 1 itp (bez tego nieszczęsnego P)?
Niestety gdyby nawet tak było to i tak pojawia mi się znowu błąd $h.

0

Misiek masz już mnie dosyć co? Niestety wstyd się przyznać, ale nic nowego nie wymyśliłem.

0
serialportng1.active:=true;
data:='0$h';
serialportng1.sendstring(#27 + 'P' + Data + CalcCRC(Data) + #27 + '\');
data:='0$lDelphi 2009'#13'2 szt'#13'0001/999/1998/';
serialportng1.sendstring(#27 + 'P' + Data + CalcCRC(Data) + #27 + '\');
data:='1;0$e001'#13'2000/1998/';
serialportng1.sendstring(#27 + 'P' + Data + CalcCRC(Data) + #27 + '\');

serialportng1.active:=false;

nie możesz tego wziąć do kupy i wyliczyć jedno CRC! Każda linijka to osobna komenda i każda ma swój początek, CRC i koniec.

0

Niestety wysyłam to w takim kształcie jak napisałeś i nadal błąd rozkazu: $h, kod błędu: 00. Ja się zastrzelę, no chyba, że ty mnie prędzej odstrzelisz.

Poniżej zamieszczam to co zostało wysłane na port (skopiowane z serialport monitor):

Port opened by process "INNOVA1.exe" (PID: 1944)

Request: 09-11-2009 1344.85664

1B 50 30 24 68 38 33 1B 5C .P0$h83.\

Port closed

0
  1. ściągnij sobie ComPort http://sourceforge.net/projects/comport/
  2. pacnij na formę i kliknij dwa razy
  3. ustaw odpowiednio com i ustaw Connected na true
  4. w kodzie pod przyciskiem daj
var
  ENQ, DLE: byte;
begin
  ENQ := 0;
  DLE := 0;
  FComPort.ClearBuffer(True, True);
  FComPort.WriteStr(#05);
  FComPort.Read(ENQ, 1);
  i := 0;
  while (ENQ = 0) and (i < 100) do
  begin
    Sleep(20);
    FComPort.Read(ENQ, 1);
    Inc(i);
  end;

  FComPort.ClearBuffer(True, True);
  FComPort.WriteStr(#16);
  FComPort.Read(DLE, 1);
  i := 0;
  while (DLE = 0) and (i < 100) do
  begin
    Sleep(20);
    FComPort.Read(DLE, 1);
    Inc(i);
  end;
  mmo1.Lines.Add('Read OK: ' + BoolToStr((ENQ <> 0) and (DLE <> 0), True));
  mmo1.Lines.Add('Last Transact Ok: ' + BoolToStr((ENQ and 1) = 1, True));
  mmo1.Lines.Add('In transact mode: ' + BoolToStr((ENQ and 2) = 2, True));
  mmo1.Lines.Add('Last Command Ok: ' + BoolToStr((ENQ and 4) = 4, True));
  mmo1.Lines.Add('Fiskal: ' + BoolToStr((ENQ and 8) = 8, True));
  mmo1.Lines.Add('Driver Error: ' + BoolToStr((DLE and 1) = 1, True));
  mmo1.Lines.Add('Paper End: ' + BoolToStr((DLE and 2) = 2, True));
  mmo1.Lines.Add('On Line: ' + BoolToStr((DLE and 4) = 4, True));
end;

i daj to co dostaniesz w memo

0

Godziny pracy i głównie obserwacja tego co jest wysyłane na port przez program serwisowy oraz to co jest wysyłane z mojego programu pomogły mi napisać w końcu prawidłowy kod wysyłany do urządzenia, żeby w końcu prawidłowo wydrukować paragon.
Oto on:

serialportng1.active:=true;
data:='0;1$h#'#13;
serialportng1.sendstring(#27 + 'P' + Data + calccrc(data) + #27 + '\'#13);

data:='1$lŻywiec 0.5l'#13'1'#13'A/1/1.00/';
serialportng1.sendstring(#27 + 'P' + Data + calccrc(data) + #27 + '\'#13);

data:='0;0;0;0;1;0;0;0;0;0;0$x'#13#13#13#13#13#13#13#13#13'1.00/0.00/1/0.00/0.00/0.00/0.00/0.00/0.00/';
serialportng1.sendstring(#27 + 'P' + Data + calccrc(data) + #27 + '\'#13);

Myślę, że teraz pójdzie z górki. Misiek dzięki wielkie za rozjaśnienie tematu. Jestem twoim dłużnikiem.

0

Niestety pojawił się kolejny problem.

Mianowicie kiedy na paragonie chcę wydrukować więcej niż dwie pozycje, pojawia się błąd kwoty total. Przez port monitor zauważyłem, że na port wysyłane są tylko dwie pozycje mimo, że wysyłam trzy.
Wysyłając takie same pozycje z programu diagnostycznego drukarki wszystko drukuje się bez problemu, ale zauważyłem, że sygnał jest wysyłany na zasadzie request -> answer a u mnie sygnał to tylko request. Wywnioskowałem z tego, że być może jest tak, że długość polecenia dla trzech pozycji wysyłanego z mojego programu jest za długa, dlatego drukarka przyjmuje tylko dwie pozycje.

Sygnał wysyłany z programu diagnostycznego wygląda tak:

Port opened by process "printo_serw.exe" (PID: 672)

Request: 11-11-2009 00:19:46.07364

 1B 50 30 3B 31 24 68 23 0D 41 37 1B 5C 05         .P0;1$h#.A7.\.  

Answer: 11-11-2009 00:19:46.27664 (+0.1094 seconds)

 66                                                f               

Request: 11-11-2009 00:20:08.62064 (+22.3438 seconds)

 1B 50 31 24 6C 61 61 61 0D 31 0D 41 2F 31 31 2F   .P1$laaa.1.A/11/
 31 31 2F 42 38 1B 5C 05                           11/B8.\.        

Answer: 11-11-2009 00:20:08.83964 (+0.1250 seconds)

 66                                                f      

Dlatego chciałbym zapytać w jaki sposób zaczarować sygnał, żeby działało to tak jak w programie diagnostycznym, czyli REQUEST -> ANSWER.

PS. Jak wysyłam z mojego programu dwie pozycje na paragonie to wszystko się drukuje bezbłędnie.
PS2. Przerzuciłem się z serialng na comport.

0

Sprawa rozwiązana. Wystarczyło dodać +char($05) na końcu każdego rozkazu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1