2016年12月31日土曜日

2016年を振り返って

早いもので、2016年から2017年に突入しようとしている

いろいろなことがあった。

まずは「Amis!
これは、温湿度・デジタル入力変化をトリガーにメール通知(今はSlackに移行)するもの。
DD-Wrt化したBuffaloルーターに
・ARMクロスコンパイル環境の構築
・USB内臓PICの接続
・Node.jsを使ったメール通知
・iModelaにて基板切削
を行った。

次に「FON2405E拡張(シリアル通信)
まだ実験段階だけど。
・下準備のためにラズベリー・パイのカーネルコンパイルやGPIO操作、ドライバ作成
・RalinkSDKを使用して上記を移植
・OpenWrtのtftpboot
を行った。
OpenWrtを入れるためにSPIFlashの載せ替えをするところで、年末を迎えてしまっていた。

その他
・Electronを使う機会もあり、簡易的なGUI環境を作れるようになった。
 なんとなくJSを使う機会が増えたね。
・git(gogs)をいろいろ使い始めた
・親友が地元に戻り、実家を継いだ。 そして、結婚した。
・投資は目標クリア! 来年も頑張ろう
上半期は仕事が落ち着いていたので、安定的に時間をとれた気がする。
下半期は、忙しくて、なかなか時間が取れなかったかな。
でも、なんとか時間を確保して少しずつ前進できたと思う。

来年も引き続き家庭も仕事も充実するといいな。
ブログ的には
・目標探し
・楽しい教育
・投資を戦略的に行う
・「巨人の肩に乗る」
・「ググるよりもググられたい」
かな。

ちなみに年初の目標は
 ・Electon(NW.jsもか)を使った開発   → ×
 ・PICマイコンを使った開発をもっと行う → ○
・投資も頑張る             → ◎
といった感じ。

2016年12月25日日曜日

ラズベリー・パイでSST26VF032の読み書き

11月の末頃にFONのフラッシュ容量拡張のために
SST26VF032Bを入手した。 
microchipのオンラインストアから注文できるし、3日程度で到着した気がする。
しかし、そのまま交換してもフラッシュに書き込みができなかった。Orz

注意
 SST26VF032はSPIモードでの書き込みに対応していないので、「B」有りが必要。
http://www.microchip.co.jp/support/faq_sst-fm.html
このあたりをあまり気にせずに購入していた。危なかった。。。

基礎知識
をあまり持っていなかったので、他の型番の日本語のデータシートなどを読んで雰囲気を学習
http://www.onsemi.jp/pub_link/Collateral/ENA2097JP-D.PDF
http://japan.xilinx.com/xcell/xl55/jp55xcell_13.pdf


そしてSST26VF032Bについて
・データシート
http://ww1.microchip.com/downloads/jp/DeviceDoc/jp566514.pdf
 ・サンプルプログラム
http://www.microchip.com/wwwproducts/jp/SST26VF032B
 →末尾のソフトウェア

初期化
Quad I/Oとか特殊なものを使わないのであれば、初期化すべき項目は少ないと思う。
01H WRSRでIOCとWPENの設定くらい
JEDEC-IDを読んで対象のデバイスかどうかを確認しておく

読み込み方法
03H Readですんなりと読み出すことができる

書き込み方法
一番手こずった
PinのWriteProtectや06H WREN、そしてBlockProtectなんてものもあるOrz
最後のBlockProtectを失念していたために半月くらい悩んだ。
前述のサンプルプログラムを最初から見ておけばよかった。
こんな流れ
1.06H WREN WriteEnable
2.42H WBPR BlockProtection解除
3.02H PP PageProgram
4.05H RDSR BUSYチェック

こんな感じ。


2016年12月8日木曜日

FON2405E カスタムファーム用のドライバ開発

前回、準備としてなんちゃってドライバを作成して、insmodするところまでいけた。
次は自力シリアル通信ドライバを作成(ラズベリー・パイ用に作った奴の移植)をしてみる。



1.概要
ドライバ名はMy2nd(まだ名称が決まってないOrz)コードは末尾に記載。
Makefileは前回からドライバ名のみ変更した。


2.導入
nfsマウント
mount -o nolock 10.10.10.3:/var/lib/tftpboot /mnt
insmodしてみる

メッセージのメジャー番号が253 マイナー番号が0が重要で、コレがないと/dev/●●が作成できない。
カーネルのバージョンがアレなので、手動でスペシャルファイル?を作成する必要がある。
mknod /dev/My2nd0 c 253 0
とするとMy2nd0というデバイスファイルが作成できる。

3.テスト
 作成したMy2nd0に対してechoで文字列を送ってみる。
 echo -n HelloWorld!! > /dev/My2nd0

するとPIC側のコンソールに表示される。

やったーうまくいった!

4.コード
こんな感じ


#ifndef __MY2ND_KM_H__
#define __MY2ND_KM_H__
#include <asm/rt2880/rt_mmap.h>
/*
* Address of RALINK_ Registers
*/
#define RALINK_PRGIO_ADDR RALINK_PIO_BASE // Programmable I/O
#define RALINK_REG_PIODATA (RALINK_PRGIO_ADDR + 0x20)
#define RALINK_REG_PIODIR (RALINK_PRGIO_ADDR + 0x24)
#define RALINK_REG_PIOSET (RALINK_PRGIO_ADDR + 0x2C)
#define RALINK_REG_PIORESET (RALINK_PRGIO_ADDR + 0x30)
#define RALINK_GPIO(x) (1 << x)
#endif
view raw my2nd.h hosted with ❤ by GitHub
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/timer.h>
#include "my2nd.h"
MODULE_AUTHOR("Adeno");
MODULE_LICENSE("Dual BSD/GPL");
#define MYSFR9_VERSION "0.4"
#define MYSFR9_NUM_DEVS 1 /* このドライバが制御するデバイスの数 */
#define MYSFR9_DEVNAME "My2nd" /* このデバイスドライバの名称 */
#define MYSFR9_MAJOR 0 /* メジャー番号だが自動設定なので0 */
#define MYSFR9_MINOR 0 /* マイナー番号のベース番号 */
#define GPIONO_CLKOUT 11 //LAN-LED output
#define GPIONO_DATAOUT 12 //NET-LED output rev
#define GPIONO_DATAIN 14 //WPS-LED input
#define UDELAY 50 //us
#define CHARDELAY 592 //us
#define RCVPOLL 10000 //us
#define DEFAULT_RCV_QUEUE_SIZE 8 //SFR ->
#define DEFAULT_SND_QUEUE_SIZE 8 // -> SFR
static int _mysfr9_major = MYSFR9_MAJOR;
static int _mysfr9_minor = MYSFR9_MINOR;
static struct cdev *mysfr9_cdev_array = NULL;
static struct class *mysfr9_class = NULL;
static struct timer_list poll_timer;
//RCV関係 SFR ->
static int rcv_queue_size = DEFAULT_RCV_QUEUE_SIZE;
static unsigned char ircv,rcv;
static unsigned char *rcv_queue = NULL;
static int rq_head, rq_tail;
//SND関係 -> SFR
static int snd_queue_size = DEFAULT_SND_QUEUE_SIZE;
static unsigned char isnd,snd;
static unsigned char *snd_queue = NULL;
static int sq_head, sq_tail;
/*プロトタイプ宣言*/
//GPIO関係
static void mysfr9_gpio_setup(void);
static int mysfr9_gpio_getpin(int pin);
static void mysfr9_gpio_setpin(int pin,uint32_t val);
static void gpio_put_msb(unsigned char isend ,unsigned char send, unsigned char *ircv,unsigned char *rcv);
//カーネルへの登録関係
static int mysfr9_register_dev(void);
//デバイスに対する処理
static int mysfr9_open(struct inode *inode, struct file *filep);
static int mysfr9_release(struct inode *inode, struct file *filep);
static ssize_t mysfr9_write(struct file *filep,const char __user *buf, size_t count, loff_t *f_pos);
static ssize_t mysfr9_read(struct file *filep,char __user *buf,size_t count, loff_t *f_pos);
//File Operations構造体
struct file_operations mysfr9_fops = {
.open = mysfr9_open,
.release = mysfr9_release,
.write = mysfr9_write,
.read = mysfr9_read,
};
//タイマー関係
static void register_poll_timer(void);
static void poll_timer_handler(unsigned long data);
//QUEUE関係
static int ArrayEnqueue(unsigned char *queue, int data, int *head, int *tail, size_t n);
static unsigned char ArrayDequeue(unsigned char *queue, int *head, int *tail, size_t n);
//Sleep
static DECLARE_WAIT_QUEUE_HEAD(wq);
static int wq_flg = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////
//デバイスドライバがロードされた時の処理
static int mysfr9_init(void)
{
int retval,i;
/* 開始のメッセージ */
printk(KERN_INFO "%s Ver.%s loading...\n", MYSFR9_DEVNAME,MYSFR9_VERSION );
/* queue */
sq_head=0, sq_tail=0;
rq_head=0, rq_tail=0;
if(!(rcv_queue_size > 0 && rcv_queue_size < 65536)){
rcv_queue_size = DEFAULT_RCV_QUEUE_SIZE;
}
rcv_queue = kmalloc(rcv_queue_size, GFP_KERNEL);
if (!rcv_queue) return -ENOMEM;
if(!(snd_queue_size > 0 && snd_queue_size < 65536)){
snd_queue_size = DEFAULT_SND_QUEUE_SIZE;
}
snd_queue = kmalloc(rcv_queue_size, GFP_KERNEL);
if (!snd_queue) return -ENOMEM;
/* デバイスドライバをカーネルに登録 */
retval = mysfr9_register_dev();
if( retval != 0 ) {
printk( KERN_ALERT "[%s] driver register failed.\n",MYSFR9_DEVNAME);
return retval;
}
printk( KERN_INFO "[%s] driver register sccessed.\n",MYSFR9_DEVNAME);
/* GPIO初期化 */
mysfr9_gpio_setup();
//for(i=0;i<10;i++){
isnd=1; snd='I';
ircv=0; rcv=0;
gpio_put_msb(isnd,snd,&ircv,&rcv);
//}
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//デバイスドライバがアンロードされた時の処理
static void mysfr9_exit(void)
{
int i;
dev_t devno;
del_timer_sync(&poll_timer);
/* キャラクタデバイスの登録解除 */
for( i = 0; i < MYSFR9_NUM_DEVS; i++ ) {
cdev_del(&(mysfr9_cdev_array[i]));
devno = MKDEV(_mysfr9_major, _mysfr9_minor+i);
device_destroy(mysfr9_class, devno);
}
/* メジャー番号/マイナー番号を取り除く */
devno = MKDEV(_mysfr9_major,_mysfr9_minor);
unregister_chrdev_region(devno, MYSFR9_NUM_DEVS);
/* デバイスノードを取り除く */
class_destroy(mysfr9_class);
kfree(mysfr9_cdev_array);
/* queue */
kfree(rcv_queue);
kfree(snd_queue);
printk( KERN_INFO "[%s] driver unregister sccessed.\n",MYSFR9_DEVNAME);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//デバイスに対する処理
static int mysfr9_open(struct inode *inode, struct file *filep)
{
printk(KERN_INFO "[%s] Device open sccessed.\n",MYSFR9_DEVNAME);
printk( KERN_INFO "[%s] FON HZ = %d\n",MYSFR9_DEVNAME,HZ);
register_poll_timer();
return 0;
}
static int mysfr9_release(struct inode *inode, struct file *filep)
{
//まだSFRに送信できていないないものがあるので、待ってみる
while ( sq_tail - sq_head ) {
//udelay(UDELAY);
msleep(1);
}
del_timer_sync(&poll_timer);
printk(KERN_INFO "[%s] Device release sccessed.\n",MYSFR9_DEVNAME);
return 0;
}
static ssize_t mysfr9_write(struct file *filep,const char __user *buf, size_t count, loff_t *f_pos)
{
unsigned char c;
if(count > 0) {
if(copy_from_user( &c, buf, sizeof(char) )) {
return -EFAULT;
}
while(ArrayEnqueue(snd_queue, c, &sq_head, &sq_tail, snd_queue_size) == 0){
//udelay(UDELAY);
msleep(1);
}
return sizeof(char);
}
return 0;
}
static ssize_t mysfr9_read(struct file *filep,char __user *buf,size_t count, loff_t *f_pos){
unsigned char c;
//printk( KERN_INFO "RCV READ cont=%d, RCVQ=%d\n",count,(rq_tail - rq_head));
if(count > 0) {
if((rq_tail - rq_head) == 0){
printk( KERN_INFO "[%s] <read> Process %i (%s) going to sleep.\n",
MYSFR9_DEVNAME,current->pid,current->comm);
wait_event_interruptible(wq,wq_flg != 0);
wq_flg = 0;
printk( KERN_INFO "[%s] <read> Awoken Process %i (%s).\n",
MYSFR9_DEVNAME,current->pid,current->comm);
}
c = ArrayDequeue(rcv_queue, &rq_head, &rq_tail, rcv_queue_size);
if(copy_to_user( buf,&c, sizeof(char) )) {
return -EFAULT;
}
return sizeof(char);
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//カーネルへの登録
static int mysfr9_register_dev(void)
{
int retval;
dev_t dev;
size_t size;
int i;
/* 空いているメジャー番号を使ってメジャー&
マイナー番号をカーネルに登録する */
retval = alloc_chrdev_region(
&dev, /* 結果を格納するdev_t構造体 */
MYSFR9_MAJOR, /* ベースマイナー番号 */
MYSFR9_NUM_DEVS, /* デバイスの数 */
MYSFR9_DEVNAME /* デバイスドライバの名前 */
);
if( retval < 0 ) {
printk(KERN_ERR "[%s] alloc_chrdev_region failed.\n",MYSFR9_DEVNAME);
return retval;
}
_mysfr9_major = MAJOR(dev);
//printk(KERN_INFO "[%s] alloc_chrdev_region sccessed.\n",MYSFR9_DEVNAME);
/* デバイスクラスを作成する */
mysfr9_class = class_create(THIS_MODULE,MYSFR9_DEVNAME);
if(IS_ERR(mysfr9_class))
return PTR_ERR(mysfr9_class);
/* cdev構造体の用意 */
size = sizeof(struct cdev) * MYSFR9_NUM_DEVS;
mysfr9_cdev_array = (struct cdev*)kmalloc(size, GFP_KERNEL);
/* デバイスの数だけキャラクタデバイスを登録する */
/* ただしデバイスは1個しかない */
for( i = 0; i < MYSFR9_NUM_DEVS; i++ ) {
dev_t devno = MKDEV(_mysfr9_major, _mysfr9_minor+i);
/* キャラクタデバイスとしてこのモジュールをカーネルに登録する */
cdev_init(&(mysfr9_cdev_array[i]), &mysfr9_fops);
mysfr9_cdev_array[i].owner = THIS_MODULE;
if( cdev_add( &(mysfr9_cdev_array[i]), devno, 1) < 0 ) {
/* 登録に失敗した */
printk(KERN_ERR "[%s] cdev_add failed minor = %d\n",MYSFR9_DEVNAME, _mysfr9_minor+i );
}
else {
printk(KERN_INFO "[%s] cdev_add major = %d minor = %d.\n",MYSFR9_DEVNAME,_mysfr9_major,_mysfr9_minor+i);
/* デバイスノードの作成 */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
device_create(
mysfr9_class,
NULL,
devno,
NULL,
MYSFR9_DEVNAME"%u",_mysfr9_minor+i
);
#else
device_create(
mysfr9_class,
NULL,
devno,
MYSFR9_DEVNAME"%u",_mysfr9_minor+i
);
#endif
}
}
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
//GPIO関係
static void mysfr9_gpio_setup(void)
{
//入出力の設定
//RALINK_GPIO_SET_DIR: Bit 1 means output
//GPIONO_CLKOUT
//GPIONO_DATAOUT
//GPIONO_DATAIN
unsigned long tmp;
tmp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIODIR));
tmp |= cpu_to_le32(RALINK_GPIO(GPIONO_CLKOUT));
tmp |= cpu_to_le32(RALINK_GPIO(GPIONO_DATAOUT));
tmp &= ~cpu_to_le32(RALINK_GPIO(GPIONO_DATAIN));
*(volatile u32 *)(RALINK_REG_PIODIR) = tmp;
printk(KERN_INFO "[%s] Setup GPIO ...%ld\n", MYSFR9_DEVNAME,tmp);
//CLKとDATAOUT
mysfr9_gpio_setpin((volatile u32)GPIONO_CLKOUT,1);
udelay(1); //debug用 200ns程度しか無いから
mysfr9_gpio_setpin((volatile u32)GPIONO_DATAOUT,0);
}
static int mysfr9_gpio_getpin(int pin){
volatile unsigned long arg,tmp;
arg = RALINK_GPIO(pin);
tmp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIODATA));
tmp &= RALINK_GPIO(pin);
return (tmp > 0 ? 1 : 0);
}
static void mysfr9_gpio_setpin(int pin,uint32_t val){
unsigned long arg;
arg = RALINK_GPIO(pin);
if(val > 0)
*(volatile u32 *)(RALINK_REG_PIOSET) = cpu_to_le32(arg);
else
*(volatile u32 *)(RALINK_REG_PIORESET) = cpu_to_le32(arg);
}
static void gpio_put_msb(unsigned char isend ,unsigned char send, unsigned char *ircv,unsigned char *rcv)
{
volatile int i=0;
volatile unsigned char _rcv = 0;
volatile unsigned char _send = send;
unsigned int _ircv = 0;
unsigned int rcvbit=0;
//D0 データ有無ビット
//--DATA
mysfr9_gpio_setpin((volatile u32)GPIONO_DATAOUT,isend);
udelay(1); //debug用 200ns程度しか無いから
//--CLK=H
mysfr9_gpio_setpin((volatile u32)GPIONO_CLKOUT,0);
udelay(UDELAY);
//--データ有無ビット入力
_ircv = mysfr9_gpio_getpin((volatile u32)GPIONO_DATAIN);
//--CLK=L
mysfr9_gpio_setpin((volatile u32)GPIONO_CLKOUT,1);
udelay(UDELAY);
//printf("データ有無\t送信:%d(%c)\t受信:%d(%c)\n",isend,((isend>0) ? 'X':'-'),_ircv,((_ircv>0) ? 'X':'-'));
for(i=0;i<8;i++){
//D1-9 データビット
//--データ出力
//printf("i=%d,v=%#x,v2=%d\n",i,v,((v & 0x80) == 0x80 ? 1 : 0));
//printf("%d",((v & 0x80) == 0x80 ? 1 : 0));
if((_send & 0x80) == 0x80){
mysfr9_gpio_setpin((volatile u32)GPIONO_DATAOUT,1);
}else{
mysfr9_gpio_setpin((volatile u32)GPIONO_DATAOUT,0);
}
udelay(1); //debug用 200ns程度しか無いから
//--CLK=H
mysfr9_gpio_setpin((volatile u32)GPIONO_CLKOUT,0);
udelay(UDELAY);
//--データ入力
_rcv = _rcv << 1 ;
rcvbit = mysfr9_gpio_getpin((volatile u32)GPIONO_DATAIN);
if(rcvbit > 0){
_rcv = _rcv | 0x01;
}
_send=_send<<1;
//--CLK=L
mysfr9_gpio_setpin((volatile u32)GPIONO_CLKOUT,1);
udelay(UDELAY);
}
*ircv = _ircv;
*rcv = _rcv;
//printf("----------------------------------------------------------------------------------------------------\n");
/*printk(KERN_INFO "### Send:%c = %c(%#x) Rcv:%c = %c(%#x) \n",
((isend>0) ? 'O':'X'),((isend>0) ? send:' '),((isend>0) ? send:0x00),
((_ircv>0) ? 'O':'X'),((_ircv>0) ? _rcv:' '),((_ircv>0) ? _rcv:0x00));*/
udelay(CHARDELAY);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//タイマー処理関係
static void register_poll_timer(void)
{
init_timer(&poll_timer);
//poll_timer.expires = jiffies + HZ;
poll_timer.expires = jiffies + (HZ * RCVPOLL) / 1000000;
/* 最短のTickより短い場合は最短のTickに */
if( poll_timer.expires == 0 ) poll_timer.expires = jiffies + 1;
poll_timer.data = jiffies;
poll_timer.function = poll_timer_handler;
add_timer(&poll_timer);
}
static void poll_timer_handler(unsigned long data)
{
do{
if(sq_tail - sq_head){
isnd = 1;
snd = ArrayDequeue(snd_queue, &sq_head, &sq_tail, snd_queue_size);
}else{
isnd = 0;
}
gpio_put_msb(isnd,snd,&ircv,&rcv);
if(ircv > 0){
//printk( KERN_INFO "RCV %c \n",rcv);
if(ArrayEnqueue(rcv_queue, rcv, &rq_head, &rq_tail, rcv_queue_size) > 0){
wq_flg = 1;
wake_up_interruptible(&wq);
}else{
printk( KERN_ALERT "[%s] RCV Buffer Full.\n",MYSFR9_DEVNAME);
}
}
}while ((sq_tail - sq_head) || (ircv > 0));
register_poll_timer();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//Queue
static int ArrayEnqueue(unsigned char *queue, int data, int *head, int *tail, size_t n) {
if (*head % n != (*tail + 1) % n) {
queue[(*tail)++ % n] = data;
return *tail - *head;
} else {
return 0;
}
}
static unsigned char ArrayDequeue(unsigned char *queue, int *head, int *tail, size_t n) {
if (*head != *tail) {
return queue[(*head)++ % n];
} else {
return (unsigned char)0;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//initの登録
module_init(mysfr9_init);
//exitの登録
module_exit(mysfr9_exit);
view raw my2nd.c hosted with ❤ by GitHub

2016年11月28日月曜日

FON2405Eのフラッシュメモリを交換→失敗

魔が差して、フラッシュメモリの交換をしてしまった。
MX25L8006EからSST26VF032へ。

しかし、書き込みで失敗してしまう。。。
Unlocking Kernel ...
Writing from /var/cgi9yh6g9 to Kernel ... [w]Post-Write check failed.

やっぱりよく調べてからじゃないといけないね。
せめて同じメーカーとかにしておけばよかった。
酩酊買いしたので、あと20個近くある!

不良在庫にしないためにも何とか解決したいものだ。
とりあえず、ロジアナ使って、SPIモードでJEDEC-ID は読めた。
さてこれからどうしようか・・。

2016年11月16日水曜日

FON2405E カスタムファーム用のドライバ開発(準備)

FON2405EのGPIOを使ってシリアル通信をさせるため、いろいろ回り道をしながら挑戦を続けてきた。
今回は、RalinkSDKで作った FON2405E用カスタムファームに向けたドライバ開発について。

1.カスタムファームの変更

まずは、カーネルコンフィングの変更
[make menuconfig]で、[Loadable module support]以降を適当に有効化しておく
Enable loadable module supportとか。
これを忘れていて、make時にprintkとかが定義されていないと怒られた。ハマった。
http://stackoverflow.com/questions/31195516/error-building-android-kernel-module-on-ubuntu-14-04

その他に、insmodとかlsmodとか必要に応じで、有効にしておく。

ファームができたら、FONに入れておく。

2.テスト用ドライバの作成

とりあえず、準備なので何でも良い。やっつけコードを、末尾に記載。

3.Makefileの準備

 ここがいろいろ試行錯誤した。
HOME:= /home/adeno/fongpio/sdk3301/RT288x_SDK
ARCH := mips
CROSS_COMPILE := /opt/buildroot-gcc342/bin/mipsel-linux-
KPATH := $(HOME)/source/linux-2.6.21.x
obj-m += my1st.o
all:
make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KPATH) M=$(PWD) modules
clean:
make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KPATH) M=$(PWD) clean
view raw Makefile hosted with ❤ by GitHub

4.いざ、Make


一撃! うれしい!! 未使用変数の注意が出ているけど、知っているやつなので、放置。

これで、my1st.koができた。

5.NFSマウント

SDKのマニュアルどおり。
mount -o nolock 10.10.10.3:/var/lib/tftpboot /mnt
でOK

6.insmodしてみる

作成したmy1st.koをinsmodすると・・・。


よかったーーー。 ちゃんとprintkも動いている。
あきらめずに続けてよかった。
ラズベリー・パイで下準備しておいて本当によかった。

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/timer.h>
MODULE_AUTHOR("Adeno");
MODULE_LICENSE("Dual BSD/GPL");
#define MYSFR9_VERSION "0.1"
#define MYSFR9_NUM_DEVS 1 /* このドライバが制御するデバイスの数 */
#define MYSFR9_DEVNAME "My1st" /* このデバイスドライバの名称 */
#define MYSFR9_MAJOR 0 /* メジャー番号だが自動設定なので0 */
#define MYSFR9_MINOR 0 /* マイナー番号のベース番号 */
static int _mysfr9_major = MYSFR9_MAJOR;
static int _mysfr9_minor = MYSFR9_MINOR;
static struct cdev *mysfr9_cdev_array = NULL;
static struct class *mysfr9_class = NULL;
/*プロトタイプ宣言*/
//カーネルへの登録関係
//デバイスに対する処理
static int mysfr9_open(struct inode *inode, struct file *filep);
static int mysfr9_release(struct inode *inode, struct file *filep);
static ssize_t mysfr9_write(struct file *filep,const char __user *buf, size_t count, loff_t *f_pos);
static ssize_t mysfr9_read(struct file *filep,char __user *buf,size_t count, loff_t *f_pos);
//File Operations構造体
struct file_operations mysfr9_fops = {
.open = mysfr9_open,
.release = mysfr9_release,
.write = mysfr9_write,
.read = mysfr9_read,
};
///////////////////////////////////////////////////////////////////////////////////////////////////
//デバイスドライバがロードされた時の処理
static int mysfr9_init(void)
{
/* 開始のメッセージ */
printk(KERN_INFO "%s Ver.%s loading...\n", MYSFR9_DEVNAME,MYSFR9_VERSION );
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//デバイスドライバがアンロードされた時の処理
static void mysfr9_exit(void)
{
printk( KERN_INFO "[%s] driver unregister sccessed.\n",MYSFR9_DEVNAME);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//デバイスに対する処理
static int mysfr9_open(struct inode *inode, struct file *filep)
{
printk(KERN_INFO "[%s] Device open sccessed.\n",MYSFR9_DEVNAME);
return 0;
}
static int mysfr9_release(struct inode *inode, struct file *filep)
{
printk(KERN_INFO "[%s] Device release sccessed.\n",MYSFR9_DEVNAME);
return 0;
}
static ssize_t mysfr9_write(struct file *filep,const char __user *buf, size_t count, loff_t *f_pos)
{
return 0;
}
static ssize_t mysfr9_read(struct file *filep,char __user *buf,size_t count, loff_t *f_pos){
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//initの登録
module_init(mysfr9_init);
//exitの登録
module_exit(mysfr9_exit);
view raw my1st.c hosted with ❤ by GitHub

2016年11月14日月曜日

FON2405EにOpenwrt導入の挑戦

約2年ほど前、FON2405Eにカスタムファーム導入に挑戦した。
http://continue-to-challenge.blogspot.jp/2015/01/fon2405e.html

その時は、Openwrtはサイズが2MB以上になってしまい、
結局 RalinkSDK的なものを使ったカスタムファームを導入することにした。
http://continue-to-challenge.blogspot.jp/2015/01/fon2405e_24.html
http://continue-to-challenge.blogspot.jp/2015/01/fon2405e_27.html

でも、最近になって、FONのGPIOでシリアル通信をやらせたいと考えるなかで、
SDKのバージョンも古いし、FONのフラッシュ2MBしか無いのが不満に思えてきた。

いまさらだけど、フラッシュメモリを載せ替えたら幸せになれるんじゃないかと思えてきた。すでにやっている方もいるみたいだし。
https://awaitingstock.wordpress.com/2013/01/11/fon2405efonara-simpl-flsah%E8%BC%89%E3%81%9B%E6%9B%BF%E3%81%88/

そのための準備として、最新のOpenwrtはFON2405E でも動くのか?というのを確認した。


手順1 Openwrtのカーネルソース入手

基本的には、以下の手順だけど、 別にtrunkじゃなくて、安定版が欲しい時は、
https://wiki.openwrt.org/jp/doc/howto/buildroot.exigence
https://dev.openwrt.org/wiki/GetSource

svn co svn://svn.openwrt.org/openwrt/trunk/
git clone -b chaos_calmer git://github.com/openwrt/openwrt.git
にしたら幸せになれた。
 
 手順2 Make!

「make menuconfig」後の話
   Tartget System = Ralink RT288x/RT3xxx
  Subtarget           = RT3x5x/RT5350 based boards

ほかは必要に応じて変更
pppやusb関係が不要なら削除など。

手順3 FON2405Eにお試しインストール

先の手順で、bin/ramips/以下にバイナリイメージがたくさん作成される。
そのなかで、これを試してみる
2369793 bin/ramips/openwrt-ramips-rt305x-rt-g32-b1-initramfs-uImage.bin
なぜお試しかというと、イメージサイズが、2MB以上だからOrz
インストールできない!!

作成したイメージをTFTPサーバー上においておく、名前は適当に今回はuImage.bin。
このサーバーのIPは10.10.10.3とした(FONのU-Bootのデフォルトがそうだから) 。

FONはリセットボタンを押しながら電源ONして、U-Bootの起動オプションで3を選択!

その後、 コマンドラインから
tftpboot 80800000  uImage.bin
そして、
bootm
とすると、Openwrtが起動しました!



嬉しいけど、やっぱりインストールしたい!
フラッシュメモリを載せ替えるか!?



ラズベリー・パイのカーネルビルドとクロスコンパイル環境のメモ

時間がたつと忘れそうなので、メモ

 カーネルビルドとクロスコンパイル環境の作成
https://www.raspberrypi.org/documentation/linux/kernel/building.md

Raspiのバージョンによって手順が異なるので注意。
以下はRaspi1の場合
git clone --depth=1 https://github.com/raspberrypi/linux
cd linux
KERNEL=kernel
make bcmrpi_defconfig

2016年10月23日日曜日

ラズベリー・パイで自力シリアル通信(ドライバー編)

随分と時間がかかってしまったけど、ようやく動くものになってきた。

概要
カーネルモジュール(ドライバー?)を作成して、GPIOをパタパタさせる。
8月からやっているヤツのデバドラ版。

デバイスとして扱われるので、echoやcatで入出力ができたり、既存の通信プログラムでも使えると思う。
出力されるクロックはdelayを使っているので、安定していると思う。
データのポーリングはカーネルタイマーを使っているので、
ラズベリー・パイの場合は100Hzが(10ms)が限界。
性能評価はこれから。

cat /dev/zero > /dev/MySFR9km0

とやってみると、大体350 Char/Secくらい。意外と遅い。

PIC側の設計上は960Char/Secまで行けるのはずなのだが??


#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/timer.h>
#include "rpi_gpio.h"
MODULE_AUTHOR("Adeno");
MODULE_LICENSE("Dual BSD/GPL");
#define MYSFR9_NUM_DEVS 1 /* このドライバが制御するデバイスの数 */
#define MYSFR9_DEVNAME "MySFR9km" /* このデバイスドライバの名称 */
#define MYSFR9_MAJOR 0 /* メジャー番号だが自動設定なので0 */
#define MYSFR9_MINOR 0 /* マイナー番号のベース番号 */
#define MySFR9_GPIO_MAPNAME "mysfr9_gpio_map"
#define MYSFR_GPIO_BASE 7
#define UDELAY 50 //us
#define CHARDELAY 592 //us
#define RCVPOLL 10000 //us
#define RCV_QUEUE_SIZE 8 //SFR ->
#define SND_QUEUE_SIZE 8 // -> SFR
static int _mysfr9_major = MYSFR9_MAJOR;
static int _mysfr9_minor = MYSFR9_MINOR;
static struct cdev *mysfr9_cdev_array = NULL;
static struct class *mysfr9_class = NULL;
static void __iomem *gpio_map;
volatile uint32_t *gpio_base;
static struct timer_list poll_timer;
//RCV関係 SFR ->
static unsigned char ircv,rcv;
static unsigned char rcv_queue[RCV_QUEUE_SIZE];
static int rq_head, rq_tail;
//SND関係 -> SFR
static unsigned char isnd,snd;
static unsigned char snd_queue[SND_QUEUE_SIZE];
static int sq_head, sq_tail;
/*プロトタイプ宣言*/
//GPIOレジスタのマップ関係
static int mysfr9_gpio_map(void);
static int mysfr9_gpio_unmap(void);
static void mysfr9_gpio_setup(void);
static int rpi_gpio_function_set(int pin, uint32_t func);
static int rpi_gpio_pull_control(int pin, uint32_t pullmode);
static void rpi_gpio_set32( uint32_t mask, uint32_t val );
//static uint32_t rpi_gpio_get32( uint32_t mask );
static void rpi_gpio_clear32( uint32_t mask, uint32_t val );
static uint32_t rpi_gpio_getpin( int pin );
static void gpio_put_msb(unsigned char isend ,unsigned char send, unsigned char *ircv,unsigned char *rcv);
//カーネルへの登録関係
static int mysfr9_register_dev(void);
//デバイスに対する処理
static int mysfr9_open(struct inode *inode, struct file *filep);
static int mysfr9_release(struct inode *inode, struct file *filep);
static ssize_t mysfr9_write(struct file *filep,const char __user *buf, size_t count, loff_t *f_pos);
static ssize_t mysfr9_read(struct file *filep,char __user *buf,size_t count, loff_t *f_pos);
//File Operations構造体
struct file_operations mysfr9_fops = {
.open = mysfr9_open,
.release = mysfr9_release,
.write = mysfr9_write,
.read = mysfr9_read,
};
//タイマー関係
static void register_poll_timer(void);
static void poll_timer_handler(unsigned long data);
//QUEUE関係
static int ArrayEnqueue(unsigned char *queue, int data, int *head, int *tail, size_t n);
static unsigned char ArrayDequeue(unsigned char *queue, int *head, int *tail, size_t n);
///////////////////////////////////////////////////////////////////////////////////////////////////
//デバイスドライバがロードされた時の処理
static int mysfr9_init(void)
{
int retval;
/* 開始のメッセージ */
printk(KERN_INFO "%s loading...\n", MYSFR9_DEVNAME );
sq_head=0, sq_tail=0;
rq_head=0, rq_tail=0;
/* GPIOレジスタがマップ可能か調べる */
retval = mysfr9_gpio_map();
if( retval != 0 ) {
printk( KERN_ALERT "Can not use GPIO registers.\n");
return -EBUSY;
}
/* GPIO初期化 */
mysfr9_gpio_setup();
isnd=1; snd='I';
ircv=0; rcv=0;
gpio_put_msb(isnd,snd,&ircv,&rcv);
/* デバイスドライバをカーネルに登録 */
retval = mysfr9_register_dev();
if( retval != 0 ) {
printk( KERN_ALERT "MySFR9 driver register failed.\n");
return retval;
}
printk( KERN_INFO "MySFR9 driver register sccessed.\n");
/* GPIOレジスタのアンマップ */
mysfr9_gpio_unmap();
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//デバイスドライバがアンロードされた時の処理
static void mysfr9_exit(void)
{
int i;
dev_t devno;
del_timer_sync(&poll_timer);
/* キャラクタデバイスの登録解除 */
for( i = 0; i < MYSFR9_NUM_DEVS; i++ ) {
cdev_del(&(mysfr9_cdev_array[i]));
devno = MKDEV(_mysfr9_major, _mysfr9_minor+i);
device_destroy(mysfr9_class, devno);
}
/* メジャー番号/マイナー番号を取り除く */
devno = MKDEV(_mysfr9_major,_mysfr9_minor);
unregister_chrdev_region(devno, MYSFR9_NUM_DEVS);
/* デバイスノードを取り除く */
class_destroy( mysfr9_class );
/* GPIOレジスタのアンマップ */
mysfr9_gpio_unmap();
kfree(mysfr9_cdev_array);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//デバイスに対する処理
static int mysfr9_open(struct inode *inode, struct file *filep)
{
int retval;
if( gpio_base != NULL ) {
/* すでにオープンされている */
printk(KERN_ERR "MySFR9 is already open.\n" );
return -EIO;
}
retval = mysfr9_gpio_map();
if( retval != 0 ) {
printk(KERN_ERR "Can not open MySFR9.\n" );
return retval;
}
printk( KERN_INFO "RPI HZ = %d\n", HZ );
register_poll_timer();
return 0;
}
static int mysfr9_release(struct inode *inode, struct file *filep)
{
//まだSFRに送信できていないないものがあるので、待ってみる
while ( sq_tail - sq_head ) {
udelay(UDELAY);
}
del_timer_sync(&poll_timer);
mysfr9_gpio_unmap();
return 0;
}
static ssize_t mysfr9_write(struct file *filep,const char __user *buf, size_t count, loff_t *f_pos)
{
//char cvalue;
//int retval;
unsigned char c;
if(count > 0) {
if(copy_from_user( &c, buf, sizeof(char) )) {
return -EFAULT;
}
while(ArrayEnqueue(snd_queue, c, &sq_head, &sq_tail, SND_QUEUE_SIZE) == 0){
//udelay(UDELAY);
msleep(1);
}
//isnd=1;
//ircv=0; rcv=0;
//gpio_put_msb(isnd,snd,&ircv,&rcv);
/*retval = ssegled_put(cvalue);
if( retval != 0 ) {
printk(KERN_ALERT "Can not display %d\n", cvalue );
}
else {
ssegled_display_value = cvalue;
}*/
return sizeof(char);
}
return 0;
}
static ssize_t mysfr9_read(struct file *filep,char __user *buf,size_t count, loff_t *f_pos){
unsigned char c;
//printk( KERN_INFO "RCV READ cont=%d, RCVQ=%d\n",count,(rq_tail - rq_head));
if(count > 0) {
while((rq_tail - rq_head) == 0){
//udelay(UDELAY);
msleep(1);
}
c = ArrayDequeue(rcv_queue, &rq_head, &rq_tail, RCV_QUEUE_SIZE);
//printk( KERN_INFO "RCV READ char=%c\n",c);
if(copy_to_user( buf,&c, sizeof(char) )) {
return -EFAULT;
}
return sizeof(char);
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//カーネルへの登録
static int mysfr9_register_dev(void)
{
int retval;
dev_t dev;
size_t size;
int i;
/* 空いているメジャー番号を使ってメジャー&
マイナー番号をカーネルに登録する */
retval = alloc_chrdev_region(
&dev, /* 結果を格納するdev_t構造体 */
MYSFR9_MAJOR, /* ベースマイナー番号 */
MYSFR9_NUM_DEVS, /* デバイスの数 */
MYSFR9_DEVNAME /* デバイスドライバの名前 */
);
if( retval < 0 ) {
printk(KERN_ERR "alloc_chrdev_region failed.\n" );
return retval;
}
_mysfr9_major = MAJOR(dev);
/* デバイスクラスを作成する */
mysfr9_class = class_create(THIS_MODULE,MYSFR9_DEVNAME);
if(IS_ERR(mysfr9_class))
return PTR_ERR(mysfr9_class);
/* cdev構造体の用意 */
size = sizeof(struct cdev) * MYSFR9_NUM_DEVS;
mysfr9_cdev_array = (struct cdev*)kmalloc(size, GFP_KERNEL);
/* デバイスの数だけキャラクタデバイスを登録する */
/* ただし7セグLEDは1個しかない */
for( i = 0; i < MYSFR9_NUM_DEVS; i++ ) {
dev_t devno = MKDEV(_mysfr9_major, _mysfr9_minor+i);
/* キャラクタデバイスとしてこのモジュールをカーネルに登録する */
cdev_init(&(mysfr9_cdev_array[i]), &mysfr9_fops);
mysfr9_cdev_array[i].owner = THIS_MODULE;
if( cdev_add( &(mysfr9_cdev_array[i]), devno, 1) < 0 ) {
/* 登録に失敗した */
printk(KERN_ERR "cdev_add failed minor = %d\n", _mysfr9_minor+i );
}
else {
/* デバイスノードの作成 */
device_create(
mysfr9_class,
NULL,
devno,
NULL,
MYSFR9_DEVNAME"%u",_mysfr9_minor+i
);
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//GPIOレジスタのマップ関係
static int mysfr9_gpio_map(void)
{
if( !request_mem_region(RPI_GPIO_BASE,
RPI_BLOCK_SIZE,
MySFR9_GPIO_MAPNAME) ) {
printk( KERN_ALERT "request_mem_region failed.\n");
//return -EBUSY;
}
gpio_map = ioremap_nocache(RPI_GPIO_BASE, BLOCK_SIZE);
gpio_base = (volatile uint32_t *)gpio_map;
return 0;
}
static int mysfr9_gpio_unmap(void)
{
iounmap(gpio_map);
release_mem_region(RPI_GPIO_BASE, RPI_BLOCK_SIZE);
gpio_map = NULL;
gpio_base = NULL;
return 0;
}
static void mysfr9_gpio_setup(void)
{
rpi_gpio_function_set(MYSFR_GPIO_BASE+0, RPI_GPF_OUTPUT);//CLK-OUT
rpi_gpio_function_set(MYSFR_GPIO_BASE+1, RPI_GPF_OUTPUT);//DATA-OUT
rpi_gpio_function_set(MYSFR_GPIO_BASE+2, RPI_GPF_INPUT);//DATA-INPUT
rpi_gpio_pull_control(MYSFR_GPIO_BASE+2,RPI_GPIO_PULLUP);
}
static int rpi_gpio_function_set(int pin, uint32_t func)
{
int index = RPI_GPFSEL0_INDEX + pin / 10;
uint32_t mask = ~(0x7 << ((pin % 10) * 3));
gpio_base[index] = (gpio_base[index] & mask) | ((func & 0x7) << ((pin % 10) * 3));
return 1;
}
static int rpi_gpio_pull_control(int pin, uint32_t pullmode)
{
gpio_base[RPI_GPPUD_INDEX] = pullmode & 0x03;
gpio_base[RPI_GPPUDCLK0_INDEX] = 0x01 << pin;
// wait > 150 cycles
udelay(100);
gpio_base[RPI_GPPUDCLK0_INDEX] = 0;
gpio_base[RPI_GPPUD_INDEX] = 0;
return 1;
}
static void rpi_gpio_set32(uint32_t mask, uint32_t val )
{
gpio_base[RPI_GPSET0_INDEX] = val & mask;
}
/*static uint32_t rpi_gpio_get32( uint32_t mask )
{
return gpio_base[RPI_GPLEV0_INDEX] & mask;
}*/
static void rpi_gpio_clear32(uint32_t mask, uint32_t val )
{
gpio_base[RPI_GPCLR0_INDEX] = val & mask;
}
static uint32_t rpi_gpio_getpin(int pin )
{
return (gpio_base[RPI_GPLEV0_INDEX] & (1 << pin)) != 0;
}
static void gpio_put_msb(unsigned char isend ,unsigned char send, unsigned char *ircv,unsigned char *rcv)
{
volatile int i=0;
volatile unsigned char _rcv = 0;
volatile unsigned char _send = send;
unsigned int _ircv = 0;
unsigned int rcvbit=0;
//D0 データ有無ビット
//--DATA
if(isend){
rpi_gpio_set32( RPI_GPIO_P1MASK, (2 & 0x0F) << MYSFR_GPIO_BASE);
}else{
rpi_gpio_clear32( RPI_GPIO_P1MASK, (2 & 0x0F) << MYSFR_GPIO_BASE);
}
//--CLK=H
rpi_gpio_set32( RPI_GPIO_P1MASK, (1 & 0x0F) << MYSFR_GPIO_BASE);
udelay(UDELAY);
//--データ有無ビット入力
_ircv = rpi_gpio_getpin(MYSFR_GPIO_BASE+2);
//--CLK=L
rpi_gpio_clear32( RPI_GPIO_P1MASK, (1 & 0x0F) << MYSFR_GPIO_BASE);
udelay(UDELAY);
//printf("データ有無\t送信:%d(%c)\t受信:%d(%c)\n",isend,((isend>0) ? 'X':'-'),_ircv,((_ircv>0) ? 'X':'-'));
for(i=0;i<8;i++){
//D1-9 データビット
//--データ出力
//printf("i=%d,v=%#x,v2=%d\n",i,v,((v & 0x80) == 0x80 ? 1 : 0));
//printf("%d",((v & 0x80) == 0x80 ? 1 : 0));
if((_send & 0x80) == 0x80){
rpi_gpio_set32( RPI_GPIO_P1MASK, (2 & 0x0F) << MYSFR_GPIO_BASE);
}else{
rpi_gpio_clear32( RPI_GPIO_P1MASK, (2 & 0x0F) << MYSFR_GPIO_BASE);
}
//--CLK=H
rpi_gpio_set32( RPI_GPIO_P1MASK, (1 & 0x0F) << MYSFR_GPIO_BASE);
udelay(UDELAY);
//--データ入力
_rcv = _rcv << 1 ;
rcvbit = rpi_gpio_getpin(MYSFR_GPIO_BASE+2);
//printf("c=%d,gpin=%d\n",c,gpin);
if(rcvbit > 0){
_rcv = _rcv | 0x01;
}
_send=_send<<1;
//--CLK=L
rpi_gpio_clear32( RPI_GPIO_P1MASK, (1 & 0x0F) << MYSFR_GPIO_BASE);
udelay(UDELAY);
}
*ircv = _ircv;
*rcv = _rcv;
//printf(" 内容\t送信:%c(%#x)\t受信:%c(%#x)\n",send,send,*rcv,*rcv);
//printf("----------------------------------------------------------------------------------------------------\n");
//printf("### 送信:%c - %c(%#x) 受信:%c - %c(%#x)\n",((isend>0) ? 'O':'X'),send,send,((_ircv>0) ? 'O':'X'),_rcv,_rcv);
udelay(CHARDELAY);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//タイマー処理関係
static void register_poll_timer(void)
{
init_timer(&poll_timer);
//poll_timer.expires = jiffies + HZ;
poll_timer.expires = jiffies + (HZ * RCVPOLL) / 1000000;
/* 最短のTickより短い場合は最短のTickに */
if( poll_timer.expires == 0 ) poll_timer.expires = jiffies + 1;
poll_timer.data = jiffies;
poll_timer.function = poll_timer_handler;
add_timer(&poll_timer);
}
static void poll_timer_handler(unsigned long data)
{
//unsigned char ircv,rcv;
//unsigned char isnd,snd;
do{
if(sq_tail - sq_head){
isnd = 1;
snd = ArrayDequeue(snd_queue, &sq_head, &sq_tail, SND_QUEUE_SIZE);
}else{
isnd = 0;
}
gpio_put_msb(isnd,snd,&ircv,&rcv);
if(ircv > 0){
//printk( KERN_INFO "RCV %c \n",rcv);
if(ArrayEnqueue(rcv_queue, rcv, &rq_head, &rq_tail, RCV_QUEUE_SIZE) > 0){
}else{
printk( KERN_ALERT "RCV Buffer Full.\n");
}
}
}while ((sq_tail - sq_head) || (ircv > 0));
/*while ((q_tail - q_head) || (ircv > 0)) {
if(q_tail - q_head){
isnd = 1;
snd = ArrayDequeue(queue, &q_head, &q_tail, QUEUE_SIZE);
}else{
isnd = 0;
}
gpio_put_msb(isnd,snd,&ircv,&rcv);
isnd = 0;
}*/
//isnd=1; snd='P';
//ircv=0; rcv=0;
//gpio_put_msb(isnd,snd,&ircv,&rcv);
//isnd=0;
register_poll_timer();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//Queue
static int ArrayEnqueue(unsigned char *queue, int data, int *head, int *tail, size_t n) {
if (*head % n != (*tail + 1) % n) {
queue[(*tail)++ % n] = data;
return *tail - *head;
} else {
return 0;
}
}
static unsigned char ArrayDequeue(unsigned char *queue, int *head, int *tail, size_t n) {
if (*head != *tail) {
return queue[(*head)++ % n];
} else {
return (unsigned char)0;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//initの登録
module_init(mysfr9_init);
//exitの登録
module_exit(mysfr9_exit);
view raw mysfr9km.c hosted with ❤ by GitHub

メモ
request_mem_regionが毎回失敗するのはなぜだろう
早速Amisでも移植してみるか?

2016年9月21日水曜日

PHPからslackに投稿する(WebPI)

最近ますます流行ってきているSlackを導入してみて2日経過した。
PHPからPOSTで投稿してみた。
rsyslogと連携して、sshdのログイン/ログアウトを通知するようにしてみた。


#attachmentsの入れ方がわからなくて、ものすごく苦労したOrz

<?php
echo "sndmsg_slack.php run...".PHP_EOL;
$slackApiKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
$url = "https://slack.com/api/chat.postMessage";
$argchk = false;
if(count($argv) == 4){
if($argv[1]=="GET"){
$argchk = true;
/// GET ///////////////////////////////////////////////////////////
$query = [ 'token' => $slackApiKey,
'channel' => '#'.$argv[2],
'text' => str_replace("\\n",PHP_EOL,$argv[3]),
'as_user' => 'true'
];
echo "[GET]URL=".$url.http_build_query($query).PHP_EOL;
$result = file_get_contents($url."?".http_build_query($query));
echo $result.PHP_EOL;
///////////////////////////////////////////////////////////////////
}
}
if(count($argv) == 7){
if($argv[1]=="POST"){
$argchk = true;
/// PST ///////////////////////////////////////////////////////////
$attachment = ['pretext' => $argv[3],
'color' => $argv[4],
'title' => $argv[5],
'text' => $argv[6]];
$query = [ 'token' => $slackApiKey,
'channel' => '#'.$argv[2],
'attachments' => json_encode(Array($attachment)),
'as_user' => 'true'
];
$options = array(
'http' => array(
'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($query)
)
);
$context = stream_context_create($options);
echo "[POST]QUERY=".json_encode($query).PHP_EOL;
$result = file_get_contents($url, false, $context);
echo $result.PHP_EOL;
}
// $result = json_decode($result);
// $obj = json_decode(json_encode($query));
// var_dump($obj);
}
if(!$argchk){
echo "[mode] [channel] [text]".PHP_EOL;
echo "\tmode\tGET or POST".PHP_EOL;
echo "GET [channel] [message]".PHP_EOL;
echo "POST [channel] [pretext] [color] [title] [text]".PHP_EOL;
}
?>
view raw sndmsg_.php hosted with ❤ by GitHub

2016年9月20日火曜日

Slackインストール

〇〇botとか作ってみたくて、でもLineは私用なので、分けてみたいと思っていたら、slackというものを発見した。

これなら今までメール通知でやっていたものを置き換えできそう!!

メール通知
http://webos-goodies.jp/archives/50645131.html


<参考>
http://toach.click/slack-botkit/
http://lab.aratana.jp/entry/2014/12/04/185053
http://tech.machiiro.jp/entry/2016/05/13/090000
https://elstreet.style/?p=1124
https://elstreet.style/?p=1099

2016年9月3日土曜日

MPLABXをLINUXで使ったら文字化け

バージョンアップの度にはまるので、備忘録として

日本語が表示できるいい感じのフォントをfonts/fallbackにぶち込んでおく

/opt/microchip/mplabx/v3.40/sys/java/jre1.8.0_91/lib/fonts/fallback/ipag.ttf
/opt/microchip/mplabx/v3.40/sys/java/jre1.8.0_91/lib/fonts/fallback/ipamp.ttf
/opt/microchip/mplabx/v3.40/sys/java/jre1.8.0_91/lib/fonts/fallback/ipam.ttf
/opt/microchip/mplabx/v3.40/sys/java/jre1.8.0_91/lib/fonts/fallback/ipagp.ttf

これだけ。毎回忘れる。Orz

2016年8月31日水曜日

ラズペリーパイで自力シリアル通信

ひょんなことから、過去にFONのGPIOを使ったなんちゃってシリアル通信を実装したのを思い出した。過去の投稿
 当時は、ラズベリーパイが注目されていて、いいな−と思いつつ、ちょっと高いなと感じており、中古で@500円程度で入手できるFONを何とか拡張できなかと思っていた。
結局受信エラーが抑えきれなくて、途中興味を失ってしまった。

最近になって、
1.2014年7月 トランジスタ技術
2.LINUXデバイスドライバ
3.RaspberryPiで学ぶARMデバイスドライバープログラミング
 を読む機会があって、FONでやりたかったことを再度挑戦してみようと思った。

そのまえに、情報が豊富なラズベリーパイで準備運動をしてみた記録。



 概要
ユーザーランドでGPIOをパタパタさせて、同期型シリアル通信を行い、
PICマイコンにて、UARTに変換する。

ラズピでuname -aを実行してPIC経由のURATで受信した結果。


ラズピ側
ユーザーランドでGPIOをパタパタさせるプログラム
ほとんど前述の 「3」のとおり
GPIO7 - CLK OUT
GPIO8 - DATA OUT
#include <stdio.h>
#include <unistd.h>
#include <rpi_gpio.h>
#include <rpi_gpiolib.h>
#define LED_BASE 7
void led_init(void)
{
// GPIOファンクションセット
rpi_gpio_function_set( LED_BASE+0, RPI_GPF_OUTPUT );//CLK
rpi_gpio_function_set( LED_BASE+1, RPI_GPF_OUTPUT );//DATA
rpi_gpio_function_set( LED_BASE+2, RPI_GPF_OUTPUT );
rpi_gpio_function_set( LED_BASE+3, RPI_GPF_OUTPUT );
}
void gpio_put_lsb(unsigned char v )
{
// 4ビットクリア
//rpi_gpio_clear32( RPI_GPIO_P1MASK, (3 & 0x0F) << LED_BASE);
printf("0b");
volatile int i=0;
for(i=0;i<8;i++){
//CLK=L
rpi_gpio_clear32( RPI_GPIO_P1MASK, (1 & 0x0F) << LED_BASE);
usleep(100);
//DATA
//printf("i=%d,v=%#x,v2=%d\n",i,v,v%2);
printf("%d",v%2);
if(v % 2 == 1){
rpi_gpio_set32( RPI_GPIO_P1MASK, (2 & 0x0F) << LED_BASE);
}else{
rpi_gpio_clear32( RPI_GPIO_P1MASK, (2 & 0x0F) << LED_BASE);
}
usleep(100);
//CLK=H
rpi_gpio_set32( RPI_GPIO_P1MASK, (1 & 0x0F) << LED_BASE);
usleep(100);
v=v>>1;
}
printf("\n");
}
void gpio_put_msb(unsigned char v )
{
// 4ビットクリア
//rpi_gpio_clear32( RPI_GPIO_P1MASK, (3 & 0x0F) << LED_BASE);
printf("0b");
volatile int i=0;
for(i=0;i<8;i++){
//CLK=L
rpi_gpio_clear32( RPI_GPIO_P1MASK, (1 & 0x0F) << LED_BASE);
usleep(100);
//DATA
//printf("i=%d,v=%#x,v2=%d\n",i,v,((v & 0x80) == 0x80 ? 1 : 0));
printf("%d",((v & 0x80) == 0x80 ? 1 : 0));
if((v & 0x80) == 0x80){
rpi_gpio_set32( RPI_GPIO_P1MASK, (2 & 0x0F) << LED_BASE);
}else{
rpi_gpio_clear32( RPI_GPIO_P1MASK, (2 & 0x0F) << LED_BASE);
}
usleep(100);
//CLK=H
rpi_gpio_set32( RPI_GPIO_P1MASK, (1 & 0x0F) << LED_BASE);
usleep(100);
v=v<<1;
}
printf("\n");
}
int main(int argc,char *argv[])
{
// GPIO初期化
if( ! rpi_gpio_init() )
return -1;
led_init();
int c=0;
if(argc==2){
while(argv[1][c]){
//ASCII値として送信する
printf("Char = %c(%#x) ",argv[1] [c],argv[1] [c]);
gpio_put_msb(argv[1] [c]);
c++;
}
}else if(argc==3){ //s
char buf[512];
fgets(buf, sizeof(buf), stdin);
while(buf[c]){
//ASCII値として送信する
printf("Char = %c(%#x) ",buf[c],buf[c]);
gpio_put_msb(buf[c]);
c++;
}
}else{
unsigned int value = 0;
for( value = 0; value < 10; value++ ) {
printf("LED = %d\n", value );
gpio_put_lsb(value);
sleep(1);
}
}
// mmap開放
rpi_gpio_deinit();
return 1;
}
view raw myi2c_test.c hosted with ❤ by GitHub
PIC側
RB0 - CLK IN (割り込み)
RB5 - DATA IN
RB2 - TX
/*
* File: main.c
* Author: adeno
*
* Created on 2016/08/31, 9:58
*/
#include <xc.h>
// CONFIG
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)
#pragma config BOREN = ON // Brown-out Detect Enable bit (BOD enabled)
#pragma config LVP = ON // Low-Voltage Programming Enable bit (RB4/PGM pin has PGM function, low-voltage programming enabled)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
#define _XTAL_FREQ 4000000 // delay_ms(x) のための定義
unsigned char rbuf=0,rcnt=0;
void putsUSART(char *str){
while(*str){
while (!TXIF);
TXREG = *str++;
}
}
void putc(unsigned char c){
while(!TXIF){
}
TXREG = c;
}
static void interrupt intr(void) {
if(INTF){ //INT割り込み
INTE = 0; //INT割り込み禁止
INTF = 0;
if(RB5 ==1){
rbuf = (rbuf<<1) + 0x01;
}else{
rbuf = (rbuf<<1) + 0x00;
}
rcnt++;
if(rcnt >= 8){
rcnt=0;
putc(rbuf);
}
INTE = 1; //INT割り込み開始
}
}
void main(void) {
OSCF = 1; //4MHz
PORTA = 0b00000000; //PORTAの中身をきれいにする
TRISA = 0b00000000; //PORTAは 1:入力 0:出力
PORTB = 0b00000000; //PORTBの中身をきれいにする
TRISB = 0b00100111; //PORTBは 1:入力 0:出力
PORTB = 0b00001000;
//USARTの初期化
TXSTA = 0b00100100;
RCSTA = 0b10010000;
SPBRG = 25; //ボーレート9600dpb @4MHz
//割り込みの設定
INTEDG = 1; //RB0 立ち上がり
INTF = 0; // RB0/INT外部割込みフラグをクリア
INTE = 1; // RB0/INT外部割込み許可
GIE = 1; // すべての割り込み許可
//SFR-RXの初期化
rbuf = 0;
rcnt = 0;
unsigned char wtim=0;
__delay_ms(100); // 100ms
putsUSART("Hello OK>\r\n");
while(1){
PORTB = 0b00001000;
__delay_ms(100); // 100ms
//putsUSART("Hello OK>\r\n");
PORTB = 0b00000000;
__delay_ms(100); // 100ms
if(rcnt>0){
wtim++;
if(wtim==10){
rcnt=0;
wtim=0;
putsUSART("Timeout\r\n");
}
}
}
return;
}
view raw main.c hosted with ❤ by GitHub
なんとなく達成感があるね。
次はPICからラズピ側に送信する機能を作ってみよう。

2016年8月22日月曜日

2つ同時に初期不良品をつかんでしまった

こんなこともあるのかと・・・。

Amazonで購入した3TBの外付けHDDと近所のハードオフで購入した光BOX3が見事に初期不良品だった。

・HDD MAL33000EX3 3TB @9,890

安さに惹かれてついつい買ってしまい、レビューを見て愕然。
リフレッシュ品とか初期不良の文字が目立つ。
実際HDDとして認識しないし、フォーマットかけてもエラーになるし・・・。

・光BOX3 @1,500
HDMI出力されない。TVにつないでもパソコンモニターにつないでもだめ。


まぁついていないことは重なるものだね。。。
返品できるかなぁ。Orz


2016年7月12日火曜日

でんき家計簿のデータをMySQLに保存する(phantom.jsを使う)

先日、selenium+firefoxを使用したでんき家計簿のスクレイピング をやってみた。
次はphantom.jsを使ってcronで実行できるようにしたいと思った。

といっても、driverの部分を変えるだけ。
最初は、

var driver = new webdriver.Builder().forBrowser('phantomjs',phantomjs.path).build();

と書いていたんだけど、cronで実行するとphantom.jsのパスが見つからないと怒られてしまった。
調べてみると、適切な書き方があった。
var driver = new webdriver.Builder()
       .withCapabilities({"phantomjs.binary.path":phantomjs.path})
       .forBrowser('phantomjs')
       .build();
これでOK!

var argv = require("minimist")(process.argv.slice(2));
if(!argv.u || !argv.p){
console.log(process.argv[1] + ' -u [userid] -p [password]');
console.log('\toption -d DB Write Mode');
console.log('\toption -c Phantom Mode');
return 0;
}
if(argv.d){
if(!argv.dbhost || !argv.dbuser || !argv.dbpass || !argv.dbname || !argv.dbtblname){
console.log(process.argv[1]
+ ' --dbhost=[hostname] --dbuser=[username] --dbpass=[password] --dbname=[dbname] --dbtblname=[dbtblname]');
console.log(argv.dbhost);
console.log(argv.dbuser);
console.log(argv.dbpass);
console.log(argv.dbname);
console.log(argv.dbtblname);
return 0;
}
}
var webdriver = require('selenium-webdriver'),
By = webdriver.By,
until = webdriver.until;
if(!argv.c){
var driver = new webdriver.Builder().forBrowser('firefox').build();
}else{
var phantomjs = require('phantomjs');
console.log(phantomjs.path);
// var driver = new webdriver.Builder().forBrowser('phantomjs',phantomjs.path).build();
var driver = new webdriver.Builder()
.withCapabilities({"phantomjs.binary.path":phantomjs.path})
.forBrowser('phantomjs')
.build();
}
driver.get('https://www.kakeibo.tepco.co.jp/dk/aut/login/');
driver.findElement(By.name('id')).sendKeys(argv.u);
driver.findElement(By.name('password')).sendKeys(argv.p);
driver.findElement(By.id('idLogin')).click();
/* 使用量と料金をグラフで見る */
driver.findElement(By.id('idNotEmptyImg_contents01.jpg')).click();
/* 時間別グラフはこちら */
driver.findElement(By.id('bt_time_view.jpg')).click();
/* データと日付を得る */
driver.getPageSource().then(function(pageSource){
var result = {};
getElectricityUsage(pageSource,result);
// console.log(JSON.stringify(result));
if(argv.d){
var mysqlid = { host : argv.dbhost,
user : argv.dbuser,
password : argv.dbpass,
database: argv.dbname};
writeDB(mysqlid,argv.dbtblname,result);
}
});
driver.quit();
function getElectricityUsage(pageSource,result) {
var findstr = 'var items = [["日次",';
var datePattern = /20\d\d\/\d\d\/\d\d/i;
var lines = pageSource.split('\n');
lines.forEach(function (line) {
var findindex = line.indexOf(findstr);
if (findindex != -1) {
var ElectricityUsage = line.substr(findindex+findstr.length).replace(/]];/g,"");
process.stdout.write(ElectricityUsage+"\n");
var ElectricityUsageArray = ElectricityUsage.split(",");
process.stdout.write("要素数:"+ElectricityUsageArray.length+"\n");
var ElectricityUsageValueArray = new Array();
ElectricityUsageArray.forEach(function (item) {
ElectricityUsageValueArray.push(parseFloat(item));
});
result['value'] = ElectricityUsageValueArray;
}
if (line.indexOf('の電気使用量') != -1) {
item = line.match(datePattern);
process.stdout.write(item[0] + '\n');
result['date'] = item[0].replace(/\//g,"-");
}
});
}
function writeDB(mysqlid,tblname,result){
var mysql = require('mysql');
var colname = "`0000-0030`,`0030-0100`,`0100-0130`,`0130-0200`,`0200-0230`,`0230-0300`,`0300-0330`,`0330-0400`,"
+"`0400-0430`,`0430-0500`,`0500-0530`,`0530-0600`,`0600-0630`,`0630-0700`,`0700-0730`,`0730-0800`,"
+"`0800-0830`,`0830-0900`,`0900-0930`,`0930-1000`,`1000-1030`,`1030-1100`,`1100-1130`,`1130-1200`,"
+"`1200-1230`,`1230-1300`,`1300-1330`,`1330-1400`,`1400-1430`,`1430-1500`,`1500-1530`,`1530-1600`,"
+"`1600-1630`,`1630-1700`,`1700-1730`,`1730-1800`,`1800-1830`,`1830-1900`,`1900-1930`,`1930-2000`,"
+"`2000-2030`,`2030-2100`,`2100-2130`,`2130-2200`,`2200-2230`,`2230-2300`,`2300-2330`,`2330-2400`";
var valline = "";
for(var i=0;i<48;i++){
if(i != 0) valline+=",";
valline+=result['value'][i];
}
console.log('insert into '+tblname+'(date,'+colname+') values("'+result['date']+'",'+valline+')');
var connection = mysql.createConnection(mysqlid);
connection.connect();
connection.query('insert into '+tblname+'(date,'+colname+') values("'+result['date']+'",'+valline+')',
function(error,results,fields){
if (error) {
console.error('error connecting: ' + error.stack);
return;
}
});
connection.end();
}
これを定期的に呼べばいい感じに電力使用量が入手できる。

2016年7月3日日曜日

でんき家計簿のデータをMySQLに保存する

でんき家計簿
 というサービスがある。

スマートメーターが設置されていれば、30分間隔の電力使用量が表示できる。
https://www.kakeibo.tepco.co.jp/dk/syo/electricUsage30MinGraph/

これをなんとかMySQLに保存したいと思った。
wgetでもごもごできるかなと思ったけど、認証があるしメンドクセー。
と思って数日経過し、ネットサーフィンしていたら、
すでに実現している人がいた。スゲー。
http://sirrow.info/archives/578

いろいろな技術を使っているのね。
  • minimist・・・コマンド引数パーサー
  • selenium-webdriver・・・Web自動テストツールらしい
  • phantomjs・・・ブラウザ画面のないQtWebKit ベースのブラウザらしい
 selenium-webdriver
 スクレイピングするツール?
https://www.npmjs.com/package/selenium-webdriver
http://www.seleniumhq.org/docs/03_webdriver.jsp#selenium-webdriver-api-commands-and-operations

PhantomJS
http://tips.hecomi.com/entry/20121229/1356785834
http://phantomjs.org/download.html
ふーん。キャプチャできた!

まずは
selenium-webdriver + firefoxででんき家計簿にアクセスしてみる
ほぼ前述の方と同じだ。 Orz
こんな感じ。
var argv = require("minimist")(process.argv.slice(2));
if(!argv.u || !argv.p){
console.log(process.argv[1] + ' -u [userid] -p [password]');
return 0;
}
if(argv.d){
if(!argv.dbhost || !argv.dbuser || !argv.dbpass || !argv.dbname || !argv.dbtblname){
console.log(process.argv[1]
+ ' --dbhost=[hostname] --dbuser=[username] --dbpass=[password] --dbname=[dbname] --dbtblname=[dbtblname]');
console.log(argv.dbhost);
console.log(argv.dbuser);
console.log(argv.dbpass);
console.log(argv.dbname);
console.log(argv.dbtblname);
return 0;
}
}
var webdriver = require('selenium-webdriver'),
By = webdriver.By,
until = webdriver.until;
var driver = new webdriver.Builder()
.forBrowser('firefox')
.build();
driver.get('https://www.kakeibo.tepco.co.jp/dk/aut/login/');
driver.findElement(By.name('id')).sendKeys(argv.u);
driver.findElement(By.name('password')).sendKeys(argv.p);
driver.findElement(By.id('idLogin')).click();
/* 使用量と料金をグラフで見る */
driver.findElement(By.id('idNotEmptyImg_contents01.jpg')).click();
/* 時間別グラフはこちら */
driver.findElement(By.id('bt_time_view.jpg')).click();
/* データと日付を得る */
driver.getPageSource().then(function(pageSource){
var result = {};
getElectricityUsage(pageSource,result);
// console.log(JSON.stringify(result));
if(argv.d){
var mysqlid = { host : argv.dbhost,
user : argv.dbuser,
password : argv.dbpass,
database: argv.dbname};
writeDB(mysqlid,argv.dbtblname,result);
}
});
driver.quit();
function getElectricityUsage(pageSource,result) {
var findstr = 'var items = [["日次",';
var datePattern = /20\d\d\/\d\d\/\d\d/i;
var lines = pageSource.split('\n');
lines.forEach(function (line) {
var findindex = line.indexOf(findstr);
if (findindex != -1) {
var ElectricityUsage = line.substr(findindex+findstr.length).replace(/]];/g,"");
process.stdout.write(ElectricityUsage+"\n");
var ElectricityUsageArray = ElectricityUsage.split(",");
process.stdout.write("要素数:"+ElectricityUsageArray.length+"\n");
var ElectricityUsageValueArray = new Array();
ElectricityUsageArray.forEach(function (item) {
ElectricityUsageValueArray.push(parseFloat(item));
});
result['value'] = ElectricityUsageValueArray;
}
if (line.indexOf('の電気使用量') != -1) {
item = line.match(datePattern);
process.stdout.write(item[0] + '\n');
result['date'] = item[0].replace(/\//g,"-");
}
});
}
function writeDB(mysqlid,tblname,result){
var mysql = require('mysql');
var colname = "`0000-0030`,`0030-0100`,`0100-0130`,`0130-0200`,`0200-0230`,`0230-0300`,`0300-0330`,`0330-0400`,"
+"`0400-0430`,`0430-0500`,`0500-0530`,`0530-0600`,`0600-0630`,`0630-0700`,`0700-0730`,`0730-0800`,"
+"`0800-0830`,`0830-0900`,`0900-0930`,`0930-1000`,`1000-1030`,`1030-1100`,`1100-1130`,`1130-1200`,"
+"`1200-1230`,`1230-1300`,`1300-1330`,`1330-1400`,`1400-1430`,`1430-1500`,`1500-1530`,`1530-1600`,"
+"`1600-1630`,`1630-1700`,`1700-1730`,`1730-1800`,`1800-1830`,`1830-1900`,`1900-1930`,`1930-2000`,"
+"`2000-2030`,`2030-2100`,`2100-2130`,`2130-2200`,`2200-2230`,`2230-2300`,`2300-2330`,`2330-2400`";
var valline = "";
for(var i=0;i<48;i++){
if(i != 0) valline+=",";
valline+=result['value'][i];
}
console.log('insert into '+tblname+'(date,'+colname+') values("'+result['date']+'",'+valline+')');
var connection = mysql.createConnection(mysqlid);
connection.connect();
connection.query('insert into '+tblname+'(date,'+colname+') values("'+result['date']+'",'+valline+')',
function(error,results,fields){
if (error) {
console.error('error connecting: ' + error.stack);
return;
}
});
connection.end();
}
得られたデータはこんな感じ。

ひさしぶりにすごいなと思った。

2016年6月25日土曜日

iij mioひかりが遅いのかと思ったら違った

インターネットが遅い!
夜、スマホを家のwifiに接続していると、ネット接続が遅すぎてイライラする。
普通にLTE接続したほうが早いくらい。

スピードテストを行ってもタイムアウトが発生することもしばしば。

なんでかなーと思って、家のネット速度を図ってみることにした。
使用したのは、speedtest-cilってやつ
 https://github.com/sivel/speedtest-cli.git

これをcron様で1時間おきに実行してみた。
期間:2016/6/21 8:51~2016/6/25 13:15

結果

平均値
Ping     :28.4ms
ダウンロード:56.9Mbps
アップロード:74.9Mbps
あれ?
あんまり遅くない!?

グラフにするとこんな感じ


生データもおいておきます。
date Ping Download Upload
2016/6/21 8:51 17.662 62.01 69.94
2016/6/21 8:52 13.458 74.54 102.25
2016/6/21 12:05 14.979 74.38 95.86
2016/6/21 12:23 13.296 66.93 73.06
2016/6/21 13:15 15.49 59.18 91.25
2016/6/21 14:15 119.306 41.96 98.37
2016/6/21 15:15 14.424 68.73 101.59
2016/6/21 16:15 57.403 28.06 73.57
2016/6/21 17:15 91.326 33.83 87.29
2016/6/21 18:15 18.206 35.91 63.8
2016/6/21 19:15 14.564 67.08 73.96
2016/6/21 20:15 16.082 64.41 83.83
2016/6/21 21:15 19.249 42.51 81.1
2016/6/21 22:15 32.393 55.25 49.22
2016/6/21 23:15 13.366 40.37 41.44
2016/6/22 0:15 14.862 60.54 69.99
2016/6/22 1:15 102.954 40.24 57.04
2016/6/22 2:15 14.314 68.08 85.78
2016/6/22 3:15 13.443 67.54 77.57
2016/6/22 4:15 13.521 67.16 81.69
2016/6/22 5:15 13.341 72.3 91.09
2016/6/22 6:15 14.252 69.19 24.39
2016/6/22 7:15 14.673 61.21 76.46
2016/6/22 8:15 18.76 37.04 91.31
2016/6/22 9:15 15.605 65.62 86.9
2016/6/22 10:15 14.654 59.9 77.27
2016/6/22 11:15 13.789 62.59 97.88
2016/6/22 12:15 17.035 44.92 98.17
2016/6/22 13:15 14.65 66.59 92.65
2016/6/22 14:15 57.149 30.3 68.24
2016/6/22 15:15 92.062 51.79 78.39
2016/6/22 16:15 14.691 56 53.31
2016/6/22 17:15 14.642 59.72 79.08
2016/6/22 18:15 89.277 30.02 68.7
2016/6/22 19:15 16.216 58.69 73.02
2016/6/22 20:15 48.201 38.4 38.21
2016/6/22 21:15 13.836 57.57 53.37
2016/6/22 22:15 48.478 47.26 34.01
2016/6/22 23:15 35.806 67.19 91.51
2016/6/23 0:15 72.176 24.71 45.62
2016/6/23 1:15 14.773 64.93 90.78
2016/6/23 2:15 41.096 43.38 43.99
2016/6/23 3:15 13.806 75.47 96.75
2016/6/23 4:15 14.745 65.45 93.72
2016/6/23 5:15 13.512 67.49 96.9
2016/6/23 6:15 14.597 70.07 98.11
2016/6/23 7:15 14.6 68.68 88.51
2016/6/23 8:15 13.641 75.12 90.88
2016/6/23 9:15 14.722 37.77 66.79
2016/6/23 10:15 13.974 72.87 99.66
2016/6/23 11:15 13.943 69.71 92.54
2016/6/23 13:15 14.196 72.69 100.79
2016/6/23 14:15 26.158 62.51 63.66
2016/6/23 15:15 14.817 49.36 34.87
2016/6/23 16:15 27.039 37.48 78.16
2016/6/23 17:15 16.061 47.53 81.91
2016/6/23 18:15 48.259 70.33 94.46
2016/6/23 19:15 21.64 33.72 52.55
2016/6/23 20:15 16.272 69.22 56.84
2016/6/23 21:15 41.007 37.62 44
2016/6/23 22:15 15.332 42.81 49.14
2016/6/23 23:15 22.458 57.33 38.63
2016/6/24 0:15 24.918 68.38 92.45
2016/6/24 1:15 14.115 53.59 22.11
2016/6/24 2:15 52.254 71.84 88.83
2016/6/24 3:15 15.287 59.09 84.3
2016/6/24 4:15 15.106 67.96 85.41
2016/6/24 5:15 15.563 73.71 93.67
2016/6/24 6:15 13.599 67.76 90.71
2016/6/24 7:15 14.032 60 87.25
2016/6/24 8:15 13.662 66.54 84.29
2016/6/24 9:15 14.192 60.12 95.02
2016/6/24 10:15 134.58 31.99 62.5
2016/6/24 11:15 13.768 60.08 59.94
2016/6/24 12:15 13.934 65 85.13
2016/6/24 13:15 13.959 65.34 83.09
2016/6/24 15:15 14.748 56.74 58.4
2016/6/24 16:15 16.261 42.16 96.2
2016/6/24 17:15 13.818 60.69 95.49
2016/6/24 18:15 13.922 61.76 75.35
2016/6/24 19:15 16.095 51.09 72.14
2016/6/24 20:15 14.162 66.01 66.65
2016/6/24 21:15 15.049 54.15 69.63
2016/6/24 22:15 14.417 56.3 53.04
2016/6/24 23:15 13.8 38.39 39.68
2016/6/25 0:15 74.175 13.08 20.96
2016/6/25 1:15 14.759 55.81 58.15
2016/6/25 2:15 14.84 62.29 53.59
2016/6/25 3:15 14.871 50.66 83.97
2016/6/25 4:15 13.858 67.08 86.4
2016/6/25 5:15 14.373 65.79 87.27
2016/6/25 6:15 181.924 59.77 84.69
2016/6/25 7:15 14.276 62.22 82
2016/6/25 8:15 13.959 65.01 87.42
2016/6/25 9:15 18.152 51.83 84.71
2016/6/25 10:15 13.731 54.33 73.85
2016/6/25 11:15 16.152 66.96 91.25
2016/6/25 12:15 180.747 63.24 58.08
2016/6/25 13:15 13.96 64.15 86.51