diff --git a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_Abstraction.c b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_Abstraction.c index 36efa2a..2c851bc 100755 --- a/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_Abstraction.c +++ b/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/ADBMS_Abstraction.c @@ -346,7 +346,8 @@ HAL_StatusTypeDef amsSendI2C(uint8_t addresses[static N_BMS], uint8_t * data[sta for (size_t i = 0; i < (packet_count * 3); i++) { //i - 1 is the number of data bytes sent so far (1 byte for the address) for (size_t j = 0; j < N_BMS; j++) { size_t offset = BUFFER_BMS_OFFSET(j, COMM_GROUP_SIZE); - if (!(bms_mask & (1 << j))) continue; //skip BMS that are not selected + if (!(bms_mask & (1 << j))) + continue; //skip BMS that are not selected if (i == 0) { buffer[offset + 0] = I2C_SEND_START; @@ -388,3 +389,109 @@ HAL_StatusTypeDef amsSendI2C(uint8_t addresses[static N_BMS], uint8_t * data[sta return HAL_OK; } + +HAL_StatusTypeDef amsReadI2C(uint8_t addresses[static N_BMS], uint8_t * data[static N_BMS], uint8_t datalens[static N_BMS], uint32_t bms_mask) { + uint8_t buffer[CMD_BUFFER_SIZE(COMM_GROUP_SIZE)] = {}; + + uint8_t max_datalen = 0; + for (size_t i = 0; i < N_BMS; i++) { + if (datalens[i] > max_datalen) { + max_datalen = datalens[i]; + } + } + + for (size_t i = 0; i < N_BMS; i++) { + size_t offset = BUFFER_BMS_OFFSET(i, COMM_GROUP_SIZE); + + if (!(bms_mask & (1 << i))) { + buffer[offset + 0] = I2C_SEND_NOTRANSFER; + buffer[offset + 2] = I2C_SEND_NOTRANSFER; + buffer[offset + 4] = I2C_SEND_NOTRANSFER; + continue; + } + } + + size_t packet_count = ((max_datalen + 1) / 3) + ((max_datalen + 1) % 3 != 0); + + for (size_t i = 0; i < (packet_count * 3); + i++) { // i - 1 is the number of data bytes sent so far (1 byte for the address) + for (size_t j = 0; j < N_BMS; j++) { + size_t offset = BUFFER_BMS_OFFSET(j, COMM_GROUP_SIZE); + if (!(bms_mask & (1 << j))) + continue; // skip BMS that are not selected + + if (i == 0) { + buffer[offset + 0] = I2C_SEND_START; + buffer[offset + 1] = addresses[j]; + continue; + } + + // add data to the buffer + + // case 1: the last group of 3 bytes contained the last data byte, so we need to send a stop + if (datalens[j] - (int)i == -1) { + buffer[offset + ((i % 3) * 2)] = I2C_SEND_STOP; + continue; + } + + // case 2: we are more than one byte past the end, so we don't need to receive any data + if (datalens[j] - (int)i < -1) { + buffer[offset + ((i % 3) * 2)] = I2C_SEND_NOTRANSFER; + continue; + } + + // case 3: we are still receiving data + buffer[offset + ((i % 3) * 2)] = I2C_RECV_ACK; + } + + // send the command data + if (i % 3 == 0 && i != 0) { + CHECK_RETURN(writeCMD(WRCOMM, buffer, COMM_GROUP_SIZE)); + + __pollCMD(STCOMM, 72); // wait 72 cycles for the I2C transfer to complete (datasheet page 43) + // TODO: not sure if this is correct for a daisy chain + + // read the data + CHECK_RETURN(readCMD(RDCOMM, buffer, COMM_GROUP_SIZE)); + + for (size_t j = 0; j < N_BMS; j++) { + size_t offset = BUFFER_BMS_OFFSET(j, COMM_GROUP_SIZE); + + if (!(bms_mask & (1 << j))) + continue; // skip BMS that are not selected + + for (size_t k = 0; k < 3; k++) { + if (datalens[j] - (int)i < -1) { + continue; + } + + data[j][i - 1 + k] = buffer[offset + (k * 2) + 1]; + } + } + } + } + + // send the last packet + CHECK_RETURN(writeCMD(WRCOMM, buffer, COMM_GROUP_SIZE)); + __pollCMD(STCOMM, 72); + + // read the data + CHECK_RETURN(readCMD(RDCOMM, buffer, COMM_GROUP_SIZE)); + + for (size_t j = 0; j < N_BMS; j++) { + size_t offset = BUFFER_BMS_OFFSET(j, COMM_GROUP_SIZE); + + if (!(bms_mask & (1 << j))) + continue; // skip BMS that are not selected + + for (size_t k = 0; k < 3; k++) { + if (datalens[j] - (int)max_datalen < -1) { + continue; + } + + data[j][max_datalen - 1 + k] = buffer[offset + (k * 2) + 1]; + } + } + + return HAL_OK; +} \ No newline at end of file