// uniCenta oPOS - Touch Friendly Point Of Sale
// Copyright (c) 2009-2013 uniCenta & previous Openbravo POS works
// http://www.unicenta.net/unicentaopos
//
// This file is part of uniCenta oPOS
//
// uniCenta oPOS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// uniCenta oPOS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with uniCenta oPOS. If not, see <http://www.gnu.org/licenses/>.
package com.openbravo.pos.scanpal2;
import gnu.io.*;
import java.io.*;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
public class DeviceScannerComm implements DeviceScanner, SerialPortEventListener {
private CommPortIdentifier m_PortIdPrinter;
private SerialPort m_CommPortPrinter;
private String m_sPort;
private OutputStream m_out;
private InputStream m_in;
private static final byte[] COMMAND_READ = new byte[] {0x52, 0x45, 0x41, 0x44};
private static final byte[] COMMAND_CIPHER = new byte[] {0x43, 0x49, 0x50, 0x48, 0x45, 0x52};
private static final byte[] COMMAND_OVER = new byte[] {0x4F, 0x56, 0x45, 0x52};
private static final byte[] COMMAND_ACK = new byte[] {0x41, 0x43, 0x4B};
private Queue<byte[]> m_aLines;
private ByteArrayOutputStream m_abuffer;
private int m_iStatus;
// private static final int STATUS_WAITING = 0;
// private static final int STATUS_LINEREADY = 1;
// private static final int STATUS_READING = 2;
private int m_iProductOrder;
/** Creates a new instance of ScanDeviceComm */
DeviceScannerComm(String sPort) {
m_sPort = sPort;
m_PortIdPrinter = null;
m_CommPortPrinter = null;
m_out = null;
m_in = null;
}
public void connectDevice() throws DeviceScannerException {
try {
// Conecto con el puerto
m_PortIdPrinter = CommPortIdentifier.getPortIdentifier(m_sPort); // Tomamos el puerto
m_CommPortPrinter = (SerialPort) m_PortIdPrinter.open("PORTID", 2000); // Abrimos el puerto
m_out = m_CommPortPrinter.getOutputStream(); // Tomamos el chorro de escritura
m_in = m_CommPortPrinter.getInputStream();
m_CommPortPrinter.addEventListener(this);
m_CommPortPrinter.notifyOnDataAvailable(true);
m_CommPortPrinter.setSerialPortParams(115200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); // Configuramos el puerto
// } catch (NoSuchPortException e) {
// e.printStackTrace();
// } catch (PortInUseException e) {
// e.printStackTrace();
// } catch (UnsupportedCommOperationException e) {
// e.printStackTrace();
// } catch (TooManyListenersException e) {
// e.printStackTrace();
// } catch (IOException e) {
// e.printStackTrace();
} catch (Exception e) {
m_PortIdPrinter = null;
m_CommPortPrinter = null;
m_out = null;
m_in = null;
throw new DeviceScannerException(e);
}
synchronized(this) {
// m_iStatus = STATUS_WAITING;
m_aLines = new LinkedList<byte[]>();
m_abuffer = new ByteArrayOutputStream();
}
}
public void disconnectDevice() {
try {
m_out.close();
m_in.close();
m_CommPortPrinter.close();
} catch (IOException e) {
}
synchronized(this) {
// m_iStatus = STATUS_WAITING;
m_aLines = null;
m_abuffer = null;
}
m_PortIdPrinter = null;
m_CommPortPrinter = null;
m_out = null;
m_in = null;
}
public void startDownloadProduct() throws DeviceScannerException {
writeLine(COMMAND_READ); // writeLine(COMMAND_READ);
readCommand(COMMAND_ACK);
}
public ProductDownloaded recieveProduct() throws DeviceScannerException {
byte[] line = readLine();
if (checkCommand(COMMAND_OVER, line)) {
// La Scanpal a terminado.
return null;
} else {
// procesamos la linea
ProductDownloaded p = new ProductDownloaded();
try {
String sLine = new String(line, 1, line.length - 3, "ISO-8859-1");
StringTokenizer T = new StringTokenizer(sLine, "|");
while (T.hasMoreTokens()) {
String sToken = T.nextToken();
if (sToken.startsWith("IEAN")) {
p.setCode(sToken.substring(4).trim());
} else if (sToken.startsWith("ICANT")) {
try {
p.setQuantity(Double.parseDouble(sToken.substring(5).trim()));
} catch (NumberFormatException e) {
}
}
}
} catch (UnsupportedEncodingException e) {
}
writeLine(COMMAND_ACK);
return p;
}
}
public void startUploadProduct() throws DeviceScannerException {
// Inicializamos la conversacion
writeLine(COMMAND_CIPHER);
readCommand(COMMAND_ACK);
m_iProductOrder = 0;
}
public void sendProduct(String sName, String sCode, Double dPrice) throws DeviceScannerException {
m_iProductOrder++;
ByteArrayOutputStream lineout = new ByteArrayOutputStream();
try {
lineout.write(convert(Integer.toString(m_iProductOrder)));
lineout.write(0x7c); // El Pipe "|"
lineout.write(convert(sName));
lineout.write(0x7c); // El Pipe "|"
lineout.write(convert(sCode));
lineout.write(0x7c); // El Pipe "|"
lineout.write(0x7c); // El Pipe "|"
lineout.write(0x7c); // El Pipe "|"
lineout.write(0x7c); // El Pipe "|"
lineout.write(convert(dPrice.toString()));
lineout.write(0x7c); // El Pipe "|"
// Mandamos el checksum
lineout.write(calcCheckSum1(lineout.toByteArray()));
} catch (UnsupportedEncodingException e) {
} catch (IOException e) {
}
writeLine(lineout.toByteArray());
readCommand(COMMAND_ACK);
}
public void stopUploadProduct() throws DeviceScannerException {
// Cerramos la conversacion
writeLine(COMMAND_OVER);
readCommand(COMMAND_ACK);
}
private void readCommand(byte[] cmd) throws DeviceScannerException {
byte[] b = readLine();
if (!checkCommand(cmd, b)) {
// excepcion que te crio.
throw new DeviceScannerException("Command not expected");
}
}
private void writeLine(byte[] aline) throws DeviceScannerException {
if (m_CommPortPrinter == null) {
throw new DeviceScannerException("No Serial port opened");
} else {
synchronized(this) {
try {
m_out.write(aline);
m_out.write(0x0D);
m_out.flush();
} catch (IOException e) {
throw new DeviceScannerException(e);
}
}
}
}
private byte[] readLine() throws DeviceScannerException {
synchronized (this) {
if (!m_aLines.isEmpty()) {
return m_aLines.poll();
}
// esperamos un ratito
try {
wait(1000);
} catch (InterruptedException e) {
}
if (m_aLines.isEmpty()) {
throw new DeviceScannerException("Timeout");
} else {
return m_aLines.poll();
}
}
}
private byte[] convert(String sdata) {
// return sdata.getBytes("ISO-8859-1");
if (sdata == null) {
return new byte[0];
} else {
byte[] result = new byte[sdata.length()];
for (int i = 0; i < sdata.length(); i++) {
char c = sdata.charAt(i);
if (c == 0x7c) { // El pipe |
result[i] = '.';
} else if ((c >= 0x0020) && (c < 0x0080)) {
result[i] = (byte) c;
} else {
result[i] = ' ';
}
}
return result;
}
}
private byte[] calcCheckSum1(byte[] adata) {
int isum = 0;
for (int i = 0; i < adata.length; i++) {
isum += adata[i];
}
byte high = (byte) ((isum & 0xFF00) >> 8);
if (high == 0x0D) high = 0x0E;
byte low = (byte) (isum & 0x00FF);
if (low == 0x0D) low = 0x0E;
byte[] result = new byte[2];
result[0] = high;
result[1] = low;
return result;
}
private boolean checkCommand(byte[] bcommand, byte[] brecieved) {
if (bcommand.length == brecieved.length) {
for (int i = 0; i < bcommand.length; i++) {
if (bcommand[i] != brecieved[i]) {
return false;
}
}
return true;
} else {
return false;
}
}
public void serialEvent(SerialPortEvent e) {
// Determine type of event.
switch (e.getEventType()) {
case SerialPortEvent.BI:
case SerialPortEvent.OE:
case SerialPortEvent.FE:
case SerialPortEvent.PE:
case SerialPortEvent.CD:
case SerialPortEvent.CTS:
case SerialPortEvent.DSR:
case SerialPortEvent.RI:
case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
break;
case SerialPortEvent.DATA_AVAILABLE:
try {
while (m_in.available() > 0) {
int b = m_in.read();
synchronized(this) {
if (b == 0x0D) {
m_aLines.add(m_abuffer.toByteArray());
m_abuffer.reset();
notifyAll();
} else {
m_abuffer.write(b);
}
}
}
} catch (IOException eIO) {}
break;
}
}
}