@ka2n

Technology and beer

Baikal X10: No device runningの対処方法

Baikal X10のコントロールボードのファームウェアを焼き直すことで、この状態から復帰できた。

エラーの時に何が起こっているか

ソフトウェアの状態

  • 管理画面
    • Minerはオンラインだが、デバイスが一切認識されず、No devices runningとエラーが表示される
  • マイニングプログラム
    • ASICにsshでログインしてsudo screen -rでマイニングプログラム(sgminer)を表示し、Device listを表示してもUSBデバイスが1つも認識されていない状態になる

ハードウェアの状態

  • 各ボードの赤いLEDのみが点灯し、他のLEDは消灯している

問題への対処

各ボードのFPGAにイメージを書き込み直すと、再認識されることがある

対処手順

1. FPGA用データをFWから抽出する

公開されているFWをダウンロードする。 Baikal X10の場合はこちらにリンクがあるはず。 現在公開されている最新のFWであるPiZero_GX10_180410_V1.2.img/tmp/PiZero_GX10_180410_V1.2.imgに保存。

次に、ダウンロードしたイメージファイルからコントロールボード用のイメージを抽出する。 FWのブートローダパーティションに存在するので、目的のパーティションの位置を調べ、mountする。

$ fdisk -l -u ./PiZero_GX10_180410_V1.2.img
Disk ./PiZero_GX10_180410_V1.2.img: 428.6 MiB, 449443328 bytes, 877819 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x0007a4f5

Device                         Boot  Start     End Sectors  Size Id Type
./PiZero_GX10_180410_V1.2.img1       40960  172031  131072   64M  b W95 FAT32
./PiZero_GX10_180410_V1.2.img2      172032 7544831 7372800  3.5G 83 Linux

セクターサイズが512bytes, 目的のブートローダパーティションはStartが40960にある。 マウント先を作成してから、セクターサイズ * Startをoffsetとして指定してマウントして、ファイルを保存する。

$ sudo mkdir /mnt/pizero
$ sudo mount -t vfat -o loop,offset=20971520 ./PiZero_GX10_180410_V1.2.img /mnt/pizero/
$ ls -la /mnt/pizero
total 4.6M
-rwxr-xr-x 1 root root  535 11月 22  2016  boot.scr*
-rwxr-xr-x 1 root root  17K  4月 11 01:47  GX10.bin*
-rwxr-xr-x 1 root root  35K 10月 20  2017  script.bin*
drwxr-xr-x 2 root root  512 12月 13  2016 'System Volume Information'/
-rwxr-xr-x 1 root root 4.5M 11月 22  2016  uImage*
$ cp /mnt/pizero/GX10.bin ~/

GX10.binがコントロールボード用のイメージであり、実際にASICで稼働する際は/media/boot/GX10.binに配置され、初回起動時に/media/boot/G*.binにファイルが存在する場合にコントロールボードであるSTM32F407へ書き込みを行う仕組み。 初回起動時に何らかの理由で書き込みに失敗すると、今回のような状態になる場合がある。

2. コントロールボード用データをASICに転送

ASICが接続されているネットワークに接続し、取り出したGX10.binを転送する。もちろんASICから取り出したSDカードに直接配置しても良い。 ちなみにsshでログインするにはユーザー名: baikal, パスワード: baikalを使用する。

$ scp ./GX10.bin baikal@<ASICのIPアドレス>:/tmp/GX10.bin
$ ssh baikal@<ASICのIPアドレス> sudo cp /tmp/GX10.bin /media/boot/GX10.bin

3. コントロールボード用データを書き込む

配置した段階で起動時に自動的に書き込まれるはずではあるが、出力が見えないのでSSHでログインして書き込みを実行する。

$ ssh baikal@<ASICのIPアドレス>
$ su -
# check_update.py


Downloading... /media/boot/GX10.bin
dfu-util 0.8

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2014 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to dfu-util@lists.gnumonks.org

dfu-util: Invalid DFU suffix signature
dfu-util: A valid DFU suffix will be required in a future dfu-util release!!!
Opening DFU capable USB device...
ID 0483:df11
Run-time device DFU version 011a
Claiming USB DFU Interface...
Setting Alternate Setting #0 ...
Determining device status: state = dfuERROR, status = 10
dfuERROR, clearing status
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
DFU mode device DFU version 011a
Device returned transfer size 2048
DfuSe interface name: "Internal Flash  "
Downloading to address = 0x08000000, size = 16616
Download        [=========================] 100%        16616 bytes
Download done.
File downloaded successfully
Transitioning to dfuMANIFEST state
Done

参考リンク

最後に

これでもダメならメーカーに相談しよう

ブログサービスからPingを受け取る

2018年になってもブログサービスからPingで更新通知を受け取っています。。 XML-RPCWordPress等のブログから更新通知を受け取れるのですがまた探すかもしれないのでメモ。

weblogUpdates.ping

詳細は weblogUpdates.extendedPing を参照

<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
   <methodName>weblogUpdates.ping</methodName>
   <params>
      <param>
         <value>Someblog</value>
      </param>
      <param>
         <value>https://example.com/someblog</value>
      </param>
   </params>
</methodCall>

weblogUpdates.extendedPing

パラメーター

  1. サイト名
  2. ウェブサイトのURLもしくはRSSフィードのURL
  3. (weblogUpdates.pingではOptional) ページのURL
  4. (weblogUpdates.pingではOptional) RSS/RDF/AtomフィードのURL
  5. (Optional) カテゴリーまたはタグ名, |区切り
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
   <methodName>weblogUpdates.extendedPing</methodName>
   <params>
      <param>
         <value>Someblog</value>
      </param>
      <param>
         <value>https://example.com/someblog</value>
      </param>
      <param>
         <value>https://example.com/someblog/entries/1111</value>
      </param>
      <param>
         <value>https://example.com/someblog/feed.rss</value>
      </param>
      <param>
         <value>personal|friends</value>
      </param>
   </params>
</methodCall>

WordPressからはweblogUpdates.pingweblogUpdates.extendedPingが同時に送られてくるのを見たことがある。

出典:

LinuxからSoftEther VPNサーバ(SSL VPN)へ接続したあとの使い方

接続した後にどうするのかわからなくて苦戦したのでメモ。

環境は

  • クライアント側: SoftEther VPN Version 4.25 Build 9656, Linux healthy 4.15.18-1-MANJARO #1 SMP PREEMPT Thu Apr 19 09:05:40 UTC 2018 x86_64 GNU/Linux
  • サーバ側: GithubのSoftEtherVPN_Stableのmaster

目的: 設定済みのSoftEther VPNサーバへvpnazure.net経由でNATを超えて接続する。ゲートウェイにはせずにVPN内のホストにIPアドレス直打ちでアクセスしたい。

SSL VPNで、サーバ側はNATの中にある状態。なんと、vpnazure.netが使える。(SSTP専用かと思いきや) vpncmdでアカウントを設定しておきます。ホスト名にvpnazure.netのホスト名を使用する。(素晴らしい) 仮想NIC名はVPNで作成。

VPNへ接続

SoftEther VPN Clientで接続

$ vpncmd /client localhost /CMD AccountConnect <アカウント名>

IPアドレスを割り当てる。デフォルトゲートウェイには追加せず、/etc/resolv.confも書き換えないようにする。

# ip link set vpn_vpn down
# ip link set vpn_vpn up
# dhcpcd -G -C resolv.conf vpn_vpn
# ip route add 192.168.100.0/24 via 192.168.30.1 dev vpn_vpn # VPN経由でアクセスしたいネットワークを指定

以上

VPNから切断

SoftEther VPN Clientで切断

$ vpncmd /client localhost /CMD AccountDisconnect <アカウント名>

IPアドレスの割り当てを削除

# ip link set vpn_vpn down
# ip link set vpn_vpn up
# dhcpcd -k vpn_vpn

Go言語で埋め込みをしたstructでのjson.UnmarshalJSON

goを書いていて、部分実装やゆるふわなJSONを扱うためにstructの埋め込みを使うことがある。 そのstructに対してJSONを読み込む時に少しハマった事があるのでメモ。

まずはじめに、こんな具合でJSNONをOuterマッピングしていた。

https://play.golang.org/p/zGo779zhxI

package main

import (
    "encoding/json"
    "fmt"
)

type Outer struct {
    InnerA
    InnerB
}

type InnerA struct {
    FieldA string `json:"a_field"`
}

type InnerB struct {
    FieldB string `json:"b_field"`
}

func main() {
    var v Outer
    data := []byte(`{"a_field": "A", "b_field": "B"}`)
    if err := json.Unmarshal(data, &v); err != nil {
        fmt.Println("[Error] " + err.Error())
        return
    }
    fmt.Printf("%+v", v)
        // {InnerA:{FieldA:A} InnerB:{FieldB:B}}
}

開発中にJSONb_fieldが文字でないfalseを返す場合があることが分かってしまったので以下の様に対応した。

https://play.golang.org/p/0WszSKVN0m

package main

import (
    "encoding/json"
    "fmt"
)

type Outer struct {
    InnerA
    InnerB
}

type InnerA struct {
    FieldA string `json:"a_field"`
}

type InnerB struct {
    FieldB string `json:"b_field"`
}

func (e *InnerB) UnmarshalJSON(data []byte) error {
    var v struct {
        FieldB interface{} `json:"b_field"`
    }
    if err := json.Unmarshal(data, &v); err != nil {
        return nil
    }

    switch v.FieldB.(type) {
    case string:
        break
    default:
        return nil
    }

    e.FieldB = v.FieldB.(string)
    return nil
}

func main() {
    var v Outer
    data := []byte(`{"a_field": "A", "b_field": "B"}`)
    if err := json.Unmarshal(data, &v); err != nil {
        fmt.Println("[Error] " + err.Error())
        return
    }
    fmt.Printf("%+v", v)
        // => {InnerA:{FieldA:} InnerB:{FieldB:B}}
}

これで上手くいくと思いきや、InnerAのフィールドがゼロ値になってしまっている。 そこで、面倒だけどOuterでそれぞれUnmarshalすることでなんとかなった。

https://play.golang.org/p/kii9ZmoX1O

package main

import (
    "encoding/json"
    "fmt"
)

type Outer struct {
    InnerA
    InnerB
}

type InnerA struct {
    FieldA string `json:"a_field"`
}

type InnerB struct {
    FieldB string `json:"b_field"`
}

func (e *Outer) UnmarshalJSON(data []byte) error {
    var err error
    err = json.Unmarshal(data, &e.InnerA)
    if err != nil {
        return err
    }
    err = json.Unmarshal(data, &e.InnerB)
    if err != nil {
        return err
    }
    return nil

}

func (e *InnerB) UnmarshalJSON(data []byte) error {
    var v struct {
        FieldB interface{} `json:"b_field"`
    }
    if err := json.Unmarshal(data, &v); err != nil {
        return nil
    }

    switch v.FieldB.(type) {
    case string:
        break
    default:
        return nil
    }

    e.FieldB = v.FieldB.(string)
    return nil
}

func main() {
    var v Outer
    data := []byte(`{"a_field": "A", "b_field": "B"}`)
    if err := json.Unmarshal(data, &v); err != nil {
        fmt.Println("[Error] " + err.Error())
        return
    }
    fmt.Printf("%+v", v)
}

理由は後で調べる。