bms_interface.cpp
Go to the documentation of this file.
1 //
2 // Created by sub on 22/10/17.
3 //
4 
5 #include <iostream>
7 
8 namespace bms
9 {
10  void BMSInterface::connect(std::string port)
11  {
12  file_handle_ = ::open(port.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
13  if (file_handle_ < 0)
14  throw BMSErrorException("Failed to open BMS port");
15 
16  // Check if the file descriptor is pointing to a TTY device or not.
17  if(!isatty(file_handle_))
18  throw BMSErrorException("BMS port is not a tty device");
19 
20  setAttributes();
21  }
22 
24  {
25  struct termios tty;
26 
27  if (tcgetattr(file_handle_, &tty) < 0)
28  throw BMSErrorException("Failed to get BMS port attributes");
29 
30  cfsetospeed(&tty, (speed_t)BAUD_RATE);
31  cfsetispeed(&tty, (speed_t)BAUD_RATE);
32  tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
33  tty.c_cflag &= ~CSIZE;
34  tty.c_cflag |= CS8; /* 8-bit characters */
35  tty.c_cflag &= ~PARENB; /* no parity bit */
36  tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
37  tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
38 
39  /* setup for non-canonical mode */
40  tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
41  tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
42  tty.c_oflag &= ~OPOST;
43 
44  /* fetch bytes as they become available */
45  tty.c_cc[VMIN] = 1;
46  tty.c_cc[VTIME] = 1;
47  if (tcsetattr(file_handle_, TCSANOW, &tty) != 0)
48  throw BMSErrorException("Failed to set BMS port attributes");
49 
50  tcflush(file_handle_,TCIOFLUSH);
51  }
52 
54  {
55  char buff[BUFF_SIZE];
56  int pkg_size = readPkgFromBMS(buff, BUFF_SIZE);
57 
58  //fprintf(stderr, "\n") ; /////////////////////////////////////////////////////////////////////////////////////////
59 
60  return decodePkg(buff, pkg_size);
61  }
62 
63 
64  //:018252008A0000000000000037B0070FE90FEA0FEA0FE80FE90FE90FEA0000000005434343424300000000000000000F00000000000000000000000000035E00B900C87E~
65  /* param: chars buffer, buffer size limit */
66  /* return: number of incoming bytes */
67  int BMSInterface::readPkgFromBMS(char *buff, size_t buff_size_limit)
68  {
69  int write_len, read_len;
70  unsigned char data_in;
71 
72  int indx = 0;
73  int bad_reads = 0;
74  bool first_read = true;
75 
76  /* ask BMS to send back data */
77  write_len = ::write(file_handle_, SEND_ME_DATA_.c_str(), SEND_ME_DATA_.length());
78  if (write_len != SEND_ME_DATA_.length())
79  throw BMSWarnException("Failed to write to BMS");
80 
81  /* read incoming BMS data */
82  while (bad_reads < MAX_BAD_READS &&
83  indx + 1 < buff_size_limit)
84  {
85 
86  read_len = ::read(file_handle_, &data_in, 1);
87  if (read_len != 1)
88  {
89  bad_reads ++;
90  continue;
91  }
92  else
93  {
94  //fprintf(stderr, "%c", data_in) ; /////////////////////////////////////////////////////////////////////////////////////////
95  if (first_read)
96  {
97  if (data_in != BMS_PKG_START_DELIM)
98  throw BMSWarnException("Invalid BMS pkg start delimiter");
99  else
100  first_read = false;
101  }
102  buff[indx] = data_in;
103  if (data_in == BMS_PKG_END_DELIM) //done reading
104  return indx + 1; //add 1 because indx starts from 0
105  indx++;
106  }
107  }
108 
109  throw BMSWarnException("Invalid BMS data");
110  }
111 
112  /********************************************************************
113  * ------------------BMS packet example------------------------------
114  *: (SOI), 01 (addr), 82 (cmd), 52 (ver), 0090 (len), 00000000000000
115  * (time_t) 48F8 (Vbat), 0A (cell_num=10), 0EA9 (v1), 0EB3 (v2), 0EB6
116  * (v3), 0EB4 (v4), 0E8C (v5), 0EB4 (v6), 0E45 (v7), 0E9E (v8), 0E9E
117  * (v9), 0E6A (v10), 0000 (curr[0]), 0000 (curr[1]), 02 (TempNum), 47
118  * (temp[0]), 45 (temp[1]), 0000 (Vstate), 0000 (Cstate), 0000
119  * (Tstate), 0000 (Alarm), 0F (FetState),0000 (WARN_VOV), 0000
120  * (WARN_VUV), 0000 (NUM_WARN_VHIGH), 0000 (NUM_WARN_VLOW), 0000
121  * (BlanceState), 0000 (DchgNum), 0000 (ChgNum), 2D (soc), 0048
122  * ( CapNow ),00A0( CapFull ),4E( CRC ),~( EOI )
123  ********************************************************************/
124  data BMSInterface::decodePkg(char *buff, size_t buff_size)
125  {
126  //fprintf(stderr, "\nbuff_size: %d \n", buff_size);
127  data pkg_data;
128 
129  /****** validate pkg size ******/
130  pkg_data.len = fetchParam(buff, BMS_PKG_LEN_INDX, BMS_PKG_LEN_SIZE);
131  //fprintf(stderr, "\nlen: %d \n", pkg_data.len);
132  if (pkg_data.len != buff_size)
133  throw BMSWarnException("BMS pkg len doesn't mach incoming pkg length - corrupted pkg");
134 
135  /****** validate crc checksum ******/
136  char crc[BMS_PKG_CRC_SIZE + 1]; //+1 to make room for \0
137  crc[BMS_PKG_CRC_SIZE] = '\0';
138  const int crc_indx = buff_size - BMS_PKG_CRC_BACK_OFFSET;
139 
140  uint8_t pkg_crc = fetchParam(buff, crc_indx, BMS_PKG_CRC_SIZE);
141  //fprintf(stderr, "\ncrc: %d \n", pkg_crc);
142 
143  //calc pkg data crc
144  uint8_t calc_crc = 0;
145  for (int i = BMS_PKG_START_DELIM_LEN; i < crc_indx; i++)
146  calc_crc += buff[i];
147  calc_crc ^= 0xff;
148 
149  if (pkg_crc != calc_crc)
150  throw BMSWarnException("Invalid BMS pkg CRC");
151 
152  /****** fetch addr ******/
154  //fprintf(stderr, "\naddr: %d \n", pkg_data.addr);
155 
156  /****** fetch cmd ******/
157  pkg_data.cmd = fetchParam(buff, BMS_PKG_CMD_INDX, BMS_PKG_CMD_SIZE);
158  if (pkg_data.cmd != BMS_PKG_CMD_SUCCESS)
159  throw BMSWarnException("BMS cmd flag indicating failure");
160  //fprintf(stderr, "\ncmd: %d \n", pkg_data.cmd);
161 
162  /****** fetch version ******/
163  pkg_data.ver = fetchParam(buff, BMS_PKG_VER_INDX, BMS_PKG_VER_SIZE);
164  if (pkg_data.ver != BMS_PKG_PROTOCOL_VERSION)
165  throw BMSErrorException("BMS protocol version is not supported by this API");
166  //fprintf(stderr, "\nversion: %d \n", pkg_data.ver);
167 
168  /****** fetch time ******/
169  //protocol doesn't implementing time (battery always return time 0)
171  //fprintf(stderr, "\ntime: %d \n", pkg_data.time);
172 
173  /****** fetch Vbat ******/
174  uint16_t raw_vbat = fetchParam(buff, BMS_PKG_VBAT_INDX, BMS_PKG_VBAT_SIZE); //output is 0.5 of the total voltage
175  pkg_data.vbat = (float)raw_vbat * 2.0 / 1000.0;
176  //fprintf(stderr, "\nVbat: %f \n", pkg_data.vbat);
177 
178  /****** fetch cells num ******/
180  //fprintf(stderr, "\ncell_num: %d \n", pkg_data.cell_num);
181 
182  const uint8_t cells_indx_offset = pkg_data.cell_num * BMS_PKG_CELL_SIZE;
183 
184 
185  /****** fetch cells voltage ******/
186  for (uint8_t cell_indx = 0; cell_indx < pkg_data.cell_num; cell_indx++)
187  {
188  uint16_t raw_vcell = fetchParam(buff, BMS_PKG_CELLS_ARR_INDX + (cell_indx * BMS_PKG_CELL_SIZE),
189  BMS_PKG_CELL_SIZE);
190  pkg_data.vcells.push_back((float)raw_vcell / 1000.0);
191  //fprintf(stderr, "cell num: %d volt: %f | ", cell_indx ,pkg_data.vcells[cell_indx]);
192  }
193  //fprintf(stderr, "\n");
194 
195  /****** fetch CHG ******/
196  uint16_t raw_chg = fetchParam(buff, BMS_PKG_CHRG_CURR_INDX + cells_indx_offset, BMS_PKG_CHRG_CURR_SIZE);
197  pkg_data.chrg_current = (float)raw_chg / 100.0;
198  //fprintf(stderr, "\nchrg_current: volt: %f\n", pkg_data.chrg_current);
199 
200  /****** fetch DCHG ******/
201  uint16_t raw_dchg = fetchParam(buff, BMS_PKG_DCHRG_CURR_INDX + cells_indx_offset, BMS_PKG_DCHRG_CURR_SIZE);
202  pkg_data.dchrg_current = (float)raw_dchg / 100.0;
203  //fprintf(stderr, "\ndchrg_current: volt: %f\n", pkg_data.dchrg_current);
204 
205  /****** fetch TempNum ******/
206  pkg_data.temp_num = fetchParam(buff, BMS_PKG_TEMP_NUM_INDX + cells_indx_offset, BMS_PKG_TEMP_NUM_SIZE);
207  //fprintf(stderr, "\ntemp_num: %d\n", pkg_data.temp_num);
208 
209  const uint8_t temp_indx_offset = pkg_data.temp_num * BMS_PKG_TEMP_SIZE;
210 
211  /****** fetch temp sensors ******/
212  for (uint8_t temp_indx = 0; temp_indx < pkg_data.temp_num; temp_indx++)
213  {
214  uint8_t temp = fetchParam(buff, BMS_PKG_TEMPS_ARRAY_INDX + cells_indx_offset + (temp_indx * BMS_PKG_TEMP_SIZE),
215  BMS_PKG_TEMP_SIZE);
216  if (temp > pkg_data.temp_max)
217  pkg_data.temp_max = temp;
218  pkg_data.temps.push_back(temp);
219  //fprintf(stderr, "temp num: %d temp: %d | ", temp_indx ,pkg_data.temps[temp_indx]);
220  }
221  //fprintf(stderr, "\ntemp max: %d", pkg_data.temp_max);
222  //fprintf(stderr, "\n");
223 
224  /****** fetch Vstate ******/
225  pkg_data.vstate = fetchParam(buff, BMS_PKG_VSTATE_INDX + temp_indx_offset + cells_indx_offset,
227  //fprintf(stderr, "\nVSTATE: %d\n", pkg_data.vstate);
228 
229  /****** fetch Cstate ******/
230  pkg_data.cstate = fetchParam(buff, BMS_PKG_CSTATE_INDX + temp_indx_offset + cells_indx_offset,
232  //fprintf(stderr, "\nCSTATE: %d\n", pkg_data.cstate);
233  pkg_data.is_chrg = getBitInWord(pkg_data.cstate, 0);
234  pkg_data.is_dchrg = getBitInWord(pkg_data.cstate, 1);
235 
236  /****** fetch Tstate ******/
237  pkg_data.tstate = fetchParam(buff, BMS_PKG_TSTATE_INDX + temp_indx_offset + cells_indx_offset,
239  //fprintf(stderr, "\nTSTATE: %d\n", pkg_data.tstate);
240 
241  /****** fetch Alarm ******/
242  pkg_data.alarm = fetchParam(buff, BMS_PKG_ALARM_INDX + temp_indx_offset + cells_indx_offset,
244  //fprintf(stderr, "\nALARM: %d\n", pkg_data.alarm);
245 
246  /****** fetch FetState ******/
247  pkg_data.fet_state = fetchParam(buff, BMS_PKG_FET_STATE_INDX + temp_indx_offset + cells_indx_offset,
249  //fprintf(stderr, "\nFET-STATE: %d\n", pkg_data.fet_state);
250 
251  /****** fetch WARN_VOV ******/
252  pkg_data.warn_vov = fetchParam(buff, BMS_PKG_WARN_VOV_INDX + temp_indx_offset + cells_indx_offset,
254  //fprintf(stderr, "\nWARN_VOV: %d\n", pkg_data.warn_vov);
255 
256  /****** fetch WARN_VUV ******/
257  pkg_data.warn_vuv = fetchParam(buff, BMS_PKG_WARN_VUV_INDX + temp_indx_offset + cells_indx_offset,
259  //fprintf(stderr, "\nWARN_VUV: %d\n", pkg_data.warn_vuv);
260 
261  /****** fetch NUM_WARN_VHIGH ******/
262  pkg_data.num_warn_vhigh = fetchParam(buff, BMS_PKG_NUM_WARN_VHIGH_INDX + temp_indx_offset + cells_indx_offset,
264  //fprintf(stderr, "\nNUM_WARN_VHIGH: %d\n", pkg_data.num_warn_vhigh);
265 
266  /****** fetch NUM_WARN_VLOW ******/
267  pkg_data.num_warn_vlow = fetchParam(buff, BMS_PKG_NUM_WARN_VLOW_INDX + temp_indx_offset + cells_indx_offset,
269  //fprintf(stderr, "\nNUM_WARN_VLOW: %d\n", pkg_data.num_warn_vlow);
270 
271  /****** fetch BalanceState ******/
272  pkg_data.balance_state = fetchParam(buff, BMS_PKG_BALANCE_STATE_INDX + temp_indx_offset + cells_indx_offset,
274  //fprintf(stderr, "\nBALANCE_STATE: %d\n", pkg_data.balance_state);
275 
276  /****** fetch DchgNum ******/
277  pkg_data.dchg_num = fetchParam(buff, BMS_PKG_DCHG_NUM_INDX + temp_indx_offset + cells_indx_offset,
279  //fprintf(stderr, "\nDCHG_NUM: %d\n", pkg_data.dchg_num);
280 
281  /****** fetch ChgNum ******/
282  pkg_data.chg_num = fetchParam(buff, BMS_PKG_CHG_NUM_INDX + temp_indx_offset + cells_indx_offset,
284  //fprintf(stderr, "\nCHG_NUM: %d\n", pkg_data.chg_num);
285 
286  /****** fetch soc ******/
287  pkg_data.soc = fetchParam(buff, BMS_PKG_SOC_INDX + temp_indx_offset + cells_indx_offset,
289  //fprintf(stderr, "\nSOC: %d\n", pkg_data.soc);
290 
291  /****** fetch CapNow ******/
292  pkg_data.cap_now = fetchParam(buff, BMS_PKG_CAP_NOW_INDX + temp_indx_offset + cells_indx_offset,
293  BMS_PKG_CAP_NOW_SIZE) / 10;
294  //fprintf(stderr, "\nCAP_NOW: %d\n", pkg_data.cap_now);
295 
296  /****** fetch CapFull ******/
297  pkg_data.cap_full = fetchParam(buff, BMS_PKG_CAP_FULL_INDX + temp_indx_offset + cells_indx_offset,
298  BMS_PKG_CAP_FULL_SIZE) / 10;
299  //fprintf(stderr, "\nCAP_FULL: %d\n", pkg_data.cap_full);
300 
301  return pkg_data;
302  }
303 
304  int BMSInterface::fetchParam(char *buff, int param_indx, size_t param_size)
305  {
306  char param[param_size + 1];
307  param[param_size] = '\0';
308  strncpy(param, buff + param_indx, param_size);
309  return strtol(param, 0, BMS_PKG_BASE);
310  }
311 
313  {
314  close(file_handle_);
315  }
316 //:018252008A000000000000002EDE070D640D640D650D640D650D660D60***0000***008A***053F3F3F3F3E00000002000000000F00000000000000000000000000030A001500C8B4~
317 //:018252008A000000000000002FA0070D950D9F0D9E0D9E0D9F0DA00D91025B0000053F3F3F3F3E00000001000000000F00000000000000000000000000030A001500C86F~
318 }
#define BMS_PKG_START_DELIM_LEN
Definition: bms_interface.h:27
#define BMS_PKG_TEMP_NUM_SIZE
Definition: bms_interface.h:67
#define BMS_PKG_CMD_SIZE
Definition: bms_interface.h:39
#define BMS_PKG_WARN_VUV_INDX
Definition: bms_interface.h:91
#define BMS_PKG_ADDR_SIZE
Definition: bms_interface.h:36
bool param(const std::string &param_name, T &param_val, const T &default_val)
#define BMS_PKG_ALARM_INDX
Definition: bms_interface.h:82
#define BMS_PKG_DCHG_NUM_SIZE
#define BMS_PKG_BALANCE_STATE_INDX
#define BMS_PKG_NUM_WARN_VHIGH_INDX
Definition: bms_interface.h:94
#define BMS_PKG_VBAT_INDX
Definition: bms_interface.h:50
uint8_t is_chrg
#define BMS_PKG_CELL_SIZE
Definition: bms_interface.h:57
#define BMS_PKG_CHG_NUM_INDX
std::vector< uint8_t > temps
#define BMS_PKG_NUM_WARN_VLOW_INDX
Definition: bms_interface.h:97
uint16_t warn_vuv
int readPkgFromBMS(char *buff, size_t buff_size_limit)
uint8_t temp_max
#define BMS_PKG_VSTATE_INDX
Definition: bms_interface.h:73
uint16_t chg_num
#define BMS_PKG_LEN_INDX
Definition: bms_interface.h:44
#define BMS_PKG_FET_STATE_INDX
Definition: bms_interface.h:85
#define BMS_PKG_CHRG_CURR_INDX
Definition: bms_interface.h:59
int fetchParam(char buff[], int param_indx, size_t param_size)
#define BMS_PKG_TIME_SIZE
Definition: bms_interface.h:48
uint8_t getBitInWord(uint16_t byte, uint8_t position)
uint16_t tstate
#define BMS_PKG_NUM_WARN_VLOW_SIZE
Definition: bms_interface.h:98
float chrg_current
#define BMS_PKG_CAP_FULL_SIZE
const std::string SEND_ME_DATA_
#define BMS_PKG_CMD_INDX
Definition: bms_interface.h:38
#define BMS_PKG_DCHG_NUM_INDX
uint16_t num_warn_vhigh
#define BMS_PKG_CAP_NOW_SIZE
#define BMS_PKG_WARN_VOV_INDX
Definition: bms_interface.h:88
uint16_t len
#define BMS_PKG_VER_INDX
Definition: bms_interface.h:41
#define BMS_PKG_START_DELIM
Definition: bms_interface.h:26
std::vector< float > vcells
#define BMS_PKG_END_DELIM
Definition: bms_interface.h:28
uint16_t balance_state
uint8_t temp_num
#define BMS_PKG_CHG_NUM_SIZE
uint16_t alarm
uint8_t cell_num
#define BMS_PKG_CSTATE_SIZE
Definition: bms_interface.h:77
#define BMS_PKG_CHRG_CURR_SIZE
Definition: bms_interface.h:60
#define BMS_PKG_LEN_SIZE
Definition: bms_interface.h:45
#define BMS_PKG_TEMP_NUM_INDX
Definition: bms_interface.h:66
uint16_t vstate
#define BMS_PKG_CRC_SIZE
Definition: bms_interface.h:30
#define BMS_PKG_NUM_WARN_VHIGH_SIZE
Definition: bms_interface.h:95
#define BMS_PKG_ALARM_SIZE
Definition: bms_interface.h:83
#define BMS_PKG_ADDR_INDX
Definition: bms_interface.h:35
#define BMS_PKG_DCHRG_CURR_SIZE
Definition: bms_interface.h:63
#define BMS_PKG_SOC_INDX
uint8_t soc
uint16_t cap_full
uint16_t dchg_num
uint16_t num_warn_vlow
void connect(std::string port)
#define MAX_BAD_READS
Definition: bms_interface.h:23
uint8_t is_dchrg
#define BAUD_RATE
Definition: bms_interface.h:24
uint8_t cmd
#define BMS_PKG_TIME_INDX
Definition: bms_interface.h:47
#define BMS_PKG_TSTATE_SIZE
Definition: bms_interface.h:80
#define BMS_PKG_TEMP_SIZE
Definition: bms_interface.h:70
#define BMS_PKG_PROTOCOL_VERSION
Definition: bms_interface.h:33
#define BMS_PKG_VER_SIZE
Definition: bms_interface.h:42
#define BMS_PKG_CAP_NOW_INDX
#define BMS_PKG_VSTATE_SIZE
Definition: bms_interface.h:74
#define BMS_PKG_WARN_VOV_SIZE
Definition: bms_interface.h:89
#define BMS_PKG_CMD_SUCCESS
Definition: bms_interface.h:32
#define BMS_PKG_BALANCE_STATE_SIZE
#define BMS_PKG_SOC_SIZE
#define BMS_PKG_WARN_VUV_SIZE
Definition: bms_interface.h:92
#define BMS_PKG_CELLS_ARR_INDX
Definition: bms_interface.h:56
uint8_t ver
uint16_t cap_now
#define BUFF_SIZE
Definition: bms_interface.h:22
#define BMS_PKG_VBAT_SIZE
Definition: bms_interface.h:51
uint8_t fet_state
#define BMS_PKG_TEMPS_ARRAY_INDX
Definition: bms_interface.h:69
float dchrg_current
#define BMS_PKG_CAP_FULL_INDX
#define BMS_PKG_CELL_NUM_SIZE
Definition: bms_interface.h:54
#define BMS_PKG_CELL_NUM_INDX
Definition: bms_interface.h:53
uint16_t cstate
uint16_t warn_vov
#define BMS_PKG_BASE
Definition: bms_interface.h:31
#define BMS_PKG_CSTATE_INDX
Definition: bms_interface.h:76
#define BMS_PKG_DCHRG_CURR_INDX
Definition: bms_interface.h:62
uint8_t addr
#define BMS_PKG_CRC_BACK_OFFSET
Definition: bms_interface.h:29
#define BMS_PKG_FET_STATE_SIZE
Definition: bms_interface.h:86
#define BMS_PKG_TSTATE_INDX
Definition: bms_interface.h:79
data decodePkg(char buff[], size_t buff_size)


bms_interface
Author(s): Jane Doe
autogenerated on Wed Jan 3 2018 03:47:54