以下の内容はhttp://netakiri.net/labo/ctrl_avc300_sample.shtmlより取得しました。


AVC300サンプル

自作プログラムからAVC300を利用する
サンプルソース
ダウンロード

自作プログラムからAVC300利用する

ここではDelphiからAVC300を操作するサンプルを載せています。卓上リモコンAVC300サンプルプログラムソースに付属しているVBソースを元に書きました。

このサンプルは、AVC300の根幹機能といえる接続(Connect)、システム情報取得(ReadSys)、システム情報保存(SaveSysdata)、ステータス情報取得(GetStatus)、リモコンコマンド送信(RemoconCMD)、リモコンコマンド学習(LearningCMD)を解析すべく作りました。

他の機能(SetReserveList、GetReserveInfo、Getrimodata、、GetMailInfo、GetDeviceInfoなど)は盛り込んでいません。予約機能などはアプリケーション側で実装できますし、他のメール機能は特にいらないかなと。というか、面倒くさかったのが一番の理由です。そのうちやる気が出たら、ここのソースを元に全機能を含んだラッパーなどを作れればと思います。

作成環境

注意点

参考資料

サンプルソース

フォーム

Connect→ReadSysの後に他のボタンが使用できます。右側にログが表示され、AVC300が返してきた返信(返ってきたバッファの1番目)や返信バッファ数なども見ることが出来ます。

フォーム

Globals.pas グローバル定数と構造体

unit Globals;

interface

const
   DEVICE_MAX_NO = 4;
   KEY_MAX_NO = 40; //1デバイス当のリモコンの操作キーの個数
   BUF_SIZE = 670;
   KEYCODE_BUFSIZE = 12000;
   END_DATA = $FF;
   LEARNING_TIMEOUT = 10000; //msec Data登録時のタイムアウト
   MAX_RESERVATION = 100;
   AVC300_RUNNING = 2;

  DATA_LENGTH_MIN = 20; //リモコンデータの最小サイズ
  PULSE_WIDTH_MIN = 3;  //パルスの最小幅
  PULSE_WIDTH_CORRECTION = 2; //パルス幅補正
  DEVICE_LEN = 12; //デバイスの名前のサイズ
  KEY_LEN = 24; //キーの名前のサイズ
  WEB_PASSWORD_LENGTH = 9;
  DEFAULT_WEB_PASSWORD = 'rimo';

  //COMMAND
  SET_CONDITION = 'S';
  TRANSMIT_MODE = 'T';
  RECEIVING_MODE = 'R';
  REGISTER_MODE = 'r';
  SET_MODE = 2;
  RESET = 7;
  NO_RES = 3;
  NO_DATA = 4;
  ENQ = 5;
  ACK = 6;
  NACK = 21;
  DATA_REQ = 16;

  DEVICE_INFO = 9;       //Device ,KeyのListを送信してSYSへ保存
  GET_DEVICE_INFO = 10;  //SYSから読み出して転送
  RIMO_OK = 17;          //赤外線照射のACK
  SET_TIME = 18;         //時刻を設定
  SET_RESERVE = 19;      //予約実行
  STP_RESERVE = 20;      //予約実行
  GET_RESERVE_INFO = 25; //予約情報の取得FromAVC300
  GET_INFO = 26;         //時刻、予約、マクロ、温度、明度の実行状態
  GET_MAIL_INFO = 29;
  SET_MAIL = 30;
  SEND_MAIL_TST = 31;
  GET_RIMO_DATA = 32;
  SAVE_RIMO_DATA = 33;
  LEARNING = 13;
  REMOCON = 14;
  WRITE_ERROR = 2;        //WriteUsb error

  RECIVE_DATA = 46;
  DEFAULT_PACKET_SIZE = 192;
  DEFAULT_TRANSMIT_PACKET_SIZE = 192;  
  //温度計測
  KELVIN_CONST = 3300; //カルビン定数
  R25 = 500; //25度の抵抗
  ABSTMP = 273; //絶対温度
  RC = 510; //分割抵抗
  VCC = 5; //基準電圧

  SYS_PASSWORD = 'AVC';
  //明度
  BRIGHT = 230; //眩
  LIGHT = 180;  //明
  DIME = 128; //照明
  DARK = 82; //薄暗
  NIGHT = 35; //暗
  BLACK = 0; //闇

type
  TReceivedData = array of Byte;
  TTransmitData = TReceivedData;

  //今回未使用
  TRecevingData = (rdNone, rdSystemData, rdStatusInfo);

  TDeviceData = record
    LedCh: Byte;
    CarrierClock: Byte;
    DeviceName: array[0..11] of Char;
  end;
    
  TKeyData = record
    DeviceNo: Byte;
    KeyNo: Byte;
    KeyName: array[0..23] of Char;
  end;  

  TSystemData = record
    SysPassWord: array[0..2] of Char;
    TransmitFrq: Byte;
    CarrierClock: Byte;
    SYSReserv1: Byte;
    TransmitInterval: Byte;
    TmpOffset: Byte;
    LocalIP: array[0..3] of Byte;
    GateWayIP: array[0..3] of Byte;
    PortNo: Word;{array[0..1] of Byte;}   //UDPプロトコルのポート
    SYSReserv2: array[0..8] of Byte;
    CurrentDeviceNo: Byte;
    CurrentLedCh: Byte;
    CurrentCarrierClock: Byte;
    SYSReserv3: array[0..19] of Byte;
    Password: array[0..8] of Char;
   //明度計測;
    Bright: Byte; //= 230  "眩"
    Light: Byte; // = 180  "明"
    Dime: Byte; // = 128 "照明"
    Dark: Byte; // = 82 "薄暗"
    Night: Byte; // = 35 "暗"
    Black: Byte; // = 0 "闇"
    LampMode: Byte;
    PacketSize: Byte; //パケット単位64BYTE AVCの受信
    TransmitPacketSize: Byte; //パケット単位64BYTE AVCの送信
    WebPortNo: Word;{array[0..1] of Byte;}    //WebBrousser用サーバのポート
    SYSReserv4: array[0..29] of Byte;
    Device: array[0..3] of TDeviceData;
    Keyname: array[0..179] of TKeyData;
  end;

  TReserveData = record
    Year: Byte;  //西暦-2000
    Month: Byte;
    Day: Byte;
    Hour: Byte;
    Minute: Byte;
    Sec: Byte;
    Week: Byte;  //0:当日のみ 1:毎日 2:月から金 3:以上は曜日指定
                 //3:Sun 4:Mon 5:Tue:,,9:sat
    DeviceNo: Byte;
    KeyNo: Byte;
  end;

  TStatusInfo = record
    Year: Byte;  //西暦-2000
    Month: Byte;
    Day: Byte;
    Hour: Byte;
    Minute: Byte;
    Seconde: Byte;
    Week: Byte;  //0:当日のみ 1:毎日 2:月から金 3:以上は曜日指定
                 //3:Sun 4:Mon 5:Tue:,,9:sat
    Luminosityc: Byte;
    Temperature: Byte;
  end;
  

implementation

end.

Unit1.pas フォームの実装

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics,
  Controls, Forms, Dialogs, StdCtrls, IdUDPServer,
  IdBaseComponent, IdComponent, IdUDPBase, IdUDPClient,
  IdSocketHandle, Globals, ComCtrls, ExtCtrls, Spin;

type
  TForm1 = class(TForm)
    Bevel1: TBevel;
    ButtonPanel: TPanel;
    CHRadioGroup: TRadioGroup;
    ConnectButton: TButton;
    DeviceNoSpinEdit: TSpinEdit;
    GetStatusButton: TButton;
    IdUDPClient1: TIdUDPClient;
    IdUDPServer1: TIdUDPServer;
    KeyNoSpinEdit: TSpinEdit;
    Label1: TLabel;
    LearningCMDButton: TButton;
    LogPanel: TPanel;
    Memo1: TMemo;
    Panel1: TPanel;
    ReadSysDataButton: TButton;
    RemoconCMDButton: TButton;
    SaveSysdataButton: TButton;
    SetModeRadioGroup: TRadioGroup;
    Splitter1: TSplitter;
    Splitter2: TSplitter;
    StatusInfoListView: TListView;
    StatusInfoPanel: TPanel;
    SystemDataListView: TListView;
    SystemDataPanel: TPanel;
    procedure ConnectButtonClick(Sender: TObject);
    procedure IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
      ABinding: TIdSocketHandle);
    procedure ReadSysDataButtonClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure GetStatusButtonClick(Sender: TObject);
    procedure SaveSysdataButtonClick(Sender: TObject);
    procedure RemoconCMDButtonClick(Sender: TObject);
    procedure LearningCMDButtonClick(Sender: TObject);
    procedure SetModeRadioGroupClick(Sender: TObject);
  private
    { Private 宣言 }
    FStartTime: Cardinal;     
    FSystemData: TSystemData;
    FStatusInfo: TStatusInfo;
    procedure Log(s: string);
    procedure StartTime;
    function StopTime: Cardinal;
    procedure SendData(cmd: Byte; const Buffer: TTransmitData;
      Count: Word);
    procedure SendCommand(cmd: Byte; Text: string);
    function TransmitByteData(cmd: Byte; Data: TTransmitData;
      Count: Word): Boolean;
    procedure SetStatusInfo(const Value: TStatusInfo);
    procedure SetSystemData(const Value: TSystemData);
    function AddIntItem(LV: TListView; AName: string;
      AValue: Integer): TListItem;
    function AddStrItem(LV: TListView; AName,
      AValue: string): TListItem;
    procedure LogResAndSize(ARes, ASize: Integer);
    procedure CheckButtonEnabled;
  public
    { Public 宣言 }
    IsReceving: Boolean;         //データ取得中かどうか
    RecevedMs: TMemoryStream;    //取得したデータ格納用
    TotalDataSize,             //トータル取得データ
    TmpTotalDataSize: Word;    //トータル取得データ計算用
    SystemDataExist: Boolean;  //SystemDataを取得したかどうか
    RecevingData: TRecevingData; //今回未使用
    property StatusInfo: TStatusInfo read FStatusInfo
      write SetStatusInfo;
    property SystemData: TSystemData read FSystemData
      write FSystemData;
    procedure Connect;
    procedure ReadSysData;
    procedure GetStatus;
    procedure SaveSysdata;
    function TransmitSystemData(sd: TSystemData): Boolean;
    function RemoconCMD(DeviceNo, KeyNo, CarrierClock,
      CH: Byte): Boolean;
    function LearningCMD(DeviceNo, KeyNo, CarrierClock,
      CH, TrasmitFrq: Byte): Boolean;
  end;

var
  Form1: TForm1;
const
  //環境に合わせて設定してください
  PASSWORD = 'rimo';
  DEFAULT_LOCAL_IP = '192.168.0.145';
  DEFAULT_PORT = 6000;
  SEP = '------------------';

implementation

{$R *.dfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Clear;
  CheckButtonEnabled;
  RecevedMs := TMemoryStream.Create;
  IsReceving := False;
  TotalDataSize := 0;
  SystemDataExist := False;
  RecevingData := rdNone;

  //Indy設定
  with IdUDPClient1 do begin
    Active := True;
    Host := DEFAULT_LOCAL_IP;
    Port := DEFAULT_PORT;
    ReceiveTimeout := 100;
  end;
  with IdUDPServer1 do begin
    Active := True;
    DefaultPort := DEFAULT_PORT;
  end;

end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  RecevedMs.Free;
end;

procedure TForm1.SendData(cmd: Byte; const Buffer: TTransmitData; Count: Word);
  //サム計算
  function GetSum(cmd: Byte; const Buffer; Count: Word): Byte;
  var i: Integer; sum: Word;
    buf: array of Byte; //len: Word;
  begin
    sum := cmd;
    SetLength(buf, Count);
    CopyMemory(Pointer(buf), Pointer(Buffer), Count);
     for i := Low(buf) to High(buf) do begin
       sum := sum + buf[i];
     end;
     Result := sum and $FF;// LoByte(sum)
  end;
  
var ms: TMemoryStream; len: Word;  tmp: Byte; i: Integer;
begin
  ms := TMemoryStream.Create;
  try
    Log(SEP);
    len := Count + 7; //+7:Datalength(2)+cmd+0+endData+endData+sum
    tmp := LoByte(len);
    ms.WriteBuffer(tmp, 1); //データ数LoByte
    tmp := HiByte(len);
    ms.WriteBuffer(tmp, 1); //データ数HiByte
    ms.WriteBuffer(cmd, 1); //コマンド
    tmp := 0;
    ms.WriteBuffer(tmp, 1); //0(予備)
    for i := 0 to Count-1 do begin
      tmp := Buffer[i];
      ms.WriteBuffer(tmp, 1); //データ配列
    end;
    tmp := END_DATA;
    ms.WriteBuffer(tmp, 1); //endData(255)
    ms.WriteBuffer(tmp, 1); //endData(255)
    tmp := GetSum(cmd, Buffer, Count);
    ms.WriteBuffer(tmp, 1); //SUM(1BYTEサムチェックコード)
    ms.Position := 0;

    //UDP送信
    IdUDPServer1.Bindings[0].SendTo(
      DEFAULT_LOCAL_IP, DEFAULT_PORT, ms.Memory^, len);
  finally
    ms.Free;
  end;
end;

procedure TForm1.SendCommand(cmd: Byte; Text: string);
var buf: TTransmitData; len: Word; 
begin
  len := Length(Text);
  SetLength(buf, len);
  CopyMemory(Pointer(buf), Pointer(text), len);
  SendData(cmd, buf, len);
end;

procedure TForm1.ConnectButtonClick(Sender: TObject);
begin
  Connect;
end;

procedure TForm1.Log(s: string);
begin
  Memo1.Lines.Add(s);
end;

procedure TForm1.LogResAndSize(ARes, ASize: Integer);
begin
  Log('RES:' + IntToStr(ARes) + #9 + 'SIZE:' + IntToStr(ASize));
end;

procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
  ABinding: TIdSocketHandle);
  function GetResult(ms: TMemoryStream): Byte;
  var res: Byte;
  begin
    Result := NACK;
    if ms.Size > 0 then begin
      ms.Position := 0;
      ms.Read(res, 1);
      Result := res;
      ms.Position := 0;
    end;
  end;
  procedure SendDataReq;
  var req: Byte;
  begin
    req := DATA_REQ;
    IdUDPServer1.Bindings[0].SendTo(DEFAULT_LOCAL_IP, DEFAULT_PORT, req, 1);
  end;
var ms: TMemoryStream; res, sum: Byte;
  buf: TReceivedData; i: Integer; tmpsum: Cardinal;
  sd: TSystemData; si: TStatusInfo; //p: PByte; psi: ^TStatusInfo;
begin
  ms := AData as TMemoryStream;
  res := GetResult(ms); //msのバッファの先頭の数字を取得

  LogResAndSize(res, ms.Size);

  if not IsReceving then begin
    case res of
      ACK: ;
      NACK: Exit;
//      4: Log(SEP);
      //ステータス取得
      GET_INFO: begin
        RecevedMs.Clear;
        RecevingData := rdStatusInfo;
        SetLength(buf, ms.Size);

        //GET_INFOの内容を見るデバック用
        //ms.SaveToFile('GetInfo.dat');

        ms.ReadBuffer(buf[0], ms.Size);

        //CopyMemory(@si, @buf[1], ms.Size-1);
        //↑何故かエラーになるから↓の方法
        with si do begin
          Year := buf[1];    
          Month := buf[2];
          Day := buf[3];
          Hour := buf[4];
          Minute := buf[5];
          Seconde := buf[6];
          Week := buf[7];
          Luminosityc := buf[8];
          Temperature := buf[9];
        end;

        SetStatusInfo(si);
        Log('ステータス情報を取得しました。');
      end;
      //システムデータ取得
      RECIVE_DATA : begin
        IsReceving := True;
        TotalDataSize := 0;
        RecevedMs.Clear;

        RecevingData := rdSystemData;
        TmpTotalDataSize := ms.Size;
        ms.Read(TotalDataSize, 2); //全体のサイズ取得
        ms.Position := 0;
        RecevedMs.Position := 0;
        //RecevedMsにデータ取得開始
        RecevedMs.WriteBuffer(ms.Memory^, ms.Size);

        SendDataReq;
      end;
      else IsReceving := False;
    end;
  end else begin
    //全体のサイズをTmpTotalDataSizeが超えたら終了処理へ
    if TotalDataSize > TmpTotalDataSize then begin
      TmpTotalDataSize := TmpTotalDataSize + ms.Size;
      ms.Position := 0;
      //TotalDataSizeになるまでデータ取得
      RecevedMs.WriteBuffer(ms.Memory^, ms.Size);
      
      SendDataReq;
    end else begin
      //RECIVE_DATA終了処理
      IsReceving := False;
      TmpTotalDataSize := 0;

      //RECIVE_DATAの内容を見るデバック用
      //RecevedMs.SaveToFile('ReceveData.txt');

      RecevedMs.Position := 0;
      RecevedMs.ReadBuffer(TotalDataSize, 2);
      Log('TOTAL:'#9 + IntToStr(TotalDataSize));
      SetLength(buf, TotalDataSize);
      RecevedMs.ReadBuffer(buf[0], TotalDataSize);
      RecevedMs.ReadBuffer(sum, 1);
      //チェックサム
      tmpsum := 0;
      for i := 0 to TotalDataSize-1 do begin
        tmpsum := tmpsum + buf[i]; //サム計算
      end;
        
      tmpsum := tmpsum mod 256;
      Log('SUM:'#9 + IntToStr(sum));
      Log('CHKSUM:'#9 + IntToStr(tmpsum));
      if sum = tmpsum then begin
        Log('サムが一致しました。');
      end else begin
        Log('サムが一致しません。');
        Exit;
      end;
      
      //データのコピー
      CopyMemory(@sd, @buf[0], SizeOf(TSystemData));
      SetSystemData(sd);

      RecevingData := rdNone;
      SystemDataExist := True;
      Log('システムデータを取得しました。');
      CheckButtonEnabled;
    end;
  end;  
end;

procedure TForm1.StartTime;
begin
  FStartTime := GetTickCount;
end;

function TForm1.StopTime: Cardinal;
begin
  Result := GetTickCount - FStartTime;
end;

procedure TForm1.ReadSysDataButtonClick(Sender: TObject);
begin
  ReadSysData;
end;

function TForm1.AddStrItem(LV: TListView; AName, AValue: string): TListItem;
begin
    Result := LV.Items.Add;
  with Result do begin
    Caption := AName;
    SubItems.Add(AValue);
  end;
end;

function TForm1.AddIntItem(LV: TListView; AName: string; AValue: Integer): TListItem;
begin
  Result := AddStrItem(LV, AName, IntToStr(AValue));
end;

procedure TForm1.SetStatusInfo(const Value: TStatusInfo);
  //温度変換
  function CnvrtToTmp(Value: Double): Double;
  var v, R:  Double;
    TmpOffset: Integer;
  begin
    if (Value <= 0) or (Value >= 200) then begin
      Result := -ABSTMP; //Error
      Exit;
    end;
    v := Value;
    v := v * VCC / 256;
    R := RC * v / (VCC - v);
    Result := 1 / (Ln(R/R25) / KELVIN_CONST + 1 / (25 + ABSTMP));
    TmpOffset := SystemData.TmpOffset - 128; //Byteのため128をゼロとする
    Result := Result - ABSTMP + (TmpOffset / 10);
  end;

begin
  FStatusInfo := Value;
  with Value do begin
    StatusInfoListView.Items.BeginUpdate;
    StatusInfoListView.Clear;
    AddStrItem(StatusInfoListView, '日付', IntToStr(Year + 2000) + '/' +
      IntToStr(Month) + '/' + IntToStr(Day)); 
    AddStrItem(StatusInfoListView, '時刻', IntToStr(Hour) + ':' +
      IntToStr(Minute) + ':' + IntToStr(Seconde));
    AddIntItem(StatusInfoListView, '明度', Luminosityc);
    AddStrItem(StatusInfoListView, '温度',
      FormatFloat('0.00', CnvrtToTmp(Temperature)) + '℃');
    StatusInfoListView.Items.EndUpdate;
  end;
end;

procedure TForm1.SetSystemData(const Value: TSystemData);
var i: Integer; s: string;
begin
  FSystemData := Value;
  with Value do begin
    SystemDataListView.Items.BeginUpdate;
    SystemDataListView.Clear;
    AddStrItem(SystemDataListView, 'SysPassWord', SysPassWord);
    AddIntItem(SystemDataListView, 'TransmitFrq', TransmitFrq);
    AddIntItem(SystemDataListView, 'CarrierClock', CarrierClock);
    AddIntItem(SystemDataListView, 'TransmitInterval', TransmitInterval);
    AddIntItem(SystemDataListView, 'TmpOffset', TmpOffset);
    AddStrItem(SystemDataListView, 'LocalIP',
      IntToStr(LocalIP[0]) + '.' + IntToStr(LocalIP[1]) + '.' +
      IntToStr(LocalIP[2]) + '.' + IntToStr(LocalIP[3]));  
    AddStrItem(SystemDataListView, 'GateWayIP',
      IntToStr(GateWayIP[0]) + '.' + IntToStr(GateWayIP[1]) + '.' +
      IntToStr(GateWayIP[2]) + '.' + IntToStr(GateWayIP[3]));  
    AddIntItem(SystemDataListView, 'PortNo', PortNo);
    AddIntItem(SystemDataListView, 'CurrentDeviceNo', CurrentDeviceNo);
    AddIntItem(SystemDataListView, 'CurrentLedCh', CurrentLedCh);
    AddIntItem(SystemDataListView, 'CurrentCarrierClock', CurrentCarrierClock);
    AddStrItem(SystemDataListView, 'PassWord', PassWord);
    AddIntItem(SystemDataListView, 'Bright', Bright);
    AddIntItem(SystemDataListView, 'Light', Light);  
    AddIntItem(SystemDataListView, 'Dime', Dime);
    AddIntItem(SystemDataListView, 'Dark', Dark);
    AddIntItem(SystemDataListView, 'Night', Night);
    AddIntItem(SystemDataListView, 'Black', Black);
    AddIntItem(SystemDataListView, 'LampMode', LampMode);
    AddIntItem(SystemDataListView, 'PacketSize', PacketSize);
    AddIntItem(SystemDataListView, 'TransmitPacketSize', TransmitPacketSize);
    AddIntItem(SystemDataListView, 'WebPortNo', WebPortNo);
    for i := 0 to 3 do begin
      s := 'Device[' + IntToStr(i) + '].';
      AddIntItem(SystemDataListView, s + 'LedCh', Device[i].LedCh);
      AddIntItem(SystemDataListView, s + 'CarrierClock', Device[i].CarrierClock);
      AddStrItem(SystemDataListView, s + 'DeviceName', Device[i].DeviceName);
    end;      
    for i := 0 to 179 do begin
      s := 'Keyname[' + IntToStr(i) + '].';
      AddIntItem(SystemDataListView, s + 'DeviceNo', Keyname[i].DeviceNo);
      AddIntItem(SystemDataListView, s + 'KeyNo', Keyname[i].KeyNo);
      AddStrItem(SystemDataListView, s + 'KeyName', Keyname[i].KeyName);
    end;
    SystemDataListView.Items.EndUpdate;
  end;
end;

procedure TForm1.GetStatusButtonClick(Sender: TObject);
begin
  GetStatus;
end;

procedure TForm1.Connect;
begin
  SendCommand(ENQ, PASSWORD);
end;

procedure TForm1.ReadSysData;
begin
  SendCommand(GET_DEVICE_INFO, '');
end;

procedure TForm1.GetStatus;
begin
  SendCommand(GET_INFO, '');
end;

procedure TForm1.SaveSysdata;
var sd: TSystemData;
begin
  sd := FSystemData;
  
  //試しにデバイス名などを変えてみてください
  //sd.Device[0].DeviceName := 'test_001';

  {***************************************
  どのシステムデータも変更することが出来ますが
  下手に弄ると繋がらなくなるので慎重に!
  システムデータがおかしくなった場合は
  AVC300ヘルプの「AVC300の初期化法」参照
  ***************************************}
  
  if TransmitSystemData(sd) then begin
    SetSystemData(sd);
  end;
end;

function TForm1.TransmitByteData(cmd: Byte; Data: TTransmitData;
  Count: Word): Boolean;
var ms: TMemoryStream; len, last, packet, leftover: Word; buf, pacbuf: TTransmitData;
  sum, l: Cardinal; i, sendCount: Integer;
  retry: Byte; rcv: array[0..9] of Byte;
begin
  Result := False;
  ms := TMemoryStream.Create;
  try
    //SUM(1BYTEサムチェックコード)サムの範囲はコマンドからendDataの前まで
    sum := cmd;
    for i := 0 to Count-1 do
      sum := sum + Data[i];
    sum := sum and $FF;

    len := Count + 7; //+7:Datalength(2)+cmd+0+endData+endData+sum

    Log(SEP);
    Log('TOTAL:'#9 + IntToStr(len)); 
    Log('DATA:'#9 + IntToStr(Count));
    Log('SUM:'#9 + IntToStr(sum));

    SetLength(buf, len);
    buf[0] := LoByte(len); //全データ数LoByte
    buf[1] := HiByte(len); //全データ数HiByte
    buf[2] := cmd;         //コマンド
    buf[3] := 0;           //0(予備)
    CopyMemory(@buf[4], Pointer(Data), Count); //データ配列
    last := len - 1;
    buf[last-2] := END_DATA;   //endData(255)
    buf[last-1] := END_DATA;   //endData(255)
    buf[last] := sum;     //SUM

    packet := SystemData.TransmitPacketSize * 64;
    leftover := len mod packet; //余り
    sendCount := (len div packet) + 1; //送る回数を計算
    SetLength(pacbuf, packet);

    l := 0;
    rcv[0] := 0;
    for i := 0 to sendCount-1 do begin
      retry := 0;
      repeat
        if (retry > 3) or (rcv[0] = NACK) then begin
          Log('データ送信に失敗しました。');
          Exit;
        end;
        ms.Clear;
        if i <> (sendCount-1) then begin
          ms.WriteBuffer(buf[packet*i], packet);
          ms.Position := 0;
          IdUDPClient1.SendBuffer(ms.Memory^, packet);
        end else begin
          ms.WriteBuffer(buf[packet*i], leftover);
          ms.Position := 0;
          IdUDPClient1.SendBuffer(ms.Memory^, leftover);
        end;
        l := IdUDPClient1.ReceiveBuffer(rcv, 1);
        LogResAndSize(rcv[0], l);

        Inc(retry);
      until (rcv[0] = ACK) or (rcv[0] = DATA_REQ);
    end;

    //リモコン学習の場合
    StartTime;
    if cmd = LEARNING then begin
      while True do begin
        if StopTime > 5000 then begin
          Log('タイムアウト。');
          Exit;
        end;

        //1秒後から取得
        //AVC300がデータを送っていないのに受信割込みが動作しないためらしい
        if StopTime > 1000 then begin
          l := IdUDPClient1.ReceiveBuffer(rcv, 2);
          len := rcv[1];
          len := len * 256 + rcv[0];
          //受信すると2BYTE返ってくるので次の処理に行く
          if (l >= 2) and (len >= 10) then Break;
        end;
      end;

      LogResAndSize(len, l);
      if len < 10 then begin
        Log('登録が未完了です。(' + IntToStr(len) + ')');
      end else begin
        if len = $FFFF then begin
          Log('登録できませんでした。(' + IntToStr(len) + ')');
        end else begin
          if len >= BUF_SIZE - 3 then begin
            Log('データが長すぎます。液晶TV、直射日光等の他からの' +
              '赤外線に注意して下さい(' + IntToStr(len) + ')');
          end else begin
            Log('登録しました。(' + IntToStr(len) + ')');
            Result := True;
          end;
        end;
      end;
      Exit;   
    end;

    Result := True;
    Log('データ送信を完了しました。');

  finally
    ms.Free;
  end;

end;

function TForm1.TransmitSystemData(sd: TSystemData): Boolean;
var buf: TTransmitData; len, all: Word;
begin
  len := SizeOf(TSystemData);
  all := len + 3;   //+3 datalen(2) + $00
  SetLength(buf, all);
  //データ作成
  buf[0] := LoByte(len);    //データ数LoByte
  buf[1] := HiByte(len);    //データ数HiByte
  buf[2] := $00;            //0
  CopyMemory(@buf[3], @sd, len); //data copy

  Result := TransmitByteData(DEVICE_INFO, buf, all);
end;

procedure TForm1.SaveSysdataButtonClick(Sender: TObject);
begin
  SaveSysdata;
end;

function TForm1.RemoconCMD(DeviceNo, KeyNo, CarrierClock,
  CH: Byte): Boolean;
var buf: TTransmitData; len: Word;
begin
  len := 4;
  SetLength(buf, len);

  buf[0] := CH + 2; //CH3がCH1に対応するため
  buf[1] := CarrierClock;  
  buf[2] := DeviceNo;
  buf[3] := KeyNo;

  Result := TransmitByteData(REMOCON, buf, len);
end;

procedure TForm1.RemoconCMDButtonClick(Sender: TObject);
var DeviceNo, KeyNo, CH: Byte;
begin
  //リモコン操作テスト
  DeviceNo := DeviceNoSpinEdit.Value;
  KeyNo := KeyNoSpinEdit.Value;
  CH := CHRadioGroup.ItemIndex;

  RemoconCMD(DeviceNo, KeyNo,
    FSystemData.Device[DeviceNo].CarrierClock, CH);
end;

function TForm1.LearningCMD(DeviceNo, KeyNo, CarrierClock, CH,
  TrasmitFrq: Byte): Boolean;
var buf: TTransmitData; len: Word;
begin
  len := 7;
  SetLength(buf, len);

  buf[0] := TrasmitFrq;
  buf[1] := CH;
  buf[2] := CarrierClock;
  buf[3] := DATA_LENGTH_MIN;
  buf[4] := PULSE_WIDTH_MIN +
    PULSE_WIDTH_CORRECTION * $10; //上位4bitはセンサーLowpulse幅補正
  buf[5] := DeviceNo;
  buf[6] := KeyNo;

  Result := TransmitByteData(LEARNING, buf, len);
end;

procedure TForm1.LearningCMDButtonClick(Sender: TObject);
var DeviceNo, KeyNo, CH: Byte; success: Boolean;
begin
  //リモコン学習テスト
  DeviceNo := DeviceNoSpinEdit.Value;
  KeyNo := KeyNoSpinEdit.Value;
  CH := CHRadioGroup.ItemIndex;


  success := LearningCMD(DeviceNo, KeyNo,
    FSystemData.Device[DeviceNo].CarrierClock,
    CH, SystemData.TransmitFrq);
  if not success then begin
    MessageDlg('AVC300からの応答がありません。',
      mtWarning, [mbOK], 0);
    Exit;
  end;
end;

procedure TForm1.SetModeRadioGroupClick(Sender: TObject);
begin
  case SetModeRadioGroup.ItemIndex of
    0: SendCommand(SET_MODE, REGISTER_MODE);
    1: SendCommand(SET_MODE, TRANSMIT_MODE);
    2: SendCommand(SET_MODE, RECEIVING_MODE);
  end;
  CheckButtonEnabled;
end;

procedure TForm1.CheckButtonEnabled;
begin
  GetStatusButton.Enabled := SystemDataExist;
  SaveSysdataButton.Enabled := SystemDataExist;
  RemoconCMDButton.Enabled := SystemDataExist
    and (SetModeRadioGroup.ItemIndex = 1);
  LearningCMDButton.Enabled := SystemDataExist
    and (SetModeRadioGroup.ItemIndex = 0);;
end;

end.

ダウンロード

ソースファイル [Down]
本家ソース 卓上リモコンAVC300サンプルプログラムソース




以上の内容はhttp://netakiri.net/labo/ctrl_avc300_sample.shtmlより取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14