首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Sun SPOT 實戰:打造持續集成構建監視器——從金絲雀靈感到無線 LED 可視化

     編輯:Java 相關知識

靈感來源:礦井金絲雀與構建監控

早期礦工攜帶金絲雀下井,鳥對毒氣敏感,倒斃即撤離信號。軟件項目同樣需要「高可視、即時、無需查郵箱」的構建狀態指示器。本文記錄如何利用 Sun SPOT (Small Programmable Object Technology) 構建無線構建監視器,集成 CruiseControl 持續集成系統。

Sun SPOT 硬體概覽

系統架構

[CruiseControl 構建服務器] 
      │ (USB) 
[基站 SPOT] ←→ 無線 802.15.4 → [遠程 SPOT (監視器)]
      │
   [CanaryHandler Java SE 應用]
  1. CruiseControl 輪詢 SVN,觸發 Maven 構建
  2. 構建階段變化 (RUNNING/SUCCESS/FAILED) → 調用 CanaryHandler
  3. CanaryHandler 經基站 SPOT 發送無線命令
  4. 遠程 SPOT 運行 BuildCanary MIDlet,解析命令驅動 LED

關鍵代碼實現

1. CanaryHandler (構建服務器端)


public class CanaryHandler {
    public static void main(String[] args) throws IOException {
        // 解析參數: --running/--failed/--success --spot "0014.4F01.xxxx.yyyy" --port 100 --serial COM4
        CommandLineParser parser = new PosixParser();
        Options options = buildOptions();
        CommandLine cmd = parser.parse(options, args);
        
        String spotAddr = cmd.getOptionValue("spot");
        String port = cmd.getOptionValue("port");
        String connStr = "radiostream://" + spotAddr + ":" + port;
        System.setProperty("SERIAL_PORT", cmd.getOptionValue("serial"));
        
        StreamConnection conn = (StreamConnection) Connector.open(connStr);
        DataOutputStream dos = conn.openDataOutputStream();
        DataInputStream dis = conn.openDataInputStream();
        
        String msg = cmd.hasOption("running") ? "RUN" :
                     cmd.hasOption("failed") ? "FAIL" : "SUCCESS";
        dos.writeUTF(msg);
        dos.flush();
        System.out.println("SPOT 回應: " + dis.readUTF());
        conn.close();
    }
}

2. BuildCanary (遠程 SPOT MIDlet)


public class BuildCanary extends MIDlet {
    private RadiostreamConnection conn;
    private DataInputStream dis;
    private DataOutputStream dos;
    private Thread colourThread;
    private SetColour setColour;

    protected void startApp() { new Thread(this::updateBuildStatus).start(); }

    private void updateBuildStatus() throws IOException {
        // 就緒指示:全白
        setColour(LEDColor.WHITE, "");
        
        String baseAddr = getAppProperty("BaseStationAddress");
        String port = getAppProperty("PortNumber");
        conn = (RadiostreamConnection) Connector.open("radiostream://" + baseAddr + ":" + port);
        dis = conn.openDataInputStream();
        dos = conn.openDataOutputStream();
        
        while (true) {
            String status = dis.readUTF();  // 阻塞等待命令
            if ("RUN".equals(status)) setColour(LEDColor.BLUE, status);      // 藍色流光
            else if ("SUCCESS".equals(status)) setColour(LEDColor.GREEN, status); // 綠色常亮
            else if ("FAIL".equals(status)) setColour(LEDColor.RED, status);    // 紅色閃爍
            else throw new IllegalArgumentException("Unknown: " + status);
            dos.writeUTF("Updated to " + status);
            dos.flush();
        }
    }

    private void setColour(LEDColor color, String status) {
        if (colourThread != null) colourThread.interrupt();
        setColour = new SetColour(color, status);
        colourThread = new Thread(setColour);
        colourThread.start();
    }

    // 內部類:驅動 8 個 LED
    class SetColour implements Runnable {
        private final ITriColorLED[] leds = EDemoBoard.getInstance().getLEDs();
        private final LEDColor color;
        private final String status;
        
        public void run() {
            try {
                if ("RUN".equals(status)) {
                    while (true) {  // 藍色流光
                        for (int i=0; i<8; i++) {
                            leds[i].setColor(color); leds[i].setOn();
                            Thread.sleep(200);
                            leds[i].setOff();
                        }
                    }
                } else if ("FAIL".equals(status)) {
                    while (true) {  // 紅色閃爍
                        for (int i=0; i<8; i++) { leds[i].setColor(color); leds[i].setOn(); }
                        Thread.sleep(250);
                        for (int i=0; i<8; i++) { leds[i].setOff(); }
                        Thread.sleep(250);
                    }
                } else {  // SUCCESS: 綠色常亮
                    for (int i=0; i<8; i++) { leds[i].setColor(color); leds[i].setOn(); }
                }
            } catch (InterruptedException e) { /* 線程切換顏色,正常退出 */ }
        }
    }
}

3. CruiseControl 配置集成 (config.xml)


<property name="javaExecutable" value="C:\jdk\bin\java.exe"/>
<property name="workingDir" value="C:\CanaryHandler\dist"/>
<property name="libPath" value="-Djava.library.path=C:\SunSPOT\sdk\lib"/>
<property name="commonArgs" value="${libPath} -jar ${workingDir}\CanaryHandler.jar 
    --spot "0014.4F01.0000.3A19" --port 100 --serial COM4"/>

<project name="ci-build">
    <schedule interval="60">
        <composite>
            <exec command="${javaExecutable}" args="${commonArgs} --running"/>  <!-- 構建開始 -->
            <maven2 pomfile="pom.xml" goal="clean compile"/>
        </composite>
    </schedule>
    <publishers>
        <onsuccess><exec command="${javaExecutable} ${commonArgs} --success"/></onsuccess>
        <onfailure><exec command="${javaExecutable} ${commonArgs} --failed"/></onfailure>
    </publishers>
</project>

運行效果演示

組件規格
主控180MHz Atmel AT91RM9200 SoC
存儲4MB Flash + 512KB 偽靜態 RAM
電源內置鋰電池(3h 連續) / USB / 外接電源
傳感器溫度、光照、三軸加速度計
輸出8 個三色 LED、2 個按鈕
無線IEEE 802.15.4 (2.4GHz)、點對點/多跳
JVMSquawk (幾乎純 Java 實現、裸機運行、CLDC 1.1)
構建階段LED 效果視覺含義
初始化全白監視器就緒待命
構建中 (RUNNING)藍色流光進度進行中,請勿提交衝突代碼
構建失敗 (FAILED)紅色閃爍緊急:有人破壞構建,需立即修復
構建成功 (SUCCESS)綠色常亮穩定:可以安全拉取/部署

技術難點與解決

  • CLDC 限制:無反射、無序列化、無正則、無 Swing、集合僅 Vector/Hashtable/Enumeration → 代碼需精簡,避免標準庫依賴。
  • 無線可靠性:radiostream 協議提供可靠流式連接,類似 TCP,自動重傳。
  • MIDlet 生命周期:startApp() 啟動監聽線程,destroyApp() 釋放連接資源。
  • 基站串口鎖定:Windows 下 COM 口唯一佔用,CruiseControl 串行執行避免衝突。

擴展想像空間

Sun SPOT 社區已實現:火箭遙測教學、樹林火災監測、體感遊戲控制器、農業環境感知網絡。構建監視器只是冰山一角——將軟件狀態映射到物理世界的可視/可觸反饋,是物聯網時代開發者的新邊疆。

總結

用約 200 行 Java 代碼 + 一個 CruiseControl 配置片段,構建了「極客桌面上的持續集成儀表盤」。SPOT 的開源性、Java 原生編程模型、豐富傳感器/执行器,讓軟件工程師能以極低門檻跨越到物理計算領域。下次構建失敗時,看一眼桌上的紅燈閃爍,比郵件通知快得多——這就是金絲雀的現代價值。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved