I made some changes according to V2.0 of "Frame Protocol of FrSky Telemetry Hub System" http://www.frsky-rc.com/uploadfile/2012 ... 254960.pdf
- e.g. it doesn't make sense to send GPS_speed and Course every 500ms because frsky receiver will send it every 1 sec.
and also taking into account er9x-frsky firmware:
- it doesn't need to send E/W and N/S for GPS position, as it's not displayed with er9x-frsky. Instead of that it's possible not remove the sign for values before point and sign will be displayed before '=' ...
- Temperature1 was used for "Distance_to_home" because it's displayed by default with er9x-frsky (custom screen is not stored to eeprom unfortunaly... i have er9x-r767 version)
- Start_altitude don't need with er9x-frsky because it's possible do the same by pressing 'Menu' button and it takes an offset to know zero point
other:
- also removed unnecessary data send, e.g. zero values after point
- as for me more usefull to have rcCommand[THROTTLE] as RPM, e.g. to know the real hover point to set MID throttle expo...
Code: Select all
// **********************
// FrSky telemetry
// **********************
#if defined(TELEMETRY_FRSKY)
// Serial config datas
#define TELEMETRY_FRSKY_SERIAL 3
#define TELEMETRY_FRSKY_BAUD 9600
// Interrupt
#define ISR_FRSKY ISR(USART3_UDRE_vect)
// Ringbuffer
#define FRSKY_BUFFER_SIZE 150
static uint8_t bufFrSky[FRSKY_BUFFER_SIZE];
static volatile uint8_t headTXFrSky;
static volatile uint8_t tailTXFrSky;
// Timing
#define Time_telemetry_send 125000
static uint8_t cycleCounter = 0;
static uint32_t FrSkyTime = 0;
// Frame protocol
#define Protocol_Header 0x5E
#define Protocol_Tail 0x5E
// Data Ids (bp = before point; af = after point)
// Official data IDs
#define ID_GPS_altidute_bp 0x01
#define ID_GPS_altidute_ap 0x09
#define ID_Temprature1 0x02
#define ID_RPM 0x03
#define ID_Fuel_level 0x04
#define ID_Temprature2 0x05
#define ID_Volt 0x06
#define ID_Altitude_bp 0x10
#define ID_Altitude_ap 0x21
#define ID_GPS_speed_bp 0x11
#define ID_GPS_speed_ap 0x19
#define ID_Longitude_bp 0x12
#define ID_Longitude_ap 0x1A
#define ID_E_W 0x22
#define ID_Latitude_bp 0x13
#define ID_Latitude_ap 0x1B
#define ID_N_S 0x23
#define ID_Course_bp 0x14
#define ID_Course_ap 0x24
#define ID_Date_Month 0x15
#define ID_Year 0x16
#define ID_Hour_Minute 0x17
#define ID_Second 0x18
#define ID_Acc_X 0x24
#define ID_Acc_Y 0x25
#define ID_Acc_Z 0x26
#define ID_Voltage_Amp_bp 0x3A
#define ID_Voltage_Amp_ap 0x3B
#define ID_Current 0x28
// User defined data IDs
#define ID_Gyro_X 0x40
#define ID_Gyro_Y 0x41
#define ID_Gyro_Z 0x42
void configure_FrSky()
{
SerialOpen(TELEMETRY_FRSKY_SERIAL,TELEMETRY_FRSKY_BAUD);
}
// Interrupt
ISR_FRSKY
{
uint8_t Tail = tailTXFrSky;
if (headTXFrSky != Tail)
{
if (++Tail >= FRSKY_BUFFER_SIZE)
{
Tail = 0;
}
tailTXFrSky = Tail;
UDR3 = bufFrSky[Tail]; // Transmit next byte in the ring
}
if (Tail == headTXFrSky) UCSR3B &= ~(1<<UDRIE3); // Check if all data is transmitted . if yes disable transmitter UDRE interrupt
}
// Main function FrSky telemetry
void telemetry_frsky()
{
if (currentTime > FrSkyTime ) //
{
FrSkyTime = currentTime + Time_telemetry_send;
cycleCounter++;
// Datas sent every 125 ms
//send_Accel();
//sendDataTail();
if ((cycleCounter % 4) == 0)
{
// Datas sent every 500ms
send_Altitude();
send_RPM();
//send_Cell_volt();
sendDataTail();
}
if ((cycleCounter % 8) == 0)
{
// Datas sent every 1s
//send_Time();
//send_Course();
send_GPS_speed();
send_GPS_position();
send_GPS_altitude();
send_Temperature1(); // Distance_to_home
//send_Fuel_level();
// send_Voltage_ampere();
sendDataTail();
}
if (cycleCounter == 40)
{
// Datas sent every 5s
send_Temperature2(); // num of Sats
sendDataTail();
cycleCounter = 0;
}
}
}
void write_FrSky8(uint8_t Data)
{
uint8_t Head = headTXFrSky;
if (++Head >= FRSKY_BUFFER_SIZE) Head = 0;
bufFrSky[Head] = Data;
headTXFrSky = Head;
UCSR3B |= (1<<UDRIE3); // Enable Interrupt
}
void write_FrSky16(uint16_t Data)
{
uint8_t Data_send;
Data_send = Data;
write_FrSky8(Data_send);
Data_send = Data >> 8 & 0xff;
write_FrSky8(Data_send);
}
static void sendDataHead(uint8_t Data_id)
{
write_FrSky8(Protocol_Header);
write_FrSky8(Data_id);
}
static void sendDataTail(void)
{
write_FrSky8(Protocol_Tail);
}
//*********************************************************************************
//----------------- Telemetrie Datas ------------------------------------------
//*********************************************************************************
// GPS altitude
void send_GPS_altitude(void)
{
if (f.GPS_FIX && GPS_numSat >= 4)
{
int16_t Datas_GPS_altidute_bp;
//uint16_t Datas_GPS_altidute_ap;
Datas_GPS_altidute_bp = GPS_altitude;
//Datas_GPS_altidute_ap = 0;
sendDataHead(ID_GPS_altidute_bp);
write_FrSky16(Datas_GPS_altidute_bp);
//sendDataHead(ID_GPS_altidute_ap);
//write_FrSky16(Datas_GPS_altidute_ap);
}
}
// Temperature
void send_Temperature2(void)
{
int16_t Datas_Temprature2;
Datas_Temprature2 = GPS_numSat; // Number of Satalits alias Temp2
sendDataHead(ID_Temprature2);
write_FrSky16(Datas_Temprature2);
}
// RPM
void send_RPM(void)
{
uint16_t Datas_RPM = 0;
/*for (uint8_t i=0;i<NUMBER_MOTOR;i++)
{
Datas_RPM += motor[i];
}
Datas_RPM = (Datas_RPM / NUMBER_MOTOR) / 30; // RPM
*/
Datas_RPM = rcCommand[THROTTLE] / 3;
sendDataHead(ID_RPM);
write_FrSky16(Datas_RPM);
}
// Fuel level
void send_Fuel_level(void)
{
uint16_t Datas_Fuel_level;
Datas_Fuel_level = 0;
sendDataHead(ID_Fuel_level);
write_FrSky16(Datas_Fuel_level);
}
// Temperature 1
void send_Temperature1(void)
{
if (f.GPS_FIX_HOME)
{
int16_t Datas_Temprature1;
Datas_Temprature1 = GPS_distanceToHome; // Distance to home alias Temp1
sendDataHead(ID_Temprature1);
write_FrSky16(Datas_Temprature1);
}
}
// Cell voltage
void send_Cell_volt(void)
{
uint16_t Datas_Volt;
Datas_Volt = 0; // 0.01v / 0 ~ 4.2v
sendDataHead(ID_Volt);
write_FrSky16(Datas_Volt);
}
// Altitude
void send_Altitude(void)
{
uint16_t Datas_altitude_bp;
//uint16_t Datas_altitude_ap;
/*static uint16_t Start_altitude;
if (!f.ARMED)
{
Start_altitude = EstAlt / 100;
}
Datas_altitude_bp = (EstAlt / 100) - Start_altitude;
Datas_altitude_ap = (EstAlt % 100);*/
Datas_altitude_bp = (EstAlt / 100);
sendDataHead(ID_Altitude_bp);
write_FrSky16(Datas_altitude_bp);
//sendDataHead(ID_Altitude_ap);
//write_FrSky16(Datas_altitude_ap);
}
// GPS speed
void send_GPS_speed(void)
{
if (f.GPS_FIX && GPS_numSat >= 4)
{
uint16_t Datas_GPS_speed_bp;
//uint16_t Datas_GPS_speed_ap;
Datas_GPS_speed_bp = GPS_speed * 0.036;
//Datas_GPS_speed_ap = 0;
sendDataHead(ID_GPS_speed_bp);
write_FrSky16(Datas_GPS_speed_bp);
//sendDataHead(ID_GPS_speed_ap);
//write_FrSky16(Datas_GPS_speed_ap);
}
}
// GPS position
void send_GPS_position(void)
{
if (f.GPS_FIX && GPS_numSat >= 4)
{
uint16_t Datas_Longitude_bp;
uint16_t Datas_Longitude_ap;
//uint16_t Datas_E_W;
uint16_t Datas_Latitude_bp;
uint16_t Datas_Latitude_ap;
//uint16_t Datas_N_S;
Datas_Longitude_bp = (GPS_coord[LON]) / 100000;
Datas_Longitude_ap = abs((GPS_coord[LON])/10) % 10000;
//Datas_E_W = GPS_coord[LON] < 0 ? 'W' : 'E';
Datas_Latitude_bp = (GPS_coord[LAT]) / 100000;
Datas_Latitude_ap = abs((GPS_coord[LAT])/10) % 10000;
//Datas_N_S = GPS_coord[LAT] < 0 ? 'S' : 'N';
sendDataHead(ID_Longitude_bp);
write_FrSky16(Datas_Longitude_bp);
sendDataHead(ID_Longitude_ap);
write_FrSky16(Datas_Longitude_ap);
//sendDataHead(ID_E_W);
//write_FrSky16(Datas_E_W);
sendDataHead(ID_Latitude_bp);
write_FrSky16(Datas_Latitude_bp);
sendDataHead(ID_Latitude_ap);
write_FrSky16(Datas_Latitude_ap);
//sendDataHead(ID_N_S);
//write_FrSky16(Datas_N_S);
}
}
// Course
void send_Course(void)
{
uint16_t Datas_Course_bp;
uint16_t Datas_Course_ap;
Datas_Course_bp = heading;
Datas_Course_ap = 0;
sendDataHead(ID_Course_bp);
write_FrSky16(Datas_Course_bp);
sendDataHead(ID_Course_ap);
write_FrSky16(Datas_Course_ap);
}
// Time
void send_Time(void)
{
uint32_t seconds_since_start = millis() / 1000;
uint16_t Datas_Date_month;
uint16_t Datas_Year;
uint16_t Datas_Minutes_hours;
uint16_t Datas_seconds;
Datas_Date_month = 0;
Datas_Year = 12;
Datas_Minutes_hours = (seconds_since_start / 60) % 60;
Datas_seconds = seconds_since_start % 60;
sendDataHead(ID_Hour_Minute);
write_FrSky16(Datas_Minutes_hours);
sendDataHead(ID_Second);
write_FrSky16(Datas_seconds);
}
// ACC
void send_Accel(void)
{
int16_t Datas_Acc_X;
int16_t Datas_Acc_Y;
int16_t Datas_Acc_Z;
Datas_Acc_X = ((float)accSmooth[0] / acc_1G) * 1000;
Datas_Acc_Y = ((float)accSmooth[1] / acc_1G) * 1000;
Datas_Acc_Z = ((float)accSmooth[2] / acc_1G) * 1000;
sendDataHead(ID_Acc_X);
write_FrSky16(Datas_Acc_X);
sendDataHead(ID_Acc_Y);
write_FrSky16(Datas_Acc_Y);
sendDataHead(ID_Acc_Z);
write_FrSky16(Datas_Acc_Z);
}
// Voltage (Ampere Sensor)
void send_Voltage_ampere(void)
{
uint16_t Datas_Voltage_Amp_bp;
uint16_t Datas_Voltage_Amp_ap;
uint16_t Datas_Current;
Datas_Voltage_Amp_bp = 0;
Datas_Voltage_Amp_ap = 0;
Datas_Current = 0;
sendDataHead(ID_Voltage_Amp_bp);
write_FrSky16(Datas_Voltage_Amp_bp);
sendDataHead(ID_Voltage_Amp_ap);
write_FrSky16(Datas_Voltage_Amp_ap);
sendDataHead(ID_Current);
write_FrSky16(Datas_Current);
}
#endif