This is sample.

Dependencies:   USBHost mbed

このページは

イルミネーション制御用のコードページです。
使い方の説明があります。

概要

LocalFileSystem利用なのでLPC1768専用と思ってください。
"local/test.csv"ファイルが作成されます。
USBキーボードの利用が絶対です。 PCとのSerial通信も必要です。
エスケープシーケンスをちょっと利用してるので、WindowsはTeraTerm、Macはscreenコマンドをオススメします。

どんなプログラム?

プログラムの構造は 基本は2つのモードを's'キーによって切り替えて使います。(常に's'キーが有効です。)

モード内容有効なキー
入力モード数字の入力、表示、保存 (起動時はこれ)'s','0-9','\b','\r','\n' ( 'd' / 'y' )
表示モード履歴の表示のみ。キー入力で次々表示's','\r','\n'

通常の運用では入力モードでの動作になります。
キーボードのコードは

  • '\b':バックスペース(BS)
  • '\r','\n':エンターキー(LF:'\n'==0x0a)です。なんとなく'\r'足しました。

モードの説明

  • 入力モード
    • 数字(0-9)を入力するとセットされます。(2,1,3と入力すると「13」、3,0,2と入力すると「2」となります。)
    • バッファが空のときにはエンターキー'\r''\n'の入力は無視されます。
    • エンターキー('\r','\n')を入力すると
      • 1回目:確認用に表示します。(prenote)
      • 2回目:(確定され)表示・保存されます。(show,save)
      • 3回目:バッファがクリアされ待機状態になります。(Delete)
      • (4回目:バッファは空なので無視されます。)
    • 'd'を入力するとファイル削除の確認をしますので(Remove)
      • 'y'キーで削除
      • その他のキーで取り消し
    • BackSpace'\b'キーでバッファクリア(Delete)
  • 表示モード
    • エンターキー('\r','\n')を入力すると
      • 過去の保存済み数字(saved)を古い順番に表示します
      • すべて表示すると"EOF"(End Of File)と表示され入力モードに戻ります。

再起動後にファイルがある場合はそのファイルに追加編集されます。(消したい場合は入力モードで削除して)

警告

表示モードの途中で's'を入力すると、再び表示モードになったときに途中からの表示になります。
これでいい?
グローバル変数としてフラグ2つ(delete,remove)、数値2桁、数値の桁位置指示、があります。

Quote:

基本的にテストページなので好きなだけいじってください。
不明な点は福田まで。

考慮すべき点

  • 要相談
    • テンキーの場合のキー割当はどうする?
    • 既に保存した数値(already exiting!)も表示(prenote,show)まではするべき?(saveだけしない)
    • ハードウェアのソフトウェアインターフェースが不明なのでint[2]に(ASCII)グローバルで実装中。表示関数(show)は"void show(int);"がいい?
      • いやいや、10進数表示だからそのままでいい(by福田)
    • 表示モード中のモード切り替えに対して、ファイル位置を戻すべき?
    • 表示モード中に次々表示されるが、戻ることも可能にする?
    • Enterを間違えて2回押すと確定されちゃう。(4回連続入力に対しては無視)
  • ソフトウェアの気になる点
    • クラス化の必要性はある?(グローバルむき出しと構造が細かいのは精神衛生的に……)
    • 10進数2桁限定なので、3桁に対応させるべき?(対応済みコードあり)
    • (表示モード中)160行目はshow();に対応するためにもshowだけは引数ありshow(int *)or(int)にしたほうがいい。(prenoteにも渡すべきなら同様に)
    • 保存、読込フォーマットは"%02d\r\n"ですが何か?(1->"01\r\n"、23->"23\r\n"など)
    • デバッグ用にUSBシリアルに対応させる(切替仕様にす)べき?

実際の動作

ログの内容です。

[USB_INFO: /src/USBHost/USBHost/USBHost.cpp:158]New device connected: 10002c6c [hub: 0 - port: 1]
[USB_INFO: /src/USBHost/USBHostHID/USBHostKeyboard.cpp:120]New Keyboard device: VID:04fe PID:000d [dev: 10002c6c - intf: 0]
[connected]
      set :'12'
create file "/local/test.csv"
  prenote :'12'
     show :'12'
    saved :'12'
   Delete :'12'
      set :'45'
  prenote :'45'
     show :'45'
    saved :'45'
   Delete :'45'
      set :'67'
      set :'65'
      set :'45'
already exiting!
   Delete :'45'
      set :'45'
already exiting!
   Delete :'45'
mode change:Show
12
45
EOF
auto change:Number
Do you want to remove File? [y/n] "/local/test.csv"
Removed"/local/test.csv"

main.cpp

Committer:
kusakagenohara
Date:
2014-10-27
Revision:
1:c50f6764f528
Parent:
0:318e4fa6590e

File content as of revision 1:c50f6764f528:

#include "mbed.h"
#include "USBHostKeyboard.h"

#define LOG_DEBUG
#ifdef LOG_DEBUG
#define log_debug(format,...)   std::printf(format,##__VA_ARGS__)
#else
#define log_debug(format,...)
#endif

typedef enum {
    Init,
    Wait,
    Prenote,
    Delete,
} num_state_t;

typedef enum {
    Number =0,
    Show =!Number
} mode_key_t;
const char *const mode_string[] = {"Number","Show"};

/*ヒープ領域に作る線形リストのノード構造体。いちいちstructって書くの面倒なんでtypedefしとく*/
typedef struct node{
    int number;         //レコード(数字)
    struct node *next;  //次のノードへのポインタ
    }node;



LocalFileSystem local("Local");
BusOut led(LED1,LED2,LED3,LED4);
/*******************ポート設定(水野)***************************/
/*通信端子*/
Serial uart_subdisplay(p9,p10); // tx,rx
//Serial uart_ps(p28,p27);
/*7セグの十の位(端子名はwikipediaの通り)*/
DigitalOut a10(p14);
DigitalOut b10(p15);
DigitalOut c10(p16);
DigitalOut d10(p17);
DigitalOut e10(p18);
DigitalOut f10(p19);
DigitalOut g10(p20);
/*7セグの一の位(端子名はwikipediaの通り)*/
DigitalOut a1(p29);
DigitalOut b1(p26);
DigitalOut c1(p25);
DigitalOut d1(p24);
DigitalOut e1(p23);
DigitalOut f1(p22);
DigitalOut g1(p21);
/*本体操作スイッチ*/
DigitalIn delete_yes(p11);
DigitalIn delete_no(p12);
DigitalIn on_off(p13);
DigitalOut file_alart_led(p8);

/*グローバル変数*/
static const char *const filename = "/Local/BINGO.csv";  //ファイル名
int number_flag = 0;
int numidx = 0;
int numbers[2] = {0,0};     //バッファ。numbers[0]が十の位、numbers[1]が一の位。ってことは、ディスプレイ系関数は配列を受け取るように変更。

node *entr; //線形リストの先頭アドレス。mainの中に置くと面倒なのでグローバルで。



/*プロトタイプ宣言*/
void onKey(uint8_t);
int mode_number(int);
int mode_show(int);
void switch_mode(mode_key_t *);
void setNum_new(int);//'0'~'9' is guaranteed
void deleteNum();

void effect(int);
int main_display(int*);
void power_supply_control(int,int,int,int);
void power_supply_shutdown_protect(void);
void start_up_file_check(void);
int number_converter(int*);
node* nodealloc(void);
void save_file(int);
void start_up_read_file(node*);
node* add_node(int,node*);
int kisyutu_check();
void save_data();


void onKey(uint8_t key)/*キーが押されたら*/
{
    static mode_key_t state_mode = Number;
    switch (key) {
        case 's':
            switch_mode(&state_mode);
            printf("mode change:%s\r\n",mode_string[state_mode]);
            break;
    }
    if((Number == state_mode ? mode_number : mode_show)(key)) {
        switch_mode(&state_mode);
        printf("auto change:%s\r\n",mode_string[state_mode]);
    }
}

inline void switch_mode(mode_key_t *mode)
{
    *mode = Number == *mode ? Show : Number;
    if(*mode == Number)
    {
        uart_subdisplay.printf("101\n");    //サブディスプレイ「入力モード」点灯
    }
    if(*mode == Show)
    {
        uart_subdisplay.printf("102\n");   //サブディスプレイ「復習モード」点灯
    }
}


int mode_number(int key)
{
    static num_state_t state = Init;
    switch (state) {
        case    Prenote:                //表示確認モードのとき
            if ('\r'==key || '\n'==key)   //エンターが押されたら
            {
                save_data();           //線形リストとファイルに保存する関数をコール
                 
                if(main_display(numbers))      //メインディスプレイ表示
                {                               //switch-case中にバッファを消されると死ぬので、終了のサイン戻り値を待って、
                    deleteNum();                //バッファをクリア
                }
            }
            state = Wait;                   //入力待ちモードにセット
            if (0) {
            case Init:
                deleteNum();
                state = Wait;
            }
        case Wait:                          //入力待ちモードなら
            switch (key) {                  //数字が入力されたらアスキーコードを数字に変換して収納
                case '0':
                    setNum_new(0);          //「値はintで欲しい」って言ったような気が・・・7セグじゃputc使えないし。
                    break;
                case '1':
                    setNum_new(1);
                    break;
                case '2':
                    setNum_new(2);
                    break;
                case '3':
                    setNum_new(3);
                    break;
                case '4':
                    setNum_new(4);
                    break;
                case '5':
                    setNum_new(5);
                    break;
                case '6':
                    setNum_new(6);
                    break;
                case '7':
                    setNum_new(7);
                    break;
                case '8':
                    setNum_new(8);
                    break;
                case '9':
                    setNum_new(9);      //setnumへ渡す(バッファへ保存とサブディスプレイへの出力)
                    break;
                case '\n':              //エンターが押されたら
                case '\r':
                    if (number_flag)  //数字フラグが1なら
                    {
                        if((kisyutu_check()) == 0){                //既出でなければ
                            state = Prenote;                //入力確認モードへ移行
                            uart_subdisplay.printf("111\n");    // サブディスプレイ「よろしいですか?」点灯
                        } else if ((kisyutu_check()) == 1) {       //既出なら
                            uart_subdisplay.printf("112\n");    //サブディスプレイ「既出です」点灯
                            wait(1.0);                          //を1秒点灯 
                            deleteNum();                    //バッファをクリア
                        }
                    }
                    break;
            }
            break;
        default:
            break;
    }
    led = state;
    if ('\b' == key) {//b(バックスペース)なら
        deleteNum();    //バッファをクリアし
        state = Wait;   //入力待ちモードへ
    }
    return 0;
}

/*復習  メモ:福田君のモード選択アルゴリズム → 1を返すと自動的に入力モードになる*/

int mode_show(int key)
{
    static node *current = entr;    //enterのたび呼び出されるので、satatic。自動変数にしてかなり悩んだ~。だけど、復習直後に復習するとバグル。
    int main_output[2];         //mainディスプレイは配列入力なので欲しい。
    int temp;
    
    if(current -> next == NULL)
    {
        return 1;               //電源ON直後に復習に入れないためのフェイルセーフ。
    }
        
    if (key == '\r' || key == '\n')
    {
            current = current-> next;           //先頭リストは空、最後のリストはデータあるんで、処理前に進めとく。
            temp = current -> number;           //線形リストから初っ端の字取り出し
            uart_subdisplay.printf("%d\n",temp);   //サブディスプレイに表示
            main_output[0] = temp / 10;             //INTなんで小数点以下切り捨て
            main_output[1] = temp - main_output[0] * 10;        //一の位取り出し
            main_display(main_output);                        //メインディスプレイに表示
     
      
            if(current -> next == NULL){     //次のリストがなければ
                current = entr;             //復習直後に復習してもバグらない。
                return 1;                           //関数を抜ける
            }
    }
    return 0;
}

void deleteNum()        //バッファクリア関数
{
    number_flag = 0;
    numbers[0]=0;           //だからーーー文字コードじゃなくてーーーーー泣
    numbers[1]=0;
    uart_subdisplay.printf("110\n");    //サブディスプレイの「よろしいですか?」と「既出です。」消す 
    wait(0.1);                         //通信まち
    uart_subdisplay.printf("0\n");  //サブディスプレイを0に 
}


void keyboard_task(void const *)    //もともとあったやつ。
{
    USBHostKeyboard keyboard;
    while(1) {
        while(!keyboard.connect()) {
            Thread::wait(500);
        }
        keyboard.attach(onKey);
        printf("[connected]\r\n");
        while(keyboard.connected()) {
            Thread::wait(500);
        }
    }
}


/********************************************関数(水野)*****************************************************/

/*setNumを整数型バージョンへ、ついでに自分のわかりやすいアルゴリズムに書き換え*/

void setNum_new(int data)      //バッファへセット(int用作り直し版)
{
    if(!number_flag) {  //数字フラグ(入力したか判定)が立ってなければ立てる
        number_flag = 1;
    } 
    numbers[0] = numbers[1];        //一の位の数字を十の位に移して
    numbers[1] = data;              //一の位を更新
    uart_subdisplay.printf("%d\n",number_converter(numbers)); //2桁整数に直してサブディスプレイへ出力。
}

/*エフェクト制御*/
void effect(int effect_type)
{
    /*理実と相談*/
}

/*メインディスプレイ 7セグ(下側MOSFET)制御 numbersが桁で分れてるので配列のままポインタで受け取りに変更*/
int main_display(int *data)
{
    switch(data[0])//十の位
    {
            case 1:
                a10 = 1;
                b10 = 0;
                c10 = 0;
                d10 = 1;
                e10 = 1;
                f10 = 1;
                g10 = 1;
                break;
            case 2:
                a10 = 0;
                b10 = 0;
                c10 = 1;
                d10 = 0;
                e10 = 0;
                f10 = 1;
                g10 = 0;
                break;
            case 3:
                a10 = 0;
                b10 = 0;
                c10 = 0;
                d10 = 0;
                e10 = 1;
                f10 = 1;
                g10 = 0;
                break;
            case 4:
                a10 = 1;
                b10 = 0;
                c10 = 0;
                d10 = 1;
                e10 = 1;
                f10 = 0;
                g10 = 0;
                break;
            case 5:
                a10 = 0;
                b10 = 1;
                c10 = 0;
                d10 = 0;
                e10 = 1;
                f10 = 0;
                g10 = 0;
                break;
            case 6:
                a10 = 0;
                b10 = 1;
                c10 = 0;
                d10 = 0;
                e10 = 0;
                f10 = 0;
                g10 = 0;
                break;
            case 7:
                a10 = 0;
                b10 = 0;
                c10 = 0;
                d10 = 1;
                e10 = 1;
                f10 = 0;
                g10 = 1;
                break;
            case 8:
                a10 = 0;
                b10 = 0;
                c10 = 0;
                d10 = 0;
                e10 = 0;
                f10 = 0;
                g10 = 0;
                break;
            case 9:
                a10 = 0;
                b10 = 0;
                c10 = 0;
                d10 = 0;
                e10 = 1;
                f10 = 0;
                g10 = 0;
                break;
            default:  // =0
                a10 = 0;
                b10 = 0;
                c10 = 0;
                d10 = 0;
                e10 = 0;
                f10 = 0;
                g10 = 1;
                break;
    }
        
    switch(data[1])//一の位
    {
            case 1:
                a1 = 1;
                b1 = 0;
                c1 = 0;
                d1 = 1;
                e1 = 1;
                f1 = 1;
                g1 = 1;
                break;
            case 2:
                a1 = 0;
                b1 = 0;
                c1 = 1;
                d1 = 0;
                e1 = 0;
                f1 = 1;
                g1 = 0;
                break;
            case 3:
                a1 = 0;
                b1 = 0;
                c1 = 0;
                d1 = 0;
                e1 = 1;
                f1 = 1;
                g1 = 0;
                break;
            case 4:
                a1 = 1;
                b1 = 0;
                c1 = 0;
                d1 = 1;
                e1 = 1;
                f1 = 0;
                g1 = 0;
                break;
            case 5:
                a1 = 0;
                b1 = 1;
                c1 = 0;
                d1 = 0;
                e1 = 1;
                f1 = 0;
                g1 = 0;
                break;
            case 6:
                a1 = 0;
                b1 = 1;
                c1 = 0;
                d1 = 0;
                e1 = 0;
                f1 = 0;
                g1 = 0;
                break;
            case 7:
                a1 = 0;
                b1 = 0;
                c1 = 0;
                d1 = 1;
                e1 = 1;
                f1 = 0;
                g1 = 1;
                break;
            case 8:
                a1 = 0;
                b1 = 0;
                c1 = 0;
                d1 = 0;
                e1 = 0;
                f1 = 0;
                g1 = 0;
                break;
            case 9:
                a1 = 0;
                b1 = 0;
                c1 = 0;
                d1 = 0;
                e1 = 1;
                f1 = 0;
                g1 = 0;
                break;
            default:  // =0
                a1 = 0;
                b1 = 0;
                c1 = 0;
                d1 = 0;
                e1 = 0;
                f1 = 0;
                g1 = 1;
                break;
    }
    return 1;
}

/*電源(各色電流)制御*/
void power_supply_control(int r,int g,int b,int control) //それぞれの明るさ(%)と、制御コード
{
    
}


/*停電時の処理(ピン変化割り込み)*/
void power_supply_shutdown_protecct(void)
{
    
    //電源が完成したら挙動を見てどんな処理が必要か考えて実装。    
}


/*起動時のファイルチェック*/
void start_up_file_check(void)
{
    FILE *fp;
    if((fp = fopen(filename,"r")) != NULL)        //読み込みモードでファイルが開けたら、つまりファイルがあったら
    {
        file_alart_led = 1;                    //「ファイルを削除しますか?」ランプ点灯
        fclose(fp);
        while(1)
        {
           if(delete_yes)//削除(3秒長押し)
           {    
                wait(3.0);
                if(delete_yes)                  //削除スイッチが、3秒経過後にまだ押されてたら
                {
                    fp = fopen(filename,"w");   //上書きモードで開いて白紙にして上書き保存
                    fclose(fp);
                    break;
                }
            }
            if(delete_no)//残す(停電復帰後等)
            {
                start_up_read_file(entr);    //ファイルを線形リストに読み込み
                wait(0.1);
                break;
            }
        }
        file_alart_led = 0;                 //「ファイルを削除しますか?」ランプ消灯
    }
}

/*桁ごとの配列を2桁の整数に変換*/
int number_converter(int *data)
{
    int output_data;
    output_data = 10 * data[0] + data[1];
    return output_data;
}


/*nodealloc関数。nodeサイズのメモリを確保して、確保したnode型のポインタを返す*/
node* nodealloc(void)
{
    return (struct node*)malloc(sizeof(node));      //malloocは必ずキャストして使うこと
}

/*ローカルストレージにバックアップをとる*/
void save_file(int data)
{
    FILE *fp;
    if((fp = fopen(filename,"a")) != NULL)  //追記モードで開いて
    {
        fprintf(fp,"%d\r\n",data);              //数字を保存して改行
        fclose(fp);                             //ファイルを閉じる
    }
}

/*停電復帰時専用。外部ファイルから線形リストに読み込み。開始ノードを引数。*/
void start_up_read_file(node *start)
{
    int data;
    node *current = start;
    FILE *fp;
    if((fp=fopen(filename,"r")) != NULL)      //ファイルが開けたら
    {
        while(fscanf(fp,"%d",&data) != EOF)
        {
            current = add_node(data,current);
        }
        fclose(fp);
    }
}

/*線形リストを追加する すべてがアドレスで動いていることに注意。メモリ内の倉庫に対し、事務所からロケーション番号と作業を指示しているだけ。*/
node* add_node(int data,struct node *current)
{
    struct node *temp;

    while(current->next != NULL)    //停電復帰後はスタートノード=最後もノードになってないので、最後のノードを探す。
    {
        current = current->next;
    }

    temp = nodealloc();        //まずノードを作る。メモリは確保されるのでローカル変数で良い。
    temp -> number = data;    //作ったノードに数字を保存する。
    temp->next = NULL;      //作ったやつはケツに足すので、次につなげるのがない最終ノードにする。
    current->next = temp;   //受け取ったやつは作ったやつの一個のリストになるため、作ったやつにつながるように書き換える。
    return temp;            //作ったやつ(新たに最後になったやつ)のアドレスを返す。
}

/*新たにデータを保存する(線形リストと外部ファイル)*/
void save_data()
{
    static node *current_node = entr;          //ノードのアドレスは静的変数で。最初は当然先頭で初期化
    int data = number_converter(numbers);   //バッファの中身を2桁整数に変換
    save_file(data);                           //ファイルに保存
    add_node(data,current_node);                //線形リストに保存
}

/*既出チェック*/
int kisyutu_check()
{
    node *task;     //ノード型のポインタ変数。
    task = entr;    //入り口ノードでスタート
    int temp;       //処理用変数(バッファを2桁に変換して一旦置くよ)
    int flag = 0;       //既出フラグ。既出なら1。ちがえば0。
    temp = number_converter(numbers);   //2桁に変換して仮置き
    
    while(task -> next != NULL){
        task = task -> next;        //入り口ノードは空。while停止条件のノードにはデータが存在。ってことで一個オフセット。
        if(task -> number == temp)  //一致したらフラグを立ててループを抜ける。
        {
            flag = 1;
            break;
        }
     }
     return flag;
}


/******************************************************************************/  


int main()
{
/**********************起動時の処理******************************************/

/*ディスプレイの準備*/
    deleteNum();                    //numbersを0にして
    main_display(numbers);          //メインディスプレイを0に
    uart_subdisplay.printf("0\n");  // サブディスプレイ0に
    wait(0.1);                      //通信待ち
    uart_subdisplay.printf("124\n");//サブディスプレイのステータスランプ全消灯

/*先頭ノードを用意*/
    entr = nodealloc();     //entr はグローバル変数。
    entr -> number = 0;     //先頭ノードはデータを持たないが、考慮めんどくさいんで0にしとく。。
    entr -> next = NULL;    //とりあえず一個なのでNULL。

/*残留データの削除または読込*/
    start_up_file_check();
    
/*電源起動*/


 
    uart_subdisplay.printf("101\n");    //サブディスプレイ「入力モード」点灯
/******************************************************************************/   
    

    Thread keyboardTask(keyboard_task, NULL, osPriorityNormal, 256 * 4);
    while(1) {
        Thread::wait(500);
    }
}