UMEHOSHI ITA TOP PAGE    COMPUTER SHIEN LAB

UMEHOSHI IT (my_usb_cmd.cと.h)

my_usb_cmd.cのソース

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

void set_hex_string(uint16_t d, char s[]);
char *set_decimal_string(int d, char s[], int width);
int set_uint_str(uint32_t d, char s[], char c, int width);

#define HEX(c) (c < 10 ? c + '0' : c - 10 + 'A')
#define DEC(c) (c >= 'A' ? c - 'A' + 10: c - '0')

extern int flagThrough;//スルーモードで 1
extern int flagEcho;// エコーモードで1

// --ここから: USB出力用リングバッファと関連関数----------------------------------
#define OB_SIZE 48 //16の倍数でなければならない。(out buffer size)
#define OB_MAX (512+2)
extern uint8_t outBuffers[OB_MAX][OB_SIZE] __attribute__((coherent, aligned(16)));
extern uint32_t outDataNumb[OB_MAX]; //上記の各配列に記憶されるデータのbyte数
extern int outBuffCount;//これが「OB_MAX」に達した時点がバッファフル状態
extern int outDataCount;//outBuffersに記憶されるバイト数
extern int flagErrorSetOutData;//バッファフルでデータをsetOutDataを使うと、1がセット
extern int numbOutputs;//outBuffers出力の始まりから送信終了まで、出力データ数を保持する

void init_outBuffers();//上記出力用リングバッファ用変数の初期化(APP_State_Resetで利用)
void send_16byte(uint32_t data);
void send_char(char data);
void setBreakBuffer();
void send_string(char *s);//文字列をUSBへ送信するための登録( API 関数)
void send_hex_low(uint32_t d);//dの下位16ビットを16進8桁でUSBhの出力登録
void send_hex_hi(uint32_t d);//dの上位16ビットを16進8桁でUSBhの出力登録
void send_decimal(int d, int width);//dを10進でwidth幅文字列で出力登録
void send_padding_uint(uint32_t d, char c, int width);//uintの10進幅で出力登録
int get_capacity();// outBuffersの残りメモリブロック取得
bool request_acc_outbuff(uint16_t id);// outBuffers関連変数の使用権の取得
uint16_t release_acc_outbuff(uint16_t id);// outBuffers関連変数の使用権の開放

// dのdoubleをwの幅指定でprecisonの精度幅の文字列を送信。
void send_float(double d, int width, int precison);
// dのdoubleをwの幅指定でprecisonの精度幅の指数表現文字列を送信。
void send_exponent(double d, int width, int precison);
void send_ume_id();

int dummy_recive(uint8_t cdata);// USBからの置き換え可能な受信処理

void requset_send_usb_if_available();
uint8_t* getSendBuff();// 現在のバッファを終わらせて送信。
void noticeSendCcomplete(); // 上記送信処理が終わった通知に対する処理
// --ここまで: USB出力用リングバッファと関連関数----------------------------------

char select_command(uint8_t c);// // 逐次に受け取る引数がコマンドと判定したら実行
char set_commad_char(uint8_t c);// 逐次に受け取る引数で、コマンドを解析して記録
char set_recive_data(uint8_t cdata, int flagBreak) ;//上記2つを使った受信関数

#endif /* _MY_USB_CMD_H */

my_usb_cmd.cのソース

/*
 *  USB の送受信アプリに必要な処理
 * UMEHOSHI ITA USB受信の受け口となる関数「set_recive_data」の定義
 * UMEHOSHI ITA USBからの送信命令 「send_string」「send_hex_low」「send_hex_hi」
 * 「send_decimal」etc
 */

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <xc.h>
#include "my_app.h"
#include "my_usb_cmd.h"
#include "my_beep.h"
#include "my_sys.h"
#include "my_uart.h"
#include "common.h"

int flagThrough = 0; //スルーモードで 1
static char code_to_nomal_mode[80] = "\ncode from through mode to nomal mode 123\r";
static int code_to_size = 0; //上記の文字サイズを記憶
static int code_to_nomal_idx = 0; // 上記の記憶、チェック用

int flagEcho = 1; // エコーモードで1
// "\nE\r" or "\rE\r" or "\rE\n" or "\nE\n" の受付で、1と0が交互に切り替わる。

char message[128]; // メッセージ用文字列の一時記憶用
void (*go_func)(void); // USBからの実行指示で実行する関数スタートアドレス記憶変数

int safetyflag= 1;// 書き込み範囲を制限  追加[2023-4] 

//dのデータ下位16ビットを16進4桁文字列にして、[5]の記憶域のsにセットする。

void set_hex_string(uint16_t d, char s[]) {
    int i;
    for (i = 3; i >= 0; i--) {
        char c = (char) (d & 0x0f);
        c = c >= 10 ? c - 10 + 'A' : c + '0';
        s[i] = c;
        d >>= 4;
    }
    s[4] = '\x0';
}

//dのintデータが符号付きの前提で、10進数文字列にして、[12]の記憶域のsにセットする。
// 幅指定は最大が11文字で、少ない場合は拡張され、戻り値で調整される。
//(戻り値はwidthを利用した、sからずれた値になり、戻り値を表示することで幅指定を実現)

char *set_decimal_string(int d, char s[], int width) {
    s[0] = ' ';
    int x10 = 1000000000;
    int minus = d < 0;
    int sign_pos = -1;
    if (minus == 1) d = -d; //正に設定
    int i = 1;
    for (; i <= 10; i++) {
        int x = d / x10;
        if (x != 0 && sign_pos == -1) sign_pos = i - 1;
        if (sign_pos == -1) {
            s[i] = ' ';
        } else {
            s[i] = x + '0';
        }
        d -= x * x10;
        x10 /= 10;
    }
    char *p = s + (11 - width);
    if (sign_pos != -1) {
        s[sign_pos] = '+';
        if (minus == 1) s[sign_pos] = '-';
        if (11 - sign_pos > width) {
            p = s + sign_pos;
        }
    } else {
        s[10] = '0';
    }
    return p;
}

// dの符号なしデータの10進文字列を[12]の記憶域のaにセットする。
//  幅指定は最大が11文字で、満たない部分はcで埋める。
//  幅が足りない指定の場合は、これに収まる下位の桁だけの文字列になる。
//   幅に収まる変換が正しくできた場合は、1を返す。

int set_uint_str(unsigned d, char s[], char c, int width) {
    char a[12];
    int i = 0;
    while (i < width) {
        if (d == 0 && i > 0) a[i++] = c;
        else a[i++] = d % 10 + '0';
        d /= 10;
    }
    int j = 0;
    for (j = 0; j < width; j++) {
        s[j] = a[--i];
    }
    s[j] = 0;
    if (d != 0) return 0;
    return 1;
}

// USB出力用リングバッファ関連変数と関連関数 ======================================
uint32_t outDataNumb[OB_MAX]; // 下記の各配列に記憶されるデータのbyte数
uint8_t outBuffers[OB_MAX][OB_SIZE] __attribute__((coherent, aligned(16)));
int idxSetOutBuf; //バッファからの取り出し先添え字
int idxGetOutBuf; //バッファへの入力先添え字(上と違う時、出力すべきデータがある)
int outBuffCount; //これが「OB_MAX」に達した時点がバッファフル状態
int outDataCount = 0; //outBuffers全体に記憶されるバイト数
int idxSetCount; //outBuffers[idxGetOutBuf][idxSetCount]が現在の記憶域となる。
int flagErrorSetOutData; //バッファフルでデータをsetOutDataを使うと、1がセット
// (これがセットされるとバッファへの設定は不可となり復帰は、リセットのみ)

int numbOutputs = 0; //outBuffers出力の始まりから送信終了まで、出力データ数を保持する
//getSendBuff関数で記憶され、noticeSendCcomplete関数で0になり、フラグ的な役割もある

//上記outBuffers関連変数の排他制御管理変数
volatile uint16_t accessing_outbuffer __attribute__((section("sfrs")));
// 上記outBuffers関連変数の排他制御で、アクセス権を要求する
// id は指定は、ID_ACCESS_XXXXXXの定義で決めて使う。

// 割り込み時にoutBuffersを操作する使う排他制御用の権限要求関数

bool request_acc_outbuff(uint16_t id) {
    if (accessing_outbuffer == id) {
        return true;
    }
    if (accessing_outbuffer != 0) {
        return false;
    }
    accessing_outbuffer |= id;
    if (accessing_outbuffer == id) {
        return true; // outBuffersへのアクセス権を得た
    }
    accessing_outbuffer &= ~id;
    return false;
}

// 上記割込み取得した権限を返す関数

uint16_t release_acc_outbuff(uint16_t id) {
    return accessing_outbuffer &= ~id; //出力バッフ利用終了
}

// USBへの送信データがoutBuffersのバッファにあるならUSB送信を促す

void requset_send_usb_if_available() {
    static int pre_outDataCount = 0;
    if (outBuffCount == 0 //出力すべき回数がゼロ
            && outDataCount > 0 //USBへの出力登録byte数がある。
            && pre_outDataCount == outDataCount) { // 出力登録byte数に変動がない
        setBreakBuffer(); //USBへの出力すべき回数をアップ(出力を促す)
    }
    pre_outDataCount = outDataCount; //USBへの出力登録byte数
}

//上記outBuffersの残り容量([OB_SIZE]のブロック数)
// おおよその残りバイト数は、[この関数の戻り値]×OB_SIZEで算出できる。

int get_capacity() {
    return (OB_MAX - outBuffCount);
    //return outBuffCount;
}

// 上記 USB出力用リングバッファ関連変数 の初期化(APP_State_Resetで呼び出す)

void init_outBuffers() {
    idxSetOutBuf = 0; //バッファからの取り出し先添え字
    idxGetOutBuf = 0; //バッファへの入力先添え字(上と違う時、出力すべきデータがある)
    outBuffCount = 0; //これが「OB_MAX」に達した時点がバッファフル状態
    outDataCount = 0; //outBuffers全体に記憶されるバイト数
    idxSetCount = 0; //outBuffers[idxGetOutBuf][idxSetCount]が現在の記憶域となる。
    // ( outDataNumb[]の配列に記憶直後にidxSetCountを0にする。)
    //flagErrorSetOutData = 0;//バッファフルでデータをsetOutDataを使うと、1がセット
    numbOutputs = 0; //outBuffers出力の始まりから送信終了まで、出力データ数を保持する
    accessing_outbuffer = 0; //上記変数がMy_APP_Tasks内でアクセス中の時true    
}

// USBへの出力データを行う時にエラーチェックするサブ関数

static bool check_on_error() {
    static bool errorFlag = false;
    if (errorFlag) return false;
    if (outBuffCount + 1 >= OB_MAX - 2) {// -2の余裕
        flagErrorSetOutData = 1;
        if (errorFlag == 0) {// バッファブロックの最後にエラー文字列をセット
            if (outDataNumb[idxSetOutBuf] != 0) {// ブロックにデータがある?
                if (++idxSetOutBuf >= OB_MAX) idxSetOutBuf = 0; //次のブロックへ
                idxSetCount = 0;
                outBuffCount++;
            }
            outBuffers[idxSetOutBuf][idxSetCount++] = '\r'; //"\r\nB ERR\r\n"
            outBuffers[idxSetOutBuf][idxSetCount++] = '\n';
            outBuffers[idxSetOutBuf][idxSetCount++] = 'B';
            outBuffers[idxSetOutBuf][idxSetCount++] = ' ';
            outBuffers[idxSetOutBuf][idxSetCount++] = 'E';
            outBuffers[idxSetOutBuf][idxSetCount++] = 'R';
            outBuffers[idxSetOutBuf][idxSetCount++] = 'R';
            outBuffers[idxSetOutBuf][idxSetCount++] = '\r';
            outBuffers[idxSetOutBuf][idxSetCount++] = '\n';
            outDataNumb[idxSetOutBuf] = idxSetCount; // 1バッファ内のデータサイズ
            outDataCount += idxSetCount; // 全バッファ内のデータサイズ
            if (++idxSetOutBuf >= OB_MAX) idxSetOutBuf = 0; //次のブロックへ
            idxSetCount = 0;
            outBuffCount++;
        }
        errorFlag = true;
        return false;
    }
    return true;
}

// 引数の1byteを上記のUSB出力用バッファ入れる。
// outBuffers[idxSetOutBuf]バッファ内の位置や数などの情報も更新される
// リングバッファのリング更新(idxSetOutBufの変更)はしない。

static uint8_t setOutData(uint8_t data) {//dataをバッファにセット
    if (appData.isConfigured == false) return 0;
    if (!check_on_error()) return 0;
    outBuffers[idxSetOutBuf][idxSetCount++] = data;
    outDataNumb[idxSetOutBuf] = idxSetCount; // 1バッファ内のデータサイズ
    outDataCount++; // 全バッファ内のデータサイズ
    return data; //check sum 計算用に使う戻れ値
}

// sizeの個数数のデータをUSB出力用バッファ(outBuffers)に入れる。
// 出力バッファへのセットは、setOutDataを使う。
// outBuffers[idxSetOutBuf]が一杯になれば、idxSetOutBuf変更でリングバッファを更新

static uint16_t setOutDatas(uint8_t *datas, int size) {
    if (appData.isConfigured == false) return 0;
    int n = 0;
    uint16_t sum = 0;
    while (n < size) {
        if (flagErrorSetOutData == 1) break;
        if (idxSetCount >= OB_SIZE) {
            if (++idxSetOutBuf >= OB_MAX) {// 次のバッファに進む
                idxSetOutBuf = 0; // リングバッファの先頭に戻る。
            }
            idxSetCount = 0;
            outBuffCount++; // バッファ使用数が増える
        }
        setOutData(datas[n]); //1byteをバッファにセット
        sum += datas[n++];
    }
    return sum;
}

//文字列をUSB出力用バッファ入れる。
// setOutDatasを使う。(必要に応じて自動的にリングバッファを更新)

static uint16_t setOutString(uint8_t *s) {
    int size = 0;
    while (s[size])size++;
    return setOutDatas(s, size);
}

// 現在使っているバッファを終わらせて、次のバッファを使うように進める。
// リングバッファを強制的更新(idxSetOutBufを変更する。)

void setBreakBuffer() {
    if (appData.isConfigured == false) return;
    if (!check_on_error()) return;
    //if(outDataNumb[idxGetOutBuf] == 0) return;//現在のバッファが空ならリターン
    if (outDataNumb[idxSetOutBuf] == 0) return; //現在のバッファが空ならリターン

    if (++idxSetOutBuf >= OB_MAX) {// 次のバッファに進む 
        idxSetOutBuf = 0; // リングバッファの先頭に戻る。
    }
    idxSetCount = 0;
    outBuffCount++; // バッファ使用中の数が増える
}

// dataの1byteをUSB出力用バッファ(outBuffers)に入れる。(バイナリにも可能)

void send_char(char data) {
    if (appData.isConfigured == false) return;

    if (flagErrorSetOutData == 1) return;
    if (idxSetCount >= OB_SIZE) {
        if (++idxSetOutBuf >= OB_MAX) {// 次のバッファに進む
            idxSetOutBuf = 0; // リングバッファの先頭に戻る。
        }
        idxSetCount = 0;
        outBuffCount++; // バッファ使用数が増える
    }
    setOutData(data); //1byteをバッファにセット
}

// 2バイト、リトルエンディアンでUSB送信

void send_16byte(uint32_t data) {
    send_char(data & 0x0ff);
    send_char((data >> 8) & 0x0ff);
    setBreakBuffer();
}

// sの文字列を、USBの出力バッファに登録する。(USBの初期化が済んでいない場合は無視)
// (割り込みルーチンから呼ぶ場合は、注意が必要!)

void send_string(char *s) {
    if (appData.isConfigured) {//USBが接続されて、初期化済みか?
        setOutString(s);
        setBreakBuffer();
    }
}

// dのデータ下位16ビットを16進4桁でUSBの出力バッファに登録する。

void send_hex_low(uint32_t d) {
    char s[5];
    set_hex_string(d, s);
    send_string(s);
}

// dのデータ上記16ビットを16進4桁でUSBの出力バッファに登録する。

void send_hex_hi(uint32_t d) {
    send_hex_low(d >> 16);
}

// dのintデータを10進10桁でUSBの出力バッファに登録する。
// 幅指定は最大が11文字で、少ない場合は拡張される。欠けずに表示する

void send_decimal(int d, int width) {
    char s[12] = "-2147483648"; //  0x8fffffff
    if (d == 0x80000000) {
        send_string(s);
        return;
    }
    char *p=set_decimal_string(d, s, width);
    send_string(p);
}

// dの符号なしを幅指定の10文字列で送信する。幅に満たない空間はcで埋める

void send_padding_uint(uint32_t d, char c, int width) {
    char s[12];
    set_uint_str(d, s, c, width); // 0で埋めた10進文字列に
    send_string(s);
}

// dのdoubleをwの幅指定でprecisonの精度幅の文字列を送信。
void send_float(double d, int width, int precison) {
	char fmt[8];
	char s[32];
	sprintf(fmt, "%%%d.%df", width, precison);
	sprintf(s, fmt, d);
	send_string(s);
}

// dのdoubleをwの幅指定でprecisonの精度幅の指数表現文字列を送信。
void send_exponent(double d, int width, int precison) {
	char fmt[8];
	char s[32];
	sprintf(fmt, "%%%d.%de", width, precison);
	sprintf(s, fmt, d);
	send_string(s);	
}

void send_ume_id(){
	//send_string("ume202107");
	send_string("ume202304");// 変更[2023-4]
}

//  USB CDC の送信する時に、現在の対象となるバッファが必要で、その取得関数。
// (my_app.c のMy_APP_Tasks ( )の中で使う))
//  グローバル変数のnumbOutputsに、送信データ数をセット(フラグ的な役割もある)

uint8_t* getSendBuff() {//
    numbOutputs = outDataNumb[idxGetOutBuf]; // returnバッファ内のデータbyte数
    outDataNumb[idxGetOutBuf] = 0; //バッファ内データ数クリア
    return &outBuffers[idxGetOutBuf][0];
}

// 上記のgetSendBuffで得られたバッファの送信処理終了時点で、通知に対する処理
// (my_app.c のMy_APP_Tasks ( )の中で使う)
//  グローバル変数のnumbOutputsの送信データ数0に戻すを。(フラグ的な役割もある)

void noticeSendCcomplete() {
    if (numbOutputs == 0) return; //出力中でないならなにもしない。
    if (++idxGetOutBuf >= OB_MAX) {
        idxGetOutBuf = 0; //リングバッファなので先頭に戻る。
    }
    outBuffCount--; // バッファ内の送出が終わったので、使用中バッファの数を減らす
    outDataCount -= numbOutputs; // 送信データ数で、バッファ内のデータ数を減らす
    numbOutputs = 0;
}
// USB出力用リングバッファと関連関数 ===========ここまで==========================


// USB 受信コマンド関連の変数定義 ここから ======================================
uint8_t recieveSetBuffer[256]; //Sコマンドで受信したデータの格納用
int idxRecieveSet = 0;
//----------------------------------------------
uint8_t hex_cmd; //受信コマンド文字 [G S R E T]
uint8_t hex_num; //受信データ部のサイズ 
uint8_t hex_num_count = 0; // 上記 hex_num の数まで受信を数える制御用
uint32_t hex_adr; //受信データ部のアドレス
uint8_t hex_typ; //受信データ種別
uint8_t hex_dat; //受信データ
uint8_t hex_chk; //受信したチェックサム
uint8_t hex_chk_calc; //上記チェックサムと比較するために受信データを加算する変数
// 以下の制御用変数は、対応する処理に移行する直前で0に戻す
uint32_t hex_cnt = 0; //制御用で、受信データ数を数える。(SWITGHで分岐)
uint32_t hex_low = 0; ////制御用で、16進で下位バイトの時に1
uint8_t flag_to_check_sum = 0; // 1になったらチェックサムを計算
uint8_t flag_hex_cmd_complete = 0; //1になった時がコマンド受信の終了
// USB 受信コマンド関連の変数定義  ======================================ここまで


// USB 受信コマンド関連の関数定義 ここから ======================================

void send_command_char_response(uint8_t cdata) {
    send_char(cdata); //USBへ応答
    if (_HANDLES[_IDX_DEF_POLLS_UART] == uart_cmd_mode_polling) {
        set_data_snd_uart(cdata); // uartSndBufへの送信データをセット
    }
}

void send_command_str_response(uint8_t *str) {
    int i = 0;
    while (str[i] != 0) {
        send_command_char_response(str[i++]);
    }
}

// data を 16進文字列に変換して得られるcolumnSiz個の文字並びを出力
// send_command_char_response関数を利用

static uint16_t send_uint_hex(uint32_t data, int columnSize) {//(設定したデータの合計を返す。これはチェックサムの計算に使われる。)
    uint16_t sum = 0;
    uint8_t d1;
    uint32_t mask = 0x0f << ((columnSize - 1) * 4);
    while (columnSize > 0) {
        d1 = (data & mask) >> ((columnSize - 1) * 4);
        d1 = HEX(d1);
        sum += d1;
        send_command_char_response(d1);
        columnSize--;
        mask >>= 4;
    }
    return sum;
}

// 「G」のデータ取得コマンドに対するレスポンス
// 外部変数、hex_adr のアドレスより、hex_numのサイズ要求に対するレスポンス出力で、
//  チェックサムを含めた文字列を、send_command_char_response関数、
//  send_uint_hex関数で送出する。

void G_response2() {
    uint16_t sum = 0;
    sum += ':';
    send_command_char_response(':');
    sum += send_uint_hex(hex_num, 2); //データ数
    sum += send_uint_hex((uint32_t) hex_adr, 8); //アドレス
    sum += send_uint_hex(0, 2); //種別コード
    uint8_t *p = (uint8_t *) hex_adr, *pEnd = (uint8_t *) hex_adr + hex_num;
    while (p < pEnd) {
        sum += send_uint_hex(*p++, 2); // 1byte設定
    }
    sum = 0x100 - (0x0FF & sum);
    send_uint_hex(sum, 2); ///チェックサムの埋め込み
    send_command_char_response(0x0D); // 13のCRを埋め込み
    send_command_char_response(0x0A); // 10のLFを埋め込み(以上で改行の埋め込み)

    setBreakBuffer();
}

// 「S」のデータ取得コマンドに対するレスポンス
// recieveSetBufferの内容を、hex_adrのポインタが指す記憶域に設定する。
// (hex_numの個数だけ取り出してメモリに並べる)

int  setToMemory() { // EEPRO領域の書き込みを可能にする変更[2023-4] 以下変更
    uint8_t n;
    if ( hex_adr >= 0x9D020000 && hex_adr <= 0x9D03FFFC || safetyflag==0) {
        if(hex_num % 4 != 0) {
            sprintf(message, "SET:%08X %d writes do not match\r\n", hex_adr, hex_num);
            return 1; // 書き込みが1ワードでない
        }
        uint32_t *adr = (uint32_t *)hex_adr;
        int rtv = 0;
        for (n = 0; n < hex_num;  adr++) {
            uint32_t data=recieveSetBuffer[n++];
            data+=recieveSetBuffer[n++]<<8;
            data+=recieveSetBuffer[n++]<<16;
            data+=recieveSetBuffer[n++]<<24;
            uint32_t *ptw = (uint32_t *)((uint32_t)adr+0x20000000);
            rtv += _nvm_write_word((uint32_t)ptw,data);
            if(rtv != 0){
                sprintf(message, "SET:%08X Failed to write %02X.\r\n", hex_adr, data);        
                return 1; // 書き込み失敗
            }
            if(*adr != data){
                sprintf(message, "SET:%08X %08X != %08X.\r\n", hex_adr, *adr, data);
                return 1;
            }
        }
        return 0;
    } else if(hex_adr >= 0x80000000 && hex_adr <= 0x8000ffff ||
                hex_adr >= 0xa0000000 && hex_adr <= 0xa000ffff || safetyflag==0){
        uint8_t *p = (uint8_t *) hex_adr;
        for (n = 0; n < hex_num; n++) {// RAM範囲のメモリ設定
            *p++ = recieveSetBuffer[n];
        }
        return 0;
    }
    return 1;
}// EEPRO領域の書き込みを可能にする変更[2023-4] 以上変更


// 逐次に受け取る引数で、コマンドを解析データをグローバル変数へ記録

char set_commad_char(uint8_t cdata) {
    hex_cnt++;
    switch (hex_cnt) {
        case 1://コマンド文字 種別 S R G A
            hex_cmd = cdata;
            idxRecieveSet = 0;
            break;

        case 2://データ数取得スタート(16進文字のデータ)
            hex_num_count = hex_low = 0;
            hex_num = DEC(cdata);
            break;
        case 3://データ数取得セット(16進文字のデータ)
            hex_num <<= 4;
            hex_num += DEC(cdata);
            break;

        case 4://アドレス取得セット(16進文字のデータ)スタート
            hex_adr = DEC(cdata);
            break;
        case 5://アドレス数取得セット(16進文字のデータ)
        case 6: case 7: case 8:
        case 9: case 10: case 11:
            hex_adr <<= 4;
            hex_adr += DEC(cdata);
            break;

        case 12://レコード種別セット(16進文字のデータ)スタート
            hex_typ = DEC(cdata);
            break;
        case 13://レコード種別取得セット(16進文字のデータ)
            hex_typ <<= 4;
            hex_typ += DEC(cdata);
            break;

        default:
            if (hex_cmd == 'G' || hex_cmd == 'R') {// メモリ内容の要求コマンド
                flag_to_check_sum = 1; // cdataはチェックサム→検証へ
            } else if (hex_cmd == 'S') {
                if (hex_num_count < hex_num) {//セットデータ
                    if (hex_low == 0) {
                        hex_low = 1;
                        hex_dat = DEC(cdata);
                    } else if (hex_low == 1) {
                        hex_low = 0;
                        hex_num_count++;
                        hex_dat <<= 4;
                        hex_dat += DEC(cdata);
                        recieveSetBuffer[idxRecieveSet++] = hex_dat;
                    }
                } else if (hex_num_count == hex_num) {//データ取得終了
                    flag_to_check_sum = 1; // cdataはチェックサム→検証へ
                }
            }
    }

    // 受信用の記憶処理のブロック終わりでチェックサムの検証 1byte(16進2文字分)
    if (flag_to_check_sum == 1) {
        if (hex_low == 0) {//チェックサム受信
            hex_chk = DEC(cdata);
            hex_low = 1;
            return 'R';
        } else if (hex_low == 1) {
            hex_chk <<= 4;
            hex_chk += DEC(cdata);
            hex_low = 0;
            flag_to_check_sum = 0;
            if (((hex_chk_calc + hex_chk) & 0x0ff) != 0) {
                sprintf(message, "check sum error %c\r\n", cdata);
                send_command_str_response(message);
                return 'W'; //チェックサムのエラー
            }
            flag_hex_cmd_complete = 1; //受信処理の完結
            return 'R'; //  送信バッファになにも設定していないことを知らせる。
        }
    }

    hex_chk_calc += cdata; //チェックサム計算
    return 'R'; //  送信バッファになにも設定していないことを知らせる。    
}

// 引数のデータの逐次に受け取る使い方で、コマンドと判定した時、そのコマンドを実行

char select_command(uint8_t cdata) {
    static uint8_t prev_cdata = 0;

    if (flagThrough == 1) { //スルーモードではUART1とスルーで通信するモード
        send_uart1(cdata); //UART1の送信用リングバッファに記憶 
        return 'R';
    }

    if (flagEcho && !usb_receiver_disable_flag) {
        // エコーモード状態の時、USB受信データを、出力バッファに入れる。
        send_command_char_response(cdata);
    }

    if (prev_cdata == 0x0D && cdata == 0x0A) {
        prev_cdata = cdata;

        if (hex_cnt == 2 && hex_cmd == 'E') {// エコーモード切り替え
            flag_to_check_sum = hex_chk_calc = hex_cnt = 0;
            flagEcho = !flagEcho; // エコーモード切り替え
            if (flagEcho) send_command_str_response("ECHO ON\r\n");
            else send_command_str_response("ECHO OFF\r\n");
            return 'W';
        }

        if (hex_cnt == 2 && hex_cmd == 'T') {// スルーモードへ
            flag_to_check_sum = hex_chk_calc = hex_cnt = 0;
            send_command_str_response("Through Mode\r\n");
            flagThrough = 1;
            flagErrorSetOutData = 0;
            init_outBuffers();
            return 'W'; // 送信バッファにセットしたことを知らせる
        }

        flag_to_check_sum = hex_chk_calc = hex_cnt = 0;
        if (flag_hex_cmd_complete) {//命令確定後の受信コマンドによる分岐 
            flag_hex_cmd_complete = 0;
            if (hex_cmd == 'G') {// メモリ内容の取得
                G_response2();
                return 'W'; // 送信バッファにセットしたことを知らせる

            } else if (hex_cmd == 'S') {//  メモリ設定
                int r = setToMemory(); // 変更[2023-4] ここから
                if(r==0) {
                    sprintf(message, "SET:%08X\r\n", hex_adr);//成功
                    send_command_str_response(message);
                }// 変更[2023-4] ここまで
                return 'W'; // 送信バッファにセットしたことを知らせる

            } else if (hex_cmd == 'R') { // 実行処理の登録
                go_func = (void (*)())hex_adr;
                if (!usb_receiver_disable_flag) {
                    sprintf(message, "START:%08X\r\n", hex_adr);
                    send_command_str_response(message);
                    return 'W'; // 送信バッファにセットしたことを知らせる
                } else {
                    return 'R';
                }
            }
        }

        if (hex_cnt != 0) {// これが成立することはチェックサムのエラー!!
            sprintf(message, "exception hex_cnt: %d\r\n", hex_cnt);
            send_command_str_response(message);
            return 'W';
        }
        return 'R'; //無視(記憶しない)
    }
    prev_cdata = cdata;
    return 0;
}

// USB受信の置き換え可能なダミー関数

int dummy_recive(uint8_t cdata) {
    return 0;
}

// USBからの1byte受信で実行する。( コマンド解析して応答処理を実行 )

char set_recive_data(uint8_t cdata, int flagBreak) {
    int change = _RECIVE_USB_FUNC(cdata);
    if (change == 1) return 'R';

    if (flagThrough == 1) { //スルーモードではUART1とスルーで通信するモード
        send_uart1(cdata); //UART1の送信用リングバッファに記憶
        if (code_to_size == 0) {
            code_to_size = strlen(code_to_nomal_mode);
            code_to_nomal_idx = 0;
        }
        if (cdata == code_to_nomal_mode[code_to_nomal_idx]) {
            code_to_nomal_idx++;
            if (code_to_nomal_idx == code_to_size) {
                flagThrough = 0; // スルーモードからノーマルに遷移
                code_to_nomal_idx = 0;
            }
        } else {
            code_to_nomal_idx = 0;
        }
        return 'R';
    }

    char rtn = select_command(cdata); // 逐次に受け取る引数がコマンド判定実行
    if (rtn != 0) return rtn;
    return set_commad_char(cdata); // 文字をコマンド解析バッファにセット   
}