2016年5月29日日曜日

FREETELの節約モードが遅くなった?

スマートフォンの通信が、なんだか遅いような感じがしたので、パソコンとUSBテザリングで接続してどのくらいの速度が出ているのかを見てみました。
回線はFREETEL SIMの「使った分だけ安心プラン」で、ずっと節約モード(200kbps)で使っています。節約モードで使うと、通話できるSIMで一ヶ月 999円(税別)で使えます。

2016年5月29日 日曜 16:00ころで、50kbpsくらいしか出ていません、懐かしのアナログモデム並(笑)。150kbps程度出てくれるとありがたいのですが。

スマートフォンの回線では地図とgoogle driveのメモを見る程度なので、ずっと節約モードで使っているのですが、今年1月に契約した時にはもう少し通信速度が速かった気がします。気のせいかな?

節約モードをOFFにすると数Mbps出ていて、ストレス無く使用できます。Youtubeの動画も止まらず再生出来ました。

2016年5月24日火曜日

ハクキンカイロの燃料に100円ショップのライターオイルを使ってみる

ダイソーで売っていたライターオイルを、ハクキンカイロに使ってみました。値段は 100ml 108円でした。

普通に点火できたのですが、あまり暖かくならずしばらく時間がたってもぬるかったです。カイロを袋から出して、直接手で持てるくらいの暖かさ。臭いはハクキンカイロ純正ベンジンより少ないかなと感じました。温度が低くてカイロには向きません。

5月27日追記:火口が痛むので使わないほうが良いです。

あまり揮発しやすいとライターでは頻繁に給油しなきゃならないので、あまり揮発しないように作られているのでしょう。


ついでに、ダイソーでペラペラのウエストポーチが売っていたので、カイロベルト用に買ってきました。

腹巻きでお腹のあたりにカイロを当てていると、いまいちしっくり来なかったのですが、カイロベルトでみぞおちのあたりにカイロを当てるといい感じです。



100円ショップのライターオイルを使った後、純正ベンジンで使っても発熱が弱くなってしまいました。火口の周りをよく見てみると、蝋のような汚れが付いています。触媒が目詰まりのような状態になったようです。

純正ベンジンで繰り返し使っていれば回復するかなと思ったのですが、回復する様子がないので触媒を換気扇用洗剤で洗って、水でよくすすいで、ドライヤーで乾かしたら回復しました。
油っぽい汚れが落ちやすいように換気扇用洗剤を使って、触媒が型崩れしないようにやさしく洗いました。

2016年5月23日月曜日

畑を耕した

家の畑を耕しました。

一日で終わった。

ついでに、池?の水を汲み出して掃除しておきました。3年前にボウフラ退治でメダカを10匹買って入れておいたのですが、まだ一匹泳いでいるのを見つけました。寒い北海道で屋外に放置なのに、メダカはずいぶん丈夫ですね。

2016年5月21日土曜日

バイクの整備

バイクのオイルを交換しました。オイルは安物の 10W-40です。
 チェーンも掃除して、注油して、張りを調整しておきました。
ついでに、チェンジペダルのゴムがすり減っているので交換しました。
 20年くらい交換せずに乗っていました。(笑)


汎用のチェンジペダルラバー。monotaroで145円でした。


ぐにゅっと簡単に外れました。


古いのと新しいの。


新しいゴムは、オフ車には長過ぎるのでカッターで切りました。


滑るように、軸に油を塗って押し込んで交換完了です。
 だいぶ操作しやすくなりました。ニュートラルに入れやすくなった。(笑)

 二時間位バイクで走ってきたのですが、家のまわりは涼しかったので厚着して出かけたら、内陸の方は真夏並みに暑くて参りました。
 桜がたくさんある神社まで行ってみたら、桜はすっかり散ってしまっていました。


うちの裏の桜は、まだ咲いています。


2016年5月18日水曜日

LSI C-86 で PC-9801のDISK BIOSを使ってみる練習 セクタの並びを調べる

READ DIAGNOSTICコマンドとREAD IDコマンドを使って、セクタの並びを表示する。
エミュレータで実行する場合、D88などのセクタの並びが保存されるディスクイメージでなければ正常に動作しません。

実行してみた所。1.2MB 2HD MS-DOSフォーマット

640KB 2DD X1のHu-BASICフォーマット。手近にセクタが順番に並んでいないフロッピーディスクが無くて、実行しても面白味がない。

PC-9801DISK BASICのフロッピーがインターリーブしていました。
しかも、シリンダ0のヘッド0のみ FM 方式です。

シリンダ0ヘッド0 以外は普通に MFM でした。

つまらないサンプルプログラムですが、なにかの役に立つかもしれません。




readsseq.c

/*
PC-9801フロッピーディスクBIOSを使ってみるサンプル
フロッピーディスクのセクタシーケンスを調べる。
FDCの動作を正確に再現するPC-9801エミュレータは少ないので、エミュレータで動作確認をする場合は注意を要する。
LSI C-86 Ver.3.30 試食版用
lcc -o readsseq.exe readsseq.c diskbios.c のようにしてコンパイルすればよい

このソースコードは CC0 パブリック・ドメイン提供です。
https://creativecommons.org/publicdomain/zero/1.0/deed.ja

2016年1月29日 2016年5月17日 佐藤恭一 kyoutan.jpn.org
*/
#include <stdio.h>
#include "diskbios.h"

#define SECTMAX   32 /*最大セクタ数 1セクタ256バイトの時26なので余裕を見て32くらい*/
#define BUFFSIZE  (8*1024)
unsigned char BUFF[BUFFSIZE];

int main()
{
    unsigned short count,startpos;
    unsigned char drive,mod,c,h;
    unsigned char sechead,seccount;

    drive=0;    /*ドライブ番号 0-3*/
    c=0;        /*シリンダ番号*/
    h=0;        /*ヘッド番号 0-1*/

    /* 0シリンダに移動 */
    if(! track00(FD2HD | drive))
    {
        /*エラー*/
        puts("RECALIBRATE ERROR");
        return FALSE;
    }

    /* ディスクのタイプを調べる FM/MFM 2DD/2HD 48tpi/96tpi */
    if(! (mod=sectsence(drive, c, h)))
    {
        puts("ID read error");
        return FALSE;
    }

    if(0x80 & mod) printf("2HD ");
    else printf("2DD ");
    drive = drive | (FD2HD & mod);  /* ドライブ番号に 2HD/2DD の指定を追加 */

    if(0x40 & mod) printf("MFM ");
    else printf("FM ");
    mod = FDMFM & mod;

    /*READDIAG で先頭セクタの番号を調べる*/
    if(!secthead(drive, mod, h, BUFF))
    {
        puts(errmsg(BUFF[0]));
        return FALSE;
    }
    sechead=BUFF[0];    /*先頭のセクタ番号*/
    printf(" head of the sector : %d \n", sechead);

    /*READID で1トラック分のセクタのIDを調べる*/
    for(count = 0; count != (SECTMAX - 1); count++)
    {
        if(! readid(drive, mod, h, &BUFF[count * 4]))
        {
            printf("ID read error %d ", count);
            puts(errmsg(BUFF[0]));
            return FALSE;
        }
    }

    /*1トラックに何セクタあるか数える*/
    for(seccount = 1; seccount != (SECTMAX - 1); seccount++)
    {
        if(BUFF[2] == BUFF[(seccount * 4) + 2]) break;
    }
    printf("%d secter/track   ", seccount);

    /*すべてのセクタ長コードが一致するか*/
    for(count = 0; count != seccount; count++)
    {
        if(BUFF[3] != BUFF[(count * 4) + 3])
        {
            /*一致しない*/
            puts("\nUnusual format : Sector length is not unified");
            return FALSE;
        }
    }
    printf("%d byte/sec \n", sectlength(BUFF[3]));

    /*先頭から順にバッファを整頓*/
    /*先頭まで読み飛ばす*/
    for(count=0; count != (SECTMAX - 1); count++)
    {
        if(sechead == BUFF[(count * 4) + 2]) break;
    }
    startpos = count * 4;
    /*バッファ内コピー (整頓)*/
    for(count=0; count != (seccount * 4); count++)
    {
        BUFF[count] = BUFF[startpos + count];
    }

    /*先頭セクタからIDを表示*/
    puts(" C  H  R  N");
    for(count = 0 ; count != (seccount * 4); count += 4)
    {
        printf("%2d %2d %2d %2d \n", BUFF[count + 0]
                                   , BUFF[count + 1]
                                   , BUFF[count + 2]
                                   , BUFF[count + 3]);
    }

    return TRUE;
}


diskbios.h

/*
PC-9801 DISK BIOS を使う関数
FDCの動作を正確に再現するPC-9801エミュレータは少ないので、エミュレータで動作確認をする場合は注意を要する。
LSI C-86 Ver.3.30 試食版用ですが、DOS用コンパイラならどれもだいたい同じ。

このソースコードは CC0 パブリック・ドメイン提供です。
https://creativecommons.org/publicdomain/zero/1.0/deed.ja

2016年2月1日 2016年5月18日 佐藤恭一 kyoutan.jpn.org
*/
#include <dos.h>

/*システム共通域の DISK_RESULT*/
struct FDC_RESULT
{
    unsigned char ST0, ST1, ST2, C, H, R, N,NCN;
};
struct DISK_RESULT
{
    struct FDC_RESULT D0, D1, D2, D3;
};
#define DISKSTAT  (*(volatile struct DISK_RESULT far *)0x00000564)

#define FALSE     0
#define TRUE      (!FALSE)
#define DISKBIOS  0x1B
#define FD2HD     0x90  /*デバイスタイプ指定*/
#define FD2DD     0x10  /*デバイスタイプ指定*/
#define FDMFM     0x40  /*コマンド識別*/
#define FDFM      0x00  /*コマンド識別*/
#define MODE2D    0     /*モード切替 48tpi*/
#define MODE2DD   1     /*モード切替 96tpi*/

unsigned char diskinit(unsigned char device);
unsigned char drvmode(unsigned char device      /* デバイス番号 0~3 */
                     ,unsigned char mode);      /* モード MODE2D/MODE2DD */
unsigned char diskmode(unsigned char mode);
unsigned char disksense(unsigned char device
                       ,unsigned char *errcode);
unsigned char track00(unsigned char device);
unsigned char seek(unsigned char device
                  ,unsigned char C);            /* シリンダ番号 */
unsigned char readid(unsigned char device
                    ,unsigned char MF           /* MFM/FM */
                    ,unsigned char H            /* ヘッド番号 */
                    ,unsigned char *buff);      /* IDを書き込むアドレス */
unsigned char readdata(unsigned char device
                      ,unsigned char MF         /* MFM / FM */
                      ,unsigned char C          /* シリンダ番号 */
                      ,unsigned char H          /* ヘッド番号 */
                      ,unsigned char R          /* セクタ番号 */
                      ,unsigned char N          /* セクタ長コード */
                      ,unsigned char *buff);    /* 出力を書き込むアドレス */
unsigned char readdeleted(unsigned char device
                         ,unsigned char MF      /* MFM / FM */
                         ,unsigned char C       /* シリンダ番号 */
                         ,unsigned char H       /* ヘッド番号 */
                         ,unsigned char R       /* セクタ番号 */
                         ,unsigned char N       /* セクタ長コード */
                         ,unsigned char *buff); /* 出力を書き込むアドレス */
unsigned char verify(unsigned char device
                    ,unsigned char MF           /* MFM / FM */
                    ,unsigned char C            /* シリンダ番号 */
                    ,unsigned char H            /* ヘッド番号 */
                    ,unsigned char R            /* セクタ番号 */
                    ,unsigned char N            /* セクタ長コード */
                    ,unsigned char *buff);      /* 出力を書き込むアドレス */
unsigned char writedata(unsigned char device
                       ,unsigned char MF        /* MFM / FM */
                       ,unsigned char C         /* シリンダ番号 */
                       ,unsigned char H         /* ヘッド番号 */
                       ,unsigned char R         /* セクタ番号 */
                       ,unsigned char N         /* セクタ長コード */
                       ,unsigned char *buff);   /* データバッファの先頭アドレス */
unsigned char writedeleted(unsigned char device
                          ,unsigned char MF     /* MFM / FM */
                          ,unsigned char C      /* シリンダ番号 */
                          ,unsigned char H      /* ヘッド番号 */
                          ,unsigned char R      /* セクタ番号 */
                          ,unsigned char N      /* セクタ長コード */
                          ,unsigned char *buff);/* データバッファの先頭アドレス */
unsigned char trackfmt(unsigned char device
                      ,unsigned char MF         /* MFM / FM */
                      ,unsigned char C          /* シリンダ番号 */
                      ,unsigned char H          /* ヘッド番号 */
                      ,unsigned char N          /* セクタ長コード */
                      ,unsigned char SC         /* トラックあたりのセクタ数*/
                      ,unsigned char DATA       /* セクタに書き込むデータパターン */
                      ,unsigned char *buff);    /* データバッファの先頭アドレス */
unsigned char readdiag(unsigned char device
                      ,unsigned char MF         /* MFM / FM */
                      ,unsigned char H          /* ヘッド番号 */
                      ,unsigned char N          /* セクタ長コード */
                      ,unsigned char *buff);    /* 出力を書き込むアドレス */
unsigned char sectsence(unsigned char device
                       ,unsigned char C
                       ,unsigned char H);
unsigned short sectlength(unsigned char N);     /*セクタ長コード*/
unsigned char secthead(unsigned char drive
                      ,unsigned char MF         /* MFM / FM */
                      ,unsigned char H          /* ヘッド番号 */
                      ,unsigned char *buff);    /* 出力を書き込むアドレス */
char *errmsg(unsigned char ah);


diskbios.c

/*
PC-9801 DISK BIOS を使う関数
FDCの動作を正確に再現するPC-9801エミュレータは少ないので、エミュレータで動作確認をする場合は注意を要する。
LSI C-86 Ver.3.30 試食版用

このソースコードは CC0 パブリック・ドメイン提供です。
https://creativecommons.org/publicdomain/zero/1.0/deed.ja

2016年2月1日 2016年5月17日 佐藤恭一 kyoutan.jpn.org
*/
/*#include <stdio.h>*/
#include "diskbios.h"

/* INITIALIZE FDCとBIOSのワークエリアの初期化
戻り値 0:異常終了 0以外:正常終了 */
unsigned char diskinit(unsigned char device)
{
  union REGS reg;

  reg.h.ah=0x03;  /* INITIALIZE */
  reg.h.al=device;
  int86(DISKBIOS, &reg, &reg);

  if(0!=reg.x.cflag) return FALSE; /* 0:異常終了*/

  return TRUE;  /* 0以外:正常終了*/
}

/* DISKMODE 動作モードの設定 デバイスタイプユニットが2DDの時のみ有効
48tpi(2D)/96tpi(2DD)の切り替え 2HDの時は無意味
戻り値 0:異常終了 0以外:正常終了 */
unsigned char drvmode(unsigned char device /* デバイス番号 0~3 */
                     ,unsigned char mode)  /* モード MODE2D/MODE2DD */
{
  unsigned char val;
  unsigned char ret;

  device&=0x03; /*0000 0011 下位2ビットのみ取り出す(0~3)*/
  val=0x0f; /* 初期値 00001111 */
  /*各ドライブの現在のモードを調べる 0:48tpi(2D) 1:96tpi(2DD*/
  if(disksense(FD2DD | 0, &ret)) if((0x04 & ret)==0) val &= ~(1<<0); /* DRIVE0 */
  if(disksense(FD2DD | 1, &ret)) if((0x04 & ret)==0) val &= ~(1<<1); /* DRIVE1 */
  if(disksense(FD2DD | 2, &ret)) if((0x04 & ret)==0) val &= ~(1<<2); /* DRIVE2 */
  if(disksense(FD2DD | 3, &ret)) if((0x04 & ret)==0) val &= ~(1<<3); /* DRIVE3 */

  if(MODE2D==mode) val &= ~(1<<device); /* 2D  ビットクリア */
  else             val |=  (1<<device); /* 2DD ビットセット */

  return diskmode(val);
}

/* DISKMODE 動作モードの設定 デバイスタイプユニットが2DDの時のみ有効
48tpi(2D)/96tpi(2DD)の切り替え 2HDの時は無意味
mode ----1111  0:2D 1:2DD
         |||+- DRIVE0
         ||+-- DRIVE1
         |+--- DRIVE2
         +---- DRIVE3
戻り値 0:異常終了 0以外:正常終了 */
unsigned char diskmode(unsigned char mode)
{
  union REGS reg;

  reg.h.ah=0x0E;  /* 全ドライブ両面モードにする */
  reg.h.al=0x1F;
  int86(DISKBIOS, &reg, &reg);

  mode &= 0x0f;
  mode |= 0x10;
  reg.h.ah=0x8E;  /* MODE設定 */
  reg.h.al=mode;
  int86(DISKBIOS, &reg, &reg);

  if(0!=reg.x.cflag) return FALSE; /* 0:異常終了*/

  return TRUE;  /* 0以外:正常終了*/
}

/* SENSE デバイスの状態を調べる
戻り値 0:異常終了 0以外:正常終了 */
unsigned char disksense(unsigned char device
                       ,unsigned char *errcode)
{
  union REGS reg;

  reg.h.ah=0x04;  /* 00000100 SENSE */
  reg.h.al=device;
  int86(DISKBIOS, &reg, &reg);

  *errcode=reg.h.ah;

  if(0!=reg.x.cflag) return FALSE; /* 0:異常終了*/

  return TRUE;  /* 0以外:正常終了*/
}

/* RECALIBRATE ヘッドをトラック0に移動する
戻り値 0:異常終了 0以外:正常終了 */
unsigned char track00(unsigned char device)
{
  union REGS reg;

  reg.h.ah=0x07;  /* RECALIBRATE */
  reg.h.al=device;
  int86(DISKBIOS, &reg, &reg);

  if(0!=reg.x.cflag) return FALSE; /* 0:異常終了*/
  return TRUE; /* 0以外:正常終了*/
}

/* SEEK 指定シリンダにヘッドを移動する
戻り値 0:異常終了 0以外:正常終了 */
unsigned char seek(unsigned char device
                  ,unsigned char C)     /* シリンダ番号 */
{
  union REGS reg;

  reg.h.ah= 0x10; /*AH 00010000*/
                  /*      +---- SEEK */
  reg.h.al= device;                /*AL デバイスタイプユニット番号*/
  reg.h.cl= C;                     /*CL シリンダ番号(ahのSEEKビットが1の時のみ有効)*/
  int86(DISKBIOS, &reg, &reg);

  if(0!=reg.x.cflag)
  {
    return FALSE; /* 0:異常終了*/
  }
  return TRUE; /* 0以外:正常終了*/
}

/* READ ID 現在のトラックからIDを読む
アドレスout から C H R N の順に4バイト書き込む
戻り値 0:異常終了 0以外:正常終了 */
unsigned char readid(unsigned char device
                    ,unsigned char MF     /* MFM/FM */
                    ,unsigned char H      /* ヘッド番号 */
                    ,unsigned char *buff) /* IDを書き込むアドレス */
{
  union REGS reg;

  reg.h.ah= MF | 0x0A; /* 01001010 ID READ */
                       /*  ||+---- SEEK */
                       /*  |+----- ~r */
                       /*  +------ MF */
  reg.h.al=device;     /*デバイスタイプユニット番号*/
  reg.h.dh=H;          /*ヘッド番号*/

  int86(DISKBIOS, &reg, &reg);

  if(0!=reg.x.cflag)
  {
      /*エラーだったら アドレスbuffにエラーコードを書く*/
      *buff = reg.h.ah;
      return FALSE; /* 0:異常終了*/
  }

  *buff++ = reg.h.cl;   /* C シリンダ */
  *buff++ = reg.h.dh;   /* H ヘッド */
  *buff++ = reg.h.dl;   /* R セクタ番号 */
  *buff   = reg.h.ch;   /* N セクタ長コード */

  return TRUE; /* 0以外:正常終了*/
}

/* READ DATA 指定した1セクタからデータを読む
戻り値 0:異常終了 0以外:正常終了 */
unsigned char readdata(unsigned char device
                      ,unsigned char MF     /* MFM / FM */
                      ,unsigned char C      /* シリンダ番号 */
                      ,unsigned char H      /* ヘッド番号 */
                      ,unsigned char R      /* セクタ番号 */
                      ,unsigned char N      /* セクタ長コード */
                      ,unsigned char *buff) /* 出力を書き込むアドレス */
{
  union REGS reg;
  struct SREGS seg;

  reg.h.ah= MF | 0x16; /*AH 00010110 READ DATA  セクタからデータを読む。*/
                       /*   |||+---- SEEK */
                       /*   ||+----- ~r   */
                       /*   |+------ MF   */
                       /*   +------- MT   */
  reg.h.al= device;                /*AL デバイスタイプユニット番号*/
  reg.x.bx= sectlength(N);         /*BX DTL*/
  reg.h.cl= C;                     /*CL シリンダ番号(ahのSEEKビットが1の時のみ有効)*/
  reg.h.dh= H;                     /*DH ヘッド番号*/
  reg.h.dl= R;                     /*DL セクタ番号*/
  reg.h.ch= N;                     /*CH セクタ長コード (合わないセクタ長コードを指定するとエラー)*/
  segread(&seg);                   /* セグメントレジスタの値を取得 */
  seg.es= seg.ds;                  /*ES バッファの先頭アドレス[セグメント]*/
  reg.x.bp= (unsigned short)buff;  /*BP バッファの先頭アドレス[オフセット]*/
  int86x(DISKBIOS, &reg, &reg, &seg); /*セグメントレジスタも設定するのでint86x*/

  if(0!=reg.x.cflag)
  {
    /*エラーだったら アドレスoutにエラーコードを書く*/
    *buff = reg.h.ah;
    return FALSE; /* 0:異常終了*/
  }
  return TRUE; /* 0以外:正常終了*/
}

/* READ DELETED DATA 指定した1セクタからデリーテッドデータを読む
戻り値 0:異常終了 0以外:正常終了 */
unsigned char readdeleted(unsigned char device
                         ,unsigned char MF     /* MFM / FM */
                         ,unsigned char C      /* シリンダ番号 */
                         ,unsigned char H      /* ヘッド番号 */
                         ,unsigned char R      /* セクタ番号 */
                         ,unsigned char N      /* セクタ長コード */
                         ,unsigned char *buff) /* 出力を書き込むアドレス */
{
  union REGS reg;
  struct SREGS seg;

  reg.h.ah= MF | 0x16; /*AH 00011100 READ DELETED DATA*/
                       /*   |||+---- SEEK */
                       /*   ||+----- ~r   */
                       /*   |+------ MF   */
                       /*   +------- MT   */
  reg.h.al= device;                /*AL デバイスタイプユニット番号*/
  reg.x.bx= sectlength(N);         /*BX DTL*/
  reg.h.cl= C;                     /*CL シリンダ番号(ahのSEEKビットが1の時のみ有効)*/
  reg.h.dh= H;                     /*DH ヘッド番号*/
  reg.h.dl= R;                     /*DL セクタ番号*/
  reg.h.ch= N;                     /*CH セクタ長コード (合わないセクタ長コードを指定するとエラー)*/
  segread(&seg);                   /* セグメントレジスタの値を取得 */
  seg.es= seg.ds;                  /*ES バッファの先頭アドレス[セグメント]*/
  reg.x.bp= (unsigned short)buff;  /*BP バッファの先頭アドレス[オフセット]*/
  int86x(DISKBIOS, &reg, &reg, &seg); /*セグメントレジスタも設定するのでint86x*/

  if(0!=reg.x.cflag)
  {
    /*エラーだったら アドレスoutにエラーコードを書く*/
    *buff = reg.h.ah;
    return FALSE; /* 0:異常終了*/
  }
  return TRUE; /* 0以外:正常終了*/
}

/* VERIFY 1セクタからデータを読むが、バッファへの転送は行わない。(セクタが存在するか、データCRCエラーが無いかのチェック)
戻り値 0:異常終了 0以外:正常終了 */
unsigned char verify(unsigned char device
                    ,unsigned char MF     /* MFM / FM */
                    ,unsigned char C      /* シリンダ番号 */
                    ,unsigned char H      /* ヘッド番号 */
                    ,unsigned char R      /* セクタ番号 */
                    ,unsigned char N      /* セクタ長コード */
                    ,unsigned char *buff) /* 出力を書き込むアドレス */
{
  union REGS reg;
  struct SREGS seg;

  reg.h.ah= MF | 0x11; /*AH 00010001 READ DATA  セクタからデータを読む。*/
                       /*   |||+---- SEEK */
                       /*   ||+----- ~r   */
                       /*   |+------ MF   */
                       /*   +------- MT   */
  reg.h.al= device;                /*AL デバイスタイプユニット番号*/
  reg.x.bx= sectlength(N);         /*BX DTL*/
  reg.h.cl= C;                     /*CL シリンダ番号(ahのSEEKビットが1の時のみ有効)*/
  reg.h.dh= H;                     /*DH ヘッド番号*/
  reg.h.dl= R;                     /*DL セクタ番号*/
  reg.h.ch= N;                     /*CH セクタ長コード (合わないセクタ長コードを指定するとエラー)*/
  segread(&seg);                   /* セグメントレジスタの値を取得 */
  seg.es= seg.ds;                  /*ES バッファの先頭アドレス[セグメント]*/
  reg.x.bp= (unsigned short)buff; /*BP バッファの先頭アドレス[オフセット]*/
  int86x(DISKBIOS, &reg, &reg, &seg); /*セグメントレジスタも設定するのでint86x*/

  if(0!=reg.x.cflag)
  {
    /*エラーだったら アドレスoutにエラーコードを書く*/
    *buff = reg.h.ah;
    return FALSE; /* 0:異常終了*/
  }
  return TRUE; /* 0以外:正常終了*/
}

/* WRITE DATA 指定した1セクタかにデータを書く
戻り値 0:異常終了 0以外:正常終了 */
unsigned char writedata(unsigned char device
                       ,unsigned char MF     /* MFM / FM */
                       ,unsigned char C      /* シリンダ番号 */
                       ,unsigned char H      /* ヘッド番号 */
                       ,unsigned char R      /* セクタ番号 */
                       ,unsigned char N      /* セクタ長コード */
                       ,unsigned char *buff)  /* データバッファの先頭アドレス */
{
  union REGS reg;
  struct SREGS seg;

  reg.h.ah= MF | 0x15; /*AH 00010101 WRITE DATA  セクタにデータを書く。*/
                       /*   |||+---- SEEK */
                       /*   ||+----- ~r   */
                       /*   |+------ MF   */
                       /*   +------- MT (マルチトラック指定は使用しないこと)*/
  reg.h.al= device;                /*AL デバイスタイプユニット番号*/
  reg.x.bx= sectlength(N);         /*BX DTL データ長(DTLで示す書き込みがセクタの途中で終わった場合、残りを0で埋めて正常終了する)*/
  reg.h.cl= C;                     /*CL シリンダ番号(ahのSEEKビットが1の時のみ有効)*/
  reg.h.dh= H;                     /*DH ヘッド番号*/
  reg.h.dl= R;                     /*DL セクタ番号*/
  reg.h.ch= N;                     /*CH セクタ長コード (合わないセクタ長コードを指定するとエラー)*/
  segread(&seg);                   /* セグメントレジスタの値を取得 */
  seg.es= seg.ds;                  /*ES バッファの先頭アドレス[セグメント]*/
  reg.x.bp= (unsigned short)buff;  /*BP バッファの先頭アドレス[オフセット]*/
  int86x(DISKBIOS, &reg, &reg, &seg); /*セグメントレジスタも設定するのでint86x*/

  if(0!=reg.x.cflag)
  {
    return FALSE; /* 0:異常終了*/
    /*エラーが発生するのはIDが見つからない時*/
  }
  return TRUE; /* 0以外:正常終了*/
}

/* WRITE DELETED DATA 指定した1セクタかにデリーデッドデータを書く
戻り値 0:異常終了 0以外:正常終了 */
unsigned char writedeleted(unsigned char device
                          ,unsigned char MF     /* MFM / FM */
                          ,unsigned char C      /* シリンダ番号 */
                          ,unsigned char H      /* ヘッド番号 */
                          ,unsigned char R      /* セクタ番号 */
                          ,unsigned char N      /* セクタ長コード */
                          ,unsigned char *buff)  /* データバッファの先頭アドレス */
{
  union REGS reg;
  struct SREGS seg;

  reg.h.ah= MF | 0x19; /*AH 00011001 WRITE DELETED DATA*/
                       /*   |||+---- SEEK */
                       /*   ||+----- ~r   */
                       /*   |+------ MF   */
                       /*   +------- MT (マルチトラック指定は使用しないこと)*/
  reg.h.al= device;                /*AL デバイスタイプユニット番号*/
  reg.x.bx= sectlength(N);         /*BX DTL データ長(DTLで示す書き込みがセクタの途中で終わった場合、残りを0で埋めて正常終了する)*/
  reg.h.cl= C;                     /*CL シリンダ番号(ahのSEEKビットが1の時のみ有効)*/
  reg.h.dh= H;                     /*DH ヘッド番号*/
  reg.h.dl= R;                     /*DL セクタ番号*/
  reg.h.ch= N;                     /*CH セクタ長コード (合わないセクタ長コードを指定するとエラー)*/
  segread(&seg);                   /* セグメントレジスタの値を取得 */
  seg.es= seg.ds;                  /*ES バッファの先頭アドレス[セグメント]*/
  reg.x.bp= (unsigned short)buff;  /*BP バッファの先頭アドレス[オフセット]*/
  int86x(DISKBIOS, &reg, &reg, &seg); /*セグメントレジスタも設定するのでint86x*/

  if(0!=reg.x.cflag)
  {
    return FALSE; /* 0:異常終了*/
    /*エラーが発生するのはIDが見つからない時*/
  }
  return TRUE; /* 0以外:正常終了*/
}

/* FORMAT TRACK 一つのトラックをフォーマットする
戻り値 0:異常終了 0以外:正常終了
与えるデータは
C H R N の4バイト*セクタ数 をバッファに用意しておく
ギャップ長はBIOSが決めてくれる */
unsigned char trackfmt(unsigned char device
                      ,unsigned char MF     /* MFM / FM */
                      ,unsigned char C      /* シリンダ番号 */
                      ,unsigned char H      /* ヘッド番号 */
                      ,unsigned char N      /* セクタ長コード */
                      ,unsigned char SC    /* トラックあたりのセクタ数*/
                      ,unsigned char DATA   /* セクタに書き込むデータパターン */
                      ,unsigned char *buff) /* データバッファの先頭アドレス */
{
  union REGS reg;
  struct SREGS seg;

  reg.h.ah= MF | 0x1D; /*AH 00011101 FORMAT TRACK*/
                       /*    ||+---- SEEK */
                       /*    |+----- ~r   */
                       /*    +------ MF   */
  reg.h.al= device;                /*AL デバイスタイプユニット番号*/
  reg.x.bx= SC * 4;               /*BX DTL データ長*/
  reg.h.cl= C;                     /*CL シリンダ番号(ahのSEEKビットが1の時のみ有効)*/
  reg.h.dh= H;                     /*DH ヘッド番号*/
  reg.h.ch= N;                     /*CH セクタ長コード (合わないセクタ長コードを指定するとエラー)*/
  reg.h.dl= DATA;                  /*DL セクタに書き込むデータパターン*/
  segread(&seg);                   /* セグメントレジスタの値を取得 */
  seg.es= seg.ds;                  /*ES バッファの先頭アドレス[セグメント]*/
  reg.x.bp= (unsigned short)buff;  /*BP バッファの先頭アドレス[オフセット]*/
  int86x(DISKBIOS, &reg, &reg, &seg); /*セグメントレジスタも設定するのでint86x*/

  if(0!=reg.x.cflag)
  {
    return FALSE; /* 0:異常終了*/
    /*エラーが発生するのはメディアが入っていない時くらい?*/
  }
  return TRUE; /* 0以外:正常終了*/
}

/* READ DIAGNOSTIC
インデックス信号直後のセクタからデータを読む。
戻り値 0:異常終了 0以外:正常終了
READ DATAと違い、IDのエラー、データのエラーがあっても処理を続行する。
リザルトステータスはコマンド中に起きたすべてのエラーの論理和になる。
*/
unsigned char readdiag(unsigned char device
                      ,unsigned char MF     /* MFM / FM */
                      ,unsigned char H      /* ヘッド番号 */
                      ,unsigned char N      /* セクタ長コード */
                      ,unsigned char *buff) /* 出力を書き込むアドレス */
{
  union REGS reg;
  struct SREGS seg;

  reg.h.ah= MF | 0x02; /*AH 01000010 READ DIAGNOSTIC インデックス信号直後のセクタからデータを読む。*/
                       /*    ||+---- SEEK            READ DATAと違い、IDのエラー、データのエラーがあっても処理を続行する。*/
                       /*    |+----- ~r              リザルトステータスはコマンド中に起きたすべてのエラーの論理和になる。*/
                       /*    +------ MF */
  reg.h.al= device;                /*AL デバイスタイプユニット番号*/
  reg.x.bx= sectlength(N);         /*BX DTL*/
  reg.h.cl= 0;                     /*CL シリンダ番号(ahのSEEKビットが1の時のみ有効)*/
  reg.h.dh= H;                     /*DH ヘッド番号*/
  reg.h.dl= 1;                     /*DL セクタ番号(無意味)*/
  reg.h.ch= N;                     /*CH セクタ長コード (合わないセクタ長コードを指定するとエラー)*/
  segread(&seg);                   /* セグメントレジスタの値を取得 */
  seg.es= seg.ds;                  /*ES バッファの先頭アドレス[セグメント]*/
  reg.x.bp= (unsigned short)buff;  /*BP バッファの先頭アドレス[オフセット]*/
  int86x(DISKBIOS, &reg, &reg, &seg); /*セグメントレジスタも設定するのでint86x*/

  if(0!=reg.x.cflag)
  {
    /*エラーだったら アドレスbuffにエラーコードを書く*/
    *buff = reg.h.ah;
    return FALSE; /* 0:異常終了*/
  }
  return TRUE; /* 0以外:正常終了*/
}

/* 指定したトラックのセクタのタイプを調べる
戻り値 0:異常終了 0以外:セクタのタイプ
2D/2HD MFM/FM */
unsigned char sectsence(unsigned char device
                       ,unsigned char C
                       ,unsigned char H)
{
  unsigned char buff[4];

  device &= 0x0F; /*ユニット番号だけにする*/

  seek(device, C);
  if(readid(FD2HD | device, FDMFM, H, buff)) return FD2HD | FDMFM;
  if(readid(FD2DD | device, FDMFM, H, buff)) return FD2DD | FDMFM;
  if(readid(FD2HD | device, FDFM,  H, buff)) return FD2HD | FDFM;
  if(readid(FD2DD | device, FDFM,  H, buff)) return FD2DD | FDFM;
  /* 2Dと2DDの見分けはつかないか?
  シークしてみれば2Dと2DDの違いでシークエラー出るかな?*/
  return FALSE;
}

/* セクタ長コードからセクタ長を得る
戻り値 0:異常終了 0以外:セクタのバイト数 */
unsigned short sectlength(unsigned char N)  /* セクタ長コード */
{
  switch(N)
  {
    case 0:
      return 128;
    case 1:
      return 256;
    case 2:
      return 512;
    case 3:
      return 1024;
    case 4:
      return 2048;
  }
  return 0;
}

/*READDIAG で先頭セクタの番号を調べる
バッファサイズはセクタ長の分必要
正常終了ならバッファ先頭にセクタ番号
以上終了ならバッファ先頭にエラーコード*/
unsigned char secthead(unsigned char drive
                      ,unsigned char MF     /* MFM / FM */
                      ,unsigned char H      /* ヘッド番号 */
                      ,unsigned char *buff) /* 出力を書き込むアドレス */
{
  unsigned char n;

  /*セクタ長コードを調べる*/
  if(! readid(drive, MF, H, buff)) return FALSE;
  n=buff[3];

  if(! readdiag(drive, MF, H, n, buff))
  {
    /*エラーならエラーコードがバッファの先頭アドレスに入る*/
    /*puts(errmsg(buff[0]));*/
    return FALSE;
  }
  drive &= 0x0F; /*ドライブ番号だけにする*/
  switch(drive)
  {
    case 0:
      buff[0] = DISKSTAT.D0.R - 1;    /*読み込んだ次のセクタ番号を示しているので引き算*/
      return TRUE;
    case 1:
      buff[0] = DISKSTAT.D1.R - 1;
      return TRUE;
    case 2:
      buff[0] = DISKSTAT.D2.R - 1;
      return TRUE;
    case 3:
      buff[0] = DISKSTAT.D3.R - 1;
      return TRUE;
  }
  return FALSE;
}

/* エラーコードからエラーメッセージを得る */
char *errmsg(unsigned char ah)
{
  switch(ah & 0xF8)
  {
    case 0x08:
      return "Corrected data";
    case 0x38:
      return "Illegal disk Addres";
    case 0x88:
      return "Direct access an alternate track";
    case 0xB8:
      return "Data error";
    case 0xC8:
      return "Seek error";
    case 0xD8:
      return "Not read the alternate track";
  }

  switch(ah & 0xF0)
  {
    case 0x20:
      return "DMA Boundary";
    case 0x30:
      return "End of cylinder";
    case 0x40:
      return "Equipment check over run";
    case 0x60:
      return "Not ready";
    case 0x70:
      return "Not writable";
    case 0x80:
      return "Error 0x80";
    case 0x90:
      return "Time out";
    case 0xA0:
      return "ID CRC error";
    case 0xB0:
      return "DATA CRC error";
    case 0xC0:
      return "No data (ID not found)";
    case 0xD0:
      return "Bad cylinder";
    case 0xE0:
      return "Missing address mark (ID)";
    case 0xF0:
      return "Missing address mark (DATA)";
    }
    return "Unknown error";
}

2016年5月13日金曜日

北海道でも桜が咲き始めました

家の裏の桜が咲きました。

ハクキンカイロの燃料に染み抜き用ベンジンを使ってみる

ホームセンターの洗濯洗剤コーナで売っていたベンジンを、ハクキンカイロの燃料に使うとどうなるのかを試してみました。

使用したベンジンは、混ぜ物が無いベンジン100%のものを使用しました。
 使ってみると、ハクキンカイロ純正ベンジンと同じように暖かくなって、持続時間も同等、使用中の匂いも純正と余り変わらない感じでした。
 純正ベンジンが500ml 666円、今回使ったベンジンが500ml 511円でしたが、安いシミ抜きベンジンでも十分かなと感じました。


2016年5月7日土曜日

ハクキンカイロの燃料にイソプロピルアルコールを使うと

 このあいだ購入したハクキンカイロの燃料に、イソプロピルアルコールを使ってみました。
 ベンジンよりも揮発しにくいのか、気温10度くらいだと点火できなかったのですが、カイロに燃料を入れた後カイロ全体を体温くらいに暖めると点火できました。
 点火後の温度上昇もベンジンよりゆっくりでしたが、一度温度が上がるとベンジンと同じ程度に暖かく使えました。温度が上がるとアルコールの気化が促進されるのでしょうね。

 ベンジンの引火点は -40度以下くらい。イソプロピルアルコールの引火点は 11度くらいで、ずいぶん違いがあります。

 イソプロピルアルコールだと使用中のアルコール臭がけっこうあります。値段は安いのですが、臭いのせいで常用は厳しいかなという感想です。

2016年5月6日金曜日

ハクキンカイロを購入

ホムセンターに行ったら、ハクキンカイロが売っていたので買ってきました。温かいらしいので前から欲しかったのです。日本製だけれどそれほど高くなくて、3,218円でした。Amazonで買っても同じくらい。カイロを入れる袋とベンジンを注入するカップが付属しています。
純正のベンジンは500mlで666円でした。

薄暗いところで使用中の触媒を見ると、赤く光っているのが見えます。
袋に入れないと、手で直接持っていられないくらい熱くなります。付属の袋に入れると使い捨てカイロが最高に熱くなっている時くらいの暖かさ。温度は燃料切れまで一定している感じでした。重さは使い捨てカイロと同じくらい。重さを測ってみると、ハクキンカイロが 86g、家にあった使い捨てカイロが 66gであまり違いを感じません。
使い捨てカイロはとても安く売っているので、値段で比べるとハクキンカイロは高いのですが、燃料切れまでぬるくならないのと、ゴミが出ないのが良いです。



ついでに、同じお店で鉄のフライパンも買いました 26cm で 2,242円。これも日本製でした。
アルミのフライパンはコーティングが元気なうちは焦げ付かなくて良いのですが、1年くらい使っているとコーティングが傷んできて、油のなじみも悪いので、鉄のフライパンに買い換えです。
鉄なら一生使える(予定)。
アルミと比べるとだいぶ重く感じます。

2016年5月2日月曜日

ホットプレートでホットケーキ


数年ぶりに、ホットプレートでホットケーキを焼きました。月に一回くらいホットケーキを食べるのですが、いつもは手間がかからない炊飯器で焼いています。
炊飯器だと火加減を気にする必要も無いし、ひっくり返す必要も無いし、スイッチを入れて放っておくだけで出来上がるので簡単で良いのですが、出来上がりがホールケーキのように大きくなります。
今日は小さく焼いたものが食べたくて、ホットプレートを使いました。

あんこを挟んでどら焼きにして食べました。
小豆はスーパーで安く売っていて 400gで298円くらいなので、普段から茹でておやつにしています。