EQ控制卡二次開發(火鳳凰、藍精靈異步單雙色控制卡卡)


     在工業信息化行業,少不了生產可視化的模塊,其中應用最多的是采用LED屏的方式,通過軟件控制屏幕展示相關的生產計划完成狀態,工位的狀態,產線的運行狀態,以及相關自動化設備的狀態等,這就要求通信實時性,准確性。LED屏控制核心在於控制卡目前市場上各種控制卡種類繁多,今天先介紹下EQ系列的控制卡吧。其實通信實時性要求采用同步卡效果最佳,但是苦於現場不想增加專用的控制電腦(大部分同步卡原理即抓屏模式,實時展現電腦桌面的內容,電腦不能同時進行其他操作),所以決定采用異步卡異步通信,直接在后台通過程序建立和LED屏幕的連接,實時發送數據給LED屏幕。此篇就講下根據官方二次開發包開發的問題。

    EQ官方二次開發包

    此處我們采用的是網絡通訊的方式,即EQ控制卡上需固定IP,用以識別並和控制程序建立連接。

    EQ2008_Dll.dll是官方提供的開發接口,其中的接口方法包含如下:

using System;
using System.Runtime.InteropServices;
using ServiceCloud.Devices.Led.EQ2008.Parameters;

namespace ServiceCloud.Devices.Led.EQ2008
{
    /*
     本動態庫接口適用於:EQ火鳳凰系列和藍精靈系列控制器!
     火鳳凰系列:EQ2013、EQ2023、EQ2033
     藍精靈系列:EQ2012、EQ2011、EQ2008-1/2E、EQ2008-M
     */
    internal class LedControllerHandler
    {
        # region 1.節目操作函數
        /// <summary>
        /// 添加節目
        /// </summary>
        /// <param name="CardNum">控制卡地址,基數為 1,即第一塊控制卡地址為 1</param>
        /// <param name="bWaitToEnd">TRUE 等待節目播放完成再播放下個節目,FALSE 節目播放時間為 iPlayTime</param>
        /// <param name="iPlayTime">節目播放時間,單位為秒</param>
        /// <returns>節目索引號</returns>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern int User_AddProgram(int CardNum, Boolean bWaitToEnd, int iPlayTime);
        /// <summary>
        /// 刪除一個節目
        /// </summary>
        /// <param name="CardNum">控制卡地址,基數為 1,即第一塊控制卡地址為 1</param>
        /// <param name="iProgramIndex">節目索引號</param>
        /// <returns>0-刪除失敗,1-刪除成功</returns>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern bool User_DelProgram(int CardNum, int iProgramIndex);
        /// <summary>
        /// 刪除所有節目
        /// </summary>
        /// <param name="CardNum">控制卡地址,基數為 1,即第一塊控制卡地址為 1</param>
        /// <returns>0-刪除失敗,1-刪除成功</returns>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern bool User_DelAllProgram(int CardNum);
        /// <summary>
        /// 添加文本區
        /// </summary>
        /// <param name="CardNum">控制卡地址,基數為 1,即第一塊控制卡地址為 1</param>
        /// <param name="pText">文本參數表指針,參考【參數表】中 9</param>
        /// <param name="iProgramIndex">節目索引號</param>
        /// <returns>-1-添加文本區失敗,非-1-分區編號</returns>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern int User_AddText(int CardNum, ref User_Text pText, int iProgramIndex);
        /// <summary>
        /// 添加單行文本區
        /// </summary>
        /// <param name="CardNum">控制卡地址,基數為 1,即第一塊控制卡地址為 1</param>
        /// <param name="pSingleText">單行文本參數表指針,參考【參數表】中 8</param>
        /// <param name="iProgramIndex">節目索引號</param>
        /// <returns>-1-添加單行文本區失敗,非-1-分區編號</returns>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern int User_AddSingleText(int CardNum, ref User_SingleText pSingleText, int iProgramIndex);
        /// <summary>
        /// 添加圖文區
        /// </summary>
        /// <param name="CardNum">控制卡地址,基數為 1,即第一塊控制卡地址為 1</param>
        /// <param name="pBmp">圖文區參數表指針,參考【參數表】中 7</param>
        /// <param name="iProgramIndex">節目索引號</param>
        /// <returns>-1-添加圖文區失敗,非-1-分區編號</returns>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern int User_AddBmpZone(int CardNum, User_Bmp pBmp, int iProgramIndex);
        /// <summary>
        /// 指定圖像句柄添加圖片
        /// </summary>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern bool User_AddBmp(int CardNum, int iBmpPartNum, IntPtr hBitmap, ref User_MoveSet pMoveSet, int iProgramIndex);
        /// <summary>
        /// 指定圖像路徑添加圖片
        /// </summary>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern bool User_AddBmpFile(int CardNum, int iBmpPartNum, string strFileName, ref User_MoveSet pMoveSet, int iProgramIndex);
        /// <summary>
        /// 添加時間區
        /// </summary>
        /// <param name="CardNum">控制卡地址,基數為 1,即第一塊控制卡地址為 1</param>
        /// <param name="pdateTime">時間參數表指針,參考【參數表】中 6</param>
        /// <param name="iProgramIndex">節目索引號</param>
        /// <returns>-1-添加時間區失敗,非-1-分區編號</returns>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern int User_AddTime(int CardNum, ref User_DateTime pdateTime, int iProgramIndex);
        /// <summary>
        /// 添加倒計時區
        /// </summary>
        /// <param name="CardNum">控制卡地址,基數為 1,即第一塊控制卡地址為 1</param>
        /// <param name="pTimeCount">倒計時參數表指針,參考【參數表】中 4</param>
        /// <param name="iProgramIndex">節目索引號</param>
        /// <returns>-1-添加計時區失敗,非-1-分區編號</returns>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern int User_AddTimeCount(int CardNum, User_Timer pTimeCount, int iProgramIndex);
        /// <summary>
        /// 添加溫度區
        /// </summary>
        /// <param name="CardNum">控制卡地址,基數為 1,即第一塊控制卡地址為 1</param>
        /// <param name="pTemperature">溫度參數表指針,參考【參數表】中 5</param>
        /// <param name="iProgramIndex">節目索引號</param>
        /// <returns>-1-添加溫度區失敗,非-1-分區編號</returns>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern int User_AddTemperature(int CardNum, User_Temperature pTemperature, int iProgramIndex);
        /// <summary>
        /// 添加 RTF 文件區
        /// </summary>
        /// <param name="CardNum">控制卡地址,基數為 1,即第一塊控制卡地址為 1</param>
        /// <param name="pRTFt">RTF 文件參數表指針,參考【參數表】中 10</param>
        /// <param name="iProgramIndex">節目索引號</param>
        /// <returns>-1-添加文本區失敗,非-1-分區編號</returns>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern int User_AddRTF(int CardNum, User_RTF pRTFt, int iProgramIndex);
        /// <summary>
        /// 向控制器發送數據
        /// </summary>
        /// <param name="CardNum">控制卡地址,基數為 1,即第一塊控制卡地址為 1</param>
        /// <returns>FALSE - 發送失敗,TRUE - 發送成功</returns>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern bool User_SendToScreen(int CardNum);
        #endregion

        #region 2.實時發送數據(高頻率發送)
        //實時建立連接
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern bool User_RealtimeConnect(int CardNum);
        //實時關閉連接
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern bool User_RealtimeDisConnect(int CardNum);
        //實時發送圖片數據
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern bool User_RealtimeSendData(int CardNum, int x, int y, int iWidth, int iHeight, IntPtr hBitmap);
        //實時發送圖片文件
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern Boolean User_RealtimeSendBmpData(int CardNum, int x, int y, int iWidth, int iHeight, string strFileName);
        //實時發送文本
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern Boolean User_RealtimeSendText(int CardNum, int x, int y, int iWidth, int iHeight, string strText, ref User_FontSet pFontInfo);
        //實時發送清屏
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern Boolean User_RealtimeScreenClear(int CardNum);
        #endregion

        #region 3.顯示屏控制函數組
        /// <summary>
        /// 校正時間
        /// </summary>
        /// <param name="CardNum">控制卡地址,基數為 1,即第一塊控制卡地址為 1</param>
        /// <returns>FALSE - 板卡校正時間失敗,TRUE - 板卡校正時間成功</returns>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern Boolean User_AdjustTime(int CardNum);
        /// <summary>
        /// 打開顯示屏
        /// </summary>
        /// <param name="CardNum">控制卡地址,基數為 1,即第一塊控制卡地址為 1</param>
        /// <returns>FALSE - 打開顯示屏失敗,TRUE - 打開顯示屏成功</returns>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern bool User_OpenScreen(int CardNum);
        /// <summary>
        /// 關閉顯示屏
        /// </summary>
        /// <param name="CardNum">控制卡地址,基數為 1,即第一塊控制卡地址為 1</param>
        /// <returns>FALSE - 關閉顯示屏失敗,TRUE - 關閉顯示屏成功</returns>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern bool User_CloseScreen(int CardNum);
        /// <summary>
        /// 亮度調節
        /// </summary>
        /// <param name="CardNum">控制卡地址,基數為 1,即第一塊控制卡地址為 1</param>
        /// <param name="iLightDegreen">屏幕亮度值</param>
        /// <returns></returns>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern Boolean User_SetScreenLight(int CardNum, int iLightDegreen);
        /// <summary>
        /// Reload參數文件
        /// </summary>
        /// <param name="strEQ2008_Dll_Set_Path"></param>
        [DllImport("EQ2008_Dll.dll", CharSet = CharSet.Ansi)]
        public static extern void User_ReloadIniFile(string strEQ2008_Dll_Set_Path);
        #endregion

        [DllImport("gdi32.dll")]
        public static extern bool DeleteObject(IntPtr hObject);
    }
}
View Code

    EQ2008_Dll_Set.ini是LED屏幕的通信的配置文件,在屏幕初始化之前就要存在,可手動配置好放至程序運行的根目錄,為了可復用性,在此將其在程序配置【通信地址(ip),端口號(port),屏幕大小(screenHeight,screenWidth),單雙色(colorStyle),控制卡型號(cardType)】,在程序運行前(即Program.cs文件中動態生成EQ2008_Dll_Set.ini文件)

var screens = BLL.Common.DataSetCache.Screens;
            foreach (var screen in screens)
            {
                if (screen.screenType == Setting.屏幕類型.主控屏)
                    ServiceCloud.Devices.Led.EQ2008.LedController.Register(CardType.EQ2023, ScreenColorStyle.Multicolor, 224, 1024, screen.ip, 5005);
                if (screen.screenType == Setting.屏幕類型.分裝區屏)
                    ServiceCloud.Devices.Led.EQ2008.LedController.Register(CardType.EQ2023, ScreenColorStyle.Multicolor, 192, 192, screen.ip, 5005);
                if (screen.screenType == Setting.屏幕類型.配發區屏)
                    ServiceCloud.Devices.Led.EQ2008.LedController.Register(CardType.EQ2023, ScreenColorStyle.Multicolor, 64, 384, screen.ip, 5005);
            }
            ServiceCloud.Devices.Led.EQ2008.LedController.Initialize();
View Code

    在生成控制卡的通信配置文件以后再程序里面(如下圖)

通過點擊開始連接按鈕(按鈕事件如下)

 private void OpenConnect()
        {
            try
            {
                var index = 0;
                var screenNumbers = GetCheckValues(false);
                if (screenNumbers.Count <= 0)
                {
                    MessageBoard.Error(this, "請先勾選您所要操作的LED屏");
                    return;
                }
                foreach (var screenNumber in screenNumbers)
                {
                    var screenModel = DataSetCache.Screens.FirstOrDefault(o => o.number == screenNumber);
                    var ledBasics = DataSetCache.LedBasics.FirstOrDefault(o => o.ScreenModel.ip == screenModel.ip);
                    if (ledBasics.ScreenState == EnumScreenState.Open)
                        continue;

                    if (!ledBasics.ScreenModel.ip.PingIp())
                    {
                        var message = string.Format("{0}-啟動失敗!可能原因:未找到當前屏幕的通信地址,請檢查當前屏幕網絡通信。", ledBasics.ScreenModel.name);
                        MSGLSBOX(message);
                        Logger.Error(message);
                        continue;
                    }
                    var controller = ServiceCloud.Devices.Led.EQ2008.LedController.GetFromIP(ledBasics.ScreenModel.ip);
                    if (controller == null)
                    {
                        var message = string.Format("{0}-啟動失敗!可能原因:屏幕初始化失敗。", ledBasics.ScreenModel.name);
                        MSGLSBOX(message);
                        Logger.Error(message);
                        continue;
                    }
                    else if (!controller.Open())
                    {
                        var message = string.Format("{0}-啟動失敗!可能原因:屏幕打開失敗。", ledBasics.ScreenModel.name);
                        MSGLSBOX(message);
                        Logger.Error(message);
                        continue;
                    }
                    else
                    {
                        ledBasics.ScreenState = EnumScreenState.Open;
                        if (ledBasics.ScreenModel.screenType == Setting.屏幕類型.主控屏)
                        {
                            ledBasics.LedThread = new Thread(new ParameterizedThreadStart(LedMainDrive));
                            ledBasics.LedThread.Start(ledBasics);
                        }
                        else if (ledBasics.ScreenModel.screenType == Setting.屏幕類型.分裝區屏)
                        {
                            ledBasics.LedThread = new Thread(new ParameterizedThreadStart(LedPackingDrive));
                            ledBasics.LedThread.Start(ledBasics);
                        }
                        else if (ledBasics.ScreenModel.screenType == Setting.屏幕類型.配發區屏)
                        {
                            if (index == 0)
                                ledBasics.LedThread = new Thread(new ParameterizedThreadStart(LedDistributionDriveN4_1));
                            if (index == 1)
                                ledBasics.LedThread = new Thread(new ParameterizedThreadStart(LedDistributionDriveN4_2));
                            if (index == 2)
                                ledBasics.LedThread = new Thread(new ParameterizedThreadStart(LedDistributionDriveN4_3));
                            index++;
                            ledBasics.LedThread.Start(ledBasics);
                        }
                        else
                            MessageBoard.Error(this, string.Format("未識別{0}的屏幕類型", ledBasics.ScreenModel.name));
                    }
                }
                RefreshScreenList();
            }
            catch
            {
                throw;
            }
        }
View Code

通過點擊斷開連接按鈕(按鈕事件如下)

private void CloseConnect()
        {
            try
            {
                var screenNumbers = GetCheckValues(false);
                if (screenNumbers.Count <= 0)
                {
                    MessageBoard.Error(this, "請先勾選所要操作的LED屏");
                    return;
                }

                foreach (var screenNumber in screenNumbers)
                {
                    var screenModel = DataSetCache.Screens.FirstOrDefault(o => o.number == screenNumber);
                    var ledBasics = DataSetCache.LedBasics.FirstOrDefault(o => o.ScreenModel == screenModel);
                    var controller = ServiceCloud.Devices.Led.EQ2008.LedController.GetFromIP(ledBasics.ScreenModel.ip);
                    if (controller.Close())
                    {
                        if (ledBasics.LedThread != null)
                        {
                            Thread.Sleep(1000);
                            ledBasics.LedThread.Abort();
                            ledBasics.LedThread.Join();
                        }
                        ledBasics.ScreenState = EnumScreenState.Close;
                        RefreshScreenList();
                        MessageBoard.Info(this, "已成功關閉連接!");
                    }
                    else
                        MSGLSBOX(string.Format("{0} 連接關閉失敗。", ledBasics.ScreenModel.name));
                }
            }
            catch
            {
                throw;
            }
        }
View Code

因為當前項目需要控制多個LED屏幕,所以此處采取獨立線程去分別控制顯示,以下是一個線程內的控制通信的代碼

public void LedPackingDrive(object source)
        {

            while (true)
            {
                try
                {
                    var ledBasics = source as LedBasics;
                    var packingScreenTwoSwitchingTime = Sys_SystemInfoManager.packingScreenTwoSwitchingTime * 2;
                    var packingScreenOneSwitchingTime = Sys_SystemInfoManager.packingScreenOneSwitchingTime * 2;
                    this.LedControllerForPackingBasic = ServiceCloud.Devices.Led.EQ2008.LedController.GetFromIP(ledBasics.ScreenModel.ip);
                    this.LedControllerForPacking = new LedController.LedControllerForPacking(this.LedControllerForPackingBasic);
                    if (indexForPacking <= packingScreenTwoSwitchingTime)
                        SendToPackingLed(ledBasics, false);
                    else if (indexForPacking > packingScreenTwoSwitchingTime &&
                             indexForPacking < packingScreenTwoSwitchingTime + packingScreenOneSwitchingTime)
                        SendToPackingLed(ledBasics, true);
                    else if (indexForPacking >= packingScreenTwoSwitchingTime + packingScreenOneSwitchingTime)
                    {
                        indexForPacking = 0;
                        continue;
                    }
                    indexForPacking++;
                    Thread.Sleep(500);
                }
                catch (System.Exception ex)
                {
                    Logger.Error(ex);
                }
            }
        }
        private void SendToPackingLed(LedBasics ledBasics, bool isSecondPages)
        {
            try
            {
                var dataItem = new LedController.LedControllerForPacking.ScreenDataItemForPacking();

                List<Obj_TaskManager> tasksForLackMaterial;
                var tasksForAll = ledBasics.Tasks;

                tasksForLackMaterial = (from task in tasksForAll
                                        where (task.taskState == Setting.作業狀態.待執行 || task.taskState == Setting.作業狀態.分揀中) &&
                                               task.completeKit == Setting.齊套狀態.缺料
                                        select task).OrderBy(o => o.sequence).ToList();

                if (tasksForLackMaterial.Count > 0)
                {
                    dataItem.WorkNumber1 = tasksForLackMaterial[0].workNumber;
                    dataItem.Line1 = tasksForLackMaterial[0].line;

                    dataItem.WorkNumber2 = tasksForLackMaterial.Count > 1 ? tasksForLackMaterial[1].workNumber : "No Task";
                    dataItem.Line2 = tasksForLackMaterial.Count > 1 ? tasksForLackMaterial[1].line : "No Task";

                    var currentTaskChildMaterialCount1 = tasksForLackMaterial[0].CurrentTaskChildMaterialCount.Select(o => string.Format("{0}{1}", RemoveMaterialMemoEnglish(o.childMaterialMemo), o.childMaterialCount)).ToArray().Join(",");
                    if (scroll_Packing1 >= currentTaskChildMaterialCount1.Length)
                    { dataItem.ScrollContent1 = currentTaskChildMaterialCount1; scroll_Packing1 = 0; }
                    else
                    { dataItem.ScrollContent1 = currentTaskChildMaterialCount1.Substring(scroll_Packing1, currentTaskChildMaterialCount1.Length - scroll_Packing1); scroll_Packing1++; }

                    if (tasksForLackMaterial.Count > 1)
                    {
                        var currentTaskChildMaterialCount2 = tasksForLackMaterial[1].CurrentTaskChildMaterialCount.Select(o => string.Format("{0}{1}", RemoveMaterialMemoEnglish(o.childMaterialMemo), o.childMaterialCount)).ToArray().Join(",");
                        if (scroll_Packing2 >= currentTaskChildMaterialCount2.Length)
                        { dataItem.ScrollContent2 = currentTaskChildMaterialCount2; scroll_Packing2 = 0; }
                        else
                        { dataItem.ScrollContent2 = currentTaskChildMaterialCount2.Substring(scroll_Packing2, currentTaskChildMaterialCount2.Length - scroll_Packing2); scroll_Packing2 = scroll_Packing2 + 2; }
                    }

                    if (isSecondPages)
                        this.LedControllerForPacking.SendToScreen(dataItem, EnumScreenPackingType.ScreenDataForScrollContent);
                    else
                        this.LedControllerForPacking.SendToScreen(dataItem, EnumScreenPackingType.ScreenImageForTask);
                }
                else
                    this.LedControllerForPacking.SendToScreen(dataItem, EnumScreenPackingType.ScreenImageForNoTask);
            }
            catch
            {
                throw;
            }
        }
View Code

其中

this.LedControllerForPacking.SendToScreen(dataItem, EnumScreenPackingType.ScreenImageForNoTask);

就是往控制卡(屏幕)中發送數據。此處只是簡單的介紹下開發包的使用,以及簡單設計。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM