距离这个开发这个项目已经过去差不多两年时间了,今天我闲来无事清理电脑里项目的时候无意看到了这个项目。已经都过去将近两年时间了,时光荏苒啊!两年前的自己也是一个冲动的年轻人,拼了命的做项目,现在想想自己,年轻人还是真年轻呀。算了,废话不多说,今天在这里总结一下调用派样机的开发流程。

需求梳理

当时公司让实现一个什么样的功能呐?就是在派样机(类似于饮料自动购物机那种机器)上的电脑上,开发一款Unity程序,这款程序上有一个二维码,用户用微信扫一扫扫这个二维码,这时用户的手机上就会出现一个互动的小程序,用户互动完成后,服务器判断用户互动完成,给派样机的Unity程序发一个网络指令。Unity程序收到该指令后,使用串口通信给派样机发一个指令,派样机硬件收到该指令后,即调用硬件推出一个小礼物,送给用户。

图1使用的派样机

这个项目不是什么很复杂的项目,这里面有两个难点。1.获取服务器传过来的信号,进行判断。2.判断完毕服务器的信号后,调用派样机,调用硬件进行派样。只要开发完成这两个功能后,这个项目就算是完成了。

开发步骤

1.首先在Unity中创建UI,将二维码贴在Unity的程序里的UI上,UI如下图所示。

图2设计的程序UI

2.开发获取服务器指令功能,并且进行判断,如果获取到正确的信息,即对派样机发送派样指令,代码如下。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using Newtonsoft.Json;
using UnityEngine.UI;
public class HttpNet : MonoBehaviour
{
Action callback;
///


/// 派样机字符类
///


public ComManager comManager;
// Start is called before the first frame update
void Start()
{
callback += Dispchater;
StartCoroutine(GetData(callback));
}
private void Dispchater()
{
//Debug.Log("掉小样!");
comManager.DemoMechineSendCom();
}
//加载路径图片
IEnumerator GetData(Action action)//Action action
{
while (true)
{
yield return new WaitForSeconds(2.0f);
UnityWebRequest unityWebRequest = UnityWebRequest.Get("https://www.brandxspace.com/development/sendPrototype/getPrototypeState?flag=0");
//UnityWebRequest unityWebRequest = UnityWebRequest.Get(jsonUrl);
yield return unityWebRequest.SendWebRequest();
if (!unityWebRequest.isNetworkError)
{
string data = unityWebRequest.downloadHandler.text;
Data d = JsonConvert.DeserializeObject(data);
if (d != null)
{
Debug.Log(data + "------");
if (d.status == "1")
{
//掉小样
if (action != null)
{
action();
}
}
}
}
}
}
}
public class Data
{
public string status;
public String message;
public object data;
}

3.开发调用派样机派样功能,该功能主要使用的是串口通信开发,如果对串口通信开发很熟悉的话这个也是十分简单的功能,主要是通过代码设置派样的顺序和速率,代码如下:

(1)CRC.CS

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class CRC
{
#region CRC16
public static byte[] CRC16(byte[] data)
{
int len = data.Length;
if (len > 0)
{
ushort crc = 0xFFFF;
for (int i = 0; i < len; i++)
{
crc = (ushort)(crc ^ (data[i]));
for (int j = 0; j < 8; j++)
{
crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1);
}
}
byte hi = (byte)((crc & 0xFF00) >> 8); //高位置
byte lo = (byte)(crc & 0x00FF); //低位置
return new byte[] { hi, lo };
}
return new byte[] { 0, 0 };
}
#endregion
#region ToCRC16
public static string ToCRC16(string content)
{
return ToCRC16(content, Encoding.UTF8);
}
public static string ToCRC16(string content, bool isReverse)
{
return ToCRC16(content, Encoding.UTF8, isReverse);
}
public static string ToCRC16(string content, Encoding encoding)
{
return ByteToString(CRC16(encoding.GetBytes(content)), true);
}
public static string ToCRC16(string content, Encoding encoding, bool isReverse)
{
return ByteToString(CRC16(encoding.GetBytes(content)), isReverse);
}
public static string ToCRC16(byte[] data)
{
return ByteToString(CRC16(data), true);
}
public static string ToCRC16(byte[] data, bool isReverse)
{
return ByteToString(CRC16(data), isReverse);
}
#endregion
#region ToModbusCRC16
public static string ToModbusCRC16(string s)
{
return ToModbusCRC16(s, true);
}
public static string ToModbusCRC16(string s, bool isReverse)
{
return ByteToString(CRC16(StringToHexByte(s)), isReverse);
}
public static string ToModbusCRC16(byte[] data)
{
return ToModbusCRC16(data, true);
}
public static string ToModbusCRC16(byte[] data, bool isReverse)
{
return ByteToString(CRC16(data), isReverse);
}
#endregion
#region ByteToString
public static string ByteToString(byte[] arr, bool isReverse)
{
try
{
byte hi = arr[0], lo = arr[1];
return Convert.ToString(isReverse ? hi + lo * 0x100 : hi * 0x100 + lo, 16).ToUpper().PadLeft(4, '0');
}
catch (Exception ex) { throw (ex); }
}
public static string ByteToString(byte[] arr)
{
try
{
return ByteToString(arr, true);
}
catch (Exception ex) { throw (ex); }
}
#endregion
#region StringToHexString
public static string StringToHexString(string str)
{
StringBuilder s = new StringBuilder();
foreach (short c in str.ToCharArray())
{
s.Append(c.ToString("X4"));
}
return s.ToString();
}
#endregion
#region StringToHexByte
private static string ConvertChinese(string str)
{
StringBuilder s = new StringBuilder();
foreach (short c in str.ToCharArray())
{
if (c <= 0 || c >= 127)
{
s.Append(c.ToString("X4"));
}
else
{
s.Append((char)c);
}
}
return s.ToString();
}
private static string FilterChinese(string str)
{
StringBuilder s = new StringBuilder();
foreach (short c in str.ToCharArray())
{
if (c > 0 && c < 127)
{
s.Append((char)c);
}
}
return s.ToString();
}
///


/// 字符串转16进制字符数组
///


///

///
public static byte[] StringToHexByte(string str)
{
return StringToHexByte(str, false);
}
///

/// 字符串转16进制字符数组
///

///

///

是否过滤掉中文字符
///
public static byte[] StringToHexByte(string str, bool isFilterChinese)
{
string hex = isFilterChinese ? FilterChinese(str) : ConvertChinese(str);
//清除所有空格
hex = hex.Replace(" ", "");
//若字符个数为奇数,补一个0
hex += hex.Length % 2 != 0 ? "0" : "";
byte[] result = new byte[hex.Length / 2];
for (int i = 0, c = result.Length; i < c; i++)
{
result[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
}
return result;
}
#endregion
}

(2)ComManager.cs

using UnityEngine;
using System.Collections;
using System;
using System.Threading;
using System.Collections.Generic;
using System.IO.Ports;
public class ComManager : MonoBehaviour
{
//public ComManager instance;
//端口号
string com2 = "";
private SerialPort sp2;
//波特率
private int baudRate;
public float timer = 0.1f;
//private bool isShinning = false;
//配置文件管理类
public ConfigTest configTest;
//private void Awake()
//{
//instance = this;
//}
void Start()
{
//string com2 = "COM7";
com2 = configTest.dic["端口号"]["portName"];
baudRate = int.Parse(configTest.dic["波特率"]["baudRate"]);
//row = 8;
row = int.Parse(configTest.dic["参数"]["row"]);
//column = 4;
column = int.Parse(configTest.dic["参数"]["column"]);
//depth = 5;
depth = int.Parse(configTest.dic["参数"]["depth"]);
mainCount = int.Parse(configTest.dic["参数"]["mainCount"]);
StartCoroutine(StartCom());
}
IEnumerator StartCom()
{
yield return new WaitForSeconds(0.1f);
sp2 = new SerialPort(com2, baudRate, Parity.None, 8, StopBits.One);
if (!sp2.IsOpen)
{
sp2.Open();
}
}
///


/// 派样机串口
///


///


private void SendDemoMechineData(byte[] data)
{
if (sp2.IsOpen)
{
sp2.Write(data, 0, data.Length);
}
}
void OnDisable()
{
if (sp2.IsOpen)
{
sp2.Close();
}
}
private int row;//8
private int column;//5
private int depth;//10
private int mainCount = 40;//总数
private static int index = 0;
public void DemoMechineSendCom()
{
int tempRow = index % row; //第几个
int tempColumn = (index / row) % row; //第几行
int tempdepth = index / (row * column) % depth;
Debug.Log(index + " row: " + tempRow + "col: " + tempColumn + "depth " + tempdepth);
string pos = tempColumn.ToString("0") + tempRow.ToString("0");
string corPos = System.Convert.ToString(int.Parse(pos),16).PadLeft(2,'0');
string data = "0105"
+ corPos
+ "030000000000000000000000000000";
byte[] byteData = CRC.StringToHexByte(data);
byte[] crcByteData = CRC.CRC16(byteData);
//Debug.Log(CRC.ByteToString(crcByteData));
data += CRC.ByteToString(crcByteData);
//Debug.Log(data);
byte[] byteDatas = CRC.StringToHexByte(data);
SendDemoMechineData(byteDatas);
index++;
if (index >= mainCount)
{
index = 0;
}
}
}

小结

就这样,派样机的功能就基本开发完成了。虽然这个程序的功能十分简单,但是用处很大,创作不易,如果喜欢文章,请点个赞。