10 May 2014, 23:16

[edX]Embedded Systems – Shape The World ずっと受けたかった組み込みソフト開発の授業

はじめに

レジスタも触ったことのないニセエセ組込みエンジニアなので、 リアル組込みエンジニアになりたくて、edXで組込み開発の学習をしました。

結果は、途中で挫折しました。全15週の10週目くらいで挫折。 なので、この記事も中途半端な記事になります。

自分はリアル組み込みエンジニアにはなれませんでしたorz.

[toc]

内容

0,1のフリップフロップから電子回路、レジスタへと、基礎からしっかり解説される。 オームの法則とか、忘れた。電子回路は読んで読まないふりをした。

期待していた?電子回路の知識は十分過ぎるほど出てきた。 ADC,DACあたりはほんとうに挫折。

言語はC言語

<div class="outline-text-3" id="text-2-1">
  <p>
    言語はもちろん、C言語だ。補足的にアセンブラ言語もでてくる。楽勝楽勝。
  </p></p>
</div></p>

実践も重視

<div class="outline-text-3" id="text-2-2">
  <p>
    知識的な部分だけではなく、開発プロセスや品質の考え方、デバッグ手法など 実践的な部分も説明される。
  </p>

  <p>
    開発プロセスでは、フローチャートやサブルーチンといった、 手続き型用語が解説されて、やや時代遅れを感じた。
  </p></p>
</div></p>

進め方

講義の流れ

<div class="outline-text-3" id="text-3-1">
  <p>
    イントロダクションとして、2人のコント?から始まる。 動画よりも、文章の方が多め。
  </p>

  <p>
    動画ではとくにパワーポイントは使わずにホワイトボードで解説されるので、 字がきれいでなく読みにくい。
  </p></p>
</div></p>

Labについて

<div class="outline-text-3" id="text-3-2">
  <p>
    講義よりも比重が置かれているのが、Labと呼ばれている実機学習。
  </p>

  <p>
    毎週課題が出されて、それに取り組むことで講義の内容の理解を深める。
  </p>

  <p>
    課題の評価はテストコードで自動でチェックされる。 シミュレータと実機の両方で評価することが求められる。
  </p>

  <p>
    評価ボードは、Texas Instrumentsの EK-LM4F120XLというものを買った。 ネットで注文して購入する必要がある。ARMの Cortex-Mが載っている。
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://www.tij.co.jp/tool/jp/ek-lm4f120xl">Stellaris LM4F120 LaunchPad 評価ボード &#8211; EK-LM4F120XL &#8211; TI ツール・フォルダ</a>
    </li>
  </ul>

  <p>
    開発環境としては、Keil uVision for the ARM, MDK-Lite (32KB) Editionを利用する。 ARMの開発をするためのIDE.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://www.keil.com/uvision/default.asp">µVision IDE &#8211; Overview</a>
    </li>
  </ul>
</div>

<div id="outline-container-sec-3-2-1" class="outline-4">
  <h4 id="sec-3-2-1">
    Lチカ
  </h4>

  <div class="outline-text-4" id="text-3-2-1">
    <iframe width="560" height="315" src="//www.youtube.com/embed/32fij3U6SUo" frameborder="0" allowfullscreen></iframe>
  </div></p>
</div></p>

感想

自己紹介

<div class="outline-text-3" id="text-4-1">
  <p>
    まず、なぜ私がニセエセ組込みエンジニアなのかを説明したい。 そのために、まずは自分のしていた仕事を書こうと思う。 このブログに仕事の話を書くのも初めてな気がする。
  </p>

  <p>
    今は別のこと(社内ニートとも)をしているけれども、ちょっと前までは、 ストレージ装置の組込みソフトエンジニアだった。
  </p>

  <p>
    開発はそこそこ大規模で、機能モジュールごとに担当チームが別れている。
  </p>

  <p>
    自分の所属していたチームは、エラー発生時のリカバリが担当。 つまり、装置でエラーが発生したときに、 可用性を失わないためにあらゆる手段をつかってあれこれする役目。
  </p>

  <p>
    そのなかでも、自分が担当していた部分は、 ハードエラーが発生して装置内の各種ドライバから通知を受けたときに、 装置の可用性を失わないためはどうすればいいかを一生懸命考える部分。
  </p>

  <div class="figure">
    <p>
      <img src="http://futurismo.biz/wp-content/uploads/wpid-sample5.png" alt="sample.png" />
    </p></p>
  </div>

  <p>
    ハードと接するinterfaceはドライバ層で隠蔽されているため、 実は自分はレジスタを触ったことがない!
  </p>

  <p>
    そもそもレジスタがなんだかわからない。 雑誌『Interface』や『トランジスタ技術』が 会社の休憩ゾーンにおいてあるが、書いてあることがほぼわからない。
  </p>

  <p>
    これって、組込みエンジニアとしてどうなの? これが、ニセエセ組込みエンジニアたる所以である。
  </p></p>
</div></p>

課題

<div class="outline-text-3" id="text-4-2">
  <p>
    自分は、組込みエンジニアという肩書きではあるものの、 実際はハードウェアを理解していない。
  </p>

  <p>
    以下の記事にとても共感する。
  </p>

  <p>
    <a href="http://monoist.atmarkit.co.jp/mn/articles/0703/26/news101.html">組み込みギョーカイの常識・非常識(8):組み込みソフトウェアって何</a>
  </p>

  <p>
    ちなみに、この記事を書いた著者のことを調べてみるとこんな本を書いてた。
  </p>

  <div class='amazlink-box' style='text-align:left;padding-bottom:20px;font-size:small;/zoom: 1;overflow: hidden;'>
    <div class='amazlink-list' style='clear: both;'>
      <div class='amazlink-image' style='float:left;margin:0px 12px 1px 0px;'>
        <a href='http://www.amazon.co.jp/%E7%B5%84%E8%BE%BC%E3%81%BF%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%8F%E3%83%BC%E3%83%89%E3%82%A6%E3%82%A7%E3%82%A2%E5%85%A5%E9%96%80-%E7%B5%84%E8%BE%BC%E3%81%BF%E3%83%97%E3%83%AC%E3%82%B9Selection-%E3%81%BF%E3%82%8F-%E3%82%88%E3%81%97%E3%81%93/dp/4774140155%3FSubscriptionId%3DAKIAJDINZW45GEGLXQQQ%26tag%3Dsleephacker-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4774140155' target='_blank' rel='nofollow'><img src='http://ecx.images-amazon.com/images/I/41MIz39174L._SL160_.jpg' style='border: none;' /></a>
      </div>

      <div class='amazlink-info' style='height:160; margin-bottom: 10px'>
        <div class='amazlink-name' style='margin-bottom:10px;line-height:120%'>
          <a href='http://www.amazon.co.jp/%E7%B5%84%E8%BE%BC%E3%81%BF%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%8F%E3%83%BC%E3%83%89%E3%82%A6%E3%82%A7%E3%82%A2%E5%85%A5%E9%96%80-%E7%B5%84%E8%BE%BC%E3%81%BF%E3%83%97%E3%83%AC%E3%82%B9Selection-%E3%81%BF%E3%82%8F-%E3%82%88%E3%81%97%E3%81%93/dp/4774140155%3FSubscriptionId%3DAKIAJDINZW45GEGLXQQQ%26tag%3Dsleephacker-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4774140155' rel='nofollow' target='_blank'>組込みソフトウェアエンジニアのためのハードウェア入門 (組込みプレスSelection)</a>
        </div>

        <div class='amazlink-powered' style='font-size:80%;margin-top:5px;line-height:120%'>
          posted with <a href='http://amazlink.keizoku.com/' title='アマゾンアフィリエイトリンク作成ツール' target='_blank'>amazlink</a> at 14.05.11
        </div>

        <div class='amazlink-detail'>
          みわ よしこ
        </div>

        <div class='amazlink-sub-info' style='float: left;'>
          <div class='amazlink-link' style='margin-top: 5px'>
            <img src='http://amazlink.fuyu.gs/icon_amazon.png' width='18' /><a href='http://www.amazon.co.jp/%E7%B5%84%E8%BE%BC%E3%81%BF%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%8F%E3%83%BC%E3%83%89%E3%82%A6%E3%82%A7%E3%82%A2%E5%85%A5%E9%96%80-%E7%B5%84%E8%BE%BC%E3%81%BF%E3%83%97%E3%83%AC%E3%82%B9Selection-%E3%81%BF%E3%82%8F-%E3%82%88%E3%81%97%E3%81%93/dp/4774140155%3FSubscriptionId%3DAKIAJDINZW45GEGLXQQQ%26tag%3Dsleephacker-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4774140155' rel='nofollow' target='_blank'>Amazon</a> <img src='http://amazlink.fuyu.gs/icon_rakuten.gif' width='18' /><a href='http://hb.afl.rakuten.co.jp/hgc/g00q0724.n763w947.g00q0724.n763x2b4/archives/c=http%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F6186429%2F&#038;m=http%3A%2F%2Fm.rakuten.co.jp%2Frms%2Fmsv%2FItem%3Fn%3D6186429%26surl%3Dbook' rel='nofollow' target='_blank'>楽天</a>
          </div>
        </div>
      </div>
    </div>
  </div>

  <p>
    ハードウェアの担当者と一緒の打ち合わせに参加しても、正直ちんぷんかんぷん。
  </p>

  <p>
    ということで、以下が学習目標。
  </p></p>
</div></p>

学習目標

<div class="outline-text-3" id="text-4-3">
  <p>
    DMA Driver が DMA Portのハードエラーを検出して、 そのエラー要因ごとに異常を通知する仕組みを理解すること。
  </p>

  <p>
    DriverがDMAなのは、 仕事で一番お世話になったのが DMA Driverの担当の人だったから。
  </p>

  <p>
    ここからは、勉強メモ。
  </p></p>
</div></p>

Embeded System

組み込みシステム。

特定の機能を実現するために機械や機器に組み込まれるコンピュータシステム。

組み込みシステムの主な構成要素は以下。

  • Embedded Systems
    • MicroCotroller
      • Memory
        • RAM
        • ROM
      • Processor(CPU)
      • I/O Ports
      • DAC
      • Bas
      • Timer
    • External Circuits
    • Physical Device
      • Sensor
      • ADC

以下のような特徴をもつ。

  • A microcontroller hidden inside
  • A dedicated purpose
  • Run in real time
  • Input/output is important
  • High volume, low cost
  • Extremely reliable
  • Low power
  • Small size and weight

MicroController

マイクロコントローラー。いわゆる、マイコン。

Microcontrollers, which are microcomputers incorporating the processor,
RAM, ROM and I/O ports into a single package,
are often employed in an embedded system because of their low cost,
small size, and low power requirements.

I/O Port

<div class="outline-text-3" id="text-6-1">
  <p>
    Input Port/Output Portの略。 Input Portは 外部の世界(外部の集積回路、sensor, etc) からの情報をコンピュータのなかに入れる。Output Portはその逆。
  </p>

  <p>
    A port is a physical connection between the computer and its outside world.
  </p></p>
</div>

<div id="outline-container-sec-6-1-1" class="outline-4">
  <h4 id="sec-6-1-1">
    device driver
  </h4>

  <div class="outline-text-4" id="text-6-1-1">
    <p>
      a set of software functions that facilitate the use of an I/O port.
    </p></p>
  </div></p>
</div>

<div id="outline-container-sec-6-1-2" class="outline-4">
  <h4 id="sec-6-1-2">
    GPIO
  </h4>

  <div class="outline-text-4" id="text-6-1-2">
    <p>
      GPIOはGeneral Purpose Input/Output(汎用入出力)の略語。
    </p>

    <p>
      <a href="http://ja.wikipedia.org/wiki/GPIO">GPIO &#8211; Wikipedia</a>
    </p>

    <p>
      LSIチップや電子機器の備える入出力端子の一種で、 設定次第で様々な用途に利用できるもの。
    </p>

    <p>
      ソフトウェアの指示によって任意の入力あるいは出力に利用することができる。 複数の端子がGPIOに割り当てられている場合には、 これを一つのグループとして一括して制御することができ「GPIOポート」などと呼ばれる
    </p>

    <p>
      <a href="http://e-words.jp/w/GPIO.html">GPIOとは 【 General Purpose Input/Output 】 &#8211; 意味/解説/説明/定義 : IT用語辞典</a>
    </p>

    <p>
      PinはGPIOの構成要素。たとえば、GPIO PortAは、PA0-PA7の8つのPinからできている。
    </p>

    <p>
      Pins can be configured for digital I/O, analog input, timer I/O, or serial I/O. For example PA0 can be digital I/O or serial input.
    </p>

    <p>
      Pinのそれぞれが外部デバイスに接続される。 用途は、レジスタの設定によって自由にできる。
    </p>

    <ul class="org-ul">
      <li>
        PA1 &#x2026; LEDへのOutput用
      </li>
      <li>
        PA2 &#x2026; Switch からの Input用
      </li>
      <li>
        PA3 &#x2026; UART の Input用
      </li>
      <li>
        PA4 &#x2026; UART の Output用
      </li>
    </ul>
  </div></p>
</div></p>

Register

<div class="outline-text-3" id="text-6-2">
  <p>
    コンピュータのプロセッサなどが内蔵する記憶回路で、 制御装置や演算装置や実行ユニットに直結した、 操作に要する速度が最速の、比較的少量のものを指す。
  </p>

  <p>
    一般に、論理回路において、フリップフロップなどにより状態を保持する装置をレジスタと呼ぶ。 コンピュータにおいては、プロセッサが内蔵しているそれを指す。 プロセッサには、プログラムが読み書きできるレジスタ以外に、 プロセッサ自身が動作するためのレジスタがあり、内部レジスタなどと呼ばれる。
  </p>

  <p>
    <a href="http://ja.wikipedia.org/wiki/%E3%83%AC%E3%82%B8%E3%82%B9%E3%82%BF_(%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF)">レジスタ (コンピュータ) &#8211; Wikipedia</a>
  </p>

  <p>
    Registers are high-speed storage inside the processor.
  </p></p>
</div>

<div id="outline-container-sec-6-2-1" class="outline-4">
  <h4 id="sec-6-2-1">
    Registerのプログラムでの扱い
  </h4>

  <div class="outline-text-4" id="text-6-2-1">
    <p>
      Pinを操作するためのレジスタには、 アドレス空間の決められたアドレスが割り振られている。(仕様)
    </p>

    <p>
      プログラムでは、あらかじめDefineを利用してレジスタのアドレスを宣言するのが王道。 volatileをつけることで、コンパイラが最適化してアドレスを変更するのを防ぐ。
    </p>

    <div class="org-src-container">
      <pre class="src src-language">#define PA5   (*((volatile unsigned long *)0x40004080))

    <p>
      これは以下と同値。
    </p>

    <div class="org-src-container">
      <pre class="src src-language">data = (*((volatile unsigned long *)0x40004080));

data = 0x40004080; data = (*0x40004080);

    <p>
      そうすると、以下のようにして Registerの値を Read/Writeできる。
    </p>

    <div class="org-src-container">
      <pre class="src src-language"># Register Write

PA5 = 0x20;

Register Read

data = PA5;

    <p>
      初期設定はこんな感じ。
    </p>

    <div class="org-src-container">
      <pre class="src src-language">void PortF_Init(void){ volatile unsigned long delay;

SYSCTL_RCGC2_R |= 0x00000020; // 1) F clock delay = SYSCTL_RCGC2_R; // delay
GPIO_PORTF_LOCK_R = 0x4C4F434B; // 2) unlock PortF PF0 GPIO_PORTF_CR_R |= 0x1F; // allow changes to PF4-0
GPIO_PORTF_AMSEL_R &= 0x00; // 3) disable analog function GPIO_PORTF_PCTL_R &= 0x00000000; // 4) GPIO clear bit PCTL GPIO_PORTF_DIR_R &= ~0x11; // 5.1) PF4,PF0 input, GPIO_PORTF_DIR_R |= 0x08; // 5.2) PF3 output GPIO_PORTF_AFSEL_R &= 0x00; // 6) no alternate function GPIO_PORTF_PUR_R |= 0x11; // enable pullup resistors on PF4,PF0
GPIO_PORTF_DEN_R |= 0x1F; // 7) enable digital pins PF4-PF0
}

<div id="outline-container-sec-6-2-2" class="outline-4">
  <h4 id="sec-6-2-2">
    LチカExample抜粋
  </h4>

  <div class="outline-text-4" id="text-6-2-2">
    <div class="org-src-container">
      <pre class="src src-language">// symbolic names instead of addresses

#define GPIO_PORTF_DATA_R (*((volatile unsigned long )0x400253FC)) #define GPIO_PORTF_DIR_R (((volatile unsigned long )0x40025400)) #define GPIO_PORTF_AFSEL_R (((volatile unsigned long )0x40025420)) #define GPIO_PORTF_PUR_R (((volatile unsigned long )0x40025510)) #define GPIO_PORTF_DEN_R (((volatile unsigned long )0x4002551C)) #define GPIO_PORTF_LOCK_R (((volatile unsigned long )0x40025520)) #define GPIO_PORTF_CR_R (((volatile unsigned long )0x40025524)) #define GPIO_PORTF_AMSEL_R (((volatile unsigned long )0x40025528)) #define GPIO_PORTF_PCTL_R (((volatile unsigned long )0x4002552C)) #define SYSCTL_RCGC2_R (((volatile unsigned long *)0x400FE108))

// 2. Declarations Section // Global Variables unsigned long SW1; // input from PF4 unsigned long SW2; // input from PF0

// Subroutine to initialize port F pins for input and output // PF4 is input SW1 and PF2 is output Blue LED void PortF_Init(void){ volatile unsigned long delay; SYSCTL_RCGC2_R |= 0x00000020; // 1) F clock delay = SYSCTL_RCGC2_R; // delay
GPIO_PORTF_LOCK_R = 0x4C4F434B; // 2) unlock PortF PF0 GPIO_PORTF_CR_R |= 0x1F; // allow changes to PF4-0
GPIO_PORTF_AMSEL_R &= 0x00; // 3) disable analog function GPIO_PORTF_PCTL_R &= 0x00000000; // 4) GPIO clear bit PCTL GPIO_PORTF_DIR_R &= ~0x11; // 5.1) PF4,PF0 input, GPIO_PORTF_DIR_R |= 0x08; // 5.2) PF3 output GPIO_PORTF_AFSEL_R &= 0x00; // 6) no alternate function GPIO_PORTF_PUR_R |= 0x11; // enable pullup resistors on PF4,PF0
GPIO_PORTF_DEN_R |= 0x1F; // 7) enable digital pins PF4-PF0
}

void FlashSOS(void){ //S GPIO_PORTF_DATA_R |= 0x08; delay(1); GPIO_PORTF_DATA_R &= ~0x08; delay(1); GPIO_PORTF_DATA_R |= 0x08; delay(1); GPIO_PORTF_DATA_R &= ~0x08; delay(1); GPIO_PORTF_DATA_R |= 0x08; delay(1); GPIO_PORTF_DATA_R &= ~0x08; delay(1); //O GPIO_PORTF_DATA_R |= 0x08; delay(4); GPIO_PORTF_DATA_R &= ~0x08;delay(4); GPIO_PORTF_DATA_R |= 0x08; delay(4); GPIO_PORTF_DATA_R &= ~0x08;delay(4); GPIO_PORTF_DATA_R |= 0x08; delay(4); GPIO_PORTF_DATA_R &= ~0x08;delay(4); //S GPIO_PORTF_DATA_R |= 0x08; delay(1); GPIO_PORTF_DATA_R &= ~0x08;delay(1); GPIO_PORTF_DATA_R |= 0x08; delay(1); GPIO_PORTF_DATA_R &= ~0x08;delay(1); GPIO_PORTF_DATA_R |= 0x08; delay(1); GPIO_PORTF_DATA_R &= ~0x08;delay(1); delay(10); // Delay for 5 secs in between flashes }

Memory

ROM

<div class="outline-text-3" id="text-7-1">
  <p>
    書き込んだデータは消去できないが、電源を切ってもデータが消えない読み出し専用のメモリ.
  </p></p>
</div></p>

RAM

<div class="outline-text-3" id="text-7-2">
  <p>
    データの読み書きは自由に行えるが、電源を切ると内容が消えるメモリ(Random Access Memory)
  </p></p>
</div></p>

Interface

ハードウェアとソフトウェアを結ぶもの。ここでいうところは、ハードウェアインタフェース。

interface is defined as the hardware and software that combine to allow the computer to communicate with the external hardware.

I/O Port, 外部電子回路、物理的デバイス、ソフトウェアなどを集めたもの。

An interface is defined as the collection of the I/O port, external electronics, physical devices, and the software, which combine to allow the computer to communicate with the external world.

以下の4つに分類される。

Parallel Interface

<div class="outline-text-3" id="text-8-1">
  <p>
    パラレルポートとは、コンピュータシステム内で、 ばらばらの周辺機器をケーブルで接続するために使われる物理的なインタフェースの一種。
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://ja.wikipedia.org/wiki/%E3%83%91%E3%83%A9%E3%83%AC%E3%83%AB%E3%83%9D%E3%83%BC%E3%83%88">パラレルポート &#8211; Wikipedia</a>
    </li>
    <li>
      <a href="http://www.sophia-it.com/content/%E3%83%91%E3%83%A9%E3%83%AC%E3%83%AB%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%95%E3%82%A7%E3%83%BC%E3%82%B9">パラレルインターフェースとは 「パラレルインタフェース」 (parallel interface): &#8211; IT用語辞典バイナリ</a>
    </li>
  </ul>
</div></p>

Syncronization

<div class="outline-text-3" id="text-8-2">
  <p>
    ハードウェアとソフトウェアの同期処理。
  </p>

  <p>
    ハードウェアのスピードとソフトウェアのスピードは、 ソフトウェアの方が早いため相互でやりとりするためには以下の手段がある。
  </p></p>
</div>

<div id="outline-container-sec-8-2-1" class="outline-4">
  <h4 id="sec-8-2-1">
    Blind-Cycle
  </h4>

  <div class="outline-text-4" id="text-8-2-1">
    <p>
      決められた時間SleepしたあとにI/Oステータスをチェックする.
    </p>

    <p>
      the software writes data to the output device, triggers (starts) the device, then waits a specified time. We call this method blind, because there is no status information about the I/O device reported to the software.
    </p></p>
  </div></p>
</div>

<div id="outline-container-sec-8-2-2" class="outline-4">
  <h4 id="sec-8-2-2">
    Busy-Wait
  </h4>

  <div class="outline-text-4" id="text-8-2-2">
    <p>
      Input deviceのデータが更新されたときにI/Oステータスをチェックする。
    </p>

    <p>
      状態がBusyならばWait(loop), Readyならば次のステップへ。
    </p>

    <p>
      Busy Wait is a software loop that checks the I/O status waiting for the done state. For an input device, the software waits until the input device has new data, and then reads it from the input device,
    </p></p>
  </div></p>
</div>

<div id="outline-container-sec-8-2-3" class="outline-4">
  <h4 id="sec-8-2-3">
    Interrupt
  </h4>

  <div class="outline-text-4" id="text-8-2-3">
    <p>
      ハードウェアが発生させる特別な通知。
    </p>

    <p>
      An interrupt uses hardware to cause special software execution. With an input device, the hardware will request an interrupt when input device has new data. The software interrupt service will read from the input device and save in global RAM,
    </p></p>
  </div></p>
</div>

<div id="outline-container-sec-8-2-4" class="outline-4">
  <h4 id="sec-8-2-4">
    Periodic Polling
  </h4>

  <div class="outline-text-4" id="text-8-2-4">
    <p>
      クロックタイマの割り込み契機でI/Oのステータスをチェック
    </p></p>
  </div></p>
</div>

<div id="outline-container-sec-8-2-5" class="outline-4">
  <h4 id="sec-8-2-5">
    DMA
  </h4>

  <div class="outline-text-4" id="text-8-2-5">
    <p>
      Direct Memory Access あるメモリから別のメモリに直接情報を書き込む
    </p></p>
  </div></p>
</div></p>

Serial Interface

<div class="outline-text-3" id="text-8-3">
</div>

<div id="outline-container-sec-8-3-1" class="outline-4">
  <h4 id="sec-8-3-1">
    UART
  </h4>

  <div class="outline-text-4" id="text-8-3-1">
    <p>
      Universal Asynchronous Receiver/Transmitter (UART). 調歩同期方式によるシリアル通信をするための汎用I/F。
    </p>

    <ul class="org-ul">
      <li>
        <a href="http://ja.wikipedia.org/wiki/UART">UART &#8211; Wikipedia</a>
      </li>
    </ul>

    <p>
      有名なので、最近のほとんどのマイコンに搭載されているらしい。
    </p></p>
  </div></p>
</div></p>

Thread/Process/Task

Thread

<div class="outline-text-3" id="text-9-1">
  <p>
    A thread is defined as the path of action of software as it executes.
  </p></p>
</div></p>

Process

<div class="outline-text-3" id="text-9-2">
  <p>
    A process is defined as the action of software as it executes.
  </p>

  <p>
    スレッドとプロセスの違いは、変数のスコープの違い?
  </p>

  <p>
    Threads share access to I/O devices, system resources, and global variables, while processes have separate global variables and system resources. Processes do not share I/O devices.
  </p>

  <p>
    実際は、OSによってバラバラ。
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://futurismo.biz/archives/2245">スレッドとタスクの違いについてしらべてみた(C++/Linux) | Futurismo</a>
    </li>
  </ul>
</div></p>

Interrupt

Hardware Interrupt Software Action.

Busy-Waitの制御で待ってられない場合は、Interruptを利用する。

ここからは、一般的な説明ではなくてedXの中だけの定義。

Arm/DisArm

<div class="outline-text-4" id="text-10-0-1">
  <p>
    Armとは、ハードウェアが割り込みをあげることを有効化する。
  </p>

  <p>
    DisArmとは、ハードウェアが割り込みをあげることを無効化する。
  </p></p>
</div></p>

Enable/Disable

<div class="outline-text-4" id="text-10-0-2">
  <p>
    Enableは一時的に割り込みを有効化する。
  </p>

  <p>
    Disbleは一時的に割り込みを無効化する。
  </p>

  <p>
    Disable中に発生したInterupptは Pendingされて、Enable時に通知される。
  </p></p>
</div></p>

Interruputの初期化処理

<div class="outline-text-4" id="text-10-0-3">
  <ol class="org-ol">
    <li>
      Trigger flag set by hardware
    </li>
    <li>
      the device is armed by software
    </li>
    <li>
      the device is enabled for interrupts in the NVIC
    </li>
    <li>
      the processor is enabled for interrupts (PRIMASK I bit is clear)
    </li>
    <li>
      the interrupt level must be less than the BASEPRI.
    </li>
  </ol>
</div></p>

Context Switch

<div class="outline-text-4" id="text-10-0-4">
  <p>
    割り込みをハードウェアが検知したときに、 foregroundとbackgroundのスレッドを入れ替える。
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%82%B9%E3%82%A4%E3%83%83%E3%83%81">コンテキストスイッチ &#8211; Wikipedia</a>
    </li>
  </ul>

  <p>
    現在のプロセスの実行を一時停止して、 スタックにレジスタ情報を覚えておく。
  </p>

  <p>
    割り込みハンドラを実行して、 ハンドラの実行が終了したらもとのプロセスを再開する。
  </p>

  <ol class="org-ol">
    <li>
      Current instruction is finished,
    </li>
    <li>
      Eight registers are pushed on the stack,
    </li>
    <li>
      LR is set to 0xFFFFFFF9,
    </li>
    <li>
      IPSR is set to the interrupt number,
    </li>
    <li>
      PC is loaded with the interrupt vector
    </li>
  </ol>
</div></p>

Interrupt Service Routine(ISR)

<div class="outline-text-3" id="text-10-1">
  <p>
    割り込みサービスルーチン。割り込みハンドラともいう。
  </p>

  <p>
    <a href="http://ja.wikipedia.org/wiki/%E5%89%B2%E3%82%8A%E8%BE%BC%E3%81%BF%E3%83%8F%E3%83%B3%E3%83%89%E3%83%A9">割り込みハンドラ &#8211; Wikipedia</a>
  </p>

  <p>
    コンテキストスイッチによって、 foregroundで動作している busy-waitなスレッドとISRがスワップされる。
  </p>

  <p>
    割り込み受け付けによって起動されるオペレーティングシステムや デバイスドライバのコールバックルーチン。 割り込みハンドラは割り込み原因によってそれぞれ存在し、 割り込みハンドラがそのタスクを完了するまでにかかる時間も様々である。
  </p></p>
</div>

<div id="outline-container-sec-10-1-1" class="outline-4">
  <h4 id="sec-10-1-1">
    NVIC
  </h4>

  <div class="outline-text-4" id="text-10-1-1">
    <p>
      割り込みハンドラに対応させたい関数は、 startup scriptに事前に登録しておく。
    </p>

    <p>
      vectorというメモリ領域にシステムにどの関数を実行すればいいかをアドレスとして教える。
    </p>

    <p>
      interrupt発生時は vectorを参照して、それに対応する割り込みルーチンの関数を呼ぶ。
    </p>

    <p>
      nested vectored interrupt controller (NVIC) manages interrupts, which are hardware-triggered software functions. Some internal peripherals, like the NVIC communicate directly with the processor via the private peripheral bus (PPB). The tight integration of the processor and interrupt controller provides fast execution of interrupt service routines (ISRs), dramatically reducing the interrupt latency.
    </p></p>
  </div></p>
</div>

<div id="outline-container-sec-10-1-2" class="outline-4">
  <h4 id="sec-10-1-2">
    Acknowledge
  </h4>

  <div class="outline-text-4" id="text-10-1-2">
    <p>
      割り込みをISRが認識すること。 ISRが割り込みの認識を行った後、同じデバイスからの割り込みが発生しないよう割り込みマスクをする必要がある。 そうしないと、クラッシュする恐れがある。
    </p>

    <ul class="org-ul">
      <li>
        <a href="http://d241445.hosting-sv.jp/community/report/report31.html">レポート31:割り込みサービスルーチン(ISR)の処理</a>
      </li>
    </ul>

    <p>
      実装でやってはいけないことは以下。
    </p>

    <ul class="org-ul">
      <li>
        長時間の処理はしてはいけない。
      </li>
      <li>
        待ち状態になってはいけない、Delay Loopはつかわないほうがよい。
      </li>
      <li>
        呼んではいけない関数がある。
      </li>
    </ul>

    <p>
      割り込みハンドラでは必要最小限の処理のみを行い、別のタスクに通知して、 メインの処理はそっちでさせるように実装すべき。
    </p></p>
  </div></p>
</div>

<div id="outline-container-sec-10-1-3" class="outline-4">
  <h4 id="sec-10-1-3">
    ISRからメイン処理への通知方法
  </h4>

  <div class="outline-text-4" id="text-10-1-3">
    <p>
      ISRとメイン処理はグローバルなメモリ領域を介して情報を受渡しする。
    </p>

    <ul class="org-ul">
      <li>
        Binary Semaphore
      </li>
    </ul>

    <p>
      ISRで 決められたflagを立てて、メイン処理でそのフラグを監視する。 flagが1ならば、それのフラグに対応する処理を実施する。
    </p>

    <ul class="org-ul">
      <li>
        MailBox
      </li>
    </ul>

    <p>
      flagとともにデータも渡すこともある。
    </p>

    <p>
      flagをStatusといい、flagとdataを合わせたデータ構造をMailという。 (MailBox Pruducer-Consumer Pattern)
    </p>

    <ul class="org-ul">
      <li>
        FIFO queue
      </li>
    </ul>

    <p>
      ISRでFifoなメモリ領域にデータをPUTし、 メイン処理のloop処理でで定期的にFifoなdataをチェックし、順次実行する。
    </p></p>
  </div></p>
</div></p>

05 Nov 2013, 15:39

「モダンC言語プログラミング」を読んだ!C言語の組込みエンジニアのためのモダンテクニックが満載

とてもエキサイティングな本に出会い、一気に読んでしまいました。感想を書こうと思います。



ターゲット読者層は組込み分野!

この本のターゲット読者はズバリ、組込みエンジニア。ソースコードのサンプルも、ズバリ組込みな内容を扱っています。C言語を使う人=組込みの人と決めつけているよう。書籍のあちこちで、このアプローチを組込み開発で適応するためにはどうすればいいかという考察が入るのがよい。

TIOBEというプログラミング言語の統計を見ると、C言語を利用している人がプログラマの2割程度いることがわかる。自分はこのデータを初めて知ったけれども、まずこの事実をしれたことは嬉しい事だ。C言語はいかに重要なのかという論題が冒頭で熱く語られる。

 内容について

各章のテーマは、広く浅く書かれているので、もう少し各章の突っ込んだ内容がほしいところだけれども、それはこの本の趣旨には合わないのだろう。

内容は、自分の日々考えていることに非常にマッチしていて、とてもエキサイティングな読後感でした。以下、自分の過去記事も整理しつつ、各章の覚書。

開発環境について

開発環境である、Ubuntuの導入方法と、Eclipseの使い方が紹介されていた。ここは、得るものはなしかな。

オブジェクト指向

C言語でオブジェクト指向のようにコーディングするためのテクニックが紹介されている。半分知っているようで、知らなかった。C言語でも、オブジェクト指向なプログラミングは可能だと気づかせてくれる。

あとは、Cでオブジェクト指向を勉強するならば、ズバリこの本でしょう。これもオススメ。



デザインパターン

自分の来年の重点学習目標の一つが、デザインパターンをマスターすること。この章は、C言語を利用したデザインパターンの実装方法が紹介されている。この章は知らないことが多く、とても興味深かった。

以下のパターンが紹介されている。

C言語に特化したデザインパターンの本をまだ知らない。これが自分が出会った中で、もっともよくかかれた本かも。この本でも勉強するつもり。まだ読んでない。

いづれにしろ、この章は再読しよう。

TDD リファクタリング

テストフレームワークとして、GoogleTestが紹介される。レガシーコードに対するリファクタリングの実践がサンプルとして載っているのがうれしい。しかも、内容が組込みなので、実践的。パフォーマンスに関する考察もある。

namespaceを利用して、static関数を強引にテストケースに組み込む方法が紹介されていた。C++系のxUnitで利用できるテクニック。

namespace unit_test {
    #include "hogehoge.c"

    TEST(hoge,hogehoge) {
        EXPECT_EQ(3, hoge(1, 2));
    }
}

モックやスタブの定義についての言及は、自分の認識とは違うのだけれども、まあよい。モッキングフレームワークはC言語でいいものがないと書かれていた。そんなことはない、CMockやfffがあるではないか!

CでTDDをするならば、この本が必読本。



継続的インテグレーション

Jenkinsの紹介。これもあまり新しきことはなし。

C言語/C++でJenkins実践入門してみるよ | Futurismo

ビルドスクリプトとして、sConsが紹介されている。なかでも、感心したのが、スモークテストでのPytyonを利用した受け入れテストのアプローチ。pyhthonコードからシリアル接続を経由してテストする方法。この作者はPythonが好きなのかな?自分は、Rubyで同じことをやろうとした。

また、Valgrindを使ったメモリ破壊との戦いも、組込みならでは。こういうことにページを割くところも高評価。ValgrindはLinux用ツールなので、まだ使ったことがないけれども、今度調べてみようかな。

まとめ

組込みの現場ではなぜ、これらのテクニックが浸透しないのだろうか?

Eclipseが浸透しないのは、べつによい。エディタはEclipseだけではないし、EmacsやVimはEclipseに負けないくらいだ。

オブジェクト指向やデザインパターンが浸透しないのは、実行速度やメモリが関係しているのだろう。また、TDDもオブジェクト指向のほうが実施しやすい。(とくにMock)CIは、文化的なものだと思う。

どれも、決定的な理由にはならない。一つ思うのは

「無知」

だからということ。自分もCに関わるいろんな情報を集めているものの、ほかの言語とくらべて、Cは圧倒的に情報量が少ない。Eclipsしかり、TDDしかり、Jenkinsしかり。

C Programmerに足りないものは、道標となるような情報や、書籍だ。C言語は使用率第一位の言語なのだ。これからも、こういう書籍がドンドン出てきてほしい。

26 Oct 2013, 12:54

組込み開発の二大迷信に挑む!リファクタリングにおけるパフォーマンスとスタックオーバーフローについての数値実験

組込み開発において、リファクタリングしようとすると、自分は怒られる。

怒られるのが嫌で、リファクタリングできない。この2大迷信について、簡単な実験してみた。

Normalコード(Test1)

これは普通のコード。ここを参考にした。clock

[tsu-nera]% cat timer.c
#include <time.h>
#include <stdio.h>

int main(void)
{
  clock_t start, end;
  long l;
  long i=0;
  int  n=0;
  clock_t total_start, total_end;

  total_start = clock();

  while(n < 5){

    start = clock();
    i = 0;

    for (l=0; l<100000000; l++) {
      i++;
    }

    end = clock();
    printf("ループ1億回の時間: %f秒\n", (double)(end - start) / CLOCKS_PER_SEC);
    n++;
  }

  total_end = clock();

  printf("平均の時間: %f秒\n", (double)(total_end - total_start) / CLOCKS_PER_SEC / n);

  return 0;

}

Functionコード(Test2)

つづいて、関数でインクリメントを抽出したコード。

[tsu-nera]% cat timer2.c
#include <time.h>
#include <stdio.h>


void incriment(long* i) {
  (*i)++;
}

int main(void)
{
  clock_t start, end;
  long l;
  long i=0;
  int  n=0;
  clock_t total_start, total_end;

  total_start = clock();

  while(n < 5){

    start = clock();
    i = 0;

    for (l=0; l<100000000; l++) {
      incriment(&i);
    }

    end = clock();
    printf("ループ1億回の時間: %f秒\n", (double)(end - start) / CLOCKS_PER_SEC);
    n++;
  }

  total_end = clock();

  printf("平均の時間: %f秒\n", (double)(total_end - total_start) / CLOCKS_PER_SEC / n);

  return 0;

}

実験結果

気持ち、Test1のほうが早い気がする。もっと実験すれば、大数の法則で正確な値がでそうだけど、まあいいや。とりあえず、気持ちの問題で小さな関数はパフォーマンスをあまり低下させないという自身がついた。

Test1

[tsu-nera]% ./a.out
ループ1億回の時間: 1.050000秒
ループ1億回の時間: 0.720000秒
ループ1億回の時間: 0.670000秒
ループ1億回の時間: 1.050000秒
ループ1億回の時間: 1.170000秒
平均の時間: 0.932000秒
[tsu-nera]% ./a.out
ループ1億回の時間: 1.030000秒
ループ1億回の時間: 0.960000秒
ループ1億回の時間: 0.960000秒
ループ1億回の時間: 0.770000秒
ループ1億回の時間: 0.680000秒
平均の時間: 0.882000秒
[tsu-nera]% ./a.out
ループ1億回の時間: 1.250000秒
ループ1億回の時間: 0.840000秒
ループ1億回の時間: 0.670000秒
ループ1億回の時間: 0.570000秒
ループ1億回の時間: 0.630000秒
平均の時間: 0.792000秒
[tsu-nera]% ./a.out
ループ1億回の時間: 1.030000秒
ループ1億回の時間: 0.730000秒
ループ1億回の時間: 0.630000秒
ループ1億回の時間: 0.520000秒
ループ1億回の時間: 0.460000秒
平均の時間: 0.674000秒
[tsu-nera]% ./a.out
ループ1億回の時間: 0.940000秒
ループ1億回の時間: 0.720000秒
ループ1億回の時間: 0.630000秒
ループ1億回の時間: 0.540000秒
ループ1億回の時間: 0.500000秒
平均の時間: 0.666000秒

Test2

[tsu-nera]% ./a.out
ループ1億回の時間: 1.010000秒
ループ1億回の時間: 0.810000秒
ループ1億回の時間: 0.650000秒
ループ1億回の時間: 0.560000秒
ループ1億回の時間: 0.480000秒
平均の時間: 0.702000秒
[tsu-nera]% ./a.out
ループ1億回の時間: 1.470000秒
ループ1億回の時間: 1.160000秒
ループ1億回の時間: 0.930000秒
ループ1億回の時間: 0.700000秒
ループ1億回の時間: 0.590000秒
平均の時間: 0.970000秒
[tsu-nera]% ./a.out
ループ1億回の時間: 1.050000秒
ループ1億回の時間: 0.870000秒
ループ1億回の時間: 0.710000秒
ループ1億回の時間: 0.770000秒
ループ1億回の時間: 1.270000秒
平均の時間: 0.934000秒
[tsu-nera]% ./a.out
ループ1億回の時間: 1.200000秒
ループ1億回の時間: 0.890000秒
ループ1億回の時間: 0.710000秒
ループ1億回の時間: 0.650000秒
ループ1億回の時間: 0.540000秒
平均の時間: 0.798000秒
[tsu-nera]% ./a.out
ループ1億回の時間: 1.020000秒
ループ1億回の時間: 0.760000秒
ループ1億回の時間: 0.620000秒
ループ1億回の時間: 0.550000秒
ループ1億回の時間: 0.560000秒
平均の時間: 0.704000秒

スタックオーバーフローのテスト(Test3)

関数を呼びすぎるとスタックオーバーフローするよと脅されたが、脅した人はどのくらいの確信をもって発言したのかをテストした。

こんなサンプル。

#include <stdio.h>

void incriment(long* i) {
  (*i)++;
  printf("i=%d\n",*i);
  incriment(i);
}

int main(void)
{
  long  i=0;
  incriment(&i);
  return 0;

}

テスト結果

大体、自分のCygwin環境だと400000くらいでクラッシュする。

i=392880
i=392881
i=392882
[1]    18958 segmentation fault  ./a.out

ただ、スタックオーバーフローは、タスクサイズと環境依存なので、一概に安心はできないな。3階層くらいならば、へのようなものか(・・?

結論

関数抽出しても、コンパイラが最適化してくれるため、パフォーマンスは気にしない。小さな関数はコンパイラがinlineしてくれる。20年前の常識は、現代の非常識。

ただし、スタックオーバーフローは注意を払う。

16 Jun 2013, 09:10

組込み開発の常識!?C-Kermitの使い方を調べたメモ

はじめに

シリアルケーブルを利用して組み込みターゲットに接続する時、kermitコマンドを使う。

仕事で、kermitコマンドしらなくて3人くらいにバカにされたので調べてみた。(´・ω・`)

組込みソフト開発では常識っぽ。

kermitとは

kermitとは、通信用プロトコルの種類の一つ。ようはsshやtelnetの兄弟。

kermitのインストール

WindowsだとMS-kermit、Unix系だとC-kermit/G-kermitなどがあるらしい。今回はLinux上で利用するのでC-kermitを試す。

C-Kermit Binaries

インストールは、ソースを落としてきてコンパイルするようだ。ソースのアーカイブはココ

最新版を落としてくる。ckuってやつがそれっぽい。

bash-4.1# mkdir kermit
bash-4.1# cd kermit/
bash-4.1# wget ftp://kermit.columbia.edu/kermit/archives/cku302.tar.gz
bash-4.1# tar zxvf cku302.tar.gz

make targetは環境によって異なるようだ。makefileに書いてある。今回はCentOSなので、linuxをつける。

bash-4.1# make linux
bash-4.1# make install

エラーした(´・ω・`)

MANDIR=/usr/local/man/man1
Creating /usr/local/man/man1...
mkdir: ディレクトリ `/usr/local/man/man1' を作成できません: そのようなファイルやディレクトリはありません
make: *** [install] エラー 1

ディレクトリを作りなおして、リトライ。

bash-4.1# mkdir -p /usr/local/man/man1
bash-4.1# make install

kermitの使い方

公式ドキュメントは以下。

kermitと入力すると、対話モードで起動

[tsu-nera]% kermit
C-Kermit 9.0.302 OPEN SOURCE:, 20 Aug 2011, for Linux
 Copyright (C) 1985, 2011,
  Trustees of Columbia University in the City of New York.
Type ? or HELP for help.
(/home/tsu-nera/) C-Kermit>

接続デバイスと接続速度をそれぞれ設定して接続する。

# デバイスを設定 /dev/ttyS0がシリアル#0 /dev/ttyUSB0がUSBケーブル
C-Kermit> set line /dev/ttyS0
# 接続スピード デバイスごと
C-Kermit> set speed 9600
# 接続する connectでもよい
C-Kermit> c

.kermrcに初期設定をしておけば、kermit起動時に読み込まれる。

いろいろオプションがあるけれども、シリアルケーブルに接続するためには、-lをつける。

kermit -l /dev/ttyS0

.kermrc以外の設定ファイルを読みこむときは、-y (arg)で。色々と作っておいて、呼び分ける。

kermit -y ~/.kermrc0
kermit -y ~/.kermrc1

参考

28 Apr 2013, 06:32

組込み開発のシステムテスト・機能テストを自動化できるか?Rubyのminitestで非同期テストを実施する方法を本気出して考えてみた

はじめに

非同期な振る舞いをxUnitでテストできたらいいなと思った。具体的には、コンソールからコマンドを打ち込んで標準出力に現れたメッセージをアサートできればいいなと思った。

そういうツールを探してみたのだが、ちょっと探しただけでは見つからなかった。teratermマクロ(TTL)では、コンソールにコマンドを打ち込んでアサートということは簡単に実現できたが、xUnitのような機能、

を自分で実装するのがけっこう大変そうだった。いろいろ調べていると、linuxで標準出力を監視するコマンドでexpectというのがある。これは、RubyやPythonでも同様なツールがあるようだ。

この記事では、GUIはSelenium、CLIはPexpectを利用すれば、どんな自動化テストも可能だと欠かれている。

Quick test automation using Pexpect and Selenium | thoughts from the test eye

そこで今回は、Rubyのminitestライブラリとexpectライブラリを利用して、非同期テストができそうかどうか探ってみた。

TODO

会社では、組み込みソフトの開発をC言語でしているのだが、実機を使ったテストをするときは、実機の目の前に置いてあるゲートウェイPCからシリアルケーブルでボードにアクセスしたり、GUI/CLIをいろいろいじったりしている。

ゲートウェイPCには、Rubyもexpectコマンドもインストールされていないので、自分のCygwinからゲートウェイPCにtelnetして、ウラウラコマンドを送りつけられたらいいなとおもった。なので、今回は以下のようなことを試してみて、実際に実現可能かどうかを探ってみた。

サーバにtelnetする

サーバ上でディレクトリを作成する(mkdir)

Rubyを使ってサーバにtelnetしてコマンドを実行する方法は前回記事にしたので、そっちを参照。

Ruby から サーバ上にパスワードなしでtelnetログイン(expect,pty) | Futurismo

#!/usr/bin/env ruby
require 'pty'
require 'expect'

# ログイン情報を入力
hostname="ubuntu"
username="tsu-nera"
password="*******"

# expect で読み込んだ内容を標準出力に出力するおまじない
$expect_verbose=true

PTY.spawn("telnet -l #{username} #{hostname}") do |r,w|
w.sync = true
r.expect(/Password: /) { w.puts "#{password}" }
r.expect(/[$%#]/) { w.puts "mkdir testdir" }
r.expect(/[$%#]/) { w.puts "exit" }
end

ディレクトリが作成できたかどうかをチェックする(lsコマンド)

ちゃんとmkdirでtestdirが作成されたかかを、lsコマンドで画面に表示して確認する。

#!/usr/bin/env ruby 

....

r.expect(/[$%#]/) { w.puts "mkdir testdir" }

r.expect(/[$%#]/){ w.puts "ls" }
r.expect("testdir")

r.expect(/[$%#]/) { w.puts "exit" }
end

しかし、この方法だとtestdirが存在すれば処理が先にすすむのだが、失敗するとずっと待たされる(9999999秒?)。

タイムアウトを使ってテストの失敗を検出する。(timeout)

Rubyのtimeoutライブラリを利用して、タイムアウトを検出する。

library timeout

require ‘timeout’でライブラリを読み込む。タイマを貼りたい場所で、タイムアウトした場合の例外も考慮してて、以下のように書く。

  
begin

timeout(タイムアウト値) { 処理 }

rescue

タイムアウトした時の例外処理

end
#!/usr/bin/env ruby 

require 'timeout'

....

r.expect(/[$%#]/) { w.puts "mkdir testdir" }

r.expect(/[$%#]/){ w.puts "ls" }
begin
    timeout(3) { r.expect("testdir", 5) }
rescue Timeout::Error => ex
      w.puts "exit"
      puts ex.message
      return ex.class
end

r.expect(/[$%#]/) { w.puts "exit" }
end

複数のテストを実行する。(minitest)

ここから、Rubyライブラリのminitest/unitライブラリを利用して、複数テストを書く。

library minitest/unit

あまり、ベストな方法ではない気がするが、こんなようにしてみた。

tc_mkdir_expect.rb

$ cat tc_mkdir_expect.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'pty'
require 'expect'
require 'timeout'

# expect で読み込んだ内容を標準出力に出力するおまじない
$expect_verbose=true

class MkdirExpect
  # ログイン情報を入力
  @@hostname="ubuntu"
  @@username="tsu-nera"
  @@password="*******"

  def setup
    # telnet通信を確立
    @pty = PTY.spawn("telnet -l #{@@username} #{@@hostname}")
    @sin = @pty[0]
    @sout= @pty[1]
    @pid = @pty[2]

    @sout.sync=true
    @sin.expect("Password:"){ @sout.puts "#{@@password}" }
  end

  def teardown
    # telnet通信の終了
    @sin.expect(/[$%#]/){@sout.puts "exit" }
  end

  def mkdir_testdir
    # Setup
    @sin.expect(/[$%#]/){
      @sout.puts "test -f testdir || rmdir testdir"
    }

    # Test
    @sin.expect(/[$%#]/){ @sout.puts "mkdir testdir" }

    # Verify
    @sin.expect(/[$%#]/){ @sout.puts "ls" }
    @sin.expect("testdir")

    # teardown
    return 0
  end

  def mkdir_two_directory
    # Setup
    @sin.expect(/[$%#]/){ @sout.puts "test -f dir1 || rmdir dir1" }
    @sin.expect(/[$%#]/){ @sout.puts "test -f dir2 || rmdir dir2" }

    # Test
    @sin.expect(/[$%#]/){ @sout.puts "mkdir dir1" }
    @sin.expect(/[$%#]/){ @sout.puts "mkdir dir2" }

    # Verify
    @sin.expect(/[$%#]/){ @sout.puts "ls" }
    @sin.expect("dir1")
    @sin.expect(/[$%#]/){ @sout.puts "ls" }
    @sin.expect("dir2")

    # teardown
    return 0
  end

  def mkdir_timeout
    # Setup
    @sin.expect(/[$%#]/){
      @sout.puts "test -f testdir || rmdir testdir"
    }

    # Test
    @sin.expect(/[$%#]/){ @sout.puts "mkdir testdir" }

    # Verify
    @sin.expect(/[$%#]/){ @sout.puts "ls" }
    begin
      timeout(3) { @sin.expect("testdir2", 5) }
    rescue Timeout::Error => ex
      @sout.puts "exit"
      puts ex.message
      return ex.class
    end

    # teardown
    return 0
  end
end

次は、テストスイート。これは公式リファレンスを見よう見まねで作成。

ts_mkdir_expect.rb

# -*- coding: utf-8 -*-
require 'minitest/unit'
require 'minitest/autorun'
require './tc_mkdir_expect'

class TestMkdirExpect < MiniTest::Unit::TestCase
  def setup
    @foo = MkdirExpect.new
    @foo.setup
  end

  def teardown
    @foo.teardown
    @foo = nil
  end

  def test_testdir
    assert_equal 0,@foo.mkdir_testdir
  end

  def test_mkdir_two_directory
    assert_equal 0,@foo.mkdir_two_directory
  end

  def test_mkdir_timeout
    assert_equal Timeout::Error,@foo.mkdir_timeout
  end

end

テスト結果

最後に、テストを実行してみる。なかなかよさげだ。

$ ruby ts_mkdir_expect.rb

Finished tests in 37.559148s, 0.0799 tests/s, 0.0799 assertions/s.

3 tests, 3 assertions, 0 failures, 0 errors, 0 skips

テストケースごとにテストを実行することもできる。

$ ruby ts_mkdir_expect.rb -n test_mkdir_timeout

タイムアウトで失敗させると、それなりのメッセージがでる。

Finished tests in 16.746958s, 0.0597 tests/s, 0.0597 assertions/s.

1) Failure:

test_mkdir_timeout(TestMkdirExpect) [ts_mkdir_expect.rb:27]:

Expected: 0

Actual: Timeout::Error

1 tests, 1 assertions, 1 failures, 0 errors, 0 skips

終わりに

実際にテストできるかどうかはまだまだ試行錯誤が必要そうだ。実際の仕事で適用するためには、後処理から正常な状態に復旧させる処理が最大の課題だと思っている。あとメンテナンスも。

なんとなく、可能性だけはつかめた気がしたので、いろいろと隠れて遊んでみようと思う。

03 Oct 2012, 12:15

地獄の苦しみ、メモリ破壊をCppcheckで華麗に食い止めよう!

前回の記事の続き。

CppCheckでC言語/C++のメモリリーク(解放漏れ)を静的解析で検出する

Cppcheckを利用して、バッファオーバーランを検出したい。

バッファオーバーランとは、バッファオーバーフロー、メモリ破壊、メモリ不正番地アクセスとも言われていて、組込みエンジニアを一瞬のうちに恐怖に戦かせる魔法のぽぽぽぽーんだ。

いろんなパターンのメモリ破壊をCppCheckで検出できるか、遊んでみた。

メモリ解放したあとにアクセスしてしまうパターン

[c]

void buffer_over_run(void)

{

char *p;

p = (char *)malloc(1);

free(p);

*p = 3;

}

[/c]

[text]

$ cppcheck –enable=all memory_leak.c

Checking memory_leak.c…

[memory_leak.c:21]: (error) Dereferencing ‘p’ after it is deallocated / released

[memory_leak.c:21]: (error) Uninitialized variable: p

Checking usage of global functions..

[/text]

関係ないメモリ領域に勝手にデータを書き込んでしまう領域破壊パターン

[c]

void buffer_over_run(void)

{

char *p;

p = (char *)malloc(1);

memset(p,”c”,2);

free(p);

}

[/c]

[text]

$ cppcheck –enable=all memory_leak.c

Checking memory_leak.c…

[memory_leak.c:11]: (error) Buffer is accessed out of bounds.

Checking usage of global functions..

[/text]

配列で宣言した領域をオーバーするパターン

[c]

void buffer_over_run(void)

{

char c[5];

c[5] = 3;

}

[/c]

[text]

$ cppcheck –enable=all memory_leak.c

Checking memory_leak.c…

[memory_leak.c:8]: (style) Variable ‘c’ is assigned a value that is never used

[memory_leak.c:21]: (error) Array ‘c[5]’ accessed at index 5, which is out of bounds.

Checking usage of global functions..

[/text]

インクリメントすることで、知らないうちに不正番地アクセス

[c]

void buffer_over_run(void)

{

char *p;

p = (char *)malloc(1);

p++;

*p = 1;

printf(“%x”,p);

free(p);

}

[/c]

[text]

$ cppcheck –enable=all memory_leak.c

Checking memory_leak.c…

Checking usage of global functions..

[/text]

あれ、検出してくれない・・・・そして

$ ./a.exe
*p = 800482a8
Aborted (コアダンプ)

ちょ・・・・なんとかしてよ。

おまけ

ネットを徘徊していたら、メモリ破壊についての面白い詩をみつけた。

直接引用はチョッと気が引けるので、参考リンクとしてリンク貼っておく。

諸君、私はC言語が好きだ

02 Oct 2012, 23:35

CppCheckでC言語/C++のメモリリーク(解放漏れ)を静的解析で検出する。

メモリ解放漏れ・メモリ二重解放は組込みエンジニアにとって、背筋が凍る単語だ。

それは、即、残業しなさいという意味に転じる。

そこから、泥沼のデバッグにハマることがよくある。

そんな課題をスマートに解決するために、メモリ解放漏れやメモリ二重解放を検出するツール調べてみたので、メモメモ。

オープンソース CppCheckのインストールをしよう

Cppcheckを使うことでメモリ解放漏れを静的解析で見つけることが可能だ。CppCheckはその他にも、アロケーション(確保と解放)の不一致(メモリ二重解放),バッファオーバーランの検出ができる。OSSなので、誰でも無料で利用可能。

CppCheckのダウンロードはココから

Cppcheckの使い方の日本語訳は、以下のサイトで公開されている。

(ものすごく感謝!)今回はこれを参考に自分でも試してみる。

cppcheck 日本語マニュアル – 一人ぼっちの共鳴

cppcheck 英語マニュアルはこちちから

Cppcheckでメモリリークを検出する

Cppcheckを利用するには、–enable=allオプションをつけて以下のコマンド実行。

[text]

cppcheck –enable=all [フアイル名]

[/text]

試しにこんなコードを書いてみた。

memory_leak.c

[c]

#include

#include

int main(void)

{

int *p = NULL;

printf(“*p = %x\n”,p);

p = malloc(10);

printf(“*p = %x\n”,p);

return 0;

}

[/c]

なかなか、喧嘩を売っているコードだけれども、

これをCppCheckでチェックすると、案の定怒られる。(よしよし (^-^))

[text]

$ cppcheck –enable=all memory_leak.c

Checking memory_leak.c…

[memory_leak.c:12]: (error) Memory leak: p

Checking usage of global functions..

[/text]

自分で定義したメモリ獲得/解放関数のメモリリークをチェックする

次に、ユーザ定義したメモリ獲得/解放関数をチェックする。

普通、C標準のメモリ獲得/解放関数を直接使用することはなく、自前の関数でカスタマイズして使用することが多い。メモリアロケート関数を別ファイルで宣言してみる。

hoge_memory.c

[c]

#include “hoge_memory.h”

void *hoge_malloc(void)

{

return malloc(10);

}

memory_leak.c

void hoge_free(void *p)

{

free(p);

}

#include

#include “hoge_memory.h”

int main(void)

{

char *p = NULL;

printf(“*p = %x\n”,p);

p = (char *)hoge_malloc();

printf(“*p = %x\n”,p);

return 0;

}

[/c]

[text]

$ cppcheck –enable=all memory_leak.c hoge_memory.c

Checking hoge_memory.c…

12 files checked 40% done

Checking memory_leak.c…

22 files checked 100% done

Checking usage of global functions..

[/text]

Oh! 検出してくれないYo!!(゜д゜)/

こんなときは、–appendオプションを使用する。

使い方は、

[text]

cppcheck 窶錀-append=<メモリ獲得・解放関数定義file> <静的解析対象file>

[/text]

[text]

$ cppcheck –enable=all –append=hoge_memory.c memory_leak.c

Checking memory_leak.c…

[memory_leak.c:13]: (error) Memory leak: p

Checking usage of global functions..

[/text]

これで、、メモリリークを検出しました。

メモリ二重解放を検出する

おまけ。メモリ二重解放もこのとおり発見できます!スゲー。

[c]

int main(void)

{

char *p = NULL;

printf(“*p = %x\n”,p);

p = (char *)hoge_malloc();

printf(“*p = %x\n”,p);

hoge_free(p);

hoge_free(p);

return 0;

}

[/c]

[text]

$ cppcheck –append=hoge_memory.c memory_leak.c

Checking memory_leak.c…

[memory_leak.c:15]: (error) Deallocating a deallocated pointer: p

[/text]

使われていない関数宣言

[text]

$ cppcheck –append=hoge_memory.c –enable=all memory_leak.c

Checking memory_leak.c…

Checking usage of global functions..

[memory_leak.c:18]: (style) The function ‘hogehoge_special’ is never used

[/text]

25 Aug 2012, 22:26

そろそろ『test driven development for embedded c』について書いてみる

1年以上前からずっと読んでいる本について書いてみる。

『test driven development for embedded c』

はじめに

C言語を使った組込み開発でテスト駆動開発をどう実践するかについてかかれた本である。

この本は、印刷された本のみではなくて、電子書籍としても販売されているのが嬉しい。しかも、電子書籍上のURLをクリックすると、その部分のソースをダウンロードできるところが、またなんともいえなく感動的である。

自分は、はじめは通勤中に本をカバンにいれて読んでいたのだけれども、ある日上司に勝手にバックのなかを覗かれて、

『これはなんだ!』

と、エロ本を見つけた先生のようにニヤけながらいわれたのが嫌で、電子書籍を購入した。

(電子書籍はここから)

http://pragprog.com/book/jgade/test-driven-development-for-embedded-c

内容について

はじめはテスト駆動開発のことが述べられているのだが、だんだんと関係ない話題が出てきて、C言語でオブジェクト指向ライクに書くための方法だったりが混じってきて、最後のほうはTDDとはあまり関係なく、いかにして”Clean Code”をかくかということに主眼が移っていくことが、?と!で面白かった。

簡単な要約

扱っているテストツールについて

の2つが紹介されている。

Unityは軽量なツールなので、結構良かった。

CppTestは、TestSuiteを作成しなくても、自分で作成してくれるところがいいところ。ほかにも、様々なサボートツールがついている(モックオブジェクト作成用のCppUMock、関数ポインタを置き換えるツールUT_PER_SET)ので、便利(これもすべて、書籍のなかでつかいかたは説明されている)

自分で作ったごみwikiのリンクもついでに貼っておこう。

http://www.wikihouse.com/fox10225fox/index.php?CppUTest

TDDの他のオススメ本についてのゴミlinkもついでに貼っておこう。

TDD テスト駆動開発 2012年 オススメ本ランキング

おわりに

仕事がC言語で組込み開発な自分にとっては最上のTDDバイブルだった。年甲斐もなく、ボロボロになるまで読んでいる。スルメイカのように、読めば読むほどに発見があるので、1年たった今でも新鮮だ。

(2013/10/22 追記)

日本語訳がでたようだ。