北海道情報専門学校 ライフハック研究所のエンベデッドUSBチーム松葉和仁により開発されたUSBSecのmbedに使用するソースコード by 和仁

Dependencies:   SDFileSystem MusicEngine

Fork of mbed-os-example-ble-LED by mbed-os-examples

北海道情報専門学校 ライフハック研究所 エンベデッドUSB USBSec用mbedプログラム

松葉和仁

source/main.cpp

Committer:
kazu0o2
Date:
2017-02-08
Revision:
37:dcb097426442
Parent:
34:41da17c652f5

File content as of revision 37:dcb097426442:

#include <events/mbed_events.h>
#include <mbed.h>
#include "SDFileSystem.h"
#include "MusicEngine.h"
#include "ble/BLE.h"
#include "INITService.h"//初期設定とその状態の送信を行う 0x01
#include "PINService.h"//パスワードの認証を行う0x02
#include "USBService.h"//USB機器の接続、切断を行う 0x03
#include "STATEService.h"//認証、電源、USB状態の送信を行う 0x04

#define NEED_CONSOLE_OUTPUT 1 /* Set this if you need debug messages on the console;
                               * it will have an impact on code-size and power consumption. */
#if NEED_CONSOLE_OUTPUT
Serial  pc(USBTX, USBRX);
#define DEBUG(...) { pc.printf(__VA_ARGS__); }
#else
#define DEBUG(...) /* nothing */
#endif /* #if NEED_CONSOLE_OUTPUT */

DigitalOut alivenessLED(LED1, 0);//システム生存確認LED
DigitalOut actuatedLED(LED2, 0);//USB用リレーピン

InterruptIn powerSwitch(p17);//パワー検出コード
InterruptIn resetSwitch(p18);//リセットボタン

DigitalOut speakerD(LED3, 0);//スピーカ省電力化デジタル
MusicEngine Speaker(LED4);

//SDFileSystem local("local");//SDカードを定義する
SDFileSystem sd(p13,p14,p15,p19,"sd");

const static char     DEVICE_NAME[] = "USBSec";
static const uint16_t uuid16_list[] = {USBService::USB_SERVICE_UUID,PINService::PIN_SERVICE_UUID,STATEService::STATE_SERVICE_UUID,INITService::INIT_SERVICE_UUID};//testcode

static EventQueue eventQueue(
    /* event count */ 10 * /* event size */ 32
);

USBService *usbServicePtr;
PINService *pinServicePtr;
STATEService *stateServicePtr;
INITService *initServicePtr;

bool authenticationInformation = false;//パスワードは登録されているか
bool authenticated = false;//パスワード認証を行ったか

char password[] = {0x00,0x00,0x00,0x00,0x00,0x00};//デバッグパスワード

//http://mag.switch-science.com/2015/06/17/fathersday2015/
//http://www.geocities.co.jp/Playtown-Denei/9628/whatsmml.html
int speakerMode = 0;//1:接続 2:切断 3:認証エラー 4:パスワードリセット 5:起動 6:USB有効 7:USB無効
int lastSpeakerId = -1;

//接続
void connectAlertOff();

/**
 *接続時発音
 *接続時に発音されるためのキュー
 */
void connectAlertOn() {
    DEBUG("connectAlertOn\r\n");
    Speaker.play("T160L4CDEFEDCB+");//カエルの歌
    //Speaker.play("T240L4CO4DO4EO4F");//再現
    
    //直前のスピーカーの省電力モード移行をキャンセルする
    if(lastSpeakerId >=0){
        eventQueue.cancel(lastSpeakerId);
        DEBUG("キュー %d をキャンセルしました\r\n",lastSpeakerId);
    }
    lastSpeakerId=eventQueue.call_in(3000.0f, &connectAlertOff);
}

/**
 *接続時発音
 *接続時に発音されるためのキュー
 */
void connectAlertOff() {
    DEBUG("connectAlertOff\r\n");
    if(speakerMode==1){
        speakerD = 0;
        speakerMode = 0;
    }
}

/**
 *接続時発音
 *接続時に発音を開始するためのキュー
 */
void connectAlertStart() {
    DEBUG("connectAlertStart\r\n");
    speakerMode = 1;
    speakerD = 1;
    eventQueue.call(&connectAlertOn);
}

//切断
void disconnectAlertOff();

/**
 *切断時発音
 *切断時に発音されるためのキュー
 */
void disconnectAlertOn() {
    DEBUG("disconnectAlertOn\r\n");
    Speaker.play("T160L4CR4CR4CR4CR4");
    
    if(lastSpeakerId >=0){
        eventQueue.cancel(lastSpeakerId);
        DEBUG("キュー %d をキャンセルしました\r\n",lastSpeakerId);
    }
    lastSpeakerId=eventQueue.call_in(3000.0f, &disconnectAlertOff);
}

/**
 *切断時発音
 *切断時に発音されるためのキュー
 */
void disconnectAlertOff() {
    DEBUG("disconnectAlertOff\r\n");
    if(speakerMode == 2){
        speakerD = 0;
        speakerMode = 0;
    }
}

/**
 *切断時発音
 *切断時に発音を開始するためのキュー
 */
void disconnectAlertStart() {
    DEBUG("disconnectAlertStart\r\n");
    speakerMode = 2;
    speakerD = 1;
    eventQueue.call(&disconnectAlertOn);
}

//認証エラー
void authErrorAlertOff();

/**
 *認証エラー発音
 *認証エラー時に発音を開始するためのキュー
 */
void authErrorAlertOn() {
    DEBUG("authErrorAlertOn\r\n");
    Speaker.play("T160L4CC");
    
    if(lastSpeakerId >=0){
        eventQueue.cancel(lastSpeakerId);
        DEBUG("キュー %d をキャンセルしました\r\n",lastSpeakerId);
    }
    lastSpeakerId=eventQueue.call_in(1500.0f, &authErrorAlertOff);
}

/**
 *認証エラー発音
 *認証エラー時に発音を開始するためのキュー
 */
void authErrorAlertOff() {
    DEBUG("authErrorAlertOff\r\n");
    if(speakerMode == 3){
        speakerD = 0;
        speakerMode = 0;
    }
}

/**
 *認証エラー発音
 *認証エラー時に発音を開始するためのキュー
 */
void authErrorAlertStart() {
    DEBUG("authErrorAlertStart\r\n");
    speakerMode = 3;
    speakerD = 1;
    eventQueue.call(&authErrorAlertOn);
}

//パスワードリセット
void passwordResetAlertOff();

/**
 *パスワードリセット発音
 *パスワードリセット時に発音を開始するためのキュー
 */
void passwordResetAlertOn() {
    DEBUG("passwordResetAlertOn\r\n");
    Speaker.play("T160L4CDCDEFEF");
    
    if(lastSpeakerId >=0){
        eventQueue.cancel(lastSpeakerId);
        DEBUG("キュー %d をキャンセルしました\r\n",lastSpeakerId);
    }
    lastSpeakerId=eventQueue.call_in(3000.0f, &passwordResetAlertOff);
}

void passwordResetAlertOff() {
    DEBUG("passwordResetAlertOff\r\n");
    if(speakerMode == 4){
        speakerD = 0;
        speakerMode = 0;
    }
}

void passwordResetAlertStart() {
    DEBUG("passwordResetAlertStart\r\n");
    speakerMode = 4;
    speakerD = 1;
    eventQueue.call(&passwordResetAlertOn);
}

//起動音
void startupAlertOff();

/**
 *起動発音
 *移動時に発音を開始するためのキュー
 */
void startupAlertOn() {
    DEBUG("startupAlertOn\r\n");
    Speaker.play("T160L4CDCDEFE");
    
    if(lastSpeakerId >=0){
        eventQueue.cancel(lastSpeakerId);
        DEBUG("キュー %d をキャンセルしました\r\n",lastSpeakerId);
    }
    lastSpeakerId=eventQueue.call_in(3000.0f, &startupAlertOff);
}

void startupAlertOff() {
    DEBUG("startupAlertOff\r\n");
    if(speakerMode == 5){
        speakerD = 0;
        speakerMode = 0;
    }
}

void startupAlertStart() {
    DEBUG("startupAlertStart\r\n");
    speakerMode = 5;
    speakerD = 1;
    eventQueue.call(&startupAlertOn);
}

//USB有効
void enableUSBAlertOff();

/**
 *USB有効発音
 *USBの回路を有効にする際に発音を開始するためのキュー
 */
void enableUSBAlertOn(){
    DEBUG("enableUSBAlertOn\r\n");
    Speaker.play("T200L4CE");
    
    if(lastSpeakerId >=0){
        eventQueue.cancel(lastSpeakerId);
        DEBUG("キュー %d をキャンセルしました\r\n",lastSpeakerId);
    }
    lastSpeakerId=eventQueue.call_in(3000.0f, &enableUSBAlertOff);
}

void enableUSBAlertOff() {
    DEBUG("enableUSBAlertOff\r\n");
    if(speakerMode == 6){
        speakerD = 0;
        speakerMode = 0;
    }
}

void enableUSBAlertStart() {
    DEBUG("enableUSBAlertStart\r\n");
    if(speakerMode == 1){
        DEBUG("接続アラートが有効なため中止しました\r\n");
        return;
    }
    speakerMode = 6;
    speakerD = 1;
    eventQueue.call(&enableUSBAlertOn);
}

//USB無効
void disableUSBAlertOff();

/**
 *USB無効発音
 *USBの回路を無効にする際に発音を開始するためのキュー
 */
void disableUSBAlertOn(){
    DEBUG("disableUSBAlertOn\r\n");
    Speaker.play("T200L4EC");
    
    if(lastSpeakerId >=0){
        eventQueue.cancel(lastSpeakerId);
        DEBUG("キュー %d をキャンセルしました\r\n",lastSpeakerId);
    }
    lastSpeakerId=eventQueue.call_in(3000.0f, &disableUSBAlertOff);
}

void disableUSBAlertOff() {
    DEBUG("disableUSBAlertOff\r\n");
    if(speakerMode == 7){
        speakerD = 0;
        speakerMode = 0;
    }
}

void disableUSBAlertStart() {
    DEBUG("disableUSBAlertStart\r\n");
    if(speakerMode == 2){
        DEBUG("切断アラートが有効なため中止しました\r\n");
        return;
    }
    speakerMode = 7;
    speakerD = 1;
    eventQueue.call(&disableUSBAlertOn);
}

/**
 *パワー検出コード
 *タクトスイッチが押されたときに実行されるキュー
 */
void togglePowerUp() {
    DEBUG("PowerUp\r\n");
    stateServicePtr->powerStateUpdate(0x01);
}

/**
 *パワー検出コード
 *タクトスイッチが離されたときに実行されるキュー
 */
void togglePowerDown() {
    DEBUG("PowerDown\r\n");
    stateServicePtr->powerStateUpdate(0x00);
    
    //USBの無効化
    actuatedLED = 0x00;
    stateServicePtr->usbStateUpdate(0x00);
}

/**
 *パワー検出コード
 *タクトスイッチが押されたときに実行される関数
 */
void powerUp() {
    // 即実行されるイベント
    eventQueue.call(&togglePowerUp);
}

/**
 *パワー検出コード
 *タクトスイッチが離されたときに実行される関数
 */
void powerDown() {
    // 即実行されるイベント
    eventQueue.call(&togglePowerDown);
}

/**
 *リセットボタン
 *タクトスイッチが離されたときに実行されるキュー
 */
void toggleResetDown() {
    DEBUG("ResetDown\r\n");
    DEBUG("パスワードのリセットを行います\r\n");
    //リセットパスワードの書き込み
    FILE *fp = fopen("/sd/sdtest.txt", "w");
    if(fp == NULL) {
        DEBUG("Could not open file for write\n");
    }else{
        fprintf(fp, "00\n00\n00\n00\n00\n00\n");
        fclose(fp);
    } 
    
    //パスワード登録状態のリセット
    authenticationInformation = false;
    initServicePtr->stateUpdate(0x00);
    //パスワード認証状態のリセット
    authenticated=false;
    stateServicePtr->authStateUpdate(0x00);
    eventQueue.call(&passwordResetAlertStart);
    DEBUG("パスワードのリセットが完了しました\r\n");
}

/**
 *リセットボタン
 *タクトスイッチが離されたときに実行される関数
 */
void resetDown() {
    // 即実行されるイベント
    eventQueue.call(&toggleResetDown);
}

/**
 * Bluetooth接続時の操作
 */
void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
{   
    char mac[6];
    DEBUG("peerMAC:%d\r\n",params->peerAddr);
    DEBUG("peerMAC_length:%d\r\n",sizeof(params->peerAddr));
    DEBUG("peerMAC:");
    for(int i = 0;i<sizeof(params->peerAddr);i+=1){
        mac[i]=params->peerAddr[i];
        DEBUG("%02x ", params->peerAddr[i]);
    }
    DEBUG("\r\n");
    
    /*
    DEBUG("peerArrayMAC:%d\r\n",mac);
    DEBUG("peerArrayMAC_length:%d\r\n",sizeof(mac));
    DEBUG("peerArrayMAC:");
    for(int i = 0;i<sizeof(mac);i+=1){
        DEBUG("%d ", mac[i]);
    }
    DEBUG("\r\n");
    */
    
    DEBUG("ownAddrMAC:%d\r\n",params->ownAddr);
    DEBUG("ownAddrMAC_length:%d\r\n",sizeof(params->ownAddr));
    DEBUG("ownAddrMAC:");
    for(int i = 0;i<sizeof(params->ownAddr);i+=1){
        DEBUG("%d ", params->ownAddr[i]);
    }
    DEBUG("\r\n");
    
    
    eventQueue.call(&connectAlertStart);
        
    DEBUG("BluetoothConnection!\r\n");
}

/**
 * Bluetooth切断時の操作
 */
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
    (void) params;
    //認証状態の無効化
    authenticated = false;
    stateServicePtr->authStateUpdate(0x00);
    //USBの無効化
    actuatedLED = 0x00;
    stateServicePtr->usbStateUpdate(0x00);
    
    BLE::Instance().gap().startAdvertising();
    
    eventQueue.call(&disconnectAlertStart);
    DEBUG("BluetoothDisconnection!\r\n");
}

/**
 *動作確認ランプの状態変更
 */
void blinkCallback(void)
{
    alivenessLED = !alivenessLED; /* Do blinky on LED1 to indicate system aliveness. */
}


/**
 *パスワードSDカード書き込み
 *パスワードが変更されたときに実行されるキュー
 */
void writeSD() {
    //SDへの書き込み処理
    DEBUG("SDカードを開きます\r\n");
    FILE *fp = fopen("/sd/sdtest.txt", "w");
    if(fp == NULL) {
        DEBUG("Could not open file for write\n");
    }else{
        for(int i = 0;i<sizeof(password);i+=1){
            fprintf(fp,"%02x", password[i]);
            fprintf(fp, "\n");
        }
        fclose(fp);
    }
    DEBUG("SDカードを閉じます\r\n");
}

/**
 * This callback allows the LEDService to receive updates to the ledState Characteristic.
 * LEDサービスにて状態変更を受信した際に呼び出されるコールバック
 *
 * @param[in] params
 *     Information about the characterisitc being updated.
 */
void onDataWrittenCallback(const GattWriteCallbackParams *params) {
    DEBUG("onDataWrittenCallback:");
    
    if (params->handle == initServicePtr->getValueHandle()) {
        DEBUG("INITService\r\n");
        DEBUG("length:%d\r\n",params->len);
        for(int i = 0;i<params->len;i+=1){
            DEBUG("%02x ", params->data[i]);
        }
        DEBUG("\r\n");
        
        //認証情報の確認
        if(authenticationInformation){
            //認証情報が登録されていた場合は登録を行わない
            DEBUG("認証情報登録済みのため、認証情報の登録を中止します\r\n");
            return;    
        }
        
        DEBUG("認証情報の登録を開始します\r\n");
        
        for(int i = 0;i<params->len;i+=1){
            password[i] = params->data[i];
        }
        
        DEBUG("PasswordLength:%d\r\n",sizeof(password));
        for(int i = 0;i<sizeof(password);i+=1){
            DEBUG("%02x ", password[i]);
        }
        DEBUG("\r\n");
        
        authenticationInformation = true;
        initServicePtr->stateUpdate(0x01);
        
        
        // 即実行されるイベント
        eventQueue.call(&writeSD);
        
        DEBUG("認証情報の登録を終了します\r\n");
        return;
    }
    
    if(!authenticationInformation){
        //認証情報が登録されていない場合は操作を行わない
        DEBUG("\r\n認証情報未登録のため、操作を中止します\r\n");
        return;    
    }
    
    if (params->handle == pinServicePtr->getValueHandle()) {
        DEBUG("PINService\r\n");
        DEBUG("length:%d\r\n",params->len);
        for(int i = 0;i<params->len;i+=1){
            DEBUG("%02x ", params->data[i]);
        }
        DEBUG("\r\n");
        
        DEBUG("認証を開始します\r\n");
        DEBUG("VerificationLength:%d\r\n",params->len);
        DEBUG("RegisterLength:%d\r\n",sizeof(password));
        if(params->len != sizeof(password)){
            eventQueue.call(&authErrorAlertStart);
            DEBUG("認証に失敗しました\r\n");
            return;
        }
        DEBUG("Verification:Register\r\n");
        for(int i = 0;i<params->len;i+=1){
            DEBUG("%02x", params->data[i]);
            DEBUG(":");
            DEBUG("%02x", password[i]);
            DEBUG("\r\n");
            if(params->data[i]!= password[i]){
                DEBUG("認証に失敗しました\r\n");
                eventQueue.call(&authErrorAlertStart);
                return;
            }
        }
        authenticated=true;
        stateServicePtr->authStateUpdate(0x01);
        DEBUG("認証が完了しました\r\n");
        return;
    }
    
    if(!authenticated){
        //認証が行われていない場合は操作を行わない
        DEBUG("\r\n認証がされていないため、操作を中止します\r\n");
        return;    
    }
    
    if ((params->handle == usbServicePtr->getValueHandle()) && (params->len == 1)) {
        
        DEBUG("USBService\r\n");
        DEBUG("length:%d\r\n",params->len);
        for(int i = 0;i<params->len;i+=1){
            DEBUG("%d ", params->data[i]);
        }
        DEBUG("\r\n");
        
        actuatedLED = *(params->data);
        stateServicePtr->usbStateUpdate(*(params->data));
        
        if(params->data[0] == 1){
            eventQueue.call(&enableUSBAlertStart);    
        }else if(params->data[0] == 0){
            eventQueue.call(&disableUSBAlertStart);    
        }
        return;
    }
}

/**
 * This function is called when the ble initialization process has failled
 * BLEの初期化失敗のコールバック
 */
void onBleInitError(BLE &ble, ble_error_t error)
{
    DEBUG("BluetoothError!\r\n");
    /* Initialization error handling should go here */
}

/**
 * Callback triggered when the ble initialization process has finished
 * BLEの初期化が完了したときに呼び出されるコールバック
 */
void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
{
    BLE&        ble   = params->ble;
    ble_error_t error = params->error;

    if (error != BLE_ERROR_NONE) {
        /* In case of error, forward the error handling to onBleInitError */
        /* エラーがあった場合はここから上の'onBleInitError'が呼び出される */
        onBleInitError(ble, error);
        return;
    }

    /* Ensure that it is the default instance of BLE */
    /* BLEのデフォルトインスタンスであることを確認 */
    if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
        return;
    }

    ble.gap().onDisconnection(disconnectionCallback);
    ble.gap().onConnection(connectionCallback);
    ble.gattServer().onDataWritten(onDataWrittenCallback);

    bool initialValueForUSBUSBCharacteristic = false;
    usbServicePtr = new USBService(ble, initialValueForUSBUSBCharacteristic);
    
    char initialValueForPINPINCharacteristic[] = {0x00,0x00,0x00,0x00,0x00,0x00};
    pinServicePtr = new PINService(ble, initialValueForPINPINCharacteristic);
    
    char initialValueForSTATEAUTHCharacteristic = 0x00;
    char initialValueForSTATEPOWERCharacteristic = 0x00;
    char initialValueForSTATEUSBCharacteristic = 0x00;
    stateServicePtr = new STATEService(ble, initialValueForSTATEAUTHCharacteristic, initialValueForSTATEPOWERCharacteristic, initialValueForSTATEUSBCharacteristic);
    
    char initialValueForINITSETCharacteristic[] = {0x00,0x00,0x00,0x00,0x00,0x00};
    char initialValueForINITGETCharacteristic = authenticationInformation;
    initServicePtr = new INITService(ble, initialValueForINITSETCharacteristic,initialValueForINITGETCharacteristic);

    /* setup advertising */
    /* BLEクライアントへの広告の設定 */
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));    
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.gap().setAdvertisingInterval(1000); /* 1000ms. */
    ble.gap().startAdvertising();
    
    DEBUG("BluetoothStart!\r\n");
    
    eventQueue.call(&startupAlertStart);
}

void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
    BLE &ble = BLE::Instance();
    eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
}


/**
 *機器状態デバッグ用出力
 *機器状態を定期的に出力するためのキュー
 */
void echoUsbsecState(){
    DEBUG("USBSec is in operation\r\n");
    DEBUG("Password regist state : %d\r\n",authenticationInformation);
    DEBUG("Password auth state : %d\r\n",authenticated);
    /*DEBUG("USB state : %d\r\n",actuatedLED);
    DEBUG("Speaker ECO state : %d\r\n",speakerD);*/
    
    eventQueue.call_in(5000.0f, &echoUsbsecState);
}

int main()
{    
    //SDカードパスワードの取得
    char charpass;//SDカードから取得されたパスワード
    FILE *fp = fopen("/sd/sdtest.txt", "r");
    if(fp == NULL) {
        DEBUG("Could not open file for write\n");
    }else{
        int passwordindex = 0;
        //パスワードを取り出しパスワード変数へ
        while( fscanf( fp, "%02x",&charpass  ) != EOF ){
            DEBUG("%02x\r\n",charpass);
            password[passwordindex] = charpass;
            passwordindex+=1;
        }
        fclose(fp); 
    }
    
    //起動時の認証情報状態の設定
    authenticationInformation = false;
    DEBUG("PasswordLength:%d\r\n",sizeof(password));
    for(int i = 0;i<sizeof(password);i+=1){
        DEBUG("%d ", password[i]);
        if(password[i] != 0x00){
            authenticationInformation = true;
        }
    }
    DEBUG("\r\n");
    
    powerSwitch.mode(PullUp);//パワー検出コード_スイッチピンをPullUpに
    powerSwitch.fall(&powerUp);//パワー検出コード_スイッチが押されたときの割り込み処理
    powerSwitch.rise(&powerDown);//パワー検出コード_スイッチが離されたときの割り込み処理
    
    resetSwitch.mode(PullUp);//リセットボタン_スイッチピンをPullUpに
    resetSwitch.rise(&resetDown);//リセットボタン_スイッチが離されたときの割り込み処理
    
    eventQueue.call_every(500, blinkCallback);

    //デバッグ用ステート確認
    eventQueue.call_in(5000.0f, &echoUsbsecState);

    BLE &ble = BLE::Instance();
    ble.onEventsToProcess(scheduleBleEventsProcessing);
    ble.init(bleInitComplete);
    
    //パスワード設定情報のBluetoothへの反映
    if(authenticationInformation){
        initServicePtr->stateUpdate(0x01);
    }

    eventQueue.dispatch_forever();
    
    return 0;
}