package com.bgy.autosale.plc; import android.os.Handler; import android.os.Message; import android.util.Log; import com.bgy.autosale.App; import com.bgy.autosale.R; import com.bgy.autosale.entitys.DataWrap; import com.bgy.autosale.entitys.Result; import com.bgy.autosale.interfaces.Callback; import com.bgy.autosale.interfaces.SendCallback; /** * Created by cjx on 2019/9/2 * 说明:雪糕机PLC通讯协议解析类 */ public class IceCreamAgreement extends BasePlcAgreement { private static volatile IceCreamAgreement util; final int PLC_HEADER = 170; // 头信息 private final int PLC_ACTION_ORDER = 2; // 下单 private final int PLC_ACTION_IMMEDIATE = 4; private final int PLC_ACTION_CONTROL = 32; //控制设备 private final int PLC_ACTION_MODIFY = 33; //控制设备 private final int DELAY_SEND_ORDER = 0; // 延迟发送订单 private final int DELAY_CHECK_STATUS_MAKE = 1; // 检查是否超时设备未响应 private boolean makeOrderByManual = false; // 手动下单状态标记 private Callback> orderCallback; private Callback deviceMessageCallback; private Callback immediateCallback; private SendCallback controlCallback; //控制设备 private int controlKey = -1; private SendCallback modifyCallback; //修改参数 private int modifyKey = -1; private int tryCount = 0; private Order outOrder; private Handler delayHandler; private boolean testMode = false; private Handler disconnectHandler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { switch (msg.what) { case 0: disConnect(new Exception(App.app.getString(R.string.plc_disconnect_initiative))); disconnectHandler.sendEmptyMessageDelayed(1, 5000); break; case 1: updateOrderErrorMessage(App.app.getString(R.string.plc_disconnect)); if (statusCallback != null) { statusCallback.onResult(getStatusResult(PLC_HEART_DISCONNECT, deviceStatus, null)); } break; } return false; } }); public static IceCreamAgreement getInstance() { if (util == null) { synchronized (IceCreamAgreement.class) { if (util == null) { util = new IceCreamAgreement(); } } } return util; } IceCreamAgreement() { super(); TAG = App.app.getString(R.string.app_name) + " >> "; delayHandler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { if (deviceStatus == null) { return false; } switch (msg.what) { case DELAY_SEND_ORDER: // 控制模式 int control = deviceStatus[0]; // 工作状态 int work = deviceStatus[1]; // 设备状态 int device = deviceStatus[2]; if (work == PLC_WORK_FREE && control == PLC_CONTROL_AUTO && device == PLC_DEVICE_NORMAL) { if (getPrevDataWrap(PLC_ACTION_ORDER) == null) { outOrder = (Order) msg.obj; sendOrderData(); } else { log.e_s(TAG, App.app.getString(R.string.plc_has_other_order)); } } else { tryCount++; if (tryCount > 10) { return false; } log.e_s(TAG, App.app.getString(R.string.plc_send_order_again)); Message newMsg = Message.obtain(); newMsg.what = DELAY_SEND_ORDER; newMsg.obj = msg.obj; delayHandler.sendMessageDelayed(newMsg, 2000); } break; case DELAY_CHECK_STATUS_MAKE: updateOrderErrorMessage(App.app.getString(R.string.plc_make_error_not_status)); break; } return false; } }); } @Override protected int getStatusLength() { return 13; } @Override public void onConnectedStatusChange(boolean connected, Exception e, String msg) { log.ui(TAG, String.format(App.app.getString(R.string.plc_connect_status), String.valueOf(connected), msg)); updateConnectStatus(); if (statusCallback != null) { if (connected) { statusCallback.onResult(getStatusResult(PLC_HEART_CONNECT, deviceStatus, msg)); } } } @Override protected boolean isTheSame(int size, int[] content) { boolean theSame = true; // 先对比第13个位的值(复位结果)是否一致 if (size > 12) { if (content[12] != deviceStatus[12]) { return false; } } if (size > 7) { if (content[7] != deviceStatus[7]) { return false; } } // 只对比前7个状态 int maxSize = Math.min(size, 7); for (int i = 0; i < maxSize; i++) { if (content[i] != deviceStatus[i]) { theSame = false; break; } } return theSame; } @Override protected void sendDataFail(int tag) { switch (tag) { case PLC_ACTION_ORDER: updateOrderErrorMessage(App.app.getString(R.string.plc_order_no_response)); break; case PLC_ACTION_MODIFY: if (modifyCallback != null) { modifyCallback.callBack(false, null); } break; case PLC_ACTION_CONTROL: if (controlCallback != null) { controlCallback.callBack(false, null); } break; } } @Override protected byte[] checkAction(int action, int random, int[] content) { updateConnectStatus(); final int PLC_ACTION_HEART = 0; final int PLC_ACTION_REPORT = 1; // 状态上报回调 final int PLC_ACTION_STATUS = 3; byte[] response = null; Log.d(TAG, "checkAction: "+action); // 检查命令 switch (action) { case PLC_ACTION_HEART: response = parserHeart(content, PLC_ACTION_REPORT, random); break; case PLC_ACTION_ORDER: // 出餐下单结果 parserOrder(content); break; case PLC_ACTION_STATUS: // 设备状态上报 response = parserStatus(content, PLC_ACTION_REPORT, random); break; case PLC_ACTION_IMMEDIATE: Log.d(TAG, "checkAction: PLC_ACTION_IMMEDIATE"); response = parserImmediate(content, random); break; case PLC_ACTION_CONTROL://解析控制指令 parserControl(content); break; case PLC_ACTION_MODIFY://解析修改参数 parserModify(content); break; } return response; } @Override protected int getHeaderCode() { return PLC_HEADER; } @Override protected void dealStatus(int[] content) { // 控制模式 int control = content[0]; // 工作状态 int work = content[1]; // 设备状态 int device = content[2]; // 取菜口1 状态 int door = content[3]; if (content.length > 7) { int deviceMessage = content[7]; if (deviceMessageCallback != null) { deviceMessageCallback.onResult(deviceMessage); } } // 设备不正常了 // 手动出餐时, 不需要判断设备状态 if (!makeOrderByManual && !testMode) { if (control != PLC_CONTROL_AUTO || device != PLC_DEVICE_NORMAL) { if (outOrder != null) { if (outOrder.status == RESULT_CODE_ORDER_CHILD_OUT) { if (PLC_DOOR_EMPTY == door) { updateOrderStatus(RESULT_CODE_ORDER_CHILD_FINISH, String.format(App.app.getString(R.string.plc_order_taked), outOrder)); outOrder = null; updateOrderErrorMessage(App.app.getString(R.string.plc_order_error2)); } } else if (outOrder.status == RESULT_CODE_ORDER_CHILD_PREPARE) { updateOrderErrorMessage(App.app.getString(R.string.plc_order_error2)); } else { outOrder = null; } } delayHandler.removeMessages(DELAY_CHECK_STATUS_MAKE); return; } } // 如果有待取餐的菜品并且当前取餐口已经空闲,表示餐已被取 if (outOrder != null) { switch (outOrder.status) { case RESULT_CODE_ORDER_CHILD_INIT: if (PLC_WORK_FREE != work) { outOrder.status = RESULT_CODE_ORDER_CHILD_PREPARE; updateOrderStatus(RESULT_CODE_ORDER_CHILD_PREPARE, String.format(App.app.getString(R.string.plc_order_making), outOrder)); delayHandler.removeMessages(DELAY_CHECK_STATUS_MAKE); } break; case RESULT_CODE_ORDER_CHILD_PREPARE: if (PLC_DOOR_EMPTY != door) { outOrder.status = RESULT_CODE_ORDER_CHILD_OUT; updateOrderStatus(RESULT_CODE_ORDER_CHILD_OUT, String.format(App.app.getString(R.string.plc_order_prepare), outOrder)); } break; case RESULT_CODE_ORDER_CHILD_OUT: if (PLC_DOOR_EMPTY == door) { outOrder.status = RESULT_CODE_ORDER_CHILD_FINISH; updateOrderStatus(RESULT_CODE_ORDER_CHILD_FINISH, String.format(App.app.getString(R.string.plc_order_taked), outOrder)); outOrder = null; if (PLC_WORK_FREE == work) { updateOrderStatus(RESULT_CODE_ORDER_COMPLETE, App.app.getString(R.string.plc_prepare)); } } break; } } else if (PLC_WORK_FREE == work) { updateOrderStatus(RESULT_CODE_ORDER_COMPLETE, App.app.getString(R.string.plc_prepare)); } } @Override protected void clearOrderFormPlc(int type) { } public void setOrderCallback(Callback> orderCallback) { this.orderCallback = orderCallback; } public void setDeviceMessageCallback(Callback callback) { this.deviceMessageCallback = callback; } public void setImmediateCallbak(Callback callback) { this.immediateCallback = callback; } public void sendOrder(Order order) { if (order == null) { updateOrderErrorMessage(App.app.getString(R.string.plc_not_order)); return; } makeOrderByManual = false; tryCount = 0; Message msg = Message.obtain(); msg.what = DELAY_SEND_ORDER; msg.obj = order; delayHandler.sendMessageDelayed(msg, 300); } // 控制设备 public void sendControl(int order, SendCallback sendCallback) { sendControl(order, 0, 0, 0, sendCallback); } public void sendControl(int order, int param1, int param2, int param3, SendCallback sendCallback) { if (getPrevDataWrap(PLC_ACTION_CONTROL) != null) { if (sendCallback != null) { sendCallback.callBack(false, null); } return; } this.controlKey = order; this.controlCallback = sendCallback; final int random = getRandom(); // 随机数 int length = 8; final byte[] data = generateData(PLC_HEADER, PLC_ACTION_CONTROL, random, length, order, param1, param2, param3); sendData(new DataWrap(random, data), PLC_ACTION_CONTROL); } // 设置当前手动出单的状态 public void setMakeOrderByManual(Order order) { outOrder = order; if (outOrder != null) { outOrder.status = RESULT_CODE_ORDER_CHILD_INIT; } this.makeOrderByManual = order != null; } // 修改参数 public void modifyParams(int order, int param, SendCallback sendCallback) { if (getPrevDataWrap(PLC_ACTION_MODIFY) != null) { sendCallback.callBack(false, null); return; } this.modifyKey = order; this.modifyCallback = sendCallback; final int random = getRandom(); // 随机数 int length = 4; final byte[] data = generateData(PLC_HEADER, PLC_ACTION_MODIFY, random, length, order, param); sendData(new DataWrap(random, data), PLC_ACTION_MODIFY); } // 解析即时状态上报 private byte[] parserImmediate(int[] content, int random) { if (immediateCallback != null) { Log.d(TAG, "parserImmediate1: "); immediateCallback.onResult(content); } Log.d(TAG, "parserImmediate2: "); return generateData(getHeaderCode(), PLC_ACTION_IMMEDIATE, random, 0); } // 解析订单 private void parserOrder(int[] content) { delayHandler.removeMessages(DELAY_SEND_ORDER); if (outOrder == null) { log.e_s(TAG, App.app.getString(R.string.plc_order_empty)); return; } if (content == null || content.length < 1) { updateOrderErrorMessage(App.app.getString(R.string.plc_order_result_empty)); return; } // 下单结果 int result = content[0]; if (result == 1) { outOrder.status = RESULT_CODE_ORDER_CHILD_INIT; log.e_s(TAG, String.format(App.app.getString(R.string.plc_order_start), outOrder)); delayHandler.sendEmptyMessageDelayed(DELAY_CHECK_STATUS_MAKE, 8000); } else if (result == 3) { // 忙碌状态 log.e_s(TAG, String.format(App.app.getString(R.string.plc_order_busy), outOrder)); } else { updateOrderErrorMessage(App.app.getString(R.string.plc_order_error)); outOrder = null; } } // 解析控制指令 private void parserControl(int[] content) { if (content != null && content.length > 0) { if (controlCallback != null) { if (content[0] == controlKey) { controlCallback.callBack(true, content); } else { controlCallback.callBack(false, content); } } } else { if (controlCallback != null) { controlCallback.callBack(false, null); } } controlCallback = null; } // 解析修改参数 private void parserModify(int[] content) { if (content != null && content.length > 0) { if (modifyCallback != null) { if (content[0] == modifyKey) { modifyCallback.callBack(true, content); } else { modifyCallback.callBack(false, content); } } } else { if (modifyCallback != null) { modifyCallback.callBack(false, null); } } modifyCallback = null; } // 发送下单命令 private void sendOrderData() { Order order = outOrder; log.e_s(TAG, String.format(App.app.getString(R.string.plc_order_receive), order)); int random = getRandom(); int length = 6; byte[] data = generateData(PLC_HEADER, PLC_ACTION_ORDER, random, length, order.flavor, order.sauce, order.kernel); sendData(new DataWrap(random, data), PLC_ACTION_ORDER); } // 设备是否正常 public boolean isNormal() { synchronized (IceCreamAgreement.class) { return deviceStatus != null && deviceStatus[0] == PLC_CONTROL_AUTO && deviceStatus[2] == PLC_DEVICE_NORMAL; } } public boolean isAuto() { return deviceStatus != null && deviceStatus[0] == PLC_CONTROL_AUTO; } public boolean isDeviceNoErr() { return deviceStatus != null && deviceStatus[2] == PLC_DEVICE_NORMAL; } public boolean isDeviceDoorNoWarn() { return deviceStatus != null && deviceStatus[3] == PLC_DOOR_EMPTY; } public boolean isDeviceFree() { return deviceStatus != null && deviceStatus[1] == PLC_WORK_FREE; } // 设备是否空闲 public boolean isFree() { synchronized (IceCreamAgreement.class) { return deviceStatus != null && deviceStatus[1] == PLC_WORK_FREE && deviceStatus[3] == PLC_DOOR_EMPTY; } } public String getStatusString() { if (deviceStatus == null) { return null; } StringBuilder stringBuilder = new StringBuilder(4); stringBuilder.append(deviceStatus[0]) .append(deviceStatus[2]) .append(deviceStatus[1]) .append(deviceStatus[3]); return stringBuilder.toString(); } private void updateOrderErrorMessage(String msg) { if (outOrder != null && outOrder.status != RESULT_CODE_ORDER_CHILD_PREPARE) { outOrder = null; } updateOrderStatus(RESULT_CODE_ORDER_ERROR, msg); outOrder = null; } private void updateOrderStatus(int code, String msg) { log.e_s(TAG, msg); if (orderCallback != null) { orderCallback.onResult(new Result<>(code, outOrder, msg)); } } private void updateConnectStatus() { if (statusCallback != null) { statusCallback.onResult(getStatusResult(PLC_HEART_CONNECT, deviceStatus, null)); } disconnectHandler.removeMessages(0); disconnectHandler.removeMessages(1); disconnectHandler.sendEmptyMessageDelayed(0, 120000); } public void setTestMode() { testMode = true; } public static class Order { public Object tag; // 标记 int flavor; // 口味 1:原味 int sauce; // 酱料 0:无口味,1:菠萝,2:草莓酱,3:蓝莓, int kernel; // 果仁 0:无口味,1:花生碎,2:榛子碎,3:腰果碎 int status; // 出餐状态 public Order(Object tag, int flavor, int sauce, int kernel) { this.tag = tag; this.flavor = flavor; this.sauce = sauce; this.kernel = kernel; this.status = -1; } @Override public String toString() { return "{" + "flavor:" + flavor + ", sauce:" + sauce + ", kernel:" + kernel + ", status:" + status + '}'; } } }