/* * Copyright (C) 2013-2014 by Embedded and Real-Time Systems Laboratory * Graduate School of Information Science, Nagoya Univ., JAPAN * * $Id: cmd_rcb3_can.c 228 2014-09-12 13:21:15Z honda $ */ /* ○仕様 ・コマンド SBXBTの PS3コントローラ/USBゲームパッドUART変換ファームウェア (http://runningele.web.fc2.com/) でサポートしているRCB3に対応 している. UARTポート2とCAN経由でコマンドを受け取る.併用するとUARTからの コマンドの取りこぼしが発生するため注意すること. ・起動時 全てのLEDを0.5秒周期で3秒点滅させる. ・ボタン操舵 左・右 ボタン ・ステアリングのニュートラルを調整. ・ボタンを押すと方向指示器がON,離すとOFF 上ボタン ・ステアリングをニュートラルにする 下ボタン ・モータ制御のゲインを初期値にする L1/R1 ・方向指示器をON/OFFする. L2/R2 ・モータ制御のゲインを変更 × ・ブレーキ △ ・ハザード ○ ・メインヘッドライト切り替え() □ ・ギア切り替え(D -> N -> B -> N) */ //#include "rc.h" //#include "cmd_msg.h" //#include "uart.h" //#include "fcan.h" #include "rcb3.h" #include "comuart.h" /* * 前方参照 */ static void onMsgUart(void); static void onMsgCAN(void); static void onMsgPS3(void); static void onTimer10m(void); static void onTimer50m(void); static void onTimer100m(void); /* * 各種定義 */ /* * ニュートラル時のステアリング角度の初期値 */ #define STEER_NEUTRAL_INIT 0 /* * モータゲインの初期値 */ #define MOTOR_GAIN_INIT 2 /* * ログ出力用のポート番号とイベント番号 */ #define RC_OUTPUT_PORT 2 #define RC_EVENT_OUTPUT_PORT (0x10 << RC_OUTPUT_PORT) /* * 起動時のボディー系の接続テスト用設定 */ #define INIT_BODY_BLINK_COUNT 3 #define INIT_BODY_BLINK_CYCLE 500 /* * 制御関連の変数 */ float g_steer_neutral = STEER_NEUTRAL_INIT; float g_angle = 0; float g_speed = 0; int g_speed_gain = MOTOR_GAIN_INIT; boolean g_blinker_l_blink = FALSE; boolean g_blinker_r_blink = FALSE; boolean g_isBrake = FALSE; /* * CAN関連 */ /* * ボディー系への指示コマンド用CANメッセージID */ #define BODY_CAN_MSG_ID 16 /* * 受信コマンド用CANメッセージID */ #define CONT_CMD_CAN_MSG_ID 3 /* * 送信のリトライ回数の上限 */ #define CAN_RETRY_LIMIT 50 /* * CAN通信を使用するかのフラグ */ boolean g_use_can = TRUE; /* * CAN通信を再開する回数 */ #define CAN_REUSE_CNT_LIMIT 1000 /* * CAN通信再開用変数 */ int g_can_reuse_cnt = 0; /* * CAN関連の初期化 */ void can_init(void) { /* CANポート初期化 */ FCan0InitPort(0); /* CAM初期化 */ FcanInit(0); /* メールボックス初期化 */ FcanSetMailBoxInfo(0, 0, DIR_SEND, IDE_STD, BODY_CAN_MSG_ID, 0, 0 ); FcanSetMailBoxInfo(0, 1, DIR_RECV, IDE_STD, CONT_CMD_CAN_MSG_ID, 0, 0 ); /* CANスタート */ FcanEnable(0); } /* * CANメッセージの送信 */ void can_send(uint8 *tx_data, uint8 len) { int cnt = 0; STATUS status; /* CAN通信停止状態の場合 */ if (!g_use_can) { g_can_reuse_cnt++; if (g_can_reuse_cnt == CAN_REUSE_CNT_LIMIT) { g_use_can = TRUE; g_can_reuse_cnt = 0; } else { return; } } while(1){ status = FcanSetTxData(0, 0, &tx_data[0], len); if(status != STATUS_OK ) { if (cnt++ > CAN_RETRY_LIMIT) { g_use_can = FALSE; uart_PSendString(RC_OUTPUT_PORT, "CAN connect error! Execute without CAN. \r\n"); break; } }else{ break; } } } /* * ボディーECUへの状態指示構造体 */ typedef struct { uint8_t headlight1; uint8_t headlight2; uint8_t headlight3; uint8_t breaklamp; uint8_t backlamp; uint8_t buzzer; uint8_t blinker_l; uint8_t blinker_r; uint8_t hazardlamp; }BODY_CONT_INFO; /* * ボディーのアイテムのON/OFFマクロ */ #define BODY_CONT_ON 1 #define BODY_CONT_OFF 0 #define BODY_CONT_BLINK 2 /* * ボディーECUへの状態指示用変数 */ BODY_CONT_INFO g_body_cont_info; /* * 周期送信とするか */ boolean g_body_can_msg_cyclic = TRUE; /* ボディー制御CANメッセージ仕様 送信周期 : 50ms メッセージID : 16 メッセージ長 : 11bit offset bits bit assign ヘッドライト1 : 0 : 1 : 1:ON 0:OFF ヘッドライト2 : 1 : 1 : 1:ON 0:OFF ヘッドライト3 : 2 : 1 : 1:ON 0:OFF ブレーキランプ : 3 : 1 : 1:ON 0:OFF バックランプ : 4 : 1 : 1:ON 0:OFF ブザー : 5 : 1 : 1:ON 0:OFF 2:BLINK ウィンカーL : 8 : 2 : 1:ON 0:OFF 2:BLINK ウィンカーR : 10 : 2 : 1:ON 0:OFF 2:BLINK ハザードランプ : 12 : 1 : 1:ON 0:OFF 2:BLINK */ void body_can_msg_send(void) { uint8 tx_data[8]; /* 前回送付の状態 */ static BODY_CONT_INFO g_pre_body_cont_info; /* 状態指示に変化が無ければ送信しない */ if (!g_body_can_msg_cyclic){ if((g_body_cont_info.headlight1 == g_pre_body_cont_info.headlight1) && (g_body_cont_info.headlight2 == g_pre_body_cont_info.headlight2) && (g_body_cont_info.headlight3 == g_pre_body_cont_info.headlight3) && (g_body_cont_info.breaklamp == g_pre_body_cont_info.breaklamp) && (g_body_cont_info.backlamp == g_pre_body_cont_info.backlamp) && (g_body_cont_info.buzzer == g_pre_body_cont_info.buzzer) && (g_body_cont_info.blinker_l == g_pre_body_cont_info.blinker_l) && (g_body_cont_info.blinker_r == g_pre_body_cont_info.blinker_r) && (g_body_cont_info.hazardlamp == g_pre_body_cont_info.hazardlamp)) { return; } } /* 送信メッセージを生成 */ tx_data[0] = ((g_body_cont_info.headlight1 << 7) & 0x80) | ((g_body_cont_info.headlight2 << 6) & 0x40) | ((g_body_cont_info.headlight3 << 5) & 0x20) | ((g_body_cont_info.breaklamp << 4) & 0x10) | ((g_body_cont_info.backlamp << 3) & 0x08) | ((g_body_cont_info.buzzer << 1) & 0x06); tx_data[1] = ((g_body_cont_info.blinker_l << 6) & 0xc0) | ((g_body_cont_info.blinker_r << 4) & 0x30) | ((g_body_cont_info.hazardlamp << 3) & 0x08); can_send(tx_data, 2); g_pre_body_cont_info = g_body_cont_info; } /* * 起動時のボディーの接続確認 * * 全LED点滅とブザーを鳴らす. */ void body_check(void) { int loop, tcnt; uint8_t status = BODY_CONT_ON; for(loop = 0; loop < INIT_BODY_BLINK_COUNT*2; loop++) { g_body_cont_info.headlight1 = status; g_body_cont_info.headlight2 = status; g_body_cont_info.headlight3 = status; g_body_cont_info.breaklamp = status; g_body_cont_info.backlamp = status; g_body_cont_info.buzzer = status; g_body_cont_info.blinker_l = status; g_body_cont_info.blinker_r = status; body_can_msg_send(); tcnt = 0; while(1) { rc_WaitEvent(RC_EVENT_TIMER); rc_ClearEvent(RC_EVENT_TIMER); tcnt++; if (tcnt == INIT_BODY_BLINK_CYCLE) { break; } } status = (status == BODY_CONT_ON)? BODY_CONT_OFF : BODY_CONT_ON; } } /* * メイン関数 */ void cmd_rcb3_Main(void) { int tcnt = 0; uint32_t event; uart_Init(RC_OUTPUT_PORT, 115200); uart_PSendString(RC_OUTPUT_PORT, "Initialize hardware start. \r\n"); can_init(); body_check(); SetServoControlMode(TRUE); SetServoEnable(SERVO_ON); SetSteerAngle(STEER_NEUTRAL_INIT); SetControlParam(1.0f, 1.0f, 0); SetMotorEnable(MOTOR_ON); rcb3_Init(); uart_PSendString(RC_OUTPUT_PORT, "Initialize hardware done. \r\n"); while (1) { event = rc_WaitEvent(RC_EVENT_CMD_PORT|RC_EVENT_TIMER); if (event & RC_EVENT_OUTPUT_PORT) { rc_ClearEvent(RC_EVENT_OUTPUT_PORT); onMsgUart(); } if (event & RC_EVENT_TIMER) { rc_ClearEvent(RC_EVENT_TIMER); onMsgCAN(); tcnt++; if (tcnt % 10 == 0) { onTimer10m(); } if (tcnt % 50 == 0) { onTimer50m(); } if (tcnt == 100) { tcnt = 0; onTimer100m(); } } } } /* * 終了処理 */ void cmd_rcb3_Exit(void) { /* 駆動モータを停止 */ mot_SetOutput(0); } /* * UARTからのメッセージの受信処理 */ void onMsgUart(void) { uint8_t c; while (uart_Get(RC_OUTPUT_PORT, &c, 1)) { /* * 有効な電文を受け取った場合は,電文に応じた処理を実施 */ if (rcb3_AddReceivedByte(c)) { onMsgPS3(); } } } /* * CANからのメッセージ受信処理 */ void onMsgCAN(void) { uint8 rx_data[8]; uint8 rx_size; int loop; BOOL result; char str[30]; FcanGetRxData(0, 1, &rx_data[0], &rx_size); if (rx_size == 0) { return; } // sprintf(str, "Can data 0x%x, 0x%x, 0x%x\r\n", rx_data[0], rx_data[1], rx_data[2]); // uart_PSendString(RC_OUTPUT_PORT, str); for (loop = 0; loop < rx_size; loop++){ result = rcb3_AddReceivedByte(rx_data[loop]); } if (result) { onMsgPS3(); } else { sprintf(str, "Received Can data Error!\r\n"); uart_PSendString(RC_OUTPUT_PORT, str); } } /* * 10m周期で呼び出される. */ void onTimer10m(void) { } /* * 50m周期で呼び出される. */ void onTimer50m(void) { /* ボディー系への指示を送信 */ body_can_msg_send(); } /* * 100m周期で呼び出される. */ void onTimer100m(void) { } /* * RoboCar制御ライブラリ */ /* * ステアリングニュートラルを初期値に */ void InitSteerNetural(void) { char str[30]; g_steer_neutral = STEER_NEUTRAL_INIT; SetSteerAngle(g_steer_neutral); sprintf(str, "Set steer neutral = %2.1f \r\n", g_steer_neutral); uart_PSendString(RC_OUTPUT_PORT, str); } /* * ステアリングニュートラルを左側に */ void AdjustSteerNeturalL(void) { char str[30]; if(g_steer_neutral < 30) { g_steer_neutral++; SetSteerAngle(g_steer_neutral); sprintf(str, "Adjust steer neutral = %2.1f \r\n", g_steer_neutral); uart_PSendString(RC_OUTPUT_PORT, str); } } /* * ステアリングニュートラルを右側に */ void AdjustSteerNeturalR(void) { char str[30]; if(g_steer_neutral > -30) { g_steer_neutral--; SetSteerAngle(g_steer_neutral); sprintf(str, "Adjust steer neutral = %2.1f \r\n", g_steer_neutral); uart_PSendString(RC_OUTPUT_PORT, str); } } /* * スピードゲインを上げる */ void AdjustSpeedGainU(void) { char str[30]; if(g_speed_gain < 10) { g_speed_gain++; SetDriveSpeed(g_speed/g_speed_gain); sprintf(str, "Adjust speed gain = %d \r\n", g_speed_gain); uart_PSendString(RC_OUTPUT_PORT, str); } } /* * スピードゲインを下げる */ void AdjustSpeedGainD(void) { char str[30]; if(g_speed_gain > 1) { g_speed_gain--; SetDriveSpeed(g_speed/g_speed_gain); sprintf(str, "Adjust speed gain = %d \r\n", g_speed_gain); uart_PSendString(RC_OUTPUT_PORT, str); } } /* * PS3コントローラのアナログボタン毎の処理 */ #define PS3ANALOG_MAX 63 #define PS3ANALOG_MIN -63 /* * 左アナログコントローラの左右動作 * ステアリングを操作 */ void onPS3AnalogL_LR(void) { char str[30]; float angle; float cur_analog = p_g_cur_ps3analog[NO_PS3ANALOG_L_LR]; if ((cur_analog <= PS3ANALOG_MAX) && (cur_analog >= PS3ANALOG_MIN)) { angle = -(cur_analog/2); angle += g_steer_neutral; if (angle != g_angle) { g_angle = angle; SetSteerAngle(g_angle); sprintf(str, "Steer angle = %2.1f\r\n", g_angle); uart_PSendString(RC_OUTPUT_PORT, str); } } } /* * 左アナログコントローラの上下動作 */ void onPS3AnalogL_UD(void) { } /* * 右アナログコントローラの左右動作 */ void onPS3AnalogR_LR(void) { } /* * 左アナログコントローラの上下動作 */ void onPS3AnalogR_UD(void) { float speed = 0; char str[30]; float cur_analog = p_g_cur_ps3analog[NO_PS3ANALOG_R_UD]; /* ブレーキボタンが押されていればバックランプとブザーを消す */ if (g_isBrake == TRUE) { g_body_cont_info.backlamp = BODY_CONT_OFF; g_body_cont_info.buzzer = BODY_CONT_OFF; return; } /* コントローラの司令値からスピードを求める */ speed = -((cur_analog / 2) * 0.1); /* 司令値に変化があった場合 */ if (g_speed != speed) { float abs_g_speed; float abs_speed; /* * 疑似ブレーキ処理 */ /* 前回司令値と新しい司令値の絶対を求める */ abs_g_speed = (g_speed < 0)? -g_speed : g_speed; abs_speed = (speed < 0)? -speed : speed; if(abs_g_speed > abs_speed){ /* 前回司令値より減った場合はブレーキランプをON */ g_body_cont_info.breaklamp = BODY_CONT_ON; } else { /* 前回司令値より増加した場合はブレーキランプをOFF */ g_body_cont_info.breaklamp = BODY_CONT_OFF; } /* * アクセル処理 */ g_speed = speed; SetDriveSpeed(g_speed/g_speed_gain); if (speed < 0){ g_body_cont_info.backlamp = BODY_CONT_ON; g_body_cont_info.buzzer = BODY_CONT_BLINK; } else { g_body_cont_info.backlamp = BODY_CONT_OFF; g_body_cont_info.buzzer = BODY_CONT_OFF; } sprintf(str, "Drive speed = %1.1f\r\n", speed/g_speed_gain); uart_PSendString(RC_OUTPUT_PORT, str); } } /* * PS3コントローラのデジタルボタン毎の処理 */ #define TOGGLE_ON_OFF(item) item = (item == BODY_CONT_ON)? BODY_CONT_OFF : BODY_CONT_ON; /* * × : ブレーキ */ void onPS3ButtonCrossEdgeOn(void) { g_isBrake = TRUE; SetDriveSpeed(0); g_body_cont_info.breaklamp = BODY_CONT_ON; } void onPS3ButtonCrossEdgeOff(void) { g_isBrake = FALSE; g_body_cont_info.breaklamp = BODY_CONT_OFF; } /* * △ : ハザード */ void onPS3ButtonTriangleEdgeOn(void) { TOGGLE_ON_OFF(g_body_cont_info.hazardlamp); } void onPS3ButtonTriangleEdgeOff(void) { } /* * ○ : メインヘッドライト(ヘッドライト1/ヘッドライト2) 切り替え */ void onPS3ButtonNoughtEdgeOn(void) { TOGGLE_ON_OFF(g_body_cont_info.headlight1); TOGGLE_ON_OFF(g_body_cont_info.headlight2); } void onPS3ButtonNoughtEdgeOff(void) { } /* * □ : フォグ(ヘッドライト3) 切り替え */ void onPS3ButtonSquareEdgeOn(void) { TOGGLE_ON_OFF(g_body_cont_info.headlight3); } void onPS3ButtonSquareEdgeOff(void) { } /* * 左ボタン : ステアリングのニュートラルを調整 */ void onPS3ButtonLeftEdgeOn(void) { AdjustSteerNeturalL(); g_body_cont_info.blinker_l = BODY_CONT_ON; } void onPS3ButtonLeftEdgeOff(void) { g_body_cont_info.blinker_l = (g_blinker_l_blink)? BODY_CONT_BLINK : BODY_CONT_OFF; } /* * 右ボタン : ステアリングのニュートラルを調整 */ void onPS3ButtonRightEdgeOn(void) { AdjustSteerNeturalR(); g_body_cont_info.blinker_r = BODY_CONT_ON; } void onPS3ButtonRightEdgeOff(void) { g_body_cont_info.blinker_r = (g_blinker_r_blink)? BODY_CONT_BLINK : BODY_CONT_OFF; } /* * 上ボタン : ステアリングをニュートラルにする */ void onPS3ButtonUpEdgeOn(void) { InitSteerNetural(); g_body_cont_info.blinker_l = BODY_CONT_ON; g_body_cont_info.blinker_r = BODY_CONT_ON; } void onPS3ButtonUpEdgeOff(void) { g_body_cont_info.blinker_l = (g_blinker_l_blink)? BODY_CONT_BLINK : BODY_CONT_OFF; g_body_cont_info.blinker_r = (g_blinker_r_blink)? BODY_CONT_BLINK : BODY_CONT_OFF; } /* * 下ボタン : モータ制御のゲインを初期値にする */ void onPS3ButtonDownEdgeOn(void) { char str[30]; g_speed_gain = MOTOR_GAIN_INIT; SetDriveSpeed(g_speed/g_speed_gain); g_body_cont_info.blinker_l = BODY_CONT_ON; g_body_cont_info.blinker_r = BODY_CONT_ON; sprintf(str, "Adjust speed gain = %d \r\n", g_speed_gain); uart_PSendString(RC_OUTPUT_PORT, str); } void onPS3ButtonDownEdgeOff(void) { g_body_cont_info.blinker_l = (g_blinker_l_blink)? BODY_CONT_BLINK : BODY_CONT_OFF; g_body_cont_info.blinker_r = (g_blinker_r_blink)? BODY_CONT_BLINK : BODY_CONT_OFF; } /* * L1/R1 : 方向指示器のON/OFF */ void onPS3ButtonL1EdgeOn(void){ if (g_blinker_l_blink) { g_blinker_l_blink = FALSE; /* ボディーへの指示がONの場合は他の機能がONにしているため何もしない */ if (!(g_body_cont_info.blinker_l == BODY_CONT_ON)) { g_body_cont_info.blinker_l = BODY_CONT_OFF; } } else { g_blinker_l_blink = TRUE; /* ボディーへの指示がONの場合は他の機能がONにしているため何もしない */ if (!(g_body_cont_info.blinker_l == BODY_CONT_ON)) { g_body_cont_info.blinker_l = BODY_CONT_BLINK; } } } void onPS3ButtonL1EdgeOff(void) { } void onPS3ButtonR1EdgeOn(void){ if (g_blinker_r_blink) { g_blinker_r_blink = FALSE; /* ボディーへの指示がONの場合は他の機能がONにしているため何もしない */ if (!(g_body_cont_info.blinker_r == BODY_CONT_ON)) { g_body_cont_info.blinker_r = BODY_CONT_OFF; } } else { g_blinker_r_blink = TRUE; /* ボディーへの指示がONの場合は他の機能がONにしているため何もしない */ if (!(g_body_cont_info.blinker_r == BODY_CONT_ON)) { g_body_cont_info.blinker_r = BODY_CONT_BLINK; } } } void onPS3ButtonR1EdgeOff(void) { } /* * L2/R2 : モータ制御のゲインを変更 */ void onPS3ButtonL2EdgeOn(void){ AdjustSpeedGainD(); g_body_cont_info.blinker_l = BODY_CONT_ON; } void onPS3ButtonL2EdgeOff(void){ g_body_cont_info.blinker_l = (g_blinker_l_blink)? BODY_CONT_BLINK : BODY_CONT_OFF; } void onPS3ButtonR2EdgeOn(void){ AdjustSpeedGainU(); g_body_cont_info.blinker_r = BODY_CONT_ON; } void onPS3ButtonR2EdgeOff(void){ g_body_cont_info.blinker_r = (g_blinker_r_blink)? BODY_CONT_BLINK : BODY_CONT_OFF; } /* * ボタンの変化検出のためのマクロ */ #define PS3BUTTON_EDGE_ON(no) ((p_g_pre_ps3button[no] == FALSE) && (p_g_cur_ps3button[no] == TRUE)) #define PS3BUTTON_EDGE_OFF(no) ((p_g_pre_ps3button[no] == TRUE) && (p_g_cur_ps3button[no] == FALSE)) #define PS3ANALOG_CHANGE(no) (p_g_pre_ps3analog[no] != p_g_cur_ps3analog[no]) /* * PS3コントローラからのイベントの処理 */ void onMsgPS3(void) { if (PS3BUTTON_EDGE_OFF(NO_PS3BUTTON_CROSS)){ onPS3ButtonCrossEdgeOff(); } if (PS3BUTTON_EDGE_ON(NO_PS3BUTTON_TRIANGLE)){ onPS3ButtonTriangleEdgeOn(); } if (PS3BUTTON_EDGE_OFF(NO_PS3BUTTON_TRIANGLE)){ onPS3ButtonTriangleEdgeOff(); } if (PS3BUTTON_EDGE_ON(NO_PS3BUTTON_NOUGHT)){ onPS3ButtonNoughtEdgeOn(); } if (PS3BUTTON_EDGE_OFF(NO_PS3BUTTON_NOUGHT)){ onPS3ButtonNoughtEdgeOff(); } if (PS3BUTTON_EDGE_ON(NO_PS3BUTTON_SQUARE)){ onPS3ButtonSquareEdgeOn(); } if (PS3BUTTON_EDGE_OFF(NO_PS3BUTTON_SQUARE)){ onPS3ButtonSquareEdgeOff(); } if (PS3BUTTON_EDGE_ON(NO_PS3BUTTON_LEFT)){ onPS3ButtonLeftEdgeOn(); } if (PS3BUTTON_EDGE_OFF(NO_PS3BUTTON_LEFT)){ onPS3ButtonLeftEdgeOff(); } if (PS3BUTTON_EDGE_ON(NO_PS3BUTTON_RIGHT)){ onPS3ButtonRightEdgeOn(); } if (PS3BUTTON_EDGE_OFF(NO_PS3BUTTON_RIGHT)){ onPS3ButtonRightEdgeOff(); } if (PS3BUTTON_EDGE_ON(NO_PS3BUTTON_UP)){ onPS3ButtonUpEdgeOn(); } if (PS3BUTTON_EDGE_OFF(NO_PS3BUTTON_UP)){ onPS3ButtonUpEdgeOff(); } if (PS3BUTTON_EDGE_ON(NO_PS3BUTTON_DOWN)){ onPS3ButtonDownEdgeOn(); } if (PS3BUTTON_EDGE_OFF(NO_PS3BUTTON_DOWN)){ onPS3ButtonDownEdgeOff(); } if (PS3BUTTON_EDGE_ON(NO_PS3BUTTON_CROSS)){ onPS3ButtonCrossEdgeOn(); } if (PS3BUTTON_EDGE_ON(NO_PS3BUTTON_L1)){ onPS3ButtonL1EdgeOn(); } if (PS3BUTTON_EDGE_ON(NO_PS3BUTTON_R1)){ onPS3ButtonR1EdgeOn(); } if (PS3BUTTON_EDGE_ON(NO_PS3BUTTON_L2)){ onPS3ButtonL2EdgeOn(); } if (PS3BUTTON_EDGE_OFF(NO_PS3BUTTON_L2)){ onPS3ButtonL2EdgeOff(); } if (PS3BUTTON_EDGE_ON(NO_PS3BUTTON_R2)){ onPS3ButtonR2EdgeOn(); } if (PS3BUTTON_EDGE_OFF(NO_PS3BUTTON_R2)){ onPS3ButtonR2EdgeOff(); } if (PS3ANALOG_CHANGE(NO_PS3ANALOG_L_LR)) { onPS3AnalogL_LR(); } if (PS3ANALOG_CHANGE(NO_PS3ANALOG_L_UD)) { onPS3AnalogL_UD(); } if (PS3ANALOG_CHANGE(NO_PS3ANALOG_R_LR)) { onPS3AnalogR_LR(); } if (PS3ANALOG_CHANGE(NO_PS3ANALOG_R_UD)) { onPS3AnalogR_UD(); } }