Merging/expanding OpenXVario branches

Development & General Chat for the superb openxvario project.

Moderator: rainer

mstrens
Posts: 1435
Joined: Fri Dec 27, 2013 7:49 pm
Country: -

Re: Merging/expanding OpenXVario branches

Post by mstrens »

@RaptorSense
I do not 100% understand the code that you provided.
As far I understand, you use timer 1 with a prescaler set to 1024 and you redefine a function milli().
Please note that in OXS, timer 1 is used for other purposes too (e.g. micros() and RPM) that are based on a prescaler set to 1.

For you information, I worked yesterday on OXS in order to fully support the Multiplex protocol inside the same version as the one used for FRSKY protocol.
The modifications are nearly done.
Still I can't test them because I do not have Multiplex devices.
Perhaps you could test it?
Note: developments are based on the documention found at this link:
http://www.mikrocontroller.net/articles ... _%28MSB%29
I hope this is right. If not could you give me a link to the right documentaion.

RaptorSense
Posts: 30
Joined: Sun Feb 16, 2014 11:50 pm
Country: -

Re: Merging/expanding OpenXVario branches

Post by RaptorSense »

Hi,

That’s correct, the Timer1 is used for ‘a kind of’ millis() function. The resolution with the prescaler set to 1024 is OK for me. And, it doesn’t give conflicts as I don't measure the RPM. But it is thus a problem for oXs. I didn’t check the RPM code yet, maybe there is a work around.

The documentation that you found is perfect, I should have it when I was trying to understand the protocol. At the end, the Multiplex MLink protocol is very easy to implement. It is even simpler than the Sport. The system polls the sensors and the sensors answer in a given time frame. And you have to scale the values according to their rigid conventions. That’s all.

Here is my old MLink implementation:
[Edit2: Source is slightly adapted according to the information from the link below ]
[Edit3: Setup logic is now similar to other protocols ]

Code: Select all

// RaptorSense Multiplex MLink
// Sinan 22-11-2013
// Sinan 5-1-2015    MLink data types completed: http://www.mikrocontroller.net/articles/Der_Multiplex_Sensor_Bus_%28MSB%29#Datenformat_und_Adressen 
//                   Sensor reset implemented
//                   Setup logic compatible with the other protocols

#include "TelemetryMLink.h"
#include "TelemetryValues.h"
#include "SoftwareSerialHD.h"

#define MLINK_RESET_COMMAND                0x5A

#define MLINK_DATATYPE_UNDEFINED           0
#define MLINK_DATATYPE_VOLTAGE             1   // 0.1v      -600..600
#define MLINK_DATATYPE_POWER               2   // 0.1A     -1000..1000
#define MLINK_DATATYPE_VERTICAL_SPEED      3   // 0.1m/s    -500..500
#define MLINK_DATATYPE_VELOCITY            4   // 0.1km/h      0..6000
#define MLINK_DATATYPE_RPM                 5   // 100rpm bzw. 10rpm    0..500  0..5000
#define MLINK_DATATYPE_TEMPERATURE         6   // 0.1C      -250..7000
#define MLINK_DATATYPE_DIRECTION           7   // 0.1deg       0..3600
#define MLINK_DATATYPE_ALTITUDE            8   // 1m        -500..2000
#define MLINK_DATATYPE_FUEL_LEVEL          9   // 1% tank      0..100
#define MLINK_DATATYPE_LQI                 10  // 1% LQI       0..100
#define MLINK_DATATYPE_POWER_USAGE         11  // 1mAh    -16000..16000
#define MLINK_DATATYPE_FUEL_USAGE          12  // 1mL          0..16000
#define MLINK_DATATYPE_DISTANCE            13  // 0.1km        0..16000

#define SETUP_MLINKDATA_TO_SEND \
             TELEMETRY_DTE        , MLINK_DATATYPE_VERTICAL_SPEED,  9,   20, -500,  500 \
           , TELEMETRY_ALTITUDE   , MLINK_DATATYPE_ALTITUDE      , 10,    2, -500, 2000 \
           , TELEMETRY_AIRSPEED   , MLINK_DATATYPE_VELOCITY      , 11,   72,    0, 6000 \
           , TELEMETRY_DH         , MLINK_DATATYPE_VERTICAL_SPEED, 12,   20, -500,  500 \
           , TELEMETRY_TEMPERATURE, MLINK_DATATYPE_TEMPERATURE   , 13,   20, -250,  700 

typedef struct t_MLinkData
{
  byte rsFieldId;
  byte dataType;
  byte screenPos;
  double multiplicationFactor;
  int minValue;
  int maxValue;
};
t_MLinkData _mLinkField[] = {SETUP_MLINKDATA_TO_SEND};

// ____________________________________________________________________________
void TelemetryMLinkClass::Init(byte softSerialPin)
{
  UTIL.SoftSerial.begin(softSerialPin, softSerialPin, 38400, false);
  UTIL.SoftSerial.setTransmitMode(false);
  _fieldCount = sizeof(_mLinkField) / sizeof(_mLinkField[0]);
}

// ____________________________________________________________________________
void TelemetryMLinkClass::SendNextValue()
{
  _requestedScreenPos = 255;
  while (UTIL.SoftSerial.available())  // use the latest
  {
    _requestedScreenPos = UTIL.SoftSerial.read(); 
    if (_requestedScreenPos == MLINK_RESET_COMMAND)
    {
      UTIL.ResetRS = true;
      return;
    }
  }
  if (_requestedScreenPos < 255)
  {
    for (_index = 0; _index < _fieldCount; _index++)
    {
      if (_mLinkField[_index].screenPos == _requestedScreenPos)
      {
        if (TELEMETRY_VALUES.PreCalculatedValueAvailable(_mLinkField[_index].rsFieldId))
        {
          _value = (int16_t)(TELEMETRY_VALUES.GetPreCalculatedValue(_mLinkField[_index].rsFieldId, true) * 20);
          sendField(_requestedScreenPos, _mLinkField[_index].dataType, constrain(_value, _mLinkField[_index].minValue, _mLinkField[_index].maxValue));
        }
        break;
      }
    }
  }
}

// ____________________________________________________________________________
void TelemetryMLinkClass::sendField(byte screenPos, byte dataType, int16_t value)
{
  value = value & 0b1111111111111110; // disable alarm
  _singleResultArr[0] = screenPos << 4 | dataType;
  _singleResultArr[1] = lowByte(value);
  _singleResultArr[2] = highByte(value);

  UTIL.SoftSerial.setTransmitMode(true);
  UTIL.SoftSerial.write(_singleResultArr, 3);
  UTIL.SoftSerial.setTransmitMode(false);
}

TelemetryMLinkClass TELEMETRY_MLINK;
[Edit1: ***Please note hereby that the Multiplex protocol works with non-inverted serial signal.]

Yes, it works now as expected. I have to borrow a MLink system to check if it's still working. I can also test your code then.

Other protocols are implemented in a similar fashion. SPort is slightly more complex due to the byte stuffing but at the end it’s a simple piece of code.

The problem is, the oXs code is so differently structured that I am struggling to port parts of my implementation. I am trying to refactor it but it doesn't feel comfortable to shuffle the others code too much.

Cheers, Sinan
Last edited by RaptorSense on Mon Jan 05, 2015 6:50 pm, edited 3 times in total.
RaptorSense
Posts: 30
Joined: Sun Feb 16, 2014 11:50 pm
Country: -

Re: Merging/expanding OpenXVario branches

Post by RaptorSense »

This is my code for the SPort protocol:

Code: Select all

// RaptorSense FrSky SPort protocol
// Sinan 10-5-2014
// 24-6-2014 Data conditioning moved to TelemetryValues.cpp
//           SETUP_SPORTDATA_TO_SEND idea from oXs implemented
// 6-8-2014  Algorithm for priorities in getFieldIdToSend()
#include "TelemetryFrSkySPort.h"
#include "SoftwareSerialHD.h"
#include "Settings.h"
#include "TimeKeeper.h"


typedef struct t_SPortData
{
  byte fieldId;
  uint16_t sPortDataTypeId;
  double refreshPeriod;
  double multiplicationFactor, divisionFactor, offset;
  double sendAt;
};

t_SPortData _telemetryField[] = {SETUP_SPORTDATA_TO_SEND};

// ____________________________________________________________________________
void TelemetryFrSkySPortClass::Init(byte softSerialPin)
{
  UTIL.SoftSerial.begin(softSerialPin, softSerialPin, 57600, true);
  UTIL.SoftSerial.setTransmitMode(false);
  _stuffedDataPacket[0] = FRSKY_X_PACKET_START;
  _fieldCount = sizeof(_telemetryField) / sizeof(_telemetryField[0]);
}

// ____________________________________________________________________________
void TelemetryFrSkySPortClass::SendNextValue()
{
  TELEMETRY_VALUES.Timestamp = TimeKeeper.Milliseconds();

  while (UTIL.SoftSerial.available())
  {
    _incoming = UTIL.SoftSerial.read();
    if (_incoming == FRSKY_X_FIELD_SEPARATOR)
    {
      _beginDataRequest = true;
    }
    else
    {
      if (_beginDataRequest)
      {
        if (!UTIL.SoftSerial.available() && (_incoming == RAPTORSENSE_DEVICE_ID))   //  RAPTORSENSE_SENSOR_ID    0x1B // 27 
        {
          sendTeleField(getFieldIdToSend());
        }
        _beginDataRequest = false;
      }
    }
  }
}

// ____________________________________________________________________________
int TelemetryFrSkySPortClass::getFieldIdToSend()
{
  _chosenField = 0;
  _highestUrgency = 0;
  _now = TimeKeeper.Milliseconds();

  for (size_t i = 0; i < _fieldCount; i++)
  {
    if (TELEMETRY_VALUES.PreCalculatedValueAvailable(_telemetryField[i].fieldId))
    {
      _timePast = _now - _telemetryField[i].sendAt;
      _urgency = _timePast / _telemetryField[i].refreshPeriod;
      if (_urgency > _highestUrgency)
      {
        _highestUrgency = _urgency;
        _chosenField = i;
      }
    }
  }
  if (_highestUrgency < 1) return -1;
  return  _chosenField;
}

// ____________________________________________________________________________
void TelemetryFrSkySPortClass::sendTeleField(byte field)
{
  if (field >= 0)
  {
    _stuffedDataPacket[0] = FRSKY_X_PACKET_START;
    _crc = FRSKY_X_PACKET_START;
    _stuffedDataPos = 1;

    addToStuffedDataPacket(lowByte(_telemetryField[field].sPortDataTypeId));
    addToStuffedDataPacket(highByte(_telemetryField[field].sPortDataTypeId));

    _scaledValue = TELEMETRY_VALUES.GetPreCalculatedValue(_telemetryField[field].fieldId, true);

#if SEND_TELEMETRY_DEBUG
    TELEMETRY_VALUES.LastSendValue[_telemetryField[field].fieldId] = _scaledValue;
#endif

    _scaledValue = (_scaledValue + _telemetryField[field].offset) * _telemetryField[field].multiplicationFactor;
    int32_t sValue = (int32_t)_scaledValue;
    addToStuffedDataPacket(sValue);
    addToStuffedDataPacket(sValue >> 8);
    addToStuffedDataPacket(sValue >> 16);
    addToStuffedDataPacket(sValue >> 24);

    _stuffedDataPacket[_stuffedDataPos] = (byte)(255 - _crc);
    _stuffedDataPos++;

    UTIL.SoftSerial.setTransmitMode(true);
    UTIL.SoftSerial.write(_stuffedDataPacket, _stuffedDataPos);
    UTIL.SoftSerial.setTransmitMode(false);
    _telemetryField[field].sendAt = TimeKeeper.Milliseconds();
  }
}

// ____________________________________________________________________________
void TelemetryFrSkySPortClass::addToStuffedDataPacket(byte d)
{
  _crc += d;
  _crc += _crc >> 8;
  _crc &= 0x00ff;
  if ((d == FRSKY_X_FIELD_SEPARATOR) || (d == FRSKY_X_ESC_CHAR))
  {
    _stuffedDataPacket[_stuffedDataPos++] = FRSKY_X_ESC_CHAR;
    d = d ^ FRSKY_X_STUFFING_MASK;
  }
  _stuffedDataPacket[_stuffedDataPos++] = d;
}

TelemetryFrSkySPortClass TELEMETRY_SPORT;

Post Reply

Return to “OpenXVario - an open source vario supported by the open source firmwares!!”