I have found what caused the problem, but have no idea why it does so.
As I mentioned earlier, the units supports two types of RF units. One type just reads the data. The other type requests data from different types of sensors on a single wire (so they can be chained).
To avoid the need to select the type manually, I implemented auto detection by first reading the signal pin (12). If I get some data within 1 second, it will support the requesting type (type-X). If not it will support the other type (type-D). This is done in isTelemetryTypeX().
The problem seems to be that SoftwareSerial gets upset if I read pin 12 first, and later use it to transmit data:
SoftwareSerial serialD(PIN_SerialTelemetryRX, PIN_SerialTelemetryTX, true);
SoftwareSerial telemetryTypeCheck(PIN_SerialTelemetryTX, PIN_SerialTelemetryRX, true); // Get input from Tx pin
The really strange part is that, as mentioned in previous posts, there is no problem if the pin transmits data to HW serial (setup #2), only if it transmits to SoftwareSerial on the other Pro Mini (setup #4). Data never gets available() there.
If I use another pin for SoftwareSerial telemetryTypeCheck(), the call to isTelemetryTypeX() causes no problems, but obviously becomes useless.
Anyone have an idea why this happens?
/*
Author: flarssen, 05/2015
GPS to FrSky Telemetry interface,
using
FrSky S-Port Telemetry library http://www.rcgroups.com/forums/showthread.php?t=2245978
TinyGPS library http://arduiniana.org/libraries/tinygps/
*/
#include <SoftwareSerial.h>
#include <TinyGPS.h>
#include "FrSkySportSensor.h"
#include "FrSkySportSensorGps.h"
#include "FrSkySportSingleWireSerial.h"
#include "FrSkySportTelemetry.h"
#define LED_PIN 13 // the pin connected to onboard LED
#define PIN_SerialTelemetryRX 255 // dummy
#define PIN_SerialTelemetryTX 12 // the pin to use for serial data to the FrSky receiver
FrSkySportSensorGps gps; // GPS sensor
FrSkySportTelemetry telemetry; // Telemetry object
TinyGPS tinyGps;
SoftwareSerial serialD(PIN_SerialTelemetryRX, PIN_SerialTelemetryTX, true);
SoftwareSerial telemetryTypeCheck(PIN_SerialTelemetryTX, PIN_SerialTelemetryRX, true); // Get input from Tx pin
uint32_t currentTime, sentenceTime1, sentenceTime2;
boolean telemetryTypeX;
byte gpsSentences = 0;
byte X[] = {3,1,1,3,0}; // -..-
byte D[] = {3,1,1,0}; // -..
void morse(byte values[])
{
for(int i=0; values[i]; i++) {
digitalWrite(LED_PIN, HIGH);
delay(values[i]*100);
digitalWrite(LED_PIN, LOW);
delay(100);
}
delay(300);
}
boolean isTelemetryTypeX(void) {
unsigned long lastTime;
boolean x = false;
telemetryTypeCheck.begin(115200);
lastTime = millis();
while (millis() < lastTime + 1000) {
while (telemetryTypeCheck.available()) {
if(telemetryTypeCheck.read() == FRSKY_TELEMETRY_START_FRAME) {
x = true;
break;
}
}
}
telemetryTypeCheck.end();
return x;
}
void SendDValue(uint8_t ID, uint16_t Value) {
uint8_t lsb = Value & 0x00ff;
uint8_t msb = (Value & 0xff00)>>8;
serialD.write(0x5E);
serialD.write(ID);
if(lsb == 0x5E) {
serialD.write(0x5D);
serialD.write(0x3E);
}
else if(lsb == 0x5D) {
serialD.write(0x5D);
serialD.write(0x3D);
}
else {
serialD.write(lsb);
}
if(msb == 0x5E) {
serialD.write(0x5D);
serialD.write(0x3E);
}
else if(msb == 0x5D) {
serialD.write(0x5D);
serialD.write(0x3D);
}
else {
serialD.write(msb);
}
serialD.write(0x5E);
}
void SendDGpsData(void) {
float flat, flon, falt, fc, fk, fmins;
unsigned long fix_age;
uint16_t degr, mins;
tinyGps.f_get_position(&flat, &flon, &fix_age);
falt = tinyGps.f_altitude(); // +/- altitude in meters
fc = tinyGps.f_course(); // course in degrees
fk = tinyGps.f_speed_mps(); // speed in m/sec
degr = (uint16_t)flat;
fmins = (flat-degr)*60;
mins = (uint16_t)fmins;
SendDValue(0x13, degr*100+(uint16_t)fmins); // Latitude (DDMM)
SendDValue(0x1B, (uint16_t)((fmins-mins)*10000)); // Latitude (.MMMM)
SendDValue(0x23, (uint16_t)(flat < 0 ? 'S' : 'N'));
degr = (uint16_t)flon;
fmins = (flon-degr)*60;
mins = (uint16_t)fmins;
SendDValue(0x12, degr*100+(uint16_t)fmins); // Longitude (DDMM)
SendDValue(0x1A, (uint16_t)((fmins-mins)*10000)); // Longitude (.MMMM)
SendDValue(0x22, (uint16_t)(flon < 0 ? 'W' : 'E'));
SendDValue(0x01, (int16_t)falt); // Altitude m
SendDValue(0x09, (uint16_t)((abs(falt)-(uint16_t)abs(falt))*100)); // Altitude centimeter
SendDValue(0x11, (uint16_t)fk); // Speed knots
SendDValue(0x19, (uint16_t)((fk-(uint16_t)fk)*100)); // Speed decimals
SendDValue(0x14, (uint16_t)fc); // Course degrees
SendDValue(0x1C, (uint16_t)((fc-(uint16_t)fc)*100)); // Course decimals
}
void SetXGpsData(void)
{
float flat, flon, falt, fc, fmps;
unsigned long fix_age;
tinyGps.f_get_position(&flat, &flon, &fix_age);
falt = tinyGps.f_altitude(); // +/- altitude in meters
fc = tinyGps.f_course(); // course in degrees
fmps = tinyGps.f_speed_mps(); // speed in m/sec
gps.setData(flat, flon, falt, fmps, fc, 14, 9, 14, 12, 00, 00);
}
void setup()
{
pinMode(LED_PIN, OUTPUT);
telemetryTypeX = isTelemetryTypeX();
if (telemetryTypeX) {
telemetry.begin(FrSkySportSingleWireSerial::SOFT_SERIAL_PIN_12, &gps);
morse(X);
}
else {
serialD.begin(9600);
morse(D);
}
Serial.begin(9600);
}
void loop() {
while (Serial.available() > 0) {
if (tinyGps.encode(Serial.read())) { // if a NMEA sentence is complete
if (!gpsSentences) // if first of two sentences
sentenceTime1 = millis(); // timestamp sentence 1
else
sentenceTime2 = millis(); // timestamp sentence 2
gpsSentences++;
}
if (gpsSentences > 1) { // if more then one sentence
if (sentenceTime2 - sentenceTime1 > 175) {// sentences not from same dataset, resync
sentenceTime1 = sentenceTime2;
gpsSentences = 1;
}
else { // process GPS data
digitalWrite(LED_PIN, HIGH);
if (telemetryTypeX)
SetXGpsData();
else
SendDGpsData();
digitalWrite(LED_PIN, LOW);
gpsSentences = 0;
}
}
}
if (telemetryTypeX)
telemetry.send();
}
Fred