Skip to content

Commit

Permalink
Merge pull request #242 from pprasse/master-pylonforce-can
Browse files Browse the repository at this point in the history
PYLONTECH ForceH* canbus support
  • Loading branch information
stuartpittaway authored Nov 13, 2023
2 parents 420c670 + 401f037 commit 0a13c45
Show file tree
Hide file tree
Showing 10 changed files with 755 additions and 27 deletions.
7 changes: 5 additions & 2 deletions ESPController/include/Rules.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,13 @@ class Rules
// Number of modules who have reported zero volts (bad!)
uint8_t zeroVoltageModuleCount;

// Highest pack voltage (millivolts)
// Highest pack voltage (millivolts) & address
uint32_t highestBankVoltage;
// Lowest pack voltage (millivolts)
uint8_t address_highestBankVoltage;

// Lowest pack voltage (millivolts) & address
uint32_t lowestBankVoltage;
uint8_t address_lowestBankVoltage;

// Highest cell voltage in the whole system (millivolts)
uint16_t highestCellVoltage;
Expand Down
5 changes: 4 additions & 1 deletion ESPController/include/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ enum CanBusProtocolEmulation : uint8_t
{
CANBUS_DISABLED = 0x00,
CANBUS_VICTRON = 0x01,
CANBUS_PYLONTECH = 0x02
CANBUS_PYLONTECH = 0x02,
CANBUS_PYLONFORCEH2 = 0x03
};

enum CurrentMonitorDevice : uint8_t
Expand Down Expand Up @@ -250,6 +251,8 @@ struct diybms_eeprom_settings

// Holds a bit pattern indicating which "tiles" are visible on the web gui
uint16_t tileconfig[5];

uint8_t canbus_equipment_addr; // battery index on the same canbus for PYLONFORCE, 0 - 15, default 0
};

typedef union
Expand Down
26 changes: 26 additions & 0 deletions ESPController/include/pylonforce_canbus.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ifndef DIYBMS_PYLONFORCE_CANBUS_H_
#define DIYBMS_PYLONFORCE_CANBUS_H_

#include "defines.h"
#include "Rules.h"
#include <driver/twai.h>


void pylonforce_handle_rx(twai_message_t *);
void pylonforce_handle_tx();


extern uint8_t TotalNumberOfCells();
extern Rules rules;
extern currentmonitoring_struct currentMonitor;
extern diybms_eeprom_settings mysettings;
extern std::string hostname;
extern ControllerState _controller_state;
extern uint32_t canbus_messages_failed_sent;
extern uint32_t canbus_messages_sent;
extern uint32_t canbus_messages_received;
extern bool wifi_isconnected;

extern void send_ext_canbus_message(const uint32_t identifier, const uint8_t *buffer, const uint8_t length);

#endif
19 changes: 12 additions & 7 deletions ESPController/src/HAL_ESP32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,13 +296,18 @@ void HAL_ESP32::ConfigureCAN(uint16_t canbusbaudrate) const
t_config = TWAI_TIMING_CONFIG_500KBITS();
}

// Filter out all messages except 0x305 and 0x307
// https://docs.espressif.com/projects/esp-idf/en/v3.3.5/api-reference/peripherals/can.html
// 01100000101 00000 00000000 00000000 = 0x60A00000 (0x305)
// 01100000111 00000 00000000 00000000 = 0x60E00000 (0x307)
// 00000000010 11111 11111111 11111111 = 0x005FFFFF
// ^ THIS BIT IS IGNORED USING THE MASK SO 0x305 and 0x307 are permitted
twai_filter_config_t f_config = {.acceptance_code = 0x60A00000, .acceptance_mask = 0x005FFFFF, .single_filter = true};

// We need the CAN ids:
// * Pylontech LV battery: 0x305, 0x307
// * Pylontech Force HV battery: 0x4200, 0x8200, 0x8210
// from these ids we _can not_ derive a filter that makes sense, i.e.
// twai_filter_config_t f_config = {
// .acceptance_code = 0x305<<21 & 0x307<<21 & 0x4200<<3 & 0x8200<<3 & 0x8210<<3, // 0
// .acceptance_mask = 0x305<<21 | 0x307<<21 | 0x4200<<3 | 0x8200<<3 | 0x8210<<3, // 0x60E61080
// .single_filter = true
// };
// ----> acceptance_code == 0, so we can only set ALL
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();

// Install CAN driver
if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK)
Expand Down
4 changes: 4 additions & 0 deletions ESPController/src/Rules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ void Rules::ClearValues()
HighestCellVoltageInBank.fill(0);

highestBankVoltage = 0;
address_highestBankVoltage = maximum_number_of_banks+1;
lowestBankVoltage = 0xFFFFFFFF;
address_lowestBankVoltage = maximum_number_of_banks+1;
highestCellVoltage = 0;
lowestCellVoltage = 0xFFFF;
highestExternalTemp = -127;
Expand Down Expand Up @@ -160,10 +162,12 @@ void Rules::ProcessBank(uint8_t bank)
if (bankvoltage.at(bank) > highestBankVoltage)
{
highestBankVoltage = bankvoltage.at(bank);
address_highestBankVoltage = bank;
}
if (bankvoltage.at(bank) < lowestBankVoltage)
{
lowestBankVoltage = bankvoltage.at(bank);
address_lowestBankVoltage = bank;
}

if (VoltageRangeInBank(bank) > highestBankRange)
Expand Down
52 changes: 35 additions & 17 deletions ESPController/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ extern "C"
#include "mqtt.h"
#include "victron_canbus.h"
#include "pylon_canbus.h"
#include "pylonforce_canbus.h"
#include "string_utils.h"

#include <SPI.h>
Expand Down Expand Up @@ -2638,11 +2639,11 @@ static const char *ESP32_TWAI_STATUS_STRINGS[] = {
"RECOVERY UNDERWAY" // CAN_STATE_RECOVERING
};

void send_canbus_message(uint32_t identifier, const uint8_t *buffer, const uint8_t length)
void _send_canbus_message(const uint32_t identifier, const uint8_t *buffer, const uint8_t length, const uint32_t flags)
{
twai_message_t message;
message.identifier = identifier;
message.flags = TWAI_MSG_FLAG_NONE;
message.flags = flags;
message.data_length_code = length;

memcpy(&message.data, buffer, length);
Expand Down Expand Up @@ -2694,6 +2695,15 @@ void send_canbus_message(uint32_t identifier, const uint8_t *buffer, const uint8
}
}

void send_canbus_message(const uint32_t identifier, const uint8_t *buffer, const uint8_t length)
{
_send_canbus_message(identifier, buffer, length, TWAI_MSG_FLAG_NONE);
}
void send_ext_canbus_message(const uint32_t identifier, const uint8_t *buffer, const uint8_t length)
{
_send_canbus_message(identifier, buffer, length, TWAI_MSG_FLAG_EXTD);
}

[[noreturn]] void canbus_tx(void *)
{
for (;;)
Expand Down Expand Up @@ -2740,8 +2750,11 @@ void send_canbus_message(uint32_t identifier, const uint8_t *buffer, const uint8
// Delay a little whilst sending packets to give ESP32 some breathing room and not flood the CANBUS
// vTaskDelay(pdMS_TO_TICKS(100));
}

if (mysettings.canbusprotocol == CanBusProtocolEmulation::CANBUS_VICTRON)
else if (mysettings.canbusprotocol == CanBusProtocolEmulation::CANBUS_PYLONFORCEH2 )
{
pylonforce_handle_tx();
}
else if (mysettings.canbusprotocol == CanBusProtocolEmulation::CANBUS_VICTRON)
{
// minimum CAN-IDs required for the core functionality are 0x351, 0x355, 0x356 and 0x35A.

Expand Down Expand Up @@ -2793,18 +2806,23 @@ void send_canbus_message(uint32_t identifier, const uint8_t *buffer, const uint8
canbus_messages_received++;
ESP_LOGD(TAG, "CANBUS received message ID: %0x, DLC: %d, flags: %0x",
message.identifier, message.data_length_code, message.flags);
/*
if (!(message.flags & TWAI_MSG_FLAG_RTR))
if (!(message.flags & TWAI_MSG_FLAG_RTR)) // we do not answer to Remote-Transmission-Requests
{
ESP_LOG_BUFFER_HEXDUMP(TAG, message.data, message.data_length_code, ESP_LOG_DEBUG);
}*/

// Remote inverter should send a 305 message every few seconds
// for now, keep track of last message.
// TODO: in future, add timeout/error condition to shut down
if (message.identifier == 0x305)
{
canbus_last_305_message_time = esp_timer_get_time();
// ESP_LOG_BUFFER_HEXDUMP(TAG, message.data, message.data_length_code, ESP_LOG_DEBUG);
if (mysettings.canbusprotocol == CanBusProtocolEmulation::CANBUS_PYLONFORCEH2 )
{
pylonforce_handle_rx(&message);
}
else
{
// Remote inverter should send a 305 message every few seconds
// for now, keep track of last message.
// TODO: in future, add timeout/error condition to shut down
if (message.identifier == 0x305)
{
canbus_last_305_message_time = esp_timer_get_time();
}
}
}
}
else
Expand Down Expand Up @@ -3885,10 +3903,10 @@ ESP32 Chip model = %u, Rev %u, Cores=%u, Features=%u)",
xTaskCreate(rs485_tx, "485_TX", 2940, nullptr, 1, &rs485_tx_task_handle);
xTaskCreate(rs485_rx, "485_RX", 2940, nullptr, 1, &rs485_rx_task_handle);
xTaskCreate(service_rs485_transmit_q, "485_Q", 2950, nullptr, 1, &service_rs485_transmit_q_task_handle);
xTaskCreate(canbus_tx, "CAN_Tx", 2950, nullptr, 1, &canbus_tx_task_handle);
xTaskCreate(canbus_tx, "CAN_Tx", 4096, nullptr, 1, &canbus_tx_task_handle);
xTaskCreate(canbus_rx, "CAN_Rx", 2950, nullptr, 1, &canbus_rx_task_handle);
xTaskCreate(transmit_task, "Tx", 1950, nullptr, configMAX_PRIORITIES - 3, &transmit_task_handle);
xTaskCreate(replyqueue_task, "rxq", 2350, nullptr, configMAX_PRIORITIES - 2, &replyqueue_task_handle);
xTaskCreate(replyqueue_task, "rxq", 4096, nullptr, configMAX_PRIORITIES - 2, &replyqueue_task_handle);
xTaskCreate(lazy_tasks, "lazyt", 2500, nullptr, 0, &lazy_task_handle);

// Set relay defaults
Expand Down
Loading

0 comments on commit 0a13c45

Please sign in to comment.