TinyGSのFirmwareをESP-WROOM-32に書き込む

TinyGSというLoRaを使った衛星地上局のプロジェクト

Home - TinyGS

海外ではESP32にLoRaのチップが乗ったモジュールがいくつか販売されているが

日本では技適が通ってないようなので・・・

技適が通っている組み合わせでなんとか実験できないかと思い

まずはESP-WROOM-32に書き込みができるか試してみた

続きを読む

RubyのC拡張でmakeしたらstdio.hがありませんというエラーがでた

自分の記事を復習してたのだが

RubyでC言語拡張のやりかた入門してみる - 知らんがな

なぜか、make したときに

...
'stdio.h' file not found
#include <stdio.h>
         ^~~~~~~~~
1 error generated.

みたいなのがでてきてなぞだったが下記のqiita記事のコメント欄みて解決した

bundle installでハマっております(汗) - Qiita


結果、libraryのpackageを再インストールすることで解決した

terminalで下記を打ち込んで

open /Library/Developer/CommandLineTools/Packages/

macOS_SDK_headers_for_macOS_xx.yy.pkg みたいなpackage fileが入ったディレクトリが開くと思われるので、ダブルクリックしてあとは指示に従ってインストールしたら、ちゃんとmakeされるようになった

wafでHello Worldまでやってみる


wscriptが下記

def options(ctx):
    ctx.load('gcc')

def configure(cnf):
    cnf.load('gcc')
    cnf.check(header_name='stdio.h', features='c cprogram')


def build(bld):
    bld(features='c cprogram', source='main.c')

main.cプログラムが下記

#include <stdio.h>

int main(){
    printf("Hello, world!\n");
    return 0;
}
  • waf buildしたらエラーがでた
$ python waf-2.0.18 build
Waf: Entering directory `programming/waf/build'
[1/2] Compiling main.c
[2/2] Linking build
ld: can't open output file for writing: /programming/waf/build, errno=21 for architecture x86_64
collect2: error: ld returned 1 exit status

Waf: Leaving directory `/programming/waf/build'
Build failed
 -> task in '' failed with exit status 1 (run with -v to display more information)


  • ファイルをみたら、.oファイルまではできてるのでリンクができてない?と考えられる
$ tree
.
├── build
│   ├── bar.md
│   ├── bar.txt
│   ├── c4che
│   │   ├── _cache.py
│   │   └── build.config.py
│   ├── config.log
│   ├── foo.md
│   ├── foo.txt
│   └── main.c.1.o
├── main.c
├── src
├── waf-2.0.18
└── wscript
  • ので、wscriptにtargetを追加してやった
def options(ctx):
    ctx.load('gcc')

def configure(cnf):
    cnf.load('gcc')
    cnf.check(header_name='stdio.h', features='c cprogram')


def build(bld):
    bld(features='c cprogram', source='main.c', target='app')
  • これでlinkがちゃんとできて、buildが通った!


$ python waf-2.0.18 build
Waf: Entering directory `/programming/waf/build'
[2/2] Linking build/app
Waf: Leaving directory `/programming/waf/build'
'build' finished successfully (0.313s)


$ ./build/app
Hello, world!
  • buildディレクトリに出力されたapp実行ファイルを実行してやって, Hello, world! と表示されたら成功

Rubyの2次元配列を標準出力するときはmapを使うと見やすい

例えば下記

W, H = 3, 2

parking = Array.new(W+2){Array.new(H+2){1}}


(W+2).times{|w|
    parking[w][0] = parking[w][H+1] = 9
}

(H+2).times{|h|
    parking[0][h] = parking[W+1][h] = 9
}

p parking
#=> [[9, 9, 9, 9], [9, 1, 1, 9], [9, 1, 1, 9], [9, 1, 1, 9], [9, 9, 9, 9]]

parking.map{|x| p x}
#=>
# [9, 9, 9, 9]
# [9, 1, 1, 9]
# [9, 1, 1, 9]
# [9, 1, 1, 9]
# [9, 9, 9, 9]

mruby-simplehttpserverをさわってみた


  • まずは通例, mrubyのclone
$ git clone https://github.com/mruby/mruby.git


  • んで、cloneしたmruby内のbuild_config.rbに下記mrbgemsの行を追加
conf.gem mgem: 'mruby-simplehttpserver'


  • んで、mrubyディレクトリ内で ./minirake しておく
  • コンパイルが終わったら、試しにmatsumotoryさんのexampleコードを動かしてみる
  • mrubyを置いていると同じディレクトリで良いと思われる
$ tree -L 2
.
├── mruby
│   ├── AUTHORS
│   ├── CONTRIBUTING.md
│   ├── LEGAL
│   ├── LICENSE
│   ├── Makefile
│   ├── NEWS
│   ├── README.md
│   ├── Rakefile
│   ├── TODO
│   ├── appveyor.yml
│   ├── appveyor_config.rb
│   ├── benchmark
│   ├── bin
│   ├── build
│   ├── build_config.rb
│   ├── doc
│   ├── examples
│   ├── include
│   ├── lib
│   ├── minirake
│   ├── mrbgems
│   ├── mrblib
│   ├── mruby-source.gemspec
│   ├── oss-fuzz
│   ├── src
│   ├── tasks
│   ├── test
│   └── travis_config.rb
└── server.rb



  • ファイルをmrubyコマンド(simplehttpserverのmrbgemsをコンパイルし終わった状態のbinファイル)実行する
$ ./mruby/bin/mruby server.rb 


  • おそらくうまくいったらエラーなど表示されず実行されていると思われる
  • localhostのport8000でサーバーが立ち上がっていると思われるのでcurlで取得してみる
$ curl http://localhost:8000/mruby
Hello mruby World.


  • exampleの server.rb 通りのコードであれば、Hello mruby Worldが返ってきて成功


  • ふむ・・・
  • 次は、、、public class methodsなるものを触ってみる
new(server_ip = nil, port = nil, nonblock = nil, app = nil, debug = nil)


  • ということは
    • server_ipはprivate IP でやると一応いけるってこと?
    • いけた!
  • nonblockパラメータをtrueにすると、non-blockingになるらしい
    • non-blockingとは
    • あー、サーバーの非同期処理とかそういうこと?
    • ためしてみる
    • ためしたけど違いがわからなかった・・・
    • なるほど
    • ちなみに nil でも false でも大丈夫だった


  • ふむ・・・
  • mrubyでチャットアプリって作れるんだろうか(たぶんRubyではそういうのがある)


http2も余裕があったら

GitHub - matsumotory/mruby-http2: HTTP2 Module for mruby

RubyでC言語拡張のやりかた入門してみる

link

The Ruby C API

#

【超入門】キミにも作れる! Ruby拡張ライブラリ開発 - Qiita

class FizzBuzz
    def fizzbuzz(arg)
        arg.each do |t|
            if t % 5 ==0 && t % 3 == 0
                puts "fizzbuzz"
            elsif t % 5 == 0
                puts "fizz"
            elsif t % 3 == 0
                puts "buzz"
            else
                puts t
            end
        end
    end
end

sample = FizzBuzz.new()
sample.fizzbuzz(1..20)


  • ふむ・・・・
  • むずかしい


void
Init_nyan()
{
    /* nyanの初期化処理 */
}
  • 初期化処理はたいてい
    • クラスを定義する
    • クラスにメソッドを定義する
  • とかそういった感じになる


  • Cの世界でRubyのオブジェクトはVALUE型で表されてる


  • 下記サンプルは動いた
#include "ruby.h"


VALUE output_printnumber(VALUE self, int argc){
    int i;

    for(i=0; i < argc; ++i) {
        printf("number is %d \n", i);
    }

    return 0;
}

// entry point
void Init_printnumber(void)
{
    VALUE cPrintnumber = rb_define_class("Printnumber", rb_cObject);
    rb_define_method(cPrintnumber, "outputnumber", output_printnumber, 1);
}
  • なるほど・・・
  • なんとなくわかってきたのでいろいろ調べる
  • mkmf
  • 書いていく順番
  • 第4章 クラスとモジュール
  • まずは、エントリーポイントとなる void Init_functionName() を書いていく, 例えば
    • function名は hogehoge
    • class名は Hogehoge
// entry point
void Init_hogehoge(){
    
    /*
        VALUE型, Rubyのデータとして使用するために使う
        cHogehoge: 名前はなんでもいいが、たぶん通例として小文字のcをつけたあとに、大文字function名で定義するのがよくあるかたち?
        rb_define_class: C言語拡張してRubyにClass定義するための関数, たぶんruby.h で定義されてる
        "Hogehoge": 定義したいクラス名、クラス名なので大文字からはじまる
        rb_cObject: オブジェクトクラスの派生オブジェクトとして作る、という宣言?
    */
    VALUE cHogehoge = rb_define_class("Hogehoge", rb_cObject);

    /*
        rb_define_method: methodを定義しますよ、って宣言で中の引数に必要事項を記述していく
        第一引数 cHogehoge: これは上の VALUE cHogehoge で定義した cHogehoge のこと, この定義したHogehogeクラスのデータに対してmethodを定義しますよ、って意味?
        第二引数 "hogehoge": string型で定義する、methodの名前, なのでhogehogeとかでなくfugafugaとか好きなやつでなんでもよい、このstringがRubyにいったあと使用されるmethod名になる
        第三引数 output_hogehoge: まだ定義してないが、Cコードの中に定義する関数(データ型の処理?)の名前, つまりoutput_hogehogeというのを後ほど定義する, なので名前はその定義と合わせておけばなんでもよい
        第四引数 1: methodが取る引数の数、intで定義する?
    */
    rb_define_method(cHogehoge, "hogehoge", output_hogehoge, 1);
}


/*
    VALUE: VALUE型, CとRubyでデータの受け渡しをするのに必要となる
    output_printnumber: データ、これが拡張したい関数の中身となる
        VALUE self: 先頭に与えられる引数, おまじないみたいなものか・・・?
        int argc: int型の引数, ここはVALUE argcとかでもいいのかもしれないが、その場合はコードがちょっとかわる --> C言語の型で定義するか、Rubyの型として変換してやるかでなんかかわっていくっぽい
*/
VALUE output_hogehoge(VALUE self, int argc){

    /*
        あとは中身をC言語で記述してやればよい
        例としてfor文で1から10までをprintfする処理を記述
    */
    int i;

    for(i=0; i < argc; ++i) {
        printf("number is %d \n", i);
    }

    // C言語なので一応最後にreturn 0 が必要? 無いとエラーになる(はず)
    return 0;
}


  • あとはextconf.rbを書いて、Makefileを出して、makeしてコンパイルが正常におわれば良い
  • あれ、試しに下記Rubyスクリプトを動作させると出力が思ったのと違う結果になる
#encoding:utf-8

require './printnumber'
Printnumber.new.outputnumber(10)
#=> 0から20までが出力される, なぜか10で止まらない?


#include "ruby.h"

// 引数もそのままでも動作はするが、一応 int argcではなく VALUE argcにしてやる
VALUE output_printnumber(VALUE self, VALUE argc){
    int i;

    // NUM2INT(argc) としてやることで、VALUEをCのデータに変換してやる
    for(i=0; i < NUM2INT(argc); i++) {
        printf("number is %d \n", i);
    }

    return 0;
}

// entry point
void Init_printnumber(void)
{
    VALUE cPrintnumber = rb_define_class("Printnumber", rb_cObject);
    rb_define_method(cPrintnumber, "outputnumber", output_printnumber, 1);
}
  • ひとまずこれで動いた、このようにしてCとRubyを行き来するのにいろいろAPIやマクロなどの力を借りて構築していくみたい

rbenv installでconfigure: error: cannot run C compiled programs.が出た場合に対処

  • Rubyのインストール
  • rbenvが一番良さそう
  • homebrewは入ってる前提で行う


かいつまむと、$ rbenv install 2.6.3 した後にエラーが出て 必要そうなところをみてみると

configure: error: cannot run C compiled programs.

とでていた、Xcode Command Line Toolsあたりのエラー?なのか下記を参考にして

Can still install ruby 2.5.1 on my MacOS · Issue #1233 · rbenv/ruby-build

下記コマンドをうって、header package?をインストールしてやってからrbenv installしたらちゃんとrubyが入った

$ sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /


以下は経緯


$ brew install rbenv ruby-build

// インストール可能なrubyのバージョンを調べる
$ rbenv install -l

// 20190501時点では2.6.3が最新だったので入れてみる
$ rbenv install 2.6.3

// 下記エラーが出た


ruby-build: use openssl from homebrew
Downloading ruby-2.6.3.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.3.tar.bz2
Installing ruby-2.6.3...
ruby-build: use readline from homebrew

BUILD FAILED (OS X 10.14.4 using ruby-build 20190423)

Inspect or clean up the working tree at /var/folders/px/kk8zlmr5057cp56tp7l34l_h0000gn/T/ruby-build.20190501144337.73860
Results logged to /var/folders/px/kk8zlmr5057cp56tp7l34l_h0000gn/T/ruby-build.20190501144337.73860.log

Last 10 log lines:
checking host system type... x86_64-apple-darwin18.5.0
checking target system type... x86_64-apple-darwin18.5.0
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... configure: error: in `/var/folders/px/kk8zlmr5057cp56tp7l34l_h0000gn/T/ruby-build.20190501144337.73860/ruby-2.6.3':
configure: error: cannot run C compiled programs.
If you meant to cross compile, use `--host'.
See `config.log' for more details
make: *** No targets specified and no makefile found.  Stop.
$ sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /
  • もっかいrbenv install
  • rubyがちゃんと入ったので $ rbenv global 2.6.3 してやった