菜園状況。ニンジンの間引きをしました。根の伸びがいい気がする。

ロガー続き。GPSまわり。GPS-52モジュールからはNMEA-0183フォーマットでシ リアルに送られてくる。これをパースして必要なデータだけパックしてファイ ルに書き込みたい。まずはパース。パースは苦手だ。なんかいつも場当たり的 なコードになってしまう。
ここはマイOSだ。富豪的にファイバを使おう!ということにしたのだけど、やっ ぱりこれは自分で自分の足を撃ち抜くような機構だ。デバッグするのに脳ミソ もつれるかと思った。やれるからといってやってはいけない悪夢のようなコー ド。とはいえおもしろい.
ここでfiber_yield, fiber_return_parentは
データを見てみると受信がかなり不安定だし、受信データもバラつき大きいし (ノイズか?)今回のチャレンジは失敗に終わりそう。

ロガー続き。GPSまわり。GPS-52モジュールからはNMEA-0183フォーマットでシ リアルに送られてくる。これをパースして必要なデータだけパックしてファイ ルに書き込みたい。まずはパース。パースは苦手だ。なんかいつも場当たり的 なコードになってしまう。
ここはマイOSだ。富豪的にファイバを使おう!ということにしたのだけど、やっ ぱりこれは自分で自分の足を撃ち抜くような機構だ。デバッグするのに脳ミソ もつれるかと思った。やれるからといってやってはいけない悪夢のようなコー ド。とはいえおもしろい.
ここでfiber_yield, fiber_return_parentは
これはARM
FUNC (fiber_switch)
//
// save context. (from)
stmia r0!, {r4-r14}
// subroutine return value/1st arg
mov r0, r2
ldmia r1, {r4-r14}
mov pc, lr
これはH8
.globl _fiber_switch
_fiber_switch:
; save current context.
; no need to store caller saved and ccr.
mov.l er7, @(0x0c, er0) ; sp (contain return address)
mov.l er6, @(0x08, er0) ; callee saved
mov.l er5, @(0x04, er0) ; callee saved
mov.l er4, @(0x00, er0) ; callee saved
; load next context.
mov.l @(0x0c, er1), er7 ; sp
mov.l @(0x08, er1), er6 ; callee saved
mov.l @(0x04, er1), er5 ; callee saved
mov.l @(0x00, er1), er4 ; callee saved
mov.l er2, er0 ; subroutine return value / 1st arg.
rts
これはx86
.code32
FUNC (fiber_switch)
//
// save context. (from)
movl %esp, 0x10 (%eax)
movl %ebp, 0x0c (%eax)
movl %edi, 0x08 (%eax)
movl %esi, 0x04 (%eax)
movl %ebx, 0x00 (%eax)
// load next context (to)
movl 0x10 (%edx), %esp
movl 0x0c (%edx), %ebp
movl 0x08 (%edx), %edi
movl 0x04 (%edx), %esi
movl 0x00 (%edx), %ebx
// subroutine return value/1st arg
movl %ecx, %eax
ret
データを見てみると受信がかなり不安定だし、受信データもバラつき大きいし (ノイズか?)今回のチャレンジは失敗に終わりそう。
#include <system.h>
#include <console.h>
#include <thread.h>
#include <fiber.h>
#include <delay.h>
#include <reg.h>
#include <string.h>
#include "local.h"
#include "timer.h"
STATIC uint8_t gps_tls[THREAD_STACK_SIZE (GPS_STACK_SIZE)]
__attribute ((aligned (4)));
STATIC void gps_thread (uint32_t);
STATIC int gps_thread_ready;
#define FIFO_SIZE 64
#define GPS_FIBER_STACK_SIZE 256
rbuf_nolock_t __recv_buf;
STATIC uint8_t buf_intr[RBUF_NOLOCK_SIZE (FIFO_SIZE)];
STATIC uint8_t buf_thread[FIFO_SIZE];
volatile size_t buf_thread_read_size;
uint8_t *buf_thread_read_p = buf_thread;
thread_t gps_th;
fiber_t fiber[3];
uint8_t fls[2][FIBER_STACK_SIZE (GPS_FIBER_STACK_SIZE)];
fiber_func gps_parser;
fiber_func gps_parser_2;
__BEGIN_DECLS
void uart3_intr (void);
uint8_t gps_getc (fiber_t);
__END_DECLS
GPS用のスレッドを作成します。
thread_t
gps_init ()
{
thread_t th;
th = thread_create (gps_tls, GPS_STACK_SIZE, "gps", gps_thread, 0);
thread_start (th);
while (!gps_thread_ready)
thread_sleep (current_thread);
return th;
}
void
gps_thread (uint32_t arg __attribute__((unused)))
{
struct fiber myself;
gps_th = current_thread;
// PCLK 18.0000MHz 9615bps error 0.16%
struct uart_clock_conf uart3 = { 0, 78, 1 | (2 << 4), CCLK4 };
uart_init (UART3, &uart3, TRUE);
UART3の割り込みハンドラとスレッドコンテキストとのデータのやりとりに
リングバッファを用意します。
// Interrupt context ring-buffer.
__recv_buf = rbuf_nolock_init (buf_intr, FIFO_SIZE);
パースのためのファイバを用意します。fiber[0]はこのスレッド自分自身。
// Create parser fiber.
fiber[0] = fiber_init (&myself);
fiber[1] = fiber_create (&myself, fls[0], GPS_FIBER_STACK_SIZE, gps_parser);
fiber[2] = fiber_create (&myself, fls[1], GPS_FIBER_STACK_SIZE, gps_parser_2);
fiber_yieldした時の連結順番を設定します。
fiber_twist (&myself, 2, fiber[1], fiber[2]);
ファイバをスタートします。
fiber_start (&myself, fiber[1]);
fiber_start (&myself, fiber[2]);
// Now OK to log.
gps_thread_ready = TRUE;
thread_wakeup (shell_th);
while (/*CONSTCOND*/1)
{
thread_sleep (current_thread);
受信割り込みから起こされるので、リングバッファにある内容をコピーします。
cpu_status_t s = intr_suspend ();
buf_thread_read_size = rbuf_nolock_read (__recv_buf, buf_thread, FIFO_SIZE);
intr_resume (s);
今回読み込んだデータが処理し終わるまでファイバを廻します。
buf_thread_read_p = buf_thread;
while (buf_thread_read_size)
{
fiber_yield (&myself, 0);
}
}
// NOTREACHED
}
void
uart3_intr ()
{
uint8_t c = *URBR (UART3_BASE);
if (rbuf_nolock_write (__recv_buf, &c, 1) != 1)
{
iprintf ("UART3 overflow\n");
}
割り込みが来たら内容をリングバッファに入れて、後処理スレッドを起こしま
す。ある程度遅延をかければその遅延の間に入った割り込みのデータをバッファ
に追加して後処理スレッドで一気に処理できます。
timer_schedule_func ((void (*)(void *))thread_wakeup_once, gps_th, 100);
}
uint8_t gps_buf[64];
void FIBER_FUNC_ATTRIBUTE
gps_parser (fiber_t myself)
{
ここは親がfiber_startした時に処理されます。
fiber_return_parent (myself, 0);
ここからは次のfiber_yieldから処理されます。
// Next yield start here.
uint8_t c;
uint8_t *p = gps_buf;
while (/*CONSTCOND*/1)
{
c = gps_getc (myself);
*p++ = c;
if ((c == ',') || (c == '\r') || (c == '\n'))
{
*--p = '\0';
p = gps_buf;
区切り文字が来たら、そのバッファを次のファイバに送ります。
fiber_yield (myself, 0);
}
}
// NOTREACHED
}
uint8_t
gps_getc (fiber_t self)
{
バッファがなくなれば、そのまま親に帰ります。また親にバッファがあればこ
こから初まるので、この関数の呼び出し先は連続してバッファが供給されるよ
うに見えます。
if (buf_thread_read_size == 0)
{
この場合、予定された次のファイバではなく、親に直接戻ってデータを待ちま
す。
fiber_return_parent (self, 0);
}
assert (buf_thread_read_size);
--buf_thread_read_size;
return *buf_thread_read_p++;
}
void FIBER_FUNC_ATTRIBUTE
gps_parser_2 (fiber_t myself)
{
bool target = FALSE;
int gga_cnt = 0;
fiber_return_parent (myself, 0);
// Next yield start here.
while (/*CONSTCOND*/1)
{
このファイバにはgps_bufにトークンが用意された状態でまわってきます。
$GPGGAの、東経、北緯、受信状況、高度だけ表示してます。
if (gps_buf[0] == '$')
{
if ((target = strcmp ((const char *)gps_buf, "$GPGGA") == 0))
{
iprintf ("\n");
gga_cnt = 0;
}
}
if (target)
{
if ((gga_cnt == 2)/*latitude*/ || (gga_cnt == 4) /*longitude*/||
(gga_cnt == 6)/*valid*/ || (gga_cnt == 9)/*altitude*/)
{
iprintf ("%s ", gps_buf);
}
gga_cnt++;
}
これは親に戻ります。
fiber_yield (myself, 0);
}
// NOTREACHED
}
/*
GPGSA
GNSS DOP and Active Satellites
$GPGSA,A,3,23,20,11,13,,,,,,,,,07.3,04.2,05.9*0D
Satellites in View
$GPGSV,3,1,09,17,83,311,00,20,42,046,42,04,39,294,26,23,38,099,41*76
$GPGSV,3,2,09,13,27,143,38,28,23,203,00,11,18,092,41,32,17,043,*76
$GPGSV,3,3,09,02,09,280,00*41
Recommended Minimum Specific GNSS Data
$GPRMC,084249.695,A,3539.4058,N,13939.2779,E,0000.00,344.21,251009,,*3A
Course Over Ground and Ground Speed
$GPVTG,344.21,T,,M,0000.00,N,0000.00,K*50
Time & Date
$GPZDA,084250.695,25,10,2009,,*5A
Global Positioning System Fix Data
$GPGGA,084250.694,3539.4058,N,13939.2779,E,1,04,04.2,00039.2,M,0039.4,M,000.0,0000*49
$GPGGA,
084250.694, UTC
3539.4058,N,
13939.2779,E,
1, Quality (0: can't receive)
04, # of Satellites
04.2, HDOP
00039.2,M, altitude
0039.4,M, altitude WGS-84
000.0, Data age
0000 DPGS ID
*49 checksum
*/
