IceCreamAgreement.java 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. package com.bgy.autosale.plc;
  2. import android.os.Handler;
  3. import android.os.Message;
  4. import android.util.Log;
  5. import com.bgy.autosale.App;
  6. import com.bgy.autosale.R;
  7. import com.bgy.autosale.entitys.DataWrap;
  8. import com.bgy.autosale.entitys.Result;
  9. import com.bgy.autosale.interfaces.Callback;
  10. import com.bgy.autosale.interfaces.SendCallback;
  11. /**
  12. * Created by cjx on 2019/9/2
  13. * 说明:雪糕机PLC通讯协议解析类
  14. */
  15. public class IceCreamAgreement extends BasePlcAgreement {
  16. private static volatile IceCreamAgreement util;
  17. final int PLC_HEADER = 170; // 头信息
  18. private final int PLC_ACTION_ORDER = 2; // 下单
  19. private final int PLC_ACTION_IMMEDIATE = 4;
  20. private final int PLC_ACTION_CONTROL = 32; //控制设备
  21. private final int PLC_ACTION_MODIFY = 33; //控制设备
  22. private final int DELAY_SEND_ORDER = 0; // 延迟发送订单
  23. private final int DELAY_CHECK_STATUS_MAKE = 1; // 检查是否超时设备未响应
  24. private boolean makeOrderByManual = false; // 手动下单状态标记
  25. private Callback<Result<Order>> orderCallback;
  26. private Callback<Integer> deviceMessageCallback;
  27. private Callback<int[]> immediateCallback;
  28. private SendCallback controlCallback; //控制设备
  29. private int controlKey = -1;
  30. private SendCallback modifyCallback; //修改参数
  31. private int modifyKey = -1;
  32. private int tryCount = 0;
  33. private Order outOrder;
  34. private Handler delayHandler;
  35. private boolean testMode = false;
  36. private Handler disconnectHandler = new Handler(new Handler.Callback() {
  37. @Override
  38. public boolean handleMessage(Message msg) {
  39. switch (msg.what) {
  40. case 0:
  41. disConnect(new Exception(App.app.getString(R.string.plc_disconnect_initiative)));
  42. disconnectHandler.sendEmptyMessageDelayed(1, 5000);
  43. break;
  44. case 1:
  45. updateOrderErrorMessage(App.app.getString(R.string.plc_disconnect));
  46. if (statusCallback != null) {
  47. statusCallback.onResult(getStatusResult(PLC_HEART_DISCONNECT, deviceStatus, null));
  48. }
  49. break;
  50. }
  51. return false;
  52. }
  53. });
  54. public static IceCreamAgreement getInstance() {
  55. if (util == null) {
  56. synchronized (IceCreamAgreement.class) {
  57. if (util == null) {
  58. util = new IceCreamAgreement();
  59. }
  60. }
  61. }
  62. return util;
  63. }
  64. IceCreamAgreement() {
  65. super();
  66. TAG = App.app.getString(R.string.app_name) + " >> ";
  67. delayHandler = new Handler(new Handler.Callback() {
  68. @Override
  69. public boolean handleMessage(Message msg) {
  70. if (deviceStatus == null) {
  71. return false;
  72. }
  73. switch (msg.what) {
  74. case DELAY_SEND_ORDER:
  75. // 控制模式
  76. int control = deviceStatus[0];
  77. // 工作状态
  78. int work = deviceStatus[1];
  79. // 设备状态
  80. int device = deviceStatus[2];
  81. if (work == PLC_WORK_FREE && control == PLC_CONTROL_AUTO && device == PLC_DEVICE_NORMAL) {
  82. if (getPrevDataWrap(PLC_ACTION_ORDER) == null) {
  83. outOrder = (Order) msg.obj;
  84. sendOrderData();
  85. } else {
  86. log.e_s(TAG, App.app.getString(R.string.plc_has_other_order));
  87. }
  88. } else {
  89. tryCount++;
  90. if (tryCount > 10) {
  91. return false;
  92. }
  93. log.e_s(TAG, App.app.getString(R.string.plc_send_order_again));
  94. Message newMsg = Message.obtain();
  95. newMsg.what = DELAY_SEND_ORDER;
  96. newMsg.obj = msg.obj;
  97. delayHandler.sendMessageDelayed(newMsg, 2000);
  98. }
  99. break;
  100. case DELAY_CHECK_STATUS_MAKE:
  101. updateOrderErrorMessage(App.app.getString(R.string.plc_make_error_not_status));
  102. break;
  103. }
  104. return false;
  105. }
  106. });
  107. }
  108. @Override
  109. protected int getStatusLength() {
  110. return 13;
  111. }
  112. @Override
  113. public void onConnectedStatusChange(boolean connected, Exception e, String msg) {
  114. log.ui(TAG, String.format(App.app.getString(R.string.plc_connect_status), String.valueOf(connected), msg));
  115. updateConnectStatus();
  116. if (statusCallback != null) {
  117. if (connected) {
  118. statusCallback.onResult(getStatusResult(PLC_HEART_CONNECT, deviceStatus, msg));
  119. }
  120. }
  121. }
  122. @Override
  123. protected boolean isTheSame(int size, int[] content) {
  124. boolean theSame = true;
  125. // 先对比第13个位的值(复位结果)是否一致
  126. if (size > 12) {
  127. if (content[12] != deviceStatus[12]) {
  128. return false;
  129. }
  130. }
  131. if (size > 7) {
  132. if (content[7] != deviceStatus[7]) {
  133. return false;
  134. }
  135. }
  136. // 只对比前7个状态
  137. int maxSize = Math.min(size, 7);
  138. for (int i = 0; i < maxSize; i++) {
  139. if (content[i] != deviceStatus[i]) {
  140. theSame = false;
  141. break;
  142. }
  143. }
  144. return theSame;
  145. }
  146. @Override
  147. protected void sendDataFail(int tag) {
  148. switch (tag) {
  149. case PLC_ACTION_ORDER:
  150. updateOrderErrorMessage(App.app.getString(R.string.plc_order_no_response));
  151. break;
  152. case PLC_ACTION_MODIFY:
  153. if (modifyCallback != null) {
  154. modifyCallback.callBack(false, null);
  155. }
  156. break;
  157. case PLC_ACTION_CONTROL:
  158. if (controlCallback != null) {
  159. controlCallback.callBack(false, null);
  160. }
  161. break;
  162. }
  163. }
  164. @Override
  165. protected byte[] checkAction(int action, int random, int[] content) {
  166. updateConnectStatus();
  167. final int PLC_ACTION_HEART = 0;
  168. final int PLC_ACTION_REPORT = 1; // 状态上报回调
  169. final int PLC_ACTION_STATUS = 3;
  170. byte[] response = null;
  171. Log.d(TAG, "checkAction: "+action);
  172. // 检查命令
  173. switch (action) {
  174. case PLC_ACTION_HEART:
  175. response = parserHeart(content, PLC_ACTION_REPORT, random);
  176. break;
  177. case PLC_ACTION_ORDER:
  178. // 出餐下单结果
  179. parserOrder(content);
  180. break;
  181. case PLC_ACTION_STATUS:
  182. // 设备状态上报
  183. response = parserStatus(content, PLC_ACTION_REPORT, random);
  184. break;
  185. case PLC_ACTION_IMMEDIATE:
  186. Log.d(TAG, "checkAction: PLC_ACTION_IMMEDIATE");
  187. response = parserImmediate(content, random);
  188. break;
  189. case PLC_ACTION_CONTROL://解析控制指令
  190. parserControl(content);
  191. break;
  192. case PLC_ACTION_MODIFY://解析修改参数
  193. parserModify(content);
  194. break;
  195. }
  196. return response;
  197. }
  198. @Override
  199. protected int getHeaderCode() {
  200. return PLC_HEADER;
  201. }
  202. @Override
  203. protected void dealStatus(int[] content) {
  204. // 控制模式
  205. int control = content[0];
  206. // 工作状态
  207. int work = content[1];
  208. // 设备状态
  209. int device = content[2];
  210. // 取菜口1 状态
  211. int door = content[3];
  212. if (content.length > 7) {
  213. int deviceMessage = content[7];
  214. if (deviceMessageCallback != null) {
  215. deviceMessageCallback.onResult(deviceMessage);
  216. }
  217. }
  218. // 设备不正常了
  219. // 手动出餐时, 不需要判断设备状态
  220. if (!makeOrderByManual && !testMode) {
  221. if (control != PLC_CONTROL_AUTO || device != PLC_DEVICE_NORMAL) {
  222. if (outOrder != null) {
  223. if (outOrder.status == RESULT_CODE_ORDER_CHILD_OUT) {
  224. if (PLC_DOOR_EMPTY == door) {
  225. updateOrderStatus(RESULT_CODE_ORDER_CHILD_FINISH, String.format(App.app.getString(R.string.plc_order_taked), outOrder));
  226. outOrder = null;
  227. updateOrderErrorMessage(App.app.getString(R.string.plc_order_error2));
  228. }
  229. } else if (outOrder.status == RESULT_CODE_ORDER_CHILD_PREPARE) {
  230. updateOrderErrorMessage(App.app.getString(R.string.plc_order_error2));
  231. } else {
  232. outOrder = null;
  233. }
  234. }
  235. delayHandler.removeMessages(DELAY_CHECK_STATUS_MAKE);
  236. return;
  237. }
  238. }
  239. // 如果有待取餐的菜品并且当前取餐口已经空闲,表示餐已被取
  240. if (outOrder != null) {
  241. switch (outOrder.status) {
  242. case RESULT_CODE_ORDER_CHILD_INIT:
  243. if (PLC_WORK_FREE != work) {
  244. outOrder.status = RESULT_CODE_ORDER_CHILD_PREPARE;
  245. updateOrderStatus(RESULT_CODE_ORDER_CHILD_PREPARE, String.format(App.app.getString(R.string.plc_order_making), outOrder));
  246. delayHandler.removeMessages(DELAY_CHECK_STATUS_MAKE);
  247. }
  248. break;
  249. case RESULT_CODE_ORDER_CHILD_PREPARE:
  250. if (PLC_DOOR_EMPTY != door) {
  251. outOrder.status = RESULT_CODE_ORDER_CHILD_OUT;
  252. updateOrderStatus(RESULT_CODE_ORDER_CHILD_OUT, String.format(App.app.getString(R.string.plc_order_prepare), outOrder));
  253. }
  254. break;
  255. case RESULT_CODE_ORDER_CHILD_OUT:
  256. if (PLC_DOOR_EMPTY == door) {
  257. outOrder.status = RESULT_CODE_ORDER_CHILD_FINISH;
  258. updateOrderStatus(RESULT_CODE_ORDER_CHILD_FINISH, String.format(App.app.getString(R.string.plc_order_taked), outOrder));
  259. outOrder = null;
  260. if (PLC_WORK_FREE == work) {
  261. updateOrderStatus(RESULT_CODE_ORDER_COMPLETE, App.app.getString(R.string.plc_prepare));
  262. }
  263. }
  264. break;
  265. }
  266. } else if (PLC_WORK_FREE == work) {
  267. updateOrderStatus(RESULT_CODE_ORDER_COMPLETE, App.app.getString(R.string.plc_prepare));
  268. }
  269. }
  270. @Override
  271. protected void clearOrderFormPlc(int type) {
  272. }
  273. public void setOrderCallback(Callback<Result<Order>> orderCallback) {
  274. this.orderCallback = orderCallback;
  275. }
  276. public void setDeviceMessageCallback(Callback<Integer> callback) {
  277. this.deviceMessageCallback = callback;
  278. }
  279. public void setImmediateCallbak(Callback<int[]> callback) {
  280. this.immediateCallback = callback;
  281. }
  282. public void sendOrder(Order order) {
  283. if (order == null) {
  284. updateOrderErrorMessage(App.app.getString(R.string.plc_not_order));
  285. return;
  286. }
  287. makeOrderByManual = false;
  288. tryCount = 0;
  289. Message msg = Message.obtain();
  290. msg.what = DELAY_SEND_ORDER;
  291. msg.obj = order;
  292. delayHandler.sendMessageDelayed(msg, 300);
  293. }
  294. // 控制设备
  295. public void sendControl(int order, SendCallback sendCallback) {
  296. sendControl(order, 0, 0, 0, sendCallback);
  297. }
  298. public void sendControl(int order, int param1, int param2, int param3, SendCallback sendCallback) {
  299. if (getPrevDataWrap(PLC_ACTION_CONTROL) != null) {
  300. if (sendCallback != null) {
  301. sendCallback.callBack(false, null);
  302. }
  303. return;
  304. }
  305. this.controlKey = order;
  306. this.controlCallback = sendCallback;
  307. final int random = getRandom(); // 随机数
  308. int length = 8;
  309. final byte[] data = generateData(PLC_HEADER, PLC_ACTION_CONTROL, random, length, order, param1, param2, param3);
  310. sendData(new DataWrap(random, data), PLC_ACTION_CONTROL);
  311. }
  312. // 设置当前手动出单的状态
  313. public void setMakeOrderByManual(Order order) {
  314. outOrder = order;
  315. if (outOrder != null) {
  316. outOrder.status = RESULT_CODE_ORDER_CHILD_INIT;
  317. }
  318. this.makeOrderByManual = order != null;
  319. }
  320. // 修改参数
  321. public void modifyParams(int order, int param, SendCallback sendCallback) {
  322. if (getPrevDataWrap(PLC_ACTION_MODIFY) != null) {
  323. sendCallback.callBack(false, null);
  324. return;
  325. }
  326. this.modifyKey = order;
  327. this.modifyCallback = sendCallback;
  328. final int random = getRandom(); // 随机数
  329. int length = 4;
  330. final byte[] data = generateData(PLC_HEADER, PLC_ACTION_MODIFY, random, length, order, param);
  331. sendData(new DataWrap(random, data), PLC_ACTION_MODIFY);
  332. }
  333. // 解析即时状态上报
  334. private byte[] parserImmediate(int[] content, int random) {
  335. if (immediateCallback != null) {
  336. Log.d(TAG, "parserImmediate1: ");
  337. immediateCallback.onResult(content);
  338. }
  339. Log.d(TAG, "parserImmediate2: ");
  340. return generateData(getHeaderCode(), PLC_ACTION_IMMEDIATE, random, 0);
  341. }
  342. // 解析订单
  343. private void parserOrder(int[] content) {
  344. delayHandler.removeMessages(DELAY_SEND_ORDER);
  345. if (outOrder == null) {
  346. log.e_s(TAG, App.app.getString(R.string.plc_order_empty));
  347. return;
  348. }
  349. if (content == null || content.length < 1) {
  350. updateOrderErrorMessage(App.app.getString(R.string.plc_order_result_empty));
  351. return;
  352. }
  353. // 下单结果
  354. int result = content[0];
  355. if (result == 1) {
  356. outOrder.status = RESULT_CODE_ORDER_CHILD_INIT;
  357. log.e_s(TAG, String.format(App.app.getString(R.string.plc_order_start), outOrder));
  358. delayHandler.sendEmptyMessageDelayed(DELAY_CHECK_STATUS_MAKE, 8000);
  359. } else if (result == 3) { // 忙碌状态
  360. log.e_s(TAG, String.format(App.app.getString(R.string.plc_order_busy), outOrder));
  361. } else {
  362. updateOrderErrorMessage(App.app.getString(R.string.plc_order_error));
  363. outOrder = null;
  364. }
  365. }
  366. // 解析控制指令
  367. private void parserControl(int[] content) {
  368. if (content != null && content.length > 0) {
  369. if (controlCallback != null) {
  370. if (content[0] == controlKey) {
  371. controlCallback.callBack(true, content);
  372. } else {
  373. controlCallback.callBack(false, content);
  374. }
  375. }
  376. } else {
  377. if (controlCallback != null) {
  378. controlCallback.callBack(false, null);
  379. }
  380. }
  381. controlCallback = null;
  382. }
  383. // 解析修改参数
  384. private void parserModify(int[] content) {
  385. if (content != null && content.length > 0) {
  386. if (modifyCallback != null) {
  387. if (content[0] == modifyKey) {
  388. modifyCallback.callBack(true, content);
  389. } else {
  390. modifyCallback.callBack(false, content);
  391. }
  392. }
  393. } else {
  394. if (modifyCallback != null) {
  395. modifyCallback.callBack(false, null);
  396. }
  397. }
  398. modifyCallback = null;
  399. }
  400. // 发送下单命令
  401. private void sendOrderData() {
  402. Order order = outOrder;
  403. log.e_s(TAG, String.format(App.app.getString(R.string.plc_order_receive), order));
  404. int random = getRandom();
  405. int length = 6;
  406. byte[] data = generateData(PLC_HEADER, PLC_ACTION_ORDER, random, length, order.flavor, order.sauce, order.kernel);
  407. sendData(new DataWrap(random, data), PLC_ACTION_ORDER);
  408. }
  409. // 设备是否正常
  410. public boolean isNormal() {
  411. synchronized (IceCreamAgreement.class) {
  412. return deviceStatus != null && deviceStatus[0] == PLC_CONTROL_AUTO && deviceStatus[2] == PLC_DEVICE_NORMAL;
  413. }
  414. }
  415. public boolean isAuto() {
  416. return deviceStatus != null && deviceStatus[0] == PLC_CONTROL_AUTO;
  417. }
  418. public boolean isDeviceNoErr() {
  419. return deviceStatus != null && deviceStatus[2] == PLC_DEVICE_NORMAL;
  420. }
  421. public boolean isDeviceDoorNoWarn() {
  422. return deviceStatus != null && deviceStatus[3] == PLC_DOOR_EMPTY;
  423. }
  424. public boolean isDeviceFree() {
  425. return deviceStatus != null && deviceStatus[1] == PLC_WORK_FREE;
  426. }
  427. // 设备是否空闲
  428. public boolean isFree() {
  429. synchronized (IceCreamAgreement.class) {
  430. return deviceStatus != null && deviceStatus[1] == PLC_WORK_FREE && deviceStatus[3] == PLC_DOOR_EMPTY;
  431. }
  432. }
  433. public String getStatusString() {
  434. if (deviceStatus == null) {
  435. return null;
  436. }
  437. StringBuilder stringBuilder = new StringBuilder(4);
  438. stringBuilder.append(deviceStatus[0])
  439. .append(deviceStatus[2])
  440. .append(deviceStatus[1])
  441. .append(deviceStatus[3]);
  442. return stringBuilder.toString();
  443. }
  444. private void updateOrderErrorMessage(String msg) {
  445. if (outOrder != null && outOrder.status != RESULT_CODE_ORDER_CHILD_PREPARE) {
  446. outOrder = null;
  447. }
  448. updateOrderStatus(RESULT_CODE_ORDER_ERROR, msg);
  449. outOrder = null;
  450. }
  451. private void updateOrderStatus(int code, String msg) {
  452. log.e_s(TAG, msg);
  453. if (orderCallback != null) {
  454. orderCallback.onResult(new Result<>(code, outOrder, msg));
  455. }
  456. }
  457. private void updateConnectStatus() {
  458. if (statusCallback != null) {
  459. statusCallback.onResult(getStatusResult(PLC_HEART_CONNECT, deviceStatus, null));
  460. }
  461. disconnectHandler.removeMessages(0);
  462. disconnectHandler.removeMessages(1);
  463. disconnectHandler.sendEmptyMessageDelayed(0, 120000);
  464. }
  465. public void setTestMode() {
  466. testMode = true;
  467. }
  468. public static class Order {
  469. public Object tag; // 标记
  470. int flavor; // 口味 1:原味
  471. int sauce; // 酱料 0:无口味,1:菠萝,2:草莓酱,3:蓝莓,
  472. int kernel; // 果仁 0:无口味,1:花生碎,2:榛子碎,3:腰果碎
  473. int status; // 出餐状态
  474. public Order(Object tag, int flavor, int sauce, int kernel) {
  475. this.tag = tag;
  476. this.flavor = flavor;
  477. this.sauce = sauce;
  478. this.kernel = kernel;
  479. this.status = -1;
  480. }
  481. @Override
  482. public String toString() {
  483. return "{" +
  484. "flavor:" + flavor +
  485. ", sauce:" + sauce +
  486. ", kernel:" + kernel +
  487. ", status:" + status +
  488. '}';
  489. }
  490. }
  491. }