ホームページ開発ツール>UPS用ソフトウェア作成記録

UPS用ソフトウェア作成記録


【免責】

 以下は筆者(作者)が個人的に行った作業の記録であり、その結果を何ら保証するものではありません。また、下記手順を再現することにより、機器の破損やシステムクラッシュ等が発生したとしても、作者は一切関知しません。全ての作業は、各自の責任において行って下さい。

 また、下記の解釈は作者が行ったものであり、正しいとは限りません。もし、誤りや、より正確な情報がありましたら、icb31246@nifty.comまでお知らせいただければ幸いです。


【自作ソフトウェアの非公開について】

 ここで自作したソフトウェアは、あくまで作者が実験のために作成したものであり、汎用性については考慮していません。そのため、任意の環境で動作する保証は全くないため、公開していません。あくまで自作のための参考情報を呈示するものとお考え下さい。


【はじめに】

 APC社製UPS「APC CS 500」を導入しました。
 これには、Mac OS X用のユーティリティは付属していますが、Mac OS 9用は付属していません。(ソフトウェア自体は付属CD-ROMに含まれているのですが、CS 500には未対応です。ちなみにインストールして確かめてみましたが、動きませんでした。)

 そこで、自作に挑戦してみました。
 なお、通常この類のソフトウェアは「機能拡張/コントロールパネル書類」とすることが多いのですが、ここではREALbasicによる実装を行ったため、アプリケーション形式となっています。

 また、ここで作成したソフトウェアは「APC CS 500」に特化していますが、USB接続のUPSであれば対応できる可能性があります。(勿論、保証はできませんが。)


【USBに関する情報の調査】

 CS 500はUSB機器であり、CS 500から情報を取得するためには、まずUSBについて知らなければなりません。そこでUSBについて調べてみました。

 USB機器はいくつかの種類に分類されますが、UPSは「HID」に分類されます。
 HID にはさらにいくつかのサブ分類があり、UPSは「Power Class HID devices」に分類されます。
 Power Class HID devices は、USB Implementers Forum, Inc.が定めた「Universal Serial Bus Usage Tables for HID Power Devices」(以下、仕様書と記述。解説ページはこちら。)に規定されていて、これを見ればUPSから取得(およびセット)できる項目が分かります。

 一方、AppleはUSBドライバ開発のためのDDKを用意しています。Mac OS 9用の最新版は1.5.5f1で、ここからダウンロードできます。
 1.4からは「Mac OS USB Power Class」という、Power Class HID devices に準拠したAPIが追加され、利用方法は「PowerClassQueryDevice」という、DDK付属のサンプルに示されています。

 サンプルを見る限り、通常のHID用APIではなく、Mac OS USB Power Class の方がずっと簡単そうなので、こちらを利用することにしました。


【Mac OS USB Power Classが動作する環境】

 Mac OS 9.2.1では、標準の環境で動作するはずです。
 それ以前のバージョンでは、USB関連の機能拡張をDDK 1.5.5f1付属のものに置き換える必要があります。


【自作ソフトウェアの仕様】

 基本的な事柄の理解と今後の改良のベースにすることを目的として、まずはシンプルなアプリケーションを作ることにしました。
 即ち、UPSに供給される商用電源の状態が通電中であるか電源断(停電)であるかを調べ、その状態をメッセージ表示する、という単純なものです。


【UPSからの情報取得方法】

 PowerClassQueryDevice 同梱のRead Me(まずはご一読下さい。)によると、情報の取得方法は、
  1. GetNextPowerDevice で、機器の Reference を取得。
  2. USBPowerGetUsageData で、必要な値を取得。
となっています。このうち、2. ではパラメータとして Reference, Collection, UsagePage, Usage を指定しますが、UsagePage, Usage は仕様書を調べれば分かります。
 問題は Collection で、これの構成自体は USBPowerFindCollection で調べることができますが、何番がどの Collection なのかは分かりません。
(仕様書には各 Collection の番号を格納する項目があるのですが、Mac OS USB Power Class APIでは取得できないようです。)

 そこで、DDK付属のHID Browserで調べてみました。それによるとCS 500では、
  1.  UPS
  2.    PowerSummary
  3.      PresentStatus
  4.    Battery
  5.    Input
  6.    Output
  7.    PresentStatus
  8.    Reserved Usage
  9.    PowerConverter
となっていました。(インデントは親子関係があることを示す。)
 これで、必要なパラメータを全て知ることができました。


【設計】

 電源断を判定するためには「AC Present」という項目を監視します。
 AC Present は PresentStatus Collection(上記リストから、ここでは「3」)に含まれ、UsagePage, Usage は仕様書によると、それぞれ 0x84, 0xD0 です。

 従って、GetNextPowerDeviceReference を取得後、
  USBPowerGetUsageData(Reference,3,0x84,0xD0,*value)
とすれば、value に現在のステータス(1なら通電中、0なら電源断)が返ってきます。

 あとはこれをタイマで定期的に監視し、値に応じたメッセージを表示すればいい訳です。


【実装】

 機器の Reference 取得と value 取得は、基本的にはサンプルをそのまま使えばいいのですが、サンプルはCodeWarrior用にC言語で書かれているため、REALbasicではDeclareを使って書き直す必要があります。
 それぞれ下記のとおりとしました。

機器の Reference 取得(アプリ起動時に1回取得すればよい)
Function GetNextPowerDevice() As Integer
   Declare Function GetNextPowerDevice Lib "USBPowerClassLib" (deviceRef As Ptr) As Integer

   Dim deviceRef as MemoryBlock
   Dim kNoDeviceRef, err, res as Integer

   kNoDeviceRef=-1
   deviceRef=NewMemoryBlock(14)
   deviceRef.Long(8)=kNoDeviceRef

   do

      err=GetNextPowerDevice(deviceRef)
      if err=0 then
         res=deviceRef.Long(8)
      end if

   loop until err<>0

   return res
(注:上記方法は、UPSが1台しか接続されていないことを前提にしています。通常、これで問題ない筈ですが、必要であれば製品名をチェックする等の処理を追加した方がいいかもしれません。)

値の取得(タイマのActionからコールして、一定時間ごとに取得を繰り返す)
Function GetUsageData(ref As Integer, collection As Integer, page As Integer, usage As Integer) As Integer
   Declare Function USBPowerGetUsageData Lib "USBPowerClassLib"  // 改行を削除して次行と連結すること
    (ref As Integer, collection As Integer, page As Integer, usage As Integer, value As Ptr) As Integer

   Dim value as MemoryBlock
   Dim kUSBPending, err as Integer

   kUSBPending=1
   value=NewMemoryBlock(4)

   err=USBPowerGetUsageData(ref,collection,page,usage,value)

   if err=0 then
      return value.Long(0)

   elseif err=kUSBPending then
      err=USBPowerGetUsageData(ref,collection,page,usage,value)
      return value.Long(0)

   else
      'MsgBox "Error="+str(err)+" ( "+hex(collection)+":0x"+hex(page)+":0x"+hex(usage)+" )"
      return err

   end if
(注:Pendingが返ってきた場合の再取得は1回ですが、これはサンプルがそうなっているからで、何度か繰り返した方がいいのかもしれません。ただ、実用上は特に問題なさそうです。)


【作成&テスト】

 上記メソッドを組み込んだアプリケーションをREALbasic 4.0.3J Classicで作成し、テストしてみました。
  1. ソフトウェア起動直後は通電中のメッセージが表示されました。
  2. UPSのコンセントを引っこ抜くと、次のタイマのタイミングで電源断のメッセージが表示されました。
  3. コンセントを差し込むと、次のタイマのタイミングで再び通電中のメッセージが表示されました。
 という訳で、正常に機能しているようです。
 あとは、一定時間電源断が続いたらシャットダウンする機能を追加する、等の応用が考えられます。


【問題点】

 USBPowerGetUsageData を使えば、AC Present 以外にも値を取得することができます。
 ですが、HID Brouserの結果と突き合わせてみると一致しない項目が多く、どこまで信用していいのか疑問です。
 これらの項目の中には「電源断後、UPS内で設定されている時間を経過した」や「バッテリ容量がUPS内で設定されている容量を下回った」等の有用な情報もあり、使えないのは残念です。

(コールする度にUPSから取ってきている訳ではない(キャッシュしている?)ような印象です。仕様なのかバグなのかは定かではありません。もしかするとリフレッシュのための手続きがあるのかもしれませんが、少なくともRead Meには書かれていません。)

 ただし AC Present に関しては、実際の状況とリアルタイムにリンクしていることが確認できたため、今回のソフトウェア程度の機能であれば、利用に支障はなさそうです。
 製品版のソフトウェアのように、詳細な情報をリアルタイムに表示するためには、HID APIを使う等する必要があるかもしれません。


【今後について】

 現在のUSBの環境がちょっと特殊(キーボードはPC/AT用、マウスは多機能マウス、おまけにUSBハブとして、以前使っていたキーボードを流用)なので、純正に戻す等、いろいろ試行してみる必要があり、また、そのつもりです。

 さらに、Mac OS USB Power Class には、USBPowerSetUsageData という、UPSにデータを送る命令もあるのですが、怖くて(笑)試していません。これもいずれはトライしてみたいです。



[Home]  [MacSoft]  [Donation]  [History]