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:
"
:=,[...][,]\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:
" [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 \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: "$"