2016年11月29日 星期二

C# 設定TcpClient連線時的TimeOut

我在設計一個測試主機是否存活的連線方式,通常除了Ping的方式之外,另外一種就是模擬telnet的連線方式,當伺服器的ICMP被關閉時,或是防火牆未開啟ICMP的通道時,Ping Host 就無法成功,但是通常伺服器都會開啟定服務埠來提供外部的服務,例如 Http(80)、DNS(43)、FTP(21)、RDP(3389)、HTTPS(443)、other Http(8080)、1433(SQL)等等。

此時可以透過基本的 Socket Connection 來確定該服務可以連線,基本上若是不存可以連線的埠,則 Connect 會發生拒絕連線的 Exception,但是在透過防火牆後的連線,有可能連拒絕連線的訊息都不會回應,導致 Connection被 Hang住,故在設計 Scoket Connect 時要有 Timeout 的設計,最好可以自己決定 Timeout 時間,但是 Socket 或 TcpClient 都沒有 Connect 的 Timeout 可以去設定,因此我們使用了 BeginConnect 非同步連線 + ManualResetEvent 等待中斷的事件來處理。


using System.Net.NetworkInformation;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;

namespace Test
{
    class tcptool
    {
        //可以取得的回覆訊息
        public string ReplyMessage;
     
        private static bool IsConnectionSuccessful = false;
        private static Exception socketexception;
        private static ManualResetEvent TimeoutEvent = new ManualResetEvent(false);

        public bool connectHost(string sHost, int port , bool onlyTest , int timeoutMS)
        {
            //將執行緒通知事件ManualResetEvent設定為未收到訊號,此時進入的事件會持續執行
            TimeoutEvent.Reset();
            socketexception = null;//清除例外承載物件
            TcpClient tcp = new TcpClient();
            ReplyMessage = "";

            try
            {
                //使用非同步連線方式,當連線完成後會通知CallBackMethod事件
                tcp.BeginConnect(sHost, port, new AsyncCallback(CallBackMethod), tcp);
             
                //進入執行緒等候,指定等候時間,並設定false=不在等候前結束處理程序
                //此時TimeoutEvent會等到被Set()並返回true,或是一直等候時間到期,還沒等到set()指令,就會返回false
                if (TimeoutEvent.WaitOne(timeoutMS , false))
                {
                    if (IsConnectionSuccessful)
                    {
                        //連線成功通知
                        NetworkStream stream = new NetworkStream(tcp.Client);
                        StreamWriter sw = new StreamWriter(stream);

                        sw.WriteLine("Hello");// 將資料寫入緩衝
                        sw.Flush(); // 刷新緩衝並將資料上傳到伺服器

                        if (!onlyTest)
                        {
                            //從伺服器接收的資料
                            StreamReader sr = new StreamReader(stream);
                            ReplyMessage = sr.ReadLine();
                        }
                        else
                        {
                            ReplyMessage = "Test successful!";
                        }
                    }
                    else
                    {
                        //沒有連線成功丟出Exception
                        throw socketexception;
                    }
                }
                else
                {
                    //當等候時間逾時
                    tcp.Close();
                    throw new TimeoutException("Time Out Exception !");
                }
            }
            catch (Exception ex)
            {
                ReplyMessage = " Exception:" + ex.Message;
                return false;
            }
            return true;
        }
        /// <summary>
        /// 當連線完成後,進入此事件處理
        /// </summary>
        /// <param name="asyncresult"></param>
        private static void CallBackMethod(IAsyncResult asyncresult)
        {
            try
            {
                IsConnectionSuccessful = false;
                //檢查回傳物件是否存在(存在代表連線成功)
                TcpClient tcpclient = asyncresult.AsyncState as TcpClient;
                if (tcpclient.Client != null)
                {
                    tcpclient.EndConnect(asyncresult);
                    IsConnectionSuccessful = true;
                }
            }
            catch (Exception ex)
            {
                //發生連線意外
                IsConnectionSuccessful = false;
                socketexception = ex;
            }
            finally
            {
                //通知等候結束
                TimeoutObject.Set();
            }
        }
    }
}

這裡要注意的是,如果只是要測試連線存在與否,必須要設定 onlyTest 為 true ,否則遇到某些伺服器沒有回應資料,可能會讓程式 Hang 在 ReplyMessage = sr.ReadLine(); 這一行上面。

2016年9月1日 星期四

C# PrintDocument的解析度

這次在製作列印文件時,需要繪製圖像與文字

但是每次在PrintDocument列印時,圖像解析度一直始終都是不佳的狀態,
儘管把 Imag 或 Bitmap 繪製的時候把 Resolutions都調高,但在列印時依然沒變好。

後來,反覆研究測試後發現,原來是最終輸出影響了整個列印品質,
可以看下面的成型原因:



為什麼 Graphics 只有 100 DPI?
原因就在於 Graphics 成像時的參考單位是『螢幕』,而一般螢幕都是在 72~96 DPI左右的。

2016年8月31日 星期三

C# 列印純黑白圖像要點

給自己備註的

如果使用的是條碼印表機列印圖像,由於條碼印表機沒有所謂顏色深淺的特性
其不是黑(Black)就是白(non-Black),如果要列印圖像(像是標籤上的LOGO),
圖片若是彩色的情況就會出現像是毛邊的點。

解決的方式就是要將圖片做灰階的二階化(threshold)

下面這個方法可以先產生一個二階化圖像的ImageAttributes:


        static ImageAttributes BWThreshold(Image sourceImage, float ThresholdLevel)
        {
            var gray_matrix = new float[][] {
                new float[] { 0.299f, 0.299f, 0.299f, 0, 0 },
                new float[] { 0.587f, 0.587f, 0.587f, 0, 0 },
                new float[] { 0.114f, 0.114f, 0.114f, 0, 0 },
                new float[] { 0,      0,      0,      1, 0 },
                new float[] { 0,      0,      0,      0, 1 }
            };
            var ia = new System.Drawing.Imaging.ImageAttributes();
            using (Graphics gr = Graphics.FromImage(sourceImage))
            {
                ia.SetColorMatrix(new System.Drawing.Imaging.ColorMatrix(gray_matrix));
                ia.SetThreshold(ThresholdLevel); // Change this threshold as needed
            }
            return ia;
        }


再把這個ImageAttributes丟給DrawImage當成參數輸入,即可繪製。

Image logopic = Image.FromFile(logoFile);
Rectangle logoRect = new Rectangle(10,10,230,120);
Graphics.DrawImage(
     logopic ,
     logoRect ,
     0 ,
     0 ,
     logopic.Width ,
     logopic.Height ,
     GraphicsUnit.Pixel ,
     BWThreshold(logopic,0.8f));

這樣可以把黑白圖像印製的比較清晰。

2016年8月30日 星期二

統一發票列印小程式


因為公司會在一堆系統上都有可能要印發票(真不懂要怎麼搞?)

希望可以有個小工具可以列印電子發票,

原本發票列印程式要使用條碼機專用語言(ZPL、EPL),但容易被某種機型綁定。

當然可以考慮使用ESC/POS指令的方式,但也是要印表機支援這種指令列印模式(當然多數表機都有支援),不過要列印QR碼,就有點不是那麼容易了,除了要自己編碼外還要注意中文問題。

後來我想改用Windows Printer Driver來列印,雖然不如指令式快速,但可以方便各類型程式應用,因此考慮了以下的條件:

使用C#開發、.Net 2.0平台、Console呼叫

本來想用RDLC來做,但是很不幸的,失敗了,原因就在於條碼,
國稅局訂定的Code39條碼內要放入21個字元(19+2)長度,
如果使用RDLC的話,解析度只有100DPI,密度不夠,條碼線條沾黏嚴重。

一般的條碼機至少都有200DPI得等級,這RDLC也太彆腳了吧,
網路上找盡RDLC條整解析度的方式都沒有比較好的效果。

因此,改用直接C#繪製的方式來做,
當然中間為了條碼圖像清晰度的問題花了不少心力解決。

下載點:PrintInvoice

2016年7月6日 星期三

【研究】條碼讀取器的類型

這篇來談談目前所知的條碼讀取器的讀取方式

我們都看過條碼,也看過便利商店、物流士、倉庫管理員等手上都有使用裝置在刷讀條碼,但大部分的人都不見得了解它的讀取原理。

所以我們就簡單以我手上有的設備來介紹幾種常見的條碼讀取方式:

1.筆式(pen):
它是我最早接觸的條碼讀取器,每次都看到操作人員拿著它在條碼上『磨來磨去』挺有趣的。它其實是由LED和光電二級管、透鏡組合而成。
由筆管內LED發射光源到前端(筆尖)的透鏡打到紙面上,然後由紙張的反射(黑色吸光、白色反光)再由透鏡返回內部光電二級管來接收訊號。其實這個原裡你都可以在光學滑鼠上面看到,因為它也是利用這個原裡來偵測移動的。

優點:目前已經想不到了(快被淘汰了,可能某些場合還用得著吧)。
             雖然有改良非接觸型和便攜型,但也快消失了。
缺點:A、在條碼上移動速度必須保持一致,否則會讀不到。
            B、透鏡是直接接觸紙張,所以長時間會磨損,當磨損太嚴重就會無法讀取。
            C、條碼常常會被以磨損的鏡片磨破。
            D、條碼密度不能太高。
            E、無法掃瞄『非反射式』條碼(螢幕)。

2、CCD式:

2016年6月24日 星期五

【研究】列印的條碼為什麼很難刷(掃描)

條碼在我們的世界無處不在,小至發票,大至大型裝置設備都會有它的身影。

每一家有制度化的公司,多少都會需要用到條碼來進行管理,身為開發人員,就很難不會碰到它。

但是我們常常因為不熟悉條碼的規則,而導致作出來的條碼沒辦法被讀取(掃描),也常遇到A設備可以讀取,B設備就無法讀取的奇怪現象,當然讀取設備本身的讀取元件也是有功力上的差別,有些廠商有能力可以調教讀寫元件的設定。

接下來,我就做點實驗給大家知道這個條碼的問題出在哪裡,以便在往後使用條碼時可以更注意到發生的原因。

在這裡我不再重述條碼的來由,這次的比較是使用大家常用的Code39(又稱39碼)來比較。
使用39碼得主要是因為他有字型檔可以使用,可以拿來做比較。

條碼的列印方式分類與優缺:

一、由條碼機(又稱標籤機)內建指令列印
優點:線條清晰,掃描讀取容易、速度快。
            列印特殊紙張(背膠式、連續型.....)
缺點:特殊的指令語言(每一個廠牌都不太一樣),等於換機器就要改寫程式碼。
            有一些貼心的廠商(精聯)會提供比較簡單的統一語言列印工具,減少開發者困擾。
            版面變化較少,沒有視覺化編輯。

二、由Windows Driver列印,或稱普通列印
優點:只要有驅動程式就可以列印,不需要改寫程式(或改寫幅度小)。
           版面彈性比較自由。由於只要有驅動就可以列印,
           所以比較不限定紙張種類,或印表機種類。
缺點:列印線條有很多模糊地帶,沒控制好就會導致無法讀取。
           受到列印裝置解析度限制,匹配沒做好就會失敗。

底下先做出三種情境比較:
雷射印表機:600DPI
條碼印表機(標籤機):203DPI
這裡,我們先比較印表機解析度的列印差異,請忽略機器種類。


2016年6月17日 星期五

簡易條碼產生器2 easy Barcode Genarator

本偏延續上一篇『簡易條碼產生器』的修改版

新增了指令列模式(Console Mode),方便給其它程式呼叫使用

下載位置:https://drive.google.com/drive/folders/0BybxVRTRlzdLbkVFc0JuM3JyS0E
必須有.net 2.0 以上環境(Windows 7以上作業系統不需要)
解壓縮密碼(如果需要):http://radio-idea.blogspot.tw

指令:
usage barcodegenwin.exe [-command:value] ||[-command]
-w,-width : integer value , specified picture width pixeles
-h,-height : integer value , specified picture height pixeles
-bc,-barcode : barcode type , qrcode/pdf417/code39/code128/codabar
                        if codabar the data text should start/end with A,B,C,D charcater,
                        if code39 the data text only accept Arabic number and upper letter
-txt,-text : string value , use data text to genarate barcode
-out,-output : picture file name , specified this file name to save barcode picture,
                   support format  jpeg(jpg)/Bitmap(bmp)/portable network graphics(png)
-s,-silent  keep window invisiable (no popup action)

if width,height,barcode,text,output any one loss or not be accepted , the window will popup


2016年6月16日 星期四

簡易條碼產生器

這是利用ZXing套件開發的,需要自己產生條碼的使用者,可以利用這個程式自己產生。
下載位置:https://drive.google.com/file/d/0BybxVRTRlzdLWUlBeGtKQXFKLVk/view?pref=2&pli=1
多行版本:https://drive.google.com/file/d/0BybxVRTRlzdLV1FQbmcxLUxZWDQ/view?usp=sharing

必須有.net 2.0 以上環境(Windows 7以上作業系統不需要)
解壓縮密碼(如果需要):http://radio-idea.blogspot.tw


可以自製QR碼、PDF417、code 39碼、code 128碼、Codabar碼,並且儲存成圖片檔



2016年5月31日 星期二

如何退出被系統鎖住的外接式磁碟機

適用於Windows 7以上版本

明明都已經把所有程式給關閉了,但是要安全退出USB外接硬碟時,卻一移無法退出。

使用Unlocker、USB Remover等軟體,確是一直提示被『系統』使用中

(這個系統又不是任何外裝軟體也不知道怎麼停止它)

而且,不管使用任何強迫終止程序手段都沒有用!

此時使用Open File View檢查會發現像是下面的東西被『系統』鎖住:

$Extend\$RmMetadata\$TxfLog\$TxfLogContainer00000000000000000001

此時,我測試過最有效的方法就是使用 Diskpart 來處理

先開啟『命令提示字元』,或是到『執行』輸入cmd.exe

注意,如果您的電腦使用權限不是『系統管理員』身分,請切換到管理員身分執行,或是以滑鼠右鍵『以系統管理員身分執行』!

1.輸入 Diskpart,進入工具模式
2.輸入 List Disk,顯示出本機所有磁碟機,這些磁碟機會以1、2、3的編號出現
3.輸入Select Disk n,這個n是你要退出的磁碟機編號
4.輸入 Offline Disk ,則可以退出此磁碟機

範例畫面:

注意!
在這之後,你的USB外接式硬碟再度裝回此部電腦時,可能不會再出現磁碟機代號。

此時可以到『裝置管理員』>『磁碟管理』,會發現這部磁碟機變成了『離線』狀態。


那要如何恢復呢?

有兩種方式:
一、使用磁碟管理,在該硬碟機上按滑鼠右鍵,跳出選單,點擊『連線』項目

二、使用Diskpart管理工具:
  1.輸入 List Disk,顯示出本機所有磁碟機,這些磁碟機會以1、2、3的編號出現
  2.輸入Select Disk n,這個n是你要退出的磁碟機編號
  3.輸入 Online Disk ,則可以重新連接此磁碟機





2016年4月25日 星期一

霹靂燈設計(帶尾) K.I.T.T Scanner Light

這次的霹靂燈製作式為了接下來的霹靂車模型製作的,因為模型比例不大,車體空間又非常小,所以盡量找零件最少的來製作,而且希望使用CR2032當電源。雖然使用PLC是最少,但麻煩的是要Codding,也要一定產量(回想當初我在手機店改裝Motorola CD928的時候,老闆訂PLC粒都是以條為單位的,每條約30顆)。因此對於只需要少少一組的使用者來說,真的不實用。

也許網路上都找得到的霹靂燈套件,最早最傳統的莫過555+74193+74154的電路,但是要做出帶尾效果,加上要塞到模型加上希望使用鈕扣電池,這個74系列的設計完全就出局了,那就更不用說要用8051來設計的霹靂燈了。

而外面買的霹靂燈條大都是汽車用,所以光是電力就out了。

後來在逛電子街的時候看到了祥昌電子的OK-154套件,發現它只使用2顆IC,而且都是MOSFET為主的驅動+40系列IC,而且只需要2顆AAA乾電池。已經非常接近我所需要的規格了;原本套件使用了25顆LED,但實際上只有5組(5組*5顆)而已。所以我便把他做了一點修改(如下圖)。

我把LED改成純5顆,然後在555端的電容器C1旁併上了一顆1uf的電容,以稍微降低一點速度(這個很重要,在接下來的改造都會有很直接的關連了)。

這裡有一件不得不注意到的事,是它們的555震盪器的設計方式真是少見啊!!
居然把output當成discharge來使用,這樣的話就不需要在discharge上裝設一顆電阻(Rn),而頻率公式就從原本的
f = 1 / (0.693 x C x (Rn + 2 x R7))
變成
f = 1 / (0.693 x C x (2 x R7))
而且上下弦波時間也都一樣,真是太棒了!
不過前提是,輸出必須加上覆載電阻,當然電流會變小,不可以直接當成驅動使用,當訊號使用是非常OK的。

霹靂燈帶尾

來說說這個故事吧,當年霹靂遊俠李麥克盛行的年代,LED大燈泡是不存在的,當時的LED真的只是很小的指示燈的燈源而已(亮度不是很夠),所以霹靂車前面的Scanner Light是真的邏輯電路+燈泡帶來的效果,而那個帶尾的效果,很單純的是燈泡熄滅後的餘光Fade out(我的學長就做過)。

直到LED光源近年來大放異彩,取代了燈泡,當然LED的特性就顯現出來的,光源點滅速度極快,就沒了帶尾現象。當然老霹靂迷總會覺得霹靂燈失去了原來的感覺。

因此,接下來再對電路進行改造,讓LED燈有 fade out 現象。
其實這個電路只需要Q1~Q5閘級增加一顆電容器,以便在訊號結束後以放電特性對閘極提供電壓,就可以讓LED產生fade out效果了。

而這個C3~C7,就我的測試結果使用4.7uf、3.3uf、2.2uf都可以的,因為fade out 有時間差,所以如果555的震盪速度太快,則可能造成在兩側燈光反向運行時,前一顆LED燈尚未熄滅,變成光源跑向兩側時,fade out效果不見了的感覺。

底下是我得實際測試影片,可一親身感覺一下有何差異

未改前:
C3~C7使用4.7uf:
C3~C7使用3.3uf:
C3~C7使用2.2uf:

===以下廢文,請斟酌觀賞===

2016年3月20日 星期日

自製簡易混音器

最近因為公司給了一個會場音控的任務而需要用到混音功能,但是市面上的混音器最便宜也要3000左右,而且接頭都不是3.5mm的音源孔,因為我的音樂來源是3部筆電,也不想買一堆轉接頭。公司也沒經費補助的情況下。遂想說手頭還有一些零件與OPA可以利用,所以就自製了簡易的混音器來使用,雖然手邊的OPA不是啥高音質的IC但是拿來撐場面應該綽綽有餘。

先構想一下架構

這個架構前面先用個加法器來完成初級混音,然後再分割耳擴(監聽)與輸出,然後再加個VU表監看輸出量,電力的部分我不想搞雙電源,因為太麻煩了,而且手上有12V/1.2A交換式變壓器,想直接利用。

接下來就準備細分電路了。
第一部分:混音電路(OPA加法器)

第二部份:耳擴與輸出(電路相同)

第三部份:VU表電路

以上參考不少其他網站的電路,但是很多都是設計成雙電源,也因此修改了一些部份設計。

接下來,開始製作電路部份
還是很苦力的用洞洞板來完成,哈!
(因為個人不太想碰藥水)
連接部份都設計成接頭形式方便日後維護。

再來製作外殼,這真是折煞的工作,誤選了鐵殼來製作,下蓋是鋁製比較好施作,上蓋卻是很硬的鐵製品,搞得全身酸痛,光是挖LED排燈的孔就累死了(銼刀一直挫挫挫⋯⋯

內部樣式:
接下來就是要開始連接各VR的電線了(還真是多的不像話啊)

最後蓋上上蓋,完成,GOOD JOB!

背後的樣子

還沒有時間測試,改天再來測試看看。