UMEHOSHI ITA TOP PAGE    COMPUTER SHIEN LAB

UMEHOSHI IT (my_app.cとmy_app.h)

my_app.cとmy_app.hの概要

「テスト・ウメ・フラッシュ」はUSBからのコマンドなどをを受信して制御するスタイルになっています。
これを担うのが、『app.c』から呼び出される_my_app_tasks();のマクロで、 デフォルトの起動時の呼び出しがここで示すMy_APP_Tasks()関数です。
(スルーモードの起動時は、My_APP_Tasks_Through())関数呼び出しに変わります。)

このMy_APP_Tasks()では、受信したら速やかにコマンド解析して、 なんらかの処理をした後に必要に応じてUSBへ出力するスタイルです。
速やかに行わせるために「テスト・ウメ・フラッシュ」で、USB受信のアプリケーションレベルにおける バッファリングをしていません。
受信したら速やかに、「my_usb_com.cのset_recive_data関数」へデータを渡して対応処理をしています。
 (なお、MPLAB HarmonyによるUSBのシステムコードに64byteの受信バッファが存在します。)
対してUSBの出力のアプリケーションレベルで「my_usb_com.cのoutBuffers[OB_MAX][OB_SIZE]」を使ってバッファリングしています。
My_APP_Tasks()では、このバッファ「outBuffers」に出力情報があれば、USBに出力する仕組みを作っています。

またMy_APP_Tasks()関数中では、「my_uart.cのrecive_and_send_uart_with_polling()」を実行しており、 次のようなことを容易する仕組みが提供されています。
  1. UARTからの送受信をUSB送受信の代わりに使う。
  2. USBから受信データをUARTへ送信し、UARTからの受信データをUSBへ送信する。(この状態を[スルーモード]と呼びます)
  3. USBとUARTの間で、データを加工して受け渡しのプログラムを作る。
デフォルト起動では上記の[ 1.]の状態になります。またデフォルトで、SW2を長押し(2秒)の起動をすると[ 2.]のスルーモードになります。

上記を実現しているMy_APP_Tasks()の基本的な動作の流れを説明します。
基本的には、変数appData.stateに応じた処理で,次の手順です。

USB受信処理です。
appData.stateが、APP_STATE_SCHEDULE_READの時、
appData.isReadComplete = false;にして、USB_DEVICE_CDC_Read関数で、 引数で指定したバッファへUSBからの読み込みを指示して、
 appData.isReadComplete = false;にします。
そして、appData.stateをAPP_STATE_WAIT_FOR_READ_COMPLETEにしてUSB受信の終了を待ちます。
これは、イベント処理(APP_USBDeviceCDCEventHandler関数)によりこのUSB受信が完了して、
 appData.isReadComplete が trueになるのを待つ状態です。

USB受信が完了して、appData.stateがAPP_STATE_WAIT_FOR_READ_COMPLETEでappData.isReadCompleteがtrueになれば、
受信処理として、「my_usb_com.cのset_recive_data関数」へデータを渡して対応処理をしています。

USB送信処理です。
appData.stateが、APP_STATE_SCHEDULE_WRITEの時、
appData.isReadComplete = false;にして、USB_DEVICE_CDC_Write関数で、 引数で指定したバッファをUSBへ出力する指示をして、
 appData.isWriteComplete = false;にします。
そして、appData.stateをAPP_STATE_WAIT_FOR_WRITE_COMPLETEにしてUSB受信の終了を待ちます。
これは、イベント処理(APP_USBDeviceCDCEventHandler関数)によりこのUSB受信が完了して、
 appData.isWriteComplete が trueになるのを待つ状態です。

USB送信が完了して、appData.stateがAPP_STATE_WAIT_FOR_WRITE_COMPLETEでappData.isWriteCompleteがtrueになれば、
送信処理が終わったとして、「my_usb_com.cのnoticeSendCcomplete関数」でUSBバッファの更新処理をしています。

以上のようにappData.stateにAPP_STATE_SCHEDULE_READを設することで受信を促し、
    APP_STATE_SCHEDULE_WRITEを設することで送信を促します。
それでは 送信を促した後で、その完了前に受信を促す必要がある場合にどうするか?
  (送信を促した後で、その完了前に受信を促す必要がある場合にどうするか? また現状でどちらを優先するか?)
などがの考慮すべき処理が必要になります。その対応は次のようにしています。
  1. 初期化後の基本スケージュールはUSB受信の予約であるが、 USB送信バッファにデータがあればUSB送信を優先にスケジュールする。
    (USB送信バッファにデータがなければUSB受信を優先してスケージュールを予約)
  2. 受信がスケージュールされると、それが完了するまで次の受信スケージュールができない制御をする。
    また同様に、送信がスケージュールされると、それが完了するまで次の送信スケジュールはできない。
  3. 受信がスケージュールされると、それが完了しなくても送信のスケージュールを、可能にする。
    送信がスケージュールされると、それが完了したタイミングで、受信のスケージュールを予約する。
    (受信スケージュールと受信スケージュールの両立を可能にするため、 flag_APP_STATE_WAIT_FOR_READ_COMPLETEとflag_APP_STATE_WAIT_FOR_WRITE_COMPLETEの識別変数を用意する)
  4. (i)〜(iii)により、送信が優先されて、受信のスケジュールできないケースが生じるのを防ぐカウンタ制御を行う。


UARTのポーリング処理(recive_and_send_uart_with_polling()関数呼び出し)が含まれて、次のような処理が付加されています。
  • アプリケーションレベルでUAR1の送信バッファを持ち、そのUART送信バッファにデータが在る時、 UART1をポーリングで送信が可能であれば、recive_and_send_uart_with_polling()内でUSB送信処理をしています。
  • [Tコマンド]による「スルーモード時」は、USBからの受信したデータはUAR1の送信バッファにセットされます。
    この「スルーモード」や「UARTコマンドモード」でない場合は、_send_uart1(c)マクロでUAR1の送信バッファにセットできます。
  • [Tコマンド]による「スルーモード時」は、UART1をポーリングで、受信データがあればUSBの送信バッファに入れて送信を促していいます。 (この時受信データがあれば、すぐにUSB送信バッファに入れるので、アプリケーションレバルのUAR1受信バッファを用意していません。)
    この「スルーモード」や「UARTコマンドモード」でない場合は、置き換え可能な_recv_uart1(c)マクロが呼び出されています。

my_app.hのソース

#ifndef _MY_APP_H    /* Guard against multiple inclusion */
#define _MY_APP_H

#include "app.h"

#define APP_READ_BUFFER_SIZE 64

/* Macro defines USB internal DMA Buffer criteria */
#define APP_MAKE_BUFFER_DMA_READY 

/* USB read buffer */
extern uint8_t APP_MAKE_BUFFER_DMA_READY readBuffer[APP_READ_BUFFER_SIZE]
        __attribute__((coherent, aligned(16)));

extern APP_DATA appData;

extern int usb_receiver_disable_flag;//受信を無効にするフラグ.
// USBから長いブロックデータを送信する場合、これを一時的にセットして制御.

// デバイスのイベントハンドラ
void APP_USBDeviceEventHandler 
        ( USB_DEVICE_EVENT event, void * eventData, uintptr_t context );

bool APP_State_Reset(void); // My_APP_Tasks内のリセット時処理

void Init_Usb( void ); // USBの初期設定

void My_APP_Tasks ( void ); // USBの状態遷移に対する分岐処理関数

void My_APP_Tasks_Through ( void ); //USBとUART間で伝達するだけのUSB分岐処理関数


#define MY_APP_ERR_IS_READ_COMPLETE 0x0001 // USBへの受信完了状態エラー
#define MY_APP_ERR_IS_WRITE_COMPLETE 0x0002 // USBへの送信完了状態エラー
#define MY_APP_ERR_STATE 0x0004 // USBへの状態エラー
#define MY_APP_ERR_DEFAULT 0x0008 // USB defaultエラー

#endif /* _MY_APP_H*/

my_app.hのソース

#include "my_app.h"
#include "my_usb_cmd.h"
#include <xc.h>
#include "my_sys.h"
#include "my_uart.h"
#include "common.h"

#define countermeasure_wait_parameter 200000 //矛盾処理対策待機パラメータ(実験値)

/* USB read buffer */
uint8_t APP_MAKE_BUFFER_DMA_READY readBuffer[APP_READ_BUFFER_SIZE]
        __attribute__((coherent, aligned(16)));
// coherent の指定は、バッファにキャッシュ(変数の配置場所を指定))

bool flag_APP_STATE_WAIT_FOR_READ_COMPLETE = false;
bool flag_APP_STATE_WAIT_FOR_WRITE_COMPLETE = false;

int usb_receiver_disable_flag = 0;//受信を無効にするフラグ
// USBから長いブロックデータを送信する場合、これを一時的にセットして制御
// これが1の場合は、エコーもしない状態になる。!★

uint16_t my_app_err=0;// my_app.c でのエラー情報
int my_app_set_err( uint16_t d){// 上記エラー情報への設定関数
    my_app_err |= d;
}

/*******************************************************************************
 * USB CDC Device Events - Application Event Handler
 * ( callback functions)
 ******************************************************************************/

USB_DEVICE_CDC_EVENT_RESPONSE APP_USBDeviceCDCEventHandler
(
    USB_DEVICE_CDC_INDEX index ,
    USB_DEVICE_CDC_EVENT event ,
    void * pData,
    uintptr_t userData
)
{
    APP_DATA * appDataObject;
    appDataObject = (APP_DATA *)userData;
    USB_CDC_CONTROL_LINE_STATE * controlLineStateData;
    USB_DEVICE_CDC_EVENT_DATA_READ_COMPLETE * eventDataRead; 

    switch ( event )
    {
        case USB_DEVICE_CDC_EVENT_GET_LINE_CODING:

            /* This means the host wants to know the current line
             * coding. This is a control transfer request. Use the
             * USB_DEVICE_ControlSend() function to send the data to
             * host.  */
            USB_DEVICE_ControlSend(appDataObject->deviceHandle,
                    &appDataObject->getLineCodingData, sizeof(USB_CDC_LINE_CODING));

            break;

        case USB_DEVICE_CDC_EVENT_SET_LINE_CODING:

            /* This means the host wants to set the line coding.
             * This is a control transfer request. Use the
             * USB_DEVICE_ControlReceive() function to receive the
             * data from the host */

            USB_DEVICE_ControlReceive(appDataObject->deviceHandle,
                    &appDataObject->setLineCodingData, sizeof(USB_CDC_LINE_CODING));

            break;

        case USB_DEVICE_CDC_EVENT_SET_CONTROL_LINE_STATE:

            /* This means the host is setting the control line state.
             * Read the control line state. We will accept this request
             * for now. */

            controlLineStateData = (USB_CDC_CONTROL_LINE_STATE *)pData;
            appDataObject->controlLineStateData.dtr = controlLineStateData->dtr;
            appDataObject->controlLineStateData.carrier = controlLineStateData->carrier;

            USB_DEVICE_ControlStatus(appDataObject->deviceHandle, USB_DEVICE_CONTROL_STATUS_OK);

            break;

        case USB_DEVICE_CDC_EVENT_SEND_BREAK:

            /* This means that the host is requesting that a break of the
             * specified duration be sent. Read the break duration */
            appDataObject->breakData = ((USB_DEVICE_CDC_EVENT_DATA_SEND_BREAK *)pData)->breakDuration;
            
            /* Complete the control transfer by sending a ZLP  */
            USB_DEVICE_ControlStatus(appDataObject->deviceHandle, USB_DEVICE_CONTROL_STATUS_OK);
            
            break;

        case USB_DEVICE_CDC_EVENT_READ_COMPLETE:

            /* This means that the host has sent some data */
            eventDataRead = (USB_DEVICE_CDC_EVENT_DATA_READ_COMPLETE *)pData;
            appDataObject->isReadComplete = true;
            appDataObject->numBytesRead = eventDataRead->length; 
            break;

        case USB_DEVICE_CDC_EVENT_CONTROL_TRANSFER_DATA_RECEIVED:

            /* The data stage of the last control transfer is
             * complete. For now we accept all the data */
            USB_DEVICE_ControlStatus(appDataObject->deviceHandle, USB_DEVICE_CONTROL_STATUS_OK);
            break;

        case USB_DEVICE_CDC_EVENT_CONTROL_TRANSFER_DATA_SENT:

            /* This means the GET LINE CODING function data is valid. We dont
             * do much with this data in this demo. */
            break;

        case USB_DEVICE_CDC_EVENT_WRITE_COMPLETE:

            /* This means that the data write got completed. We can schedule
             * the next read. */
            appDataObject->isWriteComplete = true;
            break;

        default:
            break;
    }

    return USB_DEVICE_CDC_EVENT_RESPONSE_NONE;
}


/******************************************************************************
 * Application USB Device Layer Event Handler.
 * This is the callback functions used by APP_Tasks of app.c 
 ******************************************************************************/
void APP_USBDeviceEventHandler ( USB_DEVICE_EVENT event, void * eventData, uintptr_t context )
{
    USB_DEVICE_EVENT_DATA_CONFIGURED *configuredEventData;
    switch ( event )
    {
        case USB_DEVICE_EVENT_SOF:
            /* This event is used for switch debounce. This flag is reset
             * by the switch process routine. */
            appData.sofEventHasOccurred = true;
            break;

        case USB_DEVICE_EVENT_RESET:
            appData.isConfigured = false;
            break;

        case USB_DEVICE_EVENT_CONFIGURED:
            
            /* Check the configuratio. We only support configuration 1 */
            configuredEventData = (USB_DEVICE_EVENT_DATA_CONFIGURED*)eventData;
            if ( configuredEventData->configurationValue == 1)
            {
                /* Register the CDC Device application event handler here.
                 * Note how the appData object pointer is passed as the
                 * user data */
                USB_DEVICE_CDC_EventHandlerSet(USB_DEVICE_CDC_INDEX_0, APP_USBDeviceCDCEventHandler, (uintptr_t)&appData);
                /* Mark that the device is now configured */
                appData.isConfigured = true;
            }
            break;

        case USB_DEVICE_EVENT_POWER_DETECTED:
            /* VBUS was detected. We can attach the device */
            USB_DEVICE_Attach(appData.deviceHandle);
            break;

        case USB_DEVICE_EVENT_POWER_REMOVED:
            /* VBUS is not available any more. Detach the device. */
            USB_DEVICE_Detach(appData.deviceHandle);
            break;

        case USB_DEVICE_EVENT_SUSPENDED:
            break;

        case USB_DEVICE_EVENT_RESUMED:
            break;
            
        case USB_DEVICE_EVENT_ERROR:
            break;
            
        default:
            break;
    }
}
//------------------------------------------------------------------------------


/*******************************************************************************
 * Initilaize USB functions
 ******************************************************************************/
void Init_Usb( void )
{
    /* Device Layer Handle  */
    appData.deviceHandle = USB_DEVICE_HANDLE_INVALID ;

    /* Device configured status */
    appData.isConfigured = false;

    /* Initial get line coding state */
    //appData.getLineCodingData.dwDTERate = 115200;
    appData.getLineCodingData.dwDTERate = _UME_USB_CDC_DATE;
    /* 標準のボー レートは、110、300、600、1200、2400、4800、9600、14400、
     *         19200、38400、57600、115200、128000、256000 ビット/秒
     */
    appData.getLineCodingData.bParityType =  0;
    appData.getLineCodingData.bDataBits = 8;
    
    /* Read Transfer Handle */
    appData.readTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;

    /* Write Transfer Handle */
    appData.writeTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;

    /* Intialize the read complete flag */
    appData.isReadComplete = true;

    /*Initialize the write complete flag*/
    appData.isWriteComplete = true;

    /* Initialize Ignore switch flag */
    appData.ignoreSwitchPress = false;

    /* Reset the switch debounce counter */
    appData.switchDebounceTimer = 0;

    /* Reset other flags */
    appData.sofEventHasOccurred = false;
    appData.isSwitchPressed = false;

    /* Set up the read buffer */
    appData.readBuffer = &readBuffer[0];
}

/******************************************************************************
 * This function returns true if the device was reset
 * This function is called in every step of the application state machine.
 * called by My_APP_Tasks (Local Functions)  
 *****************************************************************************/
bool APP_State_Reset(void)
{
    bool retVal;
    if(appData.isConfigured == false) {
        appData.state = APP_STATE_WAIT_FOR_CONFIGURATION;
        appData.readTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
        appData.writeTransferHandle = USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
        appData.isReadComplete = true;
        appData.isWriteComplete = true;
        
        flag_APP_STATE_WAIT_FOR_READ_COMPLETE = false;
        flag_APP_STATE_WAIT_FOR_WRITE_COMPLETE = false;
        retVal = true;
        
        init_outBuffers();// ★ USB出力用リングバッファ用変数の初期化
        
    } else  {
        retVal = false;
    }
    return(retVal);
}


/******************************************************************************
  Extension function of APP_Tasks
 ******************************************************************************/
void My_APP_Tasks( void ){

    static USB_DEVICE_CDC_RESULT result;
    
    check_uart_error();// UARTエラーチェック

    error_notice_beep();//エラーがあれば通知する
    
    // 関数実行要求のが合って、送信文字列が無ければ実行
    extern void (*go_func)(void);
    if(go_func != NULL){
        if(outBuffCount == 0){ 
            (*go_func)();// 関数実行要求の実行  
            go_func = NULL;
        }
    }
    
    // CDC は非同期通信なので、HOSTが受け取るべきタイミングで受け取ることを期待して
    // 制御している。しかし連続して高速にHOSTに送る処理があると、HOSTが情報を
    // 取り損なうケースが生じる。
    // この時不具合時、appData.isWriteCompleteは、falseのままで、
    // flag_APP_STATE_WAIT_FOR_WRITE_COMPLETEは、trueのままで、
    // 送信が終わるの待つシーケンスから抜けることができなくなる。
    // そこで、そうなった時に知らせる次のモードを作る。  
    static bool wait_WriteComplete_Error = false;
    // これがTrueになると、D1のLED を点滅を行う。
    static int wait_WriteComplete_Error_count = 0;
    if(wait_WriteComplete_Error){
        if(++wait_WriteComplete_Error_count > countermeasure_wait_parameter){
            wait_WriteComplete_Error_count = 0;
            _RB15 = ! _RB15;// エラーLED点滅
        }
    }
    // 上記wait_WriteComplete_Errorモードは、次のカウンターの値で判断する。 
    static int check_wait_WriteComplete_count = 0;
    // この変数は、appData.isWriteCompleteがfalseでクリアされる。
    
    _def_polls_uart();//UARTのデフォルトポーリング送受信処理
    // このマクロのデフォルト呼び出しは「recive_and_send_uart_with_polling();//」
    
    // USBへの送信データがoutBuffersのバッファにあるならUSB送信を促す
    requset_send_usb_if_available();// USBへの送信データがあるならUSB送信を促す  
    
    static int no_read_task_count=0;
    no_read_task_count++;
    
    // USB送信バッファにデータがあればUSB送信を優先にスケジュールする.
    if( (appData.state == APP_STATE_SCHEDULE_READ
            || appData.state == APP_STATE_WAIT_FOR_READ_COMPLETE) 
            && outBuffCount > 0
            && ! flag_APP_STATE_WAIT_FOR_WRITE_COMPLETE
            //&& no_read_task_count < 100
        ){
            appData.state = APP_STATE_SCHEDULE_WRITE;
    }
         
    /* Check the application's current state. */
    switch ( appData.state )
    {
        case APP_STATE_WAIT_FOR_CONFIGURATION:
            /* Check if the device was configured */
            if(appData.isConfigured) {// デバイスが設定された?

                /* If the device is configured then lets start reading */
                appData.state = APP_STATE_SCHEDULE_READ;
            }
            break;
 
        case APP_STATE_SCHEDULE_READ:
            if(APP_State_Reset()) {
                break;
            }
            no_read_task_count = 0;

            /* If a read is complete, then schedule a read
             * else wait for the current read to complete */        
            if( ! appData.isReadComplete ){// 受信状態エラー
                 my_app_set_err(MY_APP_ERR_IS_READ_COMPLETE);
            } else {               
                appData.isReadComplete = false;
                appData.readTransferHandle =  USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
                appData.state = APP_STATE_WAIT_FOR_READ_COMPLETE;
                flag_APP_STATE_WAIT_FOR_READ_COMPLETE = true;

                result = USB_DEVICE_CDC_Read (USB_DEVICE_CDC_INDEX_0,
                        &appData.readTransferHandle, appData.readBuffer,
                        APP_READ_BUFFER_SIZE);
                
                if( result != USB_DEVICE_CDC_RESULT_OK || 
                   appData.readTransferHandle == USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID)
                {
                    appData.state = APP_STATE_ERROR;
                }
            }
            break;

        case APP_STATE_SCHEDULE_WRITE:
            if(APP_State_Reset()){
                break;
            }
            
            if( request_acc_outbuff(_ID_ACCESS_USBTASK)  == false) break;
            uint8_t *pSendBuff = getSendBuff();//送信バッファ取得
            // (上記でグローバル変数numbOutputs送信文字数にセット
            //accessing_outbuffer &= ~_ID_ACCESS_USBTASK;//出力バッフ利用終了                    
            release_acc_outbuff(_ID_ACCESS_USBTASK);
            
            if( ! appData.isWriteComplete || numbOutputs == 0){// USBへの送信完了状態エラー
                my_app_set_err(MY_APP_ERR_IS_WRITE_COMPLETE);
                break;
            }            

            appData.writeTransferHandle= USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
            appData.isWriteComplete = false;
            appData.state = APP_STATE_WAIT_FOR_WRITE_COMPLETE;
            flag_APP_STATE_WAIT_FOR_WRITE_COMPLETE = true;             
            result = USB_DEVICE_CDC_Write(USB_DEVICE_CDC_INDEX_0,
                    &appData.writeTransferHandle,
                    //appData.readBuffer, appData.numBytesRead,//出力位置とサイズ
                    pSendBuff,numbOutputs,
                    USB_DEVICE_CDC_TRANSFER_FLAGS_DATA_COMPLETE
            );
            if( result != USB_DEVICE_CDC_RESULT_OK ||
                 appData.writeTransferHandle==USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID){
                appData.state = APP_STATE_ERROR;
            }
            break;          
            
        case APP_STATE_WAIT_FOR_READ_COMPLETE:
        case APP_STATE_WAIT_FOR_WRITE_COMPLETE:
            if(APP_State_Reset()) {
                break;
            }
                
            /* The isReadComplete flag gets updated in the CDC event handler. */
            if( flag_APP_STATE_WAIT_FOR_READ_COMPLETE
                    && ! usb_receiver_disable_flag 
                    && appData.isReadComplete == true){// USB受信完了
                int wait=countermeasure_wait_parameter;
                while( request_acc_outbuff(_ID_ACCESS_USBTASK)  == false) {
                    //出力バッフ利用許可を待つ
                    if(wait-- <= 0)return;
                }
                int i;
                for(i=0; i < appData.numBytesRead; i++){
                    if(set_recive_data(
                            appData.readBuffer[i],
                            i+1 == appData.numBytesRead // 繰り返し最後ならtrue
                            ) == 'W'){
                    }
                }
                flag_APP_STATE_WAIT_FOR_READ_COMPLETE = false;
                if( flag_APP_STATE_WAIT_FOR_WRITE_COMPLETE ){
                    appData.state = APP_STATE_WAIT_FOR_WRITE_COMPLETE;
                }
            } 
            
            /* Check if a character was sent. 
             * The isWriteComplete flag gets updated in the CDC event handler */
            if(flag_APP_STATE_WAIT_FOR_WRITE_COMPLETE){
                if(appData.isWriteComplete == true){// USB受信完了
                    int wait=countermeasure_wait_parameter;
                    while( request_acc_outbuff(_ID_ACCESS_USBTASK)  == false) {
                        //出力バッフ利用許可を待つ
                        if(wait-- <= 0)return;
                    }
                    // 送信処理が終わった通知]に対する処理
                    noticeSendCcomplete();//(numbOutputs送信文字数が0に戻している)   
                    flag_APP_STATE_WAIT_FOR_WRITE_COMPLETE = false;
                    check_wait_WriteComplete_count = 0;
                    if( flag_APP_STATE_WAIT_FOR_READ_COMPLETE ){
                        appData.state = APP_STATE_WAIT_FOR_READ_COMPLETE;
                    }
                } else if(++check_wait_WriteComplete_count > countermeasure_wait_parameter){
                    wait_WriteComplete_Error = true;// HOSTが遅いエラー!
                }
            }
            
            //accessing_outbuffer &= ~_ID_ACCESS_USBTASK;//出力バッフ利用終了
            release_acc_outbuff(_ID_ACCESS_USBTASK);
            
            if(flag_APP_STATE_WAIT_FOR_READ_COMPLETE == false
                    && flag_APP_STATE_WAIT_FOR_WRITE_COMPLETE  == false ){
                appData.state = APP_STATE_SCHEDULE_READ;
            }
            break;
            
        case APP_STATE_ERROR:
            my_app_set_err(MY_APP_ERR_STATE);

        default:
            my_app_set_err(MY_APP_ERR_DEFAULT);
            ;
    }
}

//USBとUART間で伝達するだけのUSB分岐処理関数
void My_APP_Tasks_Through ( void )
{
    // UARからの受信 そして、USBへの送信バッファ
    static uint8_t * recUartBuff = (uint8_t *) outBuffers; 
    static int recSize=0;

    static USB_DEVICE_CDC_RESULT result;
       
    check_uart_error();// UARTエラーチェック
    
    error_notice_beep();//エラーがあれば通知する
    
    // 起動時の受信を無視して、"\r\n"のメッセージを1回だけ送出する.
    if( reply_boot_message() ) {
        for(;;){// UARTからの受信をポーリングで、受信データがあればバッファに記憶
            if(U1STAbits.URXDA == 0) {
                break;//  UART信バッファ内にデータが存在しない?
            }
            uint8_t c = U1RXREG; //  UART受信データ取得
            ringbuf_set_data( & uartRecBuf, c);
        }
    }
    
    if( ringbuf_is_read( & uartRecBuf ) > 0 
        && appData.isConfigured // デバイスが設定済み
        && ! flag_APP_STATE_WAIT_FOR_WRITE_COMPLETE ){
            appData.state = APP_STATE_SCHEDULE_WRITE;// USB出力
    }
    
    /* Check the application's current state. */
    switch ( appData.state )
    {
        case APP_STATE_WAIT_FOR_CONFIGURATION:
            /* Check if the device was configured */
            if(appData.isConfigured) {// デバイスが設定された?

                /* If the device is configured then lets start reading */
                appData.state = APP_STATE_SCHEDULE_READ;
            }
            break;
 
        case APP_STATE_SCHEDULE_READ:
            if(APP_State_Reset()) {
                break;
            }
                            
            /* If a read is complete, then schedule a read
             * else wait for the current read to complete */         
            if( ! appData.isReadComplete ){// 受信状態エラー
                 my_app_set_err(MY_APP_ERR_IS_READ_COMPLETE);
            } else {               
                appData.isReadComplete = false;
                appData.readTransferHandle =  USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
                appData.state = APP_STATE_WAIT_FOR_READ_COMPLETE;

                result = USB_DEVICE_CDC_Read (USB_DEVICE_CDC_INDEX_0,
                        &appData.readTransferHandle, appData.readBuffer,
                        APP_READ_BUFFER_SIZE);
                
                if( result == USB_DEVICE_CDC_RESULT_OK ) {
                    flag_APP_STATE_WAIT_FOR_READ_COMPLETE = true;           
                } else {
                    appData.state = APP_STATE_ERROR;                    
                }
            }
            break;

        case APP_STATE_WAIT_FOR_READ_COMPLETE:
            if(APP_State_Reset()) {
                break;
            }

            /* The isReadComplete flag gets updated in the CDC event handler. */
            if( appData.isReadComplete == true){// USB受信完了  
                int i;
                for(i=0; i < appData.numBytesRead; i++){
                    for(;;){    // UARTへ送信
                        if(U1STAbits.UTXBF == 0 // 送信バッファはフルではない
                           //&& U1STAbits.TRMT == 1////送信バッファが空?
                        ){
                            uint8_t data = appData.readBuffer[i];
                            U1TXREG = data;//UART送信バッファに入れる。
                            break;
                        }
                    }
                }
                appData.state = APP_STATE_SCHEDULE_READ;
                flag_APP_STATE_WAIT_FOR_READ_COMPLETE = false;
            }
            if(flag_APP_STATE_WAIT_FOR_WRITE_COMPLETE){
                appData.state = APP_STATE_WAIT_FOR_WRITE_COMPLETE;
            }
            break;

        case APP_STATE_SCHEDULE_WRITE:
            if(APP_State_Reset()){
                break;
            }
            appData.writeTransferHandle= USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID;
            appData.isWriteComplete = false;
            appData.state = APP_STATE_WAIT_FOR_WRITE_COMPLETE;

            recSize =ringbuf_copy_to( & uartRecBuf, recUartBuff);
            result = USB_DEVICE_CDC_Write(USB_DEVICE_CDC_INDEX_0,
                    &appData.writeTransferHandle,
                    recUartBuff,//送信バッファ
                    recSize,//送信バイト数
                    USB_DEVICE_CDC_TRANSFER_FLAGS_DATA_COMPLETE
            );
            if( result == USB_DEVICE_CDC_RESULT_OK ){
                flag_APP_STATE_WAIT_FOR_WRITE_COMPLETE = true;
            } else {
                appData.state = APP_STATE_ERROR;
            }
            break;          
            
        case APP_STATE_WAIT_FOR_WRITE_COMPLETE:           
            if(APP_State_Reset()) {
                break;
            }              

            /* Check if a character was sent. 
             * The isWriteComplete flag gets updated in the CDC event handler */
            if(appData.isWriteComplete == true){// USB送信完了  
                // 送信処理が終わった通知]に対する処理
                flag_APP_STATE_WAIT_FOR_WRITE_COMPLETE = false;
                recSize = 0;
                appData.state = APP_STATE_SCHEDULE_READ;

            }
            
            if(flag_APP_STATE_WAIT_FOR_READ_COMPLETE){
                appData.state = APP_STATE_WAIT_FOR_READ_COMPLETE;
            }

            break;
            
        case APP_STATE_ERROR:
            my_app_set_err(MY_APP_ERR_STATE);
        default:
            my_app_set_err(MY_APP_ERR_DEFAULT);
    }
}