BMS55 RS232 PROTOCOL DRAFT 27.8.2010 (c) Perttu Ahola, celeron55@gmail.com License: WTFPL RS232 PROTOCOL: Baud rate is 38400 bps. - Line format from BMS to Client: ":<valuename>=<value>,[...][,]\r\n" - Order of values is not constant. There can be an ending comma, or not. - Titles and valuenames are in lowercase. - Line format from Client to BMS: "<command> [parameter] [...]\r\n" - The BMS doesn't echo back characters. - For convenience, the backspace character (127) is supported for easier debugging on a serial terminal. Clients should allow and ignore unknown titles and valuenames. It might be wise to report a possible version mismatch somehow to the user, though. When a line (ending in "\r\n") is sent to the BMS, the client has to wait for the BMS to send out a '$', after which the client can send an another line. '$' is always sent on its own line. Example communication (C = Client->BMS, B = BMS->Client): Client can send an empty command "\r\n" to see if the BMS is awake. If it is, it will reply with B: "protocol:commands=version status set nodes\r\n" or similar, followed by a '$' - The BMS replies fairly slowly. Timeout should generally be a few seconds for a 12-cell system. - Asking node info: C: "nodes\r\n" B: "nodes:count=12\r\n" B: "node:n=1,status=commfail ,\r\n" B: "node:n=2,status=text_hl,volt=3527,temp=20,shunt=0,text=Normal operation,\r\n" B: "node:n=3,status=error_nop commfail,\r\n" B: ... Possible values for "nodes:" - count=integer // The number of nodes Possible values for "node:" - n=integer // Node number (1 - 254) - status (can be many) =commfail // Fails to reply or replies random things =cellfail // Cell is getting damaged because of failure =elecfail // Electronics are getting damaged because of failure =error_nop // There is a non-fatal error. No operation allowed. =text_hl // The status text should be hilighted to the user - volt=integer // Node voltage (millivolts) - temp=integer // Node temperature (degrees celsius) - shunt=integer // Shunt usage, 0-255, where 127 is maximum continuous usage - text=string // Status text, can include spaces, should not include a '$', maximum length is 16. - Handling settings: - The client can ask for all the settings: C: "set\r\n" B: "set:cell_count=12\r\n" B: ... - The client can ask for a single setting: C: "set cell_voltage_max_fatal\r\n" B: "set:cell_voltage_max_fatal=4400\r\n" - The client can change a setting: C: "set cell_voltage_min 2800\r\n" B: "set:cell_voltage_min=2800\r\n" - The values of the settings are integers. - The settings are saved in EEPROM, so they should not be changed very often. The EEPROM lasts for 100 000 read/write cycles, so a few times a day doesn't hurt. // TODO: list of settings - Here's a crude list of settings copied from the code: SETTING_VARIABLE(uint8_t, cell_count, 12); SETTING_VARIABLE(uint16_t, cell_voltage_min_fatal, 2000); SETTING_VARIABLE(uint16_t, cell_voltage_max_fatal, 4400); SETTING_VARIABLE(uint16_t, cell_voltage_min, 3000); SETTING_VARIABLE(uint16_t, cell_voltage_max, 4200); SETTING_VARIABLE(int8_t, cell_temperature_min_fatal, -30); SETTING_VARIABLE(int8_t, cell_temperature_max_fatal, 50); SETTING_VARIABLE(uint8_t, debug_jam, 0); SETTING_VARIABLE(uint16_t, charge_current_max, 1000); - Asking status: - The client can ask for status: C: "status\r\n" B: status:fatal_error=0 B: status:uptime=1278 B: status:voltage_psu=18177 B: ... - Status variables are integers and strings. // TODO: list of status variables - Again, a crude listing from the code: VAR_TRANSMIT_UINT8("fatal_error", g_fatal_error); VAR_TRANSMIT_INT32("uptime", g_uptime_seconds); VAR_TRANSMIT_INT32("voltage_psu", g_voltage_psu); VAR_TRANSMIT_INT32("voltage_battery", g_voltage_battery); VAR_TRANSMIT_INT32("node_voltage_sum", g_node_voltage_sum); VAR_TRANSMIT_INT32("charge_current", g_charge_current); VAR_TRANSMIT_UINT8("settings_saved", g_settings_changed == -1 ? 1 : 0); - Asking version: - The client can ask for the version of the Master: C: "version\r\n" B: "version:bms55-0.0.1\r\n" - Calibrating temperature: - The client can calibrate the temperature sensors of the system. - E.g. calibrate to 20 degrees celsius C: "temp_calibrate 20\r\n" - The operation is carried out asynchronously, and will finish in some seconds. Messages sent by the Master: - info: These lines should probably be ignored by most clients B: "info: bms55 (c) Perttu Ahola <celeron55@gmail.com>\r\n" - These lines don't follow the valuename=value rule. - protocol: Sent when the Master doesn't understand what the client is sending. The client should try again whatever it did - if it fails again, it should report a communication error to the user. C: "order kebab\r\n" B: "protocol:commands=version status set nodes\r\n" C: "order kebab\r\n" B: "protocol:commands=version status set nodes\r\n" C: "fuck it.\r\n" B: "protocol:commands=version status set nodes\r\n" - bootup: At boot-up, the BMS reports a possible reset source: - Any of these: B: "bootup:reset=watchdog\r\n" B: "bootup:reset=brown-out\r\n" B: "bootup:reset=external\r\n" B: "bootup:reset=none\r\n" - A watchdog reset should be considered as a fairly serious error. It can occur repeatedly in case of a bug in the software. - A brown-out reset means low voltage. Coming out of nowhere, it means unstable voltage. It usually occurs at normal boot-up. - An external reset can occur when the chip is programmed, for example. Should not occur in normal usage. An example session: // Let's assume the client has just booted up and is connected to // the BMS. // Client sends an empty command to see if BMS is alive C: "\r\n" B: "protocol:commands=version status set nodes temp_calibrate\r\n" B: "$" // OK, BMS takes commands. Client might check version for maximum // compatibility. C: "version\r\n" B: "version:bms55-0.0.1\r\n" B: "$" // Gather some data for showing to the user C: "status\r\n" B: "status:fatal_error=1\r\n" B: "status:uptime=402054\r\n" B: "status:voltage_psu=47660\r\n" B: "status:voltage_battery=39600\r\n" B: "status:voltage_node_sum=0\r\n" B: "status:current_charger=0\r\n" B: "status:settings_saved=1\r\n" B: "$" // Looks like there is a serious problem... // Ask for info about the nodes C: "nodes\r\n" B: "nodes:count=12\r\n" B: "node:n=1,status=commfail ,\r\n" B: "node:n=2,status=commfail ,\r\n" B: "node:n=3,status=commfail ,\r\n" B: "node:n=4,status=commfail ,\r\n" B: "node:n=5,status=commfail ,\r\n" B: "node:n=6,status=commfail ,\r\n" B: "node:n=7,status=commfail ,\r\n" B: "node:n=8,status=commfail ,\r\n" B: "node:n=9,status=commfail ,\r\n" B: "node:n=10,status=commfail ,\r\n" B: "node:n=11,status=commfail ,\r\n" B: "node:n=12,status=commfail ,\r\n" B: "$" // Now this looks quite fatal. No nodes at all are connected! // Assume that the user goes to a "settings" menu. // Client probably caches the settings, but it's a good time to // update those. C: "set\r\n" B: "set:cell_count=12\r\n" B: "set:cell_voltage_min_fatal=2000\r\n" B: "set:cell_voltage_max_fatal=4400\r\n" B: "set:cell_voltage_min=3000\r\n" B: "set:cell_voltage_max=4200\r\n" B: "set:cell_temperature_min_fatal=-30\r\n" B: "set:cell_temperature_max_fatal=50\r\n" B: "set:debug_jam=0\r\n" B: "set:charge_current_max=500\r\n" B: "$" // The user changes a setting. C: "set cell_count 12\r\n" B: "set:cell_count=12\r\n" B: "$"