using Microsoft.Win32; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; using Vinno.FIS.Sonopost.Features.Oled; using Vinno.FIS.Sonopost.Managers.Interfaces; using Vinno.FIS.Sonopost.Settings; using Vinno.IUS.Common.Log; namespace Vinno.FIS.Sonopost.Managers { internal class OledManager : SonopostManager, IOledManager { private Comm _comm; private ManualResetEvent _commResetEvent = new ManualResetEvent(false); private int _totalPages = 0; private const int MaxPage = 6; private readonly IConfigManager _configManager; private OledMessage _currentStatus = OledMessage.Null; private bool _rebootFlag; public Language CurrentLanguage { get; private set; } public OledManager() { _configManager = AppManager.Instance.GetManager(); Init(); CurrentLanguage = SonopostUserDefinedSettings.Instance.LanguageSetting.OLedLanguage; } private void Init() { OledMessages.Init(); Task.Run(() => { string commName = string.Empty; if (string.IsNullOrEmpty(SonopostSystemSettings.Instance.OledCommName)) { commName = SearchAvailableCommName(); } else { var success = OpenSerialPort(SonopostSystemSettings.Instance.OledCommName); if (success == false) { commName = SearchAvailableCommName(); } } if (!string.IsNullOrEmpty(commName)) { SonopostSystemSettings.Instance.OledCommName = commName; _configManager.Save(); } _commResetEvent.Set(); }); } private bool OpenSerialPort(string comName) { try { var comm = new Comm(comName); var success = comm.OpenPort(); if (success) { var result = MessageSender.Send(comm, new CommandData(MessageType.QueryStatus)); if (result is OKResult) { MessageSender.Send(comm, new CommandData(MessageType.ClearScreen)); result = MessageSender.Send(comm, new CommandData(MessageType.SearchPage)); if (result is SearchPageResult pageResult) { _totalPages = pageResult.Page; } _comm = comm; Logger.WriteLineInfo($"Open Serial Port {comName} Success"); return true; } else { result = MessageSender.Send(comm, new CommandData(MessageType.QueryStatus));//TryAgain if (result is OKResult) { MessageSender.Send(comm, new CommandData(MessageType.ClearScreen)); result = MessageSender.Send(comm, new CommandData(MessageType.SearchPage)); if (result is SearchPageResult pageResult) { _totalPages = pageResult.Page; } _comm = comm; Logger.WriteLineInfo($"Open Serial Port {comName} Success"); return true; } else { comm.ClosePort(); } } } } catch (Exception e) { Logger.WriteLineError($"Open SerialPort Error:{e}"); } Logger.WriteLineInfo($"Open Serial Port {comName} Failed"); return false; } private string SearchAvailableCommName() { var comList = GetPortArray(); foreach (var comName in comList) { if (OpenSerialPort(comName)) { Logger.WriteLineInfo($"Search Correct Serial Port,Comm Name:{comName}"); return comName; } } Logger.WriteLineError("Can Not Get Correct Serial Port!"); return string.Empty; } private static List GetPortArray() { RegistryKey keyCom = Registry.LocalMachine.OpenSubKey("Hardware\\DeviceMap\\SerialComm"); string[] sSubKeys = keyCom.GetValueNames().Reverse().ToArray(); var comList = new List(); for (int i = 0; i < sSubKeys.Length; i++) { comList.Add((string)keyCom.GetValue(sSubKeys[i])); } return comList; } private bool CreatePage(byte page) { if (page > MaxPage) return false; if (page > _totalPages) { var count = page - _totalPages; var retryCoun = 3; for (int i = 0; i < count;) { var ret = MessageSender.Send(_comm, new CommandData(MessageType.AddPage)); if (ret is OKResult) { i++; } else { retryCoun--; if (retryCoun <= 0) { Logger.WriteLineError("Add Page Error"); return false; } } Thread.Sleep(100); } _totalPages = page; } return true; } public bool ShowMessages(byte page, MessageType type, string messages, byte row) { try { _commResetEvent.WaitOne(5000); if (_comm == null) return false; if (string.IsNullOrEmpty(messages)) return false; if (CreatePage(page) == false) { return false; } var emptyData = CreateEmptyData(); var result = SendMessage(page, MessageType.DisplayEnglishMediumInCurrentPage, row, emptyData);//清除当前行 if (result == false) { Logger.WriteLineError($"Clear Row {row} Fail"); // return false; } var encoding = Encoding.GetEncoding("GB2312"); var messageBytes = encoding.GetBytes(messages); var success = SendMessage(page, type, row, messageBytes); if (success == false) { Logger.WriteLineError($"Show OLED Message Error:{messages},Type:{type}"); } return success; } catch (Exception ex) { Logger.WriteLineError($"Show OLED Message Error:{messages},Type:{type},{ex}"); } return false; } public bool ShowImage(byte page, MessageType type, byte x, byte y, string fileName) { try { if (x < 0 || x > 127 || y < 0 || y > 31) { Logger.WriteLineError("Image is out of range!"); return false; } _commResetEvent.WaitOne(5000); if (_comm == null) return false; if (CreatePage(page) == false) { return false; } if (string.IsNullOrEmpty(fileName)) { return false; } var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream($"Vinno.FIS.Sonopost.Resources.{fileName}"); if (stream == null) { return false; } using (Bitmap bitmap = (Bitmap)Image.FromStream(stream)) { if (bitmap.Width > 128 || bitmap.Height > 32) { Logger.WriteLineError("Image is too large!"); return false; } var data = ConvertImageToArray(bitmap); var imageData = new ImageData(type, x, y, (byte)bitmap.Width, (byte)bitmap.Height, data, page); var result = MessageSender.Send(_comm, imageData); if (result as OKResult == null) { return false; } return true; } } catch (Exception ex) { Logger.WriteLineError($"Show OLED Image Error:{ex}"); } return false; } public bool ClearImage(byte page, byte x, byte y, byte width, byte height) { try { if (x < 0 || x > 127 || y < 0 || y > 31 || width > 128 || height > 32) { Logger.WriteLineError("Image is out of range!"); return false; } _commResetEvent.WaitOne(5000); if (_comm == null) return false; if (CreatePage(page) == false) { return false; } var data = new byte[width * height / 8]; var imageData = new ImageData(MessageType.DisplayImageInCurrentPage, x, y, width, height, data, page); var result = MessageSender.Send(_comm, imageData); if (result as OKResult == null) { return false; } return true; } catch (Exception ex) { Logger.WriteLineError($"Show OLED Image Error:{ex}"); } return false; } private bool SendMessage(byte page, MessageType type, byte row, byte[] data) { var displayData = new DisplayData(type, row, 0, data, page); var result = MessageSender.Send(_comm, displayData); if (result as OKResult == null) { return false; } return true; } public void ShowStatus(OledMessage message) { if (_rebootFlag) { Logger.WriteLineWarn($"OledManager Show Status:{message} skipped,because the rebootFlag is true"); return; } if (message == OledMessage.Reboot) { _rebootFlag = true; } Logger.WriteLineInfo($"OledManager Show Status:{message}"); _currentStatus = message; var msg = OledMessages.GetValue(message, CurrentLanguage); var type = CurrentLanguage == Language.English ? MessageType.DisplayEnglishMediumWithPageNum : MessageType.DisplayChineseMediumWithPageNum; ShowMessages(1, type, msg, 0); } public void SetLanguage(Language language) { if (language != CurrentLanguage) { SonopostUserDefinedSettings.Instance.LanguageSetting.OLedLanguage = language; _configManager.Save(); CurrentLanguage = language; ShowStatus(_currentStatus); } } /// /// 图片取模 /// /// /// /// /// private byte[] ConvertImageToArray(Bitmap bitmap) { int width = bitmap.Width; int height = bitmap.Height; byte ch = 0; List byteList = new List(); int pageSize = height / 8; for (int page = 0; page < pageSize; page++) { for (int i = 0; i < width; i++) { for (int j = page * 8; j < page * 8 + 8; j++) { Color color = bitmap.GetPixel(i, j); if ((0.299 * color.R + 0.587 * color.G + 0.114 * color.B) < 200) { ch |= (byte)(1 << (j % 8)); } if (j % 8 == 7)//每8个点作为一个字节 { byteList.Add(ch); ch = 0; } } } } return byteList.ToArray(); } /// /// 清屏,防止文本重叠 /// /// private byte[] CreateEmptyData() { var data = new byte[21 - 4];//图片部分不清除 for (int i = 0; i < data.Length; i++) { data[i] = 32;//空格 } return data; } public override void DoDispose() { try { if (_comm != null) { _comm.ClosePort(); _comm = null; } } catch (Exception ex) { Logger.WriteLineError($"OledManager DoDispose Error:{ex}"); } base.DoDispose(); } } }