はじめに
理屈はよくわからないけれど、Turbo Pascal で『MSX0 Stack』の IoT 関係の機能が使えそうだったので、ライブラリとして整備してみました。
ライブラリ
汎用ライブラリの SYSUTILS.LIB
と、IoT 関係の機能を使うための IOT.LIB
から構成されます。
SYSUTILS.LIB
よく使うであろう機能を入れてあります。
(*
SYSUTILS.LIB
*)
type
HexStr = string[8];
BinStr = string[32];
ItemStr = string[80];
PItem = ^TItem;
TItem = record
Data: ItemStr;
Prev: PItem;
Next: PItem;
end;
procedure AddListItem(var List, Last: PItem; s: ItemStr);
var
p: PItem;
begin
New(p);
if List = nil then
begin
List := p;
Last := nil;
end
else
Last^.Next := p;
p^.Data := s;
p^.Prev := Last;
p^.Next := nil;
Last := p;
end;
procedure ClearListItem(var List: PItem);
var
p, n: PItem;
begin
p := List;
while p <> nil do
begin
n := p^.Next;
Dispose(p);
p := n;
end;
List := nil;
end;
function UpperCase(s: ItemStr): ItemStr;
var
r: ItemStr;
i: byte;
begin
r[0] := s[0];
for i:=1 to Length(s) do
begin
if s[i] in ['a'..'z'] then
r[i] := Chr(Ord(s[i]) - 32)
else
r[i] := s[i];
end;
UpperCase := r;
end;
function LowerCase(s: ItemStr): ItemStr;
var
r: ItemStr;
i: byte;
begin
r[0] := s[0];
for i:=1 to Length(s) do
begin
if s[i] in ['A'..'Z'] then
r[i] := Chr(Ord(s[i]) + 32)
else
r[i] := s[i];
end;
LowerCase := r;
end;
function Inkey: char;
var
c: char;
begin
Inkey := #$00;
if KeyPressed then
begin
Read(kbd, c);
Inkey := c;
end;
end;
function IntToHex(v: Integer; w: byte): HexStr;
var
s: HexStr;
begin
if w < 1 then w := 1;
if w > 4 then w := 4;
s[0] := Chr(w);
while w > 0 do
begin
if v = 0 then
s[w] := '0'
else
begin
s[w] := Chr($30 + Ord(v and $000F > 9) * 7 + v and $000F);
v := v shr 4;
end;
w := w - 1;
end;
IntToHex := s;
end;
function IntToBin(v: Integer; w: byte): BinStr;
var
s: BinStr;
begin
if w < 1 then w := 1;
if w > 16 then w := 16;
s[0] := Chr(w);
while w > 0 do
begin
if v = 0 then
s[w] := '0'
else
begin
s[w] := Chr($30 + Ord(v and 1));
v := v shr 4;
end;
w := w - 1;
end;
IntToBin := s;
end;
動的配列のない Turbo Pascal のために、文字列リストを実装しました。
ルーチン | 説明 |
---|---|
AddListItem() | リストにアイテムを追加します。 |
ClearListItem() | リストのアイテムを全削除します。 |
UpperCase() | 文字列を大文字にしたものを返します。 |
LowerCase() | 文字列を小文字にしたものを返します。 |
Inkey() | 押されたキーの文字を返します。 |
IntToHex() | 整数を 16 進文字列に変換します。 |
IntToBin() | 整数を 2 進文字列に変換します。 |
Turbo Pascal 3.0 では、プログラム中で一度も使わないルーチンがあってもライブラリとしてリンクされてしまいます。実行形式ファイル (*.COM) が肥大化しがちなので、不要なルーチンはコメントアウトしてお使いください。
IOT.LIB
HRA! さんのコードを参考にしています。
(*
IOT.LIB
*)
const
_IOTADR1 = $58; { ver0.05.04: $08 }
_IOTADR2 = $57; { ver0.05.04: $10 }
procedure IotSetNode(s: LibStr);
var
i, l: byte;
begin
port[_IOTADR1] := $E0; port[_IOTADR1] := $01;
port[_IOTADR1] := $53; port[_IOTADR1] := $C0;
l := Length(s); port[_IOTADR1] := l;
for i:=1 to l do port[_IOTADR1] := Ord(s[i]);
port[_IOTADR1] := $00; l := port[_IOTADR1];
end;
function IoTFindCount(s: LibStr): integer;
var
r: array [0..1] of byte;
v: integer absolute r;
begin
IotSetNode(s);
port[_IOTADR1] := $E0; port[_IOTADR1] := $01;
port[_IOTADR1] := $11; port[_IOTADR1] := $80;
r[0] := port[_IOTADR1]; r[0] := port[_IOTADR1]; r[1] := port[_IOTADR1];
IoTFindCount := v;
end; { IoTFindCount }
procedure IoTFind(s: LibStr; var List, Last: PItem);
var
r: LibStr;
i, j, l, Cnt: byte;
begin
ClearListItem(List);
Cnt := IoTFindCount(s);
IotSetNode(s);
port[_IOTADR1] := $E0; port[_IOTADR1] := $01;
port[_IOTADR1] := $13; port[_IOTADR1] := $80;
for j:=1 to Cnt do
begin
l := port[_IOTADR1]; r[0] := Chr(l);
for i:=1 to l do r[i] := Chr(port[_IOTADR1]);
AddListItem(List, Last, r);
end;
end; { IoTFind }
function IoTGetInt(s: LibStr): integer;
var
r: array [0..1] of byte;
v: integer absolute r;
begin
IotSetNode(s);
port[_IOTADR1] := $E0; port[_IOTADR1] := $01;
port[_IOTADR1] := $01; port[_IOTADR1] := $80;
r[0] := port[_IOTADR1]; r[0] := port[_IOTADR1]; r[1] := port[_IOTADR1];
IoTGetInt := v;
end; { IoTGetInt }
function IoTGetStr(s: LibStr): LibStr;
var
r: LibStr;
i, l: byte;
begin
IotSetNode(s);
port[_IOTADR1] := $E0; port[_IOTADR1] := $01;
port[_IOTADR1] := $03; port[_IOTADR1] := $80;
l := port[_IOTADR1]; r[0] := Chr(l);
for i:=1 to l do r[i] := Chr(port[_IOTADR1]);
IoTGetStr := r;
end; { IoTGetStr }
procedure IoTPutInt(s: LibStr; v: integer);
begin
IotSetNode(s);
port[_IOTADR1] := $E0; port[_IOTADR1] := $01;
port[_IOTADR1] := $41; port[_IOTADR1] := $C0;
port[_IOTADR1] := SizeOf(integer);
port[_IOTADR1] := v and $00FF; port[_IOTADR1] := v shr 8;
end; { IoTPutInt }
procedure IoTPutStr(s: LibStr; v: LibStr);
var
i, l: byte;
begin
IotSetNode(s);
port[_IOTADR1] := $E0; port[_IOTADR1] := $01;
port[_IOTADR1] := $43; port[_IOTADR1] := $C0;
l := Length(v); port[_IOTADR1] := l;
for i:=1 to l do port[_IOTADR1] := Ord(v[i]);
port[_IOTADR1] := $00; l := port[_IOTADR1];
end; { IoTPutStr }
ルーチン | 説明 |
---|---|
IoTFindCount() | 対象のノードが持つアイテムの個数を取得します。 |
IoTFind() | 対象のノードが持つアイテム名のリストを取得します。 |
IoTGetInt() | ノードから整数値を読み出します。 |
IoTGetStr() | ノードから文字列を読み出します。 |
IoTPutInt() | ノードに対して整数値を書き込みます。 |
IoTPutStr() | ノードに対して文字列を書き込みます。 |
ファームウエアバージョン 0.07.08 以降で IoT 命令用の I/O アドレスが変更になっています。初期ファームウエア (0.05.04) の場合には _IOTADR1
と _IOTADR2
の値を書き替えてください。
使い方
SYSUTILS.LIB
と IOT.LIB
は Turbo Pascal のフォルダに放り込んでください。{$I ファイル名}
としてインクルードすると使えます。
program IOTTEST;
type
LibStr = string[80];
{$I SYSUTILS.LIB}
{$I IOT.LIB}
var
List, Last, p: PItem;
begin
{ Get Data }
writeln(IoTGetInt('host/battery/level'));
writeln(IoTGetStr('host/ip'));
{ Put Data }
IoTPutInt('conf/sound/volume', 7);
IotPutStr('conf/wifi/list/3/ssid', 'DEADBEEF');
IotPutInt('conf/save', 1);
writeln(IoTGetInt('conf/sound/volume'));
writeln(IoTGetStr('conf/wifi/list/3/ssid'));
{ Find Data }
writeln(IoTFindCount('host/media/dsk/');
List := nil;
IoTFind('host/media/dsk/', List, Last);
p := List;
while p <> nil do
begin
Writeln(p^.Data);
p := p^.Next;
end;
ClearListItem(List);
end.
IoTFind()
にはリストを使っています。List
, Last
というリスト (の先頭) を指すポインタと、リストの最後のアイテムを指すポインタを用意すると、リストが生成されます。リストが不要になったら ClearListItem()
を使ってリストアイテムを解放してください。
トランジェントコマンド
本記事にあるライブラリを用いて作られたトランジェントコマンド (外部コマンド) です。アーカイブには実行形式ファイル (*.COM
) とソースファイル (*.PAS
) が含まれています。
MSX-DOS2 上でコンパイルされているため、少なくとも MSX0 上で動作しない事はないと思います (MSX-DOS の方が TPA の空き領域が広いため、MSX-DOS 上でそのままコンパイルすると MSX-DOS2 で動作しない事があり得る)。
記事中のトランジェントコマンドのソースコード/バイナリは GitHub からもダウンロードできます。
ht-deko.com の個別アーカイブには古いファームウエア (0.05.04) に基いたバイナリが含まれています。ファームウエアバージョンが 0.07.08 以降の場合は再コンパイルを行うか、GitHub からバイナリを取得してください。
■ M0CLKUP
エミュレータのクロックアップを行う。
M0CLKUP [パーセント]
- パーセントを指定しない場合には現在の速度が表示されます。
- パーセントは 32..255 の間で有効です。
- C コンパイラでコンパイルする前にクロックアップして、実行前にクロックを元に戻すとかできます。
Download: M0ClkUp_110.zip (ht-deko.com)
■ M0SETUP
Setup Utility を起動する。
Usage: M0SETUP
- Setup Utility を起動します。
- 実行後にリセットが行われます。
Download: M0Setup_100.zip (ht-deko.com)
■ M0SHTDN
電源断または再起動を行う。
M0SHTDN [-h|-r]
- パラメータなしまたは
-h
で『MSX0 Stack』の電源断、-r
で再起動します。 - スイッチは
-
でも/
でもよく、大文字/小文字も区別しません。
Download: M0Shtdn_100.zip (ht-deko.com)
■ M0CHGDSK
M0CHGDSK [ディスクイメージ]
- パラメータなしで実行すると、ファイルリストと現在のディスクを示すインジケーターを表示します。
- ディスクイメージファイル名を指定すると、ディスクを変更します。
- ファイル名は自動的に大文字に変換されます。
- ファイル名は拡張子の省略が可能です。省略されると
.DSK
を追加します (拡張子のないファイルは使えません)。 - 空白を含むファイル名のためにダブルクォーテーション処理が入っていますが、簡易的なので可能な限り空白を含むファイル名は使わないでください。
- ディスク交換に失敗するとメッセージが表示されます。
- 交換先に M0CHGDSK があるとは限らないので、RAM ディスクにコピーして使う事をオススメします。
- MSX-C の環境ディスクを作るのに使ってみました。
Download: M0ChgDsk_110.zip (ht-deko.com) - ver0.05.04 用のバイナリが含まれる
Download: M0ChgDsk_120.zip (ht-deko.com) - ver0.07.08 以降用のバイナリが含まれる
■ M0SETAP
Wi-Fi の AP リストを登録する。
Usage: M0SETAP [登録AP番号 SSID パスワード [ON]]
- パラメータなしで実行すると、AP リストを表示します。
- 登録AP番号は 1~3。SSID と パスワードは平文で入力する事になるので、セキュリティに注意。
- 登録AP番号 4 は AP モード用 1。
- 4 番目のパラメータに
ON
(大文字/小文字の区別なし) を指定すると、登録した AP がアクティブになり Wi-Fi リスタート。 - 現在の登録 AP の内容が変更されると Wi-Fi リスタート。
- SSID に
-
を入力すると、登録 AP を空にできます。 - 一度登録した AP を未登録状態にはできない。環境設定ファイルを直接いじる必要がある。
- 接続先 AP の変更には M0CHGAP を使います。
Download: M0SetAP_110.zip (ht-deko.com)
Download: M0SetAP_120.zip (ht-deko.com) - AP モード対応版
■ M0CHGAP
M0CHGAP: Wi-Fi の接続先を変更する。
Usage: M0CHGAP [登録AP番号]
- パラメータなしで実行すると、登録APリストを表示します。
- 登録AP番号を指定するとその AP に切り替わり、Wi-Fi リスタート。
- 0 で OFF です。
- 4 で AP Mode です 1。
- AP 登録には M0SETAP を使います。
Download: M0ChgAP_110.zip (ht-deko.com)
Download: M0ChgAP_120.zip (ht-deko.com) - AP モード対応版
■ M0I2CSCN
M0I2CSCN: I2C スキャナ。
Usage: M0I2CSCN
- I2C ノードのデバイスを検索し、その ID を表示します。
- 内部接続 (Internal) は
device/i2c_i
にリストされます。 - 充電用のポゴピンに出ているのも内部接続用の I2C バスです。
- Port_A 接続 は
device/i2c_a
にリストされます。
Download: M0I2CScn_100.zip (ht-deko.com)
■ M0VER
M0VER: バージョン情報。
Usage: M0VER
- MSX0 に関するバージョンを表示します。
- MSX-DOS1 では MSX-DOS に関する詳しいバージョン情報を取得できません。
Download: M0Ver_100.zip (ht-deko.com)
■ M0CHGINP
M0CHGINP: 入力デバイスの変更
Usage: M0ChgInp [/Gnum] [/Pnum] [/Jnum] [/Anum] [/Bnum]
Setup Utility の Input と同等の設定を行います。
スイッチ | 説明 |
---|---|
/Gn | GamePad Face の接続先を指定します (n=0..3)。 |
/Pn | タッチパネルの接続先を指定します (n=0..3)。 |
/Jn | タッチジョイパッドの接続先を指定します (n=0..3)。 |
接続先として設定可能な値です。
n の値 | 説明 |
---|---|
0 | 割り当てない |
1 | キーボード |
2 | ジョイスティックポート #1 |
3 | ジョイスティックポート #2 |
ゲームパッドの連射に関する設定です。
スイッチ | 説明 |
---|---|
/An | A ボタンの連射速度を変更する (n=0..3)。 |
/Bn | B ボタンの連射速度を変更する (n=0..3)。 |
連射速度として設定可能な値です。
n の値 | 説明 |
---|---|
0 | 連射なし |
1 | 低速 |
2 | 中速 |
3 | 高速 |
- パラメータ未指定の場合には使い方と現在の設定を表示します。
- GamePad / TouchPad / TouchJoypad の接続先とジョイパッドのボタンの連射速度を変更可能です。
- スイッチは
-
でも/
でもよく、大文字/小文字も判断しません。 - 範囲外の値は 0 とみなされます。
- 無効なスイッチは無視されます。
Download: M0ChgInp_100.zip (ht-deko.com)
■ M0TPASZ
TPA サイズを表示。
Usage: M0TPASZ
- TPA サイズを表示します。
- MSX 固有の機能を使っていないので、恐らく CP/M-80 で動作します。
- コンパイラオプションで 40K システムをターゲットにしました。MSX0 (MSX-DOS2) よりメモリ搭載量の少ないシステムでも動作すると思います。
Download: M0TPAsz_110.zip (ht-deko.com)
おわりに
そのうち整理するっ!
See also: