| | |
| | | |
| | | #define DEBUG(fmt, args...) LOGD("<road_exam dummy_light> <%s>: " fmt, __func__, ##args) |
| | | |
| | | enum { |
| | | TTS_NOT_START, |
| | | TTS_DOING, |
| | | TTS_DONE, |
| | | WAIT_OPERATE, |
| | | CHECK_OPERATE |
| | | }; |
| | | |
| | | static struct RtkTime currRtkTime; |
| | | static struct dummy_light_exam *content; |
| | | static int contentNum; |
| | | |
| | | static int checkCnt; |
| | | static bool turn_left_active, flash_beam_active; |
| | | static int question; |
| | | |
| | | static int examTtsSeq = 0; |
| | | static vector<int> process; |
| | | |
| | | static bool testing; |
| | | |
| | | static void DummyLightCheckActive(union sigval sig); |
| | | static void ExamDummyLight(union sigval sig); |
| | | static void CheckSolution(union sigval sig); |
| | | static void ExamDummyLight(void); |
| | | |
| | | void StartDummyLightExam(struct dummy_light_exam *ptr, int num, const struct RtkTime* rtkTime) |
| | | { |
| | | DEBUG("StartDummyLightExam"); |
| | | content = ptr; |
| | | contentNum = num; |
| | | question = 0; |
| | | |
| | | if (content != NULL && num > 0) { |
| | | DEBUG("启动灯光"); |
| | | currRtkTime = *rtkTime; |
| | | |
| | | for (int i = 0; i < contentNum; ++i) { |
| | | content[i].itemStatus = TTS_NOT_START; |
| | | |
| | | DEBUG("灯光项目 <%d> item %d, TTS %s", i, content[i].item, content[i].tts); |
| | | DEBUG("灯光项目 <%d> item %d, TTS %s", i, content[i].item, content[i].tts.c_str()); |
| | | } |
| | | testing = true; |
| | | |
| | | AppTimer_delete(DummyLightCheckActive); |
| | | AppTimer_delete(ExamDummyLight); |
| | | AppTimer_add(ExamDummyLight, D_SEC(2)); |
| | | AppTimer_delete(CheckSolution); |
| | | ExamDummyLight(); |
| | | } else { |
| | | testing = false; |
| | | } |
| | | } |
| | | |
| | | int ExecuteDummyLightExam(const struct RtkTime* rtkTime) |
| | | bool ExecuteDummyLightExam(const struct RtkTime* rtkTime) |
| | | { |
| | | currRtkTime = *rtkTime; |
| | | return (testing)?1:2; |
| | | return testing; |
| | | } |
| | | |
| | | void DummyLightTTSDone(int id) |
| | | { |
| | | // 等语音播报完毕后计时 |
| | | if (id == examTtsSeq && testing) { |
| | | if (testing) { |
| | | vector<int>().swap(process); |
| | | |
| | | for (int i = 0; i < contentNum; ++i) { |
| | | if (content[i].itemStatus == TTS_DOING) { |
| | | DEBUG("DummyLightTTSDone item %d", content[i].item); |
| | | content[i].itemStatus = TTS_DONE; |
| | | break; |
| | | // 预读取有中间操作步骤的灯光 |
| | | for (int i = 0; i < content[question].process.size(); ++i) { |
| | | if (ReadCarStatus((content[question].process[i]>>8) & 0xFF) == content[question].process[i] & 0xFF) { |
| | | process.push_back(content[question].process[i]); |
| | | } |
| | | } |
| | | |
| | | AppTimer_add(ExamDummyLight, 100); |
| | | AppTimer_delete(CheckSolution); |
| | | AppTimer_add(CheckSolution, D_SEC(5)); |
| | | } |
| | | } |
| | | |
| | | void TerminateDummyLightExam(void) |
| | | { |
| | | testing = false; |
| | | AppTimer_delete(DummyLightCheckActive); |
| | | AppTimer_delete(ExamDummyLight); |
| | | AppTimer_delete(CheckSolution); |
| | | } |
| | | |
| | | static void DummyLightCheckActive(union sigval sig) |
| | | void handleLigthExam(uint16_t id, int value) |
| | | { |
| | | int active = sig.sival_int; |
| | | AppTimer_delete(DummyLightCheckActive); |
| | | DEBUG("DummyLightCheckActive item = %d", active); |
| | | if (testing) { |
| | | for (int i = 0; i < content[question].process.size(); ++i) { |
| | | if (id == ((content[question].process[i] >> 8) & 0xFF) && value == (content[question].process[i] & 0xFF)) { |
| | | if (process.size() == 0 || process.back() != content[question].process[i]) { |
| | | process.push_back(content[question].process[i]); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | switch (active) { |
| | | case DRIVE_AT_NIGHT: |
| | | case TURN_ON_MAIN_BEAM_LAMP: |
| | | if (ReadCarStatus(MAIN_BEAM_LAMP) != MAIN_BEAM_LIGHT) { |
| | | AddExamFault(58, &currRtkTime); |
| | | } |
| | | break; |
| | | case TURN_ON_DIPPED_LAMP: |
| | | case BRIDGE_MEET_CAR: |
| | | case FOLLOW_CAR: |
| | | if (ReadCarStatus(DIPPED_BEAM_LAMP) != DIPPED_BEAM_LIGHT) { |
| | | AddExamFault(58, &currRtkTime); |
| | | } |
| | | break; |
| | | case DRIVE_IN_FOG: |
| | | if (ReadCarStatus(FOG_LAMP) != FOG_LIGHT) { |
| | | AddExamFault(58, &currRtkTime); |
| | | } |
| | | break; |
| | | case THROUGE_CROSSWALK: |
| | | case THROUGE_CURVE: |
| | | case THROUGE_CROSSROADS: |
| | | if (++checkCnt < 5) { |
| | | if (ReadCarStatus(FLASH_BEAM_LAMP) == FLASH_BEAM_LIGHT) { |
| | | flash_beam_active = true; |
| | | } |
| | | AppTimer_add(DummyLightCheckActive, D_SEC(1), active); |
| | | return; |
| | | } else { |
| | | if (!flash_beam_active) { |
| | | AddExamFault(58, &currRtkTime); |
| | | static void CheckSolution(union sigval sig) |
| | | { |
| | | int question = sig.sival_int; |
| | | |
| | | AppTimer_delete(CheckSolution); |
| | | |
| | | if (content[question].process.size() > 0) { |
| | | if (content[question].process.size() != process.size()) { |
| | | AddExamFault(content[question].wrongCode, &currRtkTime); |
| | | goto NEXT_LIGHT; |
| | | } else { |
| | | // 操作顺序也要满足 |
| | | for (int i = 0; i < content[question].process.size(); ++i) { |
| | | if (process[i] != content[question].process[i]) { |
| | | AddExamFault(content[question].wrongCode, &currRtkTime); |
| | | goto NEXT_LIGHT; |
| | | } |
| | | } |
| | | break; |
| | | case OVERTAKE: |
| | | if (++checkCnt < 5) { |
| | | if (!flash_beam_active) { |
| | | if (ReadCarStatus(TURN_SIGNAL_LAMP) == LEFT_TURN_LIGHT) { |
| | | turn_left_active = true; |
| | | } |
| | | } |
| | | if (turn_left_active) { |
| | | if (ReadCarStatus(FLASH_BEAM_LAMP) == FLASH_BEAM_LIGHT) { |
| | | flash_beam_active = true; |
| | | } |
| | | } |
| | | AppTimer_add(DummyLightCheckActive, D_SEC(1), OVERTAKE); |
| | | return; |
| | | } else { |
| | | if (!flash_beam_active || !turn_left_active) { |
| | | AddExamFault(58, &currRtkTime); |
| | | } |
| | | } |
| | | break; |
| | | case CAR_FAULT: |
| | | case PARK_CAR_TEMP: |
| | | if (ReadCarStatus(TURN_SIGNAL_LAMP) != HAZARD_LIGHTS) { |
| | | AddExamFault(58, &currRtkTime); |
| | | } |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | } |
| | | |
| | | for (int i = 0; i < contentNum; ++i) { |
| | | if (content[i].item == active) { |
| | | content[i].itemStatus = CHECK_OPERATE; |
| | | for (int i = 0; i < content[question].solution.size(); ++i) { |
| | | if (ReadCarStatus((content[question].solution[i]>>8)&0xFF) != content[question].solution[i] & 0xFF) { |
| | | AddExamFault(content[question].wrongCode, &currRtkTime); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | AppTimer_add(ExamDummyLight, 500); |
| | | NEXT_LIGHT: |
| | | question++; |
| | | ExamDummyLight(); |
| | | } |
| | | |
| | | static void ExamDummyLight(union sigval sig) |
| | | static void ExamDummyLight(void) |
| | | { |
| | | int i = 0; |
| | | AppTimer_delete(ExamDummyLight); |
| | | |
| | | for (; i < contentNum; ++i) { |
| | | switch (content[i].itemStatus) { |
| | | case TTS_NOT_START: |
| | | DEBUG("提示语言 %d: %s", content[i].item, content[i].tts); |
| | | content[i].itemStatus = TTS_DOING; |
| | | examTtsSeq = PlayTTS(content[i].tts, DummyLightTTSDone); |
| | | // 等待TTS播放完毕 |
| | | return; |
| | | case TTS_DOING: |
| | | return; |
| | | case TTS_DONE: |
| | | content[i].itemStatus = WAIT_OPERATE; |
| | | |
| | | AppTimer_delete(DummyLightCheckActive); |
| | | |
| | | DEBUG("提示语言完毕 %d", content[i].item); |
| | | |
| | | if (content[i].item == OVERTAKE) { |
| | | checkCnt = 0; |
| | | turn_left_active = flash_beam_active = false; |
| | | AppTimer_add(DummyLightCheckActive, D_SEC(1), content[i].item); |
| | | } else if (content[i].item == THROUGE_CROSSWALK || content[i].item == THROUGE_CURVE || content[i].item == THROUGE_CROSSROADS) { |
| | | checkCnt = 0; |
| | | flash_beam_active = false; |
| | | AppTimer_add(DummyLightCheckActive, D_SEC(1), content[i].item); |
| | | } else if (content[i].item >= 100) |
| | | AppTimer_add(DummyLightCheckActive, D_SEC(3), content[i].item); |
| | | else |
| | | AppTimer_add(DummyLightCheckActive, D_SEC(5), content[i].item); |
| | | return; |
| | | case WAIT_OPERATE: |
| | | return; |
| | | case CHECK_OPERATE: |
| | | default: |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (i >= contentNum) { |
| | | if (testing && question < contentNum) { |
| | | PlayTTS(content[question].tts, DummyLightTTSDone); |
| | | } else { |
| | | testing = false; |
| | | } |
| | | } |