Some more info about the Flatpack communication protocol. This works for both a Flatpack 2 HE and a Flatpack S
0x05014400
During walk-in (the period where the voltage builds up slowly) the rectifier periodically (every 10 seconds or so) sends out the following message when it's not logged in :
05014400 is the identifier and the serial number is the message followed by 00 00
Walk in can be chosen to be either 5 seconds long or 60 seconds long. For charging my Zero I have opted for the 60 second walkin. It helps current spike when plugging in.
So in case of of my rectifier (ser nr 141471110820) it is
0x05014400 0x14 0x14 0x71 0x11 0x08 0x20 0x00 0x00 (all HEX numbers)
If you respond ONCE with 0x05004804 0x14 0x14 0x71 0x11 0x08 0x20 0x00 0x00 (serial number + 2 bytes 00) the rectifier sends out exactly 64 messages with the status every 0,2 seconds (or so) before reverting to sending 0x05014400 again every 10 seconds without status messages. If you send the same 0x05004804 again before those 64 messages are up, the rectifier sends out another 64 messages. So in summary, if you send the response command at least every 10 seconds the rectifier stays logged in and keeps sending status messages.
the status messages are (like described earlier in the thread) :
0x05014010 AA BB CC DD EE FF GG HH where
AA is the intake temperature in Celcius
BB is the output current Low Byte
CC is the output current High Byte. the current high and low byte combined give the current in deci amps (* 0.1 Amp)
DD is the output voltage Low byte
EE is the output voltage High Byte. the voltage high and low byte combined give the voltage in centivolts (* 0.01 Volt)
FF is the input voltage Low Byte
GG is the input voltage High Byte. the input voltage high and low byte combined gives the AC input voltage in volts
HH is the output temperature in Celcius
after the walk in period is reached the status messages change to :
0x05014004 AA BB CC DD EE FF GG HH when the rectifier is in normal (Constant voltage) mode
0x05014008 AA BB CC DD EE FF GG HH when the rectifier is in Constant Current mode (current-limiting)
0x0501400C AA BB CC DD EE FF GG HH when the input voltage is low (mains plug pulled)
however, during this stage every 10th message is different. The rectifier sends out a message :
0x0500NNPP 1B JJ KK LL MM NN PP 00
NN and PP are the last 2 bytes of the serial number. This has stumped me during diagnostics. I had my code perfect for 1 rectifier and the other was different. Unit i had the messages from 3 rectifiers and i saw the common link

The 1B as the first byte of the message is sometimes a 1C (don't know why).
I believe this is a request from the rectifier to keep being "logged in"
So in short
when the identifier starts with 0x0500 you have to reply with serial number which is containd in the message (do keep in mind that with a 0x05004400 the serial number is the first 6 bytes of the message and with 0x0500NNPP the serial number is the second till the seventh byte (shifted 1 byte)
when the identifier starts with 0x0501 it's a status message (and even the identifier shows different statuses)
All the above is just to keep being logged in and receive status messages.
There are (as explained earlier in the thread also ways to control the rectifier)
If it has send a message 0x05004400 or 0x0500NNPP (NNPP last 2 bytes of serial number) you can respond with a message to alter the voltage and even the maximum current setting.
First you have to send a response 0x05004804 with the serial number as message (just to keep it logged in)
Second you send the message
0x05FF4004 AA BB CC DD EE FF GG HH where
AA is the max current Low Byte
BB is the max current High Byte
CC is the voltage measured Low Byte (set it the same as the desired voltage Low byte)
DD is the voltage measured High Byte (set it the same as the desired voltage High byte)
EE is the desired voltage Low byte
FF is the desired voltage High byte
GG is the over voltage protection Low byte
HH is the over voltage protection High byte
example
If i send 0x05FF4004 0x64 0x00 0x44 0x16 0x44 0x16 0x3E 0x17
it sets the max current to 10.0 amps (0064 in HEX is 100 is 10.0 Amps)
it sets the voltage output to 57.0 Volts (1644 in Hex is 5700 is 57.00 Volts)
it sets the over voltage protection limit to 59.5 Volt (173E in Hex is 5950 is 59.50 Volts)
I Think the rectifier remembers this setting as long as it's logged in, so in theory you would only have to send this command once (but keep sending the log in command periodically (0x05004804 with the serial number)
The 0x05FF4004 is for a 5 second walk in period (after 5 seconds the output voltage reaches it's goal
if you substitute this with 0x05FF4005 (last 4 change to a 5) the walk in period will be 60 seconds. This is stored in non volatile memory and is active from that moment on every time you switch on the rectifier.
I send the command for the max current and output voltage every time I see a log in request (identifier starts with 0x0500) As said this probably is not necessary but I do switch the canbus to another rectifier sometimes so I have to send it more often.
Also keep in mind that if the rectifier loses contact with the controller (i.e. you don't send any answers) the rectifier will revert to it's original settings (default voltage and maximum current)
For those interested I have changed the code on my arduino as follows. It has automatic serial number detection and status message decoding. I've optimised it as far as possible with my average programming skills but is does the job I want it to do. It has an LCD for showing the message (2x16 characters), it shows any unknown identifier and message (which i have not seen yet), and has a pushbutton to control the maximum current. It sets it initially to 10.0 amps and with every push of the button it adds another 10 Amps. After it has reached 40 Amps and you push the button again it reverts back to 10.0 Amps. The display shows the chosen current output.
Happy Tinkering All
Code:
// from rectifier : (requests for logins)
// 05014400 + ser nr + 00 00 from rectifier : HELLOOW where are you ! rectifier sends 05014400 and 6 bytes serial number and followed by 00 00 (login request)
// 0500xxyy + 1B + ser nr + 00 is send during normal voltage every second. xxyy is the last 2 bytes from the serial number
// after either of these send 05004804 every 5 seconds ! to keep logged in. rectifier does not send login requests so after 10 second the numbers stop until 05014400 is sent
// from rectifier : (status messages)
// 0501400C + status data : walkin and below 43 volts (error) and during walk-out (input voltage low)
// 05014010 + status data : walkin busy
// 05014004 + status data : normal voltage reached
// 05014008 + status data : current-limiting active
// send TO rectifier (act as controller)
// 05004804 + ser nr + 00 00 from controller : send 05004804 and 6 bytes ser number followed by 00 00
// 05FF4004 controller sends current and voltage limits (last 4 is 5 sec walk-in, for 60 second walk-in use 05FF4005)
// 05FF4005 controller sends current and voltage limits (last 5 is 60 sec walk-in, for 5 second walk-in use 05FF4004)
#include <mcp_can.h>
#include <mcp_can_dfs.h>
#include <SPI.h>
#include <LiquidCrystal.h>
const int SPI_CS_PIN = 10;
word maxcurrent = 0x64; // set initial maxcurrent to 10A output
unsigned char len = 0;
unsigned char serialnr[8];
int msgreceived;
MCP_CAN CAN(SPI_CS_PIN); // Set CS pin for CANBUS shield
LiquidCrystal lcd(1, 3, 4, 5, 6, 7, 8); // LiquidCrystal(rs, rw, enable, d4, d5, d6, d7) or LiquidCrystal(rs, enable, d4, d5, d6, d7)
void setup() // Initialisation routine
{
pinMode(A0, INPUT); // Set pin A0 to input (pushbutton)
digitalWrite(A0, HIGH); // activate pull-up on A0
pinMode(9, OUTPUT); // Set pin 9 to output (backlight of the LCD)
digitalWrite(9, HIGH); // Backlight enable
lcd.begin(16, 2); // splash screen on LCD
lcd.print("Flatpack Charger");
lcd.setCursor(0, 1);
lcd.print("Made by RHO");
START_INIT:
if(CAN_OK == CAN.begin(CAN_125KBPS)) // init can bus : baudrate = 125k !!
{
lcd.setCursor(0,0);
lcd.print("CAN BUS init OK!");
delay(100);
}
else
{
lcd.setCursor(0,0);
lcd.print("CAN BUS init Fail");
lcd.setCursor(0,1);
lcd.print("Init CAN BUS again");
delay(100);
goto START_INIT;
}
lcd.clear();
}
void loop() // main program (LOOP)
{
unsigned char buf[8] ;
if(CAN_MSGAVAIL == CAN.checkReceive()) // check if data coming
{
CAN.readMsgBuf(&len, buf); // read data, len: data length, buf: data buf
INT32U canId = CAN.getCanId(); // read the CAN Id
if(canId==0x05014400) //this is the request from the Flatpack rectifier during walk-in (start-up) or normal operation when no log-in response has been received for a while
{
for(int i = 0; i<8; i++)
{
serialnr[i]=buf[i]; // transfer the message buffer to the serial number variable
}
CAN.sendMsgBuf(0x05004804, 1, 8, serialnr); //send message to log in (DO NOT ASSIGN AN ID use 00)
msgreceived++; // increase the variable "msgreceived"
unsigned char stmp7[8] = {lowByte(maxcurrent), highByte(maxcurrent), 0x44, 0x16, 0x44, 0x16, 0x3E, 0x17}; // set rectifier to maxcurrent 57,0V (16 44) and OVP to 59.5V (17 3E) qnd long walk-in 4005 or short walk in 4004
CAN.sendMsgBuf(0x05FF4005, 1, 8, stmp7); //(last 4 in header is for 5 sec walkin, 5 is for 60 second walkin)
}
else if(canId==(0x05000000+256*buf[5]+buf[6])) //if CANID = 0500xxyy where xxyy the last 2 digits of the serial nr
{
for(int i = 0; i<6; i++)
{
serialnr[i]=buf[i+1]; // transfer the buffer to the serial number variable (neccesary when switching the CAN-bus to another rectifier while on)
}
unsigned char serialnr[8] = {buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], 0x00, 0x00}; //this is the serial number of the unit which is covered in the request (unit announces its serial number)
CAN.sendMsgBuf(0x05004804, 1, 8, serialnr); //send message to log in (DO NOT ASSIGN AN ID) use 00
msgreceived++;
unsigned char stmp7[8] = {lowByte(maxcurrent), highByte(maxcurrent), 0x44, 0x16, 0x44, 0x16, 0x3E, 0x17}; // set rectifier to maxcurrent 57,0V (16 44) and OVP to 59.5V (17 3E) qnd long walk-in 4005 or short walk in 4004
CAN.sendMsgBuf(0x05FF4005, 1, 8, stmp7); //(last 4 in header is for 5 sec walkin, 5 is for 60 second walkin)
}
else if((canId==0x05014004)or(canId==0x05014008)or(canId==0x05014010)or(canId=0x0501400C)) // these are the status messages (05014004 is not current-limiting, 05014008 is current limiting 05014010 = busy with walkin, 0501400C in input voltage low)
{
msgreceived++; // record number of messages received
if(msgreceived>40)
{
msgreceived=0;
CAN.sendMsgBuf(0x05004804, 1, 8, serialnr); //send message to log in every 40 messages (DO NOT USE ID NR, USE 00) this because during walk-in the 0500xxyy is not send and the rectifier "logs out" because of no received log-in messages from controller
msgreceived++;
}
lcd.setCursor(0, 0); //show data on the LCD screen 0x050140yy 0xAA 0xBB 0xCC 0xDD 0xEE 0xFF 0xGG 0xHH
lcd.print("T=");
lcd.print(buf[0]); // 0xAA = Temperature in
lcd.print("/");
lcd.print(buf[7]); // 0xHH = Temperature out
lcd.print(" ");
lcd.setCursor(8,0);
lcd.print("I=");
lcd.print(buf[2]*256*0.1+buf[1]*0.1); // 0xBB = Current Low Byte, 0xCC = Current High byte. Current in deciAmps (*0.1 Amps)
lcd.print(" ");
lcd.setCursor(8,1);
lcd.print("Vo=");
lcd.print(buf[4]*256*0.01+buf[3]*0.01); // 0xDD = Voltage out Low Byte, oxEE = Voltage out High Byte. Voltgae in centivolts (*0.01 Volt)
lcd.print(" ");
lcd.setCursor(0,1);
lcd.print("Vi=");
lcd.print(256*buf[6]+buf[5]); // 0xFF = Voltage in Low byte, 0xGG = Voltage in High byte. Voltage in Volts (because voltage is below 255 Volts, high byte is always 0)
lcd.print(" ");
if((digitalRead(A0)==0)) //read digital pin Analog0 and if it is high (pushbutton is pressed)
{
maxcurrent = maxcurrent + 100; // raise maxcurrent with 10 A
if(maxcurrent > 400) // to be able to lower the current with one button, if the maxcurrent > 40 the current is reset to 10
{
maxcurrent =100;
}
digitalWrite(9,HIGH); // switch on the backlight
CAN.sendMsgBuf(0x05004804, 1, 8, serialnr); // send message to log in (DO NOT ASSIGN AN ID) use 00
unsigned char stmp7[8] = {lowByte(maxcurrent), highByte(maxcurrent), 0x44, 0x16, 0x44, 0x16, 0x3E, 0x17}; // set rectifier to maxcurrent 57,0V (16 44) and OVP to 59.5V (17 3E) qnd long walk-in 4005 or short walk in 4004
CAN.sendMsgBuf(0x05FF4005, 1, 8, stmp7); // (last 4 in header is for 5 sec walkin, 5 is for 60 second walkin)
lcd.setCursor(0, 0); // announce chosen current on LCD
lcd.print("Current set to ");
lcd.setCursor(0, 1);
lcd.print(maxcurrent*0.1);
lcd.print(" Amp ");
delay(1000);
}
}
else
{
lcd.setCursor(0,0); // if the canId is unknown
lcd.print(canId,HEX); // show the can Id and the message on the LCD
lcd.setCursor(0,1);
for(int i = 0; i<len; i++)
{
if( buf[i] < 0x10){ lcd.print("0");} lcd.print(buf[i],HEX); // send a leading zero if only one digit
}
delay(1000); // show the message for 1 second and then continue
}
}
}
/*********************************************************************************************************
END FILE
*********************************************************************************************************/