Web開発者向けのMSP430プラクティス

ハブには初心者向けの記事がたくさんあります-このTexas Instruments MSP430 LaunchPadがどれほど魔法で素晴らしいものか。 ただし、通常、LEDを備えた標準的なフラッシャーを超える人はいません。 この状況を修正する時が来ました。

チームとして、バージョン管理に古き良きSVNを使用します。 マイクロコントローラはどこにあるのでしょうか?

リポジトリへの次のコミットを通知するために、このすばらしい仕掛けを採用しました。







アイデア


リポジトリへの次のコミットについてメロディーを通知するデバイスが欲しいです。 各開発者が独自のメロディを持っていると便利であり、誰が次のコミットをしたのかを聞くことができます。



プロジェクト


Webフロントエンドとして、WebSVNは基本認証によって閉じられ、SVNに対して閉じられます。 これにより、プロジェクトとそのリビジョンのリストにアクセスできます。 次に、スケジュールに従って、たとえば、1分に1回、プロジェクトリポジトリで新しいコミットをチェックするプロセスが必要です。 PHPは手に最も近いため、その上に記述することにしました。 作業システムは、Apache 2.1 + PHP 5.3.6を搭載したWindows 7です。

新しいコミットが検出されると、スクリプトはCOMポートのデバイスに制御コマンドを送信し、作成者のメロディを再生するように指示します。



したがって、WebSVNがあります。







PHPを使用して、プロジェクトのリストを解析し、各プロジェクトを調べます。

index.php
<? //     set_time_limit(0); //      require 'functions.php'; require 'config.php'; //  CURL $s = curl_init(); curl_setopt($s, CURLOPT_URL, $svnURL); curl_setopt($s, CURLOPT_USERPWD, $authLogin.':'.$authPass); curl_setopt($s, CURLOPT_USERAGENT, 'CommitBeep 1.0'); curl_setopt($s, CURLOPT_REFERER, $svnURL); curl_setopt($s, CURLOPT_RETURNTRANSFER, true); //    $page = curl_exec($s); $httpCode = curl_getinfo($s, CURLINFO_HTTP_CODE); curl_close($s); //     $doc = new DOMDocument(); $doc->loadHTML($page); $links = $doc->getElementsByTagName('a'); foreach ($links as $link) { $link = dom2array($link); if (strpos($link['@attributes']['href'], 'listing.php?repname') !== false) { $projectName = $link['#text']; checkSVNCommit($projectName); } }
      
      





基本認証でログインするには、CURLライブラリの機能を使用します。

また、DOMDocumentとDOMを使用してHTMLを解析します。



なぜなら PHPからDOMを操作するのはかなり面倒ですが、すべてのリンクを取得するだけで、dom2array()関数を使用します。

functions.php dom2array()
 /** *  DOM    * @param object $node  */ function dom2array($node) { $res = array(); if($node->nodeType == XML_TEXT_NODE){ $res = $node->nodeValue; } else{ if($node->hasAttributes()){ $attributes = $node->attributes; if(!is_null($attributes)){ $res['@attributes'] = array(); foreach ($attributes as $index=>$attr) { $res['@attributes'][$attr->name] = $attr->value; } } } if($node->hasChildNodes()){ $children = $node->childNodes; for($i=0;$i<$children->length;$i++){ $child = $children->item($i); $res[$child->nodeName] = dom2array($child); } } } return $res; }
      
      







各プロジェクトには独自のページがあり、最新のリビジョンと作成者を示します。







すべて同じCURLを使用して、リビジョン番号とその作成者を選択します。 explode()およびstrpos()を解析するのはひどいですが、うまくいきます。

functions.php checkSVNCommit()
 /** *     ,   * @param string $projectName   */ function checkSVNCommit($projectName) { require 'config.php'; //       $old_rev = @file_get_contents('revisions/'.$projectName.'.txt'); $rev = 0; $user = 'unknown'; //  CURL $s = curl_init(); curl_setopt($s, CURLOPT_URL, $svnURL.'/listing.php?repname='.urlencode($projectName).'&path=%2F&sc=0'); curl_setopt($s, CURLOPT_USERPWD, $authLogin.':'.$authPass); curl_setopt($s, CURLOPT_USERAGENT, 'CommitBeep 1.0'); curl_setopt($s, CURLOPT_REFERER, $svnURL); curl_setopt($s, CURLOPT_RETURNTRANSFER, true); //    $page = curl_exec($s); $httpCode = curl_getinfo($s, CURLINFO_HTTP_CODE); curl_close($s); //   ,      $page = explode("\n", strip_tags($page)); foreach($page as $line) { if (strpos($line, 'Last modification:') !== false) { $line = explode(' ', $line); $rev = $line[3]; $user = $line[5]; } } echo "$projectName $rev $user<br/>\n"; //  ? ! if ($rev != $old_rev) { beep($comNumber, getMelodyByUser($user)); file_put_contents('revisions/'.$projectName.'.txt', $rev); } }
      
      







実装は平凡で不器用ですが、うまく機能します。 テキストファイルから古いリビジョンを読み取り、現在のリビジョンと比較します。 異なる場合は、書き込みとビープ音を鳴らします。



最初の落とし穴


COMポートでの作業は難しくないと146%確信していました。 判明したように、Windows 7の古いfopenメソッド(「COM6:」、「w +」)は機能しなくなりました。 十分なアクセス権がありません。 さらに、コンソールが出力をポートにリダイレクトしても、アクセスエラーが再び発生します。 したがって、cmd(bat)から-ファイルも成功せず、exec()を使用しても機能しません。

強力なグーグルは、Windows拡張機能-PHP Serialに私​​を連れてきました。

すべての拡張機能と同様に、非常に簡単に接続し、2本の指のように機能します。

functions.phpビープ音()
 /** *    * @param integer $com  COM- * @param integer $melody   */ function beep($com = 6, $melody = 1) { ser_open("COM".$com, 9600, 8, "None", "1", "None"); ser_write("$melody"); ser_close(); }
      
      







マイクロコントローラを搭載したビビカロ


LaunchPadをプログラムする番です。 Energiaを開発環境として使用してください。

Arduinoとは異なり、MSP430の場合、シリアルポートの操作方法はそれほど明確ではありません。 TimerSerialライブラリが共存していることが判明しました。これは、Arduinoベースのシリアルベースライブラリの修正版です。

少し努力すれば、ターミナルで書き込みと読み取りができます。

端末での作業の例
 #include <TimerSerial.h> TimerSerial mySerial; //   void setup() { mySerial.begin(); mySerial.println("Welcome to CommitBeep 1.0"); } //   void loop() { while (mySerial.available()) { char inChar = (char)mySerial.read(); mySerial.write(inChar); delay(100); } }
      
      







この単純な小さなプログラムは、文字を読み取り、すぐに書き戻します。 エコーのように。



落とし穴。 継続する。


したがって、データの受信と送信が整理されます。 今、ビープ音。

Energiaでは、標準のトーンライブラリも何らかの方法で変更されています。 そして、最も不快なのは、彼らは決してTimerSerialとは友達ではないということです。 おそらく一般的なタイマーなどを使用していましたが、一緒に使用することはできませんでした。

自転車を書かなければなりませんでした。



タビビビカロ
 #define NOTE_G3 196 #define NOTE_A3 220 #define NOTE_C4 262 int speakerPin; //   void setup() { speakerPin = 14; //  1.6 ( 14)      pinMode(speakerPin, OUTPUT); beep(); } void playTone(int tone, int duration) { for (long i = 0; i < duration * 1000L; i += tone * 2) { digitalWrite(speakerPin, HIGH); delayMicroseconds(tone); digitalWrite(speakerPin, LOW); delayMicroseconds(tone); } digitalWrite(speakerPin, LOW); } //  void beep() { int melody[] = {NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3}; int noteDurations[] = {4,8,8,4,4}; for (int thisNote = 0; thisNote < 4; thisNote++) { int noteDuration = 1000/noteDurations[thisNote]; playTone(melody[thisNote], noteDuration); } }
      
      







すべての問題は解決しましたが、コードを記述する必要があります。 一般に、残りは非常に簡単です。

スケッチを組み合わせて取得します。

commit_beep.ino
 #include <TimerSerial.h> #define NOTE_B0 31 #define NOTE_C1 33 #define NOTE_CS1 35 #define NOTE_D1 37 #define NOTE_DS1 39 #define NOTE_E1 41 #define NOTE_F1 44 #define NOTE_FS1 46 #define NOTE_G1 49 #define NOTE_GS1 52 #define NOTE_A1 55 #define NOTE_AS1 58 #define NOTE_B1 62 #define NOTE_C2 65 #define NOTE_CS2 69 #define NOTE_D2 73 #define NOTE_DS2 78 #define NOTE_E2 82 #define NOTE_F2 87 #define NOTE_FS2 93 #define NOTE_G2 98 #define NOTE_GS2 104 #define NOTE_A2 110 #define NOTE_AS2 117 #define NOTE_B2 123 #define NOTE_C3 131 #define NOTE_CS3 139 #define NOTE_D3 147 #define NOTE_DS3 156 #define NOTE_E3 165 #define NOTE_F3 175 #define NOTE_FS3 185 #define NOTE_G3 196 #define NOTE_GS3 208 #define NOTE_A3 220 #define NOTE_AS3 233 #define NOTE_B3 247 #define NOTE_C4 262 #define NOTE_CS4 277 #define NOTE_D4 294 #define NOTE_DS4 311 #define NOTE_E4 330 #define NOTE_F4 349 #define NOTE_FS4 370 #define NOTE_G4 392 #define NOTE_GS4 415 #define NOTE_A4 440 #define NOTE_AS4 466 #define NOTE_B4 494 #define NOTE_C5 523 #define NOTE_CS5 554 #define NOTE_D5 587 #define NOTE_DS5 622 #define NOTE_E5 659 #define NOTE_F5 698 #define NOTE_FS5 740 #define NOTE_G5 784 #define NOTE_GS5 831 #define NOTE_A5 880 #define NOTE_AS5 932 #define NOTE_B5 988 #define NOTE_C6 1047 #define NOTE_CS6 1109 #define NOTE_D6 1175 #define NOTE_DS6 1245 #define NOTE_E6 1319 #define NOTE_F6 1397 #define NOTE_FS6 1480 #define NOTE_G6 1568 #define NOTE_GS6 1661 #define NOTE_A6 1760 #define NOTE_AS6 1865 #define NOTE_B6 1976 #define NOTE_C7 2093 #define NOTE_CS7 2217 #define NOTE_D7 2349 #define NOTE_DS7 2489 #define NOTE_E7 2637 #define NOTE_F7 2794 #define NOTE_FS7 2960 #define NOTE_G7 3136 #define NOTE_GS7 3322 #define NOTE_A7 3520 #define NOTE_AS7 3729 #define NOTE_B7 3951 #define NOTE_C8 4186 #define NOTE_CS8 4435 #define NOTE_D8 4699 #define NOTE_DS8 4978 TimerSerial mySerial; int speakerPin; //   void setup() { speakerPin = 14; //  1.6 ( 14)      mySerial.begin(); mySerial.println("Welcome to CommitBeep 1.0"); pinMode(speakerPin, OUTPUT); } void playTone(int tone, int duration) { for (long i = 0; i < duration * 1000L; i += tone * 2) { digitalWrite(speakerPin, HIGH); delayMicroseconds(tone); digitalWrite(speakerPin, LOW); delayMicroseconds(tone); } digitalWrite(speakerPin, LOW); } //  void beep(int melody) { switch ((int)melody) { case '2': { int mel[] = {NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3}; int noteDurations[] = {4,8,8,4,4}; for (int thisNote = 0; thisNote < 4; thisNote++) { int noteDuration = 1000/noteDurations[thisNote]; playTone(mel[thisNote], noteDuration); } break; } case '3': { int mel[] = {NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3}; int noteDurations[] = {4,8,8,4,4}; for (int thisNote = 0; thisNote < 4; thisNote++) { int noteDuration = 1000/noteDurations[thisNote]; playTone(mel[thisNote], noteDuration); } break; } default: { int mel[] = {NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3}; int noteDurations[] = {4,8,8,4,4}; for (int thisNote = 0; thisNote < 4; thisNote++) { int noteDuration = 1000/noteDurations[thisNote]; playTone(mel[thisNote], noteDuration); } } } } //   void loop() { while (mySerial.available()) { char inChar = (char)mySerial.read(); beep(inChar); delay(100); } }
      
      







接続し、入力し、ターミナルウィンドウを開き、そこに1を書き込んで、デフォルトのメロディーを聴きます。







タスクスケジューラ


奇妙なことに、PHPスクリプトのバックグラウンド実行にタスクスケジューラを使用します。



PHPとスクリプト自体を呼び出すCMDファイルを作成しましょう。

D:\denwer\usr\bin\php5.exe D:\denwer\home\test\www\commit_beep\index.php







そして、このファームに黒いコンソールウィンドウが目障りにならないように、Andrei Grechkinのシンプルなhidconユーティリティを使用します。



スケジューラー接続:










最後の仕上げ


それ自体で、すべてがすべてのコミットで熱心に機能します。 しかし、テーブルはあまり美しくありません。 オフィス用のナイフと電気テープで少し働いて、新しい鉄片を素敵なプラスチックケースに包むことが残っています:









まとめ


ある日、アイデアから完成したデバイスまで開発します。 落とし穴に対する興味深くエキサイティングな戦いとEnergiaとMSP430の紹介。

プロジェクト予算は200〜300ルーブル。



githubのソース



更新: RTTTLのサポートが追加されました-ハードモードUARTのメロディー。

ハードモードを有効にするには、RT / TXジャンパーをドラッグする必要があります( BoxaShuに感謝)。

ソースコードを更新しました。



All Articles