1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-29 14:52:12 +01:00

Merge remote-tracking branch 'origin/LesNewell/OP-984_PID_banks' into thread/OP-984_PID_banks_GUI

This commit is contained in:
Fredrik Arvidsson 2014-01-14 20:27:57 +01:00
commit f639ab30b0
4 changed files with 5473 additions and 950 deletions

View File

@ -691,26 +691,26 @@ static void updateStabilizationDesired(ManualControlCommandData *cmd, ManualCont
}
stabilization.Roll =
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) ? cmd->Roll :
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) ? cmd->Roll * stabSettings.ManualRate.Roll :
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING) ? cmd->Roll * stabSettings.ManualRate.Roll :
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) ? cmd->Roll * stabSettings.RollMax :
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK) ? cmd->Roll * stabSettings.ManualRate.Roll :
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_VIRTUALBAR) ? cmd->Roll :
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATTITUDE) ? cmd->Roll :
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_RELAYRATE) ? cmd->Roll * stabSettings.ManualRate.Roll :
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) ? cmd->Roll :
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) ? cmd->Roll * stabSettings.ManualRate.Roll :
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING) ? cmd->Roll * stabSettings.ManualRate.Roll :
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) ? cmd->Roll * stabSettings.RollMax :
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK) ? cmd->Roll * stabSettings.ManualRate.Roll :
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_VIRTUALBAR) ? cmd->Roll :
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATTITUDE) ? cmd->Roll :
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_RELAYRATE) ? cmd->Roll * stabSettings.ManualRate.Roll :
(stab_settings[0] == STABILIZATIONDESIRED_STABILIZATIONMODE_RELAYATTITUDE) ? cmd->Roll * stabSettings.RollMax :
0; // this is an invalid mode
stabilization.Pitch =
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) ? cmd->Pitch :
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) ? cmd->Pitch * stabSettings.ManualRate.Pitch :
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING) ? cmd->Pitch * stabSettings.ManualRate.Pitch :
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) ? cmd->Pitch * stabSettings.PitchMax :
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK) ? cmd->Pitch * stabSettings.ManualRate.Pitch :
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_VIRTUALBAR) ? cmd->Pitch :
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATTITUDE) ? cmd->Pitch :
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_RELAYRATE) ? cmd->Pitch * stabSettings.ManualRate.Pitch :
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) ? cmd->Pitch :
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) ? cmd->Pitch * stabSettings.ManualRate.Pitch :
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING) ? cmd->Pitch * stabSettings.ManualRate.Pitch :
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) ? cmd->Pitch * stabSettings.PitchMax :
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK) ? cmd->Pitch * stabSettings.ManualRate.Pitch :
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_VIRTUALBAR) ? cmd->Pitch :
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATTITUDE) ? cmd->Pitch :
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_RELAYRATE) ? cmd->Pitch * stabSettings.ManualRate.Pitch :
(stab_settings[1] == STABILIZATIONDESIRED_STABILIZATIONMODE_RELAYATTITUDE) ? cmd->Pitch * stabSettings.PitchMax :
0; // this is an invalid mode
@ -722,18 +722,17 @@ static void updateStabilizationDesired(ManualControlCommandData *cmd, ManualCont
if (stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATTITUDE) {
stabilization.StabilizationMode.Yaw = STABILIZATIONDESIRED_STABILIZATIONMODE_RATE;
stabilization.Yaw = cmd->Yaw * stabSettings.ManualRate.Yaw;
}
else {
} else {
stabilization.StabilizationMode.Yaw = stab_settings[2];
stabilization.Yaw =
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) ? cmd->Yaw :
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) ? cmd->Yaw * stabSettings.ManualRate.Yaw :
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING) ? cmd->Yaw * stabSettings.ManualRate.Yaw :
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) ? cmd->Yaw * stabSettings.YawMax :
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK) ? cmd->Yaw * stabSettings.ManualRate.Yaw :
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_VIRTUALBAR) ? cmd->Yaw :
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATTITUDE) ? cmd->Yaw :
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_RELAYRATE) ? cmd->Yaw * stabSettings.ManualRate.Yaw :
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_NONE) ? cmd->Yaw :
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATE) ? cmd->Yaw * stabSettings.ManualRate.Yaw :
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING) ? cmd->Yaw * stabSettings.ManualRate.Yaw :
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE) ? cmd->Yaw * stabSettings.YawMax :
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_AXISLOCK) ? cmd->Yaw * stabSettings.ManualRate.Yaw :
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_VIRTUALBAR) ? cmd->Yaw :
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_RATTITUDE) ? cmd->Yaw :
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_RELAYRATE) ? cmd->Yaw * stabSettings.ManualRate.Yaw :
(stab_settings[2] == STABILIZATIONDESIRED_STABILIZATIONMODE_RELAYATTITUDE) ? cmd->Yaw * stabSettings.YawMax :
0; // this is an invalid mode
}

View File

@ -80,8 +80,8 @@
// The PID_RATEA_ROLL set is used by Rattitude mode because it needs to maintain
// - two independant rate PIDs because it does rate and attitude simultaneously
enum { PID_RATE_ROLL, PID_RATE_PITCH, PID_RATE_YAW, PID_ROLL, PID_PITCH, PID_YAW, PID_RATEA_ROLL, PID_RATEA_PITCH, PID_RATEA_YAW, PID_MAX };
enum{RATE_P, RATE_I, RATE_D, RATE_LIMIT, RATE_OFFSET};
enum{ATT_P, ATT_I, ATT_LIMIT, ATT_OFFSET};
enum { RATE_P, RATE_I, RATE_D, RATE_LIMIT, RATE_OFFSET };
enum { ATT_P, ATT_I, ATT_LIMIT, ATT_OFFSET };
// Private variables
static xTaskHandle taskHandle;
@ -98,7 +98,7 @@ bool lowThrottleZeroAxis[MAX_AXES];
float vbar_decay = 0.991f;
struct pid pids[PID_MAX];
int flight_mode = -1;
int flight_mode = -1;
static uint8_t rattitude_anti_windup;
@ -224,7 +224,7 @@ static void stabilizationTask(__attribute__((unused)) void *parameters)
RateDesiredGet(&rateDesired);
#endif
if(flight_mode != flightStatus.FlightMode){
if (flight_mode != flightStatus.FlightMode) {
flight_mode = flightStatus.FlightMode;
SettingsBankUpdatedCb(NULL);
}
@ -284,9 +284,9 @@ static void stabilizationTask(__attribute__((unused)) void *parameters)
#else /* if defined(PIOS_QUATERNION_STABILIZATION) */
// Simpler algorithm for CC, less memory
float local_error[3] = { stabDesired.Roll - attitudeState.Roll,
float local_error[3] = { stabDesired.Roll - attitudeState.Roll,
stabDesired.Pitch - attitudeState.Pitch,
stabDesired.Yaw - attitudeState.Yaw };
stabDesired.Yaw - attitudeState.Yaw };
// find shortest way
float modulo = fmodf(local_error[2] + 180.0f, 360.0f);
if (modulo < 0) {
@ -352,15 +352,15 @@ static void stabilizationTask(__attribute__((unused)) void *parameters)
break;
case STABILIZATIONDESIRED_STABILIZATIONMODE_RATTITUDE:
// A parameterization from Attitude mode at center stick
// - to Rate mode at full stick
// This is done by parameterizing to use the rotation rate that Attitude mode
// - would use at center stick to using the rotation rate that Rate mode
// - would use at full stick in a weighted average sort of way.
// A parameterization from Attitude mode at center stick
// - to Rate mode at full stick
// This is done by parameterizing to use the rotation rate that Attitude mode
// - would use at center stick to using the rotation rate that Rate mode
// - would use at full stick in a weighted average sort of way.
{
if (reinit) {
pids[PID_ROLL + i].iAccumulator = 0;
pids[PID_RATE_ROLL + i].iAccumulator = 0;
pids[PID_ROLL + i].iAccumulator = 0;
pids[PID_RATE_ROLL + i].iAccumulator = 0;
pids[PID_RATEA_ROLL + i].iAccumulator = 0;
}
@ -368,7 +368,7 @@ static void stabilizationTask(__attribute__((unused)) void *parameters)
// Save Rate's rate in a temp for later merging with Attitude's rate
float rateDesiredAxisRate;
rateDesiredAxisRate = bound(stabDesiredAxis[i], 1.0f)
* cast_struct_to_array(stabBank.ManualRate, stabBank.ManualRate.Roll)[i];
* cast_struct_to_array(stabBank.ManualRate, stabBank.ManualRate.Roll)[i];
// Compute what Attitude mode would give for this stick angle's rate
@ -377,8 +377,8 @@ static void stabilizationTask(__attribute__((unused)) void *parameters)
// - subtract off the actual angle to get the angle error
// This is what local_error[] holds for Attitude mode
float attitude_error = stabDesiredAxis[i]
* cast_struct_to_array(stabBank.RollMax, stabBank.RollMax)[i]
- cast_struct_to_array(attitudeState.Roll, attitudeState.Roll)[i];
* cast_struct_to_array(stabBank.RollMax, stabBank.RollMax)[i]
- cast_struct_to_array(attitudeState.Roll, attitudeState.Roll)[i];
// Compute the outer loop just like Attitude mode does
float rateDesiredAxisAttitude;
@ -395,14 +395,14 @@ static void stabilizationTask(__attribute__((unused)) void *parameters)
// magnitude = sqrt(stabDesired.Roll*stabDesired.Roll + stabDesired.Pitch*stabDesired.Pitch);
float magnitude;
magnitude = fmaxf(fabsf(stabDesired.Roll), fabsf(stabDesired.Pitch));
rateDesiredAxis[i] = (1.0f-magnitude) * rateDesiredAxisAttitude
+ magnitude * rateDesiredAxisRate;
rateDesiredAxis[i] = (1.0f - magnitude) * rateDesiredAxisAttitude
+ magnitude * rateDesiredAxisRate;
// Compute the inner loop for both Rate mode and Attitude mode
// actuatorDesiredAxis[i] is the weighted average of the two PIDs from the two rates
actuatorDesiredAxis[i] =
(1.0f-magnitude) * pid_apply_setpoint(&pids[PID_RATEA_ROLL + i], speedScaleFactor, rateDesiredAxis[i], gyro_filtered[i], dT)
+ magnitude * pid_apply_setpoint(&pids[PID_RATE_ROLL + i], speedScaleFactor, rateDesiredAxis[i], gyro_filtered[i], dT);
(1.0f - magnitude) * pid_apply_setpoint(&pids[PID_RATEA_ROLL + i], speedScaleFactor, rateDesiredAxis[i], gyro_filtered[i], dT)
+ magnitude * pid_apply_setpoint(&pids[PID_RATE_ROLL + i], speedScaleFactor, rateDesiredAxis[i], gyro_filtered[i], dT);
actuatorDesiredAxis[i] = bound(actuatorDesiredAxis[i], 1.0f);
// settings.RattitudeAntiWindup controls the iAccumulator zeroing
@ -440,28 +440,28 @@ static void stabilizationTask(__attribute__((unused)) void *parameters)
// the 7.966 and 17.668 cancel the default PID value and dT given to log2f()
// if these are non-default, tweaking is thus done so the user doesn't have to readjust
// the default value of 10 for UAVO RattitudeAntiWindup gives a power of 22
// these calculations are for magnitude = 0.5, so 22 corresponds to the number of bits
// used in the mantissa of the float
// i.e. 1.0-(0.5^22) almost underflows
// these calculations are for magnitude = 0.5, so 22 corresponds to the number of bits
// used in the mantissa of the float
// i.e. 1.0-(0.5^22) almost underflows
// This may only be useful for aircraft with large Ki values and limits
if (dT > 0.0f && rattitude_anti_windup > 0.0f) {
float factor;
// At magnitudes close to one, the Attitude accumulators gets zeroed
if (pids[PID_ROLL+i].i > 0.0f) {
factor = 1.0f - stab_powf(magnitude, ((uint8_t) (32.1f - 7.966f - stab_log2f(dT * pids[PID_ROLL+i].i))) - rattitude_anti_windup);
pids[PID_ROLL+i].iAccumulator *= factor;
if (pids[PID_ROLL + i].i > 0.0f) {
factor = 1.0f - stab_powf(magnitude, ((uint8_t)(32.1f - 7.966f - stab_log2f(dT * pids[PID_ROLL + i].i))) - rattitude_anti_windup);
pids[PID_ROLL + i].iAccumulator *= factor;
}
if (pids[PID_RATEA_ROLL+i].i > 0.0f) {
factor = 1.0f - stab_powf(magnitude, ((uint8_t) (32.1f - 17.668f - stab_log2f(dT * pids[PID_RATEA_ROLL+i].i))) - rattitude_anti_windup);
pids[PID_RATEA_ROLL+i].iAccumulator *= factor;
if (pids[PID_RATEA_ROLL + i].i > 0.0f) {
factor = 1.0f - stab_powf(magnitude, ((uint8_t)(32.1f - 17.668f - stab_log2f(dT * pids[PID_RATEA_ROLL + i].i))) - rattitude_anti_windup);
pids[PID_RATEA_ROLL + i].iAccumulator *= factor;
}
// At magnitudes close to zero, the Rate accumulator gets zeroed
if (pids[PID_RATE_ROLL+i].i > 0.0f) {
factor = 1.0f - stab_powf(1.0f-magnitude, ((uint8_t) (32.1f - 17.668f - stab_log2f(dT * pids[PID_RATE_ROLL+i].i))) - rattitude_anti_windup);
pids[PID_RATE_ROLL+i].iAccumulator *= factor;
if (pids[PID_RATE_ROLL + i].i > 0.0f) {
factor = 1.0f - stab_powf(1.0f - magnitude, ((uint8_t)(32.1f - 17.668f - stab_log2f(dT * pids[PID_RATE_ROLL + i].i))) - rattitude_anti_windup);
pids[PID_RATE_ROLL + i].iAccumulator *= factor;
}
}
@ -479,12 +479,12 @@ static void stabilizationTask(__attribute__((unused)) void *parameters)
break;
case STABILIZATIONDESIRED_STABILIZATIONMODE_WEAKLEVELING:
// FIXME: local_error[] is rate - attitude for Weak Leveling
// The only ramifications are:
// Weak Leveling Kp is off by a factor of 3 to 12 and may need a different default in GCS
// Changing Rate mode max rate currently requires a change to Kp
// That would be changed to Attitude mode max angle affecting Kp
// Also does not take dT into account
// FIXME: local_error[] is rate - attitude for Weak Leveling
// The only ramifications are:
// Weak Leveling Kp is off by a factor of 3 to 12 and may need a different default in GCS
// Changing Rate mode max rate currently requires a change to Kp
// That would be changed to Attitude mode max angle affecting Kp
// Also does not take dT into account
{
if (reinit) {
pids[PID_RATE_ROLL + i].iAccumulator = 0;
@ -649,71 +649,68 @@ static float bound(float val, float range)
// x small (0.0 < x < .01) so interpolation of fractional part is reasonable
static float stab_log2f(float x)
{
union
{
volatile float f;
volatile uint32_t i;
volatile unsigned char c[4];
} __attribute__((packed)) u1, u2;
union {
volatile float f;
volatile uint32_t i;
volatile unsigned char c[4];
} __attribute__((packed)) u1, u2;
u2.f = u1.f = x;
u1.i <<= 1;
u2.i &= 0xff800000;
u2.f = u1.f = x;
u1.i <<= 1;
u2.i &= 0xff800000;
// get and unbias the exponent, add in a linear interpolation of the fractional part
return (float) (u1.c[3] - 127) + (x / u2.f) - 1.0f;
// get and unbias the exponent, add in a linear interpolation of the fractional part
return (float)(u1.c[3] - 127) + (x / u2.f) - 1.0f;
}
// 0<=x<=1, 0<=p<=31
static float stab_powf(float x, uint8_t p)
{
float retval = 1.0f;
float retval = 1.0f;
while (p)
{
if (p&1)
{
retval *= x;
while (p) {
if (p & 1) {
retval *= x;
}
x *= x;
p >>= 1;
}
x *= x;
p >>= 1;
}
return retval;
return retval;
}
static void SettingsBankUpdatedCb(__attribute__((unused)) UAVObjEvent *ev)
{
StabilizationBankData bank, oldBank;
StabilizationBankGet(&oldBank);
if(flight_mode < 0) return;
if (flight_mode < 0) {
return;
}
switch(cast_struct_to_array(settings.FlightModeMap, settings.FlightModeMap.Stabilized1)[flight_mode])
{
switch (cast_struct_to_array(settings.FlightModeMap, settings.FlightModeMap.Stabilized1)[flight_mode]) {
case 0:
StabilizationSettingsBank1Get((StabilizationSettingsBank1Data *) &bank);
StabilizationSettingsBank1Get((StabilizationSettingsBank1Data *)&bank);
break;
case 1:
StabilizationSettingsBank2Get((StabilizationSettingsBank2Data *) &bank);
StabilizationSettingsBank2Get((StabilizationSettingsBank2Data *)&bank);
break;
case 2:
StabilizationSettingsBank3Get((StabilizationSettingsBank3Data *) &bank);
StabilizationSettingsBank3Get((StabilizationSettingsBank3Data *)&bank);
break;
default:
memset(&bank, 0, sizeof(StabilizationBankDataPacked));
// return; //bank number is invalid. All we can do is ignore it.
// return; //bank number is invalid. All we can do is ignore it.
}
//Need to do this to prevent an infinite loop
if(memcmp(&oldBank, &bank, sizeof(StabilizationBankDataPacked)) != 0)
{
// Need to do this to prevent an infinite loop
if (memcmp(&oldBank, &bank, sizeof(StabilizationBankDataPacked)) != 0) {
StabilizationBankSet(&bank);
}
}
@ -721,9 +718,10 @@ static void SettingsBankUpdatedCb(__attribute__((unused)) UAVObjEvent *ev)
static void BankUpdatedCb(__attribute__((unused)) UAVObjEvent *ev)
{
StabilizationBankData bank;
StabilizationBankGet(&bank);
//this code will be needed if any other modules alter stabilizationbank
// this code will be needed if any other modules alter stabilizationbank
/*
StabilizationBankData curBank;
if(flight_mode < 0) return;
@ -757,7 +755,7 @@ static void BankUpdatedCb(__attribute__((unused)) UAVObjEvent *ev)
default:
return; //invalid bank number
}
*/
*/
// Set the roll rate PID constants
@ -855,9 +853,9 @@ static void SettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev)
}
// Compute time constant for vbar decay term based on a tau
vbar_decay = expf(-fakeDt / settings.VbarTau);
vbar_decay = expf(-fakeDt / settings.VbarTau);
//force flight mode update
// force flight mode update
flight_mode = -1;
// Rattitude flight mode anti-windup factor

View File

@ -168,18 +168,17 @@ static void updatePIDs(UAVObjEvent *ev)
}
StabilizationBankData bank;
switch(inst.BankNumber)
{
switch (inst.BankNumber) {
case 0:
StabilizationSettingsBank1Get((StabilizationSettingsBank1Data *) &bank);
StabilizationSettingsBank1Get((StabilizationSettingsBank1Data *)&bank);
break;
case 1:
StabilizationSettingsBank2Get((StabilizationSettingsBank2Data *) &bank);
StabilizationSettingsBank2Get((StabilizationSettingsBank2Data *)&bank);
break;
case 2:
StabilizationSettingsBank2Get((StabilizationSettingsBank2Data *) &bank);
StabilizationSettingsBank2Get((StabilizationSettingsBank2Data *)&bank);
break;
default:
@ -317,18 +316,17 @@ static void updatePIDs(UAVObjEvent *ev)
StabilizationSettingsSet(&stab);
}
if (needsUpdateBank) {
switch(inst.BankNumber)
{
switch (inst.BankNumber) {
case 0:
StabilizationSettingsBank1Set((StabilizationSettingsBank1Data *) &bank);
StabilizationSettingsBank1Set((StabilizationSettingsBank1Data *)&bank);
break;
case 1:
StabilizationSettingsBank2Set((StabilizationSettingsBank2Data *) &bank);
StabilizationSettingsBank2Set((StabilizationSettingsBank2Data *)&bank);
break;
case 2:
StabilizationSettingsBank2Set((StabilizationSettingsBank2Data *) &bank);
StabilizationSettingsBank2Set((StabilizationSettingsBank2Data *)&bank);
break;
default:

View File

@ -1,57 +1,321 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_RFM22B Radio Functions
* @brief PIOS interface for for the RFM22B radio
* @{
*
* @file pios_rfm22b.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @brief Implements a driver the the RFM22B driver
* @see The GNU Public License (GPL) Version 3
* @addtogroup
* PIOS
* PIOS
* Core
* hardware
* abstraction
* layer
*
* @{
*
* @addtogroup
*
*
* PIOS_RFM22B
* Radio
* Functions
*
* @brief
* PIOS
* interface
* for
* for
* the
* RFM22B
* radio
*
* @{
*
*
* @file
*
*
*
*
*
*
* pios_rfm22b.c
*
* @author
*
*
*
*
* The
* OpenPilot
* Team,
* http://www.openpilot.org
* Copyright
* (C)
* 2012.
*
* @brief
*
*
*
*
*
* Implements
* a
* driver
* the
* the
* RFM22B
* driver
*
* @see
*
*
*
*
*
*
*
* The
* GNU
* Public
* License
* (GPL)
* Version
* 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
* This
* program
* is
* free
* software;
* you
* can
* redistribute
* it
* and/or
* modify
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* it
* under
* the
* terms
* of
* the
* GNU
* General
* Public
* License
* as
* published
* by
*
* the
* Free
* Software
* Foundation;
* either
* version
* 3
* of
* the
* License,
* or
*
* (at
* your
* option)
* any
* later
* version.
*
*
* This
* program
* is
* distributed
* in
* the
* hope
* that
* it
* will
* be
* useful,
* but
*
* WITHOUT
* ANY
* WARRANTY;
* without
* even
* the
* implied
* warranty
* of
* MERCHANTABILITY
*
* or
* FITNESS
* FOR
* A
* PARTICULAR
* PURPOSE.
* See
* the
* GNU
* General
* Public
* License
*
* for
* more
* details.
*
*
* You
* should
* have
* received
* a
* copy
* of
* the
* GNU
* General
* Public
* License
* along
*
* with
* this
* program;
* if
* not,
* write
* to
* the
* Free
* Software
* Foundation,
* Inc.,
*
* 59
* Temple
* Place,
* Suite
* 330,
* Boston,
* MA
* 02111-1307
* USA
*/
// *****************************************************************
// RFM22B hardware layer
//
// This module uses the RFM22B's internal packet handling hardware to
// encapsulate our own packet data.
//
// The RFM22B internal hardware packet handler configuration is as follows:
//
// 6-byte (32-bit) preamble .. alternating 0's & 1's
// 4-byte (32-bit) sync
// 1-byte packet length (number of data bytes to follow)
// 0 to 255 user data bytes
// 4 byte ECC
//
// OR in PPM only mode:
//
// 6-byte (32-bit) preamble .. alternating 0's & 1's
// 4-byte (32-bit) sync
// 1-byte packet length (number of data bytes to follow)
// 1 byte valid bitmask
// 8 PPM values (0-255)
// 1 byte CRC
//
// *****************************************************************
/*
* *****************************************************************
* RFM22B
* hardware
* layer
*
* This
* module
* uses
* the
* RFM22B's
* internal
* packet
* handling
* hardware
* to
* encapsulate
* our
* own
* packet
* data.
*
* The
* RFM22B
* internal
* hardware
* packet
* handler
* configuration
* is
* as
* follows:
*
* 6-byte
* (32-bit)
* preamble
* ..
* alternating
* 0's
* &
* 1's
* 4-byte
* (32-bit)
* sync
* 1-byte
* packet
* length
* (number
* of
* data
* bytes
* to
* follow)
* 0
* to
* 255
* user
* data
* bytes
* 4
* byte
* ECC
*
* OR
* in
* PPM
* only
* mode:
*
* 6-byte
* (32-bit)
* preamble
* ..
* alternating
* 0's
* &
* 1's
* 4-byte
* (32-bit)
* sync
* 1-byte
* packet
* length
* (number
* of
* data
* bytes
* to
* follow)
* 1
* byte
* valid
* bitmask
* 8
* PPM
* values
* (0-255)
* 1
* byte
* CRC
*
* *****************************************************************
*/
#include "pios.h"
@ -62,10 +326,14 @@
#include <pios_ppm_out.h>
#include <ecc.h>
/* Local Defines */
/*
* Local
* Defines
* */
#define STACK_SIZE_BYTES 200
#define TASK_PRIORITY (tskIDLE_PRIORITY + 2)
#define ISR_TIMEOUT 1 // ms
#define ISR_TIMEOUT 1 /*
* ms */
#define EVENT_QUEUE_SIZE 5
#define RFM22B_DEFAULT_RX_DATARATE RFM22_datarate_9600
#define RFM22B_DEFAULT_TX_POWER RFM22_tx_pwr_txpow_0
@ -76,30 +344,94 @@
#define RFM22B_DEFAULT_CHANNEL_SET 24
#define RFM22B_PPM_ONLY_DATARATE RFM22_datarate_9600
// The maximum amount of time without activity before initiating a reset.
#define PIOS_RFM22B_SUPERVISOR_TIMEOUT 150 // ms
/*
* The
* maximum
* amount
* of
* time
* without
* activity
* before
* initiating
* a
* reset. */
#define PIOS_RFM22B_SUPERVISOR_TIMEOUT 150 /*
* ms */
// this is too adjust the RF module so that it is on frequency
#define OSC_LOAD_CAP 0x7F // cap = 12.5pf .. default
/*
* this
* is
* too
* adjust
* the
* RF
* module
* so
* that
* it
* is
* on
* frequency */
#define OSC_LOAD_CAP 0x7F /*
* cap
* =
* 12.5pf
* ..
* default */
#define TX_PREAMBLE_NIBBLES 12 // 7 to 511 (number of nibbles)
#define RX_PREAMBLE_NIBBLES 6 // 5 to 31 (number of nibbles)
#define TX_PREAMBLE_NIBBLES 12 /*
* 7
* to
* 511
* (number
* of
* nibbles) */
#define RX_PREAMBLE_NIBBLES 6 /*
* 5
* to
* 31
* (number
* of
* nibbles) */
#define SYNC_BYTES 4
#define HEADER_BYTES 4
#define LENGTH_BYTES 1
// the size of the rf modules internal FIFO buffers
/*
* the
* size
* of
* the
* rf
* modules
* internal
* FIFO
* buffers */
#define FIFO_SIZE 64
#define TX_FIFO_HI_WATERMARK 62 // 0-63
#define TX_FIFO_LO_WATERMARK 32 // 0-63
#define TX_FIFO_HI_WATERMARK 62 /*
* 0-63 */
#define TX_FIFO_LO_WATERMARK 32 /*
* 0-63 */
#define RX_FIFO_HI_WATERMARK 32 // 0-63
#define RX_FIFO_HI_WATERMARK 32 /*
* 0-63 */
// preamble byte (preceeds SYNC_BYTE's)
/*
* preamble
* byte
* (preceeds
* SYNC_BYTE's) */
#define PREAMBLE_BYTE 0x55
// RF sync bytes (32-bit in all)
/*
* RF
* sync
* bytes
* (32-bit
* in
* all) */
#define SYNC_BYTE_1 0x2D
#define SYNC_BYTE_2 0xD4
#define SYNC_BYTE_3 0x4B
@ -116,279 +448,1056 @@
#define USB_LED_OFF
#endif
/* Local type definitions */
/*
* Local
* type
* definitions
* */
struct pios_rfm22b_transition {
enum pios_radio_event (*entry_fn)(struct pios_rfm22b_dev *rfm22b_dev);
enum pios_radio_state next_state[RADIO_EVENT_NUM_EVENTS];
enum
pios_radio_event
(
*
entry_fn)(
struct
pios_rfm22b_dev
*
rfm22b_dev);
enum
pios_radio_state
next_state
[
RADIO_EVENT_NUM_EVENTS];
};
// Must ensure these prefilled arrays match the define sizes
/*
* Must
* ensure
* these
* prefilled
* arrays
* match
* the
* define
* sizes */
static const uint8_t FULL_PREAMBLE[FIFO_SIZE] = {
PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE,
PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE,
PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE,
PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE,
PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE,
PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE,
PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE,
PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE,
PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE,
PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE,
PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE,
PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE,
PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE
}; // 64 bytes
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE,
PREAMBLE_BYTE
}; /*
* 64
* bytes */
static const uint8_t HEADER[(TX_PREAMBLE_NIBBLES + 1) / 2 + 2] = { PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, PREAMBLE_BYTE, SYNC_BYTE_1, SYNC_BYTE_2 };
static const uint8_t OUT_FF[64] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,0xFF, 0xFF, 0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,0xFF, 0xFF, 0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,0xFF, 0xFF, 0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,0xFF, 0xFF, 0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,0xFF, 0xFF, 0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,0xFF, 0xFF, 0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,0xFF, 0xFF, 0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,0xFF, 0xFF, 0xFF
};
/*
* The
* randomized
* channel
* list. */
static const uint8_t channel_list[] = {
68,
34,
2,
184,166, 94, 204, 18, 47, 118, 239, 176, 5, 213, 218, 186, 104, 160, 199, 209, 231, 197, 92, 191, 88, 129, 40, 19, 93, 200, 156, 14, 247, 182, 193, 194, 208, 210, 248, 76, 244, 48, 179, 105, 25, 74, 155, 203,
39,
97,
195,81, 83, 180, 134, 172, 235, 132, 198, 119, 207,
154,
0,
61,
140,171, 245, 26, 95, 3, 22, 62, 169, 55, 127, 144, 45, 33, 170, 91, 158, 167, 63, 201, 41, 21, 190, 51, 103, 49, 189, 205, 240, 89, 181, 149, 6, 157, 249, 230, 115, 72, 163, 17, 29, 99, 28, 117, 219,
73,
78,
53, 69,
216,
161,
124,
110,242, 214, 145, 13, 11, 220, 113, 138, 58, 54, 162, 237, 37, 152, 187, 232, 77, 126, 85, 38, 238, 173, 23, 188, 100, 131, 226, 31, 9, 114, 106, 221, 42, 233, 139, 4, 241, 96, 211, 8, 98, 121, 147, 24,
217,
27,
87,
122,
125,
135,
148,178, 71, 206, 57, 141, 35, 30, 246, 159, 16, 32, 15, 229, 20, 12, 223, 150, 101, 79, 56, 102, 111, 174, 236, 137, 143, 52, 225, 64, 224, 112, 168, 243, 130, 108, 202, 123, 146, 228, 75, 46, 153, 7, 192,
175,
151,
222,
59,
82,
90, 1, 65, 109, 44, 165, 84, 43, 36, 128, 196, 67, 80, 136, 86, 70, 234, 66, 185, 10, 164, 177, 116, 50, 107, 183, 215, 212, 60, 227, 133, 120, 142
};
// The randomized channel list.
static const uint8_t channel_list[] = { 68, 34, 2, 184, 166, 94, 204, 18, 47, 118, 239, 176, 5, 213, 218, 186, 104, 160, 199, 209, 231, 197, 92, 191, 88, 129, 40, 19, 93, 200, 156, 14, 247, 182, 193, 194, 208, 210, 248, 76, 244, 48, 179, 105, 25, 74, 155, 203, 39, 97, 195, 81, 83, 180, 134, 172, 235, 132, 198, 119, 207, 154, 0, 61, 140, 171, 245, 26, 95, 3, 22, 62, 169, 55, 127, 144, 45, 33, 170, 91, 158, 167, 63, 201, 41, 21, 190, 51, 103, 49, 189, 205, 240, 89, 181, 149, 6, 157, 249, 230, 115, 72, 163, 17, 29, 99, 28, 117, 219, 73, 78, 53, 69, 216, 161, 124, 110, 242, 214, 145, 13, 11, 220, 113, 138, 58, 54, 162, 237, 37, 152, 187, 232, 77, 126, 85, 38, 238, 173, 23, 188, 100, 131, 226, 31, 9, 114, 106, 221, 42, 233, 139, 4, 241, 96, 211, 8, 98, 121, 147, 24, 217, 27, 87, 122, 125, 135, 148, 178, 71, 206, 57, 141, 35, 30, 246, 159, 16, 32, 15, 229, 20, 12, 223, 150, 101, 79, 56, 102, 111, 174, 236, 137, 143, 52, 225, 64, 224, 112, 168, 243, 130, 108, 202, 123, 146, 228, 75, 46, 153, 7, 192, 175, 151, 222, 59, 82, 90, 1, 65, 109, 44, 165, 84, 43, 36, 128, 196, 67, 80, 136, 86, 70, 234, 66, 185, 10, 164, 177, 116, 50, 107, 183, 215, 212, 60, 227, 133, 120, 142 };
/* Local function forwared declarations */
static void pios_rfm22_task(void *parameters);
static bool pios_rfm22_readStatus(struct pios_rfm22b_dev *rfm22b_dev);
static void pios_rfm22_setDatarate(struct pios_rfm22b_dev *rfm22b_dev);
static void rfm22_rxFailure(struct pios_rfm22b_dev *rfm22b_dev);
static void pios_rfm22_inject_event(struct pios_rfm22b_dev *rfm22b_dev, enum pios_radio_event event, bool inISR);
static enum pios_radio_event rfm22_init(struct pios_rfm22b_dev *rfm22b_dev);
static enum pios_radio_event radio_setRxMode(struct pios_rfm22b_dev *rfm22b_dev);
static enum pios_radio_event radio_rxData(struct pios_rfm22b_dev *rfm22b_dev);
static enum pios_radio_event radio_receivePacket(struct pios_rfm22b_dev *rfm22b_dev, uint8_t *p, uint16_t rx_len);
static enum pios_radio_event radio_txStart(struct pios_rfm22b_dev *rfm22b_dev);
static enum pios_radio_event radio_txData(struct pios_rfm22b_dev *rfm22b_dev);
static enum pios_radio_event rfm22_txFailure(struct pios_rfm22b_dev *rfm22b_dev);
static enum pios_radio_event rfm22_process_state_transition(struct pios_rfm22b_dev *rfm22b_dev, enum pios_radio_event event);
static void rfm22_process_event(struct pios_rfm22b_dev *rfm22b_dev, enum pios_radio_event event);
static enum pios_radio_event rfm22_timeout(struct pios_rfm22b_dev *rfm22b_dev);
static enum pios_radio_event rfm22_error(struct pios_rfm22b_dev *rfm22b_dev);
static enum pios_radio_event rfm22_fatal_error(struct pios_rfm22b_dev *rfm22b_dev);
static void rfm22b_add_rx_status(struct pios_rfm22b_dev *rfm22b_dev, enum pios_rfm22b_rx_packet_status status);
static void rfm22_setNominalCarrierFrequency(struct pios_rfm22b_dev *rfm22b_dev, uint8_t init_chan);
static bool rfm22_setFreqHopChannel(struct pios_rfm22b_dev *rfm22b_dev, uint8_t channel);
static void rfm22_updatePairStatus(struct pios_rfm22b_dev *radio_dev);
static void rfm22_calculateLinkQuality(struct pios_rfm22b_dev *rfm22b_dev);
static bool rfm22_isConnected(struct pios_rfm22b_dev *rfm22b_dev);
static bool rfm22_isCoordinator(struct pios_rfm22b_dev *rfm22b_dev);
static uint32_t rfm22_destinationID(struct pios_rfm22b_dev *rfm22b_dev);
static bool rfm22_timeToSend(struct pios_rfm22b_dev *rfm22b_dev);
static void rfm22_synchronizeClock(struct pios_rfm22b_dev *rfm22b_dev);
static portTickType rfm22_coordinatorTime(struct pios_rfm22b_dev *rfm22b_dev, portTickType ticks);
static uint8_t rfm22_calcChannel(struct pios_rfm22b_dev *rfm22b_dev, uint8_t index);
static uint8_t rfm22_calcChannelFromClock(struct pios_rfm22b_dev *rfm22b_dev);
static bool rfm22_changeChannel(struct pios_rfm22b_dev *rfm22b_dev);
static void rfm22_clearLEDs();
/*
* Local
* function
* forwared
* declarations
* */
static void pios_rfm22_task(
void
*
parameters);
static bool pios_rfm22_readStatus(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static void pios_rfm22_setDatarate(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static void rfm22_rxFailure(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static void pios_rfm22_inject_event(
struct
pios_rfm22b_dev
*rfm22b_dev,
enum
pios_radio_event
event,
bool
inISR);
static enum pios_radio_event rfm22_init(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static enum pios_radio_event radio_setRxMode(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static enum pios_radio_event radio_rxData(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static enum pios_radio_event radio_receivePacket(
struct
pios_rfm22b_dev
*rfm22b_dev,
uint8_t
*
p,
uint16_t
rx_len);
static enum pios_radio_event radio_txStart(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static enum pios_radio_event radio_txData(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static enum pios_radio_event rfm22_txFailure(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static enum pios_radio_event rfm22_process_state_transition(
struct
pios_rfm22b_dev
*rfm22b_dev,
enum
pios_radio_event
event);
static void rfm22_process_event(
struct
pios_rfm22b_dev
*rfm22b_dev,
enum
pios_radio_event
event);
static enum pios_radio_event rfm22_timeout(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static enum pios_radio_event rfm22_error(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static enum pios_radio_event rfm22_fatal_error(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static void rfm22b_add_rx_status(
struct
pios_rfm22b_dev
*rfm22b_dev,
enum
pios_rfm22b_rx_packet_status
status);
static void rfm22_setNominalCarrierFrequency(
struct
pios_rfm22b_dev
*rfm22b_dev,
uint8_t
init_chan);
static bool rfm22_setFreqHopChannel(
struct
pios_rfm22b_dev
*rfm22b_dev,
uint8_t
channel);
static void rfm22_updatePairStatus(
struct
pios_rfm22b_dev
*
radio_dev);
static void rfm22_calculateLinkQuality(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static bool rfm22_isConnected(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static bool rfm22_isCoordinator(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static uint32_t rfm22_destinationID(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static bool rfm22_timeToSend(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static void rfm22_synchronizeClock(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static portTickType rfm22_coordinatorTime(
struct
pios_rfm22b_dev
*rfm22b_dev,
portTickType
ticks);
static uint8_t rfm22_calcChannel(
struct
pios_rfm22b_dev
*rfm22b_dev,
uint8_t
index);
static uint8_t rfm22_calcChannelFromClock(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static bool rfm22_changeChannel(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static void rfm22_clearLEDs();
// Utility functions.
static uint32_t pios_rfm22_time_difference_ms(portTickType start_time, portTickType end_time);
static struct pios_rfm22b_dev *pios_rfm22_alloc(void);
/*
* Utility
* functions. */
static uint32_t pios_rfm22_time_difference_ms(
portTickType
start_time,
portTickType
end_time);
static struct pios_rfm22b_dev *pios_rfm22_alloc(
void);
// SPI read/write functions
static void rfm22_assertCs(struct pios_rfm22b_dev *rfm22b_dev);
static void rfm22_deassertCs(struct pios_rfm22b_dev *rfm22b_dev);
static void rfm22_claimBus(struct pios_rfm22b_dev *rfm22b_dev);
static void rfm22_releaseBus(struct pios_rfm22b_dev *rfm22b_dev);
static void rfm22_write_claim(struct pios_rfm22b_dev *rfm22b_dev, uint8_t addr, uint8_t data);
static void rfm22_write(struct pios_rfm22b_dev *rfm22b_dev, uint8_t addr, uint8_t data);
static uint8_t rfm22_read(struct pios_rfm22b_dev *rfm22b_dev, uint8_t addr);
/*
* SPI
* read/write
* functions */
static void rfm22_assertCs(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static void rfm22_deassertCs(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static void rfm22_claimBus(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static void rfm22_releaseBus(
struct
pios_rfm22b_dev
*
rfm22b_dev);
static void rfm22_write_claim(
struct
pios_rfm22b_dev
*rfm22b_dev,
uint8_t
addr,
uint8_t
data);
static void rfm22_write(
struct
pios_rfm22b_dev
*rfm22b_dev,
uint8_t
addr,
uint8_t
data);
static uint8_t rfm22_read(
struct
pios_rfm22b_dev
*rfm22b_dev,
uint8_t
addr);
/* The state transition table */
/*
* The
* state
* transition
* table
* */
static const struct pios_rfm22b_transition rfm22b_transitions[RADIO_STATE_NUM_STATES] = {
// Initialization thread
[RADIO_STATE_UNINITIALIZED] = {
.entry_fn = 0,
.next_state = {
[RADIO_EVENT_INITIALIZE] = RADIO_STATE_INITIALIZING,
[RADIO_EVENT_ERROR] = RADIO_STATE_ERROR,
/*
* Initialization
* thread */
[
RADIO_STATE_UNINITIALIZED
]
= {
.
entry_fn
=
0,
.
next_state
={
[
RADIO_EVENT_INITIALIZE
]
=
RADIO_STATE_INITIALIZING,
[
RADIO_EVENT_ERROR
]
=
RADIO_STATE_ERROR,
},
},
},
[RADIO_STATE_INITIALIZING] = {
.entry_fn = rfm22_init,
.next_state = {
[RADIO_EVENT_INITIALIZED] = RADIO_STATE_RX_MODE,
[RADIO_EVENT_ERROR] = RADIO_STATE_ERROR,
[RADIO_EVENT_INITIALIZE] = RADIO_STATE_INITIALIZING,
[RADIO_EVENT_FATAL_ERROR] = RADIO_STATE_FATAL_ERROR,
[
RADIO_STATE_INITIALIZING
]
= {
.
entry_fn
=
rfm22_init,
.
next_state
={
[
RADIO_EVENT_INITIALIZED
]
=
RADIO_STATE_RX_MODE,
[
RADIO_EVENT_ERROR
]
=
RADIO_STATE_ERROR,
[
RADIO_EVENT_INITIALIZE
]
=
RADIO_STATE_INITIALIZING,
[
RADIO_EVENT_FATAL_ERROR
]
=
RADIO_STATE_FATAL_ERROR,
},
},
},
[RADIO_STATE_RX_MODE] = {
.entry_fn = radio_setRxMode,
.next_state = {
[RADIO_EVENT_INT_RECEIVED] = RADIO_STATE_RX_DATA,
[RADIO_EVENT_TX_START] = RADIO_STATE_TX_START,
[RADIO_EVENT_RX_MODE] = RADIO_STATE_RX_MODE,
[RADIO_EVENT_TIMEOUT] = RADIO_STATE_TIMEOUT,
[RADIO_EVENT_ERROR] = RADIO_STATE_ERROR,
[RADIO_EVENT_INITIALIZE] = RADIO_STATE_INITIALIZING,
[RADIO_EVENT_FATAL_ERROR] = RADIO_STATE_FATAL_ERROR,
[
RADIO_STATE_RX_MODE
]
= {
.
entry_fn
=
radio_setRxMode,
.
next_state
={
[
RADIO_EVENT_INT_RECEIVED
]
=
RADIO_STATE_RX_DATA,
[
RADIO_EVENT_TX_START
]
=
RADIO_STATE_TX_START,
[
RADIO_EVENT_RX_MODE
]
=
RADIO_STATE_RX_MODE,
[
RADIO_EVENT_TIMEOUT
]
=
RADIO_STATE_TIMEOUT,
[
RADIO_EVENT_ERROR
]
=
RADIO_STATE_ERROR,
[
RADIO_EVENT_INITIALIZE
]
=
RADIO_STATE_INITIALIZING,
[
RADIO_EVENT_FATAL_ERROR
]
=
RADIO_STATE_FATAL_ERROR,
},
},
},
[RADIO_STATE_RX_DATA] = {
.entry_fn = radio_rxData,
.next_state = {
[RADIO_EVENT_INT_RECEIVED] = RADIO_STATE_RX_DATA,
[RADIO_EVENT_TX_START] = RADIO_STATE_TX_START,
[RADIO_EVENT_RX_COMPLETE] = RADIO_STATE_TX_START,
[RADIO_EVENT_RX_MODE] = RADIO_STATE_RX_MODE,
[RADIO_EVENT_TIMEOUT] = RADIO_STATE_TIMEOUT,
[RADIO_EVENT_ERROR] = RADIO_STATE_ERROR,
[RADIO_EVENT_INITIALIZE] = RADIO_STATE_INITIALIZING,
[RADIO_EVENT_FATAL_ERROR] = RADIO_STATE_FATAL_ERROR,
[
RADIO_STATE_RX_DATA
]
= {
.
entry_fn
=
radio_rxData,
.
next_state
={
[
RADIO_EVENT_INT_RECEIVED
]
=
RADIO_STATE_RX_DATA,
[
RADIO_EVENT_TX_START
]
=
RADIO_STATE_TX_START,
[
RADIO_EVENT_RX_COMPLETE
]
=
RADIO_STATE_TX_START,
[
RADIO_EVENT_RX_MODE
]
=
RADIO_STATE_RX_MODE,
[
RADIO_EVENT_TIMEOUT
]
=
RADIO_STATE_TIMEOUT,
[
RADIO_EVENT_ERROR
]
=
RADIO_STATE_ERROR,
[
RADIO_EVENT_INITIALIZE
]
=
RADIO_STATE_INITIALIZING,
[
RADIO_EVENT_FATAL_ERROR
]
=
RADIO_STATE_FATAL_ERROR,
},
},
},
[RADIO_STATE_TX_START] = {
.entry_fn = radio_txStart,
.next_state = {
[RADIO_EVENT_INT_RECEIVED] = RADIO_STATE_TX_DATA,
[RADIO_EVENT_RX_MODE] = RADIO_STATE_RX_MODE,
[RADIO_EVENT_TIMEOUT] = RADIO_STATE_TIMEOUT,
[RADIO_EVENT_ERROR] = RADIO_STATE_ERROR,
[RADIO_EVENT_INITIALIZE] = RADIO_STATE_INITIALIZING,
[RADIO_EVENT_FATAL_ERROR] = RADIO_STATE_FATAL_ERROR,
[
RADIO_STATE_TX_START
]
= {
.
entry_fn
=
radio_txStart,
.
next_state
={
[
RADIO_EVENT_INT_RECEIVED
]
=
RADIO_STATE_TX_DATA,
[
RADIO_EVENT_RX_MODE
]
=
RADIO_STATE_RX_MODE,
[
RADIO_EVENT_TIMEOUT
]
=
RADIO_STATE_TIMEOUT,
[
RADIO_EVENT_ERROR
]
=
RADIO_STATE_ERROR,
[
RADIO_EVENT_INITIALIZE
]
=
RADIO_STATE_INITIALIZING,
[
RADIO_EVENT_FATAL_ERROR
]
=
RADIO_STATE_FATAL_ERROR,
},
},
},
[RADIO_STATE_TX_DATA] = {
.entry_fn = radio_txData,
.next_state = {
[RADIO_EVENT_INT_RECEIVED] = RADIO_STATE_TX_DATA,
[RADIO_EVENT_RX_MODE] = RADIO_STATE_RX_MODE,
[RADIO_EVENT_TIMEOUT] = RADIO_STATE_TIMEOUT,
[RADIO_EVENT_ERROR] = RADIO_STATE_ERROR,
[RADIO_EVENT_INITIALIZE] = RADIO_STATE_INITIALIZING,
[RADIO_EVENT_FATAL_ERROR] = RADIO_STATE_FATAL_ERROR,
[
RADIO_STATE_TX_DATA
]
= {
.
entry_fn
=
radio_txData,
.
next_state
={
[
RADIO_EVENT_INT_RECEIVED
]
=
RADIO_STATE_TX_DATA,
[
RADIO_EVENT_RX_MODE
]
=
RADIO_STATE_RX_MODE,
[
RADIO_EVENT_TIMEOUT
]
=
RADIO_STATE_TIMEOUT,
[
RADIO_EVENT_ERROR
]
=
RADIO_STATE_ERROR,
[
RADIO_EVENT_INITIALIZE
]
=
RADIO_STATE_INITIALIZING,
[
RADIO_EVENT_FATAL_ERROR
]
=
RADIO_STATE_FATAL_ERROR,
},
},
},
[RADIO_STATE_TX_FAILURE] = {
.entry_fn = rfm22_txFailure,
.next_state = {
[RADIO_EVENT_TX_START] = RADIO_STATE_TX_START,
[RADIO_EVENT_TIMEOUT] = RADIO_STATE_TIMEOUT,
[RADIO_EVENT_ERROR] = RADIO_STATE_ERROR,
[RADIO_EVENT_INITIALIZE] = RADIO_STATE_INITIALIZING,
[RADIO_EVENT_FATAL_ERROR] = RADIO_STATE_FATAL_ERROR,
[
RADIO_STATE_TX_FAILURE
]
= {
.
entry_fn
=
rfm22_txFailure,
.
next_state
={
[
RADIO_EVENT_TX_START
]
=
RADIO_STATE_TX_START,
[
RADIO_EVENT_TIMEOUT
]
=
RADIO_STATE_TIMEOUT,
[
RADIO_EVENT_ERROR
]
=
RADIO_STATE_ERROR,
[
RADIO_EVENT_INITIALIZE
]
=
RADIO_STATE_INITIALIZING,
[
RADIO_EVENT_FATAL_ERROR
]
=
RADIO_STATE_FATAL_ERROR,
},
},
},
[RADIO_STATE_TIMEOUT] = {
.entry_fn = rfm22_timeout,
.next_state = {
[RADIO_EVENT_TX_START] = RADIO_STATE_TX_START,
[RADIO_EVENT_RX_MODE] = RADIO_STATE_RX_MODE,
[RADIO_EVENT_ERROR] = RADIO_STATE_ERROR,
[RADIO_EVENT_INITIALIZE] = RADIO_STATE_INITIALIZING,
[RADIO_EVENT_FATAL_ERROR] = RADIO_STATE_FATAL_ERROR,
[
RADIO_STATE_TIMEOUT
]
= {
.
entry_fn
=
rfm22_timeout,
.
next_state
={
[
RADIO_EVENT_TX_START
]
=
RADIO_STATE_TX_START,
[
RADIO_EVENT_RX_MODE
]
=
RADIO_STATE_RX_MODE,
[
RADIO_EVENT_ERROR
]
=
RADIO_STATE_ERROR,
[
RADIO_EVENT_INITIALIZE
]
=
RADIO_STATE_INITIALIZING,
[
RADIO_EVENT_FATAL_ERROR
]
=
RADIO_STATE_FATAL_ERROR,
},
},
},
[RADIO_STATE_ERROR] = {
.entry_fn = rfm22_error,
.next_state = {
[RADIO_EVENT_INITIALIZE] = RADIO_STATE_INITIALIZING,
[RADIO_EVENT_FATAL_ERROR] = RADIO_STATE_FATAL_ERROR,
[
RADIO_STATE_ERROR
]
= {
.
entry_fn
=
rfm22_error,
.
next_state
={
[
RADIO_EVENT_INITIALIZE
]
=
RADIO_STATE_INITIALIZING,
[
RADIO_EVENT_FATAL_ERROR
]
=
RADIO_STATE_FATAL_ERROR,
},
},
[
RADIO_STATE_FATAL_ERROR
]
= {
.
entry_fn
=
rfm22_fatal_error,
.
next_state
=
{},
},
},
[RADIO_STATE_FATAL_ERROR] = {
.entry_fn = rfm22_fatal_error,
.next_state = {},
},
};
// xtal 10 ppm, 434MHz
/*
* xtal
* 10
* ppm,
* 434MHz */
static const uint32_t data_rate[] = {
9600, // 96 kbps, 433 HMz, 30 khz freq dev
19200, // 19.2 kbps, 433 MHz, 45 khz freq dev
32000, // 32 kbps, 433 MHz, 45 khz freq dev
57600, // 57.6 kbps, 433 MHz, 45 khz freq dev
64000, // 64 kbps, 433 MHz, 45 khz freq dev
100000, // 100 kbps, 433 MHz, 60 khz freq dev
128000, // 128 kbps, 433 MHz, 90 khz freq dev
192000, // 192 kbps, 433 MHz, 128 khz freq dev
256000, // 256 kbps, 433 MHz, 150 khz freq dev
9600, /*
* 96
* kbps,
* 433
* HMz,
* 30
* khz
* freq
* dev */
19200, /*
* 19.2
* kbps,
* 433
* MHz,
* 45
* khz
* freq
* dev */
32000, /*
* 32
* kbps,
* 433
* MHz,
* 45
* khz
* freq
* dev */
57600, /*
* 57.6
* kbps,
* 433
* MHz,
* 45
* khz
* freq
* dev */
64000, /*
* 64
* kbps,
* 433
* MHz,
* 45
* khz
* freq
* dev */
100000, /*
* 100
* kbps,
* 433
* MHz,
* 60
* khz
* freq
* dev */
128000, /*
* 128
* kbps,
* 433
* MHz,
* 90
* khz
* freq
* dev */
192000, /*
* 192
* kbps,
* 433
* MHz,
* 128
* khz
* freq
* dev */
256000, /*
* 256
* kbps,
* 433
* MHz,
* 150
* khz
* freq
* dev */
};
static const uint8_t reg_1C[] = { 0x01, 0x05, 0x06, 0x95, 0x95, 0x81, 0x88, 0x8B, 0x8D }; // rfm22_if_filter_bandwidth
static const uint8_t reg_1D[] = { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 }; // rfm22_afc_loop_gearshift_override
static const uint8_t reg_1E[] = { 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x02 }; // rfm22_afc_timing_control
static const uint8_t reg_1F[] = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 }; // rfm22_clk_recovery_gearshift_override
static const uint8_t reg_20[] = { 0xA1, 0xD0, 0x7D, 0x68, 0x5E, 0x78, 0x5E, 0x3F, 0x2F }; // rfm22_clk_recovery_oversampling_ratio
static const uint8_t reg_21[] = { 0x20, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02 }; // rfm22_clk_recovery_offset2
static const uint8_t reg_22[] = { 0x4E, 0x9D, 0x06, 0x3A, 0x5D, 0x11, 0x5D, 0x0C, 0xBB }; // rfm22_clk_recovery_offset1
static const uint8_t reg_23[] = { 0xA5, 0x49, 0x25, 0x93, 0x86, 0x11, 0x86, 0x4A, 0x0D }; // rfm22_clk_recovery_offset0
static const uint8_t reg_24[] = { 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x06, 0x07 }; // rfm22_clk_recovery_timing_loop_gain1
static const uint8_t reg_25[] = { 0x34, 0x88, 0x77, 0x29, 0xE2, 0x90, 0xE2, 0x1A, 0xFF }; // rfm22_clk_recovery_timing_loop_gain0
static const uint8_t reg_2A[] = { 0x1E, 0x24, 0x28, 0x3C, 0x3C, 0x50, 0x50, 0x50, 0x50 }; // rfm22_afc_limiter .. AFC_pull_in_range = <20>AFCLimiter[7:0] x (hbsel+1) x 625 Hz
static const uint8_t reg_58[] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0xC0, 0xC0, 0xC0, 0xED }; // rfm22_cpcuu
static const uint8_t reg_69[] = { 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60 }; // rfm22_agc_override1
static const uint8_t reg_6E[] = { 0x4E, 0x9D, 0x08, 0x0E, 0x10, 0x19, 0x20, 0x31, 0x41 }; // rfm22_tx_data_rate1
static const uint8_t reg_6F[] = { 0xA5, 0x49, 0x31, 0xBF, 0x62, 0x9A, 0xC5, 0x27, 0x89 }; // rfm22_tx_data_rate0
static const uint8_t reg_70[] = { 0x2C, 0x2C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C }; // rfm22_modulation_mode_control1
static const uint8_t reg_71[] = { 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23 }; // rfm22_modulation_mode_control2
static const uint8_t reg_72[] = { 0x30, 0x48, 0x48, 0x48, 0x48, 0x60, 0x90, 0xCD, 0x0F }; // rfm22_frequency_deviation
static const uint8_t reg_1C[] = { 0x01, 0x05, 0x06, 0x95, 0x95, 0x81, 0x88, 0x8B, 0x8D }; /*
* rfm22_if_filter_bandwidth */
static const uint8_t reg_1D[] = { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 }; /*
* rfm22_afc_loop_gearshift_override */
static const uint8_t reg_1E[] = { 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x02 }; /*
* rfm22_afc_timing_control */
static const uint8_t reg_1F[] = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 }; /*
* rfm22_clk_recovery_gearshift_override */
static const uint8_t reg_20[] = { 0xA1, 0xD0, 0x7D, 0x68, 0x5E, 0x78, 0x5E, 0x3F, 0x2F }; /*
* rfm22_clk_recovery_oversampling_ratio */
static const uint8_t reg_21[] = { 0x20, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02 }; /*
* rfm22_clk_recovery_offset2 */
static const uint8_t reg_22[] = { 0x4E, 0x9D, 0x06, 0x3A, 0x5D, 0x11, 0x5D, 0x0C, 0xBB }; /*
* rfm22_clk_recovery_offset1 */
static const uint8_t reg_23[] = { 0xA5, 0x49, 0x25, 0x93, 0x86, 0x11, 0x86, 0x4A, 0x0D }; /*
* rfm22_clk_recovery_offset0 */
static const uint8_t reg_24[] = { 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x06, 0x07 }; /*
* rfm22_clk_recovery_timing_loop_gain1 */
static const uint8_t reg_25[] = { 0x34, 0x88, 0x77, 0x29, 0xE2, 0x90, 0xE2, 0x1A, 0xFF }; /*
* rfm22_clk_recovery_timing_loop_gain0 */
static const uint8_t reg_2A[] = { 0x1E, 0x24, 0x28, 0x3C, 0x3C, 0x50, 0x50, 0x50, 0x50 }; /*
* rfm22_afc_limiter
* ..
* AFC_pull_in_range
* =
* <EFBFBD>AFCLimiter[7:0]
* x
* (hbsel+1)
* x
* 625
* Hz */
static const uint8_t reg_58[] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0xC0, 0xC0, 0xC0, 0xED }; /*
* rfm22_cpcuu */
static const uint8_t reg_69[] = { 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60 }; /*
* rfm22_agc_override1 */
static const uint8_t reg_6E[] = { 0x4E, 0x9D, 0x08, 0x0E, 0x10, 0x19, 0x20, 0x31, 0x41 }; /*
* rfm22_tx_data_rate1 */
static const uint8_t reg_6F[] = { 0xA5, 0x49, 0x31, 0xBF, 0x62, 0x9A, 0xC5, 0x27, 0x89 }; /*
* rfm22_tx_data_rate0 */
static const uint8_t reg_70[] = { 0x2C, 0x2C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C }; /*
* rfm22_modulation_mode_control1 */
static const uint8_t reg_71[] = { 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23 }; /*
* rfm22_modulation_mode_control2 */
static const uint8_t reg_72[] = { 0x30, 0x48, 0x48, 0x48, 0x48, 0x60, 0x90, 0xCD, 0x0F }; /*
* rfm22_frequency_deviation */
static const uint8_t packet_time[] = { 80, 40, 25, 15, 13, 10, 8, 6, 5 };
static const uint8_t packet_time_ppm[] = { 26, 25, 25, 15, 13, 10, 8, 6, 5 };
static const uint8_t num_channels[] = { 4, 4, 4, 6, 8, 8, 10, 12, 16 };
static struct pios_rfm22b_dev *g_rfm22b_dev = NULL;
/*****************************************************************************
* External Interface Functions
*
* External
* Interface
* Functions
*****************************************************************************/
/**
* Initialise an RFM22B device
*
* @param[out] rfm22b_id A pointer to store the device ID in.
* @param[in] spi_id The SPI bus index.
* @param[in] slave_num The SPI bus slave number.
* @param[in] cfg The device configuration.
* Initialise
* an
* RFM22B
* device
*
*
* @param[out]
* rfm22b_id
*
* A
* pointer
* to
* store
* the
* device
* ID
* in.
*
* @param[in]
* spi_id
*
* The
* SPI
* bus
* index.
*
* @param[in]
* slave_num
*
* The
* SPI
* bus
* slave
* number.
*
* @param[in]
* cfg
*
* The
* device
* configuration.
*/
int32_t PIOS_RFM22B_Init(uint32_t *rfm22b_id, uint32_t spi_id, uint32_t slave_num, const struct pios_rfm22b_cfg *cfg)
int32_t PIOS_RFM22B_Init(
uint32_t
*
rfm22b_id,
uint32_t
spi_id,
uint32_t
slave_num,
const
struct
pios_rfm22b_cfg
*cfg)
{
PIOS_DEBUG_Assert(rfm22b_id);
PIOS_DEBUG_Assert(cfg);
// Allocate the device structure.
/*
* Allocate
* the
* device
* structure. */
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)pios_rfm22_alloc();
if (!rfm22b_dev) {
return -1;
}
*rfm22b_id = (uint32_t)rfm22b_dev;
g_rfm22b_dev = rfm22b_dev;
// Store the SPI handle
/*
* Store
* the
* SPI
* handle */
rfm22b_dev->slave_num = slave_num;
rfm22b_dev->spi_id = spi_id;
// Initialize our configuration parameters
/*
* Initialize
* our
* configuration
* parameters */
rfm22b_dev->datarate = RFM22B_DEFAULT_RX_DATARATE;
rfm22b_dev->tx_power = RFM22B_DEFAULT_TX_POWER;
rfm22b_dev->coordinator = false;
rfm22b_dev->coordinatorID = 0;
// Initialize the com callbacks.
/*
* Initialize
* the
* com
* callbacks. */
rfm22b_dev->rx_in_cb = NULL;
rfm22b_dev->tx_out_cb = NULL;
// Initialzie the PPM callback.
/*
* Initialzie
* the
* PPM
* callback. */
rfm22b_dev->ppm_callback = NULL;
// Initialize the stats.
/*
* Initialize
* the
* stats. */
rfm22b_dev->stats.packets_per_sec = 0;
rfm22b_dev->stats.rx_good = 0;
rfm22b_dev->stats.rx_corrected = 0;
@ -404,103 +1513,301 @@ int32_t PIOS_RFM22B_Init(uint32_t *rfm22b_id, uint32_t spi_id, uint32_t slave_nu
rfm22b_dev->stats.rx_seq = 0;
rfm22b_dev->stats.tx_failure = 0;
// Initialize the channels.
/*
* Initialize
* the
* channels. */
PIOS_RFM22B_SetChannelConfig(*rfm22b_id, RFM22B_DEFAULT_RX_DATARATE, RFM22B_DEFAULT_MIN_CHANNEL,
RFM22B_DEFAULT_MAX_CHANNEL, RFM22B_DEFAULT_CHANNEL_SET, false, false, false, false);
// Create the event queue
/*
* Create
* the
* event
* queue */
rfm22b_dev->eventQueue = xQueueCreate(EVENT_QUEUE_SIZE, sizeof(enum pios_radio_event));
// Bind the configuration to the device instance
/*
* Bind
* the
* configuration
* to
* the
* device
* instance */
rfm22b_dev->cfg = *cfg;
// Create a semaphore to know if an ISR needs responding to
/*
* Create
* a
* semaphore
* to
* know
* if
* an
* ISR
* needs
* responding
* to */
vSemaphoreCreateBinary(rfm22b_dev->isrPending);
// Create our (hopefully) unique 32 bit id from the processor serial number.
/*
* Create
* our
* (hopefully)
* unique
* 32
* bit
* id
* from
* the
* processor
* serial
* number. */
uint8_t crcs[] = { 0, 0, 0, 0 };
{
char serial_no_str[33];
PIOS_SYS_SerialNumberGet(serial_no_str);
// Create a 32 bit value using 4 8 bit CRC values.
for (uint8_t i = 0; serial_no_str[i] != 0; ++i) {
crcs[i % 4] = PIOS_CRC_updateByte(crcs[i % 4], serial_no_str[i]);
PIOS_SYS_SerialNumberGet(
serial_no_str);
/*
* Create
* a
* 32
* bit
* value
* using
* 4
* 8
* bit
* CRC
* values. */
for (
uint8_t
i
=
0;
serial_no_str
[
i
]
!=
0;
++
i) {
crcs
[
i
%
4
]
=
PIOS_CRC_updateByte(
crcs
[
i
%
4
],
serial_no_str
[
i
]);
}
}
rfm22b_dev->deviceID = crcs[0] | crcs[1] << 8 | crcs[2] << 16 | crcs[3] << 24;
DEBUG_PRINTF(2, "RF device ID: %x\n\r", rfm22b_dev->deviceID);
// Initialize the external interrupt.
/*
* Initialize
* the
* external
* interrupt. */
PIOS_EXTI_Init(cfg->exti_cfg);
// Register the watchdog timer for the radio driver task
/*
* Register
* the
* watchdog
* timer
* for
* the
* radio
* driver
* task */
#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_RFM22B)
PIOS_WDG_RegisterFlag(PIOS_WDG_RFM22B);
PIOS_WDG_RegisterFlag(
PIOS_WDG_RFM22B);
#endif /* PIOS_WDG_RFM22B */
// Initialize the ECC library.
/*
* Initialize
* the
* ECC
* library. */
initialize_ecc();
// Set the state to initializing.
/*
* Set
* the
* state
* to
* initializing. */
rfm22b_dev->state = RADIO_STATE_UNINITIALIZED;
// Initialize the radio device.
/*
* Initialize
* the
* radio
* device. */
pios_rfm22_inject_event(rfm22b_dev, RADIO_EVENT_INITIALIZE, false);
// Start the driver task. This task controls the radio state machine and removed all of the IO from the IRQ handler.
xTaskCreate(pios_rfm22_task, (signed char *)"PIOS_RFM22B_Task", STACK_SIZE_BYTES, (void *)rfm22b_dev, TASK_PRIORITY, &(rfm22b_dev->taskHandle));
/*
* Start
* the
* driver
* task.
*
* This
* task
* controls
* the
* radio
* state
* machine
* and
* removed
* all
* of
* the
* IO
* from
* the
* IRQ
* handler. */
xTaskCreate(pios_rfm22_task, (signedchar *)"PIOS_RFM22B_Task", STACK_SIZE_BYTES, (void *)rfm22b_dev, TASK_PRIORITY, &(rfm22b_dev->taskHandle));
return 0;
}
/**
* Re-initialize the modem after a configuration change.
*
* @param[in] rbm22b_id The RFM22B device ID.
* Re-initialize
* the
* modem
* after
* a
* configuration
* change.
*
*
* @param[in]
* rbm22b_id
*
* The
* RFM22B
* device
* ID.
*/
void PIOS_RFM22B_Reinit(uint32_t rfm22b_id)
void PIOS_RFM22B_Reinit(uint32_trfm22b_id)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
if (PIOS_RFM22B_Validate(rfm22b_dev)) {
pios_rfm22_inject_event(rfm22b_dev, RADIO_EVENT_INITIALIZE, false);
}
}
/**
* The RFM22B external interrupt routine.
*
* The
* RFM22B
* external
* interrupt
* routine.
*/
bool PIOS_RFM22_EXT_Int(void)
bool PIOS_RFM22_EXT_Int(void)
{
if (!PIOS_RFM22B_Validate(g_rfm22b_dev)) {
return false;
}
// Inject an interrupt event into the state machine.
/*
* Inject
* an
* interrupt
* event
* into
* the
* state
* machine. */
pios_rfm22_inject_event(g_rfm22b_dev, RADIO_EVENT_INT_RECEIVED, true);
return false;
}
/**
* Returns the unique device ID for the RFM22B device.
*
* @param[in] rfm22b_id The RFM22B device index.
* @return The unique device ID
* Returns
* the
* unique
* device
* ID
* for
* the
* RFM22B
* device.
*
*
* @param[in]
* rfm22b_id
* The
* RFM22B
* device
* index.
*
* @return
* The
* unique
* device
* ID
*/
uint32_t PIOS_RFM22B_DeviceID(uint32_t rfm22b_id)
uint32_t PIOS_RFM22B_DeviceID(uint32_trfm22b_id)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
if (PIOS_RFM22B_Validate(rfm22b_dev)) {
return rfm22b_dev->deviceID;
}
return 0;
}
/**
* Are we connected to the remote modem?
*
* @param[in] rfm22b_dev The device structure
* Are
* we
* connected
* to
* the
* remote
* modem?
*
*
* @param[in]
* rfm22b_dev
*
* The
* device
* structure
*/
static bool rfm22_isConnected(struct pios_rfm22b_dev *rfm22b_dev)
{
@ -508,59 +1815,241 @@ static bool rfm22_isConnected(struct pios_rfm22b_dev *rfm22b_dev)
}
/**
* Returns true if the modem is not actively sending or receiving a packet.
*
* @param[in] rfm22b_id The RFM22B device index.
* @return True if the modem is not actively sending or receiving a packet.
* Returns
* true
* if
* the
* modem
* is
* not
* actively
* sending
* or
* receiving
* a
* packet.
*
*
* @param[in]
* rfm22b_id
* The
* RFM22B
* device
* index.
*
* @return
* True
* if
* the
* modem
* is
* not
* actively
* sending
* or
* receiving
* a
* packet.
*/
bool PIOS_RFM22B_InRxWait(uint32_t rfm22b_id)
bool PIOS_RFM22B_InRxWait(uint32_trfm22b_id)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
if (PIOS_RFM22B_Validate(rfm22b_dev)) {
return (rfm22b_dev->rfm22b_state == RFM22B_STATE_RX_WAIT) || (rfm22b_dev->rfm22b_state == RFM22B_STATE_TRANSITION);
}
return false;
}
/**
* Sets the radio device transmit power.
*
* @param[in] rfm22b_id The RFM22B device index.
* @param[in] tx_pwr The transmit power.
* Sets
* the
* radio
* device
* transmit
* power.
*
*
* @param[in]
* rfm22b_id
* The
* RFM22B
* device
* index.
*
* @param[in]
* tx_pwr
* The
* transmit
* power.
*/
void PIOS_RFM22B_SetTxPower(uint32_t rfm22b_id, enum rfm22b_tx_power tx_pwr)
void PIOS_RFM22B_SetTxPower(
uint32_t
rfm22b_id,
enum
rfm22b_tx_power
tx_pwr)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
if (!PIOS_RFM22B_Validate(rfm22b_dev)) {
return;
}
rfm22b_dev->tx_power = tx_pwr;
}
/**
* Sets the range and number of channels to use for the radio.
* The channels are 0 to 255 divided across the 430-440 MHz range.
* The number of channels configured will be spread across the selected channel range.
* The channel spacing is 10MHz / 250 = 40kHz
*
* @param[in] rfm22b_id The RFM22B device index.
* @param[in] datarate The desired datarate.
* @param[in] min_chan The minimum channel.
* @param[in] max_chan The maximum channel.
* @param[in] chan_set The "seed" for selecting a channel sequence.
* @param[in] coordinator Is this modem an coordinator.
* @param[in] ppm_mode Should this modem send/receive ppm packets?
* @param[in] oneway Only the coordinator can send packets if true.
* Sets
* the
* range
* and
* number
* of
* channels
* to
* use
* for
* the
* radio.
*
* The
* channels
* are
* 0
* to
* 255
* divided
* across
* the
* 430-440
* MHz
* range.
*
* The
* number
* of
* channels
* configured
* will
* be
* spread
* across
* the
* selected
* channel
* range.
*
* The
* channel
* spacing
* is
* 10MHz
* /
* 250
* =
* 40kHz
*
*
* @param[in]
* rfm22b_id
*
* The
* RFM22B
* device
* index.
*
* @param[in]
* datarate
*
* The
* desired
* datarate.
*
* @param[in]
* min_chan
*
* The
* minimum
* channel.
*
* @param[in]
* max_chan
*
* The
* maximum
* channel.
*
* @param[in]
* chan_set
*
* The
* "seed"
* for
* selecting
* a
* channel
* sequence.
*
* @param[in]
* coordinator
* Is
* this
* modem
* an
* coordinator.
*
* @param[in]
* ppm_mode
* Should
* this
* modem
* send/receive
* ppm
* packets?
*
* @param[in]
* oneway
* Only
* the
* coordinator
* can
* send
* packets
* if
* true.
*/
void PIOS_RFM22B_SetChannelConfig(uint32_t rfm22b_id, enum rfm22b_datarate datarate, uint8_t min_chan, uint8_t max_chan, uint8_t chan_set, bool coordinator, bool oneway, bool ppm_mode, bool ppm_only)
void PIOS_RFM22B_SetChannelConfig(
uint32_t
rfm22b_id,
enum
rfm22b_datarate
datarate,
uint8_t
min_chan,
uint8_t
max_chan,
uint8_t
chan_set,
bool
coordinator,
bool
oneway,
bool
ppm_mode,
bool
ppm_only)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
if (!PIOS_RFM22B_Validate(rfm22b_dev)) {
return;
}
ppm_mode = ppm_mode || ppm_only;
rfm22b_dev->coordinator = coordinator;
rfm22b_dev->ppm_send_mode = ppm_mode && coordinator;
@ -568,6 +2057,7 @@ void PIOS_RFM22B_SetChannelConfig(uint32_t rfm22b_id, enum rfm22b_datarate datar
if (ppm_mode && (datarate <= RFM22B_PPM_ONLY_DATARATE)) {
ppm_only = true;
}
rfm22b_dev->ppm_only_mode = ppm_only;
if (ppm_only) {
rfm22b_dev->one_way_link = true;
@ -577,21 +2067,53 @@ void PIOS_RFM22B_SetChannelConfig(uint32_t rfm22b_id, enum rfm22b_datarate datar
rfm22b_dev->one_way_link = oneway;
rfm22b_dev->datarate = datarate;
}
rfm22b_dev->packet_time = (ppm_mode ? packet_time_ppm[datarate] : packet_time[datarate]);
// Find the first N channels that meet the min/max criteria out of the random channel list.
/*
* Find
* the
* first
* N
* channels
* that
* meet
* the
* min/max
* criteria
* out
* of
* the
* random
* channel
* list. */
uint8_t num_found = 0;
for (uint16_t i = 0; (i < RFM22B_NUM_CHANNELS) && (num_found < num_channels[datarate]); ++i) {
uint8_t idx = (i + chan_set) % RFM22B_NUM_CHANNELS;
uint8_t chan = channel_list[idx];
if ((chan >= min_chan) && (chan <= max_chan)) {
rfm22b_dev->channels[num_found++] = chan;
}
}
// Calculate the maximum packet length from the datarate.
/*
* Calculate
* the
* maximum
* packet
* length
* from
* the
* datarate. */
float bytes_per_period = (float)data_rate[datarate] * (float)(rfm22b_dev->packet_time - 2) / 9000;
rfm22b_dev->max_packet_len = bytes_per_period - TX_PREAMBLE_NIBBLES / 2 - SYNC_BYTES - HEADER_BYTES - LENGTH_BYTES;
if (rfm22b_dev->max_packet_len > RFM22B_MAX_PACKET_LEN) {
rfm22b_dev->max_packet_len = RFM22B_MAX_PACKET_LEN;
@ -599,12 +2121,43 @@ void PIOS_RFM22B_SetChannelConfig(uint32_t rfm22b_id, enum rfm22b_datarate datar
}
/**
* Set a modem to be a coordinator or not.
*
* @param[in] rfm22b_id The RFM22B device index.
* @param[in] coordinator If true, this modem will be configured as a coordinator.
* Set
* a
* modem
* to
* be
* a
* coordinator
* or
* not.
*
*
* @param[in]
* rfm22b_id
* The
* RFM22B
* device
* index.
*
* @param[in]
* coordinator
* If
* true,
* this
* modem
* will
* be
* configured
* as
* a
* coordinator.
*/
extern void PIOS_RFM22B_SetCoordinator(uint32_t rfm22b_id, bool coordinator)
extern void PIOS_RFM22B_SetCoordinator(
uint32_t
rfm22b_id,
bool
coordinator)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
@ -614,12 +2167,32 @@ extern void PIOS_RFM22B_SetCoordinator(uint32_t rfm22b_id, bool coordinator)
}
/**
* Sets the device coordinator ID.
*
* @param[in] rfm22b_id The RFM22B device index.
* @param[in] coord_id The coordinator ID.
* Sets
* the
* device
* coordinator
* ID.
*
*
* @param[in]
* rfm22b_id
* The
* RFM22B
* device
* index.
*
* @param[in]
* coord_id
* The
* coordinator
* ID.
*/
void PIOS_RFM22B_SetCoordinatorID(uint32_t rfm22b_id, uint32_t coord_id)
void PIOS_RFM22B_SetCoordinatorID(
uint32_t
rfm22b_id,
uint32_t
coord_id)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
@ -629,12 +2202,39 @@ void PIOS_RFM22B_SetCoordinatorID(uint32_t rfm22b_id, uint32_t coord_id)
}
/**
* Returns the device statistics RFM22B device.
*
* @param[in] rfm22b_id The RFM22B device index.
* @param[out] stats The stats are returned in this structure
* Returns
* the
* device
* statistics
* RFM22B
* device.
*
*
* @param[in]
* rfm22b_id
* The
* RFM22B
* device
* index.
*
* @param[out]
* stats
* The
* stats
* are
* returned
* in
* this
* structure
*/
void PIOS_RFM22B_GetStats(uint32_t rfm22b_id, struct rfm22b_stats *stats)
void PIOS_RFM22B_GetStats(
uint32_t
rfm22b_id,
struct
rfm22b_stats
*
stats)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
@ -642,22 +2242,98 @@ void PIOS_RFM22B_GetStats(uint32_t rfm22b_id, struct rfm22b_stats *stats)
return;
}
// Calculate the current link quality
/*
* Calculate
* the
* current
* link
* quality */
rfm22_calculateLinkQuality(rfm22b_dev);
// Return the stats.
/*
* Return
* the
* stats. */
*stats = rfm22b_dev->stats;
}
/**
* Get the stats of the oter radio devices that are in range.
*
* @param[out] device_ids A pointer to the array to store the device IDs.
* @param[out] RSSIs A pointer to the array to store the RSSI values in.
* @param[in] mx_pairs The length of the pdevice_ids and RSSIs arrays.
* @return The number of pair stats returned.
* Get
* the
* stats
* of
* the
* oter
* radio
* devices
* that
* are
* in
* range.
*
*
* @param[out]
* device_ids
*
* A
* pointer
* to
* the
* array
* to
* store
* the
* device
* IDs.
*
* @param[out]
* RSSIs
*
* A
* pointer
* to
* the
* array
* to
* store
* the
* RSSI
* values
* in.
*
* @param[in]
* mx_pairs
*
* The
* length
* of
* the
* pdevice_ids
* and
* RSSIs
* arrays.
*
* @return
*
* The
* number
* of
* pair
* stats
* returned.
*/
uint8_t PIOS_RFM2B_GetPairStats(uint32_t rfm22b_id, uint32_t *device_ids, int8_t *RSSIs, uint8_t max_pairs)
uint8_t PIOS_RFM2B_GetPairStats(
uint32_t
rfm22b_id,
uint32_t
*
device_ids,
int8_t
*
RSSIs,
uint8_t
max_pairs)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
@ -665,99 +2341,240 @@ uint8_t PIOS_RFM2B_GetPairStats(uint32_t rfm22b_id, uint32_t *device_ids, int8_t
return 0;
}
uint8_t mp = (max_pairs >= OPLINKSTATUS_PAIRIDS_NUMELEM) ? max_pairs : OPLINKSTATUS_PAIRIDS_NUMELEM;
for (uint8_t i = 0; i < mp; ++i) {
device_ids[i] = rfm22b_dev->pair_stats[i].pairID;
RSSIs[i] = rfm22b_dev->pair_stats[i].rssi;
}
return mp;
}
/**
* Check the radio device for a valid connection
*
* @param[in] rfm22b_id The rfm22b device.
* @return true if there is a valid connection to paired radio, false otherwise.
* Check
* the
* radio
* device
* for
* a
* valid
* connection
*
*
* @param[in]
* rfm22b_id
*
* The
* rfm22b
* device.
*
* @return
* true
* if
* there
* is
* a
* valid
* connection
* to
* paired
* radio,
* false
* otherwise.
*/
bool PIOS_RFM22B_LinkStatus(uint32_t rfm22b_id)
bool PIOS_RFM22B_LinkStatus(uint32_trfm22b_id)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
if (!PIOS_RFM22B_Validate(rfm22b_dev)) {
return false;
}
return rfm22b_dev->stats.link_quality > RFM22B_LINK_QUALITY_THRESHOLD;
}
/**
* Put the RFM22B device into receive mode.
*
* @param[in] rfm22b_id The rfm22b device.
* @param[in] p The packet to receive into.
* @return true if Rx mode was entered sucessfully.
* Put
* the
* RFM22B
* device
* into
* receive
* mode.
*
*
* @param[in]
* rfm22b_id
*
* The
* rfm22b
* device.
*
* @param[in]
* p
*
* The
* packet
* to
* receive
* into.
*
* @return
* true
* if
* Rx
* mode
* was
* entered
* sucessfully.
*/
bool PIOS_RFM22B_ReceivePacket(uint32_t rfm22b_id, uint8_t *p)
bool PIOS_RFM22B_ReceivePacket(
uint32_t
rfm22b_id,
uint8_t
*
p)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
if (!PIOS_RFM22B_Validate(rfm22b_dev)) {
return false;
}
rfm22b_dev->rx_packet_handle = p;
// Claim the SPI bus.
/*
* Claim
* the
* SPI
* bus. */
rfm22_claimBus(rfm22b_dev);
// disable interrupts
/*
* disable
* interrupts */
rfm22_write(rfm22b_dev, RFM22_interrupt_enable1, 0x00);
rfm22_write(rfm22b_dev, RFM22_interrupt_enable2, 0x00);
// Switch to TUNE mode
/*
* Switch
* to
* TUNE
* mode */
rfm22_write(rfm22b_dev, RFM22_op_and_func_ctrl1, RFM22_opfc1_pllon);
#ifdef PIOS_RFM22B_DEBUG_ON_TELEM
D2_LED_OFF;
#endif // PIOS_RFM22B_DEBUG_ON_TELEM
#endif /*
* PIOS_RFM22B_DEBUG_ON_TELEM */
RX_LED_OFF;
TX_LED_OFF;
// empty the rx buffer
/*
* empty
* the
* rx
* buffer */
rfm22b_dev->rx_buffer_wr = 0;
// Clear the TX buffer.
/*
* Clear
* the
* TX
* buffer. */
rfm22b_dev->tx_data_rd = rfm22b_dev->tx_data_wr = 0;
// clear FIFOs
/*
* clear
* FIFOs */
rfm22_write(rfm22b_dev, RFM22_op_and_func_ctrl2, RFM22_opfc2_ffclrrx | RFM22_opfc2_ffclrtx);
rfm22_write(rfm22b_dev, RFM22_op_and_func_ctrl2, 0x00);
// enable RX interrupts
/*
* enable
* RX
* interrupts */
rfm22_write(rfm22b_dev, RFM22_interrupt_enable1, RFM22_ie1_encrcerror | RFM22_ie1_enpkvalid |
RFM22_ie1_enrxffafull | RFM22_ie1_enfferr);
rfm22_write(rfm22b_dev, RFM22_interrupt_enable2, RFM22_ie2_enpreainval | RFM22_ie2_enpreaval |
RFM22_ie2_enswdet);
// enable the receiver
/*
* enable
* the
* receiver */
rfm22_write(rfm22b_dev, RFM22_op_and_func_ctrl1, RFM22_opfc1_pllon | RFM22_opfc1_rxon);
// Release the SPI bus.
/*
* Release
* the
* SPI
* bus. */
rfm22_releaseBus(rfm22b_dev);
// Indicate that we're in RX wait mode.
/*
* Indicate
* that
* we're
* in
* RX
* wait
* mode. */
rfm22b_dev->rfm22b_state = RFM22B_STATE_RX_WAIT;
return true;
}
/**
* Transmit a packet via the RFM22B device.
*
* @param[in] rfm22b_id The rfm22b device.
* @param[in] p The packet to transmit.
* @return true if there if the packet was queued for transmission.
* Transmit
* a
* packet
* via
* the
* RFM22B
* device.
*
*
* @param[in]
* rfm22b_id
*
* The
* rfm22b
* device.
*
* @param[in]
* p
*
* The
* packet
* to
* transmit.
*
* @return
* true
* if
* there
* if
* the
* packet
* was
* queued
* for
* transmission.
*/
bool PIOS_RFM22B_TransmitPacket(uint32_t rfm22b_id, uint8_t *p, uint8_t len)
bool PIOS_RFM22B_TransmitPacket(
uint32_t
rfm22b_id,
uint8_t
*
p,
uint8_t
len)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
@ -772,63 +2589,147 @@ bool PIOS_RFM22B_TransmitPacket(uint32_t rfm22b_id, uint8_t *p, uint8_t len)
rfm22b_dev->packet_start_ticks = 1;
}
// Claim the SPI bus.
/*
* Claim
* the
* SPI
* bus. */
rfm22_claimBus(rfm22b_dev);
// Disable interrupts
/*
* Disable
* interrupts */
rfm22_write(rfm22b_dev, RFM22_interrupt_enable1, 0x00);
rfm22_write(rfm22b_dev, RFM22_interrupt_enable2, 0x00);
// set the tx power
/*
* set
* the
* tx
* power */
rfm22b_dev->tx_power = 0x7;
rfm22_write(rfm22b_dev, RFM22_tx_power, RFM22_tx_pwr_lna_sw | rfm22b_dev->tx_power);
// TUNE mode
/*
* TUNE
* mode */
rfm22_write(rfm22b_dev, RFM22_op_and_func_ctrl1, RFM22_opfc1_pllon);
// Queue the data up for sending
/*
* Queue
* the
* data
* up
* for
* sending */
rfm22b_dev->tx_data_wr = len;
RX_LED_OFF;
// Set the destination address in the transmit header.
/*
* Set
* the
* destination
* address
* in
* the
* transmit
* header. */
uint32_t id = rfm22_destinationID(rfm22b_dev);
rfm22_write(rfm22b_dev, RFM22_transmit_header0, id & 0xff);
rfm22_write(rfm22b_dev, RFM22_transmit_header1, (id >> 8) & 0xff);
rfm22_write(rfm22b_dev, RFM22_transmit_header2, (id >> 16) & 0xff);
rfm22_write(rfm22b_dev, RFM22_transmit_header3, (id >> 24) & 0xff);
// FIFO mode, GFSK modulation
/*
* FIFO
* mode,
* GFSK
* modulation */
uint8_t fd_bit = rfm22_read(rfm22b_dev, RFM22_modulation_mode_control2) & RFM22_mmc2_fd;
rfm22_write(rfm22b_dev, RFM22_modulation_mode_control2, fd_bit | RFM22_mmc2_dtmod_fifo | RFM22_mmc2_modtyp_gfsk);
// Clear the FIFOs.
/*
* Clear
* the
* FIFOs. */
rfm22_write(rfm22b_dev, RFM22_op_and_func_ctrl2, RFM22_opfc2_ffclrrx | RFM22_opfc2_ffclrtx);
rfm22_write(rfm22b_dev, RFM22_op_and_func_ctrl2, 0x00);
// Set the total number of data bytes we are going to transmit.
/*
* Set
* the
* total
* number
* of
* data
* bytes
* we
* are
* going
* to
* transmit. */
rfm22_write(rfm22b_dev, RFM22_transmit_packet_length, len);
// Add some data to the chips TX FIFO before enabling the transmitter
/*
* Add
* some
* data
* to
* the
* chips
* TX
* FIFO
* before
* enabling
* the
* transmitter */
uint8_t *tx_buffer = rfm22b_dev->tx_packet_handle;
rfm22_assertCs(rfm22b_dev);
PIOS_SPI_TransferByte(rfm22b_dev->spi_id, RFM22_fifo_access | 0x80);
int bytes_to_write = (rfm22b_dev->tx_data_wr - rfm22b_dev->tx_data_rd);
bytes_to_write = (bytes_to_write > FIFO_SIZE) ? FIFO_SIZE : bytes_to_write;
PIOS_SPI_TransferBlock(rfm22b_dev->spi_id, &tx_buffer[rfm22b_dev->tx_data_rd], NULL, bytes_to_write, NULL);
rfm22b_dev->tx_data_rd += bytes_to_write;
rfm22_deassertCs(rfm22b_dev);
// Enable TX interrupts.
/*
* Enable
* TX
* interrupts. */
rfm22_write(rfm22b_dev, RFM22_interrupt_enable1, RFM22_ie1_enpksent | RFM22_ie1_entxffaem);
// Enable the transmitter.
/*
* Enable
* the
* transmitter. */
rfm22_write(rfm22b_dev, RFM22_op_and_func_ctrl1, RFM22_opfc1_pllon | RFM22_opfc1_txon);
// Release the SPI bus.
/*
* Release
* the
* SPI
* bus. */
rfm22_releaseBus(rfm22b_dev);
// We're in Tx mode.
/*
* We're
* in
* Tx
* mode. */
rfm22b_dev->rfm22b_state = RFM22B_STATE_TX_MODE;
TX_LED_ON;
@ -841,33 +2742,78 @@ bool PIOS_RFM22B_TransmitPacket(uint32_t rfm22b_id, uint8_t *p, uint8_t len)
}
/**
* Process a Tx interrupt from the RFM22B device.
*
* @param[in] rfm22b_id The rfm22b device.
* @return PIOS_RFM22B_TX_COMPLETE on completed Tx, or PIOS_RFM22B_INT_SUCCESS/PIOS_RFM22B_INT_FAILURE.
* Process
* a
* Tx
* interrupt
* from
* the
* RFM22B
* device.
*
*
* @param[in]
* rfm22b_id
*
* The
* rfm22b
* device.
*
* @return
* PIOS_RFM22B_TX_COMPLETE
* on
* completed
* Tx,
* or
* PIOS_RFM22B_INT_SUCCESS/PIOS_RFM22B_INT_FAILURE.
*/
pios_rfm22b_int_result PIOS_RFM22B_ProcessTx(uint32_t rfm22b_id)
pios_rfm22b_int_result PIOS_RFM22B_ProcessTx(uint32_trfm22b_id)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
if (!PIOS_RFM22B_Validate(rfm22b_dev)) {
return PIOS_RFM22B_INT_FAILURE;
}
// Read the device status registers
/*
* Read
* the
* device
* status
* registers */
if (!pios_rfm22_readStatus(rfm22b_dev)) {
return PIOS_RFM22B_INT_FAILURE;
}
// TX FIFO almost empty, it needs filling up
/*
* TX
* FIFO
* almost
* empty,
* it
* needs
* filling
* up */
if (rfm22b_dev->status_regs.int_status_1.tx_fifo_almost_empty) {
// Add data to the TX FIFO buffer
/*
* Add
* data
* to
* the
* TX
* FIFO
* buffer */
uint8_t *tx_buffer = rfm22b_dev->tx_packet_handle;
uint16_t max_bytes = FIFO_SIZE - TX_FIFO_LO_WATERMARK - 1;
rfm22_claimBus(rfm22b_dev);
rfm22_assertCs(rfm22b_dev);
PIOS_SPI_TransferByte(rfm22b_dev->spi_id, RFM22_fifo_access | 0x80);
int bytes_to_write = (rfm22b_dev->tx_data_wr - rfm22b_dev->tx_data_rd);
bytes_to_write = (bytes_to_write > max_bytes) ? max_bytes : bytes_to_write;
PIOS_SPI_TransferBlock(rfm22b_dev->spi_id, &tx_buffer[rfm22b_dev->tx_data_rd], NULL, bytes_to_write, NULL);
rfm22b_dev->tx_data_rd += bytes_to_write;
@ -876,8 +2822,14 @@ pios_rfm22b_int_result PIOS_RFM22B_ProcessTx(uint32_t rfm22b_id)
return PIOS_RFM22B_INT_SUCCESS;
} else if (rfm22b_dev->status_regs.int_status_1.packet_sent_interrupt) {
// Transition out of Tx mode.
/*
* Transition
* out
* of
* Tx
* mode. */
rfm22b_dev->rfm22b_state = RFM22B_STATE_TRANSITION;
return PIOS_RFM22B_TX_COMPLETE;
}
@ -885,53 +2837,141 @@ pios_rfm22b_int_result PIOS_RFM22B_ProcessTx(uint32_t rfm22b_id)
}
/**
* Process a Rx interrupt from the RFM22B device.
*
* @param[in] rfm22b_id The rfm22b device.
* @return PIOS_RFM22B_RX_COMPLETE on completed Rx, or PIOS_RFM22B_INT_SUCCESS/PIOS_RFM22B_INT_FAILURE.
* Process
* a
* Rx
* interrupt
* from
* the
* RFM22B
* device.
*
*
* @param[in]
* rfm22b_id
*
* The
* rfm22b
* device.
*
* @return
* PIOS_RFM22B_RX_COMPLETE
* on
* completed
* Rx,
* or
* PIOS_RFM22B_INT_SUCCESS/PIOS_RFM22B_INT_FAILURE.
*/
pios_rfm22b_int_result PIOS_RFM22B_ProcessRx(uint32_t rfm22b_id)
pios_rfm22b_int_result PIOS_RFM22B_ProcessRx(uint32_trfm22b_id)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
if (!PIOS_RFM22B_Validate(rfm22b_dev)) {
return PIOS_RFM22B_INT_FAILURE;
}
uint8_t *rx_buffer = rfm22b_dev->rx_packet_handle;
pios_rfm22b_int_result ret = PIOS_RFM22B_INT_SUCCESS;
// Read the device status registers
/*
* Read
* the
* device
* status
* registers */
if (!pios_rfm22_readStatus(rfm22b_dev)) {
rfm22_rxFailure(rfm22b_dev);
return PIOS_RFM22B_INT_FAILURE;
}
// FIFO under/over flow error. Restart RX mode.
/*
* FIFO
* under/over
* flow
* error.
*
* Restart
* RX
* mode. */
if (rfm22b_dev->status_regs.int_status_1.fifo_underoverflow_error ||
rfm22b_dev->status_regs.int_status_1.crc_error) {
rfm22_rxFailure(rfm22b_dev);
return PIOS_RFM22B_INT_FAILURE;
}
// Valid packet received
/*
* Valid
* packet
* received */
if (rfm22b_dev->status_regs.int_status_1.valid_packet_received) {
// Claim the SPI bus.
/*
* Claim
* the
* SPI
* bus. */
rfm22_claimBus(rfm22b_dev);
// read the total length of the packet data
/*
* read
* the
* total
* length
* of
* the
* packet
* data */
uint32_t len = rfm22_read(rfm22b_dev, RFM22_received_packet_length);
// The received packet is going to be larger than the receive buffer
/*
* The
* received
* packet
* is
* going
* to
* be
* larger
* than
* the
* receive
* buffer */
if (len > rfm22b_dev->max_packet_len) {
rfm22_releaseBus(rfm22b_dev);
rfm22_rxFailure(rfm22b_dev);
return PIOS_RFM22B_INT_FAILURE;
}
// there must still be data in the RX FIFO we need to get
/*
* there
* must
* still
* be
* data
* in
* the
* RX
* FIFO
* we
* need
* to
* get */
if (rfm22b_dev->rx_buffer_wr < len) {
int32_t bytes_to_read = len - rfm22b_dev->rx_buffer_wr;
// Fetch the data from the RX FIFO
/*
* Fetch
* the
* data
* from
* the
* RX
* FIFO */
rfm22_assertCs(rfm22b_dev);
PIOS_SPI_TransferByte(rfm22b_dev->spi_id, RFM22_fifo_access & 0x7F);
rfm22b_dev->rx_buffer_wr += (PIOS_SPI_TransferBlock(rfm22b_dev->spi_id, OUT_FF, (uint8_t *)&rx_buffer[rfm22b_dev->rx_buffer_wr],
@ -939,109 +2979,296 @@ pios_rfm22b_int_result PIOS_RFM22B_ProcessRx(uint32_t rfm22b_id)
rfm22_deassertCs(rfm22b_dev);
}
// Read the packet header (destination ID)
/*
* Read
* the
* packet
* header
* (destination
* ID) */
rfm22b_dev->rx_destination_id = rfm22_read(rfm22b_dev, RFM22_received_header0);
rfm22b_dev->rx_destination_id |= (rfm22_read(rfm22b_dev, RFM22_received_header1) << 8);
rfm22b_dev->rx_destination_id |= (rfm22_read(rfm22b_dev, RFM22_received_header2) << 16);
rfm22b_dev->rx_destination_id |= (rfm22_read(rfm22b_dev, RFM22_received_header3) << 24);
// Release the SPI bus.
/*
* Release
* the
* SPI
* bus. */
rfm22_releaseBus(rfm22b_dev);
// Is there a length error?
/*
* Is
* there
* a
* length
* error? */
if (rfm22b_dev->rx_buffer_wr != len) {
rfm22_rxFailure(rfm22b_dev);
return PIOS_RFM22B_INT_FAILURE;
}
// Increment the total byte received count.
/*
* Increment
* the
* total
* byte
* received
* count. */
rfm22b_dev->stats.rx_byte_count += rfm22b_dev->rx_buffer_wr;
// Update the pair status with this packet.
/*
* Update
* the
* pair
* status
* with
* this
* packet. */
rfm22_updatePairStatus(rfm22b_dev);
// We're finished with Rx mode
/*
* We're
* finished
* with
* Rx
* mode */
rfm22b_dev->rfm22b_state = RFM22B_STATE_TRANSITION;
ret = PIOS_RFM22B_RX_COMPLETE;
} else if (rfm22b_dev->status_regs.int_status_1.rx_fifo_almost_full) {
// RX FIFO almost full, it needs emptying
// read data from the rf chips FIFO buffer
/*
* RX
* FIFO
* almost
* full,
* it
* needs
* emptying
* read
* data
* from
* the
* rf
* chips
* FIFO
* buffer
// Claim the SPI bus.
*/
/*
* Claim
* the
* SPI
* bus. */
rfm22_claimBus(rfm22b_dev);
// Read the total length of the packet data
/*
* Read
* the
* total
* length
* of
* the
* packet
* data */
uint16_t len = rfm22_read(rfm22b_dev, RFM22_received_packet_length);
// The received packet is going to be larger than the specified length
/*
* The
* received
* packet
* is
* going
* to
* be
* larger
* than
* the
* specified
* length */
if ((rfm22b_dev->rx_buffer_wr + RX_FIFO_HI_WATERMARK) > len) {
rfm22_releaseBus(rfm22b_dev);
rfm22_rxFailure(rfm22b_dev);
return PIOS_RFM22B_INT_FAILURE;
}
// The received packet is going to be larger than the receive buffer
/*
* The
* received
* packet
* is
* going
* to
* be
* larger
* than
* the
* receive
* buffer */
if ((rfm22b_dev->rx_buffer_wr + RX_FIFO_HI_WATERMARK) > rfm22b_dev->max_packet_len) {
rfm22_releaseBus(rfm22b_dev);
rfm22_rxFailure(rfm22b_dev);
return PIOS_RFM22B_INT_FAILURE;
}
// Fetch the data from the RX FIFO
/*
* Fetch
* the
* data
* from
* the
* RX
* FIFO */
rfm22_assertCs(rfm22b_dev);
PIOS_SPI_TransferByte(rfm22b_dev->spi_id, RFM22_fifo_access & 0x7F);
rfm22b_dev->rx_buffer_wr += (PIOS_SPI_TransferBlock(rfm22b_dev->spi_id, OUT_FF, (uint8_t *)&rx_buffer[rfm22b_dev->rx_buffer_wr],
RX_FIFO_HI_WATERMARK, NULL) == 0) ? RX_FIFO_HI_WATERMARK : 0;
rfm22_deassertCs(rfm22b_dev);
// Release the SPI bus.
/*
* Release
* the
* SPI
* bus. */
rfm22_releaseBus(rfm22b_dev);
// Make sure that we're in RX mode.
/*
* Make
* sure
* that
* we're
* in
* RX
* mode. */
rfm22b_dev->rfm22b_state = RFM22B_STATE_RX_MODE;
} else if (rfm22b_dev->status_regs.int_status_2.valid_preamble_detected) {
// Valid preamble detected
/*
* Valid
* preamble
* detected */
RX_LED_ON;
// Sync word detected
/*
* Sync
* word
* detected */
#ifdef PIOS_RFM22B_DEBUG_ON_TELEM
D2_LED_ON;
#endif // PIOS_RFM22B_DEBUG_ON_TELEM
#endif /*
* PIOS_RFM22B_DEBUG_ON_TELEM */
rfm22b_dev->packet_start_ticks = xTaskGetTickCount();
if (rfm22b_dev->packet_start_ticks == 0) {
rfm22b_dev->packet_start_ticks = 1;
}
// We detected the preamble, now wait for sync.
/*
* We
* detected
* the
* preamble,
* now
* wait
* for
* sync. */
rfm22b_dev->rfm22b_state = RFM22B_STATE_RX_WAIT_SYNC;
} else if (rfm22b_dev->status_regs.int_status_2.sync_word_detected) {
// Claim the SPI bus.
/*
* Claim
* the
* SPI
* bus. */
rfm22_claimBus(rfm22b_dev);
// read the 10-bit signed afc correction value
// bits 9 to 2
/*
* read
* the
* 10-bit
* signed
* afc
* correction
* value */
/*
* bits
* 9
* to
* 2 */
uint16_t afc_correction = (uint16_t)rfm22_read(rfm22b_dev, RFM22_afc_correction_read) << 8;
// bits 1 & 0
/*
* bits
* 1
* &
* 0 */
afc_correction |= (uint16_t)rfm22_read(rfm22b_dev, RFM22_ook_counter_value1) & 0x00c0;
afc_correction >>= 6;
// convert the afc value to Hz
/*
* convert
* the
* afc
* value
* to
* Hz */
int32_t afc_corr = (int32_t)(rfm22b_dev->frequency_step_size * afc_correction + 0.5f);
rfm22b_dev->afc_correction_Hz = (afc_corr < -127) ? -127 : ((afc_corr > 127) ? 127 : afc_corr);
// read rx signal strength .. 45 = -100dBm, 205 = -20dBm
/*
* read
* rx
* signal
* strength
* ..
* 45
* =
* -100dBm,
* 205
* =
* -20dBm */
uint8_t rssi = rfm22_read(rfm22b_dev, RFM22_rssi);
// convert to dBm
/*
* convert
* to
* dBm */
rfm22b_dev->rssi_dBm = (int8_t)(rssi >> 1) - 122;
// Release the SPI bus.
/*
* Release
* the
* SPI
* bus. */
rfm22_releaseBus(rfm22b_dev);
// Indicate that we're in RX mode.
/*
* Indicate
* that
* we're
* in
* RX
* mode. */
rfm22b_dev->rfm22b_state = RFM22B_STATE_RX_MODE;
} else if ((rfm22b_dev->rfm22b_state == RFM22B_STATE_RX_WAIT_SYNC) && !rfm22b_dev->status_regs.int_status_2.valid_preamble_detected) {
// Waiting for the preamble timed out.
/*
* Waiting
* for
* the
* preamble
* timed
* out. */
rfm22_rxFailure(rfm22b_dev);
return PIOS_RFM22B_INT_FAILURE;
}
@ -1049,12 +3276,44 @@ pios_rfm22b_int_result PIOS_RFM22B_ProcessRx(uint32_t rfm22b_id)
}
/**
* Set the PPM packet received callback.
*
* @param[in] rfm22b_dev The RFM22B device ID.
* @param[in] cb The callback function pointer.
* Set
* the
* PPM
* packet
* received
* callback.
*
*
* @param[in]
* rfm22b_dev
*
* The
* RFM22B
* device
* ID.
*
* @param[in]
* cb
*
*
*
*
*
*
*
*
*
* The
* callback
* function
* pointer.
*/
void PIOS_RFM22B_SetPPMCallback(uint32_t rfm22b_id, PPMReceivedCallback cb)
void PIOS_RFM22B_SetPPMCallback(
uint32_t
rfm22b_id,
PPMReceivedCallback
cb)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
@ -1066,12 +3325,40 @@ void PIOS_RFM22B_SetPPMCallback(uint32_t rfm22b_id, PPMReceivedCallback cb)
}
/**
* Set the PPM values to be transmitted.
*
* @param[in] rfm22b_dev The RFM22B device ID.
* @param[in] channels The PPM channel values.
* Set
* the
* PPM
* values
* to
* be
* transmitted.
*
*
* @param[in]
* rfm22b_dev
*
* The
* RFM22B
* device
* ID.
*
* @param[in]
* channels
*
*
*
* The
* PPM
* channel
* values.
*/
extern void PIOS_RFM22B_PPMSet(uint32_t rfm22b_id, int16_t *channels)
extern void PIOS_RFM22B_PPMSet(
uint32_t
rfm22b_id,
int16_t
*
channels)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
@ -1085,12 +3372,41 @@ extern void PIOS_RFM22B_PPMSet(uint32_t rfm22b_id, int16_t *channels)
}
/**
* Fetch the PPM values that have been received.
*
* @param[in] rfm22b_dev The RFM22B device structure pointer.
* @param[out] channels The PPM channel values.
* Fetch
* the
* PPM
* values
* that
* have
* been
* received.
*
*
* @param[in]
* rfm22b_dev
*
* The
* RFM22B
* device
* structure
* pointer.
*
* @param[out]
* channels
*
*
* The
* PPM
* channel
* values.
*/
extern void PIOS_RFM22B_PPMGet(uint32_t rfm22b_id, int16_t *channels)
extern void PIOS_RFM22B_PPMGet(
uint32_t
rfm22b_id,
int16_t
*
channels)
{
struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id;
@ -1104,9 +3420,24 @@ extern void PIOS_RFM22B_PPMGet(uint32_t rfm22b_id, int16_t *channels)
}
/**
* Validate that the device structure is valid.
*
* @param[in] rfm22b_dev The RFM22B device structure pointer.
* Validate
* that
* the
* device
* structure
* is
* valid.
*
*
* @param[in]
* rfm22b_dev
*
* The
* RFM22B
* device
* structure
* pointer.
*/
inline bool PIOS_RFM22B_Validate(struct pios_rfm22b_dev *rfm22b_dev)
{
@ -1115,13 +3446,31 @@ inline bool PIOS_RFM22B_Validate(struct pios_rfm22b_dev *rfm22b_dev)
/*****************************************************************************
* The Device Control Thread
*
* The
* Device
* Control
* Thread
*****************************************************************************/
/**
* The task that controls the radio state machine.
*
* @param[in] paramters The task parameters.
* The
* task
* that
* controls
* the
* radio
* state
* machine.
*
*
* @param[in]
* paramters
*
* The
* task
* parameters.
*/
static void pios_rfm22_task(void *parameters)
{
@ -1130,65 +3479,145 @@ static void pios_rfm22_task(void *parameters)
if (!PIOS_RFM22B_Validate(rfm22b_dev)) {
return;
}
portTickType lastEventTicks = xTaskGetTickCount();
while (1) {
#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_RFM22B)
// Update the watchdog timer
PIOS_WDG_UpdateFlag(PIOS_WDG_RFM22B);
/*
* Update
* the
* watchdog
* timer */
PIOS_WDG_UpdateFlag(
PIOS_WDG_RFM22B);
#endif /* PIOS_WDG_RFM22B */
// Wait for a signal indicating an external interrupt or a pending send/receive request.
/*
* Wait
* for
* a
* signal
* indicating
* an
* external
* interrupt
* or
* a
* pending
* send/receive
* request. */
if (xSemaphoreTake(rfm22b_dev->isrPending, ISR_TIMEOUT / portTICK_RATE_MS) == pdTRUE) {
lastEventTicks = xTaskGetTickCount();
// Process events through the state machine.
/*
* Process
* events
* through
* the
* state
* machine. */
enum pios_radio_event event;
while (xQueueReceive(rfm22b_dev->eventQueue, &event, 0) == pdTRUE) {
if ((event == RADIO_EVENT_INT_RECEIVED) &&
((rfm22b_dev->state == RADIO_STATE_UNINITIALIZED) || (rfm22b_dev->state == RADIO_STATE_INITIALIZING))) {
continue;
}
rfm22_process_event(rfm22b_dev, event);
}
} else {
// Has it been too long since the last event?
/*
* Has
* it
* been
* too
* long
* since
* the
* last
* event? */
portTickType curTicks = xTaskGetTickCount();
if (pios_rfm22_time_difference_ms(lastEventTicks, curTicks) > PIOS_RFM22B_SUPERVISOR_TIMEOUT) {
// Clear the event queue.
/*
* Clear
* the
* event
* queue. */
enum pios_radio_event event;
while (xQueueReceive(rfm22b_dev->eventQueue, &event, 0) == pdTRUE) {
// Do nothing;
/*
* Do
* nothing; */
}
lastEventTicks = xTaskGetTickCount();
// Transsition through an error event.
/*
* Transsition
* through
* an
* error
* event. */
rfm22_process_event(rfm22b_dev, RADIO_EVENT_ERROR);
}
}
// Change channels if necessary.
/*
* Change
* channels
* if
* necessary. */
if (rfm22_changeChannel(rfm22b_dev)) {
rfm22_process_event(rfm22b_dev, RADIO_EVENT_RX_MODE);
}
portTickType curTicks = xTaskGetTickCount();
// Have we been sending / receiving this packet too long?
portTickType curTicks = xTaskGetTickCount();
/*
* Have
* we
* been
* sending
* /
* receiving
* this
* packet
* too
* long? */
if ((rfm22b_dev->packet_start_ticks > 0) &&
(pios_rfm22_time_difference_ms(rfm22b_dev->packet_start_ticks, curTicks) > (rfm22b_dev->packet_time * 3))) {
rfm22_process_event(rfm22b_dev, RADIO_EVENT_TIMEOUT);
}
// Start transmitting a packet if it's time.
/*
* Start
* transmitting
* a
* packet
* if
* it's
* time. */
bool time_to_send = rfm22_timeToSend(rfm22b_dev);
#ifdef PIOS_RFM22B_DEBUG_ON_TELEM
if (time_to_send) {
#ifdef PIOS_RFM22B_DEBUG_ON_TELEM
if (
time_to_send) {
D4_LED_ON;
} else {
D4_LED_OFF;
}
#endif
#endif
if (time_to_send && PIOS_RFM22B_InRxWait((uint32_t)rfm22b_dev)) {
rfm22_process_event(rfm22b_dev, RADIO_EVENT_TX_START);
}
@ -1197,74 +3626,257 @@ static void pios_rfm22_task(void *parameters)
/*****************************************************************************
* The State Machine Functions
*
* The
* State
* Machine
* Functions
*****************************************************************************/
/**
* Inject an event into the RFM22B state machine.
*
* @param[in] rfm22b_dev The device structure
* @param[in] event The event to inject
* @param[in] inISR Is this being called from an interrrup service routine?
* Inject
* an
* event
* into
* the
* RFM22B
* state
* machine.
*
*
* @param[in]
* rfm22b_dev
* The
* device
* structure
*
* @param[in]
* event
* The
* event
* to
* inject
*
* @param[in]
* inISR
* Is
* this
* being
* called
* from
* an
* interrrup
* service
* routine?
*/
static void pios_rfm22_inject_event(struct pios_rfm22b_dev *rfm22b_dev, enum pios_radio_event event, bool inISR)
static void pios_rfm22_inject_event(
struct
pios_rfm22b_dev
*
rfm22b_dev,
enum
pios_radio_event
event,
bool
inISR)
{
if (inISR) {
// Store the event.
/*
* Store
* the
* event. */
portBASE_TYPE pxHigherPriorityTaskWoken1;
if (xQueueSendFromISR(rfm22b_dev->eventQueue, &event, &pxHigherPriorityTaskWoken1) != pdTRUE) {
return;
}
// Signal the semaphore to wake up the handler thread.
/*
* Signal
* the
* semaphore
* to
* wake
* up
* the
* handler
* thread. */
portBASE_TYPE pxHigherPriorityTaskWoken2;
if (xSemaphoreGiveFromISR(rfm22b_dev->isrPending, &pxHigherPriorityTaskWoken2) != pdTRUE) {
// Something went fairly seriously wrong
/*
* Something
* went
* fairly
* seriously
* wrong */
rfm22b_dev->errors++;
}
portEND_SWITCHING_ISR((pxHigherPriorityTaskWoken2 == pdTRUE) || (pxHigherPriorityTaskWoken2 == pdTRUE));
} else {
// Store the event.
/*
* Store
* the
* event. */
if (xQueueSend(rfm22b_dev->eventQueue, &event, portMAX_DELAY) != pdTRUE) {
return;
}
// Signal the semaphore to wake up the handler thread.
/*
* Signal
* the
* semaphore
* to
* wake
* up
* the
* handler
* thread. */
if (xSemaphoreGive(rfm22b_dev->isrPending) != pdTRUE) {
// Something went fairly seriously wrong
/*
* Something
* went
* fairly
* seriously
* wrong */
rfm22b_dev->errors++;
}
}
}
/**
* Process the next state transition from the given event.
*
* @param[in] rfm22b_dev The device structure
* @param[in] event The event to process
* @return enum pios_radio_event The next event to inject
* Process
* the
* next
* state
* transition
* from
* the
* given
* event.
*
*
* @param[in]
* rfm22b_dev
* The
* device
* structure
*
* @param[in]
* event
* The
* event
* to
* process
*
* @return
* enum
* pios_radio_event
*
* The
* next
* event
* to
* inject
*/
static enum pios_radio_event rfm22_process_state_transition(struct pios_rfm22b_dev *rfm22b_dev, enum pios_radio_event event)
static enum pios_radio_event rfm22_process_state_transition(
struct
pios_rfm22b_dev
*
rfm22b_dev,
enum
pios_radio_event
event)
{
// No event
/*
* No
* event */
if (event >= RADIO_EVENT_NUM_EVENTS) {
return RADIO_EVENT_NUM_EVENTS;
}
// Don't transition if there is no transition defined
/*
* Don't
* transition
* if
* there
* is
* no
* transition
* defined */
enum pios_radio_state next_state = rfm22b_transitions[rfm22b_dev->state].next_state[event];
if (!next_state) {
return RADIO_EVENT_NUM_EVENTS;
}
/*
* Move to the next state
*
* This is done prior to calling the new state's entry function to
* guarantee that the entry function never depends on the previous
* state. This way, it cannot ever know what the previous state was.
* Move
* to
* the
* next
* state
*
*
* This
* is
* done
* prior
* to
* calling
* the
* new
* state's
* entry
* function
* to
*
* guarantee
* that
* the
* entry
* function
* never
* depends
* on
* the
* previous
*
* state.
*
* This
* way,
* it
* cannot
* ever
* know
* what
* the
* previous
* state
* was.
*/
rfm22b_dev->state = next_state;
/* Call the entry function (if any) for the next state. */
/*
* Call
* the
* entry
* function
* (if
* any)
* for
* the
* next
* state.
* */
if (rfm22b_transitions[rfm22b_dev->state].entry_fn) {
return rfm22b_transitions[rfm22b_dev->state].entry_fn(rfm22b_dev);
}
@ -1273,15 +3885,58 @@ static enum pios_radio_event rfm22_process_state_transition(struct pios_rfm22b_d
}
/**
* Process the given event through the state transition table.
* This could cause a series of events and transitions to take place.
*
* @param[in] rfm22b_dev The device structure
* @param[in] event The event to process
* Process
* the
* given
* event
* through
* the
* state
* transition
* table.
*
* This
* could
* cause
* a
* series
* of
* events
* and
* transitions
* to
* take
* place.
*
*
* @param[in]
* rfm22b_dev
* The
* device
* structure
*
* @param[in]
* event
* The
* event
* to
* process
*/
static void rfm22_process_event(struct pios_rfm22b_dev *rfm22b_dev, enum pios_radio_event event)
static void rfm22_process_event(
struct
pios_rfm22b_dev
*
rfm22b_dev,
enum
pios_radio_event
event)
{
// Process all state transitions.
/*
* Process
* all
* state
* transitions. */
while (event != RADIO_EVENT_NUM_EVENTS) {
event = rfm22_process_state_transition(rfm22b_dev, event);
}
@ -1289,27 +3944,66 @@ static void rfm22_process_event(struct pios_rfm22b_dev *rfm22b_dev, enum pios_ra
/*****************************************************************************
* The Device Initialization / Configuration Functions
*
* The
* Device
* Initialization
* /
* Configuration
* Functions
*****************************************************************************/
/**
* Initialize (or re-initialize) the RFM22B radio device.
*
* @param[in] rfm22b_dev The device structure
* @return enum pios_radio_event The next event to inject
* Initialize
* (or
* re-initialize)
* the
* RFM22B
* radio
* device.
*
*
* @param[in]
* rfm22b_dev
* The
* device
* structure
*
* @return
* enum
* pios_radio_event
*
* The
* next
* event
* to
* inject
*/
static enum pios_radio_event rfm22_init(struct pios_rfm22b_dev *rfm22b_dev)
{
// Initialize the register values.
/*
* Initialize
* the
* register
* values. */
rfm22b_dev->status_regs.int_status_1.raw = 0;
rfm22b_dev->status_regs.int_status_2.raw = 0;
rfm22b_dev->status_regs.device_status.raw = 0;
rfm22b_dev->status_regs.ezmac_status.raw = 0;
// Clean the LEDs
/*
* Clean
* the
* LEDs */
rfm22_clearLEDs();
// Initialize the detected device statistics.
/*
* Initialize
* the
* detected
* device
* statistics. */
for (uint8_t i = 0; i < OPLINKSTATUS_PAIRIDS_NUMELEM; ++i) {
rfm22b_dev->pair_stats[i].pairID = 0;
rfm22b_dev->pair_stats[i].rssi = -127;
@ -1317,20 +4011,33 @@ static enum pios_radio_event rfm22_init(struct pios_rfm22b_dev *rfm22b_dev)
rfm22b_dev->pair_stats[i].lastContact = 0;
}
// Initlize the link stats.
/*
* Initlize
* the
* link
* stats. */
for (uint8_t i = 0; i < RFM22B_RX_PACKET_STATS_LEN; ++i) {
rfm22b_dev->rx_packet_stats[i] = 0;
}
// Initialize the state
/*
* Initialize
* the
* state */
rfm22b_dev->stats.link_state = OPLINKSTATUS_LINKSTATE_ENABLED;
// Initialize the packets.
/*
* Initialize
* the
* packets. */
rfm22b_dev->rx_packet_len = 0;
rfm22b_dev->rx_destination_id = 0;
rfm22b_dev->tx_packet_handle = NULL;
// Initialize the devide state
/*
* Initialize
* the
* devide
* state */
rfm22b_dev->rx_buffer_wr = 0;
rfm22b_dev->tx_data_rd = rfm22b_dev->tx_data_wr = 0;
rfm22b_dev->channel = 0;
@ -1341,125 +4048,349 @@ static enum pios_radio_event rfm22_init(struct pios_rfm22b_dev *rfm22b_dev)
rfm22b_dev->rfm22b_state = RFM22B_STATE_INITIALIZING;
rfm22b_dev->on_sync_channel = false;
// software reset the RF chip .. following procedure according to Si4x3x Errata (rev. B)
/*
* software
* reset
* the
* RF
* chip
* ..
* following
* procedure
* according
* to
* Si4x3x
* Errata
* (rev.
* B) */
rfm22_write_claim(rfm22b_dev, RFM22_op_and_func_ctrl1, RFM22_opfc1_swres);
for (uint8_t i = 0; i < 50; ++i) {
// read the status registers
/*
* read
* the
* status
* registers */
pios_rfm22_readStatus(rfm22b_dev);
// Is the chip ready?
/*
* Is
* the
* chip
* ready? */
if (rfm22b_dev->status_regs.int_status_2.chip_ready) {
break;
}
// Wait 1ms if not.
/*
* Wait
* 1ms
* if
* not. */
PIOS_DELAY_WaitmS(1);
}
/*
* **************** */
// ****************
// read status - clears interrupt
/*
* read
* status
* -
* clears
* interrupt */
pios_rfm22_readStatus(rfm22b_dev);
// Claim the SPI bus.
/*
* Claim
* the
* SPI
* bus. */
rfm22_claimBus(rfm22b_dev);
// disable all interrupts
/*
* disable
* all
* interrupts */
rfm22_write(rfm22b_dev, RFM22_interrupt_enable1, 0x00);
rfm22_write(rfm22b_dev, RFM22_interrupt_enable2, 0x00);
// read the RF chip ID bytes
// read the device type
/*
* read
* the
* RF
* chip
* ID
* bytes */
/*
* read
* the
* device
* type */
uint8_t device_type = rfm22_read(rfm22b_dev, RFM22_DEVICE_TYPE) & RFM22_DT_MASK;
// read the device version
/*
* read
* the
* device
* version */
uint8_t device_version = rfm22_read(rfm22b_dev, RFM22_DEVICE_VERSION) & RFM22_DV_MASK;
#if defined(RFM22_DEBUG)
DEBUG_PRINTF(2, "rf device type: %d\n\r", device_type);
DEBUG_PRINTF(2, "rf device version: %d\n\r", device_version);
#endif
#if defined(RFM22_DEBUG)
DEBUG_PRINTF(
2,
"rf device type: %d\n\r",
device_type);
DEBUG_PRINTF(
2,
"rf device version: %d\n\r",
device_version);
#endif
if (device_type != 0x08) {
#if defined(RFM22_DEBUG)
DEBUG_PRINTF(2, "rf device type: INCORRECT - should be 0x08\n\r");
DEBUG_PRINTF(
2,
"rf device type: INCORRECT - should be 0x08\n\r");
#endif
// incorrect RF module type
/*
* incorrect
* RF
* module
* type */
return RADIO_EVENT_FATAL_ERROR;
}
if (device_version != RFM22_DEVICE_VERSION_B1) {
#if defined(RFM22_DEBUG)
DEBUG_PRINTF(2, "rf device version: INCORRECT\n\r");
DEBUG_PRINTF(
2,
"rf device version: INCORRECT\n\r");
#endif
// incorrect RF module version
/*
* incorrect
* RF
* module
* version */
return RADIO_EVENT_FATAL_ERROR;
}
// calibrate our RF module to be exactly on frequency .. different for every module
/*
* calibrate
* our
* RF
* module
* to
* be
* exactly
* on
* frequency
* ..
* different
* for
* every
* module */
rfm22_write(rfm22b_dev, RFM22_xtal_osc_load_cap, OSC_LOAD_CAP);
// disable Low Duty Cycle Mode
/*
* disable
* Low
* Duty
* Cycle
* Mode */
rfm22_write(rfm22b_dev, RFM22_op_and_func_ctrl2, 0x00);
// 1MHz clock output
/*
* 1MHz
* clock
* output */
rfm22_write(rfm22b_dev, RFM22_cpu_output_clk, RFM22_coc_1MHz);
// READY mode
/*
* READY
* mode */
rfm22_write(rfm22b_dev, RFM22_op_and_func_ctrl1, RFM22_opfc1_xton);
// choose the 3 GPIO pin functions
// GPIO port use default value
/*
* choose
* the
* 3
* GPIO
* pin
* functions
* GPIO
* port
* use
* default
* value
*/
rfm22_write(rfm22b_dev, RFM22_io_port_config, RFM22_io_port_default);
if (rfm22b_dev->cfg.gpio_direction == GPIO0_TX_GPIO1_RX) {
// GPIO0 = TX State (to control RF Switch)
/*
* GPIO0
* =
* TX
* State
* (to
* control
* RF
* Switch) */
rfm22_write(rfm22b_dev, RFM22_gpio0_config, RFM22_gpio0_config_drv3 | RFM22_gpio0_config_txstate);
// GPIO1 = RX State (to control RF Switch)
/*
* GPIO1
* =
* RX
* State
* (to
* control
* RF
* Switch) */
rfm22_write(rfm22b_dev, RFM22_gpio1_config, RFM22_gpio1_config_drv3 | RFM22_gpio1_config_rxstate);
} else {
// GPIO0 = TX State (to control RF Switch)
/*
* GPIO0
* =
* TX
* State
* (to
* control
* RF
* Switch) */
rfm22_write(rfm22b_dev, RFM22_gpio0_config, RFM22_gpio0_config_drv3 | RFM22_gpio0_config_rxstate);
// GPIO1 = RX State (to control RF Switch)
/*
* GPIO1
* =
* RX
* State
* (to
* control
* RF
* Switch) */
rfm22_write(rfm22b_dev, RFM22_gpio1_config, RFM22_gpio1_config_drv3 | RFM22_gpio1_config_txstate);
}
// GPIO2 = Clear Channel Assessment
/*
* GPIO2
* =
* Clear
* Channel
* Assessment */
rfm22_write(rfm22b_dev, RFM22_gpio2_config, RFM22_gpio2_config_drv3 | RFM22_gpio2_config_cca);
// FIFO mode, GFSK modulation
/*
* FIFO
* mode,
* GFSK
* modulation */
uint8_t fd_bit = rfm22_read(rfm22b_dev, RFM22_modulation_mode_control2) & RFM22_mmc2_fd;
rfm22_write(rfm22b_dev, RFM22_modulation_mode_control2, RFM22_mmc2_trclk_clk_none | RFM22_mmc2_dtmod_fifo | fd_bit | RFM22_mmc2_modtyp_gfsk);
// setup to read the internal temperature sensor
// ADC used to sample the temperature sensor
/*
* setup
* to
* read
* the
* internal
* temperature
* sensor */
/*
* ADC
* used
* to
* sample
* the
* temperature
* sensor */
uint8_t adc_config = RFM22_ac_adcsel_temp_sensor | RFM22_ac_adcref_bg;
rfm22_write(rfm22b_dev, RFM22_adc_config, adc_config);
// adc offset
/*
* adc
* offset */
rfm22_write(rfm22b_dev, RFM22_adc_sensor_amp_offset, 0);
// temp sensor calibration .. <20>40C to +64C 0.5C resolution
/*
* temp
* sensor
* calibration
* ..
* <EFBFBD>40C
* to
* +64C
* 0.5C
* resolution */
rfm22_write(rfm22b_dev, RFM22_temp_sensor_calib, RFM22_tsc_tsrange0 | RFM22_tsc_entsoffs);
// temp sensor offset
/*
* temp
* sensor
* offset */
rfm22_write(rfm22b_dev, RFM22_temp_value_offset, 0);
// start an ADC conversion
/*
* start
* an
* ADC
* conversion */
rfm22_write(rfm22b_dev, RFM22_adc_config, adc_config | RFM22_ac_adcstartbusy);
// set the RSSI threshold interrupt to about -90dBm
/*
* set
* the
* RSSI
* threshold
* interrupt
* to
* about
* -90dBm */
rfm22_write(rfm22b_dev, RFM22_rssi_threshold_clear_chan_indicator, (-90 + 122) * 2);
// enable the internal Tx & Rx packet handlers (without CRC)
/*
* enable
* the
* internal
* Tx
* &
* Rx
* packet
* handlers
* (without
* CRC) */
rfm22_write(rfm22b_dev, RFM22_data_access_control, RFM22_dac_enpacrx | RFM22_dac_enpactx);
// x-nibbles tx preamble
/*
* x-nibbles
* tx
* preamble */
rfm22_write(rfm22b_dev, RFM22_preamble_length, TX_PREAMBLE_NIBBLES);
// x-nibbles rx preamble detection
/*
* x-nibbles
* rx
* preamble
* detection */
rfm22_write(rfm22b_dev, RFM22_preamble_detection_ctrl1, RX_PREAMBLE_NIBBLES << 3);
// header control - using a 4 by header with broadcast of 0xffffffff
/*
* header
* control
* -
* using
* a
* 4
* by
* header
* with
* broadcast
* of
* 0xffffffff */
rfm22_write(rfm22b_dev, RFM22_header_control1,
RFM22_header_cntl1_bcen_0 |
RFM22_header_cntl1_bcen_1 |
@ -1469,46 +4400,136 @@ static enum pios_radio_event rfm22_init(struct pios_rfm22b_dev *rfm22b_dev)
RFM22_header_cntl1_hdch_1 |
RFM22_header_cntl1_hdch_2 |
RFM22_header_cntl1_hdch_3);
// Check all bit of all bytes of the header, unless we're an unbound modem.
/*
* Check
* all
* bit
* of
* all
* bytes
* of
* the
* header,
* unless
* we're
* an
* unbound
* modem. */
uint8_t header_mask = (rfm22_destinationID(rfm22b_dev) == 0xffffffff) ? 0 : 0xff;
rfm22_write(rfm22b_dev, RFM22_header_enable0, header_mask);
rfm22_write(rfm22b_dev, RFM22_header_enable1, header_mask);
rfm22_write(rfm22b_dev, RFM22_header_enable2, header_mask);
rfm22_write(rfm22b_dev, RFM22_header_enable3, header_mask);
// The destination ID and receive ID should be the same.
/*
* The
* destination
* ID
* and
* receive
* ID
* should
* be
* the
* same. */
uint32_t id = rfm22_destinationID(rfm22b_dev);
rfm22_write(rfm22b_dev, RFM22_check_header0, id & 0xff);
rfm22_write(rfm22b_dev, RFM22_check_header1, (id >> 8) & 0xff);
rfm22_write(rfm22b_dev, RFM22_check_header2, (id >> 16) & 0xff);
rfm22_write(rfm22b_dev, RFM22_check_header3, (id >> 24) & 0xff);
// 4 header bytes, synchronization word length 3, 2, 1 & 0 used, packet length included in header.
/*
* 4
* header
* bytes,
* synchronization
* word
* length
* 3,
* 2,
* 1
* &
* 0
* used,
* packet
* length
* included
* in
* header. */
rfm22_write(rfm22b_dev, RFM22_header_control2,
RFM22_header_cntl2_hdlen_3210 |
RFM22_header_cntl2_synclen_3210 |
((TX_PREAMBLE_NIBBLES >> 8) & 0x01));
// sync word
/*
* sync
* word */
rfm22_write(rfm22b_dev, RFM22_sync_word3, SYNC_BYTE_1);
rfm22_write(rfm22b_dev, RFM22_sync_word2, SYNC_BYTE_2);
rfm22_write(rfm22b_dev, RFM22_sync_word1, SYNC_BYTE_3);
rfm22_write(rfm22b_dev, RFM22_sync_word0, SYNC_BYTE_4);
// TX FIFO Almost Full Threshold (0 - 63)
/*
* TX
* FIFO
* Almost
* Full
* Threshold
* (0
* -
* 63) */
rfm22_write(rfm22b_dev, RFM22_tx_fifo_control1, TX_FIFO_HI_WATERMARK);
// TX FIFO Almost Empty Threshold (0 - 63)
/*
* TX
* FIFO
* Almost
* Empty
* Threshold
* (0
* -
* 63) */
rfm22_write(rfm22b_dev, RFM22_tx_fifo_control2, TX_FIFO_LO_WATERMARK);
// RX FIFO Almost Full Threshold (0 - 63)
/*
* RX
* FIFO
* Almost
* Full
* Threshold
* (0
* -
* 63) */
rfm22_write(rfm22b_dev, RFM22_rx_fifo_control, RX_FIFO_HI_WATERMARK);
// Set the frequency calibration
/*
* Set
* the
* frequency
* calibration */
rfm22_write(rfm22b_dev, RFM22_xtal_osc_load_cap, rfm22b_dev->cfg.RFXtalCap);
// Release the bus
/*
* Release
* the
* bus */
rfm22_releaseBus(rfm22b_dev);
// Initialize the frequency and datarate to te default.
/*
* Initialize
* the
* frequency
* and
* datarate
* to
* te
* default. */
rfm22_setNominalCarrierFrequency(rfm22b_dev, 0);
pios_rfm22_setDatarate(rfm22b_dev);
@ -1516,97 +4537,239 @@ static enum pios_radio_event rfm22_init(struct pios_rfm22b_dev *rfm22b_dev)
}
/**
* Set the air datarate for the RFM22B device.
*
* Carson's rule:
* The signal bandwidth is about 2(Delta-f + fm) ..
* Set
* the
* air
* datarate
* for
* the
* RFM22B
* device.
*
* Delta-f = frequency deviation
* fm = maximum frequency of the signal
*
* @param[in] rfm33b_dev The device structure pointer.
* @param[in] datarate The air datarate.
* @param[in] data_whitening Is data whitening desired?
* Carson's
* rule:
*
*
* The
* signal
* bandwidth
* is
* about
* 2(Delta-f
* +
* fm)
* ..
*
*
* Delta-f
* =
* frequency
* deviation
*
* fm
* =
* maximum
* frequency
* of
* the
* signal
*
*
* @param[in]
* rfm33b_dev
*
* The
* device
* structure
* pointer.
*
* @param[in]
* datarate
*
* The
* air
* datarate.
*
* @param[in]
* data_whitening
*
* Is
* data
* whitening
* desired?
*/
static void pios_rfm22_setDatarate(struct pios_rfm22b_dev *rfm22b_dev)
{
enum rfm22b_datarate datarate = rfm22b_dev->datarate;
bool data_whitening = true;
// Claim the SPI bus.
/*
* Claim
* the
* SPI
* bus. */
rfm22_claimBus(rfm22b_dev);
// rfm22_if_filter_bandwidth
/*
* rfm22_if_filter_bandwidth */
rfm22_write(rfm22b_dev, 0x1C, reg_1C[datarate]);
// rfm22_afc_loop_gearshift_override
/*
* rfm22_afc_loop_gearshift_override */
rfm22_write(rfm22b_dev, 0x1D, reg_1D[datarate]);
// RFM22_afc_timing_control
/*
* RFM22_afc_timing_control */
rfm22_write(rfm22b_dev, 0x1E, reg_1E[datarate]);
// RFM22_clk_recovery_gearshift_override
/*
* RFM22_clk_recovery_gearshift_override */
rfm22_write(rfm22b_dev, 0x1F, reg_1F[datarate]);
// rfm22_clk_recovery_oversampling_ratio
/*
* rfm22_clk_recovery_oversampling_ratio */
rfm22_write(rfm22b_dev, 0x20, reg_20[datarate]);
// rfm22_clk_recovery_offset2
/*
* rfm22_clk_recovery_offset2 */
rfm22_write(rfm22b_dev, 0x21, reg_21[datarate]);
// rfm22_clk_recovery_offset1
/*
* rfm22_clk_recovery_offset1 */
rfm22_write(rfm22b_dev, 0x22, reg_22[datarate]);
// rfm22_clk_recovery_offset0
/*
* rfm22_clk_recovery_offset0 */
rfm22_write(rfm22b_dev, 0x23, reg_23[datarate]);
// rfm22_clk_recovery_timing_loop_gain1
/*
* rfm22_clk_recovery_timing_loop_gain1 */
rfm22_write(rfm22b_dev, 0x24, reg_24[datarate]);
// rfm22_clk_recovery_timing_loop_gain0
/*
* rfm22_clk_recovery_timing_loop_gain0 */
rfm22_write(rfm22b_dev, 0x25, reg_25[datarate]);
// rfm22_agc_override1
/*
* rfm22_agc_override1 */
rfm22_write(rfm22b_dev, RFM22_agc_override1, reg_69[datarate]);
// rfm22_afc_limiter
/*
* rfm22_afc_limiter */
rfm22_write(rfm22b_dev, 0x2A, reg_2A[datarate]);
// rfm22_tx_data_rate1
/*
* rfm22_tx_data_rate1 */
rfm22_write(rfm22b_dev, 0x6E, reg_6E[datarate]);
// rfm22_tx_data_rate0
/*
* rfm22_tx_data_rate0 */
rfm22_write(rfm22b_dev, 0x6F, reg_6F[datarate]);
if (!data_whitening) {
// rfm22_modulation_mode_control1
/*
* rfm22_modulation_mode_control1 */
rfm22_write(rfm22b_dev, 0x70, reg_70[datarate] & ~RFM22_mmc1_enwhite);
} else {
// rfm22_modulation_mode_control1
/*
* rfm22_modulation_mode_control1 */
rfm22_write(rfm22b_dev, 0x70, reg_70[datarate] | RFM22_mmc1_enwhite);
}
// rfm22_modulation_mode_control2
/*
* rfm22_modulation_mode_control2 */
rfm22_write(rfm22b_dev, 0x71, reg_71[datarate]);
// rfm22_frequency_deviation
/*
* rfm22_frequency_deviation */
rfm22_write(rfm22b_dev, 0x72, reg_72[datarate]);
// rfm22_cpcuu
/*
* rfm22_cpcuu */
rfm22_write(rfm22b_dev, 0x58, reg_58[datarate]);
rfm22_write(rfm22b_dev, RFM22_ook_counter_value1, 0x00);
rfm22_write(rfm22b_dev, RFM22_ook_counter_value2, 0x00);
// Release the bus
/*
* Release
* the
* bus */
rfm22_releaseBus(rfm22b_dev);
}
/**
* Set the nominal carrier frequency, channel step size, and initial channel
*
* @param[in] rfm33b_dev The device structure pointer.
* @param[in] init_chan The initial channel to tune to.
* Set
* the
* nominal
* carrier
* frequency,
* channel
* step
* size,
* and
* initial
* channel
*
*
* @param[in]
* rfm33b_dev
*
* The
* device
* structure
* pointer.
*
* @param[in]
* init_chan
*
* The
* initial
* channel
* to
* tune
* to.
*/
static void rfm22_setNominalCarrierFrequency(struct pios_rfm22b_dev *rfm22b_dev, uint8_t init_chan)
static void rfm22_setNominalCarrierFrequency(
struct
pios_rfm22b_dev
*
rfm22b_dev,
uint8_t
init_chan)
{
// Set the frequency channels to start at 430MHz
/*
* Set
* the
* frequency
* channels
* to
* start
* at
* 430MHz */
uint32_t frequency_hz = RFM22B_NOMINAL_CARRIER_FREQUENCY;
// The step size is 10MHz / 250 channels = 40khz, and the step size is specified in 10khz increments.
/*
* The
* step
* size
* is
* 10MHz
* /
* 250
* channels
* =
* 40khz,
* and
* the
* step
* size
* is
* specified
* in
* 10khz
* increments. */
uint8_t freq_hop_step_size = 4;
// holds the hbsel (1 or 2)
/*
* holds
* the
* hbsel
* (1
* or
* 2) */
uint8_t hbsel;
if (frequency_hz < 480000000) {
@ -1614,6 +4777,8 @@ static void rfm22_setNominalCarrierFrequency(struct pios_rfm22b_dev *rfm22b_dev,
} else {
hbsel = 1;
}
float freq_mhz = (float)(frequency_hz) / 1000000.0f;
float xtal_freq_khz = 30000.0f;
float sfreq = freq_mhz / (10.0f * (xtal_freq_khz / 30000.0f) * (1 + hbsel));
@ -1622,79 +4787,187 @@ static void rfm22_setNominalCarrierFrequency(struct pios_rfm22b_dev *rfm22b_dev,
uint8_t fch = (fc >> 8) & 0xff;
uint8_t fcl = fc & 0xff;
// Claim the SPI bus.
/*
* Claim
* the
* SPI
* bus. */
rfm22_claimBus(rfm22b_dev);
// Setthe frequency hopping step size.
/*
* Setthe
* frequency
* hopping
* step
* size. */
rfm22_write(rfm22b_dev, RFM22_frequency_hopping_step_size, freq_hop_step_size);
// frequency hopping channel (0-255)
/*
* frequency
* hopping
* channel
* (0-255) */
rfm22b_dev->frequency_step_size = 156.25f * hbsel;
// frequency hopping channel (0-255)
/*
* frequency
* hopping
* channel
* (0-255) */
rfm22b_dev->channel = init_chan;
rfm22_write(rfm22b_dev, RFM22_frequency_hopping_channel_select, init_chan);
// no frequency offset
/*
* no
* frequency
* offset */
rfm22_write(rfm22b_dev, RFM22_frequency_offset1, 0);
rfm22_write(rfm22b_dev, RFM22_frequency_offset2, 0);
// set the carrier frequency
/*
* set
* the
* carrier
* frequency */
rfm22_write(rfm22b_dev, RFM22_frequency_band_select, fb & 0xff);
rfm22_write(rfm22b_dev, RFM22_nominal_carrier_frequency1, fch);
rfm22_write(rfm22b_dev, RFM22_nominal_carrier_frequency0, fcl);
// Release the bus
/*
* Release
* the
* bus */
rfm22_releaseBus(rfm22b_dev);
}
/**
* Set the frequency hopping channel.
*
* @param[in] rfm33b_dev The device structure pointer.
* Set
* the
* frequency
* hopping
* channel.
*
*
* @param[in]
* rfm33b_dev
*
* The
* device
* structure
* pointer.
*/
static bool rfm22_setFreqHopChannel(struct pios_rfm22b_dev *rfm22b_dev, uint8_t channel)
static bool rfm22_setFreqHopChannel(
struct
pios_rfm22b_dev
*
rfm22b_dev,
uint8_t
channel)
{
// set the frequency hopping channel
/*
* set
* the
* frequency
* hopping
* channel */
if (rfm22b_dev->channel == channel) {
return false;
}
#ifdef PIOS_RFM22B_DEBUG_ON_TELEM
D3_LED_TOGGLE;
#endif // PIOS_RFM22B_DEBUG_ON_TELEM
#endif /*
* PIOS_RFM22B_DEBUG_ON_TELEM */
rfm22b_dev->channel = channel;
rfm22_write_claim(rfm22b_dev, RFM22_frequency_hopping_channel_select, channel);
return true;
}
/**
* Read the RFM22B interrupt and device status registers
*
* @param[in] rfm22b_dev The device structure
* Read
* the
* RFM22B
* interrupt
* and
* device
* status
* registers
*
*
* @param[in]
* rfm22b_dev
*
* The
* device
* structure
*/
static bool pios_rfm22_readStatus(struct pios_rfm22b_dev *rfm22b_dev)
{
// 1. Read the interrupt statuses with burst read
rfm22_claimBus(rfm22b_dev); // Set RC and the semaphore
/*
* 1.
* Read
* the
* interrupt
* statuses
* with
* burst
* read */
rfm22_claimBus(rfm22b_dev); /*
* Set
* RC
* and
* the
* semaphore */
uint8_t write_buf[3] = { RFM22_interrupt_status1 &0x7f, 0xFF, 0xFF };
uint8_t read_buf[3];
rfm22_assertCs(rfm22b_dev);
PIOS_SPI_TransferBlock(rfm22b_dev->spi_id, write_buf, read_buf, sizeof(write_buf), NULL);
rfm22_deassertCs(rfm22b_dev);
rfm22b_dev->status_regs.int_status_1.raw = read_buf[1];
rfm22b_dev->status_regs.int_status_2.raw = read_buf[2];
// Device status
/*
* Device
* status */
rfm22b_dev->status_regs.device_status.raw = rfm22_read(rfm22b_dev, RFM22_device_status);
// EzMAC status
/*
* EzMAC
* status */
rfm22b_dev->status_regs.ezmac_status.raw = rfm22_read(rfm22b_dev, RFM22_ezmac_status);
// Release the bus
/*
* Release
* the
* bus */
rfm22_releaseBus(rfm22b_dev);
// the RF module has gone and done a reset - we need to re-initialize the rf module
/*
* the
* RF
* module
* has
* gone
* and
* done
* a
* reset
* -
* we
* need
* to
* re-initialize
* the
* rf
* module */
if (rfm22b_dev->status_regs.int_status_2.poweron_reset) {
return false;
}
@ -1703,12 +4976,35 @@ static bool pios_rfm22_readStatus(struct pios_rfm22b_dev *rfm22b_dev)
}
/**
* Recover from a failure in receiving a packet.
*
* @param[in] rfm22b_dev The device structure
* @return enum pios_radio_event The next event to inject
* Recover
* from
* a
* failure
* in
* receiving
* a
* packet.
*
*
* @param[in]
* rfm22b_dev
*
* The
* device
* structure
*
* @return
* enum
* pios_radio_event
*
* The
* next
* event
* to
* inject
*/
static void rfm22_rxFailure(struct pios_rfm22b_dev *rfm22b_dev)
static void rfm22_rxFailure(struct pios_rfm22b_dev *rfm22b_dev)
{
rfm22b_dev->stats.rx_failure++;
rfm22b_dev->rx_buffer_wr = 0;
@ -1718,14 +5014,38 @@ static void rfm22_rxFailure(struct pios_rfm22b_dev *rfm22b_dev)
/*****************************************************************************
* Radio Transmit and Receive functions.
*
* Radio
* Transmit
* and
* Receive
* functions.
*****************************************************************************/
/**
* Start a transmit if possible
*
* @param[in] radio_dev The device structure
* @return enum pios_radio_event The next event to inject
* Start
* a
* transmit
* if
* possible
*
*
* @param[in]
* radio_dev
* The
* device
* structure
*
* @return
* enum
* pios_radio_event
*
* The
* next
* event
* to
* inject
*/
static enum pios_radio_event radio_txStart(struct pios_rfm22b_dev *radio_dev)
{
@ -1733,31 +5053,87 @@ static enum pios_radio_event radio_txStart(struct pios_rfm22b_dev *radio_dev)
uint8_t len = 0;
uint8_t max_data_len = radio_dev->max_packet_len - (radio_dev->ppm_only_mode ? 0 : RS_ECC_NPARITY);
// Don't send if it's not our turn, or if we're receiving a packet.
/*
* Don't
* send
* if
* it's
* not
* our
* turn,
* or
* if
* we're
* receiving
* a
* packet. */
if (!rfm22_timeToSend(radio_dev) || !PIOS_RFM22B_InRxWait((uint32_t)radio_dev)) {
return RADIO_EVENT_RX_MODE;
}
// Don't send anything if we're bound to a coordinator and not yet connected.
/*
* Don't
* send
* anything
* if
* we're
* bound
* to
* a
* coordinator
* and
* not
* yet
* connected. */
if (!rfm22_isCoordinator(radio_dev) && !rfm22_isConnected(radio_dev)) {
return RADIO_EVENT_RX_MODE;
}
// Should we append PPM data to the packet?
/*
* Should
* we
* append
* PPM
* data
* to
* the
* packet? */
if (radio_dev->ppm_send_mode) {
len = RFM22B_PPM_NUM_CHANNELS + (radio_dev->ppm_only_mode ? 2 : 1);
// Ensure we can fit the PPM data in the packet.
/*
* Ensure
* we
* can
* fit
* the
* PPM
* data
* in
* the
* packet. */
if (max_data_len < len) {
return RADIO_EVENT_RX_MODE;
}
// The first byte is a bitmask of valid channels.
/*
* The
* first
* byte
* is
* a
* bitmask
* of
* valid
* channels. */
p[0] = 0;
// Read the PPM input.
/*
* Read
* the
* PPM
* input. */
for (uint8_t i = 0; i < RFM22B_PPM_NUM_CHANNELS; ++i) {
int32_t val = radio_dev->ppm[i];
if ((val == PIOS_RCVR_INVALID) || (val == PIOS_RCVR_TIMEOUT)) {
p[i + 1] = 0;
} else {
@ -1765,66 +5141,144 @@ static enum pios_radio_event radio_txStart(struct pios_rfm22b_dev *radio_dev)
p[i + 1] = (val < 1000) ? 0 : ((val >= 1900) ? 255 : (uint8_t)(256 * (val - 1000) / 900));
}
}
// The last byte is a CRC.
/*
* The
* last
* byte
* is
* a
* CRC. */
if (radio_dev->ppm_only_mode) {
uint8_t crc = 0;
for (uint8_t i = 0; i < RFM22B_PPM_NUM_CHANNELS + 1; ++i) {
crc = PIOS_CRC_updateByte(crc, p[i]);
}
p[RFM22B_PPM_NUM_CHANNELS + 1] = crc;
}
}
// Append data from the com interface if applicable.
/*
* Append
* data
* from
* the
* com
* interface
* if
* applicable. */
if (!radio_dev->ppm_only_mode && radio_dev->tx_out_cb) {
// Try to get some data to send
/*
* Try
* to
* get
* some
* data
* to
* send */
bool need_yield = false;
len += (radio_dev->tx_out_cb)(radio_dev->tx_out_context, p + len, max_data_len - len, NULL, &need_yield);
}
// Always send a packet on the sync channel if this modem is a coordinator.
/*
* Always
* send
* a
* packet
* on
* the
* sync
* channel
* if
* this
* modem
* is
* a
* coordinator. */
if ((len == 0) && ((radio_dev->channel_index != 0) || !rfm22_isCoordinator(radio_dev))) {
return RADIO_EVENT_RX_MODE;
}
// Increment the packet sequence number.
/*
* Increment
* the
* packet
* sequence
* number. */
radio_dev->stats.tx_seq++;
// Add the error correcting code.
/*
* Add
* the
* error
* correcting
* code. */
if (!radio_dev->ppm_only_mode) {
if (len != 0) {
encode_data((unsigned char *)p, len, (unsigned char *)p);
encode_data((unsignedchar *)p, len, (unsigned char *)p);
}
len += RS_ECC_NPARITY;
}
// Transmit the packet.
/*
* Transmit
* the
* packet. */
PIOS_RFM22B_TransmitPacket((uint32_t)radio_dev, p, len);
return RADIO_EVENT_NUM_EVENTS;
}
/**
* Transmit packet data.
*
* @param[in] rfm22b_dev The device structure
* @return enum pios_radio_event The next event to inject
* Transmit
* packet
* data.
*
*
* @param[in]
* rfm22b_dev
* The
* device
* structure
*
* @return
* enum
* pios_radio_event
*
* The
* next
* event
* to
* inject
*/
static enum pios_radio_event radio_txData(struct pios_rfm22b_dev *radio_dev)
{
enum pios_radio_event ret_event = RADIO_EVENT_NUM_EVENTS;
pios_rfm22b_int_result res = PIOS_RFM22B_ProcessTx((uint32_t)radio_dev);
// Is the transmition complete
/*
* Is
* the
* transmition
* complete */
if (res == PIOS_RFM22B_TX_COMPLETE) {
radio_dev->tx_complete_ticks = xTaskGetTickCount();
// Is this an ACK?
/*
* Is
* this
* an
* ACK? */
ret_event = RADIO_EVENT_RX_MODE;
radio_dev->tx_packet_handle = 0;
radio_dev->tx_data_wr = radio_dev->tx_data_rd = 0;
// Start a new transaction
/*
* Start
* a
* new
* transaction */
radio_dev->packet_start_ticks = 0;
#ifdef PIOS_RFM22B_DEBUG_ON_TELEM
@ -1836,65 +5290,190 @@ static enum pios_radio_event radio_txData(struct pios_rfm22b_dev *radio_dev)
}
/**
* Switch the radio into receive mode.
*
* @param[in] rfm22b_dev The device structure
* @return enum pios_radio_event The next event to inject
* Switch
* the
* radio
* into
* receive
* mode.
*
*
* @param[in]
* rfm22b_dev
* The
* device
* structure
*
* @return
* enum
* pios_radio_event
*
* The
* next
* event
* to
* inject
*/
static enum pios_radio_event radio_setRxMode(struct pios_rfm22b_dev *rfm22b_dev)
{
if (!PIOS_RFM22B_ReceivePacket((uint32_t)rfm22b_dev, rfm22b_dev->rx_packet)) {
return RADIO_EVENT_NUM_EVENTS;
}
rfm22b_dev->packet_start_ticks = 0;
// No event generated
/*
* No
* event
* generated */
return RADIO_EVENT_NUM_EVENTS;
}
/**
* Complete the receipt of a packet.
*
* @param[in] radio_dev The device structure
* @param[in] p The packet handle of the received packet.
* @param[in] rc_len The number of bytes received.
* @return enum pios_radio_event The next event to inject
* Complete
* the
* receipt
* of
* a
* packet.
*
*
* @param[in]
* radio_dev
*
* The
* device
* structure
*
* @param[in]
* p
*
* The
* packet
* handle
* of
* the
* received
* packet.
*
* @param[in]
* rc_len
*
* The
* number
* of
* bytes
* received.
*
* @return
* enum
* pios_radio_event
*
* The
* next
* event
* to
* inject
*/
static enum pios_radio_event radio_receivePacket(struct pios_rfm22b_dev *radio_dev, uint8_t *p, uint16_t rx_len)
static enum pios_radio_event radio_receivePacket(
struct
pios_rfm22b_dev
*
radio_dev,
uint8_t
*
p,
uint16_t
rx_len)
{
bool good_packet = true;
bool corrected_packet = false;
uint8_t data_len = rx_len;
// We don't rsencode ppm only packets.
/*
* We
* don't
* rsencode
* ppm
* only
* packets. */
if (!radio_dev->ppm_only_mode) {
data_len -= RS_ECC_NPARITY;
// Attempt to correct any errors in the packet.
/*
* Attempt
* to
* correct
* any
* errors
* in
* the
* packet. */
if (data_len > 0) {
decode_data((unsigned char *)p, rx_len);
decode_data((unsignedchar *)p, rx_len);
good_packet = check_syndrome() == 0;
// We have an error. Try to correct it.
if (!good_packet && (correct_errors_erasures((unsigned char *)p, rx_len, 0, 0) != 0)) {
// We corrected it
/*
* We
* have
* an
* error.
*
* Try
* to
* correct
* it. */
if (!good_packet && (correct_errors_erasures((unsignedchar *)p, rx_len, 0, 0) != 0)) {
/*
* We
* corrected
* it */
corrected_packet = true;
}
}
}
// Should we pull PPM data off of the head of the packet?
/*
* Should
* we
* pull
* PPM
* data
* off
* of
* the
* head
* of
* the
* packet? */
if ((good_packet || corrected_packet) && radio_dev->ppm_recv_mode) {
uint8_t ppm_len = RFM22B_PPM_NUM_CHANNELS + (radio_dev->ppm_only_mode ? 2 : 1);
// Ensure the packet it long enough
/*
* Ensure
* the
* packet
* it
* long
* enough */
if (data_len < ppm_len) {
good_packet = false;
}
// Verify the CRC if this is a PPM only packet.
/*
* Verify
* the
* CRC
* if
* this
* is
* a
* PPM
* only
* packet. */
if ((good_packet || corrected_packet) && radio_dev->ppm_only_mode) {
uint8_t crc = 0;
for (uint8_t i = 0; i < RFM22B_PPM_NUM_CHANNELS + 1; ++i) {
crc = PIOS_CRC_updateByte(crc, p[i]);
}
@ -1903,48 +5482,101 @@ static enum pios_radio_event radio_receivePacket(struct pios_rfm22b_dev *radio_d
corrected_packet = false;
}
}
if (good_packet || corrected_packet) {
for (uint8_t i = 0; i < RFM22B_PPM_NUM_CHANNELS; ++i) {
// Is this a valid channel?
/*
* Is
* this
* a
* valid
* channel? */
if (p[0] & (1 << i)) {
uint32_t val = p[i + 1];
radio_dev->ppm[i] = (uint16_t)(1000 + val * 900 / 256);
} else {
radio_dev->ppm[i] = PIOS_RCVR_INVALID;
}
}
p += RFM22B_PPM_NUM_CHANNELS + 1;
data_len -= RFM22B_PPM_NUM_CHANNELS + 1;
// Call the PPM received callback if it's available.
/*
* Call
* the
* PPM
* received
* callback
* if
* it's
* available. */
if (radio_dev->ppm_callback) {
radio_dev->ppm_callback(radio_dev->ppm);
}
}
}
// Set the packet status
/*
* Set
* the
* packet
* status */
if (good_packet) {
rfm22b_add_rx_status(radio_dev, RADIO_GOOD_RX_PACKET);
} else if (corrected_packet) {
// We corrected the error.
/*
* We
* corrected
* the
* error. */
rfm22b_add_rx_status(radio_dev, RADIO_CORRECTED_RX_PACKET);
} else {
// We couldn't correct the error, so drop the packet.
/*
* We
* couldn't
* correct
* the
* error,
* so
* drop
* the
* packet. */
rfm22b_add_rx_status(radio_dev, RADIO_ERROR_RX_PACKET);
}
enum pios_radio_event ret_event = RADIO_EVENT_RX_COMPLETE;
if (good_packet || corrected_packet) {
// Send the data to the com port
/*
* Send
* the
* data
* to
* the
* com
* port */
bool rx_need_yield;
if (radio_dev->rx_in_cb && (data_len > 0) && !radio_dev->ppm_only_mode) {
(radio_dev->rx_in_cb)(radio_dev->rx_in_context, p, data_len, NULL, &rx_need_yield);
}
// We only synchronize the clock on packets from our coordinator on the sync channel.
/*
* We
* only
* synchronize
* the
* clock
* on
* packets
* from
* our
* coordinator
* on
* the
* sync
* channel. */
if (!rfm22_isCoordinator(radio_dev) && (radio_dev->rx_destination_id == rfm22_destinationID(radio_dev)) && (radio_dev->channel_index == 0)) {
rfm22_synchronizeClock(radio_dev);
radio_dev->stats.link_state = OPLINKSTATUS_LINKSTATE_CONNECTED;
@ -1958,10 +5590,28 @@ static enum pios_radio_event radio_receivePacket(struct pios_rfm22b_dev *radio_d
}
/**
* Receive the packet data.
*
* @param[in] rfm22b_dev The device structure
* @return enum pios_radio_event The next event to inject
* Receive
* the
* packet
* data.
*
*
* @param[in]
* rfm22b_dev
* The
* device
* structure
*
* @return
* enum
* pios_radio_event
*
* The
* next
* event
* to
* inject
*/
static enum pios_radio_event radio_rxData(struct pios_rfm22b_dev *radio_dev)
{
@ -1971,14 +5621,21 @@ static enum pios_radio_event radio_rxData(struct pios_rfm22b_dev *radio_dev)
switch (res) {
case PIOS_RFM22B_RX_COMPLETE:
// Receive the packet.
/*
* Receive
* the
* packet. */
ret_event = radio_receivePacket(radio_dev, radio_dev->rx_packet_handle, radio_dev->rx_buffer_wr);
radio_dev->rx_buffer_wr = 0;
#ifdef PIOS_RFM22B_DEBUG_ON_TELEM
D2_LED_OFF;
#endif
// Start a new transaction
/*
* Start
* a
* new
* transaction */
radio_dev->packet_start_ticks = 0;
break;
@ -1988,7 +5645,9 @@ static enum pios_radio_event radio_rxData(struct pios_rfm22b_dev *radio_dev)
break;
default:
// do nothing.
/*
* do
* nothing. */
break;
}
@ -1996,23 +5655,43 @@ static enum pios_radio_event radio_rxData(struct pios_rfm22b_dev *radio_dev)
}
/*****************************************************************************
* Link Statistics Functions
*
* Link
* Statistics
* Functions
*****************************************************************************/
/**
* Update the modem pair status.
*
* @param[in] rfm22b_dev The device structure
* Update
* the
* modem
* pair
* status.
*
*
* @param[in]
* rfm22b_dev
*
* The
* device
* structure
*/
static void rfm22_updatePairStatus(struct pios_rfm22b_dev *radio_dev)
static void rfm22_updatePairStatus(struct pios_rfm22b_dev *radio_dev)
{
int8_t rssi = radio_dev->rssi_dBm;
int8_t afc = radio_dev->afc_correction_Hz;
uint32_t id = radio_dev->rx_destination_id;
int8_t rssi = radio_dev->rssi_dBm;
int8_t afc = radio_dev->afc_correction_Hz;
uint32_t id = radio_dev->rx_destination_id;
// Have we seen this device recently?
bool found = false;
uint8_t id_idx = 0;
/*
* Have
* we
* seen
* this
* device
* recently? */
boolfound = false;
uint8_tid_idx = 0;
for (; id_idx < OPLINKSTATUS_PAIRIDS_NUMELEM; ++id_idx) {
if (radio_dev->pair_stats[id_idx].pairID == id) {
@ -2020,16 +5699,43 @@ static void rfm22_updatePairStatus(struct pios_rfm22b_dev *radio_dev)
break;
}
}
// If we have seen it, update the RSSI and reset the last contact counter
/*
* If
* we
* have
* seen
* it,
* update
* the
* RSSI
* and
* reset
* the
* last
* contact
* counter */
if (found) {
radio_dev->pair_stats[id_idx].rssi = rssi;
radio_dev->pair_stats[id_idx].afc_correction = afc;
radio_dev->pair_stats[id_idx].lastContact = 0;
} else {
// If we haven't seen it, find a slot to put it in.
/*
* If
* we
* haven't
* seen
* it,
* find
* a
* slot
* to
* put
* it
* in. */
uint8_t min_idx = 0;
int8_t min_rssi = radio_dev->pair_stats[0].rssi;
for (id_idx = 1; id_idx < OPLINKSTATUS_PAIRIDS_NUMELEM; ++id_idx) {
if (radio_dev->pair_stats[id_idx].rssi < min_rssi) {
min_rssi = radio_dev->pair_stats[id_idx].rssi;
@ -2044,53 +5750,180 @@ static void rfm22_updatePairStatus(struct pios_rfm22b_dev *radio_dev)
}
/**
* Calculate the link quality from the packet receipt, tranmittion statistics.
*
* @param[in] rfm22b_dev The device structure
* Calculate
* the
* link
* quality
* from
* the
* packet
* receipt,
* tranmittion
* statistics.
*
*
* @param[in]
* rfm22b_dev
*
* The
* device
* structure
*/
static void rfm22_calculateLinkQuality(struct pios_rfm22b_dev *rfm22b_dev)
static void rfm22_calculateLinkQuality(struct pios_rfm22b_dev *rfm22b_dev)
{
// Add the RX packet statistics
/*
* Add
* the
* RX
* packet
* statistics */
rfm22b_dev->stats.rx_good = 0;
rfm22b_dev->stats.rx_corrected = 0;
rfm22b_dev->stats.rx_error = 0;
rfm22b_dev->stats.tx_resent = 0;
for (uint8_t i = 0; i < RFM22B_RX_PACKET_STATS_LEN; ++i) {
uint32_t val = rfm22b_dev->rx_packet_stats[i];
for (uint8_t j = 0; j < 16; ++j) {
switch ((val >> (j * 2)) & 0x3) {
case RADIO_GOOD_RX_PACKET:
rfm22b_dev->stats.rx_good++;
break;
case RADIO_CORRECTED_RX_PACKET:
rfm22b_dev->stats.rx_corrected++;
break;
case RADIO_ERROR_RX_PACKET:
rfm22b_dev->stats.rx_error++;
break;
case RADIO_RESENT_TX_PACKET:
rfm22b_dev->stats.tx_resent++;
break;
}
}
}
/*
* Calculate
* the
* link
* quality
* metric,
* which
* is
* related
* to
* the
* number
* of
* good
* packets
* in
* relation
* to
* the
* number
* of
* bad
* packets.
* Note:
* This
* assumes
* that
* the
* number
* of
* packets
* sampled
* for
* the
* stats
* is
* 64.
* Using
* this
* equation,
* error
* and
* resent
* packets
* are
* counted
* as
* -2,
* and
* corrected
* packets
* are
* counted
* as
* -1.
* The
* range
* is
* 0
* (all
* error
* or
* resent
* packets)
* to
* 128
* (all
* good
* packets).
// Calculate the link quality metric, which is related to the number of good packets in relation to the number of bad packets.
// Note: This assumes that the number of packets sampled for the stats is 64.
// Using this equation, error and resent packets are counted as -2, and corrected packets are counted as -1.
// The range is 0 (all error or resent packets) to 128 (all good packets).
*/
rfm22b_dev->stats.link_quality = 64 + rfm22b_dev->stats.rx_good - rfm22b_dev->stats.rx_error - rfm22b_dev->stats.tx_resent;
}
/**
* Add a status value to the RX packet status array.
*
* @param[in] rfm22b_dev The device structure
* @param[in] status The packet status value
* Add
* a
* status
* value
* to
* the
* RX
* packet
* status
* array.
*
*
* @param[in]
* rfm22b_dev
*
* The
* device
* structure
*
* @param[in]
* status
*
* The
* packet
* status
* value
*/
static void rfm22b_add_rx_status(struct pios_rfm22b_dev *rfm22b_dev, enum pios_rfm22b_rx_packet_status status)
static void rfm22b_add_rx_status(
struct
pios_rfm22b_dev
*
rfm22b_dev,
enum
pios_rfm22b_rx_packet_status
status)
{
// Shift the status registers
/*
* Shift
* the
* status
* registers */
for (uint8_t i = RFM22B_RX_PACKET_STATS_LEN - 1; i > 0; --i) {
rfm22b_dev->rx_packet_stats[i] = (rfm22b_dev->rx_packet_stats[i] << 2) | (rfm22b_dev->rx_packet_stats[i - 1] >> 30);
}
@ -2099,26 +5932,58 @@ static void rfm22b_add_rx_status(struct pios_rfm22b_dev *rfm22b_dev, enum pios_r
/*****************************************************************************
* Connection Handling Functions
*
* Connection
* Handling
* Functions
*****************************************************************************/
/**
* Are we a coordinator modem?
*
* @param[in] rfm22b_dev The device structure
* Are
* we
* a
* coordinator
* modem?
*
*
* @param[in]
* rfm22b_dev
*
* The
* device
* structure
*/
static bool rfm22_isCoordinator(struct pios_rfm22b_dev *rfm22b_dev)
static bool rfm22_isCoordinator(struct pios_rfm22b_dev *rfm22b_dev)
{
return rfm22b_dev->coordinator;
}
/**
* Returns the destination ID to send packets to.
*
* @param[in] rfm22b_id The RFM22B device index.
* @return The destination ID
* Returns
* the
* destination
* ID
* to
* send
* packets
* to.
*
*
* @param[in]
* rfm22b_id
* The
* RFM22B
* device
* index.
*
* @return
* The
* destination
* ID
*/
uint32_t rfm22_destinationID(struct pios_rfm22b_dev *rfm22b_dev)
uint32_t rfm22_destinationID(struct pios_rfm22b_dev *rfm22b_dev)
{
if (rfm22_isCoordinator(rfm22b_dev)) {
return rfm22b_dev->deviceID;
@ -2131,56 +5996,193 @@ uint32_t rfm22_destinationID(struct pios_rfm22b_dev *rfm22b_dev)
/*****************************************************************************
* Frequency Hopping Functions
*
* Frequency
* Hopping
* Functions
*****************************************************************************/
/**
* Synchronize the clock after a packet receive from our coordinator on the syncronization channel.
* This function should be called when a packet is received on the synchronization channel.
*
* @param[in] rfm22b_dev The device structure
* Synchronize
* the
* clock
* after
* a
* packet
* receive
* from
* our
* coordinator
* on
* the
* syncronization
* channel.
*
* This
* function
* should
* be
* called
* when
* a
* packet
* is
* received
* on
* the
* synchronization
* channel.
*
*
* @param[in]
* rfm22b_dev
*
* The
* device
* structure
*/
static void rfm22_synchronizeClock(struct pios_rfm22b_dev *rfm22b_dev)
static void rfm22_synchronizeClock(struct pios_rfm22b_dev *rfm22b_dev)
{
portTickType start_time = rfm22b_dev->packet_start_ticks;
// This packet was transmitted on channel 0, calculate the time delta that will force us to transmit on channel 0 at the time this packet started.
uint8_t num_chan = num_channels[rfm22b_dev->datarate];
uint16_t frequency_hop_cycle_time = rfm22b_dev->packet_time * num_chan;
uint16_t time_delta = start_time % frequency_hop_cycle_time;
/*
* This
* packet
* was
* transmitted
* on
* channel
* 0,
* calculate
* the
* time
* delta
* that
* will
* force
* us
* to
* transmit
* on
* channel
* 0
* at
* the
* time
* this
* packet
* started. */
uint8_tnum_chan = num_channels[rfm22b_dev->datarate];
uint16_tfrequency_hop_cycle_time = rfm22b_dev->packet_time * num_chan;
uint16_ttime_delta = start_time % frequency_hop_cycle_time;
// Calculate the adjustment for the preamble
uint8_t offset = (uint8_t)ceil(35000.0F / data_rate[rfm22b_dev->datarate]);
/*
* Calculate
* the
* adjustment
* for
* the
* preamble */
uint8_toffset = (uint8_t)ceil(35000.0F / data_rate[rfm22b_dev->datarate]);
rfm22b_dev->time_delta = frequency_hop_cycle_time - time_delta + offset;
}
/**
* Return the extimated current clock ticks count on the coordinator modem.
* This is the master clock used for all synchronization.
*
* @param[in] rfm22b_dev The device structure
* Return
* the
* extimated
* current
* clock
* ticks
* count
* on
* the
* coordinator
* modem.
*
* This
* is
* the
* master
* clock
* used
* for
* all
* synchronization.
*
*
* @param[in]
* rfm22b_dev
*
* The
* device
* structure
*/
static portTickType rfm22_coordinatorTime(struct pios_rfm22b_dev *rfm22b_dev, portTickType ticks)
static portTickType rfm22_coordinatorTime(
struct
pios_rfm22b_dev
*
rfm22b_dev,
portTickType
ticks)
{
if (rfm22_isCoordinator(rfm22b_dev)) {
return ticks;
}
return ticks + rfm22b_dev->time_delta;
}
/**
* Return true if this modem is in the send interval, which allows the modem to initiate a transmit.
*
* @param[in] rfm22b_dev The device structure
* Return
* true
* if
* this
* modem
* is
* in
* the
* send
* interval,
* which
* allows
* the
* modem
* to
* initiate
* a
* transmit.
*
*
* @param[in]
* rfm22b_dev
*
* The
* device
* structure
*/
static bool rfm22_timeToSend(struct pios_rfm22b_dev *rfm22b_dev)
static bool rfm22_timeToSend(struct pios_rfm22b_dev *rfm22b_dev)
{
portTickType time = rfm22_coordinatorTime(rfm22b_dev, xTaskGetTickCount());
bool is_coordinator = rfm22_isCoordinator(rfm22b_dev);
portTickType time = rfm22_coordinatorTime(rfm22b_dev, xTaskGetTickCount());
bool is_coordinator = rfm22_isCoordinator(rfm22b_dev);
// If this is a one-way link, only the coordinator can send.
uint8_t packet_period = rfm22b_dev->packet_time;
/*
* If
* this
* is
* a
* one-way
* link,
* only
* the
* coordinator
* can
* send. */
uint8_tpacket_period = rfm22b_dev->packet_time;
if (rfm22b_dev->one_way_link) {
if (is_coordinator) {
@ -2189,46 +6191,151 @@ static bool rfm22_timeToSend(struct pios_rfm22b_dev *rfm22b_dev)
return false;
}
}
if (!is_coordinator) {
time += packet_period - 1;
} else {
time -= 1;
}
return (time % (packet_period * 2)) == 0;
}
/**
* Calculate the nth channel index.
*
* @param[in] rfm22b_dev The device structure
* @param[in] index The channel index to calculate
* Calculate
* the
* nth
* channel
* index.
*
*
* @param[in]
* rfm22b_dev
*
* The
* device
* structure
*
* @param[in]
* index
*
* The
* channel
* index
* to
* calculate
*/
static uint8_t rfm22_calcChannel(struct pios_rfm22b_dev *rfm22b_dev, uint8_t index)
static uint8_t rfm22_calcChannel(
struct
pios_rfm22b_dev
*
rfm22b_dev,
uint8_t
index)
{
// Make sure we don't index outside of the range.
/*
* Make
* sure
* we
* don't
* index
* outside
* of
* the
* range. */
uint8_t num_chan = num_channels[rfm22b_dev->datarate];
uint8_t idx = index % num_chan;
// Are we switching to a new channel?
/*
* Are
* we
* switching
* to
* a
* new
* channel? */
if (idx != rfm22b_dev->channel_index) {
// If the on_sync_channel flag is set, it means that we were on the sync channel, but no packet was received, so transition to a non-connected state.
/*
* If
* the
* on_sync_channel
* flag
* is
* set,
* it
* means
* that
* we
* were
* on
* the
* sync
* channel,
* but
* no
* packet
* was
* received,
* so
* transition
* to
* a
* non-connected
* state. */
if (!rfm22_isCoordinator(rfm22b_dev) && (rfm22b_dev->channel_index == 0) && rfm22b_dev->on_sync_channel) {
rfm22b_dev->on_sync_channel = false;
// Set the link state to disconnected.
/*
* Set
* the
* link
* state
* to
* disconnected. */
if (rfm22b_dev->stats.link_state == OPLINKSTATUS_LINKSTATE_CONNECTED) {
rfm22b_dev->stats.link_state = OPLINKSTATUS_LINKSTATE_DISCONNECTED;
// Set the PPM outputs to INVALID
/*
* Set
* the
* PPM
* outputs
* to
* INVALID */
for (uint8_t i = 0; i < RFM22B_PPM_NUM_CHANNELS; ++i) {
rfm22b_dev->ppm[i] = PIOS_RCVR_INVALID;
}
}
// Stay on the sync channel.
/*
* Stay
* on
* the
* sync
* channel. */
idx = 0;
} else if (idx == 0) {
// If we're switching to the sync channel, set a flag that can be used to detect if a packet was received.
/*
* If
* we're
* switching
* to
* the
* sync
* channel,
* set
* a
* flag
* that
* can
* be
* used
* to
* detect
* if
* a
* packet
* was
* received. */
rfm22b_dev->on_sync_channel = true;
}
@ -2239,29 +6346,97 @@ static uint8_t rfm22_calcChannel(struct pios_rfm22b_dev *rfm22b_dev, uint8_t ind
}
/**
* Calculate what the current channel shold be.
*
* @param[in] rfm22b_dev The device structure
* Calculate
* what
* the
* current
* channel
* shold
* be.
*
*
* @param[in]
* rfm22b_dev
*
* The
* device
* structure
*/
static uint8_t rfm22_calcChannelFromClock(struct pios_rfm22b_dev *rfm22b_dev)
static uint8_t rfm22_calcChannelFromClock(struct pios_rfm22b_dev *rfm22b_dev)
{
portTickType time = rfm22_coordinatorTime(rfm22b_dev, xTaskGetTickCount());
// Divide time into 8ms blocks. Coordinator sends in first 2 ms, and remote send in 5th and 6th ms.
// Channel changes occur in the last 2 ms.
uint8_t num_chan = num_channels[rfm22b_dev->datarate];
uint8_t n = (time / rfm22b_dev->packet_time) % num_chan;
/*
* Divide
* time
* into
* 8ms
* blocks.
*
* Coordinator
* sends
* in
* first
* 2
* ms,
* and
* remote
* send
* in
* 5th
* and
* 6th
* ms.
* Channel
* changes
* occur
* in
* the
* last
* 2
* ms.
*/
uint8_tnum_chan = num_channels[rfm22b_dev->datarate];
uint8_tn = (time / rfm22b_dev->packet_time) % num_chan;
return rfm22_calcChannel(rfm22b_dev, n);
}
/**
* Change channels to the calculated current channel.
*
* @param[in] rfm22b_dev The device structure
* Change
* channels
* to
* the
* calculated
* current
* channel.
*
*
* @param[in]
* rfm22b_dev
*
* The
* device
* structure
*/
static bool rfm22_changeChannel(struct pios_rfm22b_dev *rfm22b_dev)
static bool rfm22_changeChannel(struct pios_rfm22b_dev *rfm22b_dev)
{
// A disconnected non-coordinator modem should sit on the sync channel until connected.
/*
* A
* disconnected
* non-coordinator
* modem
* should
* sit
* on
* the
* sync
* channel
* until
* connected. */
if (!rfm22_isCoordinator(rfm22b_dev) && !rfm22_isConnected(rfm22b_dev)) {
return rfm22_setFreqHopChannel(rfm22b_dev, rfm22_calcChannel(rfm22b_dev, 0));
} else {
@ -2271,37 +6446,88 @@ static bool rfm22_changeChannel(struct pios_rfm22b_dev *rfm22b_dev)
/*****************************************************************************
* Error Handling Functions
*
* Error
* Handling
* Functions
*****************************************************************************/
/**
* Recover from a transmit failure.
*
* @param[in] rfm22b_dev The device structure
* @return enum pios_radio_event The next event to inject
* Recover
* from
* a
* transmit
* failure.
*
*
* @param[in]
* rfm22b_dev
* The
* device
* structure
*
* @return
* enum
* pios_radio_event
*
* The
* next
* event
* to
* inject
*/
static enum pios_radio_event rfm22_txFailure(struct pios_rfm22b_dev *rfm22b_dev)
{
rfm22b_dev->stats.tx_failure++;
rfm22b_dev->packet_start_ticks = 0;
rfm22b_dev->tx_data_wr = rfm22b_dev->tx_data_rd = 0;
return RADIO_EVENT_TX_START;
}
/**
* Recover from a timeout event.
*
* @param[in] rfm22b_dev The device structure
* @return enum pios_radio_event The next event to inject
* Recover
* from
* a
* timeout
* event.
*
*
* @param[in]
* rfm22b_dev
*
* The
* device
* structure
*
* @return
* enum
* pios_radio_event
*
* The
* next
* event
* to
* inject
*/
static enum pios_radio_event rfm22_timeout(struct pios_rfm22b_dev *rfm22b_dev)
{
rfm22b_dev->stats.timeouts++;
rfm22b_dev->packet_start_ticks = 0;
// Release the Tx packet if it's set.
/*
* Release
* the
* Tx
* packet
* if
* it's
* set. */
if (rfm22b_dev->tx_packet_handle != 0) {
rfm22b_dev->tx_data_rd = rfm22b_dev->tx_data_wr = 0;
}
rfm22b_dev->rfm22b_state = RFM22B_STATE_TRANSITION;
rfm22b_dev->rx_buffer_wr = 0;
TX_LED_OFF;
@ -2312,33 +6538,92 @@ static enum pios_radio_event rfm22_timeout(struct pios_rfm22b_dev *rfm22b_dev)
D3_LED_OFF;
D4_LED_OFF;
#endif
return RADIO_EVENT_RX_MODE;
}
/**
* Recover from a severe error.
*
* @param[in] rfm22b_dev The device structure
* @return enum pios_radio_event The next event to inject
* Recover
* from
* a
* severe
* error.
*
*
* @param[in]
* rfm22b_dev
*
* The
* device
* structure
*
* @return
* enum
* pios_radio_event
*
* The
* next
* event
* to
* inject
*/
static enum pios_radio_event rfm22_error(struct pios_rfm22b_dev *rfm22b_dev)
{
rfm22b_dev->stats.resets++;
rfm22_clearLEDs();
return RADIO_EVENT_INITIALIZE;
}
/**
* A fatal error has occured in the state machine.
* this should not happen.
*
* @parem [in] rfm22b_dev The device structure
* @return enum pios_radio_event The next event to inject
* A
* fatal
* error
* has
* occured
* in
* the
* state
* machine.
*
* this
* should
* not
* happen.
*
*
* @parem
* [in]
* rfm22b_dev
*
* The
* device
* structure
*
* @return
* enum
* pios_radio_event
*
* The
* next
* event
* to
* inject
*/
static enum pios_radio_event rfm22_fatal_error(__attribute__((unused)) struct pios_rfm22b_dev *rfm22b_dev)
{
// RF module error .. flash the LED's
/*
* RF
* module
* error
* ..
* flash
* the
* LED's */
rfm22_clearLEDs();
for (unsigned int j = 0; j < 16; j++) {
USB_LED_ON;
LINK_LED_ON;
@ -2354,7 +6639,6 @@ static enum pios_radio_event rfm22_fatal_error(__attribute__((unused)) struct pi
PIOS_DELAY_WaitmS(200);
}
PIOS_DELAY_WaitmS(1000);
PIOS_Assert(0);
@ -2364,30 +6648,79 @@ static enum pios_radio_event rfm22_fatal_error(__attribute__((unused)) struct pi
/*****************************************************************************
* Utility Functions
*
* Utility
* Functions
*****************************************************************************/
/**
* Calculate the time difference between the start time and end time.
* Times are in ticks. Also handles rollover.
*
* @param[in] start_time The start time in ticks.
* @param[in] end_time The end time in ticks.
* Calculate
* the
* time
* difference
* between
* the
* start
* time
* and
* end
* time.
*
* Times
* are
* in
* ticks.
*
* Also
* handles
* rollover.
*
*
* @param[in]
* start_time
*
* The
* start
* time
* in
* ticks.
*
* @param[in]
* end_time
*
* The
* end
* time
* in
* ticks.
*/
static uint32_t pios_rfm22_time_difference_ms(portTickType start_time, portTickType end_time)
static uint32_t pios_rfm22_time_difference_ms(
portTickType
start_time,
portTickType
end_time)
{
if (end_time >= start_time) {
return (end_time - start_time) * portTICK_RATE_MS;
}
// Rollover
/*
* Rollover */
return ((portMAX_DELAY - start_time) + end_time) * portTICK_RATE_MS;
}
/**
* Allocate the device structure
*
* Allocate
* the
* device
* structure
*/
#if defined(PIOS_INCLUDE_FREERTOS)
static struct pios_rfm22b_dev *pios_rfm22_alloc(void)
static struct
pios_rfm22b_dev
*pios_rfm22_alloc(void)
{
struct pios_rfm22b_dev *rfm22b_dev;
@ -2398,11 +6731,18 @@ static struct pios_rfm22b_dev *pios_rfm22_alloc(void)
}
rfm22b_dev->magic = PIOS_RFM22B_DEV_MAGIC;
return rfm22b_dev;
}
#else
static struct pios_rfm22b_dev pios_rfm22b_devs[PIOS_RFM22B_MAX_DEVS];
static uint8_t pios_rfm22b_num_devs;
static
struct
pios_rfm22b_dev
pios_rfm22b_devs
[PIOS_RFM22B_MAX_DEVS];
static
uint8_t
pios_rfm22b_num_devs;
static struct pios_rfm22b_dev *pios_rfm22_alloc(void)
{
struct pios_rfm22b_dev *rfm22b_dev;
@ -2419,9 +6759,15 @@ static struct pios_rfm22b_dev *pios_rfm22_alloc(void)
#endif /* if defined(PIOS_INCLUDE_FREERTOS) */
/**
* Turn off all of the LEDs
*
* Turn
* off
* all
* of
* the
* LEDs
*/
static void rfm22_clearLEDs(void)
static void rfm22_clearLEDs(void)
{
LINK_LED_OFF;
RX_LED_OFF;
@ -2436,15 +6782,29 @@ static void rfm22_clearLEDs(void)
/*****************************************************************************
* SPI Read/Write Functions
*
* SPI
* Read/Write
* Functions
*****************************************************************************/
/**
* Assert the chip select line.
*
* @param[in] rfm22b_dev The RFM22B device.
* Assert
* the
* chip
* select
* line.
*
*
* @param[in]
* rfm22b_dev
*
* The
* RFM22B
* device.
*/
static void rfm22_assertCs(struct pios_rfm22b_dev *rfm22b_dev)
static void rfm22_assertCs(struct pios_rfm22b_dev *rfm22b_dev)
{
PIOS_DELAY_WaituS(1);
if (rfm22b_dev->spi_id != 0) {
@ -2453,11 +6813,24 @@ static void rfm22_assertCs(struct pios_rfm22b_dev *rfm22b_dev)
}
/**
* Deassert the chip select line.
*
* @param[in] rfm22b_dev The RFM22B device structure pointer.
* Deassert
* the
* chip
* select
* line.
*
*
* @param[in]
* rfm22b_dev
*
* The
* RFM22B
* device
* structure
* pointer.
*/
static void rfm22_deassertCs(struct pios_rfm22b_dev *rfm22b_dev)
static void rfm22_deassertCs(struct pios_rfm22b_dev *rfm22b_dev)
{
if (rfm22b_dev->spi_id != 0) {
PIOS_SPI_RC_PinSet(rfm22b_dev->spi_id, rfm22b_dev->slave_num, 1);
@ -2465,11 +6838,23 @@ static void rfm22_deassertCs(struct pios_rfm22b_dev *rfm22b_dev)
}
/**
* Claim the SPI bus.
*
* @param[in] rfm22b_dev The RFM22B device structure pointer.
* Claim
* the
* SPI
* bus.
*
*
* @param[in]
* rfm22b_dev
*
* The
* RFM22B
* device
* structure
* pointer.
*/
static void rfm22_claimBus(struct pios_rfm22b_dev *rfm22b_dev)
static void rfm22_claimBus(struct pios_rfm22b_dev *rfm22b_dev)
{
if (rfm22b_dev->spi_id != 0) {
PIOS_SPI_ClaimBus(rfm22b_dev->spi_id);
@ -2477,11 +6862,23 @@ static void rfm22_claimBus(struct pios_rfm22b_dev *rfm22b_dev)
}
/**
* Release the SPI bus.
*
* @param[in] rfm22b_dev The RFM22B device structure pointer.
* Release
* the
* SPI
* bus.
*
*
* @param[in]
* rfm22b_dev
*
* The
* RFM22B
* device
* structure
* pointer.
*/
static void rfm22_releaseBus(struct pios_rfm22b_dev *rfm22b_dev)
static void rfm22_releaseBus(struct pios_rfm22b_dev *rfm22b_dev)
{
if (rfm22b_dev->spi_id != 0) {
PIOS_SPI_ReleaseBus(rfm22b_dev->spi_id);
@ -2489,45 +6886,173 @@ static void rfm22_releaseBus(struct pios_rfm22b_dev *rfm22b_dev)
}
/**
* Claim the semaphore and write a byte to a register
*
* @param[in] rfm22b_dev The RFM22B device.
* @param[in] addr The address to write to
* @param[in] data The datat to write to that address
* Claim
* the
* semaphore
* and
* write
* a
* byte
* to
* a
* register
*
*
* @param[in]
* rfm22b_dev
*
* The
* RFM22B
* device.
*
* @param[in]
* addr
* The
* address
* to
* write
* to
*
* @param[in]
* data
* The
* datat
* to
* write
* to
* that
* address
*/
static void rfm22_write_claim(struct pios_rfm22b_dev *rfm22b_dev, uint8_t addr, uint8_t data)
static void rfm22_write_claim(
struct
pios_rfm22b_dev
*
rfm22b_dev,
uint8_t
addr,
uint8_t
data)
{
rfm22_claimBus(rfm22b_dev);
rfm22_assertCs(rfm22b_dev);
uint8_t buf[2] = { addr | 0x80, data };
PIOS_SPI_TransferBlock(rfm22b_dev->spi_id, buf, NULL, sizeof(buf), NULL);
rfm22_deassertCs(rfm22b_dev);
rfm22_releaseBus(rfm22b_dev);
}
/**
* Write a byte to a register without claiming the semaphore
*
* @param[in] rfm22b_dev The RFM22B device.
* @param[in] addr The address to write to
* @param[in] data The datat to write to that address
* Write
* a
* byte
* to
* a
* register
* without
* claiming
* the
* semaphore
*
*
* @param[in]
* rfm22b_dev
*
* The
* RFM22B
* device.
*
* @param[in]
* addr
* The
* address
* to
* write
* to
*
* @param[in]
* data
* The
* datat
* to
* write
* to
* that
* address
*/
static void rfm22_write(struct pios_rfm22b_dev *rfm22b_dev, uint8_t addr, uint8_t data)
static void rfm22_write(
struct
pios_rfm22b_dev
*
rfm22b_dev,
uint8_t
addr,
uint8_t
data)
{
rfm22_assertCs(rfm22b_dev);
uint8_t buf[2] = { addr | 0x80, data };
PIOS_SPI_TransferBlock(rfm22b_dev->spi_id, buf, NULL, sizeof(buf), NULL);
rfm22_deassertCs(rfm22b_dev);
}
/**
* Read a byte from an RFM22b register without claiming the bus
*
* @param[in] rfm22b_dev The RFM22B device structure pointer.
* @param[in] addr The address to read from
* @return Returns the result of the register read
* Read
* a
* byte
* from
* an
* RFM22b
* register
* without
* claiming
* the
* bus
*
*
* @param[in]
* rfm22b_dev
*
* The
* RFM22B
* device
* structure
* pointer.
*
* @param[in]
* addr
* The
* address
* to
* read
* from
*
* @return
* Returns
* the
* result
* of
* the
* register
* read
*/
static uint8_t rfm22_read(struct pios_rfm22b_dev *rfm22b_dev, uint8_t addr)
static uint8_t rfm22_read(
struct
pios_rfm22b_dev
*
rfm22b_dev,
uint8_t
addr)
{
uint8_t out[2] = { addr &0x7F, 0xFF };
uint8_t in[2];
@ -2535,12 +7060,15 @@ static uint8_t rfm22_read(struct pios_rfm22b_dev *rfm22b_dev, uint8_t addr)
rfm22_assertCs(rfm22b_dev);
PIOS_SPI_TransferBlock(rfm22b_dev->spi_id, out, in, sizeof(out), NULL);
rfm22_deassertCs(rfm22b_dev);
return in[1];
}
#endif /* PIOS_INCLUDE_RFM22B */
/**
* @}
* @}
*
* @}
*
* @}
*/