2016/04/10

Arduino Yún:Bridge程式庫入門之Process

嘗試使用Bridge程式庫的Process,可要求執行某程式或Linux命令列模式的指令,底下程式碼會執行uptime指令,得知系統開機後已經過多少時間,然後執行curl,以參數指定某網址,取回以ASCII畫出來的Arduino logo。

#include <Process.h>

void setup() {
    Bridge.begin();
    Serial.begin(56700);

    while(!Serial){
    }

    run_uptime();
    run_curl();
}
void loop() {
}
void run_curl() {
    Process p;
    p.begin("curl"); // Linux指令
    p.addParameter("http://arduino.cc/asciilogo.txt"); // 加上參數
    p.run(); // 執行,這是阻斷式方法,執行結束後才會回傳

    while(p.available() > 0){ // 將指令執行結果送往序列埠監控視窗
        char c = p.read();
        Serial.print(c);
    }
    Serial.flush();
}
void run_uptime(){
    Process p;
    p.begin("uptime");
    p.run();

    while(p.available() > 0){
        char c = p.read();
        Serial.print(c);
    }
    Serial.flush();
}

結果如下圖:

接著試試Process的各種方法,秀出Yun的CPU資訊以及Wi-Fi連線狀態,底下這支草稿碼,可從序列埠輸入數字1到6,分別會以不同方式執行指令:

#include <Process.h>

void setup() {
    Bridge.begin();
    Serial.begin(56700);

    while(!Serial){
    }

}
void loop() {
    if(Serial.available() > 0){
        int b = Serial.read();
        Process p;
       
        switch(b){
            case '1':
                p.begin("cat");
                p.addParameter("/proc/cpuinfo");
                p.run();
            break;
            case '2': // 注意!

                p.begin("cat /proc/cpuinfo");
                p.run();
            break;
            case '3':
                p.runShellCommand("cat /proc/cpuinfo");
            break;
            case '4':
                p.runShellCommand("iw dev wlan0 station dump");
            break;
            case '5':
                p.runShellCommand("/usr/bin/pretty-wifi-info.lua");
            break;
            case '6':
                p.runShellCommand("/usr/bin/pretty-wifi-info.lua | grep Signal");
            break;
        }
       
        while(p.available() > 0){
            Serial.print((char) p.read());
        }
        Serial.flush();
    }
}


其中2的p.begin("cat /proc/cpuinfo");將會失敗,因為若以begin起始指令,須以addParameter加入參數,Process會以特殊字元分隔。至於若使用runShellCommand的話,會把整行指令丟給shell(ash),由它處理。

以上都是同步執行方式執行,意思是說,指令需完全執行完畢,才會回傳。

接下來試試非同步的呼叫方式,
#include  <Process.h>

void setup() {
    Bridge.begin();
    Serial.begin(57600);

    while(!Serial){
    }
}

Process p; // 注意,Process是全域變數

void loop() {
    if(Serial.available() > 0){ // 在序列埠監控視窗隨便輸入些什麼東西
        int b = Serial.read();
        switch(b){
            case '1':
                p.begin("cat");
                p.addParameter("/proc/cpuinfo");
                p.runAsynchronously();
            break;
            case '2':
                p.runShellCommandAsynchronously("uptime");
            break;
        }
    }

    if(!p.running()){
        while(p.available() > 0){
            char c = p.read();
            Serial.print(c);
        }
    }
    Serial.flush();
}


以runAsynchronously或runShellCommandAsynchronously來執行指令,然後以running判斷是否執行完畢。

其實run的底層會去呼叫runAsynchronously,裡頭同樣會利用running作判斷,完成後才回傳。而runShellCommand的底層會去呼叫runShellCommandAsynchronously,同樣會利用running作判斷。有ShellCommand字樣的方法,會再指定shell(ash)罷了。

使用非同步方法時,有不少地方需要注意,若把Process p;放在函式裡成為區域變數,那麼當指令尚未完成、p就會消失不見;而且若每次進入loop就呼叫begin("uptime"),begin不僅會設定新的指令,也會呼叫close結束上次的指令,所以上次指令尚未執行完成就被結束了。


參考資料:

No comments:

Post a Comment