おやこですりむ

 

■ArduinoでFizzBuzzしてみた

俺はプログラミングもほとんど初心者に等しいので、そっちの方をもう少し勉強しようと思ってます。

Arduino スケッチは C 言語をベースにしているということなので、C 言語も合わせてやっていきましょう。てなことを考えながら、とりあえず何か書いてみるなら FizzBuzz かなとか (^_^;)

 

FizzBuzz とは、まぁ誰でも知っていると思いますけど、50 まで数えて 3 の倍数のときアホになるというやつです。… じゃぁなくて、100 までカウントして 3 の倍数のとき Fizz 、5 の倍数のとき Buzz、さらに 3 と 5 の倍数のときは FizzBuzz と表示させるといったプログラムのことです。こいつを Arduino でやってみます。

ちょうど 7セグメント LED を使ってみていたので、スタートボタンを押したら 0 から 99 までカウント表示させることにしましょう。3 の倍数のときは FZ 、5 の倍数では BZ 、3 と 5 の倍数のときは FB と表示させることにします。

 

回路図は以下です。特段変わったところはありません。

Arduino の D9 にタクトスイッチをつなぎ、これを ON するとカウントをスタートさせます。

アノードコモンの 7 セグメント LED 表示器が 2個手元にありますので、これをシフトレジスタ SN74LS164 で表示させます。デジットドライブはこれも手持ちの 2N3906 を使用しています。2SA1015 とかでもいいですね。FET でもかまいません。持っているものを適当に使いましょう。でも Arduino で直接駆動するのはちょっと無理があります。

シフトレジスタと LED の接続は、7ビットのデータを LSBFIRST (最下位ビットから送出) させるつもりなので、Qa の出力を未接続にしています。このあたりはプログラムと整合させないとうまく表示できませんので注意します。

 


DizzBuzz_回路図

 

 

スケッチのフローチャートです。

スイッチの ON を検出して 0 から 99 までカウントします。それを 7 セグメント LED で 2 桁表示させます。十の位が 0 のときは表示しないようにしています。2 桁を 1 ミリ秒ずつ表示して 300 回繰り返すので、約 600 ミリ秒ごとにカウントしていくことになります。

その値の倍数かどうかは剰余が 0 かどうかを判断します。3 と 5 の倍数ということは 15 の倍数ということです。ここが FizzBuzz の肝ですね。それぞれの判定結果に従って、表示する値を変えています。

ん〜、なんかもっとすっきりできそうな気がするけど、いまの俺のレベルではこんなもんでしょ (^_^;)

 


FizzBuzz_フローチャート

 

 

スケッチです。

じつは、関数の引数とか戻り値とか初めて使ってみたんですよ (^_^;)

 

// Fizz Buzz on Arduino  2019.06.16 meyon

 

/*  スイッチを押下すると 0 から 99 までマウントする。
    3 の倍数のとき FZ 、5 の倍数のとき BZ 、
    15 の倍数のとき FB と表示させる。
*/

 

const byte segmentData[14] = {
  B1111110, // 0
  B0110000, // 1
  B1101101, // 2
  B1111001, // 3
  B0110011, // 4
  B1011011, // 5
  B1011111, // 6
  B1110000, // 7
  B1111111, // 8
  B1111011, // 9
  B1000111, // F
  B0011111, // B
  B1101100, // Z
  B0000000  // blank
};

 

const int startPin = 9;
const int driverPin[2] = {10, 11};
const int clockPin = 12;
const int dataPin = 13;

 


int judgeNumber(int value) {
  int result;
  if(value == 0) {
    result = 0;
  } else if(value % 15 == 0) {
    result = 15;
  } else if(value % 5 == 0) {
    result = 5;
  } else if(value % 3 == 0) {
    result = 3;
  } else {
    result = value;
  }
  return result;
}

 


void displayNumber(int value) {
  int digit[2];
  if(value == 15) {
    digit[0] = 11;        // B
    digit[1] = 10;        // F
  } else if(value == 5) {
    digit[0] = 12;        // Z
    digit[1] = 11;        // B
  } else if(value == 3) {
    digit[0] = 12;        // Z
    digit[1] = 10;        // F
  } else {
    digit[0] = value % 10;
    if(value / 10 == 0) {
      digit[1] = 13;      // 10 digit is blank
    } else {
      digit[1] = value / 10;
    }
  }

 

  int j=0;
  while(++j < 300) {      // Display cycle
    for(int i=0; i<2; i++) {
      shiftOut(dataPin, clockPin, LSBFIRST, ~segmentData[digit[i]]);
      digitalWrite(driverPin[i], LOW);
      delay(1);
      digitalWrite(driverPin[i], HIGH);
    }
  }
  return;
}

 

 

void setup() {
  pinMode(startPin, INPUT);
  pinMode(driverPin[0], OUTPUT);
  pinMode(driverPin[1], OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

  digitalWrite(driverPin[0], HIGH);
  digitalWrite(driverPin[1], HIGH);
}

 


void loop() {
  if(digitalRead(startPin) == LOW) {
    for(int i=0; i<100; i++) {
      int value = judgeNumber(i);
      displayNumber(value);
    }
  }
}

 

 

ついでにブレッドボードです。

7 セグメント LED がピンが左右についている品物なので 2桁並べて置けません。ご愛嬌です。

回路図にはありませんが、IC の電源には 0.1μF のコンデンサをつけてます。またブレッドボードの電源ラインには 10μF 程度の電解コンデンサを置くようにしています。
 


FizzBuzz_ブレッドボード

 

 

電源が写真にはありませんが、12V の AC アダプタの出力から 3 端子レギュレータで 5V を作っています。Arduino の電源は 12V を Vin に供給しています。ただ、USB ケーブルを挿したまま AC アダプタを切っちゃうと Vin から 5V が逆流してしまうので、12V ラインにダイオードを入れて阻止しています。まぁ小ネタですけど。

 


■Arduino Nano 互換機を買ってみた

Amazon で「HiLetgo® 3個セット Mini USB Nano V3.0 ATmega328P CH340G 5V 16M マイクロコントローラーボード Arduinoと互換」を購入しました。結果、何の問題もなく期待通り動作してくれました。

 

廉価な互換機ということなので、Uno との違いもさることながら、正規品との違いも確認しておきたいとググってみたのですが、どうもなにやら良い印象がない (^_^;) 

レビューでも数個に 1個は動作しないとか、USB シリアル変換チップ CH340 用のドライバをインストールしないといけないとか、その CH340 が偽物であるとか、Old Bootloader を選択しないと書き込みできないとか… 使ってみたというサイトを見ても同様の情報が多く、また中国からの配送なので時間がかかるとか、まぁ導入時は多少苦労するかなと覚悟をしていました。

 

が、そんな懸念は一切無用。Ubuntu 18.04.2 LTS のパソコンで、次の設定で動作しています。

 

ボード:Arduino Nano

プロセッサ:ATmega328P

シリアルポート:/dev/ttyUSB0

 

CH340 のドライバのインストールは不要です。ブートローダも Old ではないほうで良いので、新しいものになっているようです。ちなみに CH340 の真贋の判断基準となるとか言われているマークは底の平らな大きな丸でした。見た目も気になるようなところは何もなく、粗悪な安物といった感じはありません。


Arduino nano 互換機

 

USB ケーブル (A to miniB) とその他  1点とともに、注文から約 24時間で到着しました。さすが Amazon's Choice です。寸法はわかっていましたが、実物は思っていた以上に小さく感じました。A コネクタと変わらないですね。

 

まず、3個すべてに Blink を書き込んで正常に動作することを確認しました。

付属のピンヘッダを取り付けて、以前作った 3x3x3 LED Cube につないでみました。これも全く問題なく動作しています。このサイズの基板で実装できそうですね。


3x3x3 LED Cube with 互換機

 

 


■ファンクションボタンの検出

最近よく見かける、上下左右にメニューボタン、中央に決定ボタンがあるような、なんていうのか名前を知らないのですが、ファンクションボタンを作ってみました。

 

タクトスイッチ 6個を「up」「down」「right」「left」「set」「reset」のファンクションボタンとし、どのボタンが押されたかを検出します。今回の肝は電圧分圧方式でのボタン検出で、押したボタンによって入力電圧が変化するという仕組み。ググると考え方や抵抗値の計算方法が出てきますので参考にしてください。

二つ以上のボタンを同時に押した場合は優先順位がありますので、今回は「reset」を最優先のボタンとして並べてみました。

計算上の分電圧と実際の入力値は異なりますので、Arduino の入力値を実測してボタン判断のしきい値を決めています。

どのボタンが押されたかを表示するために、手元にあった 7 セグメント LED (アノードコモン) をシフトレジスタで表示させています。シフトレジスタは前に LED キューブで使っていた SN74LS164 です。こいつはストレージレジスタがありませんので、ドライブ用にトランジスタ 2N3906 を付けました。これによりデータ送信中は LED を表示させないようにしています。セグメントの電流は 7mA 程度、2N3906 は最大コレクタ電流 200mA ですので十分使えます。

 

回路図です。


function-switch 回路図

 

ブレッドボードはこんな感じ。実際はこれを時計方向に 90° 回して実験していますので、右上のタクトスイッチは上下左右に 4 個のボタンと左下に reset 、右下に set という配置になってます。まぁどんな並びでも関係ないんですけど (^_^;)  押したボタンに応じて数字が表示されるという単純なものです。


function-switch ブレッドボード

 

 

フローチャートとスケッチです。ボタン判断のしきい値がフローチャートとスケッチで異なっていますが、最終的にはスケッチの値にしています。

 


画像キャプション

 

// function-switch 2019.06.06 meyon

 

byte segmentData[7] = {
  B1111110, // 0
  B0110000, // 1
  B1101101, // 2
  B1111001, // 3
  B0110011, // 4
  B1011011, // 5
  B1011111  // 6
};

int driverPin = 11;
int clockPin = 12;
int dataPin = 13;
int displyNumber = 0;


int buttonPressed() {
  int inputVoltage = analogRead(A0);

  if (inputVoltage > 947) {
    return 0; //off
  } else if (inputVoltage > 779) {
    return 1; //set
  } else if (inputVoltage > 602) {
    return 3; //up
  } else if (inputVoltage > 436) {
    return 5; //right
  } else if (inputVoltage > 268) {
    return 4; //down
  } else if (inputVoltage > 90) {
    return 6; //left
  } else {
    return 2; //reset
  }
}


void displyButtonNo() {
  digitalWrite (driverPin, HIGH);
  shiftOut(dataPin, clockPin, MSBFIRST, ~segmentData[displyNumber]);
  digitalWrite (driverPin, LOW);
  return;
}


void setup() {
  pinMode (driverPin, OUTPUT);
  pinMode (clockPin, OUTPUT);
  pinMode (dataPin, OUTPUT);

  Serial.begin(9600);
}

 

void loop() {
  Serial.println(analogRead(A0));
  
  if (buttonPressed() != 0) {
    displyNumber = buttonPressed();
  }
  displyButtonNo();
}

 

例によって入力値の確認のためにシリアル出力を使ってます。

シフトレジスタもドライブ用トランジスタも LOW で点灯になります。これ勘違いするとすべてがおかしくなってしまいますので (^_^;)

 


■押しボタンスイッチのアクションの検出

Arduino を使って、押しボタンスイッチの入力アクションの検出を行なってみました。

アクションは「シングル (一回押し) 」「ダブル (二回押し) 」「ホールド (長押し) 」の三種類で、これらを一つのタクトスイッチから検出し LED の点灯・点滅・消灯を制御します。

ググってみると、一定の時間内にスイッチの状態を確認して OFF/ON が変化する時間や回数を調べる方法がとられているようですので、その方法で自分なりに考えてみることにします。

 

 

ますはアクションの検出について。

スイッチに入力があったら、そこから 50ミリ秒毎に 10回チェックを行い、その間にあった変化の回数をカウントすることにします。「シングル」では変化は 1回だけです。「ホールド」では変化はありません。「ダブル」の場合は 2回目の変化があった時点で判断します。


アクションの検出

 

 

次に回路図です。

難しいものではありません。タクトスイッチの入力と、出力で LED を駆動するだけです。

入力ピンの電流を確認してみると HIGH でも LOW でも 0.7mA 程度でしたので、プルアップでもプルダウンでもどちらでもよさそうです。今回は ON 時に HIGH となるようプルダウンとしました。

出力も HIGH 時に LED が点灯するようにしました。もちろん電流値をきちんと確認して Arduino で直接駆動してもかまいませんが、これぐらいの単純なスイッチング回路を作るぐらいは屁でもありませんから (^_^;)


回路図

 


大まかなフローチャートです。

グーグル先生たちはこういうのを書かないのか、あまり見ませんね (^_^;)  上手ではありませんが、考えを整理するためにも簡単に作ると具合がいいです。


フローチャート(全体)


「入力待ち」では、スイッチが押されたかどうかを検知します。待つためにここでプログラムを止めてしまうと LED の点滅の制御ができなくなるので、一度検知したら次の処理を行なってからまた戻ってくるようにします。

スイッチが押されたら「変化を調べる」処理をします。前述のように、一定の時間内にスイッチの状態が変化した回数を調べます。

変化した回数をもとに、「LED表示」で点灯・点滅・消灯の制御を行います。点滅は 150ミリ秒を経過することに点灯・消灯を切り替えます。

 

「入力待ち」はこんな感じです。

入力ピンの状態を読み込んでスイッチが押されたら state_of_button をセットします。押されなければ何もしません。


フローチャート(入力待ち)

 

スイッチが押されたら「変化を調べる」を実行します。押されていないときは何もしません。

50ミリ秒待ってからスイッチの状態が変化 (ON から OFF、または OFF から ON) しているかを調べます。変化なければ、また50ミリ秒待って調べます。これを 10回、都合 500ミリ秒間行ないます。

スイッチの状態が変化していたら number_of_changes を加算します。変化の回数が 2 になれば「ダブル」が確定しますので、ループを抜けます。これで number_of_changes は「シングル」が 1 、「ダブル」が 2 、「ホールド」は 0 となります。

ちなみに、最後の elapsed_time リセットは LED 点滅周期タイマーのスタートです。


フローチャート(変化を調べる)

 

最後は「LED 表示」です。

number_of_changes 値に従って switch case で分岐します。点滅制御は millis() 関数を利用して経過時間を調べ、150ミリ秒を経過していれば light 値を反転させて点灯・消灯を繰り返すという方法をとります。L チカでよくある delay を使う方法では、プログラムがここで止まってしまうのでうまくありません。


フローチャート(LED表示)

 

 

ということでできたスケッチは以下です。

// button-status.ino 2019/05/31 meyon

 

int inputPin = 2;
int outputPin = 13;
boolean state_of_button = 0;
boolean state_of_currently = 0;
int number_of_changes = 0;
unsigned long elapsed_time;
boolean light = 0;

 

void wait_input(){
  state_of_currently = digitalRead(inputPin);
  if(state_of_currently == 1){
    state_of_button = 1;
    number_of_changes = 0;
  }
  return;
}

 

void detect_changes(){
  if(state_of_button == 1){
    for(int i=0; i<10; i++){
      delay(50);
      state_of_currently = digitalRead(inputPin);
      if(state_of_currently != state_of_button){
        number_of_changes ++;
        if(number_of_changes >= 2){
          break;
        }
        state_of_button = state_of_currently;
      }
    }
    while(state_of_currently == 1){
      state_of_currently = digitalRead(inputPin);
    }
    state_of_button = 0;
    elapsed_time = millis();
  }
  return;
}

 

void light_led(){
  switch(number_of_changes){
    case 0:
      light = 0;
      break;
    case 1:
      light = 1;
      break;
    case 2:
      if(millis() - elapsed_time > 150){
        light = !light;
        elapsed_time = millis();
      }
  }
  digitalWrite(outputPin, light);

  return;
}

 

void setup() {
  pinMode(outputPin, OUTPUT);
  pinMode(inputPin,  INPUT);

 

//  Serial.begin(9600);
}

 

void loop() {
  wait_input();
  detect_changes();
  light_led();

 

//  Serial.print(state_of_currently);
//  Serial.print(state_of_button);
//  Serial.println(number_of_changes);

}

 

コメントアウトしてあるシリアル出力はデバック時に変数の値を確認していたものです。このように適当な位置に Serial.print を入れると、その場所で変数がどうなっているかが見えるようになります。うまく動かないときに重宝しますね。

 

ということで、スイッチアクションで制御を切り替えることができるようになりました。

 


■Ubuntu Server / NAS PC連動電源機能を設定する

設定中の ubuntu server でもバッファローの NAS TS-WXL の PC 連動電源機能を利用できるようにしようと思います。

PC 連動電源機能は PC の off-on に NAS の off-on を連動させる機能です。この機能については「ubuntu 18.04 / NASのPC連動電源機能を使う」で書いていますが、今回は crontab -e ではなく、ディレクトリ cron.d に実行スクリプトを置くように変更しました。

 

スクリプトを naspoweron としてユーザーディレクトリに作成します。cron.d では拡張子のないファイルを実行しますので、拡張子は無しとします。

#! /bin/bash

while true

do

  for i in `seq 3`

  do

    wakeonlan -i 192.168.1.xx -p 9 AA:BB:CC:DD:EE:FF

  done

  sleep 150s

done

 

作成したら実行属性を与えて、動作することを確認しておきましょう。150秒おきにマジックパケットを 3 回送信します。パケットの状況は

 

$ sudo tcpdump udp and host 192.168.1.xx

 

で確認できます。

 

このスクリプトを「Ubuntu Server / 指定時刻に自動シャットダウンする」で作成した /etc/cron.d/user_cron に追加し、起動時に実行させます。

 

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user    command
05 00    * * *    root    shutdown -h +1

@reboot    root    /home/hoge/naspoweron

 

@reboot は起動時に一回だけ実行するという意味で、時間指定部分を置き換えます。

 

cron を再起動します。

 

$ sudo service cron restart


■Ubuntu Server / 指定時刻に自動シャットダウンする

ubuntu server で cron を利用して指定した時刻に自動シャットダウンするようにします。

 

以前は crontab -e で設定していたのですが、今回は cron.d に設定することにします。cron.d ディレクトリにおいた拡張子のないファイルが実行されますので、crontab をコピーして利用することにします。

 

$ sudo cp /etc/crontab /etc/cron.d/user_cron

 

コピーしたファイルを以下のように変更します。

 

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user    command
05 00    * * *    root    shutdown -h +1

 

これで毎日 00:05 にシャットダウンコマンドが起動し、1分後に実際にシャットダウンします。

本当はアクセスしているクライアントがないかどうかを確認する必要があるのでしょうが、まぁ家サーバなので強制的にシャットダウンしてもそんなもんです (^_^;)

 

変更したら再起動します。

 

$ sudo service cron restart

 


■Windows7 / WindowsUpdateでネットワークアダプタが消える

Windows7 機を整備するために Windows Update を実行したら、ネットワークアダプタが消えてしまったという話です。

 

この Windows7 機を最後に更新したのは 3年近く前です。整備するためにまず Windows Update を実行します。

が、その前に、なにかトラブルがあった時のために HDD を丸ごとバックアップしておきます。何でもないことだけどこれは必須です。何度助けられたことか (^_^;)

蛇足ですが。バックアップを取られる人は多いと思いますが、リストアってやったことあります? たとえば別の HDD にリストアしてみるといった予行演習的なことは、常々やっておいたほうが良いです。いざというときに「リストアできない!」「方法がわからない!」という悲惨な目にあわないためにね。

 

閑話休題。

 

Windows Update の設定は「更新プログラムを確認しない」になっていましたので、それはそのまま「更新プログラムの確認」を行いました。いくつかの更新プログラムが表示されましたが、最新のものは 2019/05/14 のマンスリー品質ロールアップなどです。インストールを実行し、再起動の指示に従い再起動。とりあえず問題なく Windows7 は起動しました。

 

が、ネットワークにつながりません。タスクトレイのネットワークアイコンには ×印がついています。

そういえば Windows Update でネットワーク設定が変更されるって記事があったよなぁ、と思い出して、ネットワークアダプタの設定を確認しようとすると…… 無い…… ローカルエリア接続のアイコンが無い (^_^;)

デバイスマネージャを確認すると、ネットワークアダプタは「ドライバがインストールされていません」となっていました。ドライバの更新を実行するとなにやらエラーを起こしてインストールできません。

 

さて、どうするか?

なにかとお世話になっている「ぼくんちのTV別館」で Windows Update の情報を確認すると

今後、Windows7の更新は注意が必要 (再掲)

 

※この項目は、2019年4月度情報の再掲です。
今後、Windows 7 を2018年3月以前のイメージからリカバリを行おうと思った場合や、ゲスト仮想マシンでの運用では注意が必要。Windows Update 適用後に、ネットワーク設定が意図しないものに変更される場合がある。

とありました。

 

これかぁ、これに違いない。なんてったって最終更新は 3年前だもの (^_^;)

 

こうなってしまったら更新プログラムの削除とかシステムの復元とかを考えるわけですが、そんなことして深みにはまるより、さっさとバックアップからリストアして元に戻したほうが早いです。もうね、神様、仏様、バックアップ様ですよ。

というわけでリストア完了。もう一度 Windows Update をやり直します。

 

更新プログラムの確認をして、まず 2019年4月10日より前の日付の更新プログラムだけをインストールします。

次に、更新プログラムの確認をして表示された 5月分の更新プログラムをすべて非表示にし、もう一度更新プログラムの確認を行います。すると 4月分の更新プログラムが表示されますので、これも非表示にします。

さらに更新プログラムの確認を行うと、今度は 3月分のマンスリー品質ロールアップ (KB4489878) を含む 3月分の更新プログラムが表示されます。これをインストールします。

この「2019-03 マンスリー品質ロールアップ (KB4489878) 」こそが必須の更新プログラムなのだそうです。

 

引き続き更新プログラムの確認を進めます。

もう一つ必須の「サービススタック更新プログラム (KB4490628) 」が表示されますので、インストール。さらに更新プログラムの確認を行うと「利用できる重要な更新プログラムはありません」となりました。

ここで非表示の更新プログラムの再表示を行うと 5月分の更新プログラムが表示されます。たぶんもうこれをインストールしても問題ないのだろうと思いますが、念のためこれをもう一度非表示にして、4月分の更新プログラムを表示させインストールします。

そして最後に、5月分の更新プログラムをインストール。

 

無事、ネットワークアダプタには被害なく、Windows Update を完了しました。

 


■直す価値のないハードディスクを修復してみる の結果

ハードディスクの S.M.A.R.T. 属性について、英語版の Wikipedia S.M.A.R.T. にこんな記述を見つけました。これは「197 0xC5 Current Pending Sector Count」属性の解説の抜粋です。

 

However, some drives will not immediately remap such sectors when written; instead the drive will first attempt to write to the problem sector and if the write operation is successful then the sector will be marked good (in this case, the "Reallocation Event Count" (0xC4) will not be increased). This is a serious shortcoming, for if such a drive contains marginal sectors that consistently fail only after some time has passed following a successful write operation, then the drive will never remap these problem sectors.

 

代替保留中の不良セクタは、もう一度読み出しに失敗すると代替処理待ちとなり、次の書き込みで代替処理が行われます。しかし、「一部のドライブでは書き込みを行なってもただちに代替処理が行われない」というのです。不良セクタに対して、まず書き込みを行なってみて、書き込みが成功すれば良いセクタだとマークされます。この場合は Reallocation Event Count (0xC4) を増やしません。

 

まさにこれではないのでしょうか。

くだんの HDD は、dd コマンドでゼロフィルしたのちに Current Pending Sector が 0 になった。でも、Reallocated Event Count も Reallocated Sector Ct も増えていない。つまり、書き込みを行なったにもかかわらず代替処理が行われなかった。それは、代替処理の前に書き込みを行ない、それが成功したためだと。

これは、場合によっては不良セクタの代替処理が行われないことになるので「重大な欠点だ」と書かれています。

 

微妙な位置に立たされた HDD ということでしょうねぇ (^_^;)

 

ちなみに「198 0xC6 (Offline) Uncorrectable Sctor Count」について。

 

The total count of uncorrectable errors when reading/writing a sector. A rise in the value of this attribute indicates defects of the disk surface and/or problems in the mechanical subsystem.

 

この数値が増えるということは、「ディスク表面の欠陥」「メカニカルサブシステムの問題」があるということ。これはどうやら今後急速に劣化していく可能性を持っているようです。

 

ということで、最終結果。

この HDD は近いうちに故障する恐れがあります。でも、貧乏な俺はこの HDD を、あまり重要でない用途に、常に状態をチェックしながら使い続けてみることにします。\(^o^)/

 


■直す価値のないハードディスクを修復してみる のまとめ

もともと Windows7 のノートパソコンで使われていた 2.5 インチ 500GB のハードディスク。Windows が起動できなくなっていました。具合が悪くなると強制終了、なんて使い方を続けていたようです。そのハードディスクのままで OS を再インストールしたら正常に使えちゃったというのが、事の始まり。

で、完全に動かなくなるまでハードディスクを使い倒したい貧乏な俺は、いろいろ試しながら、グーグル先生に教えてもらいながら、あわよくばこいつを再利用できないものかと目論んでいたわけです (^_^;)

 

多くのサイトで勉強させていただきましたが、そんななかで出会ったサイトがこちら「PCと解 パソコントラブルにまつわるサイト」です。さまざまなパソコントラブルについてこれまでのご経験をもとに書かれているサイトですが、ハードディスクトラブルに関してもわかりやすく書かれています。とても参考になりました、ありがとうございます。

 

 

さて、おれが正確に理解できているかかどうかは怪しげです (^_^;) が、つまりこういうことかと。

 

S.M.A.R.T. テストは HDD の物理的な状態を調べるもの。

Windows で使ってみたらエラーもなく利用できたのは、ファイルシステムが物理的な異常を論理的に処理、回避してくれているから。Windows で動くチェックディスク chkdsk で不良セクタが表示されないのはそのためだということ。

S.M.A.R.T. によるセルフテストは読み書きのチェックを行ないますが、最初に不良セクタを見つけたところで停止します。badblocks コマンドも同じように読み書きを行ないますが、エラーがあっても停止せず HDD 全体をチェックしてくれます。

不良セクタをファイルシステムに論理的に認識させるには、Windows ならば chkdsk 、Linux ならば fsck のようなファイルシステムをチェックするコマンドを利用します。でも、すでに代替処理されたセクターにファイルシステムは関知しませんから、OS からは見えません。

 

読み出しエラーがあったセクターは Current Pending Sector となり登録されます。次に読み出しがあったときに、読み出しに成功すれば正常なセクタとなり Current Pending Sector の数は減ります。読み出しに失敗すると代替処理すべきセクタとなり、次の書き込み時に代替処理されます。

代替処理が行われると Reallocated Event Count が増やされます。処理済みとなれば Reallocated Sector Ct が増える。でも、処理に失敗した場合はどうなるのでしょうか? その場合は Offline Uncorrectable となる?

 

Current Pending Sector に書き込みを行なう ( dd や badblocks ) と代替処理が行われるので、Current Pending Sector は消失します。chkdsk や fsck はファイルシステムのエラーをチェックするものなので、いわゆる修復 (代替処理) にはならない。フォーマットもファイルシステム上の処理なのでダメ。

 

 

これらを踏まえてくだんの HDD のことを考えてみると。

 

dd コマンドでゼロフィルしたのちに、S.M.A.R.T. のセルフテスト (long) を実行し Current Pending Sector は 0 になった。でも、Reallocated Event Count も Reallocated Sector Ct も増えていない。Offline Uncorrectable は 108 が 209 に増えた。

とゆーことは、書き込みを行なったにもかかわらず代替処理が行われなかった。代替保留中だけれども、次の読み出しがまだ行われておらず、代替処理すべきセクターになっていなかった、ってことか? そこへ書き込み、読み出しを行なったら正常にできたので、代替保留中にはならなかった?

…… じゃあ、Offline Uncorrectable はなんなの?

 

まとめようかと思ったけれど、疑問はさらに続く…… (^_^;)

 


■直す価値のないハードディスクを修復してみる の参

全ブロックに 0 を書き込んでみた HDD (500GB) の S.M.A.R.T. テストの結果は、Current Pending Sector (現在保留中のセクタ) がなくなりましたが、Offline Uncorrectable (オフライン修正不可能) が 209 に増えています。これはいわゆる不良セクターって奴なのでしょうか?

badblocks コマンドを使って調べてみることにしましょう。

 

badblocks は、今回は破壊的 (書き込みモード) 検査をやってみます。man badblocks してみると、

 

-w     Use write-mode test. With this option, badblocks scans for bad blocks by writing some patterns (0xaa, 0x55,  0xff,  0x00)  on  every block (すべてのブロックにいくつかのパターンを書き込むことによって) of the device, reading every block and comparing the contents.  (後略)

 

ということです。ん〜、4つのパターンをすべてやってみるのかな。1パターンに 5時間かかるとすると 20時間 …    -t オプションでパターンを random に指定すれば良いのかもしれない。

 

-t test_pattern

Specify a test pattern to be read (and written) to disk blocks.   The test_pattern may either be a  numeric  value between  0 and ULONG_MAX-1 inclusive, or the word "random", which specifies that the block should be filled with a random bit pattern ("random" は、ブロックがランダムなビットパターンで埋められることを指定します) .  (中略) If multiple patterns are specified then all blocks will be tested with one pattern before proceeding to the next pattern (複数のパターンが指定されている場合は、すべてのブロックが1つのパターンでテストされた後に、次のパターンに進みます。) .

 

ということなので、以下のように実行してみることにします。

$ sudo badblocks -svw -b 4096 -c 256 -t random -o badblocks.txt /dev/sdb

ランダムなパターンを書き読みして、一回りで終了。1 ブロック 4096 バイトを 256個ずつテストしますので、一度に 1MB をテストすることになります。と思います (^_^;)

 

ちなみに、エラーを書き出したファイルを e2fsck に渡すといった方法を説明しているサイトがいくつも見られましたけど、いま俺がやっているような、全体を潰したファイルシステムが無い状況ではそれはできません。e2fsck はファイルシステム (ext2 / ext3) がないと実行できませんので。俺がファイルに書き出しているのは、単に記録として見るためです。

man には、e2fsck に渡す場合には badblocks を使わないように、と書かれています。

 

Important note: If the output of badblocks is going to be fed to the e2fsck or mke2fs programs (badblockの出力がe2fsckまたはmke2fsプログラムに送られる予定の場合) , (中略) it is strongly recommended that users not run badblocks directly, but rather use the -c option of the e2fsck and mke2fs programs (ユーザーが badblocks を直接実行しないことを強くお勧めします。むしろ、e2fsckおよびmke2fsプログラムの-cオプションを使用してください) .

 

さて、実際の動きですが、開始からまずランダムなパターンの書き込みが行われたようです。4時間 40分で 100% に達し、

Testing with random pattern: done

となりました。現在のところエラーは検出されていません。

そして今度は Reading and comparing: が進行しています。たしかに、dd で全体に 0 を書き込むにも同じ時間がかかっていますから、納得できる作業時間です。

ということはですよ、デフォルトが 4つのパターンを指定しているとすると、書き込みだけで 18時間 40分を要することになります。読み出しと比較に同じ時間かかるならば、全体の作業時間は 37時間 20分と見積もられます。

 

そしてついに badblocks コマンドが終了しました。正確な時間をチェックしてないのですが、ほぼ書き込みと同じほどかかっています。

$ sudo badblocks -svw -b 4096 -c 256 -t random -o badblocks.txt /dev/sdb
Checking for bad blocks in read-write mode
From block 0 to 122096645
Testing with random pattern: done                                                 
Reading and comparing: done                                                 
Pass completed, 0 bad blocks found. (0/0/0 errors)

結果、不良セクタは検出されませんでした。エラーがなかったので badblocks.txt も作成されていません。そして予定したとおり、ランダムパターンの書き込み読み出しを一回り実行して終了ということでした。

 

どうなんでしょう? この HDD ってまだしばらく利用できそうじゃないですか (^_^;)

 


| 1/59PAGES | >>

■calendar

S M T W T F S
      1
2345678
9101112131415
16171819202122
23242526272829
30      
<< June 2019 >>

■search this site.

■recommend

毎日貯まるポイントサイト ECナビ

■recommend

* 楽天ROOM *

■Twitter

■recommend

■recommend

■selected entries

■categories

■archives

■recent comment

■recent trackback

■links

■profile

■others

■mobile

qrcode

■powered

無料ブログ作成サービス JUGEM