#include #include "app/sox/soc.h" #include "app/sox/measure.h" #include "app/sox/measure_task.h" #include "app/sox/health.h" #include "app/sox/state.h" #include "app/sox/iostate.h" #include "bsp/gpio.h" #include "bsp/ml5238.h" #include "bsp/fmc_flash.h" #include "bsp/cs1180.h" #include "app/nv_storage.h" #include "libs/logger.h" #include "protocol.h" #include "bms_message.h" #include "event_record.h" #include "protocol_old.h" extern char* bsp_get_fversion(void); static uint8_t bms_insert = 0; static uint8_t bms_insert_ack = 0; //主要用来告知PSxxx是否刚插入,PSxxx答复后需要清除 void bms_message_update_insert(int is_hall_detect){ if (!is_hall_detect){ bms_insert = 0; bms_insert_ack = 0; }else { if (!bms_insert_ack) { bms_insert = 1; } } } static void response_base_info(can_frame_t *frame) { uint8_t *data = NULL; int data_len = 0; binfo_cmd_resp_t bresp; bresp.capacity = get_soc()->capacity; if (get_soc()->coulomb_now >= get_soc()->coulomb_min) { bresp.energy = get_soc()->coulomb_now - get_soc()->coulomb_min; }else{ bresp.energy = 0; } bresp.pack_current = measure_value()->load_current; bresp.pack_voltage = bms_state_get()->pack_voltage; bresp.max_temp = -100; for (int i = 0; i < PACK_TEMPS_NUM; i ++){ if (bresp.max_temp < measure_value()->pack_temp[i]){ bresp.max_temp = measure_value()->pack_temp[i]; } } bresp.health = bms_health()->i_status; if (bms_is_ps_charger_in()) {/*如果在底座或者车上(有充电器),提前置位过高/低温充电标志*/ bresp.health |= (bms_health()->lower_temp_deny_charger << 12 | bms_health()->over_temp_deny_charger << 14); } bresp.health &= ~(1 << 8); bresp.health |= ((get_soc()->flags & SOC_FLAG_CALIBRATED) != 0) << 8; stat_cmd_resp_t sresp; sresp.insert = bms_insert; sresp.is_charging = bms_state_get()->charging; sresp.discharger_fet = ml5238_is_discharging(); sresp.charger_fet = ml5238_is_charging(); sresp.small_power = AUX_VOL_IS_OPEN(); sresp.is_balancing = bms_state_get()->pack_balancing; sresp.health = (((uint16_t )(bms_health()->i_status)) != 0); sresp.is_charger_in = io_state()->charger_detect_irq; bresp.state = *((uint8_t*)&sresp); data = (uint8_t *)&bresp; data_len = sizeof(bresp); if (frame->key == CAN_KEY_BMS_SET_POWER) { u8 response[sizeof(bresp) + 1]; response[0] = 0; memcpy(response + 1, data, data_len); data = response; data_len += 1; } protocol_send_bms_info(frame->head.can_addr, frame->key, data, data_len); } void process_bms_message(can_frame_t *frame, int len){ int result = 0; uint8_t *data = NULL; int data_len = 0; // set_log_all(L_debug); switch(frame->key) { case CAN_KEY_BMS_SET_POWER: if (len != sizeof(pwr_cmd_t) || frame->head.can_addr != 0x42){//开关大电必须42发过来 result = 1; protocol_send_ack(frame->head.can_addr, frame->key, result); }else { pwr_cmd_t *cmd = (pwr_cmd_t *)frame->data; uint32_t user_request = USER_REQUEST_PENDING; if (cmd->charger_mask) { if (cmd->charger_fet){ user_request |= USER_REQUEST_CHARGER_ON; }else { user_request |= USER_REQUEST_CHARGER_OFF; } } if (cmd->discharger_mask) { if (cmd->discharger_fet){ user_request |= USER_REQUEST_DISCHARGER_ON; }else { user_request |= USER_REQUEST_DISCHARGER_OFF; } } if (cmd->small_mask) { if (cmd->small_power){ user_request |= USER_REQUEST_SMALLCURRENT_ON; }else { user_request |= USER_REQUEST_SMALLCURRENT_OFF; } } bms_state_get()->user_request = user_request; response_base_info(frame); } break; case CAN_KEY_BMS_BASE_INFO:{ if (len >= 1) { uint8_t env = frame->data[0]; bms_set_ps_charger_in(1, (env == CW_CHE_SHANG_CHARGER || env == CW_CHONG_DIAN_ZUO)); } response_base_info(frame); break; } case CAN_KEY_BMS_CHARG_INFO:{ cinfo_cmd_resp_t cresp; cresp.charge_current = measure_value()->load_current; cresp.charge_remain_time = soc_get_charger_remain_time(); data = (uint8_t *)&cresp; data_len = sizeof(cresp); protocol_send_bms_info(frame->head.can_addr, frame->key, data, data_len); break; } case CAN_KEY_BMS_CLEAR: bms_insert_ack = 1; bms_insert = 0; bms_work_mode_set(WORK_MODE_AGING_TEST, 0); protocol_send_ack(frame->head.can_addr, frame->key, result); break; case CAN_KEY_BMS_GET_TIME:{ uint32_t time = shark_get_seconds(); data = (uint8_t *)&time; data_len = sizeof(time); protocol_send_bms_info(frame->head.can_addr, frame->key, data, data_len); break; } case CAN_KEY_BMS_GET_STAT: { stat_cmd_resp_t sresp; sresp.insert = bms_insert; sresp.is_charging = bms_state_get()->charging; sresp.discharger_fet = ml5238_is_discharging(); sresp.charger_fet = ml5238_is_charging(); sresp.small_power = AUX_VOL_IS_OPEN(); sresp.is_balancing = bms_state_get()->pack_balancing; sresp.health = (((uint16_t )(bms_health()->i_status)) != 0); sresp.is_charger_in = io_state()->charger_detect_irq; data = (uint8_t *)&sresp; data_len = sizeof(sresp); protocol_send_bms_info(frame->head.can_addr, frame->key, data, data_len); break; } case CAN_KEY_BMS_TEMPS: { u8 temps[PACK_TEMPS_NUM * sizeof(int) + 1]; temps[0] = PACK_TEMPS_NUM; memcpy(temps+1, measure_value()->pack_temp, PACK_TEMPS_NUM * sizeof(int)); data = temps; data_len = PACK_TEMPS_NUM * sizeof(int) + 1; protocol_send_bms_info(frame->head.can_addr, frame->key, data, data_len); break; } case CAN_KEY_AGING_TEMPS:{ u8 temps[2 * PACK_TEMPS_NUM * sizeof(int) + 2]; temps[0] = bms_state_get()->agint_cost_time/60; //分钟 temps[1] = PACK_TEMPS_NUM * 2; memcpy(temps+2, bms_state_get()->aging_start_temp, PACK_TEMPS_NUM * sizeof(int)); memcpy(temps+PACK_TEMPS_NUM * sizeof(int)+2, bms_state_get()->aging_max_temp, PACK_TEMPS_NUM * sizeof(int)); data = temps; data_len = 2 * PACK_TEMPS_NUM * sizeof(int) + 2; protocol_send_bms_info(frame->head.can_addr, frame->key, data, data_len); break; } case CAN_KEY_BMS_GET_CELLS: { cell_cmd_resp_t cells; cells.cell_num = CELLS_NUM; for (int i = 0; i < CELLS_NUM; i++){ cells.voltages[i] = measure_value()->cell_vol[i]; } data = (uint8_t *)&cells; data_len = sizeof(cells); protocol_send_bms_info(frame->head.can_addr, frame->key, data, data_len); break; } case CAN_KEY_GET_SOC_INFO: { soc_info_t soc; soc.c_min = get_soc()->coulomb_min; soc.c_max = get_soc()->coulomb_max; soc.c_now = get_soc()->coulomb_now; soc.c_discharger = get_soc()->dischrger_coulomb; soc.c_charger = get_soc()->charger_coulomb; soc.cycle = soc_get_cycle(); soc.calibrated = (get_soc()->flags & SOC_FLAG_CALIBRATED) != 0; data = (uint8_t *)&soc; data_len = sizeof(soc); protocol_send_bms_info(frame->head.can_addr, frame->key, data, data_len); break; } case CAN_KEY_BMS_GET_HEALTH_STAT: data = (uint8_t *)(&bms_health()->i_status); data_len = sizeof(bms_health()->i_status); protocol_send_bms_info(frame->head.can_addr, frame->key, data, data_len); break; case CAN_KEY_BMS_SET_WORK_MODE: if (len != 2) { result = 1; }else { result = bms_work_mode_set(frame->data[0], frame->data[1]); } protocol_send_ack(frame->head.can_addr, frame->key, result); break; case CAN_KEY_SET_SN: nv_save_sn((uint8_t *)frame->data+1, len-2); protocol_send_ack(frame->head.can_addr, frame->key, result); break; case CAN_KEY_GET_SN: { uint8_t sn[32]; int sn_len = nv_read_sn(sn, sizeof(sn)); if (sn_len <= 0){ sn[0] = 'B'; memset(sn + 1, '0', sizeof(sn) - 1); sn_len = 18; } data = (u8 *)sn; data_len = sn_len; protocol_send_bms_info(frame->head.can_addr, frame->key, data, data_len); break; } case CAN_KEY_GET_VERSION: { data = (u8*)bsp_get_fversion(); data_len = strlen((char *)data); protocol_send_bms_info(frame->head.can_addr, frame->key, data, data_len); break; } case CAN_KEY_SET_LOGGER: if (len < 1) { set_log_all(L_debug); ml5238_reg_log(); //just for debug cs1180_log(); health_log(); soc_log(); bms_state_log(); result = 1; } else if (len < 2) { set_log_all(frame->data[0]); ml5238_reg_log(); //just for debug cs1180_log(); health_log(); soc_log(); bms_state_log(); } else if (len < 3){ set_log_level(frame->data[0], frame->data[1]); } protocol_send_ack(frame->head.can_addr, frame->key, result); break; case CAN_KEY_RESTORE_NV: { restore_nv_cmd_t *nv = (restore_nv_cmd_t *)frame->data; nv_save_sn(nv->sn, nv->sn_len); soc_restore_by_iap(nv->flags, nv->capacity); protocol_send_ack(frame->head.can_addr, frame->key, 1); break; } case CAN_KEY_MIN_SOC: get_soc()->coulomb_now -= get_soc()->coulomb_min; if (get_soc()->coulomb_now < 0) { get_soc()->coulomb_now = 0; } get_soc()->coulomb_min = (u32)frame->data[0] * 3600.0f; get_soc()->coulomb_now += get_soc()->coulomb_min; get_soc()->capacity =((get_soc()->coulomb_now - get_soc()->coulomb_min)/(get_soc()->coulomb_max - get_soc()->coulomb_min) + 0.005f) * 100; nv_save_all_soc(); protocol_send_ack(frame->head.can_addr, frame->key, 1); break; case CAN_KEY_GET_EVENT: { u8 event[sizeof(event_record_t) * 8 + 1]; u16 offset = DECODE_U16(frame->data); int num = get_event(8, offset, event + 1); *event = (u8)num; protocol_send_bms_info(frame->head.can_addr, frame->key, event, sizeof(event_record_t) * num + 1); break; } case CAN_KEY_POWERDOWN: { if (len < 4) { return; } /*magic 0xFF005AA5*/ if (frame->data[0] == 0xA5 && frame->data[1] == 0x5A && frame->data[2] == 0x00 && frame->data[3] == 0xFF) { bms_work_mode_set(WORK_MODE_PCBA_TEST, 1); system_power_down(); } break; } case CAN_KEY_FACTORY_RESULT: { if (len == 1) { nv_save_factory_result(frame->data[0]); } uint8_t res = nv_read_factory_result(); protocol_send_ack(frame->head.can_addr, frame->key, res); break; } default: break; } }