From 52d3803275e78f5a566e6266e616839071fffd04 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Wed, 18 Oct 2017 21:37:11 +0200 Subject: [PATCH] Source ruffy@eb659b3aa47a1ed699789df7e50e0d80c4640cc3, with pumpdata hackery. --- app/src/main/AndroidManifest.xml | 6 + .../jotomo/ruffyscripter/RuffyScripter.java | 14 +- .../d/ruffy/ruffy/driver/AppHandler.java | 24 + .../d/ruffy/ruffy/driver/Application.java | 369 +++ .../d/ruffy/ruffy/driver/BTConnection.java | 298 ++ .../d/ruffy/ruffy/driver/BTHandler.java | 21 + .../ruffy/driver/CompleteDisplayHandler.java | 9 + .../d/ruffy/ruffy/driver/ConnectReceiver.java | 44 + .../monkey/d/ruffy/ruffy/driver/Display.java | 87 + .../d/ruffy/ruffy/driver/DisplayUpdater.java | 11 + .../monkey/d/ruffy/ruffy/driver/Frame.java | 124 + .../d/ruffy/ruffy/driver/ListenThread.java | 43 + .../d/ruffy/ruffy/driver/LogHandler.java | 11 + .../monkey/d/ruffy/ruffy/driver/Packet.java | 203 ++ .../d/ruffy/ruffy/driver/PacketHandler.java | 17 + .../d/ruffy/ruffy/driver/PairingRequest.java | 66 + .../monkey/d/ruffy/ruffy/driver/Protocol.java | 91 + .../monkey/d/ruffy/ruffy/driver/PumpData.java | 139 + .../monkey/d/ruffy/ruffy/driver/Ruffy.java | 412 +++ .../ruffy/ruffy/driver/Twofish_Algorithm.java | 836 ++++++ .../ruffy/driver/Twofish_Properties.java | 199 ++ .../monkey/d/ruffy/ruffy/driver/Utils.java | 251 ++ .../ruffy/driver/display/DisplayParser.java | 129 + .../driver/display/DisplayParserHandler.java | 11 + .../d/ruffy/ruffy/driver/display/Menu.java | 67 +- .../ruffy/ruffy/driver/display/MenuType.java | 77 +- .../d/ruffy/ruffy/driver/display/Symbol.java | 62 + .../d/ruffy/ruffy/driver/display/Token.java | 40 + .../ruffy/driver/display/menu/MenuDate.java | 2 +- .../driver/display/menu/MenuFactory.java | 2427 +++++++++++++++++ .../ruffy/driver/display/menu/MenuTime.java | 2 +- .../ruffy/driver/display/menu/Title.java | 18 + .../driver/display/menu/TitleResolver.java | 459 ++++ .../display/parser/CharacterPattern.java | 23 + .../display/parser/LargeTextParser.java | 683 +++++ .../driver/display/parser/NumberPattern.java | 23 + .../ruffy/driver/display/parser/Pattern.java | 79 + .../display/parser/SmallTextParser.java | 1152 ++++++++ .../driver/display/parser/SymbolPattern.java | 26 + 39 files changed, 8459 insertions(+), 96 deletions(-) create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/AppHandler.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Application.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/BTConnection.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/BTHandler.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/CompleteDisplayHandler.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/ConnectReceiver.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Display.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/DisplayUpdater.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Frame.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/ListenThread.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/LogHandler.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Packet.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/PacketHandler.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/PairingRequest.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Protocol.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/PumpData.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Ruffy.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Twofish_Algorithm.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Twofish_Properties.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Utils.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/DisplayParser.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/DisplayParserHandler.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/Symbol.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/Token.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuFactory.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/Title.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/TitleResolver.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/CharacterPattern.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/LargeTextParser.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/NumberPattern.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/Pattern.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/SmallTextParser.java create mode 100644 ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/SymbolPattern.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index be3c0e5d80..8420b26768 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -105,6 +105,12 @@ + + + packet = Packet.buildPacket(sendR, payload, true,btConn); //Add the payload, set the address if valid + + if(reliable) { + int seq = btConn.seqNo; + packet.set(1, setSeqRel(packet.get(1), true,btConn)); //Set the sequence and reliable bits + } + Packet.adjustLength(packet, payload.capacity()); //Set the payload length + + packet = Utils.ccmAuthenticate(packet, btConn.getPumpData().getToPumpKey(), btConn.getPumpData().getNonceTx()); //Authenticate packet + + + List temp = Frame.frameEscape(packet); + byte[] ro = new byte[temp.size()]; + int i = 0; + for(byte b : temp) + ro[i++]=b; + + btConn.write(ro); + } + + private static Byte setSeqRel(Byte b, boolean rel, BTConnection btConn) + { + b = (byte) (b | btConn.seqNo); //Set the sequence bit + + if(rel) + b = (byte) (b |0x20); //Set the reliable bit + + btConn.seqNo ^= 0x80; + + return b; + } + private static byte[] service_activate = {16, 0, 0x66, (byte)0x90}; + private static byte[] service_deactivate = {16, 0, 0x69, (byte)0x90}; + + public static void sendAppCommand(Command command, BTConnection btConn){ + ByteBuffer payload = null; + + String s = ""; + + boolean reliable = true; + + switch(command) + { + case COMMAND_MODE: + s = "COMMAND_ACTIVATE"; + payload = ByteBuffer.allocate(7); + payload.put(service_activate); + payload.put((byte)0xB7); + payload.put((byte)0x01); + payload.put((byte)0x00); + reliable = true; + break; + + case COMMAND_DEACTIVATE: + s = "COMMAND DEACTIVATE"; + payload = ByteBuffer.allocate(5); + payload.put(service_deactivate); + payload.put((byte)0xB7); + reliable = true; + break; + case RT_MODE: + s = "RT_ACTIVATE"; + payload = ByteBuffer.allocate(7); + payload.put(service_activate); + payload.put((byte)0x48); + payload.put((byte)0x01); + payload.put((byte)0x00); + reliable = true; + break; + case RT_DEACTIVATE: + s = "RT DEACTIVATE"; + payload = ByteBuffer.allocate(5); + payload.put(service_deactivate); + payload.put((byte)0x48); + reliable = true; + break; + case COMMANDS_SERVICES_VERSION: + s = "COMMAND_SERVICES_VERSION"; + payload = ByteBuffer.allocate(5); + payload.put((byte)16); + payload.put((byte)0); + payload.put((byte) (((short)0x9065) & 0xFF)); + payload.put((byte) ((((short)0x9065)>>8) & 0xFF)); + payload.put((byte)0xb7); + reliable = true; + break; + case REMOTE_TERMINAL_VERSION: + s = "REMOTE_TERMINAL_VERSION"; + payload = ByteBuffer.allocate(5); + payload.put((byte)16); + payload.put((byte)0); + payload.put((byte) (((short)0x9065) & 0xFF)); + payload.put((byte) ((((short)0x9065)>>8) & 0xFF)); + payload.put((byte)0x48); + reliable = true; + break; + case BINDING: + s = "BINDING"; + payload = ByteBuffer.allocate(5); + payload.put((byte)16); + payload.put((byte)0); + payload.put((byte) (((short)0x9095) & 0xFF)); + payload.put((byte) ((((short)0x9095)>>8) & 0xFF)); + payload.put((byte) 0x48); //Binding OK + reliable = true; + break; + + case APP_DISCONNECT: + byte[] connect_app_layer = {16 , 0, 0x5a, 0x00}; + payload = ByteBuffer.allocate(6); //4 bytes for application header, 4 for payload + payload.put(connect_app_layer); //Add prefix array + payload.order(ByteOrder.LITTLE_ENDIAN); + payload.putShort((byte)0x6003); + reliable = true; + break; + + case CMD_PING: + payload.put((byte)16); + payload.put((byte)0xB7); + payload.put((byte) (0x9AAA & 0xFF)); + payload.put((byte) ((0x9AAA>>8) & 0xFF)); + reliable = false; + break; + + default: + s = "uknown subcommand: "+command; + break; + } + + if(payload != null) + { + sendData(payload,reliable,btConn); + } + } + + public static void sendAppDisconnect(BTConnection btConn) { + sendAppCommand(Command.APP_DISCONNECT,btConn); + } + + public static void cmdPing(BTConnection btConn) + { + sendAppCommand(Command.CMD_PING,btConn); + } + + public static short sendRTKeepAlive(short rtSeq, BTConnection btConn) { + ByteBuffer payload = ByteBuffer.allocate(6); + payload.put((byte)16); + payload.put((byte)0x48); + payload.put((byte) (0x0566 & 0xFF)); + payload.put((byte) ((0x0566>>8) & 0xFF)); + + payload.put((byte) (rtSeq & 0xFF)); + payload.put((byte) ((rtSeq>>8) & 0xFF)); + + sendData(payload,false,btConn); + + btConn.log("/////////////////////////////////////////////////////////////////////"); + btConn.log("send alive with seq: "+rtSeq); + btConn.log("/////////////////////////////////////////////////////////////////////"); + rtSeq++; + return rtSeq; + + } + + public static void cmdErrStatus(BTConnection btConn) + { + ByteBuffer payload = ByteBuffer.allocate(4); + payload.put((byte)16); + + payload.put((byte)0x48); + + payload.put((byte) (0x9AA5 & 0xFF)); + payload.put((byte) ((0x9AA5>>8) & 0xFF)); + + sendData(payload, true, btConn); + } + + public static short rtSendKey(byte key, boolean changed,short rtSeq, BTConnection btConn) + { + ByteBuffer payload = ByteBuffer.allocate(8); + + payload.put((byte)16); + payload.put((byte)0x48); + payload.put((byte) 0x65); + payload.put((byte) 0x05); + + payload.put((byte) (rtSeq & 0xFF)); + payload.put((byte) ((rtSeq>>8) & 0xFF)); + + payload.put(key); + + if(changed) + payload.put((byte) 0xB7); + else + payload.put((byte) 0x48); + + btConn.log("/////////////////////////////////////////////////////////////////////"); + String k = ""; + switch (key) + { + case 0x00: + k="NOKEY"; + break; + case 0x03: + k="MENU"; + break; + case 0x0C: + k="CHECK"; + break; + case 0x30: + k="UP"; + break; + case (byte)0xC0: + k="DOWN"; + break; + } + btConn.log("send key "+k+" with seq: "+rtSeq); + btConn.log("/////////////////////////////////////////////////////////////////////"); + sendData(payload, false, btConn); + + rtSeq++; + return rtSeq; + } + + public static void processAppResponse(byte[] payload, boolean reliable, AppHandler handler) { + handler.log("processing app response"); + ByteBuffer b = ByteBuffer.wrap(payload); + b.order(ByteOrder.LITTLE_ENDIAN); + + b.get();//ignore + byte servId = b.get(); + short commId = b.getShort(); + + handler.log("Service ID: " + String.format("%X", servId) + " Comm ID: " + String.format("%X", commId) + " reliable: " + reliable); + + String descrip = null; + if(reliable) + { + short error = b.getShort(); + if (!cmdProcessError(error,handler)) { + return; + } + + switch (commId) { + case (short) 0xA055://connect answer: + handler.connected(); + break; + case (short) 0xA065://something + case (short) 0xA095://bind + handler.log("not should happen here!"); + break; + case (short) 0xA066://activate rt: + handler.rtModeActivated(); + break; + case (short) 0x005A://AL_DISCONNECT_RES: + descrip = "AL_DISCONNECT_RES"; + break; + case (short) 0xA069://service deactivated + descrip = "AL_DEACTIVATE_RES"; + handler.modeDeactivated(); + break; + case (short) 0xA06A://service all deactivate + descrip = "AL_DEACTIVATE_ALL_RES"; + handler.modeDeactivated(); + break; + default: + descrip = "UNKNOWN"; + break; + } + } else { + switch (commId) { + case (short) 0x0555://Display frame + handler.addDisplayFrame(b); + break; + case (short) 0x0556://key answer + break; + case (short) 0x0566://alive answer, often missed + break; + default: + descrip = "UNKNOWN"; + break; + } + } + handler.log("appProcess: "+descrip); + } + + private static boolean cmdProcessError(short error, AppHandler handler) { + String desc = "Error > " + String.format("%X", error) + " "; + + if (error == 0x0000) { + desc = "No error found!"; + return true; + } else { + switch (error) { + //Application Layer **********************************************// + case (short) 0xF003: + desc = "Unknown Service ID, AL, RT, or CMD"; + break; + case (short) 0xF006: + desc = "Invalid payload length"; + break; + case (short) 0xF05F: + desc = "wrong mode"; + handler.modeError(); + break; + + case (short) 0xF50C: + desc = "wrong sequence"; + handler.sequenceError(); + break; + case (short) 0xF533: + desc = "died - no alive"; + break; + case (short) 0xF056: + desc = "not complete connected"; + break; + } + + handler.error(error,desc); + return false; + } + } +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/BTConnection.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/BTConnection.java new file mode 100644 index 0000000000..08bc14b509 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/BTConnection.java @@ -0,0 +1,298 @@ +package org.monkey.d.ruffy.ruffy.driver; + +import android.app.Activity; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothServerSocket; +import android.bluetooth.BluetoothSocket; +import android.content.Intent; +import android.content.IntentFilter; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +/** + * Created by SandraK82 on 15.05.17. + */ + +public class BTConnection { + private final BTHandler handler; + private BluetoothAdapter bluetoothAdapter; + private ListenThread listen; + + private BluetoothSocket currentConnection; + + public int seqNo; + private InputStream currentInput; + private OutputStream currentOutput; + private PairingRequest pairingReciever; + private ConnectReceiver connectReceiver; + + private PumpData pumpData; + + public BTConnection(final BTHandler handler) + { + this.handler = handler; + bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + if (!bluetoothAdapter.isEnabled()) { + handler.requestBlueTooth(); + } + } + + public void makeDiscoverable(Activity activity) { + + this.pumpData = new PumpData(activity); + + IntentFilter filter = new IntentFilter("android.bluetooth.device.action.PAIRING_REQUEST"); + pairingReciever = new PairingRequest(activity, handler); + activity.registerReceiver(pairingReciever, filter); + + Intent discoverableIntent = new Intent("android.bluetooth.adapter.action.REQUEST_DISCOVERABLE"); + discoverableIntent.putExtra("android.bluetooth.adapter.extra.DISCOVERABLE_DURATION", 60); + discoverableIntent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE); + activity.startActivity(discoverableIntent); + + BluetoothServerSocket srvSock = null; + try { + srvSock = bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord("SerialLink", UUID.fromString("00001101-0000-1000-8000-00805f9b34fb")); + } catch (IOException e) { + handler.fail("socket listen() failed"); + return; + } + + final BluetoothServerSocket lSock = srvSock; + listen = new ListenThread(srvSock); + + filter = new IntentFilter("android.bluetooth.device.action.ACL_CONNECTED"); + connectReceiver = new ConnectReceiver(handler); + activity.registerReceiver(connectReceiver, filter); + + ScheduledExecutorService scheduler = Executors.newScheduledThreadPool( 1 ); + scheduler.execute(listen); + } + + public void stopDiscoverable() { + if(listen!=null) + { + listen.halt(); + } + if(bluetoothAdapter.isDiscovering()) + { + bluetoothAdapter.cancelDiscovery(); + } + } + + public void connect(BluetoothDevice device) { + connect(device.getAddress(), 4); + } + + public void connect(PumpData pumpData, int retries) + { + this.pumpData = pumpData; + connect(pumpData.getPumpMac(),retries); + } + + private int state = 0; + + private void connect(String deviceAddress, int retry) { + + if(state!=0) + { + handler.log("in connect!"); + return; + } + state=1; + BluetoothDevice device = bluetoothAdapter.getRemoteDevice(deviceAddress); + + BluetoothSocket tmp = null; + try { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + tmp = device.createInsecureRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805f9b34fb")); + } catch (IOException e) { + handler.log("socket create() failed: "+e.getMessage()); + } + if(tmp != null) { + stopDiscoverable(); + activateConnection(tmp); + } + else + { + handler.log("failed the pump connection( retries left: "+retry+")"); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + if(retry>0) + { + connect(deviceAddress,retry-1); + } + else + { + handler.fail("Failed to connect"); + } + } + } + + private void startReadThread() { + new Thread() { + @Override + public void run() { + try { + currentConnection.connect();//This method will block until a connection is made or the connection fails. If this method returns without an exception then this socket is now connected. + currentInput = currentConnection.getInputStream(); + currentOutput = currentConnection.getOutputStream(); + } catch (IOException e) { + //e.printStackTrace(); + handler.fail("no connection possible"); + + + //?????????? + //state=1; + //return; + } + try { + pumpData.getActivity().unregisterReceiver(connectReceiver); + }catch(Exception e){/*ignore*/} + try { + pumpData.getActivity().unregisterReceiver(pairingReciever); + }catch(Exception e){/*ignore*/} + state=0; + + //here check if really connected! + //this will start thread to write + handler.deviceConnected();//in ruffy.java + + + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + byte[] buffer = new byte[512]; + while (true) { + try { + int bytes = currentInput.read(buffer); + handler.log("read "+bytes+": "+ Utils.byteArrayToHexString(buffer,bytes)); + handler.handleRawData(buffer,bytes); + } catch (Exception e) { + //e.printStackTrace(); + //do not fail here as we maybe just closed the socket.. + handler.log("got error in read"); + return; + } + } + } + }.start(); + } + + public void writeCommand(byte[] key) { + List out = new LinkedList(); + for(Byte b : key) + out.add(b); + for (Byte n : pumpData.getNonceTx()) + out.add(n); + Utils.addCRC(out); + + List temp = Frame.frameEscape(out); + + byte[] ro = new byte[temp.size()]; + int i = 0; + for(byte b : temp) + ro[i++]=b; + + StringBuilder sb = new StringBuilder(); + for (i = 0; i < key.length; i++) { + sb.append(String.format("%02X ", key[i])); + } + handler.log("writing command: "+sb.toString()); + write(ro); + } + + private void activateConnection(BluetoothSocket newConnection){ + if(this.currentConnection!=null) + { + try { + this.currentOutput.close(); + } catch (Exception e) {/*ignore*/} + try { + this.currentInput.close(); + } catch (Exception e) {/*ignore*/} + try { + this.currentConnection.close(); + } catch (Exception e) {/*ignore*/} + this.currentInput=null; + this.currentOutput=null; + this.currentConnection=null; + handler.log("closed current Connection"); + } + handler.log("got new Connection: "+newConnection); + this.currentConnection = newConnection; + if(newConnection!=null) + { + startReadThread(); + } + } + + public void write(byte[] ro){ + + handler.log("!!!write!!!"); + + if(this.currentConnection==null) + { + handler.fail("unable to write: no socket"); + return; + } + try { + currentOutput.write(ro); + handler.log("wrote "+ro.length+" bytes: "+ Utils.byteArrayToHexString(ro,ro.length)); + }catch(Exception e) + { + //e.printStackTrace(); + handler.fail("failed write of "+ro.length+" bytes!"); + } + } + + public void log(String s) { + if(handler!=null) + handler.log(s); + } + + public void disconnect() { + try { + this.currentOutput.close(); + } catch (Exception e) {/*ignore*/} + try { + this.currentInput.close(); + } catch (Exception e) {/*ignore*/} + try { + this.currentConnection.close(); + } catch (Exception e) {/*ignore*/} + this.currentInput=null; + this.currentOutput=null; + this.currentConnection=null; + this.pumpData = null; + + handler.log("disconnect() closed current Connection"); + } + + public PumpData getPumpData() { + return pumpData; + } + + public boolean isConnected() { + return this.currentConnection != null && this.currentConnection.isConnected(); + } +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/BTHandler.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/BTHandler.java new file mode 100644 index 0000000000..322371bb89 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/BTHandler.java @@ -0,0 +1,21 @@ +package org.monkey.d.ruffy.ruffy.driver; + +import android.bluetooth.BluetoothDevice; + +/** + * Created by fishermen21 on 15.05.17. + */ + +public interface BTHandler { + void deviceConnected(); + + void log(String s); + + void fail(String s); + + void deviceFound(BluetoothDevice bd); + + void handleRawData(byte[] buffer, int bytes); + + void requestBlueTooth(); +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/CompleteDisplayHandler.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/CompleteDisplayHandler.java new file mode 100644 index 0000000000..d0553e7c06 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/CompleteDisplayHandler.java @@ -0,0 +1,9 @@ +package org.monkey.d.ruffy.ruffy.driver; + +/** + * Created by fishermen21 on 20.05.17. + */ + +public interface CompleteDisplayHandler { + void handleCompleteFrame(byte[][] pixels); +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/ConnectReceiver.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/ConnectReceiver.java new file mode 100644 index 0000000000..18024ae52e --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/ConnectReceiver.java @@ -0,0 +1,44 @@ +package org.monkey.d.ruffy.ruffy.driver; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +/** + * Created by fishermen21 on 15.05.17. + */ + +public class ConnectReceiver extends BroadcastReceiver { + private final BTHandler handler; + + + public ConnectReceiver(BTHandler handler) + { + this.handler = handler; + } + + public void onReceive(Context context, Intent intent) { + for(String k: intent.getExtras().keySet()) + { + if(k.equals(BluetoothDevice.EXTRA_DEVICE)) + { + if(intent.getStringExtra("address")== null) + { + + BluetoothDevice bd = ((BluetoothDevice)intent.getExtras().get(k)); + String address = bd.getAddress(); + intent.getExtras().putString("address",address); + if (address.substring(0, 8).equals("00:0E:2F")) { + BluetoothAdapter.getDefaultAdapter().cancelDiscovery(); + + handler.log("Pump found: "+address); + + handler.deviceFound(bd); + } + } + } + } + } +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Display.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Display.java new file mode 100644 index 0000000000..96f7183f0d --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Display.java @@ -0,0 +1,87 @@ +package org.monkey.d.ruffy.ruffy.driver; + +import java.nio.ByteBuffer; + +public class Display { + + private final DisplayUpdater updater; + private int index = -1; + private CompleteDisplayHandler completeHandler; + private boolean[] complete = {false,false,false,false}; + private byte[][] displayBytes = new byte[4][]; + + public Display(DisplayUpdater updater) + { + this.updater = updater; + } + + public void setCompletDisplayHandler(CompleteDisplayHandler completeHandler) {this.completeHandler = completeHandler;} + + private void update(byte[] rowBytes, boolean quarter[][], int which, int index) + { + updater.update(rowBytes,which); + if(this.index==index) + { + complete[which]=true; + + this.displayBytes[which] = rowBytes; + if(this.completeHandler != null && complete[0] && complete[1] && complete[2] && complete[3]) + completeHandler.handleCompleteFrame(this.displayBytes); + + } + else + { + this.index = index; + complete = new boolean[]{false,false,false,false}; + complete[which] = true; + + this.displayBytes= new byte[4][]; + this.displayBytes[which] = rowBytes; + } + } + + public void addDisplayFrame(ByteBuffer b) + { + //discard first 3 + b.getShort(); + b.get(); + int index = (int)(b.get() & 0xFF); + byte row = b.get(); + + byte[] displayBytes = new byte[96]; //New array + b.get(displayBytes); //Read in array from packet + + boolean[][] quarter = new boolean[8][96]; + + int column = 96; + for(byte d:displayBytes) + { + column--; + + quarter[0][column] = ((d & 0x01)!=0); + quarter[1][column] = ((d & 0x02)!=0); + quarter[2][column] = ((d & 0x04)!=0); + quarter[3][column] = ((d & 0x08)!=0); + quarter[4][column] = ((d & 0x10)!=0); + quarter[5][column] = ((d & 0x20)!=0); + quarter[6][column] = ((d & 0x40)!=0); + quarter[7][column] = ((d & 0x80)!=0); + } + + switch(row) + { + case 0x47: + update(displayBytes,quarter,0,index); + break; + case 0x48: + update(displayBytes,quarter,1,index); + break; + case (byte)0xB7: + update(displayBytes,quarter,2,index); + break; + case (byte)0xB8: + update(displayBytes,quarter,3,index); + break; + } + } +} \ No newline at end of file diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/DisplayUpdater.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/DisplayUpdater.java new file mode 100644 index 0000000000..d6a7142b92 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/DisplayUpdater.java @@ -0,0 +1,11 @@ +package org.monkey.d.ruffy.ruffy.driver; + +/** + * Created by fishermen21 on 19.05.17. + */ + +public interface DisplayUpdater { + void clear(); + + void update(byte[] quarter, int which); +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Frame.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Frame.java new file mode 100644 index 0000000000..16bc007696 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Frame.java @@ -0,0 +1,124 @@ +package org.monkey.d.ruffy.ruffy.driver; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by fishermen21 on 16.05.17. + */ + +public class Frame { + public static List frameEscape(List out) + { + List temp = new ArrayList(); + temp.add((byte)-52); + for (int i = 0; i < out.size(); i++) { + if (((Byte) out.get(i)).byteValue() == -52) { + temp.add((byte)119); + temp.add((byte)-35); + } else if (((Byte) out.get(i)).byteValue() == (byte) 119) { + temp.add((byte) 119); + temp.add((byte) -18); + } else { + temp.add((Byte) out.get(i)); + } + } + temp.add((byte)-52); + return temp; + } + + private static List packet = new ArrayList(); + private static boolean start = false, stop = false, escaped = false; + + public static List> frameDeEscaping(List buffer) + { + List> complete = new ArrayList>(); + + if(start) + { + + } + else + { + start = stop = escaped = false; + packet.clear(); + } + + for(int i=0;i= buffer.size()) + { + escaped = true; //If we are at the end of the buffer and find an escape character + } + else + { + Byte next = buffer.get(i+1); + if(next == -35) + { + packet.add((byte)-52); + i++; //Skip the next byte + } + else if(next == -18) + { + packet.add((byte)119); //Skip the next byte + i++; + } + } + } + else if(buffer.get(i) == -52) //We need to cover the chance that there are multiple packets in the buffer + { + if(!start) + { + start = true; + } + else + { + stop = true; + } + + if(start && stop) + { + start = false; + stop = false; + + if(packet.size() == 0) + { + start = true; + stop = false; + } + else if(i == 0) + { + start = true; + stop = false; + } + else + { + complete.add(packet); + packet = new ArrayList(); + } + } + } + else + { + if(start) + packet.add(buffer.get(i)); + } + } + + return complete; + } +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/ListenThread.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/ListenThread.java new file mode 100644 index 0000000000..34c4b2aa02 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/ListenThread.java @@ -0,0 +1,43 @@ +package org.monkey.d.ruffy.ruffy.driver; + +import android.bluetooth.BluetoothServerSocket; +import android.bluetooth.BluetoothSocket; + +import java.io.IOException; + +/** + * Created by fishermen21 on 15.05.17. + */ + +class ListenThread implements Runnable { + private final BluetoothServerSocket srvSock; + + public ListenThread(BluetoothServerSocket srvSock) { + this.srvSock = srvSock; + } + public void run() { + BluetoothSocket socket = null; + + try { + if (socket != null) { + socket = srvSock.accept(); + } + if (socket != null) { + socket.close(); + socket=null; + } + } + catch(Exception e) + { + + } + } + public void halt() + { + try { + srvSock.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/LogHandler.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/LogHandler.java new file mode 100644 index 0000000000..a792b23cc0 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/LogHandler.java @@ -0,0 +1,11 @@ +package org.monkey.d.ruffy.ruffy.driver; + +/** + * Created by fishermen21 on 20.05.17. + */ + +public interface LogHandler { + void log(String s); + + void fail(String s); +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Packet.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Packet.java new file mode 100644 index 0000000000..9b35b1b9ff --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Packet.java @@ -0,0 +1,203 @@ +package org.monkey.d.ruffy.ruffy.driver; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by fishermen21 on 16.05.17. + */ + +public class Packet { + public static byte[] padPacket(byte[] packet) + { + byte pad; + byte[] output; + + pad = (byte) (16 - (packet.length % 16)); //(ENCRYPT_BLOCKSIZE - (packet.length % ENCRYPT_BLOCKSIZE)); + if(pad > 0) + { + output = new byte[pad+packet.length]; + for(int n=0;n buildPacket(byte[] command, ByteBuffer payload, boolean address, BTConnection btConn) + { + List output = new ArrayList(); + + for(int i=0; i < command.length; i++) + output.add(command[i]); + + if(address) //Replace the default address with the real one + { + output.remove(command.length-1); //Remove the last byte (address) + output.add(btConn.getPumpData().getAddress()); //Add the real address byte + } + + Packet.addNonce(output, btConn.getPumpData().getNonceTx()); + + if(payload!=null) + { + payload.rewind(); + for(int i=0;i packet, int length) + { + packet.set(2, (byte) (length & 0xFF)); + packet.set(3, (byte) (length >> 8)); + } + + + public static void addNonce(List packet, byte[] nonce) + { + for(int i=0;i t = new ArrayList<>(); + for (int i = 0; i < bytes; i++) + t.add(buffer[i]); + for (List x : Frame.frameDeEscaping(t)) { + byte[] xx = new byte[x.size()]; + for (int i = 0; i < x.size(); i++) + xx[i] = x.get(i); + boolean rel = false; + if (x.size()>1 && (x.get(1) & 0x20) == 0x20) { + rel = true; + + byte seq = 0x00; + if ((x.get(1) & 0x80) == 0x80) + seq = (byte) 0x80; + + handler.sendImidiateAcknowledge(seq); + } else { + rel = false; + } + handleRX(xx, x.size(), rel,handler); + } + } + + public static enum Response{ + ID, + SYNC, + RELIABLE_DATA, + UNRELIABLE_DATA + + } + private static void handleRX(byte[] inBuf, int length, boolean reliableFlagged, PacketHandler handler) { + + ByteBuffer buffer = ByteBuffer.wrap(inBuf, 0, length); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + byte[] nonce, payload, umac, packetNoUmac; + + Byte command; + buffer.get(); //ignore + command = buffer.get(); + + short payloadlength = buffer.getShort(); + + buffer.get(); //ignore + + nonce = new byte[13]; + buffer.get(nonce, 0, nonce.length); + + payload = new byte[payloadlength]; + buffer.get(payload, 0, payload.length); + + umac = new byte[8]; + buffer.get(umac, 0, umac.length); + + packetNoUmac = new byte[buffer.capacity() - umac.length]; + buffer.rewind(); + for (int i = 0; i < packetNoUmac.length; i++) + packetNoUmac[i] = buffer.get(); + + buffer.rewind(); + + byte c = (byte)(command & 0x1F); + switch (c) { + case 20: + handler.log("got an id response"); + if (Utils.ccmVerify(packetNoUmac, handler.getToDeviceKey(), umac, nonce)) { + handler.handleResponse(Response.ID,reliableFlagged,payload); + } + break; + case 24: + handler.log("got a sync response "); + if (Utils.ccmVerify(packetNoUmac, handler.getToDeviceKey(), umac, nonce)) { + handler.handleResponse(Response.SYNC,reliableFlagged,payload); + } + break; + + case 0x23: + if (Utils.ccmVerify(packetNoUmac, handler.getToDeviceKey(), umac, nonce)) { + handler.handleResponse(Response.RELIABLE_DATA,reliableFlagged,payload); + } + break; + case 0x03: + if (Utils.ccmVerify(packetNoUmac, handler.getToDeviceKey(), umac, nonce)) { + handler.handleResponse(Response.UNRELIABLE_DATA,reliableFlagged,payload); + } + break; + + case 0x06: + if(Utils.ccmVerify(packetNoUmac, handler.getToDeviceKey(), umac, nonce)) + { + byte error = 0; + String err = ""; + + if(payload.length > 0) + error = payload[0]; + + switch(error) + { + case 0x00: + err = "Undefined"; + break; + case 0x0F: + err = "Wrong state"; + break; + case 0x33: + err = "Invalid service primitive"; + break; + case 0x3C: + err = "Invalid payload length"; + break; + case 0x55: + err = "Invalid source address"; + break; + case 0x66: + err = "Invalid destination address"; + break; + } + + handler.log( "Error in Transport Layer! ("+err+")"); + handler.handleErrorResponse(error,err,reliableFlagged,payload); + + } + break; + default: + handler.log("not yet implemented rx command: " + command + " ( " + String.format("%02X", command)); + + } + } +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/PacketHandler.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/PacketHandler.java new file mode 100644 index 0000000000..0c458954a2 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/PacketHandler.java @@ -0,0 +1,17 @@ +package org.monkey.d.ruffy.ruffy.driver; + +/** + * Created by fishermen21 on 19.05.17. + */ + +public interface PacketHandler { + void sendImidiateAcknowledge(byte sequenceNUmber); + + void log(String s); + + void handleResponse(Packet.Response response, boolean reliableFlagged, byte[] payload); + + void handleErrorResponse(byte errorCode, String errDecoded, boolean reliableFlagged, byte[] payload); + + Object getToDeviceKey(); +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/PairingRequest.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/PairingRequest.java new file mode 100644 index 0000000000..afde40d58e --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/PairingRequest.java @@ -0,0 +1,66 @@ +package org.monkey.d.ruffy.ruffy.driver; + +import android.app.Activity; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import java.lang.reflect.Method; + +class PairingRequest extends BroadcastReceiver { + private final Activity activity; + private final BTHandler handler; + + public PairingRequest(final Activity activity, final BTHandler handler) + { + super(); + this.activity = activity; + this.handler = handler; + } + + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals("android.bluetooth.device.action.PAIRING_REQUEST")) { + try { + final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + try + { + byte[] pinBytes; + pinBytes = ("}gZ='GD?gj2r|B}>").getBytes("UTF-8"); + + handler.log( "Try to set the PIN"); + Method m = device.getClass().getMethod("setPin", byte[].class); + m.invoke(device, pinBytes); + handler.log("Success to add the PIN."); + + try { + m = device.getClass().getMethod("createBond"); + m.invoke(device); + handler.log("Success to start bond."); + } catch (Exception e) { + e.printStackTrace(); + } + try { + device.getClass().getMethod("setPairingConfirmation", boolean.class).invoke(device, true); + handler.log( "Success to setPairingConfirmation."); + } catch (Exception e) { + e.printStackTrace(); + } + }catch(Exception e) + { + e.printStackTrace(); + } + } + }); + + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } \ No newline at end of file diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Protocol.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Protocol.java new file mode 100644 index 0000000000..94abf795d8 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Protocol.java @@ -0,0 +1,91 @@ +package org.monkey.d.ruffy.ruffy.driver; + +import android.bluetooth.BluetoothAdapter; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.List; + +/** + * Created by fishermen21 on 16.05.17. + */ + +public class Protocol { + public static void sendSyn(BTConnection btConn) { + + Utils.incrementArray(btConn.getPumpData().getNonceTx()); + + byte[] p_s = {16,23,0,0,0}; + + List packet = Packet.buildPacket(p_s, null, true, btConn); //Use real address (gathered in Key Response) + packet = Utils.ccmAuthenticate(packet, btConn.getPumpData().getToPumpKey(), btConn.getPumpData().getNonceTx()); //Add U-MAC (Use D->P key) + + List temp = Frame.frameEscape(packet); + byte[] ro = new byte[temp.size()]; + int i = 0; + for(byte b : temp) + ro[i++]=b; + + btConn.write(ro); + } + public static void sendIDReq(BTConnection btConn) { + btConn.getPumpData().resetTxNonce(); //Reset TX Nonce (previous to this the nonce is not used and is zero) + Utils.incrementArray(btConn.getPumpData().getNonceTx()); //Increment it to 1 + + ByteBuffer ids = ByteBuffer.allocate(17); //Allocate payload + + String btName = BluetoothAdapter.getDefaultAdapter().getName(); //Get the Device ID + + byte[] deviceId = new byte[13]; + for(int i=0;i packet = Packet.buildPacket(p_r, ids, true,btConn); //Use real address (gathered in Key Response) + packet = Utils.ccmAuthenticate(packet, btConn.getPumpData().getToPumpKey(), btConn.getPumpData().getNonceTx()); //Add U-MAC (Use D->P key) + + List temp = Frame.frameEscape(packet); + byte[] ro = new byte[temp.size()]; + int i = 0; + for(byte b : temp) + ro[i++]=b; + + btConn.write(ro); + } + + public static void sendAck(byte sequenceNUmber,BTConnection btConn) { + btConn.getPumpData().incrementNonceTx(); + + List packet = Packet.buildPacket(new byte[]{16, 5, 0, 0, 0}, null, true,btConn); + + packet.set(1, (byte) (packet.get(1) | sequenceNUmber)); + + packet = Utils.ccmAuthenticate(packet, btConn.getPumpData().getToPumpKey(), btConn.getPumpData().getNonceTx()); + + List temp = Frame.frameEscape(packet); + byte[] ro = new byte[temp.size()]; + int i = 0; + for (byte b : temp) + ro[i++] = b; + + btConn.write(ro); + } +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/PumpData.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/PumpData.java new file mode 100644 index 0000000000..72f8dc385b --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/PumpData.java @@ -0,0 +1,139 @@ +package org.monkey.d.ruffy.ruffy.driver; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.RemoteException; + +import java.security.InvalidKeyException; + +/** + * Created by fishermen21 on 20.05.17. + */ + +public class PumpData { + private String pumpMac; + private Object pump_tf; + private Object driver_tf; + private byte address; + private byte[] nonceTx; + private Context activity; + + public PumpData(Context activity) { + this.activity = activity; + this.nonceTx = new byte[13]; + } + + public static PumpData loadPump(Context activity, IRTHandler handler) { + PumpData data = new PumpData(activity); + + SharedPreferences prefs = activity.getSharedPreferences("pumpdata", Activity.MODE_PRIVATE); + String dp = prefs.getString("dp","E9 24 39 46 84 8A B6 B7 B0 7E 90 C3 2E 2E C2 40 "); + String pd = prefs.getString("pd","29 E2 BD 11 DE 42 49 24 40 30 70 61 DD 4A DF DD "); + data.pumpMac = prefs.getString("device", "00:0E:2F:E8:A5:89"); + + try { + handler.log("Loading data of Pump "+data.pumpMac); + } catch (RemoteException e) { + e.printStackTrace(); + } + + if(data.pumpMac != null) + { + try { + data.pump_tf = Twofish_Algorithm.makeKey(Utils.hexStringToByteArray(pd)); + data.driver_tf = Twofish_Algorithm.makeKey(Utils.hexStringToByteArray(dp)); + data.address = (byte)prefs.getInt("address",16); //0); + + data.nonceTx = Utils.hexStringToByteArray(prefs.getString("nonceTx", "F5 01 00 00 00 00 00 00 00 00 00 00 00 "));//"00 00 00 00 00 00 00 00 00 00 00 00 00")); + + } catch(Exception e) + { + e.printStackTrace(); + try { + handler.fail("unable to load keys!"); + } catch (RemoteException e1) { + e1.printStackTrace(); + } + return null; + } + } + return data; + } + + public byte[] getNonceTx() { + return nonceTx; + } + + public void setAndSaveAddress(byte address) { + this.address = address; + SharedPreferences prefs = activity.getSharedPreferences("pumpdata", Activity.MODE_PRIVATE); + prefs.edit().putInt("address",address).commit(); + + } + + public byte getAddress() { + return address; + } + + public String getPumpMac() { + return pumpMac; + } + + public void resetTxNonce() { + for (int i = 0; i < nonceTx.length; i++) + nonceTx[i] = 0; + SharedPreferences prefs = activity.getSharedPreferences("pumpdata", Activity.MODE_PRIVATE); + prefs.edit().putString("nonceTx", Utils.byteArrayToHexString(nonceTx,nonceTx.length)).apply(); + } + + public void incrementNonceTx() { + Utils.incrementArray(nonceTx); + SharedPreferences prefs = activity.getSharedPreferences("pumpdata", Activity.MODE_PRIVATE); + prefs.edit().putString("nonceTx", Utils.byteArrayToHexString(nonceTx,nonceTx.length)).apply(); + } + + public Context getActivity() { + return activity; + } + + public Object getToPumpKey() { + return driver_tf; + } + + public Object getToDeviceKey() { + return pump_tf; + } + + public void setAndSaveToDeviceKey(byte[] key_pd, Object tf) throws InvalidKeyException { + + byte[] key_pd_de = Twofish_Algorithm.blockDecrypt(key_pd, 0, tf); + this.pump_tf = Twofish_Algorithm.makeKey(key_pd_de); + + SharedPreferences prefs = getActivity().getSharedPreferences("pumpdata", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + editor.putString("pd", Utils.byteArrayToHexString(key_pd_de,key_pd_de.length)); + editor.apply(); + } + public void setAndSaveToPumpKey(byte[] key_dp, Object tf) throws InvalidKeyException { + byte[] key_dp_de = Twofish_Algorithm.blockDecrypt(key_dp, 0, tf); + + this.driver_tf = Twofish_Algorithm.makeKey(key_dp_de); + SharedPreferences prefs = getActivity().getSharedPreferences("pumpdata", Activity.MODE_PRIVATE); + + SharedPreferences.Editor editor = prefs.edit(); + editor.putString("dp", Utils.byteArrayToHexString(key_dp_de,key_dp_de.length)); + editor.apply(); + + } + + public void setAndSavePumpMac(String pumpMac) { + this.pumpMac = pumpMac; + SharedPreferences prefs = getActivity().getSharedPreferences("pumpdata", Activity.MODE_PRIVATE); + + SharedPreferences.Editor editor = prefs.edit(); + editor.putString("device",pumpMac); + editor.putBoolean("paired",true); + editor.apply(); + } +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Ruffy.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Ruffy.java new file mode 100644 index 0000000000..fdff0ff6ae --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Ruffy.java @@ -0,0 +1,412 @@ +package org.monkey.d.ruffy.ruffy.driver; + +import android.app.Activity; +import android.app.Service; +import android.bluetooth.BluetoothDevice; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.IBinder; +import android.os.RemoteException; + +import org.monkey.d.ruffy.ruffy.driver.display.DisplayParser; +import org.monkey.d.ruffy.ruffy.driver.display.DisplayParserHandler; +import org.monkey.d.ruffy.ruffy.driver.display.Menu; + +import java.nio.ByteBuffer; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +/** + * Created by fishermen21 on 25.05.17. + */ + +public class Ruffy extends Service { + + public static class Key { + public static byte NO_KEY =(byte)0x00; + public static byte MENU =(byte)0x03; + public static byte CHECK =(byte)0x0C; + public static byte UP =(byte)0x30; + public static byte DOWN =(byte)0xC0; + } + + private IRTHandler rtHandler = null; + private BTConnection btConn; + private PumpData pumpData; + + private boolean rtModeRunning = false; + private long lastRtMessageSent = 0; + + private final Object rtSequenceSemaphore = new Object(); + private short rtSequence = 0; + + private int modeErrorCount = 0; + private int step = 0; + + private boolean synRun=false;//With set to false, write process is started at first time + private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool( 3 ); + + private Display display; + + private final IRuffyService.Stub serviceBinder = new IRuffyService.Stub(){ + + @Override + public void setHandler(IRTHandler handler) throws RemoteException { + Ruffy.this.rtHandler = handler; + } + + @Override + public int doRTConnect() throws RemoteException { + step= 0; + if(Ruffy.this.rtHandler==null) + { + return -2;//FIXME make errors + } + if(pumpData==null) + { + pumpData = PumpData.loadPump(Ruffy.this,rtHandler); + } + if(pumpData != null) { + btConn = new BTConnection(rtBTHandler); + btConn.connect(pumpData, 10); + return 0; + } + return -1; + } + + public void doRTDisconnect() + { + step = 200; + stopRT(); + btConn.disconnect(); + } + + public void rtSendKey(byte keyCode, boolean changed) + { + //FIXME + lastRtMessageSent = System.currentTimeMillis(); + synchronized (rtSequenceSemaphore) { + rtSequence = Application.rtSendKey(keyCode, changed, rtSequence, btConn); + } + } + + public void resetPairing() + { + SharedPreferences prefs = Ruffy.this.getSharedPreferences("pumpdata", Activity.MODE_PRIVATE); + prefs.edit().putBoolean("paired",false).apply(); + synRun=false; + rtModeRunning =false; + } + + public boolean isConnected() + { + if (btConn!=null) { + return btConn.isConnected(); + } else { + return false; + } + + } + }; + + + @Override + public void onCreate() { + super.onCreate(); + } + + @Override + public IBinder onBind(Intent intent) { + return serviceBinder; + } + + @Override + public void onRebind(Intent intent) { + super.onRebind(intent); + } + + @Override + public boolean onUnbind(Intent intent) { + return true; + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + private BTHandler rtBTHandler = new BTHandler() { + @Override + public void deviceConnected() { + log("connected to pump"); + if(synRun==false) { + synRun = true; + log("start synThread"); + scheduler.execute(synThread); + } + } + + @Override + public void log(String s) { + Ruffy.this.log(s); + if(s.equals("got error in read") && step < 200) + { + synRun=false; + btConn.connect(pumpData,4); + } + } + + @Override + public void fail(String s) { + log("failed: "+s); + synRun=false; + if(step < 200) + btConn.connect(pumpData,4); + else + Ruffy.this.fail(s); + + } + + @Override + public void deviceFound(BluetoothDevice bd) { + log("not be here!?!"); + } + + @Override + public void handleRawData(byte[] buffer, int bytes) { + log("got data from pump"); + synRun=false; + step=0; + Packet.handleRawData(buffer,bytes, rtPacketHandler); + } + + @Override + public void requestBlueTooth() { + try { + rtHandler.requestBluetooth(); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + }; + + private void stopRT() + { + rtModeRunning = false; + rtSequence =0; + } + + private void startRT() { + log("starting RT keepAlive"); + new Thread(){ + @Override + public void run() { + rtModeRunning = true; + rtSequence = 0; + lastRtMessageSent = System.currentTimeMillis(); + rtModeRunning = true; + try { + display = new Display(new DisplayUpdater() { + @Override + public void clear() { + try { + rtHandler.rtClearDisplay(); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + @Override + public void update(byte[] quarter, int which) { + try { + rtHandler.rtUpdateDisplay(quarter,which); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + }); + display.setCompletDisplayHandler(new CompleteDisplayHandler() { + @Override + public void handleCompleteFrame(byte[][] pixels) { + DisplayParser.findMenu(pixels, new DisplayParserHandler() { + @Override + public void menuFound(Menu menu) { + try { + rtHandler.rtDisplayHandleMenu(menu); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + @Override + public void noMenuFound() { + try { + rtHandler.rtDisplayHandleNoMenu(); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + }); + + } + }); + rtHandler.rtStarted(); + } catch (RemoteException e) { + e.printStackTrace(); + } + while(rtModeRunning) + { + if(System.currentTimeMillis() > lastRtMessageSent +1000L) { + log("sending keep alive"); + synchronized (rtSequenceSemaphore) { + rtSequence = Application.sendRTKeepAlive(rtSequence, btConn); + lastRtMessageSent = System.currentTimeMillis(); + } + } + try{ + Thread.sleep(500);}catch(Exception e){/*ignore*/} + } + try { + rtHandler.rtStopped(); + } catch (RemoteException e) { + e.printStackTrace(); + } + + } + }.start(); + } + + private Runnable synThread = new Runnable(){ + @Override + public void run() { + while(synRun) + { + Protocol.sendSyn(btConn); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }; + + private AppHandler rtAppHandler = new AppHandler() { + @Override + public void log(String s) { + Ruffy.this.log(s); + } + + @Override + public void connected() { + Application.sendAppCommand(Application.Command.RT_MODE, btConn); + } + + @Override + public void rtModeActivated() { + startRT(); + } + + @Override + public void modeDeactivated() { + rtModeRunning = false; + Application.sendAppCommand(Application.Command.RT_MODE, btConn); + } + + @Override + public void addDisplayFrame(ByteBuffer b) { + display.addDisplayFrame(b); + } + + @Override + public void modeError() { + modeErrorCount++; + + if (modeErrorCount > Application.MODE_ERROR_TRESHHOLD) { + stopRT(); + log("wrong mode, deactivate"); + + modeErrorCount = 0; + Application.sendAppCommand(Application.Command.DEACTIVATE_ALL, btConn); + } + } + + @Override + public void sequenceError() { + Application.sendAppCommand(Application.Command.RT_DEACTIVATE, btConn); + } + + @Override + public void error(short error, String desc) { + switch (error) + { + case (short) 0xF056: + PumpData d = btConn.getPumpData(); + btConn.disconnect(); + btConn.connect(d,4); + break; + default: + log(desc); + } + } + }; + + public void log(String s) { + try{ + rtHandler.log(s); + }catch(Exception e){e.printStackTrace();} + } + + public void fail(String s) { + try{ + rtHandler.fail(s); + }catch(Exception e){e.printStackTrace();} + } + + private PacketHandler rtPacketHandler = new PacketHandler(){ + @Override + public void sendImidiateAcknowledge(byte sequenceNumber) { + Protocol.sendAck(sequenceNumber,btConn); + } + + @Override + public void log(String s) { + Ruffy.this.log(s); + } + + @Override + public void handleResponse(Packet.Response response, boolean reliableFlagged, byte[] payload) { + switch (response) + { + case ID: + Protocol.sendSyn(btConn); + break; + case SYNC: + btConn.seqNo = 0x00; + + if(step<100) + Application.sendAppConnect(btConn); + else + { + Application.sendAppDisconnect(btConn); + step = 200; + } + break; + case UNRELIABLE_DATA: + case RELIABLE_DATA: + Application.processAppResponse(payload, reliableFlagged, rtAppHandler); + break; + } + } + + @Override + public void handleErrorResponse(byte errorCode, String errDecoded, boolean reliableFlagged, byte[] payload) { + log(errDecoded); + } + + @Override + public Object getToDeviceKey() { + return pumpData.getToDeviceKey(); + } + }; +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Twofish_Algorithm.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Twofish_Algorithm.java new file mode 100644 index 0000000000..0d686b7ccb --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Twofish_Algorithm.java @@ -0,0 +1,836 @@ +// $Id: $ +// +// $Log: $ +// Revision 1.0 1998/03/24 raif +// + start of history. +// +// $Endlog$ +/* + * Copyright (c) 1997, 1998 Systemics Ltd on behalf of + * the Cryptix Development Team. All rights reserved. + */ +package org.monkey.d.ruffy.ruffy.driver; + +import java.io.PrintWriter; +import java.security.InvalidKeyException; + +//........................................................................... + +/** + * Twofish is an AES candidate algorithm. It is a balanced 128-bit Feistel + * cipher, consisting of 16 rounds. In each round, a 64-bit S-box value is + * computed from 64 bits of the block, and this value is xored into the other + * half of the block. The two half-blocks are then exchanged, and the next + * round begins. Before the first round, all input bits are xored with key- + * dependent "whitening" subkeys, and after the final round the output bits + * are xored with other key-dependent whitening subkeys; these subkeys are + * not used anywhere else in the algorithm.

+ * + * Twofish was submitted by Bruce Schneier, Doug Whiting, John Kelsey, Chris + * Hall and David Wagner.

+ * + * Reference:

    + *
  1. TWOFISH2.C -- Optimized C API calls for TWOFISH AES submission, + * Version 1.00, April 1998, by Doug Whiting.

+ * + * Copyright © 1998 + * Systemics Ltd on behalf of the + * Cryptix Development Team. + *
All rights reserved.

+ * + * $Revision: $ + * @author Raif S. Naffah + */ +public final class Twofish_Algorithm // implicit no-argument constructor +{ +// Debugging methods and variables +//........................................................................... + + static final String NAME = "Twofish_Algorithm"; + static final boolean IN = true, OUT = false; + + static final boolean DEBUG = Twofish_Properties.GLOBAL_DEBUG; + static final int debuglevel = DEBUG ? Twofish_Properties.getLevel(NAME) : 0; + static final PrintWriter err = DEBUG ? Twofish_Properties.getOutput() : null; + + static final boolean TRACE = Twofish_Properties.isTraceable(NAME); + + static void debug (String s) { err.println(">>> "+NAME+": "+s); } + static void trace (boolean in, String s) { + if (TRACE) err.println((in?"==> ":"<== ")+NAME+"."+s); + } + static void trace (String s) { if (TRACE) err.println("<=> "+NAME+"."+s); } + + +// Constants and variables +//........................................................................... + + static final int BLOCK_SIZE = 16; // bytes in a data-block + private static final int ROUNDS = 16; + private static final int MAX_ROUNDS = 16; // max # rounds (for allocating subkeys) + + /* Subkey array indices */ + private static final int INPUT_WHITEN = 0; + private static final int OUTPUT_WHITEN = INPUT_WHITEN + BLOCK_SIZE/4; + private static final int ROUND_SUBKEYS = OUTPUT_WHITEN + BLOCK_SIZE/4; // 2*(# rounds) + + private static final int TOTAL_SUBKEYS = ROUND_SUBKEYS + 2*MAX_ROUNDS; + + private static final int SK_STEP = 0x02020202; + private static final int SK_BUMP = 0x01010101; + private static final int SK_ROTL = 9; + + /** Fixed 8x8 permutation S-boxes */ + private static final byte[][] P = new byte[][] { + { // p0 + (byte) 0xA9, (byte) 0x67, (byte) 0xB3, (byte) 0xE8, + (byte) 0x04, (byte) 0xFD, (byte) 0xA3, (byte) 0x76, + (byte) 0x9A, (byte) 0x92, (byte) 0x80, (byte) 0x78, + (byte) 0xE4, (byte) 0xDD, (byte) 0xD1, (byte) 0x38, + (byte) 0x0D, (byte) 0xC6, (byte) 0x35, (byte) 0x98, + (byte) 0x18, (byte) 0xF7, (byte) 0xEC, (byte) 0x6C, + (byte) 0x43, (byte) 0x75, (byte) 0x37, (byte) 0x26, + (byte) 0xFA, (byte) 0x13, (byte) 0x94, (byte) 0x48, + (byte) 0xF2, (byte) 0xD0, (byte) 0x8B, (byte) 0x30, + (byte) 0x84, (byte) 0x54, (byte) 0xDF, (byte) 0x23, + (byte) 0x19, (byte) 0x5B, (byte) 0x3D, (byte) 0x59, + (byte) 0xF3, (byte) 0xAE, (byte) 0xA2, (byte) 0x82, + (byte) 0x63, (byte) 0x01, (byte) 0x83, (byte) 0x2E, + (byte) 0xD9, (byte) 0x51, (byte) 0x9B, (byte) 0x7C, + (byte) 0xA6, (byte) 0xEB, (byte) 0xA5, (byte) 0xBE, + (byte) 0x16, (byte) 0x0C, (byte) 0xE3, (byte) 0x61, + (byte) 0xC0, (byte) 0x8C, (byte) 0x3A, (byte) 0xF5, + (byte) 0x73, (byte) 0x2C, (byte) 0x25, (byte) 0x0B, + (byte) 0xBB, (byte) 0x4E, (byte) 0x89, (byte) 0x6B, + (byte) 0x53, (byte) 0x6A, (byte) 0xB4, (byte) 0xF1, + (byte) 0xE1, (byte) 0xE6, (byte) 0xBD, (byte) 0x45, + (byte) 0xE2, (byte) 0xF4, (byte) 0xB6, (byte) 0x66, + (byte) 0xCC, (byte) 0x95, (byte) 0x03, (byte) 0x56, + (byte) 0xD4, (byte) 0x1C, (byte) 0x1E, (byte) 0xD7, + (byte) 0xFB, (byte) 0xC3, (byte) 0x8E, (byte) 0xB5, + (byte) 0xE9, (byte) 0xCF, (byte) 0xBF, (byte) 0xBA, + (byte) 0xEA, (byte) 0x77, (byte) 0x39, (byte) 0xAF, + (byte) 0x33, (byte) 0xC9, (byte) 0x62, (byte) 0x71, + (byte) 0x81, (byte) 0x79, (byte) 0x09, (byte) 0xAD, + (byte) 0x24, (byte) 0xCD, (byte) 0xF9, (byte) 0xD8, + (byte) 0xE5, (byte) 0xC5, (byte) 0xB9, (byte) 0x4D, + (byte) 0x44, (byte) 0x08, (byte) 0x86, (byte) 0xE7, + (byte) 0xA1, (byte) 0x1D, (byte) 0xAA, (byte) 0xED, + (byte) 0x06, (byte) 0x70, (byte) 0xB2, (byte) 0xD2, + (byte) 0x41, (byte) 0x7B, (byte) 0xA0, (byte) 0x11, + (byte) 0x31, (byte) 0xC2, (byte) 0x27, (byte) 0x90, + (byte) 0x20, (byte) 0xF6, (byte) 0x60, (byte) 0xFF, + (byte) 0x96, (byte) 0x5C, (byte) 0xB1, (byte) 0xAB, + (byte) 0x9E, (byte) 0x9C, (byte) 0x52, (byte) 0x1B, + (byte) 0x5F, (byte) 0x93, (byte) 0x0A, (byte) 0xEF, + (byte) 0x91, (byte) 0x85, (byte) 0x49, (byte) 0xEE, + (byte) 0x2D, (byte) 0x4F, (byte) 0x8F, (byte) 0x3B, + (byte) 0x47, (byte) 0x87, (byte) 0x6D, (byte) 0x46, + (byte) 0xD6, (byte) 0x3E, (byte) 0x69, (byte) 0x64, + (byte) 0x2A, (byte) 0xCE, (byte) 0xCB, (byte) 0x2F, + (byte) 0xFC, (byte) 0x97, (byte) 0x05, (byte) 0x7A, + (byte) 0xAC, (byte) 0x7F, (byte) 0xD5, (byte) 0x1A, + (byte) 0x4B, (byte) 0x0E, (byte) 0xA7, (byte) 0x5A, + (byte) 0x28, (byte) 0x14, (byte) 0x3F, (byte) 0x29, + (byte) 0x88, (byte) 0x3C, (byte) 0x4C, (byte) 0x02, + (byte) 0xB8, (byte) 0xDA, (byte) 0xB0, (byte) 0x17, + (byte) 0x55, (byte) 0x1F, (byte) 0x8A, (byte) 0x7D, + (byte) 0x57, (byte) 0xC7, (byte) 0x8D, (byte) 0x74, + (byte) 0xB7, (byte) 0xC4, (byte) 0x9F, (byte) 0x72, + (byte) 0x7E, (byte) 0x15, (byte) 0x22, (byte) 0x12, + (byte) 0x58, (byte) 0x07, (byte) 0x99, (byte) 0x34, + (byte) 0x6E, (byte) 0x50, (byte) 0xDE, (byte) 0x68, + (byte) 0x65, (byte) 0xBC, (byte) 0xDB, (byte) 0xF8, + (byte) 0xC8, (byte) 0xA8, (byte) 0x2B, (byte) 0x40, + (byte) 0xDC, (byte) 0xFE, (byte) 0x32, (byte) 0xA4, + (byte) 0xCA, (byte) 0x10, (byte) 0x21, (byte) 0xF0, + (byte) 0xD3, (byte) 0x5D, (byte) 0x0F, (byte) 0x00, + (byte) 0x6F, (byte) 0x9D, (byte) 0x36, (byte) 0x42, + (byte) 0x4A, (byte) 0x5E, (byte) 0xC1, (byte) 0xE0 + }, + { // p1 + (byte) 0x75, (byte) 0xF3, (byte) 0xC6, (byte) 0xF4, + (byte) 0xDB, (byte) 0x7B, (byte) 0xFB, (byte) 0xC8, + (byte) 0x4A, (byte) 0xD3, (byte) 0xE6, (byte) 0x6B, + (byte) 0x45, (byte) 0x7D, (byte) 0xE8, (byte) 0x4B, + (byte) 0xD6, (byte) 0x32, (byte) 0xD8, (byte) 0xFD, + (byte) 0x37, (byte) 0x71, (byte) 0xF1, (byte) 0xE1, + (byte) 0x30, (byte) 0x0F, (byte) 0xF8, (byte) 0x1B, + (byte) 0x87, (byte) 0xFA, (byte) 0x06, (byte) 0x3F, + (byte) 0x5E, (byte) 0xBA, (byte) 0xAE, (byte) 0x5B, + (byte) 0x8A, (byte) 0x00, (byte) 0xBC, (byte) 0x9D, + (byte) 0x6D, (byte) 0xC1, (byte) 0xB1, (byte) 0x0E, + (byte) 0x80, (byte) 0x5D, (byte) 0xD2, (byte) 0xD5, + (byte) 0xA0, (byte) 0x84, (byte) 0x07, (byte) 0x14, + (byte) 0xB5, (byte) 0x90, (byte) 0x2C, (byte) 0xA3, + (byte) 0xB2, (byte) 0x73, (byte) 0x4C, (byte) 0x54, + (byte) 0x92, (byte) 0x74, (byte) 0x36, (byte) 0x51, + (byte) 0x38, (byte) 0xB0, (byte) 0xBD, (byte) 0x5A, + (byte) 0xFC, (byte) 0x60, (byte) 0x62, (byte) 0x96, + (byte) 0x6C, (byte) 0x42, (byte) 0xF7, (byte) 0x10, + (byte) 0x7C, (byte) 0x28, (byte) 0x27, (byte) 0x8C, + (byte) 0x13, (byte) 0x95, (byte) 0x9C, (byte) 0xC7, + (byte) 0x24, (byte) 0x46, (byte) 0x3B, (byte) 0x70, + (byte) 0xCA, (byte) 0xE3, (byte) 0x85, (byte) 0xCB, + (byte) 0x11, (byte) 0xD0, (byte) 0x93, (byte) 0xB8, + (byte) 0xA6, (byte) 0x83, (byte) 0x20, (byte) 0xFF, + (byte) 0x9F, (byte) 0x77, (byte) 0xC3, (byte) 0xCC, + (byte) 0x03, (byte) 0x6F, (byte) 0x08, (byte) 0xBF, + (byte) 0x40, (byte) 0xE7, (byte) 0x2B, (byte) 0xE2, + (byte) 0x79, (byte) 0x0C, (byte) 0xAA, (byte) 0x82, + (byte) 0x41, (byte) 0x3A, (byte) 0xEA, (byte) 0xB9, + (byte) 0xE4, (byte) 0x9A, (byte) 0xA4, (byte) 0x97, + (byte) 0x7E, (byte) 0xDA, (byte) 0x7A, (byte) 0x17, + (byte) 0x66, (byte) 0x94, (byte) 0xA1, (byte) 0x1D, + (byte) 0x3D, (byte) 0xF0, (byte) 0xDE, (byte) 0xB3, + (byte) 0x0B, (byte) 0x72, (byte) 0xA7, (byte) 0x1C, + (byte) 0xEF, (byte) 0xD1, (byte) 0x53, (byte) 0x3E, + (byte) 0x8F, (byte) 0x33, (byte) 0x26, (byte) 0x5F, + (byte) 0xEC, (byte) 0x76, (byte) 0x2A, (byte) 0x49, + (byte) 0x81, (byte) 0x88, (byte) 0xEE, (byte) 0x21, + (byte) 0xC4, (byte) 0x1A, (byte) 0xEB, (byte) 0xD9, + (byte) 0xC5, (byte) 0x39, (byte) 0x99, (byte) 0xCD, + (byte) 0xAD, (byte) 0x31, (byte) 0x8B, (byte) 0x01, + (byte) 0x18, (byte) 0x23, (byte) 0xDD, (byte) 0x1F, + (byte) 0x4E, (byte) 0x2D, (byte) 0xF9, (byte) 0x48, + (byte) 0x4F, (byte) 0xF2, (byte) 0x65, (byte) 0x8E, + (byte) 0x78, (byte) 0x5C, (byte) 0x58, (byte) 0x19, + (byte) 0x8D, (byte) 0xE5, (byte) 0x98, (byte) 0x57, + (byte) 0x67, (byte) 0x7F, (byte) 0x05, (byte) 0x64, + (byte) 0xAF, (byte) 0x63, (byte) 0xB6, (byte) 0xFE, + (byte) 0xF5, (byte) 0xB7, (byte) 0x3C, (byte) 0xA5, + (byte) 0xCE, (byte) 0xE9, (byte) 0x68, (byte) 0x44, + (byte) 0xE0, (byte) 0x4D, (byte) 0x43, (byte) 0x69, + (byte) 0x29, (byte) 0x2E, (byte) 0xAC, (byte) 0x15, + (byte) 0x59, (byte) 0xA8, (byte) 0x0A, (byte) 0x9E, + (byte) 0x6E, (byte) 0x47, (byte) 0xDF, (byte) 0x34, + (byte) 0x35, (byte) 0x6A, (byte) 0xCF, (byte) 0xDC, + (byte) 0x22, (byte) 0xC9, (byte) 0xC0, (byte) 0x9B, + (byte) 0x89, (byte) 0xD4, (byte) 0xED, (byte) 0xAB, + (byte) 0x12, (byte) 0xA2, (byte) 0x0D, (byte) 0x52, + (byte) 0xBB, (byte) 0x02, (byte) 0x2F, (byte) 0xA9, + (byte) 0xD7, (byte) 0x61, (byte) 0x1E, (byte) 0xB4, + (byte) 0x50, (byte) 0x04, (byte) 0xF6, (byte) 0xC2, + (byte) 0x16, (byte) 0x25, (byte) 0x86, (byte) 0x56, + (byte) 0x55, (byte) 0x09, (byte) 0xBE, (byte) 0x91 + } + }; + + /** + * Define the fixed p0/p1 permutations used in keyed S-box lookup. + * By changing the following constant definitions, the S-boxes will + * automatically get changed in the Twofish engine. + */ + private static final int P_00 = 1; + private static final int P_01 = 0; + private static final int P_02 = 0; + private static final int P_03 = P_01 ^ 1; + private static final int P_04 = 1; + + private static final int P_10 = 0; + private static final int P_11 = 0; + private static final int P_12 = 1; + private static final int P_13 = P_11 ^ 1; + private static final int P_14 = 0; + + private static final int P_20 = 1; + private static final int P_21 = 1; + private static final int P_22 = 0; + private static final int P_23 = P_21 ^ 1; + private static final int P_24 = 0; + + private static final int P_30 = 0; + private static final int P_31 = 1; + private static final int P_32 = 1; + private static final int P_33 = P_31 ^ 1; + private static final int P_34 = 1; + + /** Primitive polynomial for GF(256) */ + private static final int GF256_FDBK = 0x169; + private static final int GF256_FDBK_2 = 0x169 / 2; + private static final int GF256_FDBK_4 = 0x169 / 4; + + /** MDS matrix */ + private static final int[][] MDS = new int[4][256]; // blank final + + private static final int RS_GF_FDBK = 0x14D; // field generator + + /** data for hexadecimal visualisation. */ + private static final char[] HEX_DIGITS = { + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' + }; + + +// Static code - to intialise the MDS matrix +//........................................................................... + + static { + long time = System.currentTimeMillis(); + +if (DEBUG && debuglevel > 6) { + System.out.println("Algorithm Name: "+ Twofish_Properties.FULL_NAME); + System.out.println("Electronic Codebook (ECB) Mode"); + System.out.println(); + } + // + // precompute the MDS matrix + // + int[] m1 = new int[2]; + int[] mX = new int[2]; + int[] mY = new int[2]; + int i, j; + for (i = 0; i < 256; i++) { + j = P[0][i] & 0xFF; // compute all the matrix elements + m1[0] = j; + mX[0] = Mx_X( j ) & 0xFF; + mY[0] = Mx_Y( j ) & 0xFF; + + j = P[1][i] & 0xFF; + m1[1] = j; + mX[1] = Mx_X( j ) & 0xFF; + mY[1] = Mx_Y( j ) & 0xFF; + + MDS[0][i] = m1[P_00] << 0 | // fill matrix w/ above elements + mX[P_00] << 8 | + mY[P_00] << 16 | + mY[P_00] << 24; + MDS[1][i] = mY[P_10] << 0 | + mY[P_10] << 8 | + mX[P_10] << 16 | + m1[P_10] << 24; + MDS[2][i] = mX[P_20] << 0 | + mY[P_20] << 8 | + m1[P_20] << 16 | + mY[P_20] << 24; + MDS[3][i] = mX[P_30] << 0 | + m1[P_30] << 8 | + mY[P_30] << 16 | + mX[P_30] << 24; + } + + time = System.currentTimeMillis() - time; + +if (DEBUG && debuglevel > 8) { +System.out.println("=========="); +System.out.println(); +System.out.println("Static Data"); +System.out.println(); +System.out.println("MDS[0][]:"); for(i=0; i<64; i++) { for(j=0; j<4; j++) System.out.print("0x"+intToString(MDS[0][i*4+j])+", "); System.out.println();} +System.out.println(); +System.out.println("MDS[1][]:"); for(i=0; i<64; i++) { for(j=0; j<4; j++) System.out.print("0x"+intToString(MDS[1][i*4+j])+", "); System.out.println();} +System.out.println(); +System.out.println("MDS[2][]:"); for(i=0; i<64; i++) { for(j=0; j<4; j++) System.out.print("0x"+intToString(MDS[2][i*4+j])+", "); System.out.println();} +System.out.println(); +System.out.println("MDS[3][]:"); for(i=0; i<64; i++) { for(j=0; j<4; j++) System.out.print("0x"+intToString(MDS[3][i*4+j])+", "); System.out.println();} +System.out.println(); +System.out.println("Total initialization time: "+time+" ms."); +System.out.println(); +} + } + + private static final int LFSR1( int x ) { + return (x >> 1) ^ + ((x & 0x01) != 0 ? GF256_FDBK_2 : 0); + } + + private static final int LFSR2( int x ) { + return (x >> 2) ^ + ((x & 0x02) != 0 ? GF256_FDBK_2 : 0) ^ + ((x & 0x01) != 0 ? GF256_FDBK_4 : 0); + } + + private static final int Mx_1( int x ) { return x; } + private static final int Mx_X( int x ) { return x ^ LFSR2(x); } // 5B + private static final int Mx_Y( int x ) { return x ^ LFSR1(x) ^ LFSR2(x); } // EF + + +// Basic API methods +//........................................................................... + + /** + * Expand a user-supplied key material into a session key. + * + * @param key The 64/128/192/256-bit user-key to use. + * @return This cipher's round keys. + * @exception InvalidKeyException If the key is invalid. + */ + public static synchronized Object makeKey (byte[] k) + throws InvalidKeyException { +if (DEBUG) trace(IN, "makeKey("+k+")"); + if (k == null) + throw new InvalidKeyException("Empty key"); + int length = k.length; + if (!(length == 8 || length == 16 || length == 24 || length == 32)) + throw new InvalidKeyException("Incorrect key length"); + +if (DEBUG && debuglevel > 7) { +System.out.println("Intermediate Session Key Values"); +System.out.println(); +System.out.println("Raw="+toString(k)); +System.out.println(); +} + int k64Cnt = length / 8; + int subkeyCnt = ROUND_SUBKEYS + 2*ROUNDS; + int[] k32e = new int[4]; // even 32-bit entities + int[] k32o = new int[4]; // odd 32-bit entities + int[] sBoxKey = new int[4]; + // + // split user key material into even and odd 32-bit entities and + // compute S-box keys using (12, 8) Reed-Solomon code over GF(256) + // + int i, j, offset = 0; + for (i = 0, j = k64Cnt-1; i < 4 && offset < length; i++, j--) { + k32e[i] = (k[offset++] & 0xFF) | + (k[offset++] & 0xFF) << 8 | + (k[offset++] & 0xFF) << 16 | + (k[offset++] & 0xFF) << 24; + k32o[i] = (k[offset++] & 0xFF) | + (k[offset++] & 0xFF) << 8 | + (k[offset++] & 0xFF) << 16 | + (k[offset++] & 0xFF) << 24; + sBoxKey[j] = RS_MDS_Encode( k32e[i], k32o[i] ); // reverse order + } + // compute the round decryption subkeys for PHT. these same subkeys + // will be used in encryption but will be applied in reverse order. + int q, A, B; + int[] subKeys = new int[subkeyCnt]; + for (i = q = 0; i < subkeyCnt/2; i++, q += SK_STEP) { + A = F32( k64Cnt, q , k32e ); // A uses even key entities + B = F32( k64Cnt, q+SK_BUMP, k32o ); // B uses odd key entities + B = B << 8 | B >>> 24; + A += B; + subKeys[2*i ] = A; // combine with a PHT + A += B; + subKeys[2*i + 1] = A << SK_ROTL | A >>> (32-SK_ROTL); + } + // + // fully expand the table for speed + // + int k0 = sBoxKey[0]; + int k1 = sBoxKey[1]; + int k2 = sBoxKey[2]; + int k3 = sBoxKey[3]; + int b0, b1, b2, b3; + int[] sBox = new int[4 * 256]; + for (i = 0; i < 256; i++) { + b0 = b1 = b2 = b3 = i; + switch (k64Cnt & 3) { + case 1: + sBox[ 2*i ] = MDS[0][(P[P_01][b0] & 0xFF) ^ b0(k0)]; + sBox[ 2*i+1] = MDS[1][(P[P_11][b1] & 0xFF) ^ b1(k0)]; + sBox[0x200+2*i ] = MDS[2][(P[P_21][b2] & 0xFF) ^ b2(k0)]; + sBox[0x200+2*i+1] = MDS[3][(P[P_31][b3] & 0xFF) ^ b3(k0)]; + break; + case 0: // same as 4 + b0 = (P[P_04][b0] & 0xFF) ^ b0(k3); + b1 = (P[P_14][b1] & 0xFF) ^ b1(k3); + b2 = (P[P_24][b2] & 0xFF) ^ b2(k3); + b3 = (P[P_34][b3] & 0xFF) ^ b3(k3); + case 3: + b0 = (P[P_03][b0] & 0xFF) ^ b0(k2); + b1 = (P[P_13][b1] & 0xFF) ^ b1(k2); + b2 = (P[P_23][b2] & 0xFF) ^ b2(k2); + b3 = (P[P_33][b3] & 0xFF) ^ b3(k2); + case 2: // 128-bit keys + sBox[ 2*i ] = MDS[0][(P[P_01][(P[P_02][b0] & 0xFF) ^ b0(k1)] & 0xFF) ^ b0(k0)]; + sBox[ 2*i+1] = MDS[1][(P[P_11][(P[P_12][b1] & 0xFF) ^ b1(k1)] & 0xFF) ^ b1(k0)]; + sBox[0x200+2*i ] = MDS[2][(P[P_21][(P[P_22][b2] & 0xFF) ^ b2(k1)] & 0xFF) ^ b2(k0)]; + sBox[0x200+2*i+1] = MDS[3][(P[P_31][(P[P_32][b3] & 0xFF) ^ b3(k1)] & 0xFF) ^ b3(k0)]; + } + } + + Object sessionKey = new Object[] { sBox, subKeys }; + +if (DEBUG && debuglevel > 7) { +System.out.println("S-box[]:"); +for(i=0;i<64;i++) { for(j=0;j<4;j++) System.out.print("0x"+intToString(sBox[i*4+j])+", "); System.out.println();} +System.out.println(); +for(i=0;i<64;i++) { for(j=0;j<4;j++) System.out.print("0x"+intToString(sBox[256+i*4+j])+", "); System.out.println();} +System.out.println(); +for(i=0;i<64;i++) { for(j=0;j<4;j++) System.out.print("0x"+intToString(sBox[512+i*4+j])+", "); System.out.println();} +System.out.println(); +for(i=0;i<64;i++) { for(j=0;j<4;j++) System.out.print("0x"+intToString(sBox[768+i*4+j])+", "); System.out.println();} +System.out.println(); +System.out.println("User (odd, even) keys --> S-Box keys:"); +for(i=0;i 0x"+intToString(sBoxKey[k64Cnt-1-i])); } +System.out.println(); +System.out.println("Round keys:"); +for(i=0;i 6) System.out.println("PT="+toString(in, inOffset, BLOCK_SIZE)); + + int x0 = (in[inOffset++] & 0xFF) | + (in[inOffset++] & 0xFF) << 8 | + (in[inOffset++] & 0xFF) << 16 | + (in[inOffset++] & 0xFF) << 24; + int x1 = (in[inOffset++] & 0xFF) | + (in[inOffset++] & 0xFF) << 8 | + (in[inOffset++] & 0xFF) << 16 | + (in[inOffset++] & 0xFF) << 24; + int x2 = (in[inOffset++] & 0xFF) | + (in[inOffset++] & 0xFF) << 8 | + (in[inOffset++] & 0xFF) << 16 | + (in[inOffset++] & 0xFF) << 24; + int x3 = (in[inOffset++] & 0xFF) | + (in[inOffset++] & 0xFF) << 8 | + (in[inOffset++] & 0xFF) << 16 | + (in[inOffset++] & 0xFF) << 24; + + x0 ^= sKey[INPUT_WHITEN ]; + x1 ^= sKey[INPUT_WHITEN + 1]; + x2 ^= sKey[INPUT_WHITEN + 2]; + x3 ^= sKey[INPUT_WHITEN + 3]; +if (DEBUG && debuglevel > 6) System.out.println("PTw="+intToString(x0)+intToString(x1)+intToString(x2)+intToString(x3)); + + int t0, t1; + int k = ROUND_SUBKEYS; + for (int R = 0; R < ROUNDS; R += 2) { + t0 = Fe32( sBox, x0, 0 ); + t1 = Fe32( sBox, x1, 3 ); + x2 ^= t0 + t1 + sKey[k++]; + x2 = x2 >>> 1 | x2 << 31; + x3 = x3 << 1 | x3 >>> 31; + x3 ^= t0 + 2*t1 + sKey[k++]; +if (DEBUG && debuglevel > 6) System.out.println("CT"+(R)+"="+intToString(x0)+intToString(x1)+intToString(x2)+intToString(x3)); + + t0 = Fe32( sBox, x2, 0 ); + t1 = Fe32( sBox, x3, 3 ); + x0 ^= t0 + t1 + sKey[k++]; + x0 = x0 >>> 1 | x0 << 31; + x1 = x1 << 1 | x1 >>> 31; + x1 ^= t0 + 2*t1 + sKey[k++]; +if (DEBUG && debuglevel > 6) System.out.println("CT"+(R+1)+"="+intToString(x0)+intToString(x1)+intToString(x2)+intToString(x3)); + } + x2 ^= sKey[OUTPUT_WHITEN ]; + x3 ^= sKey[OUTPUT_WHITEN + 1]; + x0 ^= sKey[OUTPUT_WHITEN + 2]; + x1 ^= sKey[OUTPUT_WHITEN + 3]; +if (DEBUG && debuglevel > 6) System.out.println("CTw="+intToString(x0)+intToString(x1)+intToString(x2)+intToString(x3)); + + byte[] result = new byte[] { + (byte) x2, (byte)(x2 >>> 8), (byte)(x2 >>> 16), (byte)(x2 >>> 24), + (byte) x3, (byte)(x3 >>> 8), (byte)(x3 >>> 16), (byte)(x3 >>> 24), + (byte) x0, (byte)(x0 >>> 8), (byte)(x0 >>> 16), (byte)(x0 >>> 24), + (byte) x1, (byte)(x1 >>> 8), (byte)(x1 >>> 16), (byte)(x1 >>> 24), + }; + +if (DEBUG && debuglevel > 6) { +System.out.println("CT="+toString(result)); +System.out.println(); +} +if (DEBUG) trace(OUT, "blockEncrypt()"); + return result; + } + + /** + * Decrypt exactly one block of ciphertext. + * + * @param in The ciphertext. + * @param inOffset Index of in from which to start considering data. + * @param sessionKey The session key to use for decryption. + * @return The plaintext generated from a ciphertext using the session key. + */ + public static byte[] blockDecrypt (byte[] in, int inOffset, Object sessionKey) + { + if (DEBUG) trace(IN, "blockDecrypt("+in+", "+inOffset+", "+sessionKey+")"); + Object[] sk = (Object[]) sessionKey; // extract S-box and session key + int[] sBox = (int[]) sk[0]; + int[] sKey = (int[]) sk[1]; + + if (DEBUG && debuglevel > 6) System.out.println("CT="+toString(in, inOffset, BLOCK_SIZE)); + + int x2 = (in[inOffset++] & 0xFF) | + (in[inOffset++] & 0xFF) << 8 | + (in[inOffset++] & 0xFF) << 16 | + (in[inOffset++] & 0xFF) << 24; + int x3 = (in[inOffset++] & 0xFF) | + (in[inOffset++] & 0xFF) << 8 | + (in[inOffset++] & 0xFF) << 16 | + (in[inOffset++] & 0xFF) << 24; + int x0 = (in[inOffset++] & 0xFF) | + (in[inOffset++] & 0xFF) << 8 | + (in[inOffset++] & 0xFF) << 16 | + (in[inOffset++] & 0xFF) << 24; + int x1 = (in[inOffset++] & 0xFF) | + (in[inOffset++] & 0xFF) << 8 | + (in[inOffset++] & 0xFF) << 16 | + (in[inOffset++] & 0xFF) << 24; + + x2 ^= sKey[OUTPUT_WHITEN ]; + x3 ^= sKey[OUTPUT_WHITEN + 1]; + x0 ^= sKey[OUTPUT_WHITEN + 2]; + x1 ^= sKey[OUTPUT_WHITEN + 3]; + if (DEBUG && debuglevel > 6) System.out.println("CTw="+intToString(x2)+intToString(x3)+intToString(x0)+intToString(x1)); + + int k = ROUND_SUBKEYS + 2*ROUNDS - 1; + int t0, t1; + for (int R = 0; R < ROUNDS; R += 2) { + t0 = Fe32( sBox, x2, 0 ); + t1 = Fe32( sBox, x3, 3 ); + x1 ^= t0 + 2*t1 + sKey[k--]; + x1 = x1 >>> 1 | x1 << 31; + x0 = x0 << 1 | x0 >>> 31; + x0 ^= t0 + t1 + sKey[k--]; + if (DEBUG && debuglevel > 6) System.out.println("PT"+(ROUNDS-R)+"="+intToString(x2)+intToString(x3)+intToString(x0)+intToString(x1)); + + t0 = Fe32( sBox, x0, 0 ); + t1 = Fe32( sBox, x1, 3 ); + x3 ^= t0 + 2*t1 + sKey[k--]; + x3 = x3 >>> 1 | x3 << 31; + x2 = x2 << 1 | x2 >>> 31; + x2 ^= t0 + t1 + sKey[k--]; + if (DEBUG && debuglevel > 6) System.out.println("PT"+(ROUNDS-R-1)+"="+intToString(x2)+intToString(x3)+intToString(x0)+intToString(x1)); + } + x0 ^= sKey[INPUT_WHITEN ]; + x1 ^= sKey[INPUT_WHITEN + 1]; + x2 ^= sKey[INPUT_WHITEN + 2]; + x3 ^= sKey[INPUT_WHITEN + 3]; + if (DEBUG && debuglevel > 6) System.out.println("PTw="+intToString(x2)+intToString(x3)+intToString(x0)+intToString(x1)); + + byte[] result = new byte[] { + (byte) x0, (byte)(x0 >>> 8), (byte)(x0 >>> 16), (byte)(x0 >>> 24), + (byte) x1, (byte)(x1 >>> 8), (byte)(x1 >>> 16), (byte)(x1 >>> 24), + (byte) x2, (byte)(x2 >>> 8), (byte)(x2 >>> 16), (byte)(x2 >>> 24), + (byte) x3, (byte)(x3 >>> 8), (byte)(x3 >>> 16), (byte)(x3 >>> 24), + }; + + if (DEBUG && debuglevel > 6) { + System.out.println("PT="+toString(result)); + System.out.println(); + } + if (DEBUG) trace(OUT, "blockDecrypt()"); + return result; + } + + /** A basic symmetric encryption/decryption test. */ + public static boolean self_test() { return self_test(BLOCK_SIZE); } + + +// own methods +//........................................................................... + + private static final int b0( int x ) { return x & 0xFF; } + private static final int b1( int x ) { return (x >>> 8) & 0xFF; } + private static final int b2( int x ) { return (x >>> 16) & 0xFF; } + private static final int b3( int x ) { return (x >>> 24) & 0xFF; } + + /** + * Use (12, 8) Reed-Solomon code over GF(256) to produce a key S-box + * 32-bit entity from two key material 32-bit entities. + * + * @param k0 1st 32-bit entity. + * @param k1 2nd 32-bit entity. + * @return Remainder polynomial generated using RS code + */ + private static final int RS_MDS_Encode( int k0, int k1) { + int r = k1; + for (int i = 0; i < 4; i++) // shift 1 byte at a time + r = RS_rem( r ); + r ^= k0; + for (int i = 0; i < 4; i++) + r = RS_rem( r ); + return r; + } + + /* + * Reed-Solomon code parameters: (12, 8) reversible code:

+ *

+    *   g(x) = x**4 + (a + 1/a) x**3 + a x**2 + (a + 1/a) x + 1
+    * 
+ * where a = primitive root of field generator 0x14D + */ + private static final int RS_rem( int x ) { + int b = (x >>> 24) & 0xFF; + int g2 = ((b << 1) ^ ( (b & 0x80) != 0 ? RS_GF_FDBK : 0 )) & 0xFF; + int g3 = (b >>> 1) ^ ( (b & 0x01) != 0 ? (RS_GF_FDBK >>> 1) : 0 ) ^ g2 ; + int result = (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b; + return result; + } + + private static final int F32( int k64Cnt, int x, int[] k32 ) { + int b0 = b0(x); + int b1 = b1(x); + int b2 = b2(x); + int b3 = b3(x); + int k0 = k32[0]; + int k1 = k32[1]; + int k2 = k32[2]; + int k3 = k32[3]; + + int result = 0; + switch (k64Cnt & 3) { + case 1: + result = + MDS[0][(P[P_01][b0] & 0xFF) ^ b0(k0)] ^ + MDS[1][(P[P_11][b1] & 0xFF) ^ b1(k0)] ^ + MDS[2][(P[P_21][b2] & 0xFF) ^ b2(k0)] ^ + MDS[3][(P[P_31][b3] & 0xFF) ^ b3(k0)]; + break; + case 0: // same as 4 + b0 = (P[P_04][b0] & 0xFF) ^ b0(k3); + b1 = (P[P_14][b1] & 0xFF) ^ b1(k3); + b2 = (P[P_24][b2] & 0xFF) ^ b2(k3); + b3 = (P[P_34][b3] & 0xFF) ^ b3(k3); + case 3: + b0 = (P[P_03][b0] & 0xFF) ^ b0(k2); + b1 = (P[P_13][b1] & 0xFF) ^ b1(k2); + b2 = (P[P_23][b2] & 0xFF) ^ b2(k2); + b3 = (P[P_33][b3] & 0xFF) ^ b3(k2); + case 2: // 128-bit keys (optimize for this case) + result = + MDS[0][(P[P_01][(P[P_02][b0] & 0xFF) ^ b0(k1)] & 0xFF) ^ b0(k0)] ^ + MDS[1][(P[P_11][(P[P_12][b1] & 0xFF) ^ b1(k1)] & 0xFF) ^ b1(k0)] ^ + MDS[2][(P[P_21][(P[P_22][b2] & 0xFF) ^ b2(k1)] & 0xFF) ^ b2(k0)] ^ + MDS[3][(P[P_31][(P[P_32][b3] & 0xFF) ^ b3(k1)] & 0xFF) ^ b3(k0)]; + break; + } + return result; + } + + private static final int Fe32( int[] sBox, int x, int R ) { + return sBox[ 2*_b(x, R ) ] ^ + sBox[ 2*_b(x, R+1) + 1] ^ + sBox[0x200 + 2*_b(x, R+2) ] ^ + sBox[0x200 + 2*_b(x, R+3) + 1]; + } + + private static final int _b( int x, int N) { + int result = 0; + switch (N%4) { + case 0: result = b0(x); break; + case 1: result = b1(x); break; + case 2: result = b2(x); break; + case 3: result = b3(x); break; + } + return result; + } + + /** @return The length in bytes of the Algorithm input block. */ + public static int blockSize() { return BLOCK_SIZE; } + + /** A basic symmetric encryption/decryption test for a given key size. */ + private static boolean self_test (int keysize) { +if (DEBUG) trace(IN, "self_test("+keysize+")"); + boolean ok = false; + try { + byte[] kb = new byte[keysize]; + byte[] pt = new byte[BLOCK_SIZE]; + int i; + + for (i = 0; i < keysize; i++) + kb[i] = (byte) i; + for (i = 0; i < BLOCK_SIZE; i++) + pt[i] = (byte) i; + +if (DEBUG && debuglevel > 6) { +System.out.println("=========="); +System.out.println(); +System.out.println("KEYSIZE="+(8*keysize)); +System.out.println("KEY="+toString(kb)); +System.out.println(); +} + Object key = makeKey(kb); + +if (DEBUG && debuglevel > 6) { +System.out.println("Intermediate Ciphertext Values (Encryption)"); +System.out.println(); +} + byte[] ct = blockEncrypt(pt, 0, key); + +if (DEBUG && debuglevel > 6) { +System.out.println("Intermediate Plaintext Values (Decryption)"); +System.out.println(); +} + byte[] cpt = blockDecrypt(ct, 0, key); + + ok = areEqual(pt, cpt); + if (!ok) + throw new RuntimeException("Symmetric operation failed"); + } catch (Exception x) { +if (DEBUG && debuglevel > 0) { + debug("Exception encountered during self-test: " + x.getMessage()); + x.printStackTrace(); +} + } +if (DEBUG && debuglevel > 0) debug("Self-test OK? " + ok); +if (DEBUG) trace(OUT, "self_test()"); + return ok; + } + + +// utility static methods (from cryptix.util.core ArrayUtil and Hex classes) +//........................................................................... + + /** @return True iff the arrays have identical contents. */ + private static boolean areEqual (byte[] a, byte[] b) { + int aLength = a.length; + if (aLength != b.length) + return false; + for (int i = 0; i < aLength; i++) + if (a[i] != b[i]) + return false; + return true; + } + + /** + * Returns a string of 8 hexadecimal digits (most significant + * digit first) corresponding to the integer n, which is + * treated as unsigned. + */ + private static String intToString (int n) { + char[] buf = new char[8]; + for (int i = 7; i >= 0; i--) { + buf[i] = HEX_DIGITS[n & 0x0F]; + n >>>= 4; + } + return new String(buf); + } + + /** + * Returns a string of hexadecimal digits from a byte array. Each + * byte is converted to 2 hex symbols. + */ + private static String toString (byte[] ba) { + return toString(ba, 0, ba.length); + } + private static String toString (byte[] ba, int offset, int length) { + char[] buf = new char[length * 2]; + for (int i = offset, j = 0, k; i < offset+length; ) { + k = ba[i++]; + buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F]; + buf[j++] = HEX_DIGITS[ k & 0x0F]; + } + return new String(buf); + } + + +// main(): use to generate the Intermediate Values KAT +//........................................................................... + + public static void main (String[] args) { + self_test(16); + self_test(24); + self_test(32); + } +} \ No newline at end of file diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Twofish_Properties.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Twofish_Properties.java new file mode 100644 index 0000000000..456d2b4aee --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Twofish_Properties.java @@ -0,0 +1,199 @@ +// $Id: $ +// +// $Log: $ +// Revision 1.0 1998/03/24 raif +// + start of history. +// +// $Endlog$ +/* + * Copyright (c) 1997, 1998 Systemics Ltd on behalf of + * the Cryptix Development Team. All rights reserved. + */ +package org.monkey.d.ruffy.ruffy.driver; + +import java.io.InputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.util.Enumeration; +import java.util.Properties; + +/** + * This class acts as a central repository for an algorithm specific + * properties. It reads an (algorithm).properties file containing algorithm- + * specific properties. When using the AES-Kit, this (algorithm).properties + * file is located in the (algorithm).jar file produced by the "jarit" batch/ + * script command.

+ * + * Copyright © 1997, 1998 + * Systemics Ltd on behalf of the + * Cryptix Development Team. + *
All rights reserved.

+ * + * $Revision: $ + * @author David Hopwood + * @author Jill Baker + * @author Raif S. Naffah + */ +public class Twofish_Properties // implicit no-argument constructor +{ +// Constants and variables with relevant static code +//........................................................................... + + static final boolean GLOBAL_DEBUG = false; + + static final String ALGORITHM = "Twofish"; + static final double VERSION = 0.2; + static final String FULL_NAME = ALGORITHM + " ver. " + VERSION; + static final String NAME = "Twofish_Properties"; + + static final Properties properties = new Properties(); + + /** Default properties in case .properties file was not found. */ + private static final String[][] DEFAULT_PROPERTIES = { + {"Trace.Twofish_Algorithm", "true"}, + {"Debug.Level.*", "1"}, + {"Debug.Level.Twofish_Algorithm", "9"}, + }; + + static { +if (GLOBAL_DEBUG) System.err.println(">>> " + NAME + ": Looking for " + ALGORITHM + " properties"); + String it = ALGORITHM + ".properties"; + InputStream is = Twofish_Properties.class.getResourceAsStream(it); + boolean ok = is != null; + if (ok) + try { + properties.load(is); + is.close(); +if (GLOBAL_DEBUG) System.err.println(">>> " + NAME + ": Properties file loaded OK..."); + } catch (Exception x) { + ok = false; + } + if (!ok) { +if (GLOBAL_DEBUG) System.err.println(">>> " + NAME + ": WARNING: Unable to load \"" + it + "\" from CLASSPATH."); +if (GLOBAL_DEBUG) System.err.println(">>> " + NAME + ": Will use default values instead..."); + int n = DEFAULT_PROPERTIES.length; + for (int i = 0; i < n; i++) + properties.put( + DEFAULT_PROPERTIES[i][0], DEFAULT_PROPERTIES[i][1]); +if (GLOBAL_DEBUG) System.err.println(">>> " + NAME + ": Default properties now set..."); + } + } + + +// Properties methods (excluding load and save, which are deliberately not +// supported). +//........................................................................... + + /** Get the value of a property for this algorithm. */ + public static String getProperty (String key) { + return properties.getProperty(key); + } + + /** + * Get the value of a property for this algorithm, or return + * value if the property was not set. + */ + public static String getProperty (String key, String value) { + return properties.getProperty(key, value); + } + + /** List algorithm properties to the PrintStream out. */ + public static void list (PrintStream out) { + list(new PrintWriter(out, true)); + } + + /** List algorithm properties to the PrintWriter out. */ + public static void list (PrintWriter out) { + out.println("#"); + out.println("# ----- Begin "+ALGORITHM+" properties -----"); + out.println("#"); + + String key, value; + Enumeration enumer = properties.propertyNames(); + while (enumer.hasMoreElements()) { + key = (String) enumer.nextElement(); + value = getProperty(key); + out.println(key + " = " + value); + } + + out.println("#"); + out.println("# ----- End "+ALGORITHM+" properties -----"); + } + +// public synchronized void load(InputStream in) throws IOException {} + + public static Enumeration propertyNames() { + return properties.propertyNames(); + } + +// public void save (OutputStream os, String comment) {} + + +// Developer support: Tracing and debugging enquiry methods (package-private) +//........................................................................... + + /** + * Return true if tracing is requested for a given class.

+ * + * User indicates this by setting the tracing boolean + * property for label in the (algorithm).properties + * file. The property's key is "Trace.label".

+ * + * @param label The name of a class. + * @return True iff a boolean true value is set for a property with + * the key Trace.label. + */ + static boolean isTraceable (String label) { + String s = getProperty("Trace." + label); + if (s == null) + return false; + return new Boolean(s).booleanValue(); + } + + /** + * Return the debug level for a given class.

+ * + * User indicates this by setting the numeric property with key + * "Debug.Level.label".

+ * + * If this property is not set, "Debug.Level.*" is looked up + * next. If neither property is set, or if the first property found is + * not a valid decimal integer, then this method returns 0. + * + * @param label The name of a class. + * @return The required debugging level for the designated class. + */ + static int getLevel (String label) { + String s = getProperty("Debug.Level." + label); + if (s == null) { + s = getProperty("Debug.Level.*"); + if (s == null) + return 0; + } + try { + return Integer.parseInt(s); + } catch (NumberFormatException e) { + return 0; + } + } + + /** + * Return the PrintWriter to which tracing and debugging output is to + * be sent.

+ * + * User indicates this by setting the property with key Output + * to the literal out or err.

+ * + * By default or if the set value is not allowed, System.err + * will be used. + */ + static PrintWriter getOutput() { + PrintWriter pw; + String name = getProperty("Output"); + if (name != null && name.equals("out")) + pw = new PrintWriter(System.out, true); + else + pw = new PrintWriter(System.err, true); + return pw; + } +} \ No newline at end of file diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Utils.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Utils.java new file mode 100644 index 0000000000..fecaa4fef8 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/Utils.java @@ -0,0 +1,251 @@ +package org.monkey.d.ruffy.ruffy.driver; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by fishermen21 on 16.05.17. + */ + +public class Utils { + + public static byte[] generateKey(String strKey) + { + byte[] pin = new byte[10]; + + for(int i=0;i ccmAuthenticate(List buffer, Object key, byte[] nonceIn) + { + List output = new ArrayList(); + int origLength = buffer.size(); //Hang on to the original length + + byte[] packet = new byte[buffer.size()]; //Create primitive array + for(int i=0;i + output.add(packetBuffer.array()[i]); + + return output; + } + + public static void addCRC(List out) + { + short crc = -1; + Object[] objArr = new Object[1]; + objArr[0] = Short.valueOf((short)-1); + for (int i = 0; i < out.size(); i += 1) { + crc = Utils.updateCrc(crc, ((Byte) out.get(i)).byteValue()); + objArr = new Object[1]; + objArr[0] = Short.valueOf(crc); + } + out.add(Byte.valueOf((byte) (crc & 255))); + out.add(Byte.valueOf((byte) (crc >> 8))); + for (int i = 0; i < 8; i += 1) { + out.add(Byte.valueOf((byte) 0)); + } + } + private static short updateCrc(short crc, byte input) { + Object[] objArr = new Object[1]; + objArr[0] = Byte.valueOf(input); + short crcTemp = (short) (((short) input) ^ crc); + crc = (short) (((short) (crc >> 8)) & 255); + objArr = new Object[1]; + objArr[0] = Short.valueOf(crc); + objArr = new Object[1]; + objArr[0] = Short.valueOf(crcTemp); + if ((crcTemp & 128) > 0) { + crc = (short) (crc ^ -31736); + } + objArr = new Object[1]; + objArr[0] = Short.valueOf(crc); + if ((crcTemp & 64) > 0) { + crc = (short) (crc ^ 16900); + } + objArr = new Object[1]; + objArr[0] = Short.valueOf(crc); + if ((crcTemp & 32) > 0) { + crc = (short) (crc ^ 8450); + } + objArr = new Object[1]; + objArr[0] = Short.valueOf(crc); + if ((crcTemp & 16) > 0) { + crc = (short) (crc ^ 4225); + } + objArr = new Object[1]; + objArr[0] = Short.valueOf(crc); + if ((crcTemp & 8) > 0) { + crc = (short) (crc ^ -29624); + } + objArr = new Object[1]; + objArr[0] = Short.valueOf(crc); + if ((crcTemp & 4) > 0) { + crc = (short) (crc ^ 17956); + } + objArr = new Object[1]; + objArr[0] = Short.valueOf(crc); + if ((crcTemp & 2) > 0) { + crc = (short) (crc ^ 8978); + } + objArr = new Object[1]; + objArr[0] = Short.valueOf(crc); + if ((crcTemp & 1) > 0) { + crc = (short) (crc ^ 4489); + } + objArr = new Object[1]; + objArr[0] = Short.valueOf(crc); + return crc; + } + + public static int incrementArray(byte[] array) { + int i = 0, carry = 0; + + array[i]++; + if (array[i] == 0) + carry = 1; + + for (i = 1; i < array.length; i++) { + if (carry == 1) { + array[i] += carry; + if (array[i] > 0) { + carry = 0; + return carry; + } else + carry = 1; + } + } + + return carry; + } + + public static String byteArrayToHexString(byte[] buffer, int bytes) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < bytes; i++) { + sb.append(String.format("%02X ", buffer[i])); + } + return sb.toString(); + } + public static byte[] hexStringToByteArray(String s) { + s = s.replaceAll(" ",""); + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i+1), 16)); + } + return data; + } +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/DisplayParser.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/DisplayParser.java new file mode 100644 index 0000000000..66cd683bae --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/DisplayParser.java @@ -0,0 +1,129 @@ +package org.monkey.d.ruffy.ruffy.driver.display; + +import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuFactory; +import org.monkey.d.ruffy.ruffy.driver.display.parser.LargeTextParser; +import org.monkey.d.ruffy.ruffy.driver.display.parser.SmallTextParser; + +import java.util.LinkedList; + +/** + * Created by fishermen21 on 20.05.17. + */ + +public class DisplayParser { + private static boolean busy = false; + + public static void findMenu(final byte[][] pixels, final DisplayParserHandler handler) { + if(busy) + { +// Log.v("Tokens","skipping frame, busy…"); + return; + } + busy = true; + + long t1 = System.currentTimeMillis(); + + try { + byte[][] display = new byte[4][96]; + for(int i = 0; i < 4;i++) + for(int c = 0;c < 96;c++) + display[i][c]=pixels[i][95-c]; + + LinkedList[] tokens = new LinkedList[]{ + new LinkedList(), + new LinkedList(), + new LinkedList(), + new LinkedList()}; + int toks = 0; + + for(int i = 0; i< 4;i++) + { + + for(int x = 0; x < 92;)//no token is supposed to be smaller then 5 columns + { + Token t = null; + + t = LargeTextParser.findToken(display,i,x); + + if(t==null) + { + t = SmallTextParser.findToken(display, i, x); + } + + if (t != null) { + tokens[i].add(t); + toks++; + x += t.getWidth()-1; + } else { + x++; + } + } + } + + long s = 0; + for(int i = 0; i< 4;i++) { + for (int x = 0; x < 96; x++) { + s+=display[i][x]; + } + } + if(s!=0) + { + print(display,"not empty"); + } + + Menu menu = MenuFactory.get(tokens); + + if(menu != null) { +// Log.v("tokens", " needed " + ((((double) (System.currentTimeMillis() - t1)) / 1000d)) + " for parsing " + (menu != null ? menu.getType() : "no menu")); + menu.setAttribute(MenuAttribute.DEBUG_TIMING, (((double) (System.currentTimeMillis() - t1)) / 1000d)); + handler.menuFound(menu); + } + else + handler.noMenuFound(); + + int nct = 0; + for(int i=0;i<4;i++)nct+=tokens[i].size(); +// if(nct>0 && menu!= null) +// Log.v("tokens",nct+" toks not consumed in "+menu.getType()); + }catch(Throwable e){e.printStackTrace(); +// Log.e("Tokens","error...",e); + } + finally { + busy=false; + } + } + + private static String[] makeStrings(boolean[][][] pixels) { + String[] display = new String[32]; + for (int w = 0; w < 4; w++) { + for (int r = 0; r < 8; r++) { + String line = ""; + for (int c = 0; c < 96; c++) { + line += pixels[w][r][c] ? "β–ˆ" : " "; + } + display[(w*8)+r]=line; + } + } + return display; + } + + public static void print(byte[][] display, String text) { +// Log.d("DisplayParser","////////////////////////////////////////////////////////////////////////////////////////////////"); +// Log.d("DisplayParser",text); + + for (int i = 0; i < 4; i++) { + String[] lines = new String[]{"","","","","","","",""}; + for(int c = 0;c < 96;c++) + { + for(int r = 0; r < 8; r++) { + lines[r] += (display[i][c] & ((1 << r) & 0xFF)) != 0 ? "β–ˆ" : " "; + } + } +// for(int r = 0; r < 8; r++) { +// Log.d("DisplayParser", lines[r]); +// } + } +// Log.d("DisplayParser","////////////////////////////////////////////////////////////////////////////////////////////////"); + } +} + diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/DisplayParserHandler.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/DisplayParserHandler.java new file mode 100644 index 0000000000..7bfe761d10 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/DisplayParserHandler.java @@ -0,0 +1,11 @@ +package org.monkey.d.ruffy.ruffy.driver.display; + +/** + * Created by fishermen21 on 22.05.17. + */ + +public interface DisplayParserHandler { + void menuFound(Menu menu); + + void noMenuFound(); +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/Menu.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/Menu.java index 24a57b7d15..7307dd540d 100644 --- a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/Menu.java +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/Menu.java @@ -2,7 +2,6 @@ package org.monkey.d.ruffy.ruffy.driver.display; import android.os.Parcel; import android.os.Parcelable; -import android.util.Log; import org.monkey.d.ruffy.ruffy.driver.display.menu.BolusType; import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuBlink; @@ -18,7 +17,7 @@ import java.util.Map; * Created by fishermen21 on 20.05.17. */ -public class Menu implements Parcelable{ +public class Menu implements Parcelable { private MenuType type; private Map attributes = new HashMap<>(); @@ -35,36 +34,34 @@ public class Menu implements Parcelable{ String clas = in.readString(); String value = in.readString(); - if(attr!=null && clas!=null && value!=null) { - MenuAttribute a = MenuAttribute.valueOf(attr); - Object o = null; - if (Integer.class.toString().equals(clas)) { - o = new Integer(value); - } else if (Double.class.toString().equals(clas)) { - o = new Double(value); - } else if (Boolean.class.toString().equals(clas)) { - o = new Boolean(value); - } else if (MenuDate.class.toString().equals(clas)) { - o = new MenuDate(value); - } else if (MenuTime.class.toString().equals(clas)) { - o = new MenuTime(value); - } else if (MenuBlink.class.toString().equals(clas)) { - o = new MenuBlink(); - } else if (BolusType.class.toString().equals(clas)) { - o = BolusType.valueOf(value); - } else if (String.class.toString().equals(clas)) { - o = new String(value); - } + MenuAttribute a = MenuAttribute.valueOf(attr); + Object o = null; + if (Integer.class.toString().equals(clas)) { + o = new Integer(value); + } else if (Double.class.toString().equals(clas)) { + o = new Double(value); + } else if (Boolean.class.toString().equals(clas)) { + o = new Boolean(value); + } else if (MenuDate.class.toString().equals(clas)) { + o = new MenuDate(value); + } else if (MenuTime.class.toString().equals(clas)) { + o = new MenuTime(value); + } else if (MenuBlink.class.toString().equals(clas)) { + o = new MenuBlink(); + } else if (BolusType.class.toString().equals(clas)) { + o = BolusType.valueOf(value); + } else if (String.class.toString().equals(clas)) { + o = new String(value); + } - if (o != null) { - attributes.put(a, o); - } else { - Log.e("MenuIn", "failed to parse: " + attr + " / " + clas + " / " + value); - } + if (o != null) { + attributes.put(a, o); + } else { +// Log.e("MenuIn", "failed to parse: " + attr + " / " + clas + " / " + value); } }catch(Exception e) { - Log.e("MenuIn","Exception in read",e); +// Log.e("MenuIn","Exception in read",e); } } @@ -108,12 +105,12 @@ public class Menu implements Parcelable{ dest.writeString(o.toString()); }catch(Exception e) { - Log.v("MenuOut","error in write",e); +// Log.v("MenuOut","error in write",e); } } } - public static final Creator

CREATOR = new - Creator() { + public static final Parcelable.Creator CREATOR = new + Parcelable.Creator() { public Menu createFromParcel(Parcel in) { return new Menu(in); } @@ -122,12 +119,4 @@ public class Menu implements Parcelable{ return new Menu[size]; } }; - - @Override - public String toString() { - String to = "Menu: "+getType()+" atr:"; - for(MenuAttribute atr : attributes()) - to+=atr.toString()+"="+getAttribute(atr)+";"; - return to; - } } diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/MenuType.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/MenuType.java index 2fb7a53f67..4d00ea9155 100644 --- a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/MenuType.java +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/MenuType.java @@ -5,47 +5,38 @@ package org.monkey.d.ruffy.ruffy.driver.display; */ public enum MenuType { - MAIN_MENU(true), - STOP_MENU(true), - BOLUS_MENU(true), - BOLUS_ENTER(false), - EXTENDED_BOLUS_MENU(true), - BOLUS_DURATION(false), - MULTIWAVE_BOLUS_MENU(true), - IMMEDIATE_BOLUS(false), - TBR_MENU(true), - MY_DATA_MENU(true), - BASAL_MENU(true), - BASAL_1_MENU(true), - BASAL_2_MENU(true), - BASAL_3_MENU(true), - BASAL_4_MENU(true), - BASAL_5_MENU(true), - DATE_AND_TIME_MENU(true), - ALARM_MENU(true), - MENU_SETTINGS_MENU(true), - BLUETOOTH_MENU(true), - THERAPY_MENU(true), - PUMP_MENU(true), - QUICK_INFO(false), - BOLUS_DATA(false), - DAILY_DATA(false), - TBR_DATA(false), - ERROR_DATA(false), - TBR_SET(false), - TBR_DURATION(false), - STOP(false), - START_MENU(false), - BASAL_TOTAL(false), - BASAL_SET(false), - WARNING_OR_ERROR(false),; - - private boolean maintype = false; - MenuType(boolean b) { - maintype=b; - } - - public boolean isMaintype() { - return maintype; - } + MAIN_MENU, + STOP_MENU, + BOLUS_MENU, + BOLUS_ENTER, + EXTENDED_BOLUS_MENU, + BOLUS_DURATION, + MULTIWAVE_BOLUS_MENU, + IMMEDIATE_BOLUS, + TBR_MENU, + MY_DATA_MENU, + BASAL_MENU, + BASAL_1_MENU, + BASAL_2_MENU, + BASAL_3_MENU, + BASAL_4_MENU, + BASAL_5_MENU, + DATE_AND_TIME_MENU, + ALARM_MENU, + MENU_SETTINGS_MENU, + BLUETOOTH_MENU, + THERAPY_MENU, + PUMP_MENU, + QUICK_INFO, + BOLUS_DATA, + DAILY_DATA, + TBR_DATA, + ERROR_DATA, + TBR_SET, + TBR_DURATION, + STOP, + START_MENU, + BASAL_TOTAL, + BASAL_SET, + WARNING_OR_ERROR, } diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/Symbol.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/Symbol.java new file mode 100644 index 0000000000..7ef9e7a239 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/Symbol.java @@ -0,0 +1,62 @@ +package org.monkey.d.ruffy.ruffy.driver.display; + +/** + * Created by fishermen21 on 20.05.17. + */ + +public enum Symbol { + CLOCK, + LOCK_CLOSED, + LOCK_OPENED, + CHECK, + LOW_BAT, + WARNING, + DIVIDE, + LOW_INSULIN, + NO_INSULIN, + CALENDAR, + SEPERATOR, + ARROW, + UNITS_PER_HOUR, + BOLUS, + MULTIWAVE, + SPEAKER, + ERROR, + DOT, + UP, + DOWN, + SUM, + BRACKET_RIGHT, + BRACKET_LEFT, + EXTENDED_BOLUS, + PERCENT, + BASAL, + MINUS, + WARANTY, + + LARGE_DOT, + LARGE_SEPERATOR, + LARGE_WARNING, + LARGE_PERCENT, + LARGE_UNITS_PER_HOUR, + LARGE_BASAL_SET, + LARGE_AMPULE_FULL, + LARGE_ARROW, + LARGE_STOP, + LARGE_CALENDAR, + LARGE_TBR, + LARGE_BOLUS, + LARGE_MULTIWAVE, + LARGE_MULTIWAVE_BOLUS, + LARGE_EXTENDED_BOLUS, + LARGE_BLUETOOTH_SETTINGS, + LARGE_THERAPIE_SETTINGS, + LARGE_PUMP_SETTINGS, + LARGE_MENU_SETTINGS, + LARGE_BASAL, + LARGE_MY_DATA, + LARGE_ALARM_SETTINGS, + LARGE_CHECK, + LARGE_ERROR, + +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/Token.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/Token.java new file mode 100644 index 0000000000..86ddb582ce --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/Token.java @@ -0,0 +1,40 @@ +package org.monkey.d.ruffy.ruffy.driver.display; + +import org.monkey.d.ruffy.ruffy.driver.display.parser.Pattern; + +/** + * Created by fishermen21 on 21.05.17. + */ + +public class Token { + private final Pattern pattern; + private final int block; + private final int column; + + public Token(Pattern pattern, int block, int x) { + this.pattern = pattern; + this.block = block; + this.column = x; + } + + public int getWidth() { + return pattern.getWidth(); + } + + @Override + public String toString() { + return pattern+" at ["+block+" / "+column+"]"; + } + + public Pattern getPattern() { + return pattern; + } + + public int getBlock() { + return block; + } + + public int getColumn() { + return column; + } +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuDate.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuDate.java index 9b727cc965..3a1dc5fd10 100644 --- a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuDate.java +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuDate.java @@ -22,6 +22,6 @@ public class MenuDate { @Override public String toString() { - return day+"."+String.format("%02d",month)+"."; + return day+"."+ String.format("%02d",month)+"."; } } diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuFactory.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuFactory.java new file mode 100644 index 0000000000..0c8f00c498 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuFactory.java @@ -0,0 +1,2427 @@ +package org.monkey.d.ruffy.ruffy.driver.display.menu; + +import org.monkey.d.ruffy.ruffy.driver.display.Menu; +import org.monkey.d.ruffy.ruffy.driver.display.MenuAttribute; +import org.monkey.d.ruffy.ruffy.driver.display.MenuType; +import org.monkey.d.ruffy.ruffy.driver.display.Symbol; +import org.monkey.d.ruffy.ruffy.driver.display.Token; +import org.monkey.d.ruffy.ruffy.driver.display.parser.CharacterPattern; +import org.monkey.d.ruffy.ruffy.driver.display.parser.NumberPattern; +import org.monkey.d.ruffy.ruffy.driver.display.parser.Pattern; +import org.monkey.d.ruffy.ruffy.driver.display.parser.SymbolPattern; + +import java.util.LinkedList; + +/** + * Created by fishermen21 on 22.05.17. + */ + +public class MenuFactory { + public static Menu get(LinkedList[] tokens) { + if(tokens[0].size()>0) + { + Pattern p = tokens[0].getFirst().getPattern(); + if(isSymbol(p,Symbol.CLOCK)) + { + if(tokens[1].size()==1) + { + if(isSymbol(tokens[1].get(0).getPattern(),Symbol.LARGE_STOP)) + return makeStopMenu(tokens); + } + else + { + for(Token t:tokens[0]) + if(isSymbol(t.getPattern(),Symbol.MINUS)) + return makeBasalSet(tokens); + + } + return makeMainMenu(tokens); + } + } + + + + if(tokens[2].size()==1) + { + String s0 = parseString(tokens[0],true); + Pattern p = tokens[2].get(0).getPattern(); + + if(p instanceof NumberPattern && isSymbol(tokens[1].get(0).getPattern(),Symbol.LARGE_BASAL_SET)) + { + return makeBasalTotal(tokens); + } + + String s1 = parseString(tokens[1],true); + + if(isSymbol(p,Symbol.LARGE_STOP)) + { + tokens[2].removeFirst(); + return new Menu(MenuType.STOP_MENU); + } + + if(isSymbol(p,Symbol.LARGE_BOLUS)) + { + tokens[2].removeFirst(); + return new Menu(MenuType.BOLUS_MENU); + } + + if(isSymbol(p,Symbol.LARGE_EXTENDED_BOLUS)) + { + tokens[2].removeFirst(); + return new Menu(MenuType.EXTENDED_BOLUS_MENU); + } + + if(isSymbol(p,Symbol.LARGE_MULTIWAVE)) + { + tokens[2].removeFirst(); + return new Menu(MenuType.MULTIWAVE_BOLUS_MENU); + } + + if(isSymbol(p,Symbol.LARGE_TBR)) + { + tokens[2].removeFirst(); + return new Menu(MenuType.TBR_MENU); + } + + if(isSymbol(p,Symbol.LARGE_MY_DATA)) + { + tokens[2].removeFirst(); + return new Menu(MenuType.MY_DATA_MENU); + } + + if(isSymbol(p,Symbol.LARGE_BASAL)) + { + tokens[2].removeFirst(); + return new Menu(MenuType.BASAL_MENU); + } + + if(isSymbol(p,Symbol.LARGE_ALARM_SETTINGS)) + { + tokens[2].removeFirst(); + return new Menu(MenuType.ALARM_MENU); + } + + if(isSymbol(p,Symbol.LARGE_CALENDAR)) + { + tokens[2].removeFirst(); + return new Menu(MenuType.DATE_AND_TIME_MENU); + } + + if(isSymbol(p,Symbol.LARGE_PUMP_SETTINGS)) + { + tokens[2].removeFirst(); + return new Menu(MenuType.PUMP_MENU); + } + + if(isSymbol(p,Symbol.LARGE_THERAPIE_SETTINGS)) + { + tokens[2].removeFirst(); + return new Menu(MenuType.THERAPY_MENU); + } + + if(isSymbol(p,Symbol.LARGE_BLUETOOTH_SETTINGS)) + { + tokens[2].removeFirst(); + return new Menu(MenuType.BLUETOOTH_MENU); + } + + if(isSymbol(p,Symbol.LARGE_MENU_SETTINGS)) + { + tokens[2].removeFirst(); + return new Menu(MenuType.MENU_SETTINGS_MENU); + } + + if(isSymbol(p,Symbol.LARGE_CHECK)) + { + tokens[2].removeFirst(); + return new Menu(MenuType.START_MENU); + } + } + else if(tokens[2].size()==2) + { + Pattern p1 = tokens[2].removeFirst().getPattern(); + Pattern p2 = tokens[2].removeFirst().getPattern(); + + if(isSymbol(p1,Symbol.LARGE_BASAL)) + { + if(p2 instanceof NumberPattern) + { + int num = ((NumberPattern)p2).getNumber(); + parseString(tokens[0],true); + parseString(tokens[1],true); + switch(num) + { + case 1: + return new Menu(MenuType.BASAL_1_MENU); + case 2: + return new Menu(MenuType.BASAL_2_MENU); + case 3: + return new Menu(MenuType.BASAL_3_MENU); + case 4: + return new Menu(MenuType.BASAL_4_MENU); + case 5: + return new Menu(MenuType.BASAL_5_MENU); + } + } + } + return null; + } + else if(tokens[0].size()>1) + { + String title = parseString(tokens[0],false); + + Title t = TitleResolver.resolve(title); + if(t!=null) { + //resolved so we can consume + parseString(tokens[0],true); + switch (t) { + case BOLUS_AMOUNT: + return makeBolusEnter(tokens); + case BOLUS_DURATION: + return makeBolusDuration(tokens); + case IMMEDIATE_BOLUS: + return makeImmediateBolus(tokens); + case QUICK_INFO: + return makeQuickInfo(tokens); + case BOLUS_DATA: + return makeBolusData(tokens); + case DAILY_TOTALS: + return makeDailyData(tokens); + case ERROR_DATA: + return makeErrorData(tokens); + case TBR_DATA: + return makeTBRData(tokens); + case TBR_SET: + return makeTBRSet(tokens); + case TBR_DURATION: + return makeTBRDuration(tokens); + } + Pattern p = tokens[1].get(0).getPattern(); + } + } + if(tokens[0].size()>0 && tokens[3].size()>0) { + String m = parseString(tokens[0], false); + Token t30 = tokens[3].getFirst(); + + if(isSymbol(t30.getPattern(),Symbol.CHECK) && m.length()>0) + return makeWarning(tokens); + } + return null; + } + + private static Menu makeWarning(LinkedList[] tokens) { + Menu m = new Menu(MenuType.WARNING_OR_ERROR); + String message = parseString(tokens[0],true); + m.setAttribute(MenuAttribute.MESSAGE,message); + int stage = 0; + int warning = 0; + int type = 0; + while(tokens[1].size()>0) { + Pattern p = tokens[1].removeFirst().getPattern(); + switch (stage) { + case 0: + if(isSymbol(p,Symbol.LARGE_WARNING)) + { + type = 1; + stage++; + } + else if(isSymbol(p,Symbol.LARGE_ERROR)) + { + type = 2; + stage++; + } + else + return null; + break; + case 1: + if(p instanceof CharacterPattern) + { + char w = ((CharacterPattern)p).getCharacter(); + if(type == 1 && w == 'W') + { + stage++; + } + else if(type == 2 && w == 'E') + { + stage++; + } + else + return null; + } + else + return null; + break; + case 2: + if(p instanceof NumberPattern) + { + warning = ((NumberPattern)p).getNumber(); + stage++; + } + else return null; + break; + case 3: + if(p instanceof NumberPattern) { + warning *= 10; + warning += ((NumberPattern) p).getNumber(); + stage++; + } + else if(isSymbol(p,Symbol.LARGE_STOP)) + stage+=2; + else + return null; + break; + case 4: + if(isSymbol(p,Symbol.LARGE_STOP)) + stage++; + else + return null; + break; + default: + return null; + } + } + if(type == 1) { + m.setAttribute(MenuAttribute.WARNING, warning); + } + else if(type == 2) { + m.setAttribute(MenuAttribute.ERROR, warning); + } else { + m.setAttribute(MenuAttribute.ERROR_OR_WARNING, warning); + } + + if(isSymbol(tokens[3].getFirst().getPattern(),Symbol.CHECK)) + { + tokens[3].removeFirst(); + parseString(tokens[3],true);//ignore result + } + return m; + } + + private static Menu makeBasalSet(LinkedList[] tokens) { + Menu m = new Menu(MenuType.BASAL_SET); + LinkedList from = new LinkedList<>(); + LinkedList to = new LinkedList<>(); + int stage = 0; + while(tokens[0].size()>0) { + Pattern p = tokens[0].removeFirst().getPattern(); + switch (stage) { + case 0: + if(isSymbol(p,Symbol.CLOCK)) + stage++; + else + return null; + break; + case 1: + if(isSymbol(p,Symbol.MINUS)) + stage++; + else if(isSymbol(p,Symbol.SEPERATOR)) + from.add(p); + else if(p instanceof CharacterPattern) + from.add(p); + else if(p instanceof NumberPattern) + from.add(p); + else + return null; + break; + case 2: + if(p instanceof CharacterPattern) + to.add(p); + else if(p instanceof NumberPattern) + to.add(p); + else if(isSymbol(p,Symbol.SEPERATOR)) + to.add(p); + else + return null; + break; + + default: + return null; + } + } + if(from.size()>0 && to.size()>0) + { + try { + int f10 = ((NumberPattern) from.removeFirst()).getNumber(); + int f1 = ((NumberPattern) from.removeFirst()).getNumber(); + int a = 0; + if (from.size() > 0) { + if(from.getFirst() instanceof CharacterPattern) { + char c0 = ((CharacterPattern) from.removeFirst()).getCharacter(); + char c1 = ((CharacterPattern) from.removeFirst()).getCharacter(); + if (c0 == 'P' && c1 == 'M' && !(f10 == 1 && f1 == 2)) + a += 12; + else if (c0 == 'A' && c1 == 'M' && f10 == 1 && f1 == 2) + a -= 12; + } else if(isSymbol(from.getFirst(),Symbol.SEPERATOR)) + {}//ignore + else + return null; + + } + m.setAttribute(MenuAttribute.BASAL_START, new MenuTime((f10 * 10) + f1 + a, 0)); + + int t10 = ((NumberPattern) to.removeFirst()).getNumber(); + int t1 = ((NumberPattern) to.removeFirst()).getNumber(); + a = 0; + if (to.size() > 0) { + if(to.getFirst() instanceof CharacterPattern) { + char c0 = ((CharacterPattern) to.removeFirst()).getCharacter(); + char c1 = ((CharacterPattern) to.removeFirst()).getCharacter(); + if (c0 == 'P' && c1 == 'M' && !(t10==1 && t1 == 2)) + a += 12; + else if (c0 == 'A' && c1 == 'M' && t10 == 1 && t1 == 2) + a -= 12; + } else if(isSymbol(to.getFirst(),Symbol.SEPERATOR)) + {}//ignore + else + return null; + } + m.setAttribute(MenuAttribute.BASAL_END, new MenuTime((t10 * 10) + t1 + a, 0)); + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + } + else + return null; + + stage = 0; + LinkedList basal = new LinkedList<>(); + while(tokens[1].size()>0) { + Pattern p = tokens[1].removeFirst().getPattern(); + switch (stage) { + case 0: + if(isSymbol(p,Symbol.LARGE_BASAL)) + stage++; + else + return null; + break; + case 1: + if(isSymbol(p,Symbol.LARGE_UNITS_PER_HOUR)) + stage++; + else if(isSymbol(p,Symbol.LARGE_DOT)) + basal.add(p); + else if(p instanceof NumberPattern) + basal.add(p); + else + return null; + break; + default: + return null; + } + } + if(basal.size()>0) + { + try + { + String n = ""; + for(Pattern p: basal) + { + if(p instanceof NumberPattern) + n+=((NumberPattern)p).getNumber(); + else if(isSymbol(p,Symbol.LARGE_DOT)) + n+="."; + else + return null; + } + double d = Double.parseDouble(n); + m.setAttribute(MenuAttribute.BASAL_RATE,d); + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + } + else + { + m.setAttribute(MenuAttribute.BASAL_RATE,new MenuBlink()); + } + if(tokens[2].size()==1 && tokens[2].get(0).getPattern() instanceof NumberPattern) + { + m.setAttribute(MenuAttribute.BASAL_SELECTED,((NumberPattern)tokens[2].removeFirst().getPattern()).getNumber()); + } + else + return null; + return m; + } + + private static Menu makeBasalTotal(LinkedList[] tokens) { + Menu m = new Menu(MenuType.BASAL_TOTAL); + LinkedList basal = new LinkedList<>(); + + int stage = 0; + while(tokens[1].size()>0) { + Pattern p = tokens[1].removeFirst().getPattern(); + switch (stage) { + case 0: + if(isSymbol(p,Symbol.LARGE_BASAL_SET)) + stage++; + else + return null; + break; + case 1: + if(p instanceof NumberPattern) + basal.add(p); + else if (isSymbol(p,Symbol.LARGE_DOT)) + basal.add(p); + else if(p instanceof CharacterPattern && ((CharacterPattern)p).getCharacter()=='u') + stage++; + else + return null; + break; + default: + return null; + } + } + if(basal.size()>0) + { + try { + String n = ""; + for (Pattern p : basal) + if (p instanceof NumberPattern) + n += ((NumberPattern) p).getNumber(); + else if (isSymbol(p, Symbol.LARGE_DOT)) + n += "."; + else + return null; + double d = Double.parseDouble(n); + m.setAttribute(MenuAttribute.BASAL_TOTAL,d); + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + } + else + return null; + + if(tokens[2].size()==1 && tokens[2].get(0).getPattern() instanceof NumberPattern) + { + m.setAttribute(MenuAttribute.BASAL_SELECTED,((NumberPattern)tokens[2].removeFirst().getPattern()).getNumber()); + } + else + { + return null; + } + + stage = 0; + while(tokens[3].size()>0) + { + Pattern p = tokens[3].removeFirst().getPattern(); + switch(stage) + { + case 0: + if(isSymbol(p,Symbol.CHECK)) + { + String s = parseString(tokens[3],true); + if(s!=null) + stage++; + else + return null; + } + else + return null; + break; + default: + return null; + } + } + return m; + } + + private static Menu makeStopMenu(LinkedList[] tokens) { + Menu m = new Menu(MenuType.STOP); + if(!isSymbol(tokens[1].removeFirst().getPattern(),Symbol.LARGE_STOP)) + return null; + int stage = 0; + LinkedList clock = new LinkedList<>(); + LinkedList date = new LinkedList<>(); + while(tokens[0].size()>0) { + Pattern p = tokens[0].removeFirst().getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.CLOCK)) + stage++; + else + return null; + break; + case 1: + if(p instanceof NumberPattern) + clock.add(p); + else if(p instanceof CharacterPattern) + clock.add(p); + else if (isSymbol(p, Symbol.SEPERATOR)) + {} + else if(isSymbol(p,Symbol.CALENDAR)) + stage++; + else + return null; + break; + case 2: + if(p instanceof NumberPattern) + date.add(p); + else if (isSymbol(p, Symbol.DIVIDE)) + date .add(p); + else if (isSymbol(p, Symbol.DOT)) + date .add(p); + else + return null; + break; + case 3: + return null; + } + } + if(clock.size()>=4) { + try { + int hour10 = ((NumberPattern) clock.removeFirst()).getNumber(); + int hour1 = ((NumberPattern) clock.removeFirst()).getNumber(); + int minute10 = ((NumberPattern) clock.removeFirst()).getNumber(); + int minute1 = ((NumberPattern) clock.removeFirst()).getNumber(); + int timeadd = 0; + if (clock.size() == 2) { + CharacterPattern p0 = (CharacterPattern) clock.removeFirst(); + CharacterPattern p1 = (CharacterPattern) clock.removeFirst(); + if(p0.getCharacter()=='A' && p1.getCharacter()=='M' && hour10==1 && hour1 == 2) + timeadd-=12; + else if(p0.getCharacter()=='P' && p1.getCharacter()=='M') + timeadd+=12; + } + m.setAttribute(MenuAttribute.TIME,new MenuTime((hour10*10)+hour1+timeadd,(minute10*10)+minute1)); + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + + } + else + return null; + if(date.size()==5) { + try { + int f10 = ((NumberPattern) date.removeFirst()).getNumber(); + int f1 = ((NumberPattern) date.removeFirst()).getNumber(); + boolean divide = isSymbol(date.removeFirst(),Symbol.DIVIDE); + int s10 = ((NumberPattern) date.removeFirst()).getNumber(); + int s1 = ((NumberPattern) date.removeFirst()).getNumber(); + if(divide) + m.setAttribute(MenuAttribute.DATE, new MenuDate((s10*10)+s1,(f10*10)+f1)); + else + m.setAttribute(MenuAttribute.DATE, new MenuDate((f10*10)+f1,(s10*10)+s1)); + + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + } + else + return null; + + stage = 0; + int lowInsulin = 0; + boolean lowBattery= false; + boolean waranty= true; + int lockState = 0; + while(tokens[3].size()>0) { + Token t = tokens[3].removeFirst(); + Pattern p = t.getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.LOW_BAT)) { + lowBattery = true; + } else if (isSymbol(p, Symbol.LOW_INSULIN)) { + lowInsulin= 1; + } else if (isSymbol(p, Symbol.NO_INSULIN)) { + lowInsulin= 2; + } else if (isSymbol(p, Symbol.LOCK_CLOSED)) { + lockState=2; + } else if (isSymbol(p, Symbol.LOCK_OPENED)) { + lockState=2; + } else if (isSymbol(p, Symbol.WARANTY)) { + waranty = false; + } else { + return null; + } + break; + case 2: + return null; + } + } + if(lowBattery) + m.setAttribute(MenuAttribute.LOW_BATTERY,new Boolean(true)); + else + m.setAttribute(MenuAttribute.LOW_BATTERY,new Boolean(false)); + + m.setAttribute(MenuAttribute.INSULIN_STATE,lowInsulin); + + m.setAttribute(MenuAttribute.WARANTY,new Boolean(waranty)); + + m.setAttribute(MenuAttribute.LOCK_STATE,new Integer(lockState)); + + return m; + } + + private static Menu makeTBRSet(LinkedList[] tokens) { + Menu m = new Menu(MenuType.TBR_SET); + int stage = 0; + LinkedList number = new LinkedList<>(); + while(tokens[1].size()>0) + { + Pattern p = tokens[1].removeFirst().getPattern(); + switch (stage) + { + case 0: + if(isSymbol(p,Symbol.LARGE_BASAL)) + stage++; + else + return null; + break; + case 1: + if(p instanceof NumberPattern) + { + number.add((NumberPattern)p); + } + else if (isSymbol(p,Symbol.LARGE_PERCENT)) + { + stage++; + } + break; + case 2: + return null; + } + } + if(number.size()>0) + { + String n = ""; + while(number.size()>0) + { + n += number.removeFirst().getNumber(); + } + try{ + double d = Double.parseDouble(n); + m.setAttribute(MenuAttribute.BASAL_RATE,d); + }catch(Exception e){e.printStackTrace();return null;} + } else if(number.size()==0) + m.setAttribute(MenuAttribute.BASAL_RATE, new MenuBlink()); + else + return null; + + if(tokens[3].size()>0) { + stage = 0; + number.clear(); + while (tokens[3].size() > 0) { + Pattern p = tokens[3].removeFirst().getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.ARROW)) + stage++; + else + return null; + break; + case 1: + if (p instanceof NumberPattern) + number.add((NumberPattern) p); + else if (isSymbol(p, Symbol.SEPERATOR)) + {} + else return null; + break; + case 2: + return null; + } + } + if (number.size() == 4) { + int hour10 = number.removeFirst().getNumber(); + int hour1 = number.removeFirst().getNumber(); + int minute10 = number.removeFirst().getNumber(); + int minute1 = number.removeFirst().getNumber(); + m.setAttribute(MenuAttribute.RUNTIME, new MenuTime((hour10 * 10) + hour1, (minute10 * 10) + minute1)); + } else return null; + } + else m.setAttribute(MenuAttribute.RUNTIME,new MenuTime(0,0)); + return m; + } + + private static Menu makeTBRDuration(LinkedList[] tokens) { + Menu m = new Menu(MenuType.TBR_DURATION); + int stage = 0; + LinkedList number = new LinkedList<>(); + while(tokens[1].size()>0) + { + Pattern p = tokens[1].removeFirst().getPattern(); + switch (stage) + { + case 0: + if(isSymbol(p,Symbol.LARGE_ARROW)) + stage++; + else + return null; + break; + case 1: + if(p instanceof NumberPattern) + { + number.add((NumberPattern)p); + } + else if (isSymbol(p,Symbol.LARGE_PERCENT)) + { + stage++; + } + else if (isSymbol(p,Symbol.LARGE_SEPERATOR)) + { + } + else return null; + break; + case 2: + return null; + } + } + if(number.size()==4) + { + int hour10 = number.removeFirst().getNumber(); + int hour1 = number.removeFirst().getNumber(); + int minute10 = number.removeFirst().getNumber(); + int minute1 = number.removeFirst().getNumber(); + m.setAttribute(MenuAttribute.RUNTIME,new MenuTime((hour10*10)+hour1,(minute10*10)+minute1)); + } else if(number.size()==0) m.setAttribute(MenuAttribute.RUNTIME,new MenuBlink()); + else return null; + + stage = 0; + number.clear(); + while(tokens[3].size()>0) + { + Pattern p = tokens[3].removeFirst().getPattern(); + switch (stage) + { + case 0: + if(isSymbol(p,Symbol.BASAL)) + stage++; + else return null; + break; + case 1: + if(p instanceof NumberPattern) + number.add((NumberPattern)p); + else if(isSymbol(p,Symbol.PERCENT)) + stage++; + else return null; + break; + case 3: + return null; + } + } + if(number.size()>0) + { + String n = ""; + while(number.size()>0) + { + n += number.removeFirst().getNumber(); + } + try{ + double d = Double.parseDouble(n); + m.setAttribute(MenuAttribute.BASAL_RATE,d); + }catch(Exception e){e.printStackTrace();return null;} + } + return m; + } + + private static Menu makeTBRData(LinkedList[] tokens) { + Menu m = new Menu(MenuType.TBR_DATA); + int stage = 0; + LinkedList percent = new LinkedList<>(); + LinkedList cr = new LinkedList<>(); + LinkedList tr = new LinkedList<>(); + + while (tokens[1].size()>0) { + Token t = tokens[1].removeFirst(); + Pattern p = t.getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.UP)) + stage++; + else if (isSymbol(p, Symbol.DOWN)) + stage++; + else + return null; + break; + case 1: + if(p instanceof NumberPattern) + percent.add((NumberPattern) p); + else if(isSymbol(p,Symbol.PERCENT)) + stage++; + else + return null; + break; + case 2: + if(p instanceof NumberPattern) + cr.add((NumberPattern) p); + else if(isSymbol(p,Symbol.DIVIDE)) + stage++; + else + return null; + break; + case 3: + if(p instanceof NumberPattern) + tr.add((NumberPattern) p); + else + return null; + break; + default: + return null; + } + } + if(percent.size()>0) + { + try + { + String n = ""; + for(NumberPattern p : percent) + { + n+=p.getNumber(); + } + double d = Double.parseDouble(n); + m.setAttribute(MenuAttribute.TBR,d); + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + } + if(cr.size()==2 && tr.size() == 2) + { + int c = cr.removeFirst().getNumber()*10; + c+=cr.removeFirst().getNumber(); + m.setAttribute(MenuAttribute.CURRENT_RECORD,new Integer(c)); + int t = tr.removeFirst().getNumber()*10; + t+=tr.removeFirst().getNumber(); + m.setAttribute(MenuAttribute.TOTAL_RECORD,new Integer(t)); + } + else + return null; + + LinkedList clock = new LinkedList<>(); + stage = 0; + while(tokens[2].size()>0) { + Pattern p = tokens[2].removeFirst().getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.ARROW)) + stage++; + else + return null; + break; + case 1: + if (p instanceof NumberPattern) + clock.add(p); + else if (isSymbol(p, Symbol.SEPERATOR)) { + } else + return null; + break; + default: + return null; + } + } + if(clock.size()==4) { + try { + int hour10 = ((NumberPattern) clock.removeFirst()).getNumber(); + int hour1 = ((NumberPattern) clock.removeFirst()).getNumber(); + int minute10 = ((NumberPattern) clock.removeFirst()).getNumber(); + int minute1 = ((NumberPattern) clock.removeFirst()).getNumber(); + m.setAttribute(MenuAttribute.RUNTIME,new MenuTime((hour10*10)+hour1,(minute10*10)+minute1)); + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + + } + else + return null; + + clock.clear(); + LinkedList date = new LinkedList<>(); + stage = 0; + while(tokens[3].size()>0) { + Pattern p = tokens[3].removeFirst().getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.CLOCK)) + stage++; + else + return null; + break; + case 1: + if(p instanceof NumberPattern) + clock.add(p); + else if(p instanceof CharacterPattern) + clock.add(p); + else if (isSymbol(p, Symbol.SEPERATOR)) + {} + else if(isSymbol(p,Symbol.CALENDAR)) + stage++; + else + return null; + break; + case 2: + if(p instanceof NumberPattern) + date.add(p); + else if (isSymbol(p, Symbol.DIVIDE)) + date .add(p); + else if (isSymbol(p, Symbol.DOT)) + date .add(p); + else + return null; + break; + case 3: + return null; + } + } + if(clock.size()>=4) { + try { + int hour10 = ((NumberPattern) clock.removeFirst()).getNumber(); + int hour1 = ((NumberPattern) clock.removeFirst()).getNumber(); + int minute10 = ((NumberPattern) clock.removeFirst()).getNumber(); + int minute1 = ((NumberPattern) clock.removeFirst()).getNumber(); + int timeadd = 0; + if (clock.size() == 2) { + CharacterPattern p0 = (CharacterPattern) clock.removeFirst(); + CharacterPattern p1 = (CharacterPattern) clock.removeFirst(); + if(p0.getCharacter()=='A' && p1.getCharacter()=='M' && hour10==1 && hour1 == 2) + timeadd-=12; + else if(p0.getCharacter()=='P' && p1.getCharacter()=='M') + timeadd+=12; + } + m.setAttribute(MenuAttribute.TIME,new MenuTime((hour10*10)+hour1+timeadd,(minute10*10)+minute1)); + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + + } + else + return null; + if(date.size()==5) { + try { + int f10 = ((NumberPattern) date.removeFirst()).getNumber(); + int f1 = ((NumberPattern) date.removeFirst()).getNumber(); + boolean divide = isSymbol(date.removeFirst(),Symbol.DIVIDE); + int s10 = ((NumberPattern) date.removeFirst()).getNumber(); + int s1 = ((NumberPattern) date.removeFirst()).getNumber(); + if(divide) + m.setAttribute(MenuAttribute.DATE, new MenuDate((s10*10)+s1,(f10*10)+f1)); + else + m.setAttribute(MenuAttribute.DATE, new MenuDate((f10*10)+f1,(s10*10)+s1)); + + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + } + else + return null; + return m; + } + + private static Menu makeErrorData(LinkedList[] tokens) { + Menu m = new Menu(MenuType.ERROR_DATA); + boolean error = false; + boolean warning = false; + int code = 0; + LinkedList cr = new LinkedList<>(); + LinkedList tr = new LinkedList<>(); + + int stage = 0; + while (tokens[1].size()>0) { + Token t = tokens[1].removeFirst(); + Pattern p = t.getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.WARNING)) { + warning=true; + stage++; + } else if (isSymbol(p, Symbol.ERROR)) { + error=true; + stage++; + } else + return null; + break; + case 1: + if(p instanceof CharacterPattern && ((((CharacterPattern)p).getCharacter()=='W' && warning) || + (((CharacterPattern)p).getCharacter()=='E' && error))) + stage++; + else + return null; + break; + case 2: + if(p instanceof NumberPattern) + { + code = ((NumberPattern) p).getNumber(); + stage++; + } + else + return null; + break; + case 3: + if(p instanceof NumberPattern) + cr.add((NumberPattern) p); + else if(isSymbol(p,Symbol.DIVIDE)) + stage++; + else + return null; + break; + case 4: + if(p instanceof NumberPattern) + tr.add((NumberPattern) p); + else + return null; + break; + case 5: + return null; + } + } + if(error) + m.setAttribute(MenuAttribute.ERROR,new Integer(code)); + else if(warning) + m.setAttribute(MenuAttribute.WARNING,new Integer(code)); + else + return null; + + if(cr.size()==2 && tr.size() == 2) + { + int c = cr.removeFirst().getNumber()*10; + c+=cr.removeFirst().getNumber(); + m.setAttribute(MenuAttribute.CURRENT_RECORD,new Integer(c)); + int t = tr.removeFirst().getNumber()*10; + t+=tr.removeFirst().getNumber(); + m.setAttribute(MenuAttribute.TOTAL_RECORD,new Integer(t)); + } + else + return null; + + String message = parseString(tokens[2],true); + if(message!=null) + m.setAttribute(MenuAttribute.MESSAGE,message); + else + return null; + + LinkedList clock = new LinkedList<>(); + LinkedList date = new LinkedList<>(); + stage = 0; + while(tokens[3].size()>0) { + Pattern p = tokens[3].removeFirst().getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.CLOCK)) + stage++; + else + return null; + break; + case 1: + if(p instanceof NumberPattern) + clock.add(p); + else if(p instanceof CharacterPattern) + clock.add(p); + else if (isSymbol(p, Symbol.SEPERATOR)) + {} + else if(isSymbol(p,Symbol.CALENDAR)) + stage++; + else + return null; + break; + case 2: + if(p instanceof NumberPattern) + date.add(p); + else if (isSymbol(p, Symbol.DIVIDE)) + date .add(p); + else if (isSymbol(p, Symbol.DOT)) + date .add(p); + else + return null; + break; + case 3: + return null; + } + } + if(clock.size()>=4) { + try { + int hour10 = ((NumberPattern) clock.removeFirst()).getNumber(); + int hour1 = ((NumberPattern) clock.removeFirst()).getNumber(); + int minute10 = ((NumberPattern) clock.removeFirst()).getNumber(); + int minute1 = ((NumberPattern) clock.removeFirst()).getNumber(); + int timeadd = 0; + if (clock.size() == 2) { + CharacterPattern p0 = (CharacterPattern) clock.removeFirst(); + CharacterPattern p1 = (CharacterPattern) clock.removeFirst(); + if(p0.getCharacter()=='A' && p1.getCharacter()=='M' && hour10==1 && hour1 == 2) + timeadd-=12; + else if(p0.getCharacter()=='P' && p1.getCharacter()=='M') + timeadd+=12; + } + m.setAttribute(MenuAttribute.TIME,new MenuTime((hour10*10)+hour1+timeadd,(minute10*10)+minute1)); + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + + } + else + return null; + if(date.size()==5) { + try { + int f10 = ((NumberPattern) date.removeFirst()).getNumber(); + int f1 = ((NumberPattern) date.removeFirst()).getNumber(); + boolean divide = isSymbol(date.removeFirst(),Symbol.DIVIDE); + int s10 = ((NumberPattern) date.removeFirst()).getNumber(); + int s1 = ((NumberPattern) date.removeFirst()).getNumber(); + if(divide) + m.setAttribute(MenuAttribute.DATE, new MenuDate((s10*10)+s1,(f10*10)+f1)); + else + m.setAttribute(MenuAttribute.DATE, new MenuDate((f10*10)+f1,(s10*10)+s1)); + + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + } + else + return null; + return m; + } + + private static Menu makeDailyData(LinkedList[] tokens) { + Menu m = new Menu(MenuType.DAILY_DATA); + + LinkedList cr = new LinkedList<>(); + LinkedList tr = new LinkedList<>(); + + int stage = 0; + while (tokens[1].size()>0) { + Token t = tokens[1].removeFirst(); + Pattern p = t.getPattern(); + switch (stage) { + case 0: + if(p instanceof NumberPattern) + cr.add((NumberPattern) p); + else if(isSymbol(p,Symbol.DIVIDE)) + stage++; + else + return null; + break; + case 1: + if(p instanceof NumberPattern) + tr.add((NumberPattern) p); + else + return null; + break; + case 2: + return null; + } + } + if(cr.size()==2 && tr.size() == 2) + { + int c = cr.removeFirst().getNumber()*10; + c+=cr.removeFirst().getNumber(); + m.setAttribute(MenuAttribute.CURRENT_RECORD,new Integer(c)); + int t = tr.removeFirst().getNumber()*10; + t+=tr.removeFirst().getNumber(); + m.setAttribute(MenuAttribute.TOTAL_RECORD,new Integer(t)); + } + else + return null; + + LinkedList sum = new LinkedList<>(); + stage = 0; + while (tokens[2].size()>0) { + Token t = tokens[2].removeFirst(); + Pattern p = t.getPattern(); + switch (stage) { + case 0: + if(isSymbol(p,Symbol.SUM)) + stage++; + else + return null; + break; + case 1: + if(p instanceof NumberPattern) + sum.add((NumberPattern) p); + else if(isSymbol(p,Symbol.DOT)) + sum.add(p); + else if(p instanceof CharacterPattern && ((CharacterPattern)p).getCharacter()=='U') + stage++; + else + return null; + break; + case 2: + return null; + } + } + + if(sum.size()>0) + { + try + { + String n = ""; + for(Pattern p : sum) + { + if(p instanceof NumberPattern) + n+=((NumberPattern)p).getNumber(); + else if(isSymbol(p,Symbol.DOT)) + n+="."; + else + return null; + } + double d = Double.parseDouble(n); + m.setAttribute(MenuAttribute.DAILY_TOTAL,d); + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + } + LinkedList date = new LinkedList<>(); + stage = 0; + while(tokens[3].size()>0) { + Pattern p = tokens[3].removeFirst().getPattern(); + switch (stage) { + case 0: + if(isSymbol(p,Symbol.CALENDAR)) + stage++; + else + return null; + break; + case 1: + if(p instanceof NumberPattern) + date.add(p); + else if (isSymbol(p, Symbol.DIVIDE)) + date .add(p); + else if (isSymbol(p, Symbol.DOT)) + date .add(p); + else + return null; + break; + case 2: + return null; + } + } + if(date.size()==5) { + try { + int f10 = ((NumberPattern) date.removeFirst()).getNumber(); + int f1 = ((NumberPattern) date.removeFirst()).getNumber(); + boolean divide = isSymbol(date.removeFirst(),Symbol.DIVIDE); + int s10 = ((NumberPattern) date.removeFirst()).getNumber(); + int s1 = ((NumberPattern) date.removeFirst()).getNumber(); + if(divide) + m.setAttribute(MenuAttribute.DATE, new MenuDate((s10*10)+s1,(f10*10)+f1)); + else + m.setAttribute(MenuAttribute.DATE, new MenuDate((f10*10)+f1,(s10*10)+s1)); + + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + } + else + return null; + return m; + } + + private static Menu makeBolusData(LinkedList[] tokens) { + Menu m = new Menu(MenuType.BOLUS_DATA); + LinkedList bolus = new LinkedList<>(); + LinkedList cr = new LinkedList<>(); + LinkedList tr = new LinkedList<>(); + BolusType bt = null; + + int stage = 0; + while (tokens[1].size()>0) { + Token t = tokens[1].removeFirst(); + Pattern p = t.getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.BOLUS)) { + bt = BolusType.NORMAL; + stage++; + } else if (isSymbol(p, Symbol.EXTENDED_BOLUS)) { + bt = BolusType.EXTENDED; + stage++; + } else if (isSymbol(p, Symbol.MULTIWAVE)) { + bt = BolusType.MULTIWAVE; + stage++; + } else + return null; + break; + case 1: + if(isSymbol(p,Symbol.DOT)) + bolus.add(p); + else if(p instanceof NumberPattern) + bolus.add(p); + else if(p instanceof CharacterPattern && ((CharacterPattern)p).getCharacter()=='U') + stage++; + else + return null; + break; + case 2: + if(p instanceof NumberPattern) + cr.add((NumberPattern) p); + else if(isSymbol(p,Symbol.DIVIDE)) + stage++; + else + return null; + break; + case 3: + if(p instanceof NumberPattern) + tr.add((NumberPattern) p); + else if(isSymbol(p,Symbol.DIVIDE)) + stage++; + else + return null; + break; + case 4: + return null; + } + } + if(bt!=null) + { + m.setAttribute(MenuAttribute.BOLUS_TYPE,bt); + + try + { + String n = ""; + for(Pattern p: bolus) + { + if(p instanceof NumberPattern) + n+=((NumberPattern)p).getNumber(); + else if(isSymbol(p,Symbol.DOT)) + n+="."; + else + return null; + } + double d = Double.parseDouble(n); + m.setAttribute(MenuAttribute.BOLUS,d); + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + } + else + return null; + if(cr.size()==2 && tr.size() == 2) + { + int c = cr.removeFirst().getNumber()*10; + c+=cr.removeFirst().getNumber(); + m.setAttribute(MenuAttribute.CURRENT_RECORD,new Integer(c)); + int t = tr.removeFirst().getNumber()*10; + t+=tr.removeFirst().getNumber(); + m.setAttribute(MenuAttribute.TOTAL_RECORD,new Integer(t)); + } + else + return null; + + LinkedList clock = new LinkedList<>(); + stage = 0; + while(tokens[2].size()>0) { + Pattern p = tokens[2].removeFirst().getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.ARROW)) + stage++; + else + return null; + break; + case 1: + if(p instanceof NumberPattern) + clock.add(p); + else if(p instanceof CharacterPattern) + clock.add(p); + else if (isSymbol(p, Symbol.SEPERATOR)) + {} + else + return null; + break; + case 2: + return null; + } + } + if(clock.size()>=4) { + try { + int hour10 = ((NumberPattern) clock.removeFirst()).getNumber(); + int hour1 = ((NumberPattern) clock.removeFirst()).getNumber(); + int minute10 = ((NumberPattern) clock.removeFirst()).getNumber(); + int minute1 = ((NumberPattern) clock.removeFirst()).getNumber(); + int timeadd = 0; + if (clock.size() == 2) { + CharacterPattern p0 = (CharacterPattern) clock.removeFirst(); + CharacterPattern p1 = (CharacterPattern) clock.removeFirst(); + if(p0.getCharacter()=='A' && p1.getCharacter()=='M' && hour10==1 && hour1 == 2) + timeadd-=12; + else if(p0.getCharacter()=='P' && p1.getCharacter()=='M') + timeadd+=12; + } + m.setAttribute(MenuAttribute.RUNTIME,new MenuTime((hour10*10)+hour1+timeadd,(minute10*10)+minute1)); + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + + } + else if(bt != BolusType.NORMAL)//we need a runtime if not normal/quick bolus + return null; + + clock.clear(); + LinkedList date = new LinkedList<>(); + stage = 0; + while(tokens[3].size()>0) { + Pattern p = tokens[3].removeFirst().getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.CLOCK)) + stage++; + else + return null; + break; + case 1: + if(p instanceof NumberPattern) + clock.add(p); + else if(p instanceof CharacterPattern) + clock.add(p); + else if (isSymbol(p, Symbol.SEPERATOR)) + {} + else if(isSymbol(p,Symbol.CALENDAR)) + stage++; + else + return null; + break; + case 2: + if(p instanceof NumberPattern) + date.add(p); + else if (isSymbol(p, Symbol.DIVIDE)) + date .add(p); + else if (isSymbol(p, Symbol.DOT)) + date .add(p); + else + return null; + break; + case 3: + return null; + } + } + if(clock.size()>=4) { + try { + int hour10 = ((NumberPattern) clock.removeFirst()).getNumber(); + int hour1 = ((NumberPattern) clock.removeFirst()).getNumber(); + int minute10 = ((NumberPattern) clock.removeFirst()).getNumber(); + int minute1 = ((NumberPattern) clock.removeFirst()).getNumber(); + int timeadd = 0; + if (clock.size() == 2) { + CharacterPattern p0 = (CharacterPattern) clock.removeFirst(); + CharacterPattern p1 = (CharacterPattern) clock.removeFirst(); + if(p0.getCharacter()=='A' && p1.getCharacter()=='M' && hour10==1 && hour1 == 2) + timeadd-=12; + else if(p0.getCharacter()=='P' && p1.getCharacter()=='M') + timeadd+=12; + } + m.setAttribute(MenuAttribute.TIME,new MenuTime((hour10*10)+hour1+timeadd,(minute10*10)+minute1)); + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + + } + else + return null; + if(date.size()==5) { + try { + int f10 = ((NumberPattern) date.removeFirst()).getNumber(); + int f1 = ((NumberPattern) date.removeFirst()).getNumber(); + boolean divide = isSymbol(date.removeFirst(),Symbol.DIVIDE); + int s10 = ((NumberPattern) date.removeFirst()).getNumber(); + int s1 = ((NumberPattern) date.removeFirst()).getNumber(); + if(divide) + m.setAttribute(MenuAttribute.DATE, new MenuDate((s10*10)+s1,(f10*10)+f1)); + else + m.setAttribute(MenuAttribute.DATE, new MenuDate((f10*10)+f1,(s10*10)+s1)); + + }catch(Exception e) + { + e.printStackTrace(); + return null; + } + } + else + return null; + + return m; + } + + private static Menu makeQuickInfo(LinkedList[] tokens) { + Menu m = new Menu(MenuType.QUICK_INFO); + LinkedList number = new LinkedList<>(); + + int stage = 0; + while (tokens[1].size()>0) { + Token t = tokens[1].removeFirst(); + Pattern p = t.getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.LARGE_AMPULE_FULL)) { + stage++; + } else + return null; + break; + case 1: + if(p instanceof NumberPattern || isSymbol(p,Symbol.LARGE_DOT)) + { + number.add(p); + } + else if(p instanceof CharacterPattern && ((CharacterPattern)p).getCharacter()=='u') + { + stage++; + } + else + return null; + break; + case 3: + return null; + } + } + double doubleNumber = 0d; + String d = ""; + for(Pattern p : number) + { + if(p instanceof NumberPattern) + { + d+=""+((NumberPattern)p).getNumber(); + } else if(isSymbol(p,Symbol.LARGE_DOT)) { + d += "."; + } else { + return null;//violation! + } + } + try { doubleNumber = Double.parseDouble(d);} + catch (Exception e){return null;}//violation, there must something parseable + + m.setAttribute(MenuAttribute.REMAINING_INSULIN,new Double(doubleNumber)); + + //FIXME 4th line + tokens[3].clear(); + + return m; + } + + private static String parseString(LinkedList tokens, boolean consume) { + String s = ""; + Token last =null; + for(Token t : new LinkedList<>(tokens)) + { + Pattern p = t.getPattern(); + + if(consume) + tokens.removeFirst(); + + if(last!=null) + { + int x = last.getColumn()+last.getWidth()+1+3; + if(x < t.getColumn()) + { + s+=" "; + } + } + if(p instanceof CharacterPattern) + { + s += ((CharacterPattern)p).getCharacter(); + } + else if(isSymbol(p,Symbol.DOT)) + { + s+="."; + } + else if(isSymbol(p,Symbol.SEPERATOR)) + { + s+=":"; + } + else if(isSymbol(p,Symbol.DIVIDE)) + { + s+="/"; + } + else if(isSymbol(p,Symbol.BRACKET_LEFT)) + { + s+="("; + } + else if(isSymbol(p,Symbol.BRACKET_RIGHT)) + { + s+=")"; + } + else if(isSymbol(p,Symbol.MINUS)) + { + s+="-"; + } + else + { + return null; + } + last = t; + } + return s; + } + + private static Menu makeBolusDuration(LinkedList[] tokens) { + Menu m = new Menu(MenuType.BOLUS_DURATION); + LinkedList time = new LinkedList<>(); + + int stage = 0; + while (tokens[1].size()>0) { + Token t = tokens[1].removeFirst(); + Pattern p = t.getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.LARGE_ARROW)) { + stage++; + } else + return null; + break; + case 1: + case 2: + case 4: + case 5: + if (p instanceof NumberPattern) { + time.add(((NumberPattern) p).getNumber()); + stage++; + } else + return null; + break; + case 3: + if (isSymbol(p, Symbol.LARGE_SEPERATOR)) + stage++; + else + return null; + break; + } + } + if(time.size()==4) + { + int minute1 = time.removeLast(); + int minute10 = time.removeLast(); + int hour1 = time.removeLast(); + int hour10 = time.removeLast(); + m.setAttribute(MenuAttribute.RUNTIME,new MenuTime((hour10*10)+hour1,(minute10*10)+minute1)); + } + else if(time.size()==0) + { + m.setAttribute(MenuAttribute.RUNTIME,new MenuBlink()); + } + else + return null; + + LinkedList number = new LinkedList<>(); + LinkedList number2 = new LinkedList<>(); + Symbol sym1 = null; + Symbol sym2 = null; + stage = 0; + while (tokens[3].size()>0) { + Token t = tokens[3].removeFirst(); + Pattern p = t.getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.EXTENDED_BOLUS)) { + sym1 = Symbol.EXTENDED_BOLUS; + stage++; + } else if (isSymbol(p, Symbol.MULTIWAVE)) { + sym1 = Symbol.MULTIWAVE; + stage++; + } else + return null; + break; + case 1: + if (p instanceof NumberPattern || isSymbol(p, Symbol.DOT)) { + number.add(p); + } else if (p instanceof CharacterPattern && ((CharacterPattern) p).getCharacter() == 'U') { + stage++; + } else + return null; + break; + case 2: + if (isSymbol(p, Symbol.BOLUS)) { + sym2 = Symbol.BOLUS; + stage++; + } else + return null; + break; + case 3: + if (p instanceof NumberPattern || isSymbol(p,Symbol.DOT)) { + number2.add(p); + } else if(p instanceof CharacterPattern && ((CharacterPattern)p).getCharacter()=='U') { + stage++; + } else + return null; + break; + } + } + double doubleNumber = 0d; + String d = ""; + for(Pattern p : number) + { + if(p instanceof NumberPattern) + { + d+=""+((NumberPattern)p).getNumber(); + } else if(isSymbol(p,Symbol.DOT)) { + d += "."; + } else { + return null;//violation! + } + } + try { doubleNumber = Double.parseDouble(d);} + catch (Exception e){return null;}//violation, there must something parseable + + if(sym1 == Symbol.EXTENDED_BOLUS) + m.setAttribute(MenuAttribute.BOLUS,new Double(doubleNumber)); + else if(sym1 == Symbol.MULTIWAVE) { + m.setAttribute(MenuAttribute.BOLUS, new Double(doubleNumber)); + doubleNumber = 0d; + d = ""; + for (Pattern p : number2) { + if (p instanceof NumberPattern) { + d += "" + ((NumberPattern) p).getNumber(); + } else if (isSymbol(p, Symbol.DOT)) { + d += "."; + } else { + return null;//violation! + } + } + try { + doubleNumber = Double.parseDouble(d); + } catch (Exception e) { + return null; + }//violation, there must something parseable + + m.setAttribute(MenuAttribute.MULTIWAVE_BOLUS, new Double(doubleNumber)); + } + return m; + } + + private static Menu makeImmediateBolus(LinkedList[] tokens) { + Menu m = new Menu(MenuType.IMMEDIATE_BOLUS); + LinkedList number = new LinkedList<>(); + + int stage = 0; + while (tokens[1].size()>0) { + Token t = tokens[1].removeFirst(); + Pattern p = t.getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.LARGE_MULTIWAVE_BOLUS)) { + stage++; + } else + return null; + break; + case 1: + if (p instanceof NumberPattern) { + number.add(p); + } else if(isSymbol(p,Symbol.LARGE_DOT)) { + number.add(p); + } else if(p instanceof CharacterPattern && ((CharacterPattern)p).getCharacter()=='u') { + stage++; + } else + return null; + break; + case 3: + return null; + } + } + + double doubleNumber = 0d; + String d = ""; + + if(number.size()==0) + { + m.setAttribute(MenuAttribute.MULTIWAVE_BOLUS,new MenuBlink()); + } + else { + for (Pattern p : number) { + if (p instanceof NumberPattern) { + d += "" + ((NumberPattern) p).getNumber(); + } else if (isSymbol(p, Symbol.LARGE_DOT)) { + d += "."; + } else { + return null;//violation! + } + } + try { + doubleNumber = Double.parseDouble(d); + } catch (Exception e) { + return null; + }//violation, there must something parseable + + m.setAttribute(MenuAttribute.MULTIWAVE_BOLUS, new Double(doubleNumber)); + } + + LinkedList time = new LinkedList<>(); + number.clear(); + stage = 0; + while (tokens[3].size() > 0) { + Token t = tokens[3].removeFirst(); + Pattern p = t.getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.ARROW)) { + stage++; + } else + return null; + break; + case 1: + case 2: + case 4: + case 5: + if (p instanceof NumberPattern) { + time.add(((NumberPattern) p).getNumber()); + stage++; + } else + return null; + break; + case 3: + if (isSymbol(p, Symbol.SEPERATOR)) + stage++; + else + return null; + break; + case 6: + if (isSymbol(p, Symbol.MULTIWAVE)) { + stage++; + } else + return null; + break; + case 7: + if (p instanceof NumberPattern || isSymbol(p,Symbol.DOT)) { + number.add(p); + } else if(p instanceof CharacterPattern && ((CharacterPattern)p).getCharacter()=='U') { + stage++; + } else + return null; + break; + case 8: + return null; + } + } + if (time.size() == 4) { + int minute1 = time.removeLast(); + int minute10 = time.removeLast(); + int hour1 = time.removeLast(); + int hour10 = time.removeLast(); + m.setAttribute(MenuAttribute.RUNTIME, new MenuTime((hour10 * 10) + hour1, (minute10 * 10) + minute1)); + } + else + return null; + + if(number.size()>0) + { + d=""; + for (Pattern p : number) { + if (p instanceof NumberPattern) { + d += "" + ((NumberPattern) p).getNumber(); + } else if (isSymbol(p, Symbol.DOT)) { + d += "."; + } else { + return null;//violation! + } + } + try { + doubleNumber = Double.parseDouble(d); + } catch (Exception e) { + return null; + }//violation, there must something parseable + + m.setAttribute(MenuAttribute.BOLUS, new Double(doubleNumber)); + } + else + return null; + return m; + } + + private static Menu makeBolusEnter(LinkedList[] tokens) { + Menu m = new Menu(MenuType.BOLUS_ENTER); + LinkedList number = new LinkedList<>(); + + int stage = 0; + + BolusType bt = null; + //main part + while (tokens[1].size()>0) { + Token t = tokens[1].removeFirst(); + Pattern p = t.getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.LARGE_BOLUS)) { + bt = BolusType.NORMAL; + stage++; + } else if (isSymbol(p, Symbol.LARGE_MULTIWAVE)) { + bt = BolusType.MULTIWAVE; + stage++; + } else if (isSymbol(p, Symbol.LARGE_EXTENDED_BOLUS)) { + bt = BolusType.EXTENDED; + stage++; + } else if(p instanceof NumberPattern) { + number.add(p); + stage++; + } else if(p instanceof CharacterPattern && ((CharacterPattern)p).getCharacter()=='u') { + stage=2; + }else + return null; + break; + case 1: + if (p instanceof NumberPattern) { + number.add(p); + } else if(isSymbol(p,Symbol.LARGE_DOT)) { + number.add(p); + } else if(p instanceof CharacterPattern && ((CharacterPattern)p).getCharacter()=='u') { + stage++; + } else + return null; + break; + case 2: + return null; + } + } + + if(bt!=null) + m.setAttribute(MenuAttribute.BOLUS_TYPE,bt); + else + m.setAttribute(MenuAttribute.BOLUS_TYPE,new MenuBlink()); + + double doubleNumber = 0d; + String d = ""; + if(number.size()>0) { + for (Pattern p : number) { + if (p instanceof NumberPattern) { + d += "" + ((NumberPattern) p).getNumber(); + } else if (isSymbol(p, Symbol.LARGE_DOT)) { + d += "."; + } else { + return null;//violation! + } + } + try { + doubleNumber = Double.parseDouble(d); + } catch (Exception e) { + return null; + }//violation, there must something parseable + + m.setAttribute(MenuAttribute.BOLUS, new Double(doubleNumber)); + } else + m.setAttribute(MenuAttribute.BOLUS,new MenuBlink()); + + //4th line + LinkedList time = new LinkedList<>(); + number.clear(); + stage = 0; + while (tokens[3].size() > 0) { + Token t = tokens[3].removeFirst(); + Pattern p = t.getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.ARROW)) { + stage++; + } else + return null; + break; + case 1: + case 2: + case 4: + case 5: + if (p instanceof NumberPattern) { + time.add(((NumberPattern) p).getNumber()); + stage++; + } else + return null; + break; + case 3: + if (isSymbol(p, Symbol.SEPERATOR)) + stage++; + else + return null; + break; + case 6: + if (isSymbol(p, Symbol.BOLUS)) { + stage++; + } else + return null; + break; + case 7: + if (p instanceof NumberPattern) { + number.add(p); + } else if(isSymbol(p,Symbol.DOT)) { + number.add(p); + } else if(p instanceof CharacterPattern && ((CharacterPattern)p).getCharacter()=='U') { + stage++; + } else + return null; + break; + case 8: + return null; + } + } + if(time.size()>0) + { + int minute1 = time.removeLast(); + int minute10 = time.removeLast(); + int hour1 = time.removeLast(); + int hour10 = time.removeLast(); + m.setAttribute(MenuAttribute.RUNTIME, new MenuTime((hour10 * 10) + hour1, (minute10 * 10) + minute1)); + + if(number.size() > 0) + { + doubleNumber = 0d; + d = ""; + for(Pattern p : number) + { + if(p instanceof NumberPattern) + { + d+=""+((NumberPattern)p).getNumber(); + } else if(isSymbol(p,Symbol.DOT)) { + d += "."; + } else if(p instanceof CharacterPattern && ((CharacterPattern)p).getCharacter()=='U'){ + //irgnore + } else { + return null;//violation! + } + } + try { doubleNumber = Double.parseDouble(d);} + catch (Exception e){return null;}//violation, there must something parseable + + m.setAttribute(MenuAttribute.MULTIWAVE_BOLUS, new Double(doubleNumber)); + } + } + else + { + m.setAttribute(MenuAttribute.RUNTIME, new MenuTime(0,0)); + m.setAttribute(MenuAttribute.MULTIWAVE_BOLUS, new Double(0)); + } + return m; + } + + private static Menu makeMainMenu(LinkedList[] tokens) { + Menu m = new Menu(MenuType.MAIN_MENU); + LinkedList time = new LinkedList<>(); + LinkedList runtime = new LinkedList<>(); + LinkedList timeC = new LinkedList<>(); + boolean hasRunning=false; + + int stage = 0; + while(tokens[0].size()>0) + { + Token t = tokens[0].removeFirst(); + Pattern p = t.getPattern(); + switch(stage) + { + case 0://clock + if(!isSymbol(p,Symbol.CLOCK)) + return null;//wrong + stage++; + break; + case 1://hour10 + case 2://hour1 + case 4://minute10 + case 5://minute1 + if (p instanceof NumberPattern) { + time.add(((NumberPattern) p).getNumber()); + } else + return null;//Wrong + stage++; + break; + case 3://: or number (: blinks) + if(isSymbol(p,Symbol.SEPERATOR)) + { + stage++; + } + else if (p instanceof NumberPattern) { + time.add(((NumberPattern) p).getNumber()); + stage += 2; + } + else + return null;//wr + break; + case 6://P(m), A(M), or running + if(p instanceof CharacterPattern) { + timeC.add(((CharacterPattern) p).getCharacter()); + stage++; + } else if(isSymbol(p,Symbol.ARROW)) { + hasRunning = true; + stage = 9; + } else + return null;//wrong + break; + case 7://it should be an M + if(p instanceof CharacterPattern) { + timeC.add(((CharacterPattern) p).getCharacter()); + stage++; + } else + return null;//nothing else matters + break; + case 8://can onbly be running arrow + if(isSymbol(p,Symbol.ARROW)) { + hasRunning = true; + stage++; + } else + return null; + break; + case 9://h10 + case 10://h1 + case 12://m10 + case 13://m1 + if (p instanceof NumberPattern) { + runtime.add(((NumberPattern) p).getNumber()); + } else + return null;//Wrong + stage++; + break; + case 11://: or number (: blinks) + if(isSymbol(p,Symbol.SEPERATOR)) + { + stage++; + } + else + return null;//wr + break; + default: + return null;//the impossible girl + } + } + //set time + int minute1 = time.removeLast(); + int minute10 = time.removeLast(); + int hour1 = time.removeLast(); + int hour10 = 0; + if(time.size()>0) + hour10 = time.removeLast(); + + int tadd = 0; + if(timeC.size()>0) + { + if(timeC.get(0)=='P' && timeC.get(1)=='M' && !(hour10==1 && hour1 == 2)) + { + tadd += 12; + } + else if(timeC.get(0)=='A' && timeC.get(1)=='M' && hour10 == 1 && hour1 == 2) + { + tadd -= 12; + } + } + m.setAttribute(MenuAttribute.TIME,new MenuTime((hour10*10)+tadd+hour1,(minute10*10)+minute1)); + + if(hasRunning) { + minute1 = runtime.removeLast(); + minute10 = runtime.removeLast(); + hour1 = runtime.removeLast(); + hour10 = runtime.removeLast(); + m.setAttribute(MenuAttribute.RUNTIME, new MenuTime((hour10 * 10) + hour1, (minute10 * 10) + minute1)); + } + + stage = 0; + BolusType bt = null; + int tbr = 0; + LinkedList number = new LinkedList<>(); + + while(tokens[1].size()>0) { + Token t = tokens[1].removeFirst(); + Pattern p = t.getPattern(); + switch (stage) { + case 0: + if (isSymbol(p, Symbol.SEPERATOR.LARGE_EXTENDED_BOLUS)) { + bt = BolusType.EXTENDED; + stage++; + } else if (isSymbol(p, Symbol.SEPERATOR.LARGE_MULTIWAVE)) { + bt = BolusType.MULTIWAVE_EXTENDED; + stage++; + } + else if(isSymbol(p,Symbol.SEPERATOR.LARGE_MULTIWAVE_BOLUS)) + { + bt = BolusType.MULTIWAVE_BOLUS; + stage++; + } + else if(isSymbol(p,Symbol.SEPERATOR.LARGE_BOLUS)) + { + bt = BolusType.NORMAL; + stage++; + } + else if (isSymbol(p, Symbol.SEPERATOR.LARGE_BASAL)) { + bt = null; + stage++; + } else { + return null; + } + break; + case 1: + if (isSymbol(p, Symbol.UP)) { + tbr = 1; + stage++; + } else if (isSymbol(p, Symbol.DOWN)) { + tbr = 2; + stage++; + } else if (p instanceof NumberPattern) { + number.add(p); + stage += 2; + } else + return null;// + break; + case 2: + if (p instanceof NumberPattern) { + number.add(p); + stage++; + } else + return null;// + break; + case 3: + if (p instanceof NumberPattern) { + number.add(p); + } else if (p instanceof CharacterPattern && ((CharacterPattern)p).getCharacter()=='u') { + number.add(p); + } else if (isSymbol(p, Symbol.LARGE_DOT) || isSymbol(p, Symbol.LARGE_PERCENT) || isSymbol(p,Symbol.LARGE_UNITS_PER_HOUR)) { + number.add(p); + } else + return null;// + break; + } + } + double doubleNUmber = 0d; + String d = ""; + for(Pattern p : number) + { + if(p instanceof NumberPattern) + { + d+=""+((NumberPattern)p).getNumber(); + } else if(isSymbol(p,Symbol.LARGE_DOT)) { + d += "."; + } else if(isSymbol(p,Symbol.LARGE_PERCENT) || + isSymbol(p,Symbol.LARGE_UNITS_PER_HOUR) || + (p instanceof CharacterPattern && ((CharacterPattern)p).getCharacter()=='u')){ + //irgnore + } else { + return null;//violation! + } + } + try { doubleNUmber = Double.parseDouble(d);} + catch (Exception e){return null;}//violation, there must something parseable + + if(bt != null) + { + //running bolus + m.setAttribute(MenuAttribute.BOLUS_TYPE,bt); + m.setAttribute(MenuAttribute.BOLUS_REMAINING,doubleNUmber); + } + else + { + switch(tbr) + { + case 0: + m.setAttribute(MenuAttribute.TBR,new Double(100)); + m.setAttribute(MenuAttribute.BASAL_RATE,doubleNUmber); + break; + case 1: + case 2: + m.setAttribute(MenuAttribute.TBR,new Double(doubleNUmber)); + break; + } + } + + if(tokens[2].size()==1 && tokens[2].get(0).getPattern() instanceof NumberPattern) + m.setAttribute(MenuAttribute.BASAL_SELECTED,new Integer(((NumberPattern)tokens[2].removeFirst().getPattern()).getNumber())); + else + return null; + + stage = 0; + number.clear(); + int lowInsulin = 0; + boolean lowBattery= false; + boolean waranty = true; + + int lockState = 0; + while(tokens[3].size()>0) { + Token t = tokens[3].removeFirst(); + Pattern p = t.getPattern(); + switch (stage) { + case 0: + if (p instanceof NumberPattern) { + number.add(p); + } else if (isSymbol(p, Symbol.DOT)) { + number.add(p); + } else if (isSymbol(p, Symbol.UNITS_PER_HOUR)) { + number.add(p); + stage++; + } else if (isSymbol(p, Symbol.LOW_BAT)) { + lowBattery = true; + } else if (isSymbol(p, Symbol.LOW_INSULIN)) { + lowInsulin= 1; + } else if (isSymbol(p, Symbol.NO_INSULIN)) { + lowInsulin= 2; + } else if (isSymbol(p, Symbol.LOCK_CLOSED)) { + lockState=2; + } else if (isSymbol(p, Symbol.LOCK_OPENED)) { + lockState=2; + } else if (isSymbol(p, Symbol.WARANTY)) { + waranty = false; + } else { + return null; + } + break; + case 1: + if (isSymbol(p, Symbol.LOW_BAT)) { + lowBattery = true; + } else if (isSymbol(p, Symbol.LOW_INSULIN)) { + lowInsulin = 1; + } else if (isSymbol(p, Symbol.NO_INSULIN)) { + lowInsulin= 2; + } else if (isSymbol(p, Symbol.LOCK_CLOSED)) { + lockState=2; + } else if (isSymbol(p, Symbol.LOCK_OPENED)) { + lockState=2; + } else if (isSymbol(p, Symbol.WARANTY)) { + waranty = false; + } else { + return null; + } + break; + } + } + if(lowBattery) + m.setAttribute(MenuAttribute.LOW_BATTERY,new Boolean(true)); + else + m.setAttribute(MenuAttribute.LOW_BATTERY,new Boolean(false)); + + m.setAttribute(MenuAttribute.INSULIN_STATE,lowInsulin); + m.setAttribute(MenuAttribute.WARANTY,new Boolean(waranty)); + + m.setAttribute(MenuAttribute.LOCK_STATE,new Integer(lockState)); + + if(number.size()>0) { + doubleNUmber = 0d; + d = ""; + for (Pattern p : number) { + if (p instanceof NumberPattern) { + d += "" + ((NumberPattern) p).getNumber(); + } else if (isSymbol(p, Symbol.DOT)) { + d += "."; + } else if (isSymbol(p, Symbol.UNITS_PER_HOUR)) { + //irgnore + } else { + return null;//violation! + } + } + try { + doubleNUmber = Double.parseDouble(d); + } catch (Exception e) { + return null; + }//violation, there must something parseable + m.setAttribute(MenuAttribute.BASAL_RATE, doubleNUmber); + } + + return m; + } + + + private static boolean isSymbol(Pattern p, Symbol symbol) { + return (p instanceof SymbolPattern) && ((SymbolPattern) p).getSymbol() == symbol; + } +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuTime.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuTime.java index 147aafc8eb..7f844416a8 100644 --- a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuTime.java +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuTime.java @@ -31,6 +31,6 @@ public class MenuTime { @Override public String toString() { - return hour+":"+String.format("%02d",minute); + return hour+":"+ String.format("%02d",minute); } } diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/Title.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/Title.java new file mode 100644 index 0000000000..2d123cdcfa --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/Title.java @@ -0,0 +1,18 @@ +package org.monkey.d.ruffy.ruffy.driver.display.menu; + +/** + * Created by fishermen21 on 22.05.17. + */ + +enum Title { + BOLUS_AMOUNT, + IMMEDIATE_BOLUS, + BOLUS_DURATION, + QUICK_INFO, + BOLUS_DATA, + ERROR_DATA, + DAILY_TOTALS, + TBR_DATA, + TBR_SET, + TBR_DURATION, +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/TitleResolver.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/TitleResolver.java new file mode 100644 index 0000000000..9c09ec172a --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/TitleResolver.java @@ -0,0 +1,459 @@ +package org.monkey.d.ruffy.ruffy.driver.display.menu; + +/** + * Created by fishermen21 on 22.05.17. + */ + +class TitleResolver { + public static Title resolve(String title) { + + /**english titles**/ + if(title.equalsIgnoreCase("bolus amount")) + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("immediate bolus")) + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("bolus duration")) + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("bolus data")) + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("error data")) + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("daily totals")) + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("tbr data")) + return Title.TBR_DATA; + if(title.equalsIgnoreCase("tbr percentage")) + return Title.TBR_SET; + if(title.equalsIgnoreCase("tbr duration")) + return Title.TBR_DURATION; + + /**german titles**/ + if(title.equalsIgnoreCase("bolus-menge")) + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("sofortige abgabe")) + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("abgabedauer")) + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("bolusinformation")) + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("fehlermeldungen")) + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("tagesgesamtmenge")) + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("tbr-information")) + return Title.TBR_DATA; + if(title.equalsIgnoreCase("tbr wert")) + return Title.TBR_SET; + if(title.equalsIgnoreCase("tbr dauer")) + return Title.TBR_DURATION; + + /**French titles**/ + if(title.equalsIgnoreCase("quantitΓ© bolus")) + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("quanti. immΓ©diate")) + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("durΓ©e du bolus")) + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("bolus")) + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("erreurs")) + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("quantitΓ©s journ.")) + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("dbt")) + return Title.TBR_DATA; + if(title.equalsIgnoreCase("valeur du dbt")) + return Title.TBR_SET; + if(title.equalsIgnoreCase("durΓ©e du dbt")) + return Title.TBR_DURATION; + + + /**spanish titles**/ + if(title.equalsIgnoreCase("cantidad de bolo")) + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("bolo inmediato")) + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("duraciΓ³n de bolo")) + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("datos de bolo")) + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("datos de error")) + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("totales diarios")) + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("datos de dbt")) + return Title.TBR_DATA; + if(title.equalsIgnoreCase("porcentaje dbt")) + return Title.TBR_SET; + if(title.equalsIgnoreCase("duraciΓ³n de dbt")) + return Title.TBR_DURATION; + + + /**italian titles**/ + if(title.equalsIgnoreCase("quantita bolo")) //multiwave 1 + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("bolo immediato")) //multiwave 2 + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("tempo erogazione")) //multiwave 3 + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) //check1 + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("memoria boli")) //check2, mydata 1 + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("memoria allarmi")) //mydata 2 + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("totali giornata")) //mydata 3 + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("memoria pbt")) //mydata 4 + return Title.TBR_DATA; + if(title.equalsIgnoreCase("percentuale pbt")) //TBR 1 + return Title.TBR_SET; + if(title.equalsIgnoreCase("durata pbt")) //TBR 2 + return Title.TBR_DURATION; + + /**dutch titles**/ + if(title.equalsIgnoreCase("bolushoeveelheid")) //multiwave 1 + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("directe bolus")) //multiwave 2 + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("bolusduur")) //multiwave 3 + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) //check1 + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("bolusgegevens")) //check2, mydata 1 + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("foutengegevens")) //mydata 2 + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("dagtotalen")) //mydata 3 + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("tbd-gegevens")) //mydata 4 + return Title.TBR_DATA; + if(title.equalsIgnoreCase("tbd-percentage")) //TBR 1 + return Title.TBR_SET; + if(title.equalsIgnoreCase("tbd-duur")) //TBR 2 + return Title.TBR_DURATION; + + /**norwegian titles**/ + if(title.equalsIgnoreCase("bolusmengde")) //multiwave 1 + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("umiddelbar bolus")) //multiwave 2 + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("bolusvarighet")) //multiwave 3 + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) //check1 + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("bolusdata")) //check2, mydata 1 + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("feildata")) //mydata 2 + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("dΓΈgnmengde")) //mydata 3 + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("mbd-data")) //mydata 4 + return Title.TBR_DATA; + if(title.equalsIgnoreCase("mbd-prosent")) //TBR 1 + return Title.TBR_SET; + if(title.equalsIgnoreCase("mbd-varighet")) //TBR 2 + return Title.TBR_DURATION; + + /**polish titles**/ + if(title.equalsIgnoreCase("wielkoΕ›Δ‡ bolusa")) //multiwave 1 + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("bolus natychm.")) //multiwave 2 + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("cz. trw. bolusa")) //multiwave 3 + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) //check1 + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("dane bolusa")) //check2, mydata 1 + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("dane bΕ‚Δ™du")) //mydata 2 + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("dzien. d. caΕ‚k.")) //mydata 3 + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("dane tdp")) //mydata 4 + return Title.TBR_DATA; + if(title.equalsIgnoreCase("procent tdp")) //TBR 1 + return Title.TBR_SET; + if(title.equalsIgnoreCase("czas trwania tdp")) //TBR 2 + return Title.TBR_DURATION; + + /**cz titles**/ + if(title.equalsIgnoreCase("mnoΕΎstvΓ­ bolusu")) //multiwave 1 + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("okamΕΎitΓ½ bolus")) //multiwave 2 + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("trvΓ‘nΓ­ bolusu")) //multiwave 3 + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) //check1 + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("ΓΊdaje bolusΕ―")) //check2, mydata 1 + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("ΓΊdaje chyb")) //mydata 2 + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("celk. den. dΓ‘vky")) //mydata 3 + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("ΓΊdaje dbd")) //mydata 4 + return Title.TBR_DATA; + if(title.equalsIgnoreCase("procento dbd")) //TBR 1 + return Title.TBR_SET; + if(title.equalsIgnoreCase("trvΓ‘nΓ­ dbd")) //TBR 2 + return Title.TBR_DURATION; + + /**finnish titles**/ + if(title.equalsIgnoreCase("boluksen mÀÀrΓ€")) //multiwave 1 + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("nopea bolus")) //multiwave 2 + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("boluksen kesto")) //multiwave 3 + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) //check1 + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("bolustiedot")) //check2, mydata 1 + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("hΓ€lytystiedot")) //mydata 2 + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("pΓ€iv. kok.annos")) //mydata 3 + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("tba - tiedot")) //mydata 4 + return Title.TBR_DATA; + if(title.equalsIgnoreCase("tba - prosentti")) //TBR 1 + return Title.TBR_SET; + if(title.equalsIgnoreCase("tba - kesto")) //TBR 2 + return Title.TBR_DURATION; + + /**turkish titles**/ + if(title.equalsIgnoreCase("bolus mΔ°ktari")) //multiwave 1 + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("hemen bolus uygl")) //multiwave 2 + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("bolus sΓΌresΔ°")) //multiwave 3 + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) //check1 + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("bolus verΔ°lerΔ°")) //check2, mydata 1 + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("hata verΔ°lerΔ°")) //mydata 2 + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("gΓΌnlΓΌk toplam")) //mydata 3 + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("gbh verΔ°lerΔ°")) //mydata 4 + return Title.TBR_DATA; + if(title.equalsIgnoreCase("gbh yΓΌzdesΔ°")) //TBR 1 + return Title.TBR_SET; + if(title.equalsIgnoreCase("gbh sΓΌresΔ°")) //TBR 2 + return Title.TBR_DURATION; + + /**romanian titles**/ + if(title.equalsIgnoreCase("cantitate bolus")) //multiwave 1 + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("bolus imediat")) //multiwave 2 + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("duratΔƒ bolus")) //multiwave 3 + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) //check1 + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("date bolus")) //check2, mydata 1 + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("date eroare")) //mydata 2 + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("totaluri zilnice")) //mydata 3 + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("date rbt")) //mydata 4 + return Title.TBR_DATA; + if(title.equalsIgnoreCase("procent rbt")) //TBR 1 + return Title.TBR_SET; + if(title.equalsIgnoreCase("durata rbt")) //TBR 2 + return Title.TBR_DURATION; + + /**swedish titles**/ + if(title.equalsIgnoreCase("bolusmΓ€ngd")) //multiwave 1 + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("direkt bolus")) //multiwave 2 + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("bolusduration")) //multiwave 3 + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) //check1 + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("bolusdata")) //check2, mydata 1 + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("feldata")) //mydata 2 + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("dygnshistorik")) //mydata 3 + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("tbd data")) //mydata 4 + return Title.TBR_DATA; + if(title.equalsIgnoreCase("tbd procent")) //TBR 1 + return Title.TBR_SET; + if(title.equalsIgnoreCase("tbd duration")) //TBR 2 + return Title.TBR_DURATION; + + + /**danish titles**/ + if(title.equalsIgnoreCase("bolusmΓ¦ngde")) //multiwave 1 + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("umiddelbar bolus")) //multiwave 2 + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("bolusvarighed")) //multiwave 3 + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) //check1 + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("bolusdata")) //check2, mydata 1 + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("fejldata")) //mydata 2 + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("daglig total")) //mydata 3 + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("mbr-data")) //mydata 4 + return Title.TBR_DATA; + if(title.equalsIgnoreCase("mbr-procent")) //TBR 1 + return Title.TBR_SET; + if(title.equalsIgnoreCase("mbr-varighed")) //TBR 2 + return Title.TBR_DURATION; + + /**hungarian titles**/ + if(title.equalsIgnoreCase("bΓ³lusmennyisΓ©g")) //multiwave 1 + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("azonnali bΓ³lus")) //multiwave 2 + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("bΓ³lus idΕ‘tartam")) //multiwave 3 + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) //check1 + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("bΓ³lusadatok")) //check2, mydata 1 + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("hibaadatok")) //mydata 2 + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("napi teljes")) //mydata 3 + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("tbr-adatok")) //mydata 4 + return Title.TBR_DATA; + if(title.equalsIgnoreCase("tbr szΓ‘zalΓ©k")) //TBR 1 + return Title.TBR_SET; + if(title.equalsIgnoreCase("tbr idΕ‘tartam")) //TBR 2 + return Title.TBR_DURATION; + + + /**slovak titles**/ + if(title.equalsIgnoreCase("mnoΕΎstvo bolusu")) //multiwave 1 + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("okamΕΎitΓ½ bolus")) //multiwave 2 + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("trvanie bolusu")) //multiwave 3 + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) //check1 + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("bolusovΓ© dΓ‘ta")) //check2, mydata 1 + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("dΓ‘ta o chybΓ‘ch")) //mydata 2 + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("súčty dňa")) //mydata 3 + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("dbd dΓ‘ta")) //mydata 4 + return Title.TBR_DATA; + if(title.equalsIgnoreCase("percento dbd")) //TBR 1 + return Title.TBR_SET; + if(title.equalsIgnoreCase("trvanie dbd")) //TBR 2 + return Title.TBR_DURATION; + + /**portugues titles**/ + if(title.equalsIgnoreCase("volume do bolus")) //multiwave 1 + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("bolus imediato")) //multiwave 2 + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("duraÇão do bolus")) //multiwave 3 + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) //check1 + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("dados de bolus")) //check2, mydata 1 + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("dados de erros")) //mydata 2 + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("totais diΓ‘rios")) //mydata 3 + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("dados dbt")) //mydata 4 + return Title.TBR_DATA; + if(title.equalsIgnoreCase("dbt percentagem")) //TBR 1 + return Title.TBR_SET; + if(title.equalsIgnoreCase("dbt duraÇão")) //TBR 2 + return Title.TBR_DURATION; + + + /**russian titles**/ + if(title.equalsIgnoreCase("OбъEΠΌ Π±OлюCΠ°")) //multiwave 1 + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("ΠΏPямOΠΉ Π±OлюC")) //multiwave 2 + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("ΠΏPOΠ΄OΠ»ΠΆ. Π±OлюCΠ°")) //multiwave 3 + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) //check1 + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("Π΄Π°HHΡ‹E O Π±OлюCE")) //check2, mydata 1 + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("Π΄Π°HHΡ‹E OΠ± O ΠΈΠ±.")) //mydata 2 + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("CΡƒTOΡ‡HΡ‹E Π΄OΠ·Ρ‹")) //mydata 3 + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("Π΄Π°HHΡ‹E O BΠ±C")) //mydata 4 + return Title.TBR_DATA; + if(title.equalsIgnoreCase("ΠΏPOΡ†EHT BΠ±C")) //TBR 1 + return Title.TBR_SET; + if(title.equalsIgnoreCase("ΠΏPOΠ΄OΠ»ΠΆΠΈT. BΠ±C")) //TBR 2 + return Title.TBR_DURATION; + + /**croatian titles**/ + if(title.equalsIgnoreCase("KOLIčINA BOLUSA")) //multiwave 1 + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("TRENUTNI BOLUS")) //multiwave 2 + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("TRAJANJE BOLUSA")) //multiwave 3 + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) //check1 + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("PODACI O BOLUSU")) //check2, mydata 1 + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("PODACI O GREΕ‘K.")) //mydata 2 + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("UKUPNE DNEV.DOZE")) //mydata 3 + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("PODACI O PBD-u")) //mydata 4 + return Title.TBR_DATA; + if(title.equalsIgnoreCase("POSTOTAK PBD-a")) //TBR 1 + return Title.TBR_SET; + if(title.equalsIgnoreCase("TRAJANJE PBD-a")) //TBR 2 + return Title.TBR_DURATION; + + /**greek titles**/ + if(title.equalsIgnoreCase("ΠΏOΞ£OTHTΠ° Ξ”OΞ£HΞ£")) //multiwave 1 + return Title.BOLUS_AMOUNT; + if(title.equalsIgnoreCase("Π°ΠΌEΞ£H Ξ”OΞ£H")) //multiwave 2 + return Title.IMMEDIATE_BOLUS; + if(title.equalsIgnoreCase("Ξ”IΠ°PKEIΠ° Ξ”OΞ£HΞ£")) //multiwave 3 + return Title.BOLUS_DURATION; + if(title.equalsIgnoreCase("quick info")) //check1 + return Title.QUICK_INFO; + if(title.equalsIgnoreCase("Ξ”EΞ”OΠΌENΠ° Ξ”OΞ£EΞ©N")) //check2, mydata 1 + return Title.BOLUS_DATA; + if(title.equalsIgnoreCase("Ξ”EΞ”OΠΌ. ΣΦаΛмаTΞ©N")) //mydata 2 + return Title.ERROR_DATA; + if(title.equalsIgnoreCase("HΠΌEPHΞ£IO ΣυNOΞ›O")) //mydata 3 + return Title.DAILY_TOTALS; + if(title.equalsIgnoreCase("Ξ”EΞ”OΠΌENΠ° ΠΏ.B.P.")) //mydata 4 + return Title.TBR_DATA; + if(title.equalsIgnoreCase("ΠΏOΞ£OΞ£TO ΠΏ.B.P.")) //TBR 1 + return Title.TBR_SET; + if(title.equalsIgnoreCase("Ξ”IΠ°PKEIΠ° ΠΏ.B.P.")) //TBR 2 + return Title.TBR_DURATION; + + + //FIXME add Translations + return null; + } +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/CharacterPattern.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/CharacterPattern.java new file mode 100644 index 0000000000..0943169fa9 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/CharacterPattern.java @@ -0,0 +1,23 @@ +package org.monkey.d.ruffy.ruffy.driver.display.parser; + +/** + * Created by fishermen21 on 21.05.17. + */ + +public class CharacterPattern extends Pattern { + private final char character; + + public CharacterPattern(char c, String[] patternString, int blocksize) { + super(patternString,blocksize); + this.character = c; + } + + @Override + public String toString() { + return "Character("+character+")"; + } + + public char getCharacter() { + return character; + } +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/LargeTextParser.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/LargeTextParser.java new file mode 100644 index 0000000000..44193dedeb --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/LargeTextParser.java @@ -0,0 +1,683 @@ +package org.monkey.d.ruffy.ruffy.driver.display.parser; + +import org.monkey.d.ruffy.ruffy.driver.display.Symbol; +import org.monkey.d.ruffy.ruffy.driver.display.Token; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +/** + * Created by fishermen21 on 20.05.17. + */ + +public class LargeTextParser { + + private static String[][] numbers = { + { + " β–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ " + }, + { + " β–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ " + }, + { + " β–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }, + { + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ " + + }, + { + " β–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ " + + }, + { + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ " + }, + { + " β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ " + }, + { + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ " + }, + { + " β–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ " + }, + { + " β–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + " β–ˆβ–ˆ β–ˆβ–ˆβ–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆβ–ˆ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ " + } + }; + + private static Map letters = new HashMap(); + + static { + letters.put('E', new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + letters.put('W', new String[]{ + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ ", + " β–ˆ β–ˆ " + }); + letters.put('u', new String[]{ + " ", + " ", + " ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆ " + }); + } + + private static Map symbols = new HashMap(); + + static { + symbols.put(Symbol.LARGE_DOT, new String[]{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "β–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆ ", + " " + }); + symbols.put(Symbol.LARGE_SEPERATOR, new String[]{ + " ", + " ", + " ", + "β–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆ ", + " ", + " ", + "β–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆ ", + " ", + " ", + }); + symbols.put(Symbol.LARGE_WARNING, new String[]{ + " β–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆ β–ˆβ–ˆ β–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆ β–ˆβ–ˆ β–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + symbols.put(Symbol.LARGE_PERCENT, new String[]{ + " β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + }); + symbols.put(Symbol.LARGE_UNITS_PER_HOUR, new String[]{ + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ" + }); + symbols.put(Symbol.LARGE_BASAL_SET, new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆβ–ˆ β–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆ β–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆ β–ˆ β–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆβ–ˆ" + }); + symbols.put(Symbol.LARGE_AMPULE_FULL, new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ " + }); + symbols.put(Symbol.LARGE_ARROW, new String[]{ + " β–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆ " + }); + symbols.put(Symbol.LARGE_EXTENDED_BOLUS, new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + symbols.put(Symbol.LARGE_MULTIWAVE, new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ" + }); + symbols.put(Symbol.LARGE_BOLUS, new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + symbols.put(Symbol.LARGE_MULTIWAVE_BOLUS, new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ" + }); + symbols.put(Symbol.LARGE_STOP, new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ β–ˆ β–ˆ β–ˆβ–ˆ", + "β–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆ β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆ β–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆ β–ˆ β–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆ β–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ " + }); + symbols.put(Symbol.LARGE_CALENDAR, new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆ ", + "β–ˆ β–ˆ β–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆ ", + "β–ˆ β–ˆ β–ˆ β–ˆβ–ˆβ–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ β–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆβ–ˆ β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + symbols.put(Symbol.LARGE_TBR, new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ " + }); + symbols.put(Symbol.LARGE_BASAL, new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ" + }); + symbols.put(Symbol.LARGE_PUMP_SETTINGS, new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ", + " β–ˆβ–ˆ", + " β–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆ β–ˆ β–ˆ", + " β–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + symbols.put(Symbol.LARGE_PUMP_SETTINGS, new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ", + " β–ˆβ–ˆ", + " β–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆ β–ˆ β–ˆ", + " β–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + symbols.put(Symbol.LARGE_THERAPIE_SETTINGS, new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆ β–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆ", + " β–ˆ β–ˆβ–ˆ", + " β–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆ β–ˆ β–ˆ", + " β–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + symbols.put(Symbol.LARGE_BLUETOOTH_SETTINGS, new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆ β–ˆ β–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆ β–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆ β–ˆ β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ β–ˆ β–ˆβ–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + symbols.put(Symbol.LARGE_MENU_SETTINGS, new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + symbols.put(Symbol.LARGE_MY_DATA, new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ ", + "β–ˆ β–ˆ β–ˆ ", + "β–ˆ β–ˆβ–ˆβ–ˆ β–ˆ β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆβ–ˆβ–ˆ β–ˆ β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + symbols.put(Symbol.LARGE_ALARM_SETTINGS, new String[]{ + " β–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ β–ˆ β–ˆ ", + " β–ˆ β–ˆ β–ˆ ", + " β–ˆ β–ˆ β–ˆβ–ˆ ", + " β–ˆ β–ˆ β–ˆ ", + " β–ˆ β–ˆ β–ˆ ", + " β–ˆ β–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ", + " β–ˆ β–ˆ β–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆ β–ˆ", + " β–ˆ β–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + + }); + symbols.put(Symbol.LARGE_CHECK, new String[]{ + " β–ˆβ–ˆβ–ˆ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ " + + }); + symbols.put(Symbol.LARGE_ERROR, new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆ β–ˆ β–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ " + + }); + } + + private static LinkedList pattern = new LinkedList<>(); + static + { + for(Symbol s : Symbol.values()) + { + if(symbols.containsKey(s)) { + String[] patternString = symbols.get(s); + Pattern p = new SymbolPattern(s, patternString, 16); + pattern.add(p); + } + } + for(int i = 0; i < 10;i++) + { + String[] patternString = numbers[i]; + Pattern p = new NumberPattern(i,patternString,16); + pattern.add(p); + } + for(Character c : letters.keySet()) + { + String[] patternString = letters.get(c); + Pattern p = new CharacterPattern(c,patternString,16); + pattern.add(p); + } + } + + public static Token findToken(byte[][] display, int which, int x) { + for(Pattern p : pattern) + { + Token t = p.match(display, which, x); + if (t != null) + return t; + } + return null; + } +} \ No newline at end of file diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/NumberPattern.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/NumberPattern.java new file mode 100644 index 0000000000..b961454b18 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/NumberPattern.java @@ -0,0 +1,23 @@ +package org.monkey.d.ruffy.ruffy.driver.display.parser; + +/** + * Created by fishermen21 on 21.05.17. + */ + +public class NumberPattern extends Pattern { + private final int number; + + public NumberPattern(int number, String[] patternString, int blockSize) { + super(patternString,blockSize); + this.number = number; + } + + @Override + public String toString() { + return "Numbervalue("+number+")"; + } + + public int getNumber() { + return number; + } +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/Pattern.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/Pattern.java new file mode 100644 index 0000000000..adfbe4c394 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/Pattern.java @@ -0,0 +1,79 @@ +package org.monkey.d.ruffy.ruffy.driver.display.parser; + +import org.monkey.d.ruffy.ruffy.driver.display.Token; + +/** + * Created by fishermen21 on 21.05.17. + */ + +public abstract class Pattern { + private final byte[][] pattern; + private final int shiftable; + + public Pattern(String[] patternString, int blocksize) { + this.shiftable = blocksize - patternString.length; + + this.pattern = new byte[blocksize/8][patternString[0].length()]; + for(int row = 0; row < patternString.length;row+=8) + { + for(int c = 0; c < patternString[row].length();c++) + { + byte b = 0; + for(int br = 0; br < 8; br++) + { + if (row+br >= patternString.length) + break; + if (patternString[row+br].charAt(c) == 'β–ˆ') + b |= 1 << br; + } + pattern[row/8][c] = b; + } + } + } + + public Token match(byte[][] display, int which, int x) + { + int s = 0; + while(s<=shiftable) + { + boolean run = true; + for(int r = 0;run && r < pattern.length;r++) + { + if(which+r>3){ + run=false; + break; + } + + for(int c = 0;run && c < pattern[0].length; c++) + { + byte compare = ((byte)(pattern[r][c]<0) + { + short cs = pattern[r][c]; + cs = ((short)(cs << 8)); + cs |= pattern[r-1][c]&0xFF; + cs = ((short)(cs << s)); + compare = (byte) (cs >> 8); + } + if(x+c >= 96 || display[which+r][x+c] != compare) + run = false; + } + } + if(run) + { + for(int r = 0;run && r < pattern.length;r++) { + for (int c = 0; run && c < pattern[0].length; c++) { + display[which+r][x + c] = 0; + } + } + return new Token(this, which, x);//pattern found + } + s++; + } + return null; + } + + public int getWidth() { + return pattern[0].length; + } +} diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/SmallTextParser.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/SmallTextParser.java new file mode 100644 index 0000000000..51040557d3 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/SmallTextParser.java @@ -0,0 +1,1152 @@ +package org.monkey.d.ruffy.ruffy.driver.display.parser; + +import org.monkey.d.ruffy.ruffy.driver.display.Symbol; +import org.monkey.d.ruffy.ruffy.driver.display.Token; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +/** + * Created by fishermen21 on 20.05.17. + */ + +public class SmallTextParser { + + private static String[][] numbers = { + { + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆβ–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆβ–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ " + }, + { + " β–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆβ–ˆβ–ˆ " + }, + { + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + " β–ˆ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }, + { + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ " + }, + { + " β–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆ ", + " β–ˆ " + + }, + { + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆ", + " β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ " + }, + { + " β–ˆβ–ˆ ", + " β–ˆ ", + "β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ " + }, + { + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + }, + { + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ " + }, + { + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆ", + " β–ˆ ", + " β–ˆβ–ˆ " + } + }; + + private static Map letters = new HashMap(); + + static { + letters.put('A', new String[]{ + " β–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('a', new String[]{ + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆ" + }); + letters.put('Γ„', new String[]{ + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('Δƒ', new String[]{ + " β–ˆ β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('Á', new String[]{ + " β–ˆ ", + " β–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('Γ‘', new String[]{ + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('Γ£', new String[]{ + " β–ˆ β–ˆ", + "β–ˆ β–ˆβ–ˆ ", + " β–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ" + }); + + letters.put('Γ¦', new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆβ–ˆβ–ˆ" + }); + + letters.put('B', new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆ " + }); + letters.put('C', new String[]{ + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ ", + "β–ˆ ", + "β–ˆ ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ " + }); + letters.put('Δ‡', new String[]{ + " β–ˆ ", + " β–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ ", + "β–ˆ ", + "β–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ" + }); + letters.put('č', new String[]{ + " β–ˆ β–ˆ ", + " β–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ ", + "β–ˆ ", + "β–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ" + }); + letters.put('Γ‡', new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ ", + "β–ˆ ", + "β–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆ ", + " β–ˆβ–ˆ " + }); + + letters.put('D', new String[]{ + "β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆ " + }); + letters.put('E', new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ ", + "β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ ", + "β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + letters.put('Γ‰', new String[]{ + " β–ˆ ", + " β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + letters.put('Ê', new String[]{ + " β–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + letters.put('Δ™', new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆ ", + " β–ˆβ–ˆ " + }); + letters.put('F', new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ ", + "β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ ", + "β–ˆ ", + "β–ˆ " + }); + letters.put('G', new String[]{ + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ ", + "β–ˆ β–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆ" + }); + letters.put('H', new String[]{ + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('I', new String[]{ + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆβ–ˆβ–ˆ " + }); + letters.put('i', new String[]{ + " β–ˆ ", + " ", + "β–ˆβ–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + "β–ˆβ–ˆβ–ˆ" + }); + letters.put('Γ­', new String[]{ + " β–ˆ", + " β–ˆ ", + "β–ˆβ–ˆβ–ˆ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + "β–ˆβ–ˆβ–ˆ" + }); + letters.put('Δ°', new String[]{ + " β–ˆ ", + " ", + "β–ˆβ–ˆβ–ˆ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + "β–ˆβ–ˆβ–ˆ" + }); + + letters.put('J', new String[]{ + " β–ˆβ–ˆβ–ˆ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + "β–ˆ β–ˆ ", + " β–ˆβ–ˆ " + }); + letters.put('K', new String[]{ + "β–ˆ β–ˆ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆβ–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ" + }); + letters.put('L', new String[]{ + "β–ˆ ", + "β–ˆ ", + "β–ˆ ", + "β–ˆ ", + "β–ˆ ", + "β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + letters.put('Ε‚', new String[]{ + " β–ˆ ", + " β–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆβ–ˆ ", + "β–ˆβ–ˆ ", + " β–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ" + }); + letters.put('M', new String[]{ + "β–ˆ β–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('N', new String[]{ + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆβ–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('Γ‘', new String[]{ + " β–ˆ β–ˆ", + "β–ˆ β–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆβ–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('ň', new String[]{ + " β–ˆ β–ˆ ", + " β–ˆ ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆβ–ˆ", + "β–ˆ β–ˆ" + }); + + letters.put('O', new String[]{ + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ " + }); + letters.put('Γ–', new String[]{ + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ " + }); + letters.put('Γ³', new String[]{ + " β–ˆ ", + " β–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ " + }); + letters.put('ΓΈ', new String[]{ + " β–ˆ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ β–ˆ β–ˆ", + " β–ˆ β–ˆ β–ˆ", + " β–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ " + }); + letters.put('Ε‘', new String[]{ + " β–ˆ β–ˆ", + "β–ˆ β–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ " + }); + + letters.put('P', new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ ", + "β–ˆ ", + "β–ˆ " + }); + letters.put('Q', new String[]{ + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ ", + " β–ˆβ–ˆ β–ˆ" + }); + letters.put('R', new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ" + }); + letters.put('S', new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ ", + "β–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ", + " β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆ " + }); + letters.put('Ε›', new String[]{ + " β–ˆ ", + " β–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆ " + }); + letters.put('Ε‘', new String[]{ + " β–ˆ β–ˆ ", + " β–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆ " + }); + + letters.put('T', new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ " + }); + letters.put('U', new String[]{ + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ " + }); + letters.put('u', new String[]{ + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆβ–ˆ", + " β–ˆβ–ˆ β–ˆ" + }); + letters.put('Ü', new String[]{ + "β–ˆ β–ˆ", + " ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ " + }); + letters.put('ΓΊ', new String[]{ + " β–ˆ ", + " β–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ " + }); + letters.put('Ε―', new String[]{ + " β–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ " + }); + letters.put('V', new String[]{ + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆ β–ˆ ", + " β–ˆ " + }); + letters.put('W', new String[]{ + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + " β–ˆ β–ˆ " + }); + letters.put('X', new String[]{ + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆ β–ˆ ", + " β–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('Y', new String[]{ + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆ β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ " + }); + letters.put('Γ½', new String[]{ + " β–ˆ ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆ β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ " + }); + letters.put('Z', new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + "β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + letters.put('ΕΊ', new String[]{ + " β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆ", + " β–ˆβ–ˆ ", + " β–ˆ ", + "β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + letters.put('ΕΎ', new String[]{ + " β–ˆ β–ˆ ", + " β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + + /// russian letters (not in alphabetical order): + letters.put('Π±', new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ ", + "β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆ " + }); + letters.put('ъ', new String[]{ + "β–ˆβ–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆ β–ˆ", + " β–ˆ β–ˆ", + " β–ˆβ–ˆ " + }); + letters.put('ΠΌ', new String[]{ + "β–ˆ β–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('Π»', new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆ β–ˆ", + " β–ˆ β–ˆ", + " β–ˆ β–ˆ", + " β–ˆ β–ˆ", + " β–ˆ β–ˆ", + "β–ˆβ–ˆ β–ˆ" + }); + letters.put('ю', new String[]{ + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ " + }); + letters.put('Π°', new String[]{ + " β–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('ΠΏ', new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('я', new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆ β–ˆ", + " β–ˆ β–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('ΠΉ', new String[]{ + " β–ˆ β–ˆ ", + " β–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆβ–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆβ–ˆ β–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('Π΄', new String[]{ + " β–ˆβ–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('ΠΆ', new String[]{ + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ" + }); + letters.put('Ρ‹', new String[]{ + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆβ–ˆ β–ˆ" + }); + letters.put('Ρƒ', new String[]{ + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ ", + " β–ˆ ", + "β–ˆ " + }); + letters.put('Ρ‡', new String[]{ + " β–ˆ β–ˆ", + " β–ˆ β–ˆ", + " β–ˆ β–ˆ", + " β–ˆ β–ˆβ–ˆ", + " β–ˆβ–ˆ β–ˆ", + " β–ˆ", + " β–ˆ" + }); + letters.put('Π·', new String[]{ + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ β–ˆ", + " β–ˆ", + " β–ˆβ–ˆ ", + " β–ˆ", + " β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ " + }); + letters.put('Ρ†', new String[]{ + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆ" + }); + letters.put('ΠΈ', new String[]{ + "β–ˆ β–ˆ", + "β–ˆ β–ˆβ–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆβ–ˆ β–ˆ", + "β–ˆ β–ˆ" + }); + + /// GREEK LETTERS (out of order) + letters.put('Ξ£', new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + "β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + letters.put('Ξ”', new String[]{ + " β–ˆ ", + " β–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + letters.put('Ξ¦', new String[]{ + " β–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ " + }); + letters.put('Ξ›', new String[]{ + " β–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ" + }); + letters.put('Ξ©', new String[]{ + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆ β–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ" + }); + letters.put('Ο…', new String[]{ + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ " + }); + letters.put('Θ', new String[]{ + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆβ–ˆβ–ˆ " + }); + + + } + + + private static Map symbols = new HashMap(); + + static { + symbols.put(Symbol.CLOCK, new String[]{ + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ β–ˆ β–ˆ ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆβ–ˆ β–ˆ", + "β–ˆ β–ˆ", + " β–ˆ β–ˆ ", + " β–ˆβ–ˆβ–ˆ " + }); + symbols.put(Symbol.UNITS_PER_HOUR, new String[]{ + "β–ˆ β–ˆ β–ˆ β–ˆ ", + "β–ˆ β–ˆ β–ˆ β–ˆ ", + "β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ ", + "β–ˆ β–ˆ β–ˆ β–ˆβ–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ", + " β–ˆβ–ˆ β–ˆ β–ˆ β–ˆ" + }); + symbols.put(Symbol.LOCK_CLOSED, new String[]{ + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + symbols.put(Symbol.LOCK_OPENED, new String[]{ + " β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆβ–ˆ β–ˆβ–ˆ", + " β–ˆβ–ˆ β–ˆβ–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + symbols.put(Symbol.CHECK, new String[]{ + " β–ˆ", + " β–ˆβ–ˆ", + "β–ˆ β–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆ ", + " β–ˆ ", + " ", + " " + }); + symbols.put(Symbol.DIVIDE, new String[]{ + " ", + " β–ˆ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + "β–ˆ ", + " " + }); + symbols.put(Symbol.LOW_BAT, new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆ β–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ " + + }); + symbols.put(Symbol.LOW_INSULIN, new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ β–ˆ β–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ β–ˆ β–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆ", + "β–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆ", + "β–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆ", + "β–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ " + }); + symbols.put(Symbol.NO_INSULIN, new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ β–ˆ β–ˆ β–ˆ β–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ β–ˆ β–ˆ β–ˆβ–ˆβ–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆβ–ˆβ–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ " + }); + symbols.put(Symbol.CALENDAR, new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ β–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + symbols.put(Symbol.DOT, new String[]{ + " ", + " ", + " ", + " ", + " ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ " + }); + symbols.put(Symbol.SEPERATOR, new String[]{ + " ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " ", + " β–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " " + }); + symbols.put(Symbol.ARROW, new String[]{ + " β–ˆ ", + " β–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆ ", + " β–ˆ " + }); + symbols.put(Symbol.DOWN, new String[]{ + " β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ " + }); + symbols.put(Symbol.UP, new String[]{ + " β–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ " + + }); + symbols.put(Symbol.SUM, new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + "β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + }); + symbols.put(Symbol.BOLUS, new String[]{ + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ" + }); + symbols.put(Symbol.MULTIWAVE, new String[]{ + "β–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ" + }); + symbols.put(Symbol.EXTENDED_BOLUS, new String[]{ + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆ ", + "β–ˆ β–ˆβ–ˆ", + }); + symbols.put(Symbol.SPEAKER, new String[]{ + " β–ˆβ–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆβ–ˆ β–ˆ ", + "β–ˆβ–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆβ–ˆ " + }); + symbols.put(Symbol.ERROR, new String[]{ + " β–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆ β–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆ β–ˆ β–ˆβ–ˆ", + " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆβ–ˆβ–ˆ " + }); + symbols.put(Symbol.WARNING, new String[]{ + " β–ˆ ", + " β–ˆβ–ˆβ–ˆ ", + " β–ˆ β–ˆ ", + " β–ˆ β–ˆ β–ˆ ", + " β–ˆ β–ˆ ", + "β–ˆ β–ˆ β–ˆ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + }); + symbols.put(Symbol.BRACKET_LEFT, new String[]{ + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " " + }); + symbols.put(Symbol.BRACKET_RIGHT, new String[]{ + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + " " + }); + symbols.put(Symbol.PERCENT, new String[]{ + "β–ˆβ–ˆ ", + "β–ˆβ–ˆ β–ˆ", + " β–ˆ ", + " β–ˆ ", + " β–ˆ ", + "β–ˆ β–ˆβ–ˆ", + " β–ˆβ–ˆ" + }); + symbols.put(Symbol.BASAL, new String[]{ + " β–ˆβ–ˆβ–ˆβ–ˆ ", + " β–ˆ β–ˆβ–ˆβ–ˆ", + "β–ˆβ–ˆβ–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ β–ˆ" + }); + symbols.put(Symbol.MINUS, new String[]{ + " ", + " ", + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ", + " " + }); + symbols.put(Symbol.WARANTY, new String[]{ + " β–ˆβ–ˆβ–ˆ β–ˆ ", + " β–ˆβ–ˆ β–ˆ ", + " β–ˆ β–ˆ β–ˆ", + "β–ˆ β–ˆ", + "β–ˆ β–ˆ β–ˆ ", + " β–ˆ β–ˆβ–ˆ ", + " β–ˆ β–ˆβ–ˆβ–ˆ " + }); + } + + private static LinkedList pattern = new LinkedList<>(); + static + { + for(Symbol s : symbols.keySet()) + { + String[] patternString = symbols.get(s); + Pattern p = new SymbolPattern(s,patternString,8); + pattern.add(p); + } + for(int i = 0; i < 10;i++) + { + String[] patternString = numbers[i]; + Pattern p = new NumberPattern(i,patternString,8); + pattern.add(p); + } + for(Character c : letters.keySet()) + { + String[] patternString = letters.get(c); + Pattern p = new CharacterPattern(c,patternString,8); + pattern.add(p); + } + } + public static Token findToken(byte[][] display, int which, int x) { + for(Pattern p : pattern) + { + Token t = p.match(display,which,x); + if(t!=null) + return t; + } + return null; + } +} \ No newline at end of file diff --git a/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/SymbolPattern.java b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/SymbolPattern.java new file mode 100644 index 0000000000..5d0d688db8 --- /dev/null +++ b/ruffyscripter/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/parser/SymbolPattern.java @@ -0,0 +1,26 @@ +package org.monkey.d.ruffy.ruffy.driver.display.parser; + +import org.monkey.d.ruffy.ruffy.driver.display.Symbol; + +/** + * Created by fishermen21 on 21.05.17. + */ + +public class SymbolPattern extends Pattern { + + private final Symbol symbol; + public SymbolPattern(Symbol s, String[] patternString, int blocksize) { + super(patternString, blocksize); + this.symbol = s; + + } + + @Override + public String toString() { + return "Symbol("+symbol+")"; + } + + public Symbol getSymbol() { + return symbol; + } +}