MainForm.cs 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950
  1. using Newtonsoft.Json;
  2. using Newtonsoft.Json.Linq;
  3. using RestSharp;
  4. using S7.Net;
  5. using System.Drawing.Imaging;
  6. using System.Runtime.InteropServices;
  7. using System.Threading.Channels;
  8. using System.Windows.Forms;
  9. using static xicheji.CHCNetSDK;
  10. namespace xicheji
  11. {
  12. public partial class MainForm : Form
  13. {
  14. private readonly Config config;
  15. private static DateTime logDate = DateTime.Now;
  16. private static StreamWriter logWriter;
  17. private DateTime lastReceiveTime = DateTime.MinValue;
  18. private byte[]? currentDataBlock;
  19. private Plc? plc = null;
  20. private bool m_bInitSDK = false;
  21. private bool m_bRecord = false;
  22. private uint iLastErr = 0;
  23. private int m_lUserID = -1;
  24. private int m_lRealHandle = -1;
  25. private string str1;
  26. private string str2;
  27. private int i = 0;
  28. private int m_lTree = 0;
  29. private string str;
  30. private long iSelIndex = 0;
  31. private uint dwAChanTotalNum = 0;
  32. private uint dwDChanTotalNum = 0;
  33. private int m_lPort = -1;
  34. private IntPtr m_ptrRealHandle;
  35. private int[] iIPDevID = new int[96];
  36. private int[] iChannelNum = new int[96];
  37. private CHCNetSDK.REALDATACALLBACK RealData = null;
  38. public CHCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo;
  39. public CHCNetSDK.NET_DVR_IPPARACFG_V40 m_struIpParaCfgV40;
  40. public CHCNetSDK.NET_DVR_STREAM_MODE m_struStreamMode;
  41. public CHCNetSDK.NET_DVR_IPCHANINFO m_struChanInfo;
  42. public CHCNetSDK.NET_DVR_PU_STREAM_URL m_struStreamURL;
  43. public CHCNetSDK.NET_DVR_IPCHANINFO_V40 m_struChanInfoV40;
  44. private PlayCtrl.DECCBFUN m_fDisplayFun = null;
  45. public delegate void MyDebugInfo(string str);
  46. private readonly List<WashRecord> washRecords = new();
  47. private string lastCarNo = string.Empty;
  48. private IFreeSql db;
  49. public MainForm()
  50. {
  51. InitializeComponent();
  52. config = ConfigHelper.GetConfig();
  53. logWriter = new StreamWriter(DateTime.Now.ToString("yyyy_MM_dd") + ".log");
  54. db = new FreeSql.FreeSqlBuilder()
  55. .UseAutoSyncStructure(true)
  56. .UseConnectionString(FreeSql.DataType.Sqlite, config.DBString)
  57. .Build();
  58. }
  59. private void MainForm_Load(object sender, EventArgs e)
  60. {
  61. try
  62. {
  63. m_bInitSDK = CHCNetSDK.NET_DVR_Init();
  64. if (m_bInitSDK == false)
  65. {
  66. MessageBox.Show("NET_DVR_Init error!");
  67. return;
  68. }
  69. else
  70. {
  71. //保存SDK日志 To save the SDK log
  72. CHCNetSDK.NET_DVR_SetLogToFile(3, Path.Combine(Directory.GetCurrentDirectory(), "log"), true);
  73. for (int i = 0; i < 64; i++)
  74. {
  75. iIPDevID[i] = -1;
  76. iChannelNum[i] = -1;
  77. }
  78. }
  79. dataGridView1.AutoGenerateColumns = false;
  80. dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
  81. #region 测试代码: 表格数据
  82. washRecords.Add(new WashRecord()
  83. {
  84. DeviceId = "asdf",
  85. CarNum = "京123456",
  86. StartTime = new DateTime(2024, 6, 1, 12, 00, 00),
  87. EndTime = new DateTime(2024, 6, 1, 12, 30, 00),
  88. WashTime = 15,
  89. DryTime = 15,
  90. TotalElectricity = 10,
  91. TotalWater = 2,
  92. WaterPressure = 6,
  93. });
  94. #endregion
  95. dataGridView1.DataSource = washRecords;
  96. ConnectPLC();
  97. ConnectCamera();
  98. receivePLCTimer.Interval = config.PLCReceiveInterval * 1000;
  99. receivePLCTimer.Enabled = true;
  100. uploadTimer.Enabled = true;
  101. }
  102. catch (Exception ex)
  103. {
  104. MessageBox.Show(ex.Message + ex.StackTrace);
  105. }
  106. }
  107. private void btnSetting_Click(object sender, EventArgs e)
  108. {
  109. try
  110. {
  111. var settingForm = new SettingForm();
  112. if (settingForm.ShowDialog() == DialogResult.OK)
  113. {
  114. ConnectPLC();
  115. ConnectCamera();
  116. receivePLCTimer.Enabled = true;
  117. uploadTimer.Enabled = true;
  118. }
  119. }
  120. catch (Exception ex)
  121. {
  122. MessageBox.Show(ex.Message + ex.StackTrace);
  123. }
  124. }
  125. private void nowTimer_Tick(object sender, EventArgs e)
  126. {
  127. try
  128. {
  129. var now = DateTime.Now;
  130. lblTime.Text = $"{now.Month}月 {now.Day}日 {now.Hour}:{now:mm}:{now:ss}";
  131. }
  132. catch { }
  133. }
  134. public static void Log(object message)
  135. {
  136. if (message == null) return;
  137. if (DateTime.Now.Date != logDate.Date)
  138. {
  139. logDate = DateTime.Now;
  140. logWriter = new StreamWriter(DateTime.Now.ToString("yyyy_MM_dd") + ".log");
  141. }
  142. logWriter.WriteLine(DateTime.Now.ToString("HH:mm:ss:fff> ") + " " + message);
  143. logWriter.Flush();
  144. }
  145. #region 读PLC数据
  146. private void ConnectPLC()
  147. {
  148. plc = new Plc(config.PLCType, config.PLCIP, int.Parse(config.PLCPort), 0, 1);
  149. plc.Open();
  150. if (!plc.IsConnected)
  151. {
  152. MessageBox.Show("PLC连接失败!");
  153. return;
  154. }
  155. }
  156. private void receivePLCTimer_Tick(object sender, EventArgs e)
  157. {
  158. try
  159. {
  160. if (plc == null || !plc.IsConnected)
  161. {
  162. receivePLCTimer.Enabled = false;
  163. return;
  164. }
  165. ReadPLCData();
  166. }
  167. catch (Exception ex)
  168. {
  169. receivePLCTimer.Enabled = false;
  170. MessageBox.Show(ex.Message + ex.StackTrace);
  171. }
  172. }
  173. private void ReadPLCData()
  174. {
  175. currentDataBlock = plc!.ReadBytes(DataType.DataBlock, 1, 0, 100);
  176. var time = DateTime.Now; //临时代码, 先跳过下面日期报错的
  177. //var time = new DateTime(
  178. // DateTime.Now.Year,
  179. // ReadPLCInt("当前月"),
  180. // ReadPLCInt("当前日"),
  181. // ReadPLCInt("当前时"),
  182. // ReadPLCInt("当前分"),
  183. // ReadPLCInt("当前秒"));
  184. var macAddress = ReadMacAddress();
  185. Log("macAddress: " + macAddress);
  186. if (string.IsNullOrEmpty(config.PLCMacAddress))
  187. {
  188. //第一次配置为空时,更新一下mac地址
  189. config.PLCMacAddress = macAddress;
  190. }
  191. //if (config.PLCMacAddress != macAddress)
  192. //{
  193. // //以后还不匹配就提示
  194. // MessageBox.Show("PLC设备Mac地址不匹配,请确认!");
  195. // return;
  196. //}
  197. if (time <= lastReceiveTime)
  198. {
  199. //已经读过这个时间的了
  200. return;
  201. }
  202. db.Insert(new PLCRecord() { Data = currentDataBlock }).ExecuteAffrows();
  203. lastReceiveTime = time;
  204. ReadError();
  205. ReadStatus();
  206. lblWashCount.Text = ReadPLCString("洗车次数");
  207. lblTotalWater.Text = ReadPLCString("累计用水量");
  208. lblTotalElectricity.Text = ReadPLCString("累计用电量");
  209. //.Text = ReadPLCStringValue("当前流量");
  210. lblCurrentElectricity.Text = ReadPLCString("当前功率");
  211. lblCurrentWaterP.Text = ReadPLCString("当前压力");
  212. var myCrc = CRCCheck(currentDataBlock);
  213. var readCrc = ReadPLCInt("CRC");
  214. if (myCrc != readCrc)
  215. {
  216. //receivePLCTimer.Enabled = false;
  217. //MessageBox.Show("CRC不匹配!");
  218. //return;
  219. }
  220. if (ReadPLCInt("最后一次洗车开始月") != 0)
  221. {
  222. if (string.IsNullOrEmpty(lastCarNo))
  223. {
  224. receivePLCTimer.Enabled = false;
  225. MessageBox.Show("未检测到车牌信息,请检查是否识别正常");
  226. return;
  227. }
  228. //洗车完成后才有数据的
  229. var washStartTime = new DateTime(
  230. DateTime.Now.Year,
  231. ReadPLCInt("最后一次洗车开始月"),
  232. ReadPLCInt("最后一次洗车开始日"),
  233. ReadPLCInt("最后一次洗车开始时"),
  234. ReadPLCInt("最后一次洗车开始分"),
  235. ReadPLCInt("最后一次洗车开始秒"));
  236. var washEndTime = new DateTime(
  237. DateTime.Now.Year,
  238. ReadPLCInt("最后一次洗车结束月"),
  239. ReadPLCInt("最后一次洗车结束日"),
  240. ReadPLCInt("最后一次洗车结束时"),
  241. ReadPLCInt("最后一次洗车结束分"),
  242. ReadPLCInt("最后一次洗车结束秒"));
  243. var washRecord = new WashRecord()
  244. {
  245. DeviceId = macAddress,
  246. CarNum = lastCarNo,
  247. StartTime = washStartTime,
  248. EndTime = washEndTime,
  249. DryTime = ReadPLCInt("最后一次洗车风干时长"),
  250. TotalElectricity = ReadPLCInt("最后一次洗车用电"),
  251. TotalWater = ReadPLCInt("最后一次洗车用水"),
  252. WashTime = ReadPLCInt("最后一次洗车总时长"),
  253. WaterPressure = ReadPLCInt("最后一次洗车水压"),
  254. };
  255. washRecords.Add(washRecord);
  256. db.Insert(washRecord).ExecuteAffrows();
  257. //洗车完成后重置车牌信息
  258. lastCarNo = string.Empty;
  259. }
  260. }
  261. private static readonly ushort[] crcTable = new ushort[256] {
  262. 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
  263. 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
  264. 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
  265. 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
  266. 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
  267. 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
  268. 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
  269. 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
  270. 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
  271. 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
  272. 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
  273. 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
  274. 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
  275. 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
  276. 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
  277. 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
  278. 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
  279. 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
  280. 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
  281. 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
  282. 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
  283. 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
  284. 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
  285. 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
  286. 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
  287. 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
  288. 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
  289. 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
  290. 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
  291. 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
  292. 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
  293. 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
  294. };
  295. private static ushort CRCCheck(byte[] data)
  296. {
  297. ushort crc = 0xFFFF;
  298. foreach (byte b in data)
  299. {
  300. byte tableIndex = (byte)(((crc >> 8) ^ b) & 0xFF);
  301. crc = (ushort)((crc << 8) ^ crcTable[tableIndex]);
  302. }
  303. return crc;
  304. }
  305. private string ReadMacAddress()
  306. {
  307. var mac1 = ReadPLCInt("MAC1");
  308. var mac2 = ReadPLCInt("MAC2");
  309. var mac3 = ReadPLCInt("MAC3");
  310. var mac4 = ReadPLCInt("MAC4");
  311. var mac5 = ReadPLCInt("MAC5");
  312. var mac6 = ReadPLCInt("MAC6");
  313. return $"{ConvertMacItem(mac1)}:{ConvertMacItem(mac2)}:{ConvertMacItem(mac3)}:{ConvertMacItem(mac4)}:{ConvertMacItem(mac5)}:{ConvertMacItem(mac6)}";
  314. }
  315. private string ConvertMacItem(int value)
  316. {
  317. return value.ToString("X").PadLeft(2, '0');
  318. }
  319. private void ReadStatus()
  320. {
  321. lblStatus.Text = string.Empty;
  322. var statuses = new List<string>() {
  323. "洗车中", "清洗中", "沥水中",
  324. "出车中", "风干中"};
  325. foreach (var status in statuses)
  326. {
  327. if (ReadPLCBool(status))
  328. {
  329. lblStatus.Text = status;
  330. break;
  331. }
  332. }
  333. }
  334. private void ReadError()
  335. {
  336. lblError.Text = string.Empty;
  337. var errors = new List<string>() {
  338. "急停", "冲洗泵故障", "反洗泵故障",
  339. "清淤泵故障", "伴热故障", "风刀故障" };
  340. foreach (var error in errors)
  341. {
  342. if (ReadPLCBool(error))
  343. {
  344. lblError.Text = error;
  345. break;
  346. }
  347. }
  348. }
  349. private string ReadPLCString(string name)
  350. {
  351. var variable = ConfigHelper.FindVariable(name);
  352. if (variable == null || currentDataBlock == null)
  353. return string.Empty;
  354. ParsePLCKey(variable.Key, out _, out _, out var varType, out var address, out var bitNumber);
  355. if (varType == VarType.DWord)
  356. {
  357. var value = S7.Net.Types.DWord.FromByteArray(currentDataBlock.Take(new Range(address, address + 4)).ToArray());
  358. return $"{value} {variable.Desc}".TrimEnd();
  359. }
  360. else if (varType == VarType.Word)
  361. {
  362. var value = S7.Net.Types.Word.FromByteArray(currentDataBlock.Take(new Range(address, address + 2)).ToArray());
  363. return $"{value} {variable.Desc}".TrimEnd();
  364. }
  365. else if (varType == VarType.Byte)
  366. {
  367. var value = S7.Net.Types.Byte.FromByteArray(currentDataBlock.Take(new Range(address, address + 1)).ToArray());
  368. return $"{value} {variable.Desc}".TrimEnd();
  369. }
  370. return string.Empty;
  371. }
  372. private int ReadPLCInt(string name)
  373. {
  374. var variable = ConfigHelper.FindVariable(name);
  375. if (variable == null || currentDataBlock == null)
  376. return 0;
  377. ParsePLCKey(variable.Key, out var dataType, out var dbNumber, out var varType, out var address, out var bitNumber);
  378. if (varType == VarType.DWord)
  379. {
  380. var value = S7.Net.Types.DWord.FromByteArray(currentDataBlock.Take(new Range(address, address + 4)).ToArray());
  381. return (int)value;
  382. }
  383. else if (varType == VarType.Word)
  384. {
  385. var value = S7.Net.Types.Word.FromByteArray(currentDataBlock.Take(new Range(address, address + 2)).ToArray());
  386. return value;
  387. }
  388. else if (varType == VarType.Byte)
  389. {
  390. var value = S7.Net.Types.Byte.FromByteArray(currentDataBlock.Take(new Range(address, address + 1)).ToArray());
  391. return value;
  392. }
  393. return 0;
  394. }
  395. private bool ReadPLCBool(string name)
  396. {
  397. var variable = ConfigHelper.FindVariable(name);
  398. if (variable == null || currentDataBlock == null)
  399. return false;
  400. ParsePLCKey(variable.Key, out _, out _, out _, out var address, out var bitNumber);
  401. var value = S7.Net.Types.Boolean.GetValue(currentDataBlock[address], bitNumber);
  402. return value;
  403. }
  404. private static void ParsePLCKey(string plcKey, out DataType dataType, out int dbNumber, out VarType varType, out int address, out int bitNumber)
  405. {
  406. bitNumber = -1;
  407. dbNumber = 0;
  408. switch (plcKey.Substring(0, 2))
  409. {
  410. case "DB":
  411. string[] strings = plcKey.Split(new char[] { '.' });
  412. if (strings.Length < 2)
  413. throw new InvalidAddressException("To few periods for DB address");
  414. dataType = DataType.DataBlock;
  415. dbNumber = int.Parse(strings[0].Substring(2));
  416. address = int.Parse(strings[1].Substring(3));
  417. string dbType = strings[1].Substring(0, 3);
  418. switch (dbType)
  419. {
  420. case "DBB":
  421. varType = VarType.Byte;
  422. return;
  423. case "DBW":
  424. varType = VarType.Word;
  425. return;
  426. case "DBD":
  427. varType = VarType.DWord;
  428. return;
  429. case "DBX":
  430. bitNumber = int.Parse(strings[2]);
  431. if (bitNumber > 7)
  432. throw new InvalidAddressException("Bit can only be 0-7");
  433. varType = VarType.Bit;
  434. return;
  435. default:
  436. throw new InvalidAddressException();
  437. }
  438. case "IB":
  439. case "EB":
  440. // Input byte
  441. dataType = DataType.Input;
  442. dbNumber = 0;
  443. address = int.Parse(plcKey.Substring(2));
  444. varType = VarType.Byte;
  445. return;
  446. case "IW":
  447. case "EW":
  448. // Input word
  449. dataType = DataType.Input;
  450. dbNumber = 0;
  451. address = int.Parse(plcKey.Substring(2));
  452. varType = VarType.Word;
  453. return;
  454. case "ID":
  455. case "ED":
  456. // Input double-word
  457. dataType = DataType.Input;
  458. dbNumber = 0;
  459. address = int.Parse(plcKey.Substring(2));
  460. varType = VarType.DWord;
  461. return;
  462. case "QB":
  463. case "AB":
  464. case "OB":
  465. // Output byte
  466. dataType = DataType.Output;
  467. dbNumber = 0;
  468. address = int.Parse(plcKey.Substring(2));
  469. varType = VarType.Byte;
  470. return;
  471. case "QW":
  472. case "AW":
  473. case "OW":
  474. // Output word
  475. dataType = DataType.Output;
  476. dbNumber = 0;
  477. address = int.Parse(plcKey.Substring(2));
  478. varType = VarType.Word;
  479. return;
  480. case "QD":
  481. case "AD":
  482. case "OD":
  483. // Output double-word
  484. dataType = DataType.Output;
  485. dbNumber = 0;
  486. address = int.Parse(plcKey.Substring(2));
  487. varType = VarType.DWord;
  488. return;
  489. case "MB":
  490. // Memory byte
  491. dataType = DataType.Memory;
  492. dbNumber = 0;
  493. address = int.Parse(plcKey.Substring(2));
  494. varType = VarType.Byte;
  495. return;
  496. case "MW":
  497. // Memory word
  498. dataType = DataType.Memory;
  499. dbNumber = 0;
  500. address = int.Parse(plcKey.Substring(2));
  501. varType = VarType.Word;
  502. return;
  503. case "MD":
  504. // Memory double-word
  505. dataType = DataType.Memory;
  506. dbNumber = 0;
  507. address = int.Parse(plcKey.Substring(2));
  508. varType = VarType.DWord;
  509. return;
  510. default:
  511. switch (plcKey.Substring(0, 1))
  512. {
  513. case "E":
  514. case "I":
  515. // Input
  516. dataType = DataType.Input;
  517. varType = VarType.Bit;
  518. break;
  519. case "Q":
  520. case "A":
  521. case "O":
  522. // Output
  523. dataType = DataType.Output;
  524. varType = VarType.Bit;
  525. break;
  526. case "M":
  527. // Memory
  528. dataType = DataType.Memory;
  529. varType = VarType.Bit;
  530. break;
  531. case "T":
  532. // Timer
  533. dataType = DataType.Timer;
  534. dbNumber = 0;
  535. address = int.Parse(plcKey.Substring(1));
  536. varType = VarType.Timer;
  537. return;
  538. case "Z":
  539. case "C":
  540. // Counter
  541. dataType = DataType.Counter;
  542. dbNumber = 0;
  543. address = int.Parse(plcKey.Substring(1));
  544. varType = VarType.Counter;
  545. return;
  546. default:
  547. throw new InvalidAddressException(string.Format("{0} is not a valid address", plcKey.Substring(0, 1)));
  548. }
  549. string txt2 = plcKey.Substring(1);
  550. if (txt2.IndexOf(".") == -1)
  551. throw new InvalidAddressException("To few periods for DB address");
  552. address = int.Parse(txt2.Substring(0, txt2.IndexOf(".")));
  553. bitNumber = int.Parse(txt2.Substring(txt2.IndexOf(".") + 1));
  554. if (bitNumber > 7)
  555. throw new InvalidAddressException("Bit can only be 0-7");
  556. return;
  557. }
  558. }
  559. #endregion
  560. #region 上传到洗车平台
  561. private async void uploadTimer_Tick(object sender, EventArgs e)
  562. {
  563. try
  564. {
  565. await UploadPlatform();
  566. }
  567. catch (Exception ex)
  568. {
  569. uploadTimer.Enabled = false;
  570. MessageBox.Show(ex.Message + ex.StackTrace);
  571. }
  572. }
  573. private async Task UploadPlatform()
  574. {
  575. var restClient = new RestClient(config.Server);
  576. var request = new RestRequest("cyft/common/carWashRecord", Method.Post);
  577. // 测试代码
  578. WashRecord washRecord = new WashRecord();
  579. var jsonBody = new
  580. {
  581. deviceId = washRecord.DeviceId, //洗车机器mac地址
  582. carNo = washRecord.CarNum, //车牌号码
  583. beginTime = washRecord.StartTime.ToString("yyyy-MM-dd HH:mm:ss"), //洗车开始时间
  584. endTime = washRecord.EndTime.ToString("yyyy-MM-dd HH:mm:ss"), //洗车结束时间
  585. washTime = washRecord.WashTime, //洗车时长(s)
  586. widnowsDefender = washRecord.TotalWater, //用水量(t)
  587. waterPressure = washRecord.WaterPressure, //压力(MPa)
  588. picBase64 = ImageToBase64(pbCamera.Image, ImageFormat.Jpeg), //洗车图片base64
  589. };
  590. request.AddParameter("application/json", JsonConvert.SerializeObject(jsonBody), ParameterType.RequestBody);
  591. var response = await restClient.ExecuteAsync(request);
  592. if (response == null) return;
  593. }
  594. #endregion
  595. #region 摄像头
  596. private void btnConnectCamera_Click(object sender, EventArgs e)
  597. {
  598. try
  599. {
  600. ConnectCamera();
  601. }
  602. catch (Exception ex)
  603. {
  604. MessageBox.Show(ex.Message + ex.StackTrace);
  605. }
  606. }
  607. private void ConnectCamera()
  608. {
  609. try
  610. {
  611. cboCameraChannel.DisplayMember = "Display";
  612. cboCameraChannel.ValueMember = "Value";
  613. cboCameraChannel.Items.Clear();
  614. //登录设备 Login the device
  615. m_lUserID = CHCNetSDK.NET_DVR_Login_V30(config.CameraIP, int.Parse(config.CameraPort),
  616. config.CameraUserName, config.CameraPassword, ref DeviceInfo);
  617. if (m_lUserID < 0)
  618. {
  619. var iLastErr = CHCNetSDK.NET_DVR_GetLastError();
  620. var errMsg = "NET_DVR_Login_V30 failed, error code= " + iLastErr; //登录失败,输出错误号 Failed to login and output the error code
  621. MessageBox.Show(errMsg);
  622. return;
  623. }
  624. else
  625. {
  626. //登录成功
  627. Log("NET_DVR_Login_V30 succ!");
  628. dwAChanTotalNum = (uint)DeviceInfo.byChanNum;
  629. dwDChanTotalNum = (uint)DeviceInfo.byIPChanNum + 256 * (uint)DeviceInfo.byHighDChanNum;
  630. if (dwDChanTotalNum > 0)
  631. {
  632. InfoIPChannel();
  633. }
  634. else
  635. {
  636. for (var i = 0; i < dwAChanTotalNum; i++)
  637. {
  638. ListAnalogChannel(i + 1, 1);
  639. iChannelNum[i] = i + (int)DeviceInfo.byStartChan;
  640. }
  641. //comboBoxView.SelectedItem = 1;
  642. // MessageBox.Show("This device has no IP channel!");
  643. }
  644. }
  645. if (cboCameraChannel.Items.Count > 0 && cboCameraChannel.SelectedIndex == -1)
  646. {
  647. cboCameraChannel.SelectedIndex = 0;
  648. }
  649. }
  650. catch (Exception ex)
  651. {
  652. MessageBox.Show(ex.Message + ex.StackTrace);
  653. }
  654. }
  655. public void InfoIPChannel()
  656. {
  657. uint dwSize = (uint)Marshal.SizeOf(m_struIpParaCfgV40);
  658. IntPtr ptrIpParaCfgV40 = Marshal.AllocHGlobal((Int32)dwSize);
  659. Marshal.StructureToPtr(m_struIpParaCfgV40, ptrIpParaCfgV40, false);
  660. uint dwReturn = 0;
  661. int iGroupNo = 0; //该Demo仅获取第一组64个通道,如果设备IP通道大于64路,需要按组号0~i多次调用NET_DVR_GET_IPPARACFG_V40获取
  662. if (!CHCNetSDK.NET_DVR_GetDVRConfig(m_lUserID, CHCNetSDK.NET_DVR_GET_IPPARACFG_V40, iGroupNo, ptrIpParaCfgV40, dwSize, ref dwReturn))
  663. {
  664. iLastErr = CHCNetSDK.NET_DVR_GetLastError();
  665. str = "NET_DVR_GET_IPPARACFG_V40 failed, error code= " + iLastErr;
  666. //获取IP资源配置信息失败,输出错误号 Failed to get configuration of IP channels and output the error code
  667. Log(str);
  668. }
  669. else
  670. {
  671. Log("NET_DVR_GET_IPPARACFG_V40 succ!");
  672. m_struIpParaCfgV40 = (CHCNetSDK.NET_DVR_IPPARACFG_V40)Marshal.PtrToStructure(ptrIpParaCfgV40, typeof(CHCNetSDK.NET_DVR_IPPARACFG_V40));
  673. for (var i = 0; i < dwAChanTotalNum; i++)
  674. {
  675. ListAnalogChannel(i + 1, m_struIpParaCfgV40.byAnalogChanEnable[i]);
  676. iChannelNum[i] = i + (int)DeviceInfo.byStartChan;
  677. }
  678. byte byStreamType = 0;
  679. uint iDChanNum = 64;
  680. if (dwDChanTotalNum < 64)
  681. {
  682. iDChanNum = dwDChanTotalNum; //如果设备IP通道小于64路,按实际路数获取
  683. }
  684. for (var i = 0; i < iDChanNum; i++)
  685. {
  686. iChannelNum[i + dwAChanTotalNum] = i + (int)m_struIpParaCfgV40.dwStartDChan;
  687. byStreamType = m_struIpParaCfgV40.struStreamMode[i].byGetStreamType;
  688. dwSize = (uint)Marshal.SizeOf(m_struIpParaCfgV40.struStreamMode[i].uGetStream);
  689. switch (byStreamType)
  690. {
  691. //目前NVR仅支持直接从设备取流 NVR supports only the mode: get stream from device directly
  692. case 0:
  693. IntPtr ptrChanInfo = Marshal.AllocHGlobal((Int32)dwSize);
  694. Marshal.StructureToPtr(m_struIpParaCfgV40.struStreamMode[i].uGetStream, ptrChanInfo, false);
  695. m_struChanInfo = (CHCNetSDK.NET_DVR_IPCHANINFO)Marshal.PtrToStructure(ptrChanInfo, typeof(CHCNetSDK.NET_DVR_IPCHANINFO));
  696. //列出IP通道 List the IP channel
  697. ListIPChannel(i + 1, m_struChanInfo.byEnable, m_struChanInfo.byIPID);
  698. iIPDevID[i] = m_struChanInfo.byIPID + m_struChanInfo.byIPIDHigh * 256 - iGroupNo * 64 - 1;
  699. Marshal.FreeHGlobal(ptrChanInfo);
  700. break;
  701. case 4:
  702. IntPtr ptrStreamURL = Marshal.AllocHGlobal((Int32)dwSize);
  703. Marshal.StructureToPtr(m_struIpParaCfgV40.struStreamMode[i].uGetStream, ptrStreamURL, false);
  704. m_struStreamURL = (CHCNetSDK.NET_DVR_PU_STREAM_URL)Marshal.PtrToStructure(ptrStreamURL, typeof(CHCNetSDK.NET_DVR_PU_STREAM_URL));
  705. //列出IP通道 List the IP channel
  706. ListIPChannel(i + 1, m_struStreamURL.byEnable, m_struStreamURL.wIPID);
  707. iIPDevID[i] = m_struStreamURL.wIPID - iGroupNo * 64 - 1;
  708. Marshal.FreeHGlobal(ptrStreamURL);
  709. break;
  710. case 6:
  711. IntPtr ptrChanInfoV40 = Marshal.AllocHGlobal((Int32)dwSize);
  712. Marshal.StructureToPtr(m_struIpParaCfgV40.struStreamMode[i].uGetStream, ptrChanInfoV40, false);
  713. m_struChanInfoV40 = (CHCNetSDK.NET_DVR_IPCHANINFO_V40)Marshal.PtrToStructure(ptrChanInfoV40, typeof(CHCNetSDK.NET_DVR_IPCHANINFO_V40));
  714. //列出IP通道 List the IP channel
  715. ListIPChannel(i + 1, m_struChanInfoV40.byEnable, m_struChanInfoV40.wIPID);
  716. iIPDevID[i] = m_struChanInfoV40.wIPID - iGroupNo * 64 - 1;
  717. Marshal.FreeHGlobal(ptrChanInfoV40);
  718. break;
  719. default:
  720. break;
  721. }
  722. }
  723. }
  724. Marshal.FreeHGlobal(ptrIpParaCfgV40);
  725. }
  726. public void ListIPChannel(int iChanNo, byte byOnline, int byIPID)
  727. {
  728. str1 = String.Format("通道 {0}", iChanNo);
  729. m_lTree++;
  730. if (byIPID == 0)
  731. {
  732. str2 = "空闲"; //通道空闲,没有添加前端设备 the channel is idle
  733. }
  734. else
  735. {
  736. if (byOnline == 0)
  737. {
  738. str2 = "离线"; //通道不在线 the channel is off-line
  739. }
  740. else
  741. str2 = "在线"; //通道在线 The channel is on-line
  742. }
  743. cboCameraChannel.Items.Add(new
  744. {
  745. Display = $"{str1}: {str2}",
  746. Value = iChanNo,
  747. });
  748. }
  749. public void ListAnalogChannel(int iChanNo, byte byEnable)
  750. {
  751. str1 = String.Format("通道 {0}", iChanNo);
  752. m_lTree++;
  753. if (byEnable == 0)
  754. {
  755. str2 = "禁用"; //通道已被禁用 This channel has been disabled
  756. }
  757. else
  758. {
  759. str2 = "启用"; //通道处于启用状态 This channel has been enabled
  760. }
  761. cboCameraChannel.Items.Add(new
  762. {
  763. Display = $"{str1}: {str2}",
  764. Value = iChanNo,
  765. });
  766. }
  767. private void cboCameraChannel_SelectedIndexChanged(object sender, EventArgs e)
  768. {
  769. try
  770. {
  771. //停止预览 Stop live view
  772. if (!CHCNetSDK.NET_DVR_StopRealPlay(m_lRealHandle))
  773. {
  774. iLastErr = CHCNetSDK.NET_DVR_GetLastError();
  775. str = "NET_DVR_StopRealPlay failed, error code= " + iLastErr;
  776. Log(str);
  777. }
  778. Log("NET_DVR_StopRealPlay succ!");
  779. m_lRealHandle = -1;
  780. pbCamera.Invalidate();//刷新窗口 refresh the window
  781. iSelIndex = cboCameraChannel.SelectedIndex;
  782. //hikApi?.PlaybackService.StartPlayBack(channelNumber, pbCamera.Handle);
  783. CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();
  784. lpPreviewInfo.hPlayWnd = pbCamera.Handle;//预览窗口 live view window
  785. lpPreviewInfo.lChannel = iChannelNum[(int)iSelIndex];//预览的设备通道 the device channel number
  786. lpPreviewInfo.dwStreamType = 0;//码流类型:0-主码流,1-子码流,2-码流3,3-码流4,以此类推
  787. lpPreviewInfo.dwLinkMode = 0;//连接方式:0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP
  788. lpPreviewInfo.bBlocked = true; //0- 非阻塞取流,1- 阻塞取流
  789. lpPreviewInfo.dwDisplayBufNum = 15; //播放库显示缓冲区最大帧数
  790. IntPtr pUser = IntPtr.Zero;//用户数据 user data
  791. //打开预览 Start live view
  792. m_lRealHandle = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo, null/*RealData*/, pUser);
  793. if (m_lRealHandle < 0)
  794. {
  795. iLastErr = CHCNetSDK.NET_DVR_GetLastError();
  796. str = "NET_DVR_RealPlay_V40 failed, error code= " + iLastErr; //预览失败,输出错误号 failed to start live view, and output the error code.
  797. Log(str);
  798. pbCamera.Invalidate();//刷新窗口 refresh the window
  799. return;
  800. }
  801. else
  802. {
  803. //预览成功
  804. Log("NET_DVR_RealPlay_V40 succ!");
  805. }
  806. }
  807. catch (Exception ex)
  808. {
  809. MessageBox.Show(ex.Message + ex.StackTrace);
  810. }
  811. }
  812. #endregion
  813. #region 服务接口回调->更新汽车信息
  814. #endregion
  815. #region Image <-> Base64
  816. public static Image Base64ToImage(string base64String)
  817. {
  818. byte[] imageBytes = Convert.FromBase64String(base64String);
  819. using var ms = new MemoryStream(imageBytes, 0, imageBytes.Length);
  820. ms.Write(imageBytes, 0, imageBytes.Length);
  821. Image image = Image.FromStream(ms, true);
  822. return image;
  823. }
  824. public static string ImageToBase64(Image image, ImageFormat format)
  825. {
  826. if (image == null) return string.Empty;
  827. using var memoryStream = new MemoryStream();
  828. image.Save(memoryStream, format);
  829. var imageBytes = memoryStream.ToArray();
  830. return Convert.ToBase64String(imageBytes);
  831. }
  832. #endregion
  833. }
  834. }