2015/1/30

【PetaLinux】設定自動登入

PetaLinux預設要由使用者輸入帳號密碼登入後才能進行系統操作,但很多時候在嵌入式裝置應用上會希望能夠開機完成後能自動登入並執行後續指令功能。要設定自動登入主要就是修改/etc/inittab這個檔案,只要把修改後的inittab檔案塞進Root File System中即可完成。

首先使用開發套件產生一個安裝開發樣版
1
petalinux-create -t apps --template install --name autostart
這會在開發目錄components/apps下產生一個名為autostart的樣板資料夾
inittabautologin.sh檔案放到autostart資料夾中

接著修改Makefile
1
2
3
4
5
6
7
8
install:
 # Please add commands below the comments to install data to target file system.
 # Use $(TARGETINST) to copy data into the target
 # E.g. there is data/acos_install in the current directory, and I want to
 # copy it into the target "/" directory:
 #$(TARGETINST) -d data/acos_install /acos_install
 $(TARGETINST) -d -p 0755 autologin.sh /home/autologin.sh
 $(TARGETINST) -d -p 0755 inittab /etc/inittab

回到開發環境最上層資料夾
1
petalinux-config -c rootfs
進入Root File System編譯選單鉤選autostart安裝選項並存檔離開
執行編譯
1
petalinux-build

最後將在images/linux目錄下的image.ub複製到SD Card中取代原本檔案即可。

Keyword: How to set auto login for PetaLinux, Push files into root file system

2015/1/28

【Ubuntu】切換預設shell為bash

  Ubuntu基於效能等因素從6.10版以後將預設執行的shell由bash改為dash,最近要編譯PetaLinux在很前面步驟就錯誤了,從Log看不出點蛛絲馬跡,後來將預設的shell改為bash後一切就沒問題了!
  修改指令:
1
sudo dpkg-reconfigure dash
跳出選單選擇no即可完成修改。

參考文件:DashAsBinSh

2015/1/15

【Ubuntu】 開機自動登入Console

在Ubuntu上要設定開機後自動登入Console只需要三個步驟即可完成
  1. 安裝虛擬終端機程式mingetty
    1
    2
    sudo apt-get update
    sudo apt-get install mingetty
    
  2. 修改開機到文字介面
    1
    sudo vi /etc/default/grub
    
    GRUB_CMDLINE_LINUX_DEFAULT設定值改為text(原本是quiet splash

    設定完成後更新grub
    1
    sudo update-grub
    
  3. 設定自動登入
    1
    sudo vi /etc/init/tty1.conf
    
    exec /sbin/getty -8 38400 tty1修改成exec /sbin/mingetty --autologin root tty1即可
完成上述三個步驟,重新開機後就可以看到系統開啟文字終端機並且以root帳號自動登入,若要改成其他帳號登入,可將第三步驟的root改成對應帳號名稱。

2015/1/7

【C#】重導向(Output Redirection)判斷

參考下面這段程式
1
2
3
4
5
6
7
8
class Program
{
    static void Main(string[] args)
    {
        Console.SetCursorPosition(36, Console.CursorTop);
        Console.WriteLine("Hello World");
    }
}
這段程式能將Hello World印在終端機(Terminal)的行中央,但如果今天使用者使用了重導向將輸出串流導向檔案時,則會看到System.IO.IOException的錯誤例外訊息
Google上找到有人寫了一個ConsoleEx類別可以判斷使用者是否使用了重導向輸出將結果寫到檔案。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static class ConsoleEx
{
    public static bool IsOutputRedirected
    {
        get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stdout)); }
    }
    public static bool IsInputRedirected
    {
        get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stdin)); }
    }
    public static bool IsErrorRedirected
    {
        get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stderr)); }
    }
    private enum FileType { Unknown, Disk, Char, Pipe };
    private enum StdHandle { Stdin = -10, Stdout = -11, Stderr = -12 };
    [DllImport("kernel32.dll")]
    private static extern FileType GetFileType(IntPtr hdl);
    [DllImport("kernel32.dll")]
    static extern bool GetFileSizeEx(IntPtr hFile, out long lpFileSize);
    [DllImport("kernel32.dll")]
    private static extern IntPtr GetStdHandle(StdHandle std);
}
若偵測到使用者重導向則跳過Console相關的控制(如SetCursorPosition(), Clear())以避免發生錯誤。
1
2
3
4
5
6
7
8
9
class Program
{
    static void Main(string[] args)
    {
        if (!ConsoleEx.IsOutputRedirected)
            Console.SetCursorPosition(36, Console.CursorTop);
        Console.WriteLine("Hello World");
    }
}

但上述的ConsoleEx類別提供的方法在使用者將結果輸出到NUL時會判斷錯誤
後來上Stackoverflow詢問得到可以使用GetConsoleMode來判斷終端機模式:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Program
{
    private enum StdHandle { Stdin = -10, Stdout = -11, Stderr = -12 };
    [DllImport("kernel32.dll")]
    private static extern IntPtr GetStdHandle(StdHandle std);
    [DllImport("kernel32.dll")]
    [System.Runtime.Versioning.ResourceExposure(System.Runtime.Versioning.ResourceScope.Process)]
    internal static extern bool GetConsoleMode(IntPtr hConsoleHandle, out int mode);
    public static bool IsRedirected
    {
        get
        {
            int mode;
            GetConsoleMode(GetStdHandle(StdHandle.Stdout), out mode);
            return mode == 0;
        }
    }

    static void Main(string[] args)
    {
        if (!IsRedirected)
            Console.SetCursorPosition(36, Console.CursorTop);
        Console.WriteLine("Hello World");
    }
}

若使用的.Net Framework版本是在4.5以後的話則可以直接使用Console.IsOutputRedirected進行判斷
1
2
3
4
5
6
7
8
9
class Program
{
    static void Main(string[] args)
    {
    if (!Console.IsOutputRedirected)
        Console.SetCursorPosition(36, Console.CursorTop);
        Console.WriteLine("Hello World");
    }
}


Reference:

2015/1/5

【C#】讓使用者動態調整控制元件大小,以按鈕為例

讓控制元件(Control Components,如按鈕、標籤...等)可以供使用者自由調整大小,首先準備一個小圖示提示使用者該元件可以隨心所欲的調整大小。
接著在Form中新增一個按鈕(Button)元件,並命名為button1,將準備好的提示圖片加入button1的Image屬性,並設定ImageAlign為BottomRight,讓提示圖片顯示在按鈕的右下角。
在Form類別中加入成員屬性
1
private bool resize = false;
最後註冊按鈕的MouseMove事件即可:
在MouseMove事件中加入下列程式碼
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void button1_MouseMove(object sender, MouseEventArgs e)
{
    Button btn = (Button)sender;
    if (e.Button == MouseButtons.Left && resize)
    {
        btn.Width = e.X;
        btn.Height = e.Y;
    }
    else
    {
        Point pt = btn.PointToClient(Control.MousePosition);
        if (pt.X > btn.Width - 5 && pt.Y > btn.Height - 5)
        {
            btn.Cursor = Cursors.SizeNWSE;
            resize = true;
        }
        else
        {
            btn.Cursor = Cursors.Default;
            resize = false;
        }
    }
}
首先判斷滑鼠移入控制元件範圍時resize變數是否已經被設定並且滑鼠左鍵有被按壓,先看else(resize變數還未設定這邊),用Control.MousePosition取得游標在螢幕的座標位置並運用button1的成員函數PointToClient算出游標在button1中的座標,判斷若游標靠近右下角5個畫素點的話就把游標圖示改成調整大小的游標圖示並將resize變數設定為true開啟調整大小的功能,否則將游標還原成預設圖示。
  接著看if區塊,只要符合調整大小的要素,就把按鈕的寬高分別指定為e.X與e.Y即可。

【C#】讓控制元件可在視窗中自由移動,以按鈕為例

  想讓控制元件(Control Component,如:按鈕、標籤...等)可以在視窗中自由移動只需要註冊MouseDown與MouseMove兩個事件並加入一些程式碼即可達成:
  1. 首先在Form中加入一個按鈕,在此範例名稱設定為button1
  2. 在Form類別中增加一個成員屬性
    private Point mouse_offset;
    
  3. 註冊button1的MouseDown事件,加入下面程式碼記錄滑鼠點擊位置(此位置是以按鈕左上角為原點的座標)
    private void button1_MouseDown(object sender, MouseEventArgs e)
    {
        mouse_offset = new Point(-e.X, -e.Y);
    }
    
  4. 註冊button1的MouseMove事件,加入下面程式碼
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    private void button1_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            Button btn = (Button)sender;
            Point mousePos = PointToClient(Control.MousePosition);
            mousePos.Offset(mouse_offset.X, mouse_offset.Y);
            btn.Location = mousePos;
        }
    }
    
    Control.MousePosition可以取得滑鼠在螢幕中的座標值,但因按鈕是附著於Form視窗,因此必須使用PointToClient方法把螢幕做標值轉換為Form視窗中的座標值。
    使用者可能是點擊按鈕左上角以外的位置,因此需使用第七行做Offset修正,否則移動放開後按鈕總會落在滑鼠的右下方。

2015/1/1

【C#】製作不規則形狀的控制元件,以按鈕為例

Custom Button, Irregularly shaped control
製作一個不規則的控制元件(Non-rectangular Controls)相對不規則視窗較為複雜一點,但也只是要自己多敲一些代碼而已,在示範中會運用GraphicsPath類別與控制元件的Paint事件來製作一對鬥雞眼按鈕:
  1. 首先在Form中加入一個按鈕(Button)元件,在此把該按鈕命名為CustomButton,並把Text顯示文字清空(清空文字只是為了讓外觀較為乾淨,若有需要可以設定要顯示的文字內容),按鈕大小設定為100x50
  2. 幫此按鈕註冊Paint事件,在此事件中運用GraphicsPath生成一個物件並設定欲顯示圖樣路徑,最將此物件指定給按鈕的Region屬性即可。
    private void CustomButton_Paint(object sender, PaintEventArgs e)
    {
        System.Drawing.Drawing2D.GraphicsPath myGraphicsPath = new System.Drawing.Drawing2D.GraphicsPath();
        myGraphicsPath.AddEllipse(new Rectangle(0, 0, 50, 50));
        myGraphicsPath.AddEllipse(new Rectangle(30, 35, 10, 10));
        myGraphicsPath.AddEllipse(new Rectangle(50, 0, 50, 50));
        myGraphicsPath.AddEllipse(new Rectangle(60, 35, 10, 10));
        CustomButton.BackColor = Color.Brown;
        CustomButton.FlatStyle = FlatStyle.Flat;
        CustomButton.FlatAppearance.BorderSize = 0;
        CustomButton.Region = new Region(myGraphicsPath);
    }
    
補充:

  1. GraphicsPath內建多種預設圖形,如:圓形、舉行、三角形,甚至是文字等,因此可以輕易透過疊加方式繪出各種客製化的形狀。
  2. 在GraphicsPath中的圖形疊加具有互斥或的效果,意思是如果兩個圖案有重疊到的區域會呈現挖空效果,但如果又有第三張圖片重疊上去,則三張圖片重疊的區域會被顯示。