SVX日記

2004|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|05|06|07|08|09|10|11|

2014-12-24(Wed) 敢えてオーバフローしちゃうリングバッファ

  しばらく、ウチのガキが入院していてドタバタしていたので、ひさびさの更新。

  先日からXBeeをAPIモードで使うべく、ごちゃごちゃとやっていたのだが、APIモードだと不特定のタイミングでドカッとAPIデータフレームが到着してしまうので、割り込みを使ってシリアル受信しないと、取りこぼしまくってしまうことに気がついた。

  割り込みを使って受信するならば、リングバッファしかないよな、と思ったのだが、XBeeのAPIデータフレームは結構大きく、間欠動作、かつ、メモリ効率を考えると、バッファオーバフローの発生を考慮しないわけにはいかない。しかし、どのように考慮するのか? オーバフローを検知して、受信を抑制すれば、新しいフレームを取りこぼしてしまう。ならば、古いデータから捨てていくべきか? いずれにせよ、どちらかをあきらめる必要がある。

  考えた末、今回の結論は「オーバフローを考慮しない」となった。読み書きのポインタは丸めずに走らせておいて、リングバッファにアクセスする時だけ、剰余を取ってからアクセスする。まさに「オーバフローを考慮しない」だけ。判断が必要ないので動作も軽い。

  これにより、トータルで受け取るバイト数をそのままに、化けたデータや、重複して同じデータフレームを読んでしまう、という仕様となる。言い方を変えると、スタートデリミタとチェックサムの効用により、途中のデータフレームは取りこぼしてしまうが、最後に送信されたデータフレームは正しく受け取れる、という仕様となる。いいじゃん。

  というわけで、Rubyでアルゴリズムを試作してみたのが以下。

#!/usr/bin/env ruby
 
class LappedRingBuffer
 
    attr_reader :buf
 
    def initialize(size = 16)
        @size = size
        @buf = []; @size.times {
            @buf << '..'
        }
        @wp = 0; @rp = 0
    end
 
    def write(dat)
        @buf[@wp % @size] = dat
        @wp += 1
    end
 
    def read
        if(@rp != @wp)
            r = @buf[@rp % @size]
            @rp += 1
        end
        r
    end
end
 
buf = LappedRingBuffer.new(16)
p buf.buf
 
frame = 'A'; 4.times {
    (0...10).each {|d|                          # write n frames
        buf.write('%s%d' % [frame, d])
    }
    frame.next!
}
p buf.buf
 
dat = []; while(d = buf.read)
    dat << d
end
p dat

  実行結果は以下。最後のDフレームだけは、重複するものの、正しく読み出せることになる。用途にもよるが、これは明らかに利点だろう。

["..", "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", ".."]
["D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "C4", "C5", "C6", "C7", "C8", "C9", "D0", "D1"]
["D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "C4", "C5", "C6", "C7", "C8", "C9", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "C4", "C5", "C6", "C7", "C8", "C9", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9"]

  ちゅーわけで、工作再開、である。


2014-12-27(Sat) ラジコン始めました

  誕生日の11月末にランチアのラジコンをゲットしたのだが、その後、入院して死にかけていたので、今日が初めてのラジコン遊び。

  画像の説明

  しかし、ちょっと走ったら、モータが息をつくように……どうも、電池切れらしい。こんなに早いもんなのね。また明日。