Initial commit

This commit is contained in:
Gatsby Van
2024-11-04 19:43:31 +08:00
parent f3fc4279b1
commit 1e44e8ea8b
124 changed files with 46332 additions and 0 deletions
+189
View File
@@ -0,0 +1,189 @@
/*****************************************************************************/
/**
* @file framing.h
* @author FanHao ([email protected])
* @brief DF Linklayer framing functions.
* @version 0.0
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup LinkLayer
* @{
*/
/**
* @addtogroup LinkLayer_Framing
* @{
*/
/***************************** Include Files *********************************/
#include <stdint.h>
#include <string.h>
#include "error.h"
#include "common.h"
#include "msg_def.h"
#include "link_layer.h"
/************************** Constant Definitions *****************************/
/*****************************************************************************/
/**
* @brief Insert a data chunk to a bit array.
*
* @param frame pointer to target bit array.
* @param offset offset of insert start position.
* @param bytes number of insert bytes
* @param chunk pointer to data chunk
*
* @return NONE
*
******************************************************************************/
void L2_FrameInsertChunk(uint8_t *frame, size_t offset, size_t bytes, const void *chunk)
{
ASSERT(frame != NULL);
ASSERT(chunk != NULL);
memcpy(frame + offset, chunk, bytes);
}
/*****************************************************************************/
/**
* @brief Get a data chunk to a frame buff.
*
* @param frame pointer to target bit array.
* @param offset offset of data chunk start position.
* @param bytes number of data bytes
* @param chunk pointer to data chunk
*
* @return NONE
*
******************************************************************************/
void L2_FrameGetChunk(uint8_t *frame, size_t offset, size_t bytes, void *chunk)
{
ASSERT(frame != NULL);
ASSERT(chunk != NULL);
memcpy(chunk, frame + offset, bytes);
}
/*****************************************************************************/
/**
* @brief Generate crc of specified data.
*
* @param dataBuff pointer to data buffer.
* @param dataLen length of specified data.
* @param crcType type of crc
* @param crc a pointer to 32 bit crc container.
*
* @return FAILURE crc type not support.
* SUCCESS
*
******************************************************************************/
static int32_t L2_CrcGen(uint8_t *dataBuff, uint32_t dataLen, L2_CRC_TYPE crcType, uint32_t *crc)
{
ASSERT(dataBuff != NULL);
int32_t Status;
switch (crcType)
{
case L2_CRC16_1021:
Status = crc16_gen(dataBuff, dataLen, 0x1021, (uint16_t *)crc);
break;
case L2_CRC16_8005:
Status = crc16_gen(dataBuff, dataLen, 0x8005, (uint16_t *)crc);
break;
case L2_CRC8_31:
Status = crc8_gen(dataBuff, dataLen, 0x31, (uint8_t *)crc);
break;
default:
Status = EPARAM;
break;
}
return Status;
}
/*****************************************************************************/
/**
* @brief Append a crc of specified data, to a specified position.
*
* @param dataBuff pointer to data buffer.
* @param dataLen length of specified data.
* @param crcPos position of crc insert position
* @param crcType type of crc
*
* @return FAILURE crc type not support.
* SUCCESS
*
******************************************************************************/
int32_t L2_CrcAppend(uint8_t *dataBuff, uint32_t dataLen, uint32_t crcPos, L2_CRC_TYPE crcType)
{
ASSERT(dataBuff != NULL);
int32_t Status;
uint32_t crcVal;
uint8_t *crcPtr;
crcPtr = dataBuff + crcPos;
Status = L2_CrcGen(dataBuff, dataLen, crcType, &crcVal);
if (Status != SUCCESS)
{
return Status;
}
switch (crcType)
{
case L2_CRC16_1021:
*(crcPtr + 1) = (uint8_t)(crcVal >> 8);
*crcPtr = (uint8_t)(crcVal);
break;
case L2_CRC16_8005:
*(crcPtr + 1) = (uint8_t)(crcVal >> 8);
*crcPtr = (uint8_t)(crcVal);
break;
case L2_CRC8_31:
*crcPtr = (uint8_t)crcVal;
break;
default:
Status = EPARAM;
break;
}
return Status;
}
/*****************************************************************************/
/**
* @brief Check data validation by crc.
*
* @param dataBuff pointer to data buffer.
* @param dataLen length of specified data.
* @param crcType type of crc
*
* @return FAILURE crc type not support.
* SUCCESS
*
******************************************************************************/
bool L2_CrcCheck(uint8_t *dataBuff, uint32_t dataLen, L2_CRC_TYPE crcType)
{
ASSERT(dataBuff != NULL);
int32_t Status;
uint32_t crcVal;
crcVal = 0;
Status = L2_CrcGen(dataBuff, dataLen, crcType, &crcVal);
if (Status == SUCCESS)
{
if (crcVal == 0)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
/** @} LinkLayer_Framing*/
/** @} LinkLayer*/
+237
View File
@@ -0,0 +1,237 @@
/*****************************************************************************/
/**
* @file coord.c
* @author FanHao ([email protected])
* @version 0.0
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup LinkLayer
* @{
*/
/**
* @addtogroup LinkLayerGeometry
* @{
*/
/**
* @addtogroup LinkLayerGeometry_Coord
* @{
*/
#include <math.h>
#include "coord.h"
const COORD COORD_NIL = {NAN, NAN, NAN};
const COORD COORD_ZERO = {0.0, 0.0, 0.0};
const COORD COORD_ONE = {1.0, 1.0, 1.0};
const COORD COORD_X_AXIS = {1.0, 0.0, 0.0};
const COORD COORD_Y_AXIS = {0.0, 1.0, 0.0};
const COORD COORD_Z_AXIS = {0.0, 0.0, 1.0};
/** @brief Subtracts two coordinate vectors. */
COORD Coord_Sub(COORD a, COORD b)
{
COORD ret;
ret.x = a.x - b.x;
ret.y = a.y - b.y;
ret.z = a.z - b.z;
return ret;
}
/** @brief Adds two coordinate vectors. */
COORD Coord_Add(COORD a, COORD b)
{
COORD ret;
ret.x = a.x + b.x;
ret.y = a.y + b.y;
ret.z = a.z + b.z;
return ret;
}
/** @brief Multiplies a coordinate vector by a real number. */
void Coord_ScalarMult(COORD *a, double t)
{
a->x *= t;
a->y *= t;
a->z *= t;
}
/** @brief Multiplies a coordinate vector by a real number. */
COORD Coord_GetScalarMult(COORD a, double t)
{
COORD ret;
ret.x = a.x * t;
ret.y = a.y * t;
ret.z = a.z * t;
return ret;
}
/** @brief Divides a coordinate vector by a real number. */
void Coord_ScalarDiv(COORD *a, double t)
{
a->x /= t;
a->y /= t;
a->z /= t;
}
/** @brief Divides a coordinate vector by a real number. */
COORD Coord_GetScalarDiv(COORD a, double t)
{
COORD ret;
ret.x = a.x / t;
ret.y = a.y / t;
ret.z = a.z / t;
return ret;
}
/** @brief Dot product. */
inline double Coord_Dot(COORD a, COORD b)
{
return (a.x * b.x + a.y * b.y + a.z * b.z);
}
/** @brief Cross product. */
COORD Coord_Cross(COORD a, COORD b)
{
COORD ret;
ret.x = a.y * b.z - a.z * b.y;
ret.y = a.z * b.x - a.x * b.z;
ret.z = a.x * b.y - a.y * b.x;
return ret;
}
/** @brief Multiplies two coordinate vector in elementwise. */
COORD Coord_ElementwiseMult(COORD a, COORD b)
{
COORD ret;
ret.x = a.x * b.x;
ret.y = a.y * b.y;
ret.z = a.z * b.z;
return ret;
}
/** @brief Divides two coordinate vector in elementwise. */
COORD Coord_ElementwiseDiv(COORD a, COORD b)
{
COORD ret;
ret.x = a.x / b.x;
ret.y = a.y / b.y;
ret.z = a.z / b.z;
return ret;
}
/** @brief Calculate a coordinate vector length^2 (omits calling square root). */
double Coord_SquareLength(COORD a)
{
return (a.x * a.x + a.y * a.y + a.z * a.z);
}
/** @brief Calculate a coordinate vector length. */
double Coord_Length(COORD a)
{
return sqrt(Coord_SquareLength(a));
}
/** @brief Calculate two coordinates' distance. */
double Coord_Distance(COORD a, COORD b)
{
return Coord_Length(Coord_Sub(a, b));
}
/** @brief Normalize coordinate vector. */
void Coord_Normalize(COORD *a)
{
Coord_ScalarDiv(a, Coord_Length(*a));
}
/** @brief Normalize coordinate vector. */
COORD Coord_GetNormalized(COORD a)
{
Coord_Normalize(&a);
return a;
}
/** @brief Returns the angle between the two vectors. */
double Coord_Angle(COORD a, COORD b)
{
Coord_Normalize(&a);
Coord_Normalize(&b);
return acos(Coord_Dot(a, b));
}
// Additional Coordinates convert
// TODO: Confirm correctness
/** @brief Convert coordinate from Launch coordinate system to ECEF. */
COORD Coord_Launch2Ecef(COORD o, COORD p, double A, double B, double lambda)
{
COORD ret;
double sinA, cosA, sinB, cosB, sinL, cosL;
double S11, S12, S13, S21, S22, S23, S31, S32, S33;
sinA = sin(A);
cosA = cos(A);
sinB = sin(B);
cosB = cos(B);
sinL = sin(lambda);
cosL = cos(lambda);
S11 = -sinA * sinL - cosA * sinB * cosL;
S12 = cosB * cosL;
S13 = -cosA * sinL + sinA * sinB * cosL;
S21 = sinA * cosL - cosA * sinB * sinL;
S22 = cosB * sinL;
S23 = cosA * cosL + sinA * sinB * sinL;
S31 = cosA * cosB;
S32 = sinB;
S33 = -sinA * cosB;
ret.x = p.x * (S11 + S21 + S31) + o.x;
ret.y = p.y * (S12 + S22 + S32) + o.y;
ret.z = p.z * (S13 + S23 + S33) + o.z;
return ret;
}
/** @brief Convert coordinate from launch coordinate system to Inertia coordinate system. */
COORD Coord_Launch2Inertia(COORD o, COORD p, double A, double B, double we, double t)
{
COORD ret;
double OmgX, OmgY, OmgZ, sinwet, coswet;
double M11, M12, M13, M21, M22, M23, M31, M32, M33;
OmgX = cos(A) * cos(B);
OmgY = sin(B);
OmgZ = -sin(A) * cos(B);
sinwet = sin(we * t);
coswet = cos(we * t);
M11 = 1 - (1 - OmgX * OmgX) * (1 - coswet);
M12 = OmgX * OmgY * (1 - coswet) + OmgZ * sinwet;
M13 = OmgX * OmgZ * (1 - coswet) - OmgY * sinwet;
M21 = OmgY * OmgX * (1 - coswet) - OmgZ * sinwet;
M22 = 1 - (1 - OmgY * OmgY) * (1 - coswet);
M23 = OmgY * OmgZ * (1 - coswet) + OmgX * sinwet;
M31 = OmgZ * OmgX * (1 - coswet) + OmgY * sinwet;
M32 = OmgZ * OmgY * (1 - coswet) - OmgX * sinwet;
M33 = 1 - (1 - OmgZ * OmgZ) * (1 - coswet);
ret.x = p.x * (M11 + M21 + M31) + o.x;
ret.y = p.y * (M12 + M22 + M32) + o.y;
ret.z = p.z * (M13 + M23 + M33) + o.z;
return ret;
}
/** @} LinkLayerGeometry_Coord */
/** @} LinkLayerGeometry */
/** @} LinkLayer */
+102
View File
@@ -0,0 +1,102 @@
/*****************************************************************************/
/**
* @file coord.h
* @author FanHao ([email protected])
* @version 0.0
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
#ifndef _COORD_H
#define _COORD_H
/**
* @addtogroup LinkLayer
* @{
*/
/**
* @defgroup LinkLayerGeometry
* @{
*/
/**
* @defgroup LinkLayerGeometry_Coord
* @{
*/
/**
* @struct COORD
* @brief Structure for storing 3D coordinates.
*/
typedef struct
{
double x;
double y;
double z;
} COORD;
extern const COORD COORD_NIL;
extern const COORD COORD_ZERO;
extern const COORD COORD_ONE;
extern const COORD COORD_X_AXIS;
extern const COORD COORD_Y_AXIS;
extern const COORD COORD_Z_AXIS;
/** @brief Subtracts two coordinate vectors. */
COORD Coord_Sub(COORD a, COORD b);
/** @brief Adds two coordinate vectors. */
COORD Coord_Add(COORD a, COORD b);
/** @brief Multiplies a coordinate vector by a real number. */
void Coord_ScalarMult(COORD *a, double t);
/** @brief Multiplies a coordinate vector by a real number. */
COORD Coord_GetScalarMult(COORD a, double t);
/** @brief Divides a coordinate vector by a real number. */
void Coord_ScalarDiv(COORD *a, double t);
/** @brief Divides a coordinate vector by a real number. */
COORD Coord_GetScalarDiv(COORD a, double t);
/** @brief Dot product. */
double Coord_Dot(COORD a, COORD b);
/** @brief Cross product. */
COORD Coord_Cross(COORD a, COORD b);
/** @brief Multiplies two coordinate vector in elementwise. */
COORD Coord_ElementwiseMult(COORD a, COORD b);
/** @brief Divides two coordinate vector in elementwise. */
COORD Coord_ElementwiseDiv(COORD a, COORD b);
/** @brief Calculate a coordinate vector length^2 (omits calling square root). */
double Coord_SquareLength(COORD a);
/** @brief Calculate a coordinate vector length. */
double Coord_Length(COORD a);
/** @brief Calculate two coordinates' distance. */
double Coord_Distance(COORD a, COORD b);
/** @brief Normalize coordinate vector. */
void Coord_Normalize(COORD *a);
/** @brief Normalize coordinate vector. */
COORD Coord_GetNormalized(COORD a);
/** @brief Returns the angle between the two vectors. */
double Coord_Angle(COORD a, COORD b);
#endif
/** @} LinkLayerGeometry_Coord */
/** @} LinkLayerGeometry */
/** @} LinkLayer */
@@ -0,0 +1,88 @@
/*****************************************************************************/
/**
* @file eulerangles.c
* @author FanHao ([email protected])
* @version 0.0
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup LinkLayer
* @{
*/
/**
* @addtogroup LinkLayerGeometry
* @{
*/
/**
* @addtogroup LinkLayerGeometry_EulerAngles
* @{
*/
#include <math.h>
#include "eulerangles.h"
const EULERANGLES EULERANGLES_NIL = {NAN, NAN, NAN};
const EULERANGLES EULERANGLES_ZERO = {0.0, 0.0, 0.0};
/** @brief Add two EulerAngles. */
EULERANGLES EulerAngles_Add(EULERANGLES e1, EULERANGLES e2)
{
EULERANGLES ret;
ret.alpha = e1.alpha + e2.alpha;
ret.beta = e1.beta + e2.beta;
ret.gamma = e1.gamma + e2.gamma;
return ret;
}
/** @brief Subtracts two EulerAngles. */
EULERANGLES EulerAngles_Sub(EULERANGLES e1, EULERANGLES e2)
{
EULERANGLES ret;
ret.alpha = e1.alpha - e2.alpha;
ret.beta = e1.beta - e2.beta;
ret.gamma = e1.gamma - e2.gamma;
return ret;
}
/** @brief Multiplies EulerAngles by a real number. */
void EulerAngles_ScalarMult(EULERANGLES *e, double f)
{
e->alpha *= f;
e->beta *= f;
e->gamma *= f;
}
/** @brief Multiplies EulerAngles by a real number. */
EULERANGLES EulerAngles_GetScalarMult(EULERANGLES e, double f)
{
EulerAngles_ScalarMult(&e, f);
return e;
}
/** @brief Normalize EulerAngles. */
void EulerAngles_Normalize(EULERANGLES *e)
{
e->alpha = fmod(e->alpha, 2 * EUL_PI);
e->beta = fmod(e->beta, 2 * EUL_PI);
e->gamma = fmod(e->gamma, 2 * EUL_PI);
}
/** @brief Normalize EulerAngles. */
EULERANGLES EulerAngles_GetNormalize(EULERANGLES e)
{
EulerAngles_Normalize(&e);
return e;
}
/** @} LinkLayerGeometry_EulerAngles */
/** @} LinkLayerGeometry */
/** @} LinkLayer */
@@ -0,0 +1,93 @@
/*****************************************************************************/
/**
* @file eulerangles.h
* @author FanHao ([email protected])
* @version 0.0
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup LinkLayer
* @{
*/
/**
* @addtogroup LinkLayerGeometry
* @{
*/
/**
* @defgroup LinkLayerGeometry_EulerAngles
* @{
*/
#ifndef __EULERANGLES_H
#define __EULERANGLES_H
#define EUL_PI 3.14159265358979323846
#define DEG2RAD(d) ((EUL_PI / 180.0) * d)
#define RAD2DEG(r) ((180.0 / EUL_PI) * r)
/**
* Orientations are represented by 3D double precision Tait-Bryan (Euler) tuples
* called EulerAngles. The angles are in Z, Y', X" order that is often called
* intrinsic rotations, they are measured in radians. The default (unrotated)
* orientation is along the X axis. Conceptually, the Z axis rotation is heading,
* the Y' axis rotation is descending (negative elevation), the X" axis rotation is bank.
* For example, positive rotation along the Z axis rotates X into Y (turns left), positive
* rotation along the Y axis rotates Z into X (leans forward), positive rotation
* along the X axis rotates Y into Z (leans right).
*/
/**
* @struct EULERANGLES
* @brief Structure for standard quaternion
*/
typedef struct
{
double alpha; // unit rad
double beta; // unit rad
double gamma; // unit rad
} EULERANGLES;
typedef enum
{
EULERANGLES_NONE = 0,
EULERANGLES_ZYX = 1,
EULERANGLES_ZYZ = 2,
EULERANGLES_XYZ = 3,
} EULERANGLES_TYPE;
extern const EULERANGLES EULERANGLES_ZERO;
extern const EULERANGLES EULERANGLES_NIL;
/** @brief Add two EulerAngles. */
EULERANGLES EulerAngles_Add(EULERANGLES e1, EULERANGLES e2);
/** @brief Subtracts two EulerAngles. */
EULERANGLES EulerAngles_Sub(EULERANGLES e1, EULERANGLES e2);
/** @brief Multiplies EulerAngles by a real number. */
void EulerAngles_ScalarMult(EULERANGLES *e, double f);
/** @brief Multiplies EulerAngles by a real number. */
EULERANGLES EulerAngles_GetScalarMult(EULERANGLES e, double f);
/** @brief Normalize EulerAngles. */
void EulerAngles_Normalize(EULERANGLES *e);
/** @brief Normalize EulerAngles. */
EULERANGLES EulerAngles_GetNormalize(EULERANGLES e);
#endif
/** @} LinkLayerGeometry_EulerAngles */
/** @} LinkLayerGeometry */
/** @} LinkLayer */
@@ -0,0 +1,480 @@
/*****************************************************************************/
/**
* @file quaternion.c
* @author FanHao ([email protected])
* @version 0.0
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup LinkLayer
* @{
*/
/**
* @addtogroup LinkLayerGeometry
* @{
*/
/**
* @addtogroup LinkLayerGeometry_Quaternion
* @{
*/
#include <math.h>
#include <stdint.h>
#include <stdbool.h>
#include "coord.h"
#include "eulerangles.h"
#include "quaternion.h"
typedef union
{
float value;
uint32_t raw;
} SOFT_FLOAT;
typedef union
{
double value;
uint64_t raw;
} SOFT_DOUBLE;
const SOFT_FLOAT EPS_FLOAT = {.raw = 0x34000000};
const SOFT_DOUBLE EPS_DOUBLE = {.raw = 0x3CB0000000000000};
const QUATERNION QUATERNION_IDENTITY = {1.0, 0.0, 0.0, 0.0};
const QUATERNION QUATERNION_NIL = {NAN, NAN, NAN, NAN};
/** @brief Subtracts two quaternions. */
QUATERNION Quaternion_Sub(QUATERNION q1, QUATERNION q2)
{
QUATERNION ret;
ret.s = q1.s - q2.s;
ret.i = q1.i - q2.i;
ret.j = q1.j - q2.j;
ret.k = q1.k - q2.k;
return ret;
}
/** @brief Adds two quaternions. */
QUATERNION Quaternion_Add(QUATERNION q1, QUATERNION q2)
{
QUATERNION ret;
ret.s = q1.s + q2.s;
ret.i = q1.i + q2.i;
ret.j = q1.j + q2.j;
ret.k = q1.k + q2.k;
return ret;
}
/** @brief Multiplies a quaternion by a real number. */
void Quaternion_ScalarMult(QUATERNION *q, double t)
{
q->s *= t;
q->i *= t;
q->j *= t;
q->k *= t;
}
/** @brief Multiplies a quaternion by a real number. */
QUATERNION Quaternion_GetScalarMult(QUATERNION a, double t)
{
Quaternion_ScalarMult(&a, t);
return a;
}
/** @brief Divides a quaternion by a real number. */
void Quaternion_ScalarDiv(QUATERNION *q, double t)
{
q->s /= t;
q->i /= t;
q->j /= t;
q->k /= t;
}
/** @brief Divides a quaternion by a real number. */
QUATERNION Quaternion_GetScalarDiv(QUATERNION q, double t)
{
Quaternion_ScalarDiv(&q, t);
return q;
}
/** @brief Multiplies two quaternions. */
QUATERNION Quaternion_Mult(QUATERNION q1, QUATERNION q2)
{
QUATERNION ret;
ret.s = q1.s * q2.s - (q1.i * q2.i + q1.j * q2.j + q1.k * q2.k);
ret.i = q1.j * q2.k - q1.k * q2.j + q1.s * q2.i + q1.i * q2.s;
ret.j = q1.k * q2.i - q1.i * q2.k + q1.s * q2.j + q1.j * q2.s;
ret.k = q1.i * q2.j - q1.j * q2.i + q1.s * q2.k + q1.k * q2.s;
return ret;
}
/** @brief Divides two quaternions. */
QUATERNION Quaternion_Div(QUATERNION q1, QUATERNION q2)
{
Quaternion_Inverse(&q2);
return Quaternion_Mult(q1, q2);
}
/** @brief Dot product. */
inline double Quaternion_Dot(QUATERNION q1, QUATERNION q2)
{
return (q1.s * q2.s + q1.i * q2.i + q1.j * q2.j + q1.k * q2.k);
}
/** @brief Calculate a quaternion length^2 (omits calling square root). */
inline double Quaternion_SquareLength(QUATERNION q)
{
return (q.s * q.s + q.i * q.i + q.j * q.j + q.k * q.k);
}
/** @brief Calculate a quaternion length. */
inline double Quaternion_Length(QUATERNION q)
{
return sqrt(Quaternion_SquareLength(q));
}
/** @brief Normalize quaternion. */
void Quaternion_Normalize(QUATERNION *q)
{
Quaternion_ScalarDiv(q, Quaternion_Length(*q));
}
/** @brief Normalize quaternion. */
QUATERNION Quaternion_GetNormalized(QUATERNION q)
{
Quaternion_Normalize(&q);
return q;
}
/** @brief Conjugated quaternion. */
void Quaternion_Conjugated(QUATERNION *q)
{
q->i = -q->i;
q->j = -q->j;
q->k = -q->k;
}
/** @brief Conjugated quaternion. */
QUATERNION Quaternion_GetConjugated(QUATERNION q)
{
Quaternion_Conjugated(&q);
return q;
}
/** @brief Inverse quaternion. */
void Quaternion_Inverse(QUATERNION *q)
{
Quaternion_Conjugated(q);
Quaternion_ScalarDiv(q, Quaternion_SquareLength(*q));
}
/** @brief Inverse quaternion. */
QUATERNION Quaternion_GeInverse(QUATERNION q)
{
Quaternion_Inverse(&q);
return q;
}
inline double Quaternion_GetRotationAngle(QUATERNION q)
{
return (acos(q.s) * 2);
}
/** @brief Get axis of quaternion. */
COORD Quaternion_GetRotationAxis(QUATERNION q)
{
double sin_theta_inv;
COORD ret;
sin_theta_inv = 1.0 / sin(acos(q.s));
ret.x = q.i * sin_theta_inv;
ret.y = q.j * sin_theta_inv;
ret.z = q.k * sin_theta_inv;
return ret;
}
/** @brief Get the axis and rotate angle of a unit Quaternion */
void Quaternion_GetRotationAxisAndAngle(QUATERNION q, COORD *axis, double *angle)
{
double sin_theta_inv;
*angle = acos(q.s);
// pre-compute to save time
sin_theta_inv = 1.0 / sin(*angle);
// now the vector
axis->x = q.i * sin_theta_inv;
axis->y = q.j * sin_theta_inv;
axis->z = q.k * sin_theta_inv;
*angle = (*angle) * 2;
}
/** @brief Decompose the rotation on to 2 parts. */
void Quaternion_GetSwingAndTwist(QUATERNION q, COORD axis, QUATERNION *swing, QUATERNION *twist)
{
double p;
COORD v;
v.x = q.i;
v.y = q.j;
v.z = q.k;
// return projection v1 on to v2 (parallel component)
p = Coord_Dot(v, axis);
v = Coord_GetScalarMult(axis, p);
twist->s = q.s;
twist->i = v.x;
twist->j = v.y;
twist->k = v.z;
Quaternion_Normalize(twist);
*swing = Quaternion_Mult(q, Quaternion_GetConjugated(*twist));
}
/** @brief rotates v by this quaternion (quaternion must be unit) */
COORD Quaternion_Rotate(QUATERNION q, COORD v)
{
QUATERNION temp;
COORD ret;
temp.s = 0;
temp.i = v.x;
temp.j = v.y;
temp.k = v.z;
temp = Quaternion_Mult(q, temp);
Quaternion_Conjugated(&q);
temp = Quaternion_Mult(temp, q);
ret.x = temp.i;
ret.y = temp.j;
ret.z = temp.k;
return ret;
}
/** @brief returns the euler angles from a rotation Quaternion */
EULERANGLES Quaternion_ToEulerAngles(QUATERNION q, EULERANGLES_TYPE type)
{
EULERANGLES ret;
switch (type)
{
case EULERANGLES_ZYX:
{
/* Covert form matlab 2023a */
// Cap all inputs to asin to 1, since values >1 produce complex
// results
// Since the quaternion is of unit length, this should never happen,
// but some code generation configuration seem to hit this edge case
// under some circumstances.
double asinValue;
bool mask1, mask2;
asinValue = -2.0 * (q.i * q.k - q.s * q.j);
mask1 = asinValue >= 1.0 - 10 * EPS_DOUBLE.value;
mask2 = asinValue <= -1.0 + 10 * EPS_DOUBLE.value;
if (mask1)
asinValue = 1;
if (mask2)
asinValue = -1;
if (mask1 || mask2)
{
ret.alpha = (asinValue > 0) ? (-2.0 * atan2(q.i, q.s)) : (2.0 * atan2(q.i, q.s));
ret.gamma = 0;
}
else
{
ret.alpha = atan2(2.0 * (q.i * q.j + q.s * q.k), q.s * q.s + q.i * q.i - q.j * q.j - q.k * q.k);
ret.gamma = atan2(2.0 * (q.j * q.k + q.s * q.i), q.s * q.s - q.i * q.i - q.j * q.j + q.k * q.k);
}
ret.beta = asin(asinValue);
break;
}
case EULERANGLES_ZYZ:
{
// TODO;
ret = EULERANGLES_NIL;
break;
}
case EULERANGLES_XYZ:
{
/* Covert form matlab 2023a */
// Prevent singularities as done in ZYX case
// Alternative to rotm2eul(quat2rotm(q), 'XYZ') with fewer
// operations
// sin(y) = R13 = 2 * (qx*qz + qy*qw)
// tan(x) = sin(x) / cos(x) = -R23 / R33
// = -2 * (qy*qz - qx*qw) / (1 - 2*(qx^2 + qy^2))
// = -2 * (qy*qz - qx*qw) / (qw^2 - qx^2 - qy^2 + qz^2)
// tan(z) = sin(z) / cos(z) = -R12 / R11
// = -2 * (qx*qy - qz*qw) / (1 - 2*(qy^2 + qz^2))
// = -2 * (qy*qz - qx*qw) / (qw^2 + qx^2 - qy^2 - qz^2)
double asinValue;
bool mask1, mask2;
asinValue = 2.0 * (q.i * q.k + q.s * q.j);
mask1 = asinValue >= 1.0 - 10 * EPS_DOUBLE.value;
mask2 = asinValue <= -1.0 + 10 * EPS_DOUBLE.value;
if (mask1)
asinValue = 1;
if (mask2)
asinValue = -1;
if (mask1 || mask2)
{
ret.alpha = 0;
ret.gamma = (asinValue > 0) ? (2.0 * atan2(q.i, q.s)) : (-2.0 * atan2(q.i, q.s));
}
else
{
ret.alpha = atan2(-2.0 * (q.j * q.k - q.s * q.i), q.s * q.s - q.i * q.i - q.j * q.j + q.k * q.k);
ret.gamma = atan2(-2.0 * (q.i * q.j - q.s * q.k), q.s * q.s + q.i * q.i - q.j * q.j - q.k * q.k);
}
ret.beta = asin(asinValue);
break;
}
default:
ret = EULERANGLES_NIL;
}
return ret;
}
/** @brief returns the rotation Quaternion from a euler angles */
QUATERNION Quaternion_FromeEulerAngles(EULERANGLES e, EULERANGLES_TYPE type)
{
QUATERNION ret;
double cosx, sinx, cosy, siny, cosz, sinz;
cosx = cos(e.alpha * 0.5);
sinx = sin(e.alpha * 0.5);
cosy = cos(e.beta * 0.5);
siny = sin(e.beta * 0.5);
cosz = cos(e.gamma * 0.5);
sinz = sin(e.gamma * 0.5);
switch (type)
{
case EULERANGLES_ZYX:
ret.s = cosx * cosy * cosz + sinx * siny * sinz;
ret.i = cosx * cosy * sinz - sinx * siny * cosz;
ret.j = cosx * siny * cosz + sinx * cosy * sinz;
ret.k = sinx * cosy * cosz - cosx * siny * sinz;
break;
case EULERANGLES_ZYZ:
ret.s = cosx * cosy * cosz - sinx * cosy * sinz;
ret.i = cosx * siny * sinz - sinx * siny * cosz;
ret.j = cosx * siny * cosz + sinx * siny * sinz;
ret.k = sinx * cosy * cosz + cosx * cosy * sinz;
break;
case EULERANGLES_XYZ:
ret.s = cosx * cosy * cosz - sinx * siny * sinz;
ret.i = sinx * cosy * cosz + cosx * siny * sinz;
ret.j = -sinx * cosy * sinz + cosx * siny * cosz;
ret.k = cosx * cosy * sinz + sinx * siny * cosz;
break;
default:
ret = QUATERNION_NIL;
break;
}
return ret;
}
/** @brief adapted from https://svn.code.sf.net/p/irrlicht/code/trunk/include/quaternion.h */
QUATERNION Quaternion_RotationFromTo(COORD from, COORD to)
{
// Based on Stan Melax's article in Game Programming Gems
COORD axis;
QUATERNION ret;
double c, s;
Coord_Normalize(&from);
Coord_Normalize(&to);
c = Coord_Dot(from, to);
if (c >= 1.0)
{ // If dot == 1, vectors are the same
return QUATERNION_IDENTITY; // identity
}
else if (c <= -1.0)
{ // exactly opposite
axis = Coord_Cross(COORD_X_AXIS, from);
if (Coord_Length(axis) == 0)
axis = Coord_Cross(COORD_Y_AXIS, from);
// same as fromAxisAngle(axis, PI).normalize();
ret.s = 0;
ret.i = axis.x;
ret.j = axis.y;
ret.k = axis.z;
Quaternion_Normalize(&ret);
return ret;
}
s = sqrt((1 + c) * 2);
axis = Coord_Cross(from, to);
Coord_ScalarDiv(&axis, s);
ret.s = s * 0.5;
ret.i = axis.x;
ret.j = axis.y;
ret.k = axis.z;
Quaternion_Normalize(&ret);
return ret;
}
/** @brief linear quaternion interpolation */
QUATERNION Quaternion_Lerp(QUATERNION q1, QUATERNION q2, double t)
{
QUATERNION ret;
Quaternion_ScalarMult(&q1, 1 - t);
Quaternion_ScalarMult(&q1, t);
ret = Quaternion_Add(q1, q2);
Quaternion_Normalize(&ret);
return ret;
}
/** @brief spherical linear interpolation */
QUATERNION Quaternion_Slerp(QUATERNION q1, QUATERNION q2, double t)
{
double dot;
QUATERNION q3, ret;
dot = Quaternion_Dot(q1, q2);
/* dot = cos(theta)
if (dot < 0), q1 and q2 are more than 90 degrees apart,
so we can invert one to reduce spinning */
if (dot < 0)
{
dot = -dot;
q3.s = -q2.s;
q3.i = -q2.i;
q3.j = -q2.j;
q3.k = -q2.k;
}
else
{
q3 = q2;
}
if (dot < 0.95)
{
double angle = acos(dot);
Quaternion_ScalarMult(&q1, sin(angle * (1 - t)));
Quaternion_ScalarMult(&q3, sin(angle * t));
ret = Quaternion_Add(q1, q3);
Quaternion_ScalarDiv(&ret, sin(angle));
return ret;
}
// if the angle is small, use linear interpolation
else
{
return Quaternion_Lerp(q1, q3, t);
}
}
/** @} LinkLayerGeometry_Quaternion */
/** @} LinkLayerGeometry */
/** @} LinkLayer */
@@ -0,0 +1,144 @@
/*****************************************************************************/
/**
* @file quaternion.h
* @author FanHao ([email protected])
* @version 0.0
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup LinkLayer
* @{
*/
/**
* @addtogroup LinkLayerGeometry
* @{
*/
/**
* @defgroup LinkLayerGeometry_Quaternion
* @{
*/
#ifndef __QUATERNION_H
#define __QUATERNION_H
#include "coord.h"
#include "eulerangles.h"
/**
* @struct QUATERNION
* @brief Structure for standard quaternion
*/
typedef struct
{
double s;
double i;
double j;
double k;
} QUATERNION;
extern const QUATERNION QUATERNION_IDENTITY;
extern const QUATERNION QUATERNION_NIL;
/** @brief Subtracts two quaternions. */
QUATERNION Quaternion_Sub(QUATERNION q1, QUATERNION q2);
/** @brief Adds two quaternions. */
QUATERNION Quaternion_Add(QUATERNION q1, QUATERNION q2);
/** @brief Multiplies a quaternion by a real number. */
void Quaternion_ScalarMult(QUATERNION *q, double t);
/** @brief Multiplies a quaternion by a real number. */
QUATERNION Quaternion_GetScalarMult(QUATERNION a, double t);
/** @brief Divides a quaternion by a real number. */
void Quaternion_ScalarDiv(QUATERNION *q, double t);
/** @brief Divides a quaternion by a real number. */
QUATERNION Quaternion_GetScalarDiv(QUATERNION a, double t);
/** @brief Multiplies two quaternions. */
QUATERNION Quaternion_Mult(QUATERNION q1, QUATERNION q2);
/** @brief Divides two quaternions. */
QUATERNION Quaternion_Div(QUATERNION q1, QUATERNION q2);
/** @brief Dot product. */
double Quaternion_Dot(QUATERNION q1, QUATERNION q2);
/** @brief Calculate a quaternion length^2 (omits calling square root). */
double Quaternion_SquareLength(QUATERNION q);
/** @brief Calculate a quaternion length. */
double Quaternion_Length(QUATERNION q);
/** @brief Normalize quaternion. */
void Quaternion_Normalize(QUATERNION *q);
/** @brief Normalize quaternion. */
QUATERNION Quaternion_GetNormalized(QUATERNION q);
/** @brief Conjugated quaternion. */
void Quaternion_Conjugated(QUATERNION *q);
/** @brief Conjugated quaternion. */
QUATERNION Quaternion_GetConjugated(QUATERNION q);
/** @brief Inverse quaternion. */
void Quaternion_Inverse(QUATERNION *q);
/** @brief Inverse quaternion. */
QUATERNION Quaternion_GeInverse(QUATERNION q);
/** @brief Get rotate angle of quaternion. */
double Quaternion_GetRotationAngle(QUATERNION q);
/** @brief Get axis of quaternion. */
COORD Quaternion_GetRotationAxis(QUATERNION q);
/** @brief Get the axis and rotate angle of a unit Quaternion */
void Quaternion_GetRotationAxisAndAngle(QUATERNION q, COORD *axis, double *angle);
/** @brief Decompose the rotation on to 2 parts.
1. Twist - rotation around the "direction" vector
2. Swing - rotation around axis that is perpendicular to "direction" vector
The rotation can be composed back by rotation = swing * twist
has singularity in case of swing_rotation close to 180 degrees rotation.
if the input quaternion is of non-unit length, the outputs are non-unit as well
otherwise, outputs are both unit
*/
void Quaternion_GetSwingAndTwist(QUATERNION q, COORD axis, QUATERNION *swing, QUATERNION *twist);
/** @brief rotates v by this quaternion (quaternion must be unit) */
COORD Quaternion_Rotate(QUATERNION q, COORD v);
/** @brief returns the euler angles from a rotation Quaternion */
EULERANGLES Quaternion_ToEulerAngles(QUATERNION q, EULERANGLES_TYPE type);
/** @brief returns the rotation Quaternion from a euler angles */
QUATERNION Quaternion_FromeEulerAngles(EULERANGLES e, EULERANGLES_TYPE type);
/** @brief adapted from https://svn.code.sf.net/p/irrlicht/code/trunk/include/quaternion.h */
QUATERNION Quaternion_RotationFromTo(COORD from, COORD to);
/** @brief linear quaternion interpolation */
QUATERNION Quaternion_Lerp(QUATERNION q1, QUATERNION q2, double t);
/** @brief spherical linear interpolation */
QUATERNION Quaternion_Slerp(QUATERNION q1, QUATERNION q2, double t);
#endif
/** @} LinkLayerGeometry_Quaternion */
/** @} LinkLayerGeometry */
/** @} LinkLayer */
File diff suppressed because it is too large Load Diff
+221
View File
@@ -0,0 +1,221 @@
/*****************************************************************************/
/**
* @file link_layer.h
* @author FanHao ([email protected])
* @brief DF Linklayer header file.
* @version 0.1
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @defgroup LinkLayer
* @{
*/
#ifndef __LINK_LAYER_H_
#define __LINK_LAYER_H_
/***************************** Include Files *********************************/
#include <stdint.h>
#include "link_layer_types.h"
#include "schdevent.h"
#include "node_list.h"
#include "circ_queue.h"
#include "../phy_layer/phy_layer.h"
#include "../../system_monitor.h"
/************************** Constant Definitions *****************************/
/***************** Macros (Inline Functions) Definitions *********************/
#define AssertL2Event(instPtr, event) Linklayer_EventHandler(instPtr, event)
/**************************** Type Definitions *******************************/
/**
* @struct L2_CONFIG
* @brief A struct holds all linklayer initialization parameters
*/
typedef struct
{
L2_NODE_TYPE myType; ///< node type
uint8_t clustId; ///< node cluster id
uint8_t myId; ///< node id
uint8_t headId; ///< head node id
uint8_t netScale; ///< net scale
PHY_INST *phyInstPtr; ///< pointer to system physical layer instance
TMC_INST *tmcInstPtr; ///< pointer to system timer controller layer instance
} L2_CONFIG;
/**
* @struct L2_LOG
* @brief A struct holds linklayer operating log
*/
typedef struct
{
uint32_t frameRx; ///< total rx frame count
uint32_t frameTx; ///< total tx frame count
uint32_t frameRecv; ///< total received frame count
uint32_t frameCorrect; ///< total correctly received frame count
uint32_t advRxCnt; ///< advertise rx frame count
uint32_t advTxCnt; ///< advertise tx frame count
uint32_t advRecvCnt; ///< advertise received frame count
uint32_t advCorrectCnt; ///< advertise correctly received frame count
uint32_t cfmRxCnt; ///< confirm rx frame count
uint32_t cfmTxCnt; ///< confirm tx frame count
uint32_t cfmRecvCnt; ///< confirm received frame count
uint32_t cfmCorrectCnt; ///< confirm correctly received frame count
uint32_t svcRxCnt; ///< service rx frame count
uint32_t svcTxCnt; ///< service tx frame count
uint32_t svcRecvCnt; ///< service received frame count
uint32_t svcCorrectCnt; ///< service correctly received frame count
int64_t timeDev; ///< last time deviation estimation result
uint8_t lastBeamWidth; ///< last beam width
uint32_t reconnectCnt; ///< reconnect trial count
PAYLOAD rxLog;
PAYLOAD txLog;
} L2_LOG;
/**
* @struct L2_INST
* @brief A linklayer instance
*/
typedef struct
{
L2_CONFIG config; ///< linklayer configuration parameters
L2_NODE_INFO myInfo; ///< current node info
NODE_LIST *nodeList; ///< discovered node list
L2_SCHD_POOL *schdEventPool; ///< event schedule pool
uint32_t netStartTime; ///< network start time
bool isEnable; ///< indicates if the node is connected to the network
bool dataAvail; ///< indicates if there is a valid received frame data in rx buffer
bool cxn2Net; ///< indicates if the node is connected to the network
L2_RCD frameNum; ///< stores the last current and next frame number.
L2_RCD slotNum; ///< stores the last current and next slot number.
L2_RCD frame; ///< stores the last current and next link layer frame type.
L2_RCD tor; ///< stores the last current and next link layer tx/rx state.
L2_NODE_STATE mainState; ///< the main state of link layer state
L2_NODE_STATE nextState; ///< next state of link layer state, which will be applied to mainState every second.
L2_RTNE_CONFIG rtneConfig; ///< current routine table configuration and status.
L2_SCAN_FSM *scanFSM; ///< FSM of scan net (link set up)
L2_SVC_FSM *serviceFSM; ///< FSM of service net (data service)
uint8_t *sendPktData; ///< send data buffer
uint8_t *recvPktData; ///< received data buffer
L2_LOG log; ///< Linklayer operating log
// for system log
SYSINFO sysInfo; ///< system info
LINKLOG linkLog; ///< linklayer log for system monitor
} L2_INST;
/************************** Variable Definitions *****************************/
extern L2_RTNE_TABLE_ENTRY *initTable[L2_INIT_RTNE_PERIOD];
extern L2_RTNE_TABLE_ENTRY *normalTable[L2_NORMAL_RTNE_PERIOD];
/************************** Function Prototypes ******************************/
/**
* @defgroup LinkLayer_Main
* @{
*/
int32_t Linklayer_Init(L2_INST **instPtr, const L2_CONFIG *config);
int32_t Linklayer_Reconfig(L2_INST *instPtr, const L2_CONFIG *config);
void Linklayer_Destroy(L2_INST *instPtr);
int32_t Linklayer_Start(L2_INST *instPtr);
int32_t Linklayer_Halt(L2_INST *instPtr);
int32_t Linklayer_Proc(L2_INST *instPtr);
int32_t Linklayer_EventHandler(L2_INST *instPtr, const L2_EVENT *l2Event);
int32_t Linklayer_PktHandler(L2_INST *instPtr, L2_FRAME_TYPE frameType);
int32_t L2_SteerBeam2Node(L2_INST *instPtr, uint8_t nodeId);
int32_t L2_SetupNextSlot(L2_INST *instPtr, L2_TOR_TYPE txrxMode, L2_FRAME_TYPE frameType);
/** @} LinkLayer_Main*/
/**
* @defgroup LinkLayer_Framing
* @{
*/
void L2_FrameInsertChunk(uint8_t *frame, size_t offset, size_t bytes, const void *chunk);
void L2_FrameGetChunk(uint8_t *frame, size_t offset, size_t bytes, void *chunk);
int32_t L2_CrcAppend(uint8_t *dataBuff, uint32_t dataLen, uint32_t crcPos, L2_CRC_TYPE crcType);
bool L2_CrcCheck(uint8_t *dataBuff, uint32_t dataLen, L2_CRC_TYPE crcType);
/** @} LinkLayer_Framing*/
/**
* @defgroup LinkLayer_Scheduler
* @{
*/
void L2_EventPoolHandler(L2_INST *instPtr);
int32_t L2_ScheduleEventAt(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t frameNo, uint32_t slotNo);
int32_t L2_ScheduleEventAfter(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t numSlots);
int32_t L2_RescheduleEventAt(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t frameNo, uint32_t slotNo);
int32_t L2_RescheduleEventAfter(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t numSlots);
/** @} LinkLayer_Scheduler*/
/**
* @defgroup LinkLayer_Scan
* @{
*/
int32_t L2_Scan_Init(L2_SCAN_FSM **scanFSMPtr);
void L2_Scan_RefreashScanTable(L2_INST *instPtr);
void L2_Scan_Reset(L2_SCAN_FSM *scanFSMPtr);
void L2_Scan_Destroy(L2_SCAN_FSM *scanFSMPtr);
int32_t L2_Scan_Proc(L2_INST *instPtr);
int32_t L2_Scan_PktHandler(L2_INST *instPtr, uint8_t *msg);
int32_t L2_Scan_Routine(L2_INST *instPtr, const L2_RTNE_TABLE_ENTRY *schedEntry);
/** @} LinkLayer_Scan*/
/**
* @defgroup LinkLayer_Service
* @{
*/
int32_t L2_Service_Init(L2_SVC_FSM **svcFSMPtr);
void L2_Service_Reset(L2_SVC_FSM *svcFSMPtr);
void L2_Service_Destroy(L2_SVC_FSM *svcFSMPtr);
int32_t L2_Service_PktHandler(L2_INST *instPtr, uint8_t *msg);
int32_t L2_Service_Proc(L2_INST *instPtr);
int32_t L2_Service_Routine(L2_INST *instPtr, const L2_RTNE_TABLE_ENTRY *schedEntry);
/** @} LinkLayer_Service*/
/**
* @defgroup LinkLayer_TimeSync
* @{
*/
int32_t L2_GetTimeDeviation(L2_INST *instPtr, uint32_t frameNum, uint32_t slotNum, bool relative, int64_t *timeDev);
void L2_TimeAdjust(L2_INST *instPtr, const int64_t *timeDev);
/** @} LinkLayer_TimeSync*/
/**
* @defgroup LinkLayer_Utility
* @{
*/
uint8_t L2_GetNodeId(L2_INST *instPtr);
uint8_t L2_GetClusterId(L2_INST *instPtr);
uint8_t L2_GetHeadId(L2_INST *instPtr);
uint8_t L2_GetNetScale(L2_INST *instPtr);
L2_NODE_TYPE L2_GetNodeType(L2_INST *instPtr);
L2_NODE_STATE L2_GetMainState(L2_INST *instPtr);
bool L2_isStarted(L2_INST *instPtr);
bool L2_isDataAvail(L2_INST *instPtr);
bool L2_isCxn2Net(L2_INST *instPtr);
uint32_t L2_GetFrameLen(L2_FRAME_TYPE l2FrameType);
uint32_t L2_GetLastFrameNum(L2_INST *instPtr);
uint32_t L2_GetLastSlotNum(L2_INST *instPtr);
L2_FRAME_TYPE L2_GetLastFrameType(L2_INST *instPtr);
L2_TOR_TYPE L2_GetLastTor(L2_INST *instPtr);
uint32_t L2_GetCurrentFrameNum(L2_INST *instPtr);
uint32_t L2_GetCurrentSlotNum(L2_INST *instPtr);
L2_FRAME_TYPE L2_GetCurrentFrameType(L2_INST *instPtr);
L2_TOR_TYPE L2_GetCurrentTor(L2_INST *instPtr);
uint32_t L2_GetNextFrameNum(L2_INST *instPtr);
uint32_t L2_GetNextSlotNum(L2_INST *instPtr);
L2_FRAME_TYPE L2_GetNextFrameType(L2_INST *instPtr);
L2_TOR_TYPE L2_GetNextTor(L2_INST *instPtr);
L2_FRAME_TYPE L2_GetLastOptFrameType(L2_INST *instPtr);
L1_FRAME_TYPE L2_L2frame2L1frame(L2_FRAME_TYPE l2Frame);
/** @} LinkLayer_Utility*/
#endif /* __LINK_LAYER_H_ */
/** @} LinkLayer*/
@@ -0,0 +1,262 @@
/*****************************************************************************/
/**
* @file link_layer_types.h
* @author FanHao ([email protected])
* @brief DF Linklayer types definition.
* @version 0.1
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @defgroup LinkLayer
* @{
*/
#ifndef __LINK_LAYER_DEF_H_
#define __LINK_LAYER_DEF_H_
/***************************** Include Files *********************************/
#include <stdbool.h>
#include <stdint.h>
#include "geometry/coord.h"
#include "geometry/quaternion.h"
#include "../phy_layer/phy_layer.h"
#ifndef EMULATION
#include "../config/app_config.h"
#endif
/************************** Constant Definitions *****************************/
/**
* @name Linklayer_Common_Constants
* @{
*/
// Common node ID definition
#define L2_BROADCAST_ID 0xFF
#define L2_NONE_ID 0
// Routine configure
#define L2_INIT_RTNE_PERIOD 1
#define L2_NORMAL_RTNE_PERIOD 1
// Common slot number definition
#define L2_SLOTNO_NONE 0
#define L2_FRAMENO_NONE 0
// Common number of slots definition
#define L2_SLOTS_PER_FRAME 100
#define L2_SLOTS_PER_SUBFRAME 20
#define L2_NUM_SLOTS_NONE UINT32_MAX
#define L2_NUM_SLOTS_100MS 20
#define L2_NUM_SLOTS_20MS 4
#define L2_NUM_SLOTS_10MS 2
#define L2_NUM_SLOTS_5MS 1
#define L2_NUM_SLOTS_SKIP 0
/** @} Linklayer_Common_Constants*/
/**************************** Type Definitions *******************************/
/**
* @struct L2_RCD
* @brief Linklayer recode buffer
*/
typedef struct
{
uint32_t last;
uint32_t curr;
uint32_t next;
} L2_RCD;
/**
* @enum L2_TOR_TYPE
*/
typedef enum
{
L2_TOR_SUSPEND = 0,
L2_TOR_TX = 1,
L2_TOR_RX = 2
} L2_TOR_TYPE;
/**
* @enum L2_NODE_TYPE
*/
typedef enum
{
L2_NODE_NONE = 0,
L2_NODE_HEAD = 1,
L2_NODE_MEMBER = 2,
L2_NODE_BACKUP = 3
} L2_NODE_TYPE;
/**
* @enum L2_NODE_STATE
*/
typedef enum
{
L2_NONE_STATE = 0,
L2_INIT_STATE = 1,
L2_NORMAL_STATE = 2,
L2_INTRA_SEEK_STATE = 3,
L2_INTER_SEEK_STATE = 4,
L2_SEEK_STATE = 5
} L2_NODE_STATE;
/**
* @struct L2_NODE_INFO
* @brief Node information struct contains the detail node info which needed by the link layer.
*/
typedef struct
{
uint8_t nodeId; ///< node ID
uint8_t clustId; ///< node cluster ID
uint8_t headId; ///< cluster head ID
L2_NODE_TYPE nodeType; ///< node type
uint8_t beamNo; ///< beam number to this node
COORD pos; ///< node position
COORD speed; ///< node speed
QUATERNION attitude; ///< node attitude
} L2_NODE_INFO;
/**
* @enum L2_EVENT_TYPE
*/
typedef enum
{
L2_EV_NONE = 0,
L2_EV_SCAN_PROC_DONE = 1,
L2_EV_NET_ADV_UPDATE = 2,
L2_EV_NET_SETUP_DONE = 3,
L2_EV_TIME_SYNC = 4,
L2_EV_LOST_CXN = 5,
L2_EV_LOST_NODE = 6,
L2_EV_SET_FRAME_NUM = 7,
L2_EV_SET_SLOT_NUM = 8,
L2_EV_MAIN_STATE_UPDATE = 9,
L2_ROUTINE_FINISH = 10,
L2_ROUTINE_UPDATE = 11
} L2_EVENT_TYPE;
/**
* @struct L2_EVENT
* @brief Linklayer event instance
*/
typedef struct
{
L2_EVENT_TYPE event; ///< event type
void *msg; ///< event message
} L2_EVENT;
/**
* @enum L2_SLOT_TYPE
*/
typedef enum
{
L2_SLOT_NONE = 0,
L2_SLOT_IDLE = 1,
L2_SLOT_SCAN = 2,
L2_SLOT_ADVERTISE = 3,
L2_SLOT_CONFIRM = 4,
L2_SLOT_SERVICE = 5,
} L2_SLOT_TYPE;
/**
* @enum L2_FRAME_TYPE
*/
typedef enum
{
L2_NONE_FRAME = 0,
L2_SCAN_FRAME = 1,
L2_ADV_FRAME = 2,
L2_CFM_FRAME = 3,
L2_SVC_FRAME = 4
} L2_FRAME_TYPE;
/**
* @enum L2_CRC_TYPE
*/
typedef enum
{
L2_CRC_NONE = 0,
L2_CRC16_1021 = 1,
L2_CRC16_8005 = 2,
L2_CRC8_31 = 3
} L2_CRC_TYPE;
/**
* @struct L2_RTNE_TABLE_ENTRY
* @brief Linklayer routine table entry
*/
typedef struct
{
L2_SLOT_TYPE slotType : 8; ///< slot type
uint8_t slotSeq; ///< slot sequence number
uint8_t src; ///< source node ID
uint8_t dst; ///< destination node ID
} L2_RTNE_TABLE_ENTRY;
/**
* @enum SCAN_STAGE
*/
typedef enum
{
L2_SCAN_NONE_STAGE = 0,
L2_SCAN_INIT_STAGE = 1,
L2_SCAN_ADV_STAGE = 2,
L2_SCAN_CFM_STAGE = 3
} SCAN_STAGE;
/**
* @struct L2_SCAN_FSM
* @brief Linklayer scan process FSM instance
*/
typedef struct
{
bool isLocked; ///< indicates if init acq done(beam locked).
bool isAdvRecvd; ///< indicates if advertisement frame done(beam locked).
bool isAckPending; ///< indicates if confirm message acked
uint8_t scanCnt; ///< scan count
uint8_t advTimeout; ///< adv receive try count
uint8_t cfmTimeout; ///< cmf receive try count
SCAN_STAGE scanStage; ///< scan stage \n
/// only for member node
uint8_t beamNo; ///< locked beam number
uint8_t tableNo; ///< scan table index
} L2_SCAN_FSM;
/**
* @struct L2_SVC_FSM
* @brief Linklayer service process FSM
*/
typedef struct
{
uint32_t txCnt; ///< tx frame count
uint32_t rxCnt; ///< rx frame count
uint32_t rxdCnt; ///< received frame count
#ifdef DATALINK_ENABLE_BERTEST
uint32_t bitTotal; ///< received bits count
uint32_t bitError; ///< error bits count
double lossRate; ///< packet loss rate
double errorRate; ///< bit error rate
#endif
} L2_SVC_FSM;
/**
* @struct L2_RTNE_CONFIG
* @brief Linklayer routine table configuration
*/
typedef struct
{
L2_RTNE_TABLE_ENTRY **rtneTable; ///< routine table
uint32_t rtnePrd; ///< period of routine table
L2_RTNE_TABLE_ENTRY *last; ///< last routine entry
L2_RTNE_TABLE_ENTRY *curr; ///< curent routine entry
L2_RTNE_TABLE_ENTRY *next; ///< next routine entry
} L2_RTNE_CONFIG;
/************************** Variable Definitions *****************************/
#endif /* __LINK_LAYER_DEF_H_ */
/** @} LinkLayer*/
+130
View File
@@ -0,0 +1,130 @@
/*****************************************************************************/
/**
* @file msg_def.c
* @author FanHao ([email protected])
* @brief DF Linklayer message definition constants.
* @version 0.0
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup LinkLayer
* @{
*/
/**
* @name LinkLayer_MSG_Constants
* @{
*/
#ifndef __L2_MSG_DEF_H_
#define __L2_MSG_DEF_H_
#define L2_PACK_LEN_MAX 512 // bytes
#define L2_ADV_PACK_LEN 28 // bytes
#define L2_CMF_PACK_LEN 268 // bytes
#define L2_SVC_PACK_LEN 268 // bytes
// Common structure:
// [bytes] [name]
// 4 fame number
// 1 slot number
// 1 source id
// 1 destination id
// 1 message type
#define L2_MSG_FRAME_NUM 0
#define L2_MSG_FRAME_NUM_LEN 4
#define L2_MSG_SLOT_NUM 4
#define L2_MSG_SLOT_NUM_LEN 1
#define L2_MSG_SRC_ID 5
#define L2_MSG_SRC_ID_LEN 1
#define L2_MSG_DST_ID 6
#define L2_MSG_DST_ID_LEN 1
#define L2_MSG_TYPE 7
#define L2_MSG_TYPE_LEN 1
#define L2_MSG_PAYLOAD 8
// advertisement payload structure:
// [bytes] [name]
// 4 position x
// 4 position y
// 4 position z
// 4 net start time
// 2 crc
#define L2_MSG_ADV_SRC_POSX 8
#define L2_MSG_ADV_SRC_POSX_LEN 4
#define L2_MSG_ADV_SRC_POSY 12
#define L2_MSG_ADV_SRC_POSY_LEN 4
#define L2_MSG_ADV_SRC_POSZ 16
#define L2_MSG_ADV_SRC_POSZ_LEN 4
#define L2_MSG_ADV_SRC_NETSTART_TIME 20
#define L2_MSG_ADV_SRC_NETSTART_TIME_LEN 4
#define L2_MSG_ADV_SVC_CRC 26
#define L2_MSG_ADV_SVC_CRC_LEN 2
// confirm payload structure:
// [bytes] [name]
// 4 position x
// 4 position y
// 4 position z
// 4 speed x
// 4 speed y
// 4 speed z
// 2 crc
#define L2_MSG_CFM_SRC_POSX 8
#define L2_MSG_CFM_SRC_POSX_LEN 4
#define L2_MSG_CFM_SRC_POSY 12
#define L2_MSG_CFM_SRC_POSY_LEN 4
#define L2_MSG_CFM_SRC_POSZ 16
#define L2_MSG_CFM_SRC_POSZ_LEN 4
#define L2_MSG_CFM_SRC_SPEEDX 20
#define L2_MSG_CFM_SRC_SPEEDX_LEN 4
#define L2_MSG_CFM_SRC_SPEEDY 24
#define L2_MSG_CFM_SRC_SPEEDY_LEN 4
#define L2_MSG_CFM_SRC_SPEEDZ 28
#define L2_MSG_CFM_SRC_SPEEDZ_LEN 4
#define L2_MSG_CFM_PAYLOAD_ID 32
#define L2_MSG_CFM_PAYLOAD_ID_LEN 4
#define L2_MSG_CFM_PAYLOAD 36
#define L2_MSG_CFM_PAYLOAD_LEN 230
#define L2_MSG_CFM_CRC 266
#define L2_MSG_CFM_CRC_LEN 2
// service payload structure:
// [bytes] [name]
// 4 position x
// 4 position y
// 4 position z
// 4 speed x
// 4 speed y
// 4 speed z
// 234 payload
// 2 crc
#define L2_MSG_SVC_SRC_POSX 8
#define L2_MSG_SVC_SRC_POSX_LEN 4
#define L2_MSG_SVC_SRC_POSY 12
#define L2_MSG_SVC_SRC_POSY_LEN 4
#define L2_MSG_SVC_SRC_POSZ 16
#define L2_MSG_SVC_SRC_POSZ_LEN 4
#define L2_MSG_SVC_SRC_SPEEDX 20
#define L2_MSG_SVC_SRC_SPEEDX_LEN 4
#define L2_MSG_SVC_SRC_SPEEDY 24
#define L2_MSG_SVC_SRC_SPEEDY_LEN 4
#define L2_MSG_SVC_SRC_SPEEDZ 28
#define L2_MSG_SVC_SRC_SPEEDZ_LEN 4
#define L2_MSG_SVC_PAYLOAD_ID 32
#define L2_MSG_SVC_PAYLOAD_ID_LEN 4
#define L2_MSG_SVC_PAYLOAD 36
#define L2_MSG_SVC_PAYLOAD_LEN 230
#define L2_MSG_SVC_CRC 266
#define L2_MSG_SVC_CRC_LEN 2
#endif //__L2_MSG_DEF_H_
/** @} LinkLayer_MSG_Constants*/
/** @} LinkLayer*/
+561
View File
@@ -0,0 +1,561 @@
/*****************************************************************************/
/**
* @file node_list.c
* @author FanHao ([email protected])
* @brief DF Linklayer node list implementation file
* @version 0.0
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup LinkLayer
* @{
*/
/**
* @addtogroup LinkLayer_NodeList
* @{
*/
/***************************** Include Files *********************************/
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "link_layer_types.h"
#include "node_list.h"
#include "clist.h"
#include "common.h"
#include "error.h"
/***************** Macros (Inline Functions) Definitions *********************/
/**
* @brief Get the node list length
* @param list pointer to node list
*/
inline uint32_t L2_GetNodeListLen(NODE_LIST *list)
{
ASSERT(list != NULL);
return list->len;
}
/**************************** Type Definitions *******************************/
/************************** Variable Definitions *****************************/
static NODE_ENTRY util_entry;
/************************** Function Prototypes ******************************/
/**
* @brief helper function to free node entry.
*/
static void entry_free(void *val)
{
free(val);
}
/**
* @brief helper function to match node entries by nodeIds
*/
static int8_t entry_compare(void *a, void *b)
{
ASSERT(a != NULL);
ASSERT(b != NULL);
register uint8_t idA, idB;
idA = ((NODE_ENTRY *)a)->nodeInfo.nodeId;
idB = ((NODE_ENTRY *)b)->nodeInfo.nodeId;
if (idA == idB)
{
return 0;
}
else if (idA < idB)
{
return -1;
}
else
{
return 1;
}
}
/*****************************************************************************/
/**
* @brief Initialize node list
*
* @param list
*
* @return SUCCESS
* ENOMEM - not enough memory.
*
******************************************************************************/
int32_t L2_NodeList_Init(NODE_LIST **list)
{
(*list) = clist_new();
if (*list == NULL)
{
return ENOMEM;
}
(*list)->free = entry_free;
(*list)->compare = entry_compare;
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Clear all nodes in the node list, free allocated memory.
*
* @param list
* @return NONE
*
******************************************************************************/
void L2_NodeList_Clear(NODE_LIST *list)
{
ASSERT(list != NULL);
clist_clear(list);
}
/*****************************************************************************/
/**
* @brief Completely destroy node list.
*
* @param list
*
* @return NONE
*
******************************************************************************/
void L2_NodeList_Destroy(NODE_LIST *list)
{
clist_destroy(list);
}
/*****************************************************************************/
/**
* @brief Get node entry from node list base on node id.
*
* @param list
* @param nodeId
*
* @return Node entry \n
* NULL if node dose not exist.
*
******************************************************************************/
NODE_ENTRY *L2_GetNodeById(NODE_LIST *list, uint8_t nodeId)
{
ASSERT(list != NULL);
if (nodeId == L2_BROADCAST_ID || nodeId == L2_NONE_ID)
{
return NULL;
}
util_entry.nodeInfo.nodeId = nodeId;
clist_node_t *node = clist_find(list, &util_entry);
if (node == NULL)
{
return NULL;
}
else
{
return ((NODE_ENTRY *)node->val);
}
}
/*****************************************************************************/
/**
* @brief Append a new node entry to the node list
*
* @param list
* @param nodeId
* @param nodeType
*
* @return SUCCESS Node was added successfully.\n
* Other Error occurred.(Node already exist, memory alloc error ect.)
*
******************************************************************************/
NODE_ENTRY *L2_AppendNode(NODE_LIST *list, uint8_t nodeId, L2_NODE_TYPE nodeType)
{
ASSERT(list != NULL);
if (L2_isNodeInList(list, nodeId))
{
DBG_WARNING("Node [%" PRIu8 "] already exist.\n", nodeId);
return NULL;
}
DBG_INFO("Link layer appending node [%" PRIu8 "] to node list.\n", nodeId);
NODE_ENTRY *nodeEntry = (NODE_ENTRY *)malloc(sizeof(NODE_ENTRY));
if (nodeEntry == NULL)
{
DBG_ERROR("Failed to allocated memory for nodeEntry.\n");
return NULL;
}
clist_node_t *node = clist_node_new(nodeEntry);
if (node == NULL)
{
DBG_ERROR("Failed to allocated memory for list node.\n");
free(nodeEntry);
return NULL;
}
nodeEntry->nodeInfo.nodeId = nodeId;
nodeEntry->nodeInfo.nodeType = (uint8_t)nodeType;
nodeEntry->nodeInfo.pos.x = 0;
nodeEntry->nodeInfo.pos.y = 0;
nodeEntry->nodeInfo.pos.z = 0;
nodeEntry->nodeInfo.speed.x = 0;
nodeEntry->nodeInfo.speed.y = 0;
nodeEntry->nodeInfo.speed.z = 0;
nodeEntry->nodeInfo.beamNo = 0;
nodeEntry->ttlCnt = 0;
clist_rpush(list, node);
return nodeEntry;
}
/*****************************************************************************/
/**
* @brief Delete a node in list based on node id.
*
* @param list
* @param nodeId
*
* @return SUCCESS Node has been successfully deleted.\n
* Other Node not exist.
*
******************************************************************************/
int32_t L2_DeleteNodeById(NODE_LIST *list, uint8_t nodeId)
{
ASSERT(list != NULL);
util_entry.nodeInfo.nodeId = nodeId;
clist_node_t *node = clist_find(list, &util_entry);
if (node == NULL)
{
DBG_WARNING("Node [%" PRIu8 "] in not in node list, skip deleting process.\n", nodeId);
return SUCCESS;
}
DBG_INFO("Deleting node [%" PRIu8 "].\n", nodeId);
clist_remove(list, node);
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Check whether the node is already in the node list.
*
* @param list
* @param nodeId
*
* @return true node in the list\n
* false node not in the list
*
******************************************************************************/
bool L2_isNodeInList(NODE_LIST *list, uint8_t nodeId)
{
ASSERT(list != NULL);
return (L2_GetNodeById(list, nodeId) != NULL);
}
/*****************************************************************************/
/**
* @brief Get the distance between me and the node.
*
* @param list
* @param nodeId
* @param dst A pointer to store distance.
*
* @return SUCCESS distance has been successfully store in dst\n
* FAILURE Node dose not exit.
*
******************************************************************************/
int32_t L2_GetDistance(NODE_LIST *list, COORD myCoord, uint8_t nodeId, double *dst)
{
ASSERT(list != NULL);
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
if (nodeEntry == NULL)
{
return FAILURE;
}
else
{
*dst = Coord_Distance(myCoord, nodeEntry->nodeInfo.pos);
return SUCCESS;
}
}
/*****************************************************************************/
/**
* @brief Update node positions information.
*
* @param list
* @param nodeId
* @param newPos A structure stores the corresponding node position info.
*
* @return SUCCESS update successfully.\n
* FAILURE node not exist.
*
******************************************************************************/
int32_t L2_UpdateNodePos(NODE_LIST *list, uint8_t nodeId, const COORD *newPos)
{
ASSERT(list != NULL);
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
if (nodeEntry == NULL)
{
return FAILURE;
}
else
{
memcpy(&(nodeEntry->nodeInfo.pos), newPos, sizeof(COORD));
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Get node positions information.
*
* @param list
* @param nodeId
* @param newPos A structure stores the corresponding node position info.
*
* @return SUCCESS update successfully.\n
* FAILURE node not exist.
*
******************************************************************************/
int32_t L2_GetNodePos(NODE_LIST *list, uint8_t nodeId, COORD *pos)
{
ASSERT(list != NULL);
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
if (nodeEntry == NULL)
{
return FAILURE;
}
else
{
memcpy(pos, &(nodeEntry->nodeInfo.pos), sizeof(COORD));
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Update node speed information.
*
* @param list
* @param nodeId
* @param newSpeed A structure stores the corresponding node speed info.
*
* @return SUCCESS update successfully.\n
* FAILURE node not exist.
*
******************************************************************************/
int32_t L2_UpdateNodeSpeed(NODE_LIST *list, uint8_t nodeId, const COORD *newSpeed)
{
ASSERT(list != NULL);
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
if (nodeEntry == NULL)
{
return FAILURE;
}
else
{
memcpy(&(nodeEntry->nodeInfo.speed), newSpeed, sizeof(COORD));
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Get node speed information.
*
* @param list
* @param nodeId
* @param newSpeed A structure stores the corresponding node speed info.
*
* @return SUCCESS update successfully.\n
* FAILURE node not exist.
*
******************************************************************************/
int32_t L2_GetNodeSpeed(NODE_LIST *list, uint8_t nodeId, COORD *speed)
{
ASSERT(list != NULL);
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
if (nodeEntry == NULL)
{
return FAILURE;
}
else
{
memcpy(speed, &(nodeEntry->nodeInfo.speed), sizeof(COORD));
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Update node ACK status.
*
* @param list
* @param nodeId
* @param devi
*
* @return SUCCESS update successfully.\n
* FAILURE Node not exist.
*
******************************************************************************/
int32_t L2_UpdateNodeTimeDeviation(NODE_LIST *list, uint8_t nodeId, int32_t devi)
{
ASSERT(list != NULL);
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
if (nodeEntry == NULL)
{
return FAILURE;
}
else
{
nodeEntry->timeDevi = devi;
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Increase TTL of specified node in the list.
*
* @param list
* @param inc cnt of slot to add
* @param nodeId
*
* @return NONE
*
******************************************************************************/
int32_t L2_IncNodeTTL(NODE_LIST *list, uint8_t nodeId, uint32_t inc)
{
ASSERT(list != NULL);
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
if (nodeEntry == NULL)
{
return FAILURE;
}
else
{
nodeEntry->ttlCnt += inc;
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Reset node TTL based on node id.
*
* @param list
* @param nodeId
*
* @return SUCCESS TTL has been successfully cleared.\n
* FAILURE Node not exist.
*
******************************************************************************/
int32_t L2_RstNodeTTL(NODE_LIST *list, uint8_t nodeId)
{
ASSERT(list != NULL);
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
if (nodeEntry == NULL)
{
return FAILURE;
}
else
{
nodeEntry->ttlCnt = 0;
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Get TTL of specified node in the list.
*
* @param list
* @param nodeId
* @param ttl
*
* @return NONE
*
******************************************************************************/
int32_t L2_GetNodeTTL(NODE_LIST *list, uint8_t nodeId, uint32_t *ttl)
{
ASSERT(list != NULL);
NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId);
if (nodeEntry == NULL)
{
return FAILURE;
}
else
{
*ttl = nodeEntry->ttlCnt;
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Implements a edit operations to each node.
*
* @param list
* @param param
* @param operation A pointer to a function handled "NODE_ENTRY*" as input
* which defines the operations need to be apply.
*
* @return SUCCESS Operations has been applied successfully to all nodes.\n
* Other Error occurred.
*
******************************************************************************/
int32_t L2_IterEditNode(NODE_LIST *list, const void *param, int32_t (*operation)(NODE_ENTRY *, const void *))
{
ASSERT(list != NULL);
int32_t Status;
clist_node_t *node;
clist_iterator_t *iter = clist_iterator_new(list, LIST_HEAD);
if (iter == NULL)
{
DBG_ERROR("Failed to initialize list iteration process.\n");
return ENOMEM;
}
while ((node = clist_iterator_next(iter)))
{
Status = operation((NODE_ENTRY *)node->val, param);
if (Status != SUCCESS)
{
DBG_ERROR("Error occurred when iteratively edit node entry.\n");
break;
}
}
clist_iterator_destroy(iter);
return Status;
}
/*****************************************************************************/
/**
* @brief Filter all node, delete all the node not satisfied the condition.
*
* @param list
* @param condition A pointer to a function handled "NODE_ENTRY*" as input
* which defines the condition need to be verify.
*
* @return SUCCESS
*
******************************************************************************/
int32_t L2_IterDeleteNode(NODE_LIST *list, bool (*condition)(NODE_ENTRY *))
{
ASSERT(list != NULL);
clist_node_t *node;
clist_iterator_t *iter = clist_iterator_new(list, LIST_HEAD);
if (iter == NULL)
{
DBG_ERROR("Failed to initialize list iteration process.\n");
return ENOMEM;
}
while ((node = clist_iterator_next(iter)))
{
if (condition((NODE_ENTRY *)node->val) == false)
{
clist_remove(list, node);
}
}
clist_iterator_destroy(iter);
return SUCCESS;
}
/** @} LinkLayer_NodeList*/
/** @} LinkLayer*/
+79
View File
@@ -0,0 +1,79 @@
/*****************************************************************************/
/**
* @file node_list.h
* @author FanHao ([email protected])
* @brief DF Linklayer node list header file
* @version 0.0
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup LinkLayer
* @{
*/
/**
* @defgroup LinkLayer_NodeList
* @{
*/
/***************************** Include Files *********************************/
#ifndef NODE_LIST_H_
#define NODE_LIST_H_
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
#include "link_layer_types.h"
#include "geometry/coord.h"
#include "util.h"
#include "clist.h"
/************************** Constant Definitions *****************************/
/***************** Macros (Inline Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
/**
* @struct NODE_ENTRY
* @brief Linklayer discovered node list node entry
*/
typedef struct
{
L2_NODE_INFO nodeInfo;
uint32_t ttlCnt;
int32_t timeDevi;
} NODE_ENTRY;
typedef clist_t NODE_LIST;
/************************** Variable Definitions *****************************/
/************************** Function Prototypes ******************************/
int32_t L2_NodeList_Init(NODE_LIST **list);
void L2_NodeList_Clear(NODE_LIST *list);
void L2_NodeList_Destroy(NODE_LIST *list);
uint32_t L2_GetNodeListLen(NODE_LIST *list);
NODE_ENTRY *L2_GetNodeById(NODE_LIST *list, uint8_t nodeId);
NODE_ENTRY *L2_AppendNode(NODE_LIST *list, uint8_t nodeId, L2_NODE_TYPE nodeType);
int32_t L2_DeleteNodeById(NODE_LIST *list, uint8_t nodeId);
int32_t L2_UpdateNodePos(NODE_LIST *list, uint8_t nodeId, const COORD *newPos);
bool L2_isNodeInList(NODE_LIST *list, uint8_t nodeId);
int32_t L2_GetNodePos(NODE_LIST *list, uint8_t nodeId, COORD *newPos);
int32_t L2_UpdateNodeSpeed(NODE_LIST *list, uint8_t nodeId, const COORD *newSpeed);
int32_t L2_GetNodeSpeed(NODE_LIST *list, uint8_t nodeId, COORD *speed);
int32_t L2_UpdateNodeTimeDeviation(NODE_LIST *list, uint8_t nodeId, int32_t devi);
int32_t L2_GetDistance(NODE_LIST *list, COORD myCoord, uint8_t nodeId, double *dst);
int32_t L2_RstNodeTTL(NODE_LIST *list, uint8_t nodeId);
int32_t L2_IncNodeTTL(NODE_LIST *list, uint8_t nodeId, uint32_t inc);
int32_t L2_GetNodeTTL(NODE_LIST *list, uint8_t nodeId, uint32_t *ttl);
int32_t L2_IterEditNode(NODE_LIST *list, const void *param, int32_t (*operation)(NODE_ENTRY *, const void *));
int32_t L2_IterDeleteNode(NODE_LIST *list, bool (*condition)(NODE_ENTRY *));
#endif /* NODE_LIST_H_ */
/** @} LinkLayer_NodeList*/
/** @} LinkLayer*/
+263
View File
@@ -0,0 +1,263 @@
/*****************************************************************************/
/**
* @file routine_table.c
* @author FanHao ([email protected])
* @brief DF Linklayer node list implementation file
* @version 0.0
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup LinkLayer
* @{
*/
/**
* @name RoutineTable
* @{
*/
#include <inttypes.h>
#include "link_layer.h"
#include "link_layer_types.h"
L2_RTNE_TABLE_ENTRY intraScanSubT[L2_SLOTS_PER_FRAME] = {
// SubFrame 0
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
// SubFrame 1
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
// SubFrame 2
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x00, 0x01, 0xFF},
{L2_SLOT_SCAN, 0x01, 0x01, 0xFF},
{L2_SLOT_ADVERTISE, 0x00, 0x01, 0xFF},
{L2_SLOT_ADVERTISE, 0x01, 0x01, 0xFF},
{L2_SLOT_ADVERTISE, 0x02, 0x01, 0xFF},
{L2_SLOT_ADVERTISE, 0x03, 0x01, 0xFF},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
// SubFrame 3
{L2_SLOT_CONFIRM, 0x00, 0x01, 0xFF},
{L2_SLOT_CONFIRM, 0x01, 0x01, 0xFF},
{L2_SLOT_CONFIRM, 0x02, 0x01, 0xFF},
{L2_SLOT_CONFIRM, 0x03, 0x01, 0xFF},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_CONFIRM, 0x00, 0x01, 0xFF},
{L2_SLOT_CONFIRM, 0x01, 0x01, 0xFF},
{L2_SLOT_CONFIRM, 0x02, 0x01, 0xFF},
{L2_SLOT_CONFIRM, 0x03, 0x01, 0xFF},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_CONFIRM, 0x00, 0x02, 0x01},
{L2_SLOT_CONFIRM, 0x01, 0x02, 0x01},
{L2_SLOT_CONFIRM, 0x02, 0x02, 0x01},
{L2_SLOT_CONFIRM, 0x03, 0x02, 0x01},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_CONFIRM, 0x00, 0x03, 0x01},
{L2_SLOT_CONFIRM, 0x01, 0x03, 0x01},
{L2_SLOT_CONFIRM, 0x02, 0x03, 0x01},
{L2_SLOT_CONFIRM, 0x03, 0x03, 0x01},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
// SubFrame 4
{L2_SLOT_CONFIRM, 0x00, 0x02, 0x01},
{L2_SLOT_CONFIRM, 0x01, 0x02, 0x01},
{L2_SLOT_CONFIRM, 0x02, 0x02, 0x01},
{L2_SLOT_CONFIRM, 0x03, 0x02, 0x01},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_CONFIRM, 0x00, 0x03, 0x01},
{L2_SLOT_CONFIRM, 0x01, 0x03, 0x01},
{L2_SLOT_CONFIRM, 0x02, 0x03, 0x01},
{L2_SLOT_CONFIRM, 0x03, 0x03, 0x01},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_CONFIRM, 0x00, 0x02, 0x01},
{L2_SLOT_CONFIRM, 0x01, 0x02, 0x01},
{L2_SLOT_CONFIRM, 0x02, 0x02, 0x01},
{L2_SLOT_CONFIRM, 0x03, 0x02, 0x01},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_CONFIRM, 0x00, 0x03, 0x01},
{L2_SLOT_CONFIRM, 0x01, 0x03, 0x01},
{L2_SLOT_CONFIRM, 0x02, 0x03, 0x01},
{L2_SLOT_CONFIRM, 0x03, 0x03, 0x01},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
};
L2_RTNE_TABLE_ENTRY normalSub[L2_SLOTS_PER_FRAME] = {
// SubFrame 0
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_SERVICE, 0x00, 0x01, 0x03},
{L2_SLOT_SERVICE, 0x01, 0x01, 0x03},
{L2_SLOT_SERVICE, 0x02, 0x01, 0x03},
{L2_SLOT_SERVICE, 0x03, 0x01, 0x03},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_SERVICE, 0x00, 0x03, 0x01},
{L2_SLOT_SERVICE, 0x01, 0x03, 0x01},
{L2_SLOT_SERVICE, 0x02, 0x03, 0x01},
{L2_SLOT_SERVICE, 0x03, 0x03, 0x01},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
// SubFrame 1
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_SERVICE, 0x00, 0x01, 0x03},
{L2_SLOT_SERVICE, 0x01, 0x01, 0x03},
{L2_SLOT_SERVICE, 0x02, 0x01, 0x03},
{L2_SLOT_SERVICE, 0x03, 0x01, 0x03},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_SERVICE, 0x00, 0x03, 0x01},
{L2_SLOT_SERVICE, 0x01, 0x03, 0x01},
{L2_SLOT_SERVICE, 0x02, 0x03, 0x01},
{L2_SLOT_SERVICE, 0x03, 0x03, 0x01},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
// SubFrame 2
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_SERVICE, 0x00, 0x01, 0x03},
{L2_SLOT_SERVICE, 0x01, 0x01, 0x03},
{L2_SLOT_SERVICE, 0x02, 0x01, 0x03},
{L2_SLOT_SERVICE, 0x03, 0x01, 0x03},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_SERVICE, 0x00, 0x03, 0x01},
{L2_SLOT_SERVICE, 0x01, 0x03, 0x01},
{L2_SLOT_SERVICE, 0x02, 0x03, 0x01},
{L2_SLOT_SERVICE, 0x03, 0x03, 0x01},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
// SubFrame 3
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_SERVICE, 0x00, 0x01, 0x03},
{L2_SLOT_SERVICE, 0x01, 0x01, 0x03},
{L2_SLOT_SERVICE, 0x02, 0x01, 0x03},
{L2_SLOT_SERVICE, 0x03, 0x01, 0x03},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_SERVICE, 0x00, 0x03, 0x01},
{L2_SLOT_SERVICE, 0x01, 0x03, 0x01},
{L2_SLOT_SERVICE, 0x02, 0x03, 0x01},
{L2_SLOT_SERVICE, 0x03, 0x03, 0x01},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
// SubFrame 4
{L2_SLOT_SERVICE, 0x00, 0x01, 0x02},
{L2_SLOT_SERVICE, 0x01, 0x01, 0x02},
{L2_SLOT_SERVICE, 0x02, 0x01, 0x02},
{L2_SLOT_SERVICE, 0x03, 0x01, 0x02},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_SERVICE, 0x00, 0x02, 0x01},
{L2_SLOT_SERVICE, 0x01, 0x02, 0x01},
{L2_SLOT_SERVICE, 0x02, 0x02, 0x01},
{L2_SLOT_SERVICE, 0x03, 0x02, 0x01},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_SERVICE, 0x00, 0x01, 0x03},
{L2_SLOT_SERVICE, 0x01, 0x01, 0x03},
{L2_SLOT_SERVICE, 0x02, 0x01, 0x03},
{L2_SLOT_SERVICE, 0x03, 0x01, 0x03},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
{L2_SLOT_SERVICE, 0x00, 0x03, 0x01},
{L2_SLOT_SERVICE, 0x01, 0x03, 0x01},
{L2_SLOT_SERVICE, 0x02, 0x03, 0x01},
{L2_SLOT_SERVICE, 0x03, 0x03, 0x01},
{L2_SLOT_IDLE, 0x00, 0x00, 0x00},
};
L2_RTNE_TABLE_ENTRY *initTable[L2_INIT_RTNE_PERIOD] =
{
intraScanSubT
};
L2_RTNE_TABLE_ENTRY *normalTable[L2_NORMAL_RTNE_PERIOD] =
{
normalSub
};
/** @} RoutineTable*/
/** @} LinkLayer*/
+929
View File
@@ -0,0 +1,929 @@
/*****************************************************************************/
/**
* @file scan.c
* @author FanHao ([email protected])
* @brief DF Linklayer scan implementation file.
* @version 0.1
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup LinkLayer
* @{
*/
/**
* @addtogroup LinkLayer_Scan
* @{
*/
/***************************** Include Files *********************************/
#include <string.h>
#include "link_layer.h"
#include "link_layer_types.h"
#include "msg_def.h"
#include "node_list.h"
#include "error.h"
#include "common.h"
#include "../phy_layer/phy_layer.h"
/************************** Constant Definitions *****************************/
#define ADV_LISTEN_TIMEOUT 40
#define CFM_LISTEN_TIMEOUT 5
#define ADV_FRAME_SLOTS 4
#define CFM_FRAME_SLOTS 5
/***************** Macros (In-line Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
/************************** Variable Definitions *****************************/
// Pair by regex
// Regex: ((\{\.oaxis = [0-9]+[ ,]+\.raxis = [0-9]+[ ]*\}, ){2})
PHY_ANT_ANGLE antNrrwPattern_0[L1_NUM_ANT_NRRW_PATTERN] =
{
{.oaxis = 0 , .raxis = 0 },
{.oaxis = 139, .raxis = 2225},
{.oaxis = 152, .raxis = 850 },
{.oaxis = 138, .raxis = 3155},
{.oaxis = 159, .raxis = 1680},
{.oaxis = 168, .raxis = 285 },
{.oaxis = 195, .raxis = 2630},
{.oaxis = 211, .raxis = 1204},
{.oaxis = 225, .raxis = 3429},
{.oaxis = 249, .raxis = 2022},
{.oaxis = 272, .raxis = 629 },
{.oaxis = 265, .raxis = 2934},
{.oaxis = 277, .raxis = 1499},
{.oaxis = 289, .raxis = 124 },
{.oaxis = 300, .raxis = 2349},
{.oaxis = 311, .raxis = 959 },
{.oaxis = 321, .raxis = 3199},
{.oaxis = 331, .raxis = 1824},
{.oaxis = 341, .raxis = 389 },
{.oaxis = 351, .raxis = 2674},
{.oaxis = 360, .raxis = 1268},
{.oaxis = 364, .raxis = 3483},
{.oaxis = 378, .raxis = 2118},
{.oaxis = 387, .raxis = 733 },
{.oaxis = 416, .raxis = 3028},
{.oaxis = 404, .raxis = 1623},
{.oaxis = 433, .raxis = 248 },
{.oaxis = 421, .raxis = 2473},
{.oaxis = 429, .raxis = 1098},
{.oaxis = 437, .raxis = 3303},
{.oaxis = 445, .raxis = 1948},
{.oaxis = 443, .raxis = 543 },
{.oaxis = 450, .raxis = 2828},
{.oaxis = 448, .raxis = 1422},
{.oaxis = 455, .raxis = 47 },
{.oaxis = 453, .raxis = 2272},
{.oaxis = 450, .raxis = 897 }
};
PHY_ANT_ANGLE antNrrwPattern_1[L1_NUM_ANT_NRRW_PATTERN] =
{
{.oaxis = 0 , .raxis = 0 },
{.oaxis = 139, .raxis = 1155},
{.oaxis = 152, .raxis = 3380},
{.oaxis = 138, .raxis = 2085},
{.oaxis = 159, .raxis = 610 },
{.oaxis = 168, .raxis = 2815},
{.oaxis = 195, .raxis = 1560},
{.oaxis = 211, .raxis = 134 },
{.oaxis = 225, .raxis = 2359},
{.oaxis = 249, .raxis = 952 },
{.oaxis = 272, .raxis = 3159},
{.oaxis = 265, .raxis = 1864},
{.oaxis = 277, .raxis = 429 },
{.oaxis = 289, .raxis = 2654},
{.oaxis = 300, .raxis = 1279},
{.oaxis = 311, .raxis = 3489},
{.oaxis = 321, .raxis = 2129},
{.oaxis = 331, .raxis = 754 },
{.oaxis = 341, .raxis = 2919},
{.oaxis = 351, .raxis = 1604},
{.oaxis = 360, .raxis = 198 },
{.oaxis = 364, .raxis = 2413},
{.oaxis = 378, .raxis = 1048},
{.oaxis = 387, .raxis = 3263},
{.oaxis = 416, .raxis = 1958},
{.oaxis = 404, .raxis = 553 },
{.oaxis = 433, .raxis = 2778},
{.oaxis = 421, .raxis = 1403},
{.oaxis = 429, .raxis = 28 },
{.oaxis = 437, .raxis = 2233},
{.oaxis = 445, .raxis = 878 },
{.oaxis = 443, .raxis = 3073},
{.oaxis = 450, .raxis = 1758},
{.oaxis = 448, .raxis = 352 },
{.oaxis = 455, .raxis = 2577},
{.oaxis = 453, .raxis = 1202},
{.oaxis = 450, .raxis = 3427},
};
/************************** Function Prototypes ******************************/
static void LockStateUpdate(L2_SCAN_FSM *scanFsmPtr, bool state);
static void AdvRecvStateUpdate(L2_SCAN_FSM *scanFsmPtr, bool state);
static void StageUpdate(L2_SCAN_FSM *scanFsmPtr, SCAN_STAGE newStage);
static void PendCfmAck(L2_SCAN_FSM *scanFsmPtr);
static int32_t Scan_InitScanHandler(L2_INST *instPtr);
static int32_t Scan_AdvHandler(L2_INST *instPtr);
static int32_t Scan_CfmHandler(L2_INST *instPtr);
static int32_t ScanMsg_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dstId);
/**
* @brief Update Init-Scan lock state.
*/
static inline void LockStateUpdate(L2_SCAN_FSM *scanFsmPtr, bool state)
{
ASSERT(scanFsmPtr != NULL);
DBG_INFO("Update BeamLockState from [%" PRId8 "] to [%" PRId8 "].\n",
scanFsmPtr->isLocked, state);
scanFsmPtr->isLocked = state;
return;
}
/**
* @brief Update Base-info Advertisement state.
*/
static void AdvRecvStateUpdate(L2_SCAN_FSM *scanFsmPtr, bool state)
{
ASSERT(scanFsmPtr != NULL);
DBG_INFO("Update AdvRecvState from [%" PRId8 "] to [%" PRId8 "].\n",
scanFsmPtr->isAdvRecvd, state);
scanFsmPtr->isAdvRecvd = state;
return;
}
/**
* @brief Update 2-Way Acquisition ack state.
*/
static void PendCfmAck(L2_SCAN_FSM *scanFsmPtr)
{
ASSERT(scanFsmPtr != NULL);
DBG_INFO("Pending Cfm-Ack...\n");
scanFsmPtr->isAckPending = true;
return;
}
/*****************************************************************************/
/**
* @brief Update current Scan-Net stage
*
* @param scanFsmPtr A pointer to scan net fsm.
* newStage New state.
*
* @return NONE.
*
******************************************************************************/
static void StageUpdate(L2_SCAN_FSM *scanFsmPtr, SCAN_STAGE newStage)
{
ASSERT(newStage >= L2_SCAN_NONE_STAGE && newStage <= L2_SCAN_CFM_STAGE);
DBG_INFO("ScanNet current stage: %" PRIu8 " -> ScanNet new stage: %" PRIu8 " \n",
scanFsmPtr->scanStage, newStage);
scanFsmPtr->scanStage = newStage;
}
/*****************************************************************************/
/**
* @brief Member node scan net InitScan stage handler.
*
* @param instPtr A pointer to l2 instance
*
* @return used slot (5ms slot).
*
******************************************************************************/
static int32_t Scan_InitScanHandler(L2_INST *instPtr)
{
ASSERT(instPtr != NULL);
PHY_INST *phyRef = instPtr->config.phyInstPtr;
L2_SCAN_FSM *scanFsmPtr = instPtr->scanFSM;
DBG_INFO("** Net-Setup - InitScan Procedure (Attempts: %" PRIu8 ")**\n", scanFsmPtr->scanCnt);
if (scanFsmPtr->scanCnt == 0)
{
// Update scan beam table
L2_Scan_RefreashScanTable(instPtr);
}
else if (Phy_IsFrameDetected(phyRef))
{
// last scan beam number
scanFsmPtr->beamNo = Phy_LastScanBeamNo(phyRef);
// Update scan beam table
L2_Scan_RefreashScanTable(instPtr);
}
if (scanFsmPtr->isLocked == true)
{
scanFsmPtr->beamNo = Phy_LastScanBeamNo(phyRef);
Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_ADV_FRAME);
StageUpdate(scanFsmPtr, L2_SCAN_ADV_STAGE);
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
} /* Otherwise remain L2_SCAN_INIT_STAGE */
else
{
/* Antenna steering (reserved, automatically accomplished by physical layer) */
Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_SCAN_FRAME);
scanFsmPtr->scanCnt++;
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Member node scan net BmAdvt stage handler.
*
* @param scanFsmPtr A pointer to scan net fsm.
* mainState A pointer to main node state.
*
* @return used slot (5ms slot).
*
******************************************************************************/
static int32_t Scan_AdvHandler(L2_INST *instPtr)
{
ASSERT(instPtr != NULL);
L2_SCAN_FSM *scanFsmPtr = instPtr->scanFSM;
PHY_INST *phyRef = instPtr->config.phyInstPtr;
TMC_INST *tmcRef = instPtr->config.tmcInstPtr;
DBG_INFO("** Net-Setup - Advertisement Procedure (Timeout: %" PRIu8 ") **\n", scanFsmPtr->advTimeout);
// if received a valid bm frame.
if (scanFsmPtr->isAdvRecvd == true)
{
// last scan beam number
scanFsmPtr->beamNo = Phy_LastScanBeamNo(phyRef);
// reset listen counter.
scanFsmPtr->advTimeout = 0;
// Update scan stage
StageUpdate(scanFsmPtr, L2_SCAN_CFM_STAGE);
// start a confirm frame reception if in the target slot
if ((TimeCtrl_GetIntCnt(tmcRef) + 1) % CFM_FRAME_SLOTS == 0)
{
// using pull mode to receive confirm frame
// since first time sync procedure is accomplished in ADV stage.
Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_16);
Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
Phy_SetMode(phyRef, PHY_MODE_PULL);
L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_CFM_FRAME);
scanFsmPtr->cfmTimeout++; // increase counter.
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
}
// otherwise skip...
return SUCCESS;
}
// no valid bm frame was received.
else
{
/* if time out reached, go back to init scan stage. */
if (scanFsmPtr->advTimeout > ADV_LISTEN_TIMEOUT)
{
/* Antenna steering (reserved, automatically accomplished by physical layer) */
Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_SCAN_FRAME);
DBG_WARNING("Adv timeout, restart net scan from L2_SCAN_INIT_STAGE.\n");
L2_Scan_Reset(scanFsmPtr);
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
}
else
{
/* Antenna steering (reserved, automatically accomplished by physical layer) */
Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_ADV_FRAME);
scanFsmPtr->advTimeout++;
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
}
return SUCCESS;
}
}
/*****************************************************************************/
/**
* @brief Scan net 2Way-Acq stage handler.
*
* @param instPtr a pointer to linklayer layer instance
*
* @return used slot (5ms slot).
*
******************************************************************************/
static int32_t Scan_CfmHandler(L2_INST *instPtr)
{
ASSERT(instPtr != NULL);
L2_SCAN_FSM *scanFsmPtr = instPtr->scanFSM;
PHY_INST *phyRef = instPtr->config.phyInstPtr;
DBG_INFO("** Net-Setup - Confirm Procedure (Timeout: %" PRIu8 ") **\n", scanFsmPtr->cfmTimeout);
// 2 way acq failed, back to init stage.
if (scanFsmPtr->cfmTimeout >= CFM_LISTEN_TIMEOUT)
{
DBG_WARNING("Cmf timeout, restart net scan from L2_SCAN_INIT_STAGE.\n");
L2_Scan_Reset(scanFsmPtr);
return SUCCESS;
}
if (L2_GetNextSlotNum(instPtr) % CFM_FRAME_SLOTS == 0)
{
// using pull mode to receive confirm frame
// since first time sync procedure is accomplished in ADV stage.
Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_16);
Phy_SetBeamNo(phyRef, scanFsmPtr->beamNo, PHY_ANT_BEAM_16);
Phy_SetMode(phyRef, PHY_MODE_PULL);
L2_SetupNextSlot(instPtr, L2_TOR_RX, L2_CFM_FRAME);
scanFsmPtr->cfmTimeout++; // increase counter.
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Packing Scan message to a bit array.
*
* @param bitarr pointer to bit array buffer.
* @param msgType message type.
*
* @return EPARAM
* SUCCESS
*
******************************************************************************/
static int32_t ScanMsg_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dstId)
{
ASSERT(instPtr != NULL);
int32_t Status;
uint32_t dataChunk;
uint8_t *buff = instPtr->sendPktData;
if (type < L2_ADV_FRAME || type > L2_CFM_FRAME)
{
DBG_ERROR("Unexpected frame type: %" PRId8 ".\n", type);
return EPARAM;
}
// Common section of link layer package
dataChunk = L2_GetNextFrameNum(instPtr);
L2_FrameInsertChunk(buff, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &dataChunk);
dataChunk = L2_GetNextSlotNum(instPtr);
L2_FrameInsertChunk(buff, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &dataChunk);
dataChunk = L2_GetNodeId(instPtr);
L2_FrameInsertChunk(buff, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &dataChunk);
dataChunk = dstId;
L2_FrameInsertChunk(buff, L2_MSG_DST_ID, L2_MSG_DST_ID_LEN, &dataChunk);
switch (type)
{
case L2_ADV_FRAME:
{
dataChunk = L2_ADV_FRAME;
L2_FrameInsertChunk(buff, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &dataChunk);
SysMonitor_GetSysinfo(&(instPtr->sysInfo));
// insert position and speed info
L2_FrameInsertChunk(buff, L2_MSG_ADV_SRC_POSX, L2_MSG_ADV_SRC_POSX_LEN, &(instPtr->sysInfo.posX));
L2_FrameInsertChunk(buff, L2_MSG_ADV_SRC_POSY, L2_MSG_ADV_SRC_POSY_LEN, &(instPtr->sysInfo.posY));
L2_FrameInsertChunk(buff, L2_MSG_ADV_SRC_POSZ, L2_MSG_ADV_SRC_POSZ_LEN, &(instPtr->sysInfo.posZ));
// Insert net start time
L2_FrameInsertChunk(buff, L2_MSG_ADV_SRC_NETSTART_TIME, L2_MSG_ADV_SRC_NETSTART_TIME_LEN, &(instPtr->netStartTime));
// Append CRC
Status = L2_CrcAppend(buff, L2_ADV_PACK_LEN - L2_MSG_ADV_SVC_CRC_LEN, L2_MSG_ADV_SVC_CRC, L2_CRC16_1021);
if (Status != SUCCESS)
{
DBG_ERROR("Fail to append CRC, error code: %" PRId32 ".\n", Status);
return Status;
}
break;
}
case L2_CFM_FRAME:
{
dataChunk = L2_CFM_FRAME;
L2_FrameInsertChunk(buff, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &dataChunk);
SysMonitor_GetSysinfo(&(instPtr->sysInfo));
// insert position and speed info
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_POSX, L2_MSG_CFM_SRC_POSX_LEN, &(instPtr->sysInfo.posX));
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_POSY, L2_MSG_CFM_SRC_POSY_LEN, &(instPtr->sysInfo.posY));
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_POSZ, L2_MSG_CFM_SRC_POSZ_LEN, &(instPtr->sysInfo.posZ));
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_SPEEDX, L2_MSG_CFM_SRC_SPEEDX_LEN, &(instPtr->sysInfo.vX));
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_SPEEDY, L2_MSG_CFM_SRC_SPEEDY_LEN, &(instPtr->sysInfo.vY));
L2_FrameInsertChunk(buff, L2_MSG_CFM_SRC_SPEEDZ, L2_MSG_CFM_SRC_SPEEDZ_LEN, &(instPtr->sysInfo.vZ));
// Packing extra payload
uint32_t dataId;
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
{
SysMonitor_GetSendPayload(buff + L2_MSG_CFM_PAYLOAD, &dataId, PAYLOAD_LEN_FLJ_TX);
}
else
{
SysMonitor_GetSendPayload(buff + L2_MSG_CFM_PAYLOAD, &dataId, PAYLOAD_LEN_LJ_TX);
}
L2_FrameInsertChunk(buff, L2_MSG_CFM_PAYLOAD_ID, L2_MSG_CFM_PAYLOAD_ID_LEN, &dataId);
if (dataId == DATA_ID_NONE)
{
memset(buff + L2_MSG_CFM_PAYLOAD, 0xAA, L2_MSG_CFM_PAYLOAD_LEN);
}
// Append CRC
Status = L2_CrcAppend(buff, L2_CMF_PACK_LEN - L2_MSG_CFM_CRC_LEN, L2_MSG_CFM_CRC, L2_CRC16_1021);
if (Status != SUCCESS)
{
DBG_ERROR("Fail to append CRC, error code: %" PRId32 ".\n", Status);
return Status;
}
// Logging...
memcpy(instPtr->log.txLog.data, buff, L2_CMF_PACK_LEN);
instPtr->log.txLog.dataId = dataId;
break;
}
default:
{
DBG_ERROR("Unexpected frame type: %" PRId8 ".\n", type);
return EPARAM;
}
}
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Scan net packet handler.
*
* @param instPtr a pointer to linklayer layer instance
* @param msg A pointer to frame data buffer.
*
* @return
*
******************************************************************************/
int32_t L2_Scan_PktHandler(L2_INST *instPtr, uint8_t *msg)
{
ASSERT(instPtr != NULL);
ASSERT(msg != NULL);
int32_t Status;
uint8_t srcId = L2_NONE_ID;
uint8_t dstId = L2_NONE_ID;
L2_FRAME_TYPE frameType = L2_NONE_FRAME;
L2_SCAN_FSM *scanFsmPtr = instPtr->scanFSM;
L2_FrameGetChunk(msg, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &frameType);
L2_FrameGetChunk(msg, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &srcId);
L2_FrameGetChunk(msg, L2_MSG_DST_ID, L2_MSG_DST_ID_LEN, &dstId);
if(dstId != L2_GetNodeId(instPtr) && L2_GetNodeType(instPtr) == L2_NODE_HEAD)
{
DBG_WARNING("Drop frame not addressed to me (%u)", nodeId);
return SUCCESS;
}
else if(dstId != L2_GetNodeId(instPtr) && dstId == L2_NONE_ID)
{
DBG_WARNING("Drop frame not addressed to me (%u)", nodeId);
return SUCCESS;
}
switch (frameType)
{
case L2_SCAN_FRAME:
case L2_ADV_FRAME:
{
if (L2_GetLastOptFrameType(instPtr) == L2_SCAN_FRAME)
{
LockStateUpdate(scanFsmPtr, true);
StageUpdate(scanFsmPtr, L2_SCAN_ADV_STAGE);
}
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
{
DBG_ERROR("Unexpected call from head node, only member Node can handle L2_SCAN_FRAME and L2_ADV_FRAME.\n");
Status = EUNEXP;
break;
}
NODE_ENTRY *node;
node = L2_GetNodeById(instPtr->nodeList, srcId);
if (node == NULL)
{
node = L2_AppendNode(instPtr->nodeList, srcId, L2_NODE_MEMBER);
if (node == NULL)
{
DBG_ERROR("Failed to append new node [id: %" PRId8 "]", srcId);
Status = ENOMEM;
break;
}
}
// Update node info.
float nodePos;
L2_FrameGetChunk(msg, L2_MSG_ADV_SRC_POSX, L2_MSG_ADV_SRC_POSX_LEN, &nodePos);
node->nodeInfo.pos.x = (double)nodePos;
L2_FrameGetChunk(msg, L2_MSG_ADV_SRC_POSY, L2_MSG_ADV_SRC_POSY_LEN, &nodePos);
node->nodeInfo.pos.y = (double)nodePos;
L2_FrameGetChunk(msg, L2_MSG_ADV_SRC_POSZ, L2_MSG_ADV_SRC_POSZ_LEN, &nodePos);
node->nodeInfo.pos.z = (double)nodePos;
node->nodeInfo.beamNo = Phy_LastScanBeamNo(instPtr->config.phyInstPtr);
// Reset node ttl
node->ttlCnt = 0;
uint32_t netstartTime;
// Update net start time.
L2_FrameGetChunk(msg, L2_MSG_ADV_SRC_NETSTART_TIME, L2_MSG_ADV_SRC_NETSTART_TIME_LEN, &netstartTime);
L2_EVENT netSetupDoneEvent = {
.event = L2_EV_NET_ADV_UPDATE,
.msg = &netstartTime};
AssertL2Event(instPtr, &netSetupDoneEvent);
// Calculate time deviation
uint32_t frameNum, slotNum = 0;
L2_FrameGetChunk(msg, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &frameNum);
L2_FrameGetChunk(msg, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &slotNum);
Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev));
if (Status != SUCCESS)
{
DBG_ERROR("Failed to compute time deviation.\n");
break;
}
// Time sync.
L2_TimeAdjust(instPtr, &(instPtr->log.timeDev));
// trigger flag
AdvRecvStateUpdate(scanFsmPtr, true);
Status = SUCCESS;
break;
}
case L2_CFM_FRAME:
{
NODE_ENTRY *node;
node = L2_GetNodeById(instPtr->nodeList, srcId);
if (node == NULL)
{
node = L2_AppendNode(instPtr->nodeList, srcId, L2_NODE_MEMBER);
if (node == NULL)
{
DBG_ERROR("Failed to append new node [id: %" PRId8 "]", srcId);
Status = ENOMEM;
break;
}
}
// Update node info.
float nodePos;
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_POSX, L2_MSG_CFM_SRC_POSX_LEN, &nodePos);
node->nodeInfo.pos.x = (double)nodePos;
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_POSY, L2_MSG_CFM_SRC_POSY_LEN, &nodePos);
node->nodeInfo.pos.y = (double)nodePos;
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_POSZ, L2_MSG_CFM_SRC_POSZ_LEN, &nodePos);
node->nodeInfo.pos.z = (double)nodePos;
float nodeSpeed;
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_SPEEDX, L2_MSG_CFM_SRC_SPEEDX_LEN, &nodeSpeed);
node->nodeInfo.speed.x = (double)nodePos;
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_SPEEDY, L2_MSG_CFM_SRC_SPEEDY_LEN, &nodeSpeed);
node->nodeInfo.speed.y = (double)nodePos;
L2_FrameGetChunk(msg, L2_MSG_CFM_SRC_SPEEDZ, L2_MSG_CFM_SRC_SPEEDZ_LEN, &nodeSpeed);
node->nodeInfo.speed.z = (double)nodePos;
// Reset node ttl
node->ttlCnt = 0;
// Calculate time deviation
uint32_t frameNum, slotNum = 0;
L2_FrameGetChunk(msg, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &frameNum);
L2_FrameGetChunk(msg, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &slotNum);
Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev));
if (Status != SUCCESS)
{
DBG_ERROR("Failed to compute time deviation.\n");
break;
}
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
{
// check if net setup finished.
if (L2_isCxn2Net(instPtr) == false)
{
// Assert Net-Setup Done.
L2_EVENT l2Event;
l2Event.event = L2_EV_NET_SETUP_DONE;
l2Event.msg = NULL;
AssertL2Event(instPtr, &l2Event);
// Assert update routine event...
L2_RTNE_CONFIG newRtneConfig = {0};
L2_EVENT rtneUpEvent =
{
.event = L2_ROUTINE_UPDATE,
.msg = &newRtneConfig
};
newRtneConfig.rtneTable = initTable;
newRtneConfig.rtnePrd = ARRAY_SIZE(initTable);
AssertL2Event(instPtr, &rtneUpEvent);
}
PendCfmAck(instPtr->scanFSM);
// Time sync.
L2_TimeAdjust(instPtr, &(instPtr->log.timeDev));
}
else
{
if (L2_GetMainState(instPtr) == L2_INIT_STATE
&& L2_GetNodeListLen(instPtr->nodeList) >= instPtr->config.netScale - 1)
{
// Assert Net-Setup Done.
L2_EVENT l2Event;
L2_NODE_STATE newState = L2_NORMAL_STATE;
l2Event.event = L2_EV_MAIN_STATE_UPDATE;
l2Event.msg = &newState;
AssertL2Event(instPtr, &l2Event);
}
}
// Get data payload
uint32_t dataId;
L2_FrameGetChunk(msg, L2_MSG_CFM_PAYLOAD_ID, L2_MSG_CFM_PAYLOAD_ID_LEN, &dataId);
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
{
SysMonitor_UpdateRecvPayload(msg + L2_MSG_CFM_PAYLOAD, dataId, PAYLOAD_LEN_FLJ_RX);
}
else
{
SysMonitor_UpdateRecvPayload(msg + L2_MSG_CFM_PAYLOAD, dataId, PAYLOAD_LEN_LJ_RX);
}
// Logging...
memcpy(instPtr->log.rxLog.data, msg, L2_CMF_PACK_LEN);
instPtr->log.rxLog.dataId = dataId;
Status = SUCCESS;
break;
}
default:
DBG_ERROR("Unsupported frame type: %" PRId8 ".\n", frameType);
Status = EUNEXP;
break;
}
return Status;
}
/*****************************************************************************/
/**
* @brief Initialize scan FSM.
*
* @param instPtr
*
* @return
*
******************************************************************************/
int32_t L2_Scan_Init(L2_SCAN_FSM **scanFSMPtr)
{
ASSERT(scanFSMPtr != NULL);
*scanFSMPtr = (L2_SCAN_FSM *)malloc(sizeof(L2_SCAN_FSM));
if (*scanFSMPtr == NULL)
{
DBG_ERROR("Failed to allocate memory for scanFsmPtr.\n");
return ENOMEM;
}
L2_Scan_Reset(*scanFSMPtr);
(*scanFSMPtr)->beamNo = 0;
(*scanFSMPtr)->tableNo = 0;
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Reset ScanNet FSM
*
* @param scanFsmPtr a pointer to scan net finite state machine
*
* @return NONE
*
******************************************************************************/
void L2_Scan_Reset(L2_SCAN_FSM *scanFSMPtr)
{
ASSERT(scanFSMPtr != NULL);
scanFSMPtr->isLocked = false;
scanFSMPtr->isAdvRecvd = false;
scanFSMPtr->isAckPending = false;
scanFSMPtr->scanCnt = 0;
scanFSMPtr->advTimeout = 0;
scanFSMPtr->cfmTimeout = 0;
scanFSMPtr->scanStage = L2_SCAN_NONE_STAGE;
}
/*****************************************************************************/
/**
* @brief Destroy ScanNet FSM, free memory
*
* @param scanFsmPtr a pointer to scan net finite state machine
*
* @return NONE
*
******************************************************************************/
void L2_Scan_Destroy(L2_SCAN_FSM *scanFSMPtr)
{
free(scanFSMPtr);
}
/*****************************************************************************/
/**
* @brief Refresh scan beam table.
*
* @param instPtr a pointer to linklayer layer instance
*
* @return NONE
*
******************************************************************************/
void L2_Scan_RefreashScanTable(L2_INST *instPtr)
{
ASSERT(instPtr != NULL);
L2_SCAN_FSM *scanFsmPtr = instPtr->scanFSM;
PHY_INST *phyRef = instPtr->config.phyInstPtr;
if (scanFsmPtr->tableNo == 0)
{
Phy_SetBeamTable(phyRef, antNrrwPattern_0, scanFsmPtr->beamNo);
scanFsmPtr->tableNo = 1;
}
else
{
Phy_SetBeamTable(phyRef, antNrrwPattern_1, scanFsmPtr->beamNo);
scanFsmPtr->tableNo = 0;
}
}
/*****************************************************************************/
/**
* @brief Execute a member node scan net procedure.
*
* @param instPtr a pointer to linklayer layer instance
*
* @return used slot (5ms slot).
*
******************************************************************************/
int32_t L2_Scan_Proc(L2_INST *instPtr)
{
L2_SCAN_FSM *scanFSM = instPtr->scanFSM;
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
{
DBG_ERROR("Only member node needs to execute L2_Scan_Proc. \n");
return FAILURE;
}
int32_t Status;
DBG_INFO("-------- ScanNet Process --------\n");
switch (scanFSM->scanStage)
{
case L2_SCAN_NONE_STAGE:
/* Start Scan. */
StageUpdate(scanFSM, L2_SCAN_INIT_STAGE);
Status = Scan_InitScanHandler(instPtr);
break;
case L2_SCAN_INIT_STAGE:
Status = Scan_InitScanHandler(instPtr);
break;
case L2_SCAN_ADV_STAGE:
Status = Scan_AdvHandler(instPtr);
break;
case L2_SCAN_CFM_STAGE:
Status = Scan_CfmHandler(instPtr);
break;
default:
DBG_ERROR("Unexpected scan net stage: %" PRId8 ".\n", scanFSM->scanStage);
Status = FAILURE;
break;
}
return Status;
}
/*****************************************************************************/
/**
* @brief Execute a scan net Routine procedure.
*
* @param rtneEntry Routine configuration
*
* @return used slot (5ms slot).
*
******************************************************************************/
int32_t L2_Scan_Routine(L2_INST *instPtr, const L2_RTNE_TABLE_ENTRY *rtneEntry)
{
ASSERT(instPtr != NULL);
L2_TOR_TYPE torState;
int32_t Status;
const NODE_ENTRY *commNode;
PHY_INST *phyRef = instPtr->config.phyInstPtr;
DBG_INFO("-------- Scan Routine --------\n");
if (rtneEntry->slotSeq != 0)
{
return SUCCESS; // skip
}
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
{
if (rtneEntry->dst == L2_GetNodeId(instPtr) || rtneEntry->dst == L2_BROADCAST_ID)
{
torState = L2_TOR_RX;
commNode = L2_GetNodeById(instPtr->nodeList, rtneEntry->src);
}
else if (rtneEntry->src == L2_GetNodeId(instPtr) || rtneEntry->src == L2_BROADCAST_ID)
{
torState = L2_TOR_TX;
commNode = L2_GetNodeById(instPtr->nodeList, rtneEntry->dst);
}
else
{
torState = L2_TOR_SUSPEND;
}
// Setup antenna beam
Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_16);
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
if (commNode != NULL)
{
Phy_SetBeamNo(phyRef, commNode->nodeInfo.beamNo, PHY_ANT_BEAM_16);
}
}
else
{
if (rtneEntry->dst == L2_GetNodeId(instPtr))
{
torState = L2_TOR_RX;
}
else if (rtneEntry->src == L2_GetNodeId(instPtr))
{
torState = L2_TOR_TX;
}
else
{
torState = L2_TOR_SUSPEND;
}
// Setup antenna beam
Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_120);
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_120;
}
switch (rtneEntry->slotType)
{
case L2_SLOT_SCAN:
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD && torState == L2_TOR_TX)
{
DBG_ERROR("Only head node can send init-scan Frame.\n");
Status = FAILURE;
goto routine_err;
}
L2_SetupNextSlot(instPtr, torState, L2_SCAN_FRAME);
break;
case L2_SLOT_ADVERTISE:
if (torState == L2_TOR_TX)
{
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
{
DBG_ERROR("Only head node can send ADV Frame.\n");
Status = FAILURE;
goto routine_err;
}
memset(instPtr->sendPktData, 0xAA, L2_PACK_LEN_MAX);
if (ScanMsg_Packing(instPtr, L2_ADV_FRAME, rtneEntry->dst) != SUCCESS)
{
Status = FAILURE;
goto routine_err;
}
}
/* Antenna setting (reserved.) */
L2_SetupNextSlot(instPtr, torState, L2_ADV_FRAME);
break;
case L2_SLOT_CONFIRM:
if (torState == L2_TOR_TX)
{
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
{
if (instPtr->scanFSM->isAckPending == false)
{
DBG_INFO("Member node has no pending CFM-Ack frame.\n");
break;
}
}
memset(instPtr->sendPktData, 0xAA, L2_PACK_LEN_MAX);
if (ScanMsg_Packing(instPtr, L2_CFM_FRAME, rtneEntry->dst) != SUCCESS)
{
Status = FAILURE;
goto routine_err;
}
}
/* Antenna setting (reserved.) */
L2_SetupNextSlot(instPtr, torState, L2_CFM_FRAME);
break;
default:
DBG_ERROR("Cannot start a routine for slot type [%" PRId8 "] properly.\n", rtneEntry->slotType);
Status = FAILURE;
goto routine_err;
}
return SUCCESS;
routine_err:
return Status;
}
/** @} LinkLayer_Scan*/
/** @} LinkLayer*/
+438
View File
@@ -0,0 +1,438 @@
/*****************************************************************************/
/**
* @file schdevent.c
* @author FanHao ([email protected])
* @brief DF Linklayer Event scheduling implementation file.
* @version 0.1
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup LinkLayer
* @{
*/
/**
* @addtogroup LinkLayer_Scheduler
* @{
*/
/***************************** Include Files *********************************/
#include <stdlib.h>
#include "schdevent.h"
#include "link_layer.h"
#include "link_layer_types.h"
#include "error.h"
#include "clist.h"
/***************** Macros (Inline Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
/************************** Variable Definitions *****************************/
static L2_SCHD_EVENT util_schdevent;
/************************** Function Prototypes ******************************/
/**
* @brief helper function to free schedule events.
*/
static void schdevent_free(void *val)
{
if (val == NULL)
{
return;
}
free(((L2_SCHD_EVENT *)val)->l2Event.msg);
free(val);
}
/**
* @brief helper function to match events by ids.
*/
static int8_t schdevent_compare(void *a, void *b)
{
ASSERT(a == NULL);
ASSERT(b != NULL);
register uint32_t idA, idB;
idA = ((L2_SCHD_EVENT *)a)->eventId;
idB = ((L2_SCHD_EVENT *)b)->eventId;
if (idA == idB)
{
return 0;
}
else if (idA < idB)
{
return -1;
}
else
{
return 1;
}
}
/*****************************************************************************/
/**
* @brief Creat a schedule event pool.
*
* @param schdPool a pointer to schedule pool instance.
*
* @return SUCCESS
*
******************************************************************************/
int32_t L2_CreateSchedEventPool(L2_SCHD_POOL **schdPool)
{
(*schdPool) = malloc(sizeof(L2_SCHD_POOL));
if (*schdPool == NULL)
{
DBG_ERROR("Failed to allocated memory for schdPool.\n");
return ENOMEM;
}
(*schdPool)->schdList = clist_new();
if ((*schdPool)->schdList == NULL)
{
DBG_ERROR("Failed to allocated memory for schdPool->schdList.\n");
free(*schdPool);
return ENOMEM;
}
(*schdPool)->schdList->free = schdevent_free;
(*schdPool)->schdList->compare = schdevent_compare;
(*schdPool)->envCnt = 0;
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Clear schedule event pool, delete all events in pool and
* free allocated memory.
*
* @param schdPool a pointer to schedule pool instance.
*
* @return SUCCESS
*
******************************************************************************/
void L2_ClearSchedEventPool(L2_SCHD_POOL *schdPool)
{
ASSERT(schdPool != NULL);
clist_clear(schdPool->schdList);
schdPool->envCnt = 0;
}
/*****************************************************************************/
/**
* @brief Completely destroy schedule event pool.
*
* @param schdPool a pointer to schedule pool instance.
*
* @return SUCCESS
*
******************************************************************************/
void L2_DestroySchedEventPool(L2_SCHD_POOL *schdPool)
{
if (schdPool == NULL)
{
return;
}
clist_destroy(schdPool->schdList);
free(schdPool);
}
/*****************************************************************************/
/**
* @brief Creat a new schedule event, register event in schedule event pool.
*
* @param schdPool a pointer to schedule pool instance.
* @param event event type of the new schedule event.
* @param isVolatile event type of the new schedule event.
*
* @return NULL error occurred
* Pointer to schedule event.
*
******************************************************************************/
L2_SCHD_EVENT *L2_CreatNewSchdEvent(L2_SCHD_POOL *schdPool, L2_EVENT_TYPE event, bool isVolatile)
{
ASSERT(schdPool != NULL);
if (event < L2_EV_SCAN_PROC_DONE || event > L2_ROUTINE_UPDATE)
{
DBG_ERROR("Unknown event type: %" PRId8 ".\n", event);
return NULL;
}
L2_SCHD_EVENT *schdEvent = (L2_SCHD_EVENT *)malloc(sizeof(L2_SCHD_EVENT));
if (schdEvent == NULL)
{
DBG_ERROR("Failed to allocate schedule event.\n");
return NULL;
}
clist_node_t *node = clist_node_new(schdEvent);
if (node == NULL)
{
DBG_ERROR("Failed to allocate schedule event list node.\n");
free(schdEvent);
return NULL;
}
schdEvent->eventId = schdPool->envCnt++;
schdEvent->occurCnt = 0;
schdEvent->l2Event.event = event;
schdEvent->l2Event.msg = NULL;
schdEvent->isSchd = false;
schdEvent->isVolatile = isVolatile;
schdEvent->schdSlot = L2_SLOTNO_NONE;
schdEvent->schdFrame = L2_FRAMENO_NONE;
clist_rpush(schdPool->schdList, node);
return schdEvent;
}
/*****************************************************************************/
/**
* @brief Get a schedule event by its id.
*
* @param schdPool a pointer to schedule pool instance.
* @param id ID of the event
*
* @return NULL
* Pointer to the schedule event.
*
******************************************************************************/
L2_SCHD_EVENT *L2_GetEventById(L2_SCHD_POOL *schdPool, uint32_t id)
{
ASSERT(schdPool != NULL);
util_schdevent.eventId = id;
clist_node_t *node = clist_find(schdPool->schdList, &util_schdevent);
if (node != NULL)
{
DBG_WARNING("Event with id=%" PRIu32 ", dose not exist.\n", id);
return NULL;
}
return ((L2_SCHD_EVENT *)node->val);
}
/*****************************************************************************/
/**
* @brief Delete a schedule event, remove the event from event pool,
* release memory.
*
* @param schdPool a pointer to schedule pool instance.
* @param id ID of the event
*
* @return SUCCESS
* error code
*
******************************************************************************/
int32_t L2_DeleteSchdEventById(L2_SCHD_POOL *schdPool, uint32_t id)
{
ASSERT(schdPool != NULL);
util_schdevent.eventId = id;
clist_node_t *node = clist_find(schdPool->schdList, &util_schdevent);
if (node != NULL)
{
DBG_ERROR("Event with id=%" PRIu32 ", dose not exist.\n", id);
return EIGNORE;
}
clist_remove(schdPool->schdList, node);
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Schedule a event at a specific time(indexed by frame and slot number)
*
* @param instPtr a pointer to linklayer instance
* @param schdEvent pointer to the schedule event.
* @param frameNum schedule frame number
* @param slotNum schedule slot number
*
* @return FAILURE, event has already been scheduled/schedule time not allowed.
* SUCCESS
*
******************************************************************************/
int32_t L2_ScheduleEventAt(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t frameNum, uint32_t slotNum)
{
ASSERT(schdEvent != NULL);
if (L2_isEventScheduled(schdEvent) == true)
{
DBG_ERROR("Event %" PRIu32 " has already been scheduled.\n", schdEvent->eventId);
return FAILURE;
}
if (frameNum <= L2_GetCurrentFrameNum(instPtr) && slotNum < L2_GetCurrentSlotNum(instPtr))
{
DBG_ERROR("Cannot schedule event %" PRIu32 " to the past(current: [%" PRIu32 "-%" PRIu32 "], schedule: [%" PRIu32 "-%" PRIu32 "]).\n",
schdEvent->eventId, L2_GetCurrentFrameNum(instPtr), L2_GetCurrentSlotNum(instPtr), frameNum, slotNum);
return FAILURE;
}
DBG_INFO("Schedule event (type:%" PRIu8 ") [%" PRIu32 "] at %" PRIu32 "-%" PRIu32 ".\n",
schdEvent->l2Event.event, schdEvent->eventId,
frameNum, slotNum);
schdEvent->isSchd = true;
schdEvent->schdFrame = frameNum;
schdEvent->schdSlot = slotNum;
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Schedule a event after a specific time period.
*
* @param instPtr a pointer to linklayer instance
* @param schdEvent pointer to the schedule event.
* @param numSlots how many slot later the event should be scheduled
*
* @return FAILURE, event has already been scheduled/schedule time not allowed.
* SUCCESS
*
******************************************************************************/
int32_t L2_ScheduleEventAfter(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t numSlots)
{
ASSERT(schdEvent != NULL);
if (L2_isEventScheduled(schdEvent) == true)
{
DBG_ERROR("Event %" PRIu32 " has already been scheduled.\n", schdEvent->eventId);
return FAILURE;
}
uint32_t frameNum = L2_GetCurrentFrameNum(instPtr) + (numSlots / L2_SLOTS_PER_FRAME);
uint32_t slotNum = L2_GetCurrentSlotNum(instPtr) + (numSlots % L2_SLOTS_PER_FRAME);
return L2_ScheduleEventAt(instPtr, schdEvent, frameNum, slotNum);
}
/*****************************************************************************/
/**
* @brief Reschedule a event at a specific time(indexed by frame and slot number)
*
* @param instPtr a pointer to linklayer instance
* @param schdEvent pointer to the schedule event.
* @param frameNum schedule frame number
* @param slotNum schedule slot number
*
* @return FAILURE, event has already been scheduled/schedule time not allowed.
* SUCCESS
*
******************************************************************************/
int32_t L2_RescheduleEventAt(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t frameNum, uint32_t slotNum)
{
ASSERT(schdEvent != NULL);
if (schdEvent->isSchd == false)
{
DBG_WARNING("Event %" PRIu32 " has not been scheduled yet.\n", schdEvent->eventId);
}
schdEvent->isSchd = false;
return L2_ScheduleEventAt(instPtr, schdEvent, frameNum, slotNum);
}
/*****************************************************************************/
/**
* @brief Reschedule a event after a specific time period.
*
* @param instPtr a pointer to linklayer instance
* @param schdEvent pointer to the schedule event.
* @param numSlots how many slot later the event should be scheduled
*
* @return FAILURE, event has already been scheduled/schedule time not allowed.
* SUCCESS
*
******************************************************************************/
int32_t L2_RescheduleEventAfter(L2_INST *instPtr, L2_SCHD_EVENT *schdEvent, uint32_t numSlots)
{
ASSERT(schdEvent != NULL);
if (schdEvent->isSchd == false)
{
DBG_WARNING("Event %" PRIu32 " has not been scheduled yet.\n", schdEvent->eventId);
}
return L2_ScheduleEventAfter(instPtr, schdEvent, numSlots);
}
/*****************************************************************************/
/**
* @brief Check and excute schedule event in event pool illiterate.
*
* @param instPtr a pointer to linklayer instance
*
* @return NONE.
*
******************************************************************************/
void L2_EventPoolHandler(L2_INST *instPtr)
{
ASSERT(instPtr != NULL);
clist_node_t *node;
L2_SCHD_EVENT *event;
L2_SCHD_POOL *pool = instPtr->schdEventPool;
clist_iterator_t *iter = clist_iterator_new(pool->schdList, LIST_HEAD);
if (iter == NULL)
{
DBG_ERROR("Failed to initialize schedule event pool iteration.\n");
return;
}
while ((node = clist_iterator_next(iter)))
{
event = (L2_SCHD_EVENT *)node->val;
if (L2_isEventScheduled(event))
{
if (event->schdFrame == L2_GetCurrentFrameNum(instPtr) && event->schdSlot == L2_GetCurrentSlotNum(instPtr))
{
DBG_INFO("Asserting scheduled event [%" PRIu32 "].\n", event->eventId);
AssertL2Event(instPtr, &(event->l2Event));
if (event->isVolatile == true)
{
DBG_INFO("Deleting scheduled event [%" PRIu32 "], since it is volatile.\n", event->eventId);
clist_remove(pool->schdList, node);
}
else
{
event->occurCnt++;
}
}
}
}
clist_iterator_destroy(iter);
}
/*****************************************************************************/
/**
* @brief Append extra message content to specific schedule event.
*
* @param schdEvent pointer to the schedule event.
* msg pointer to the append content.
*
* @return SUCCESS.
* error code.
*
******************************************************************************/
inline void L2_SchdEventAppendMsg(L2_SCHD_EVENT *schdEvent, void *msg)
{
ASSERT(schdEvent != NULL);
schdEvent->l2Event.msg = msg;
}
/*****************************************************************************/
/**
* @brief Cancel a scheduled event.
*
* @param schdEvent pointer to the schedule event.
*
* @return SUCCESS.
*
******************************************************************************/
inline int32_t L2_CancelEvent(L2_SCHD_EVENT *schdEvent)
{
ASSERT(schdEvent != NULL);
if (schdEvent->isSchd == false)
{
DBG_WARNING("Event %" PRIu32 " has not been scheduled yet.\n", schdEvent->eventId);
}
schdEvent->isSchd = false;
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Check if the event was scheduled.
*
* @param schdEvent pointer to the schedule event.
*
* @return true.
* false.
*
******************************************************************************/
inline bool L2_isEventScheduled(const L2_SCHD_EVENT *schdEvent)
{
ASSERT(schdEvent != NULL);
return schdEvent->isSchd;
}
/** @} LinkLayer_Scheduler*/
/** @} LinkLayer*/
+76
View File
@@ -0,0 +1,76 @@
/*****************************************************************************/
/**
* @file schdevent.c
* @author FanHao ([email protected])
* @brief DF Linklayer Event scheduling header file.
* @version 0.1
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup LinkLayer
* @{
*/
/**
* @addtogroup LinkLayer_Scheduler
* @{
*/
#ifndef SCHDEVENT_H_
#define SCHDEVENT_H_
#define SCHDEVENT_ID_NONE UINT32_MAX
/***************************** Include Files *********************************/
#include <stdlib.h>
#include "link_layer_types.h"
#include "error.h"
#include "clist.h"
/***************** Macros (Inline Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
/**
* @struct L2_SCHD_EVENT
* @brief Linklayer scheduled event descriptor
*/
typedef struct
{
bool isSchd;
bool isVolatile;
L2_EVENT l2Event;
uint32_t eventId;
uint32_t occurCnt;
uint32_t schdFrame;
uint32_t schdSlot;
} L2_SCHD_EVENT;
/**
* @struct L2_SCHD_POOL
* @brief Linklayer schedule event pool instance
*/
typedef struct
{
clist_t *schdList;
uint32_t envCnt;
} L2_SCHD_POOL;
/************************** Variable Definitions *****************************/
/************************** Function Prototypes ******************************/
// Scheduling Event
int32_t L2_CreateSchedEventPool(L2_SCHD_POOL **schdPool);
void L2_ClearSchedEventPool(L2_SCHD_POOL *schdPool);
void L2_DestroySchedEventPool(L2_SCHD_POOL *schdPool);
L2_SCHD_EVENT *L2_CreatNewSchdEvent(L2_SCHD_POOL *schdPool, L2_EVENT_TYPE event, bool isVolatile);
L2_SCHD_EVENT *L2_GetEventById(L2_SCHD_POOL *schdPool, uint32_t id);
int32_t L2_DeleteSchdEventById(L2_SCHD_POOL *schdPool, uint32_t id);
void L2_SchdEventAppendMsg(L2_SCHD_EVENT *schdEvent, void *msg);
bool L2_isEventScheduled(const L2_SCHD_EVENT *schdEvent);
int32_t L2_CancelEvent(L2_SCHD_EVENT *schdEvent);
#endif // SCHDEVENT_H_
/** @} LinkLayer_Scheduler*/
/** @} LinkLayer*/
+440
View File
@@ -0,0 +1,440 @@
/*****************************************************************************/
/**
* @file service.c
* @author FanHao ([email protected])
* @brief DF Linklayer service implementation file.
* @version 0.0
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup LinkLayer
* @{
*/
/**
* @addtogroup LinkLayer_Service
* @{
*/
/***************************** Include Files *********************************/
#include <string.h>
#include <stdint.h>
#include "link_layer.h"
#include "link_layer_types.h"
#include "msg_def.h"
#include "error.h"
#include "common.h"
#include "circ_queue.h"
#ifndef EMULATION
#include "../config/app_config.h"
#endif
/************************** Constant Definitions *****************************/
/***************** Macros (Inline Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
/************************** Function Prototypes ******************************/
static int32_t Service_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dstId);
/************************** Variable Definitions *****************************/
static uint8_t testData[L2_PACK_LEN_MAX] =
{
0x39, 0x85, 0x02, 0xF0, 0xC7, 0x6A, 0xE8, 0xB4, 0xE7, 0xAB, 0xC9, 0xDC, 0x0B, 0x41, 0x42, 0xE0,
0xED, 0x21, 0x07, 0x62, 0x4E, 0x80, 0xA0, 0xE1, 0xAC, 0x77, 0x9B, 0x1F, 0x48, 0x0B, 0x58, 0xB9,
0x45, 0xA5, 0x24, 0xEF, 0xF3, 0x71, 0x2E, 0x84, 0x6C, 0x22, 0xB3, 0x05, 0xEB, 0x75, 0xF2, 0x0B,
0x45, 0x73, 0x01, 0xA8, 0x1E, 0x00, 0x21, 0x3E, 0x03, 0x86, 0x55, 0x59, 0x98, 0x5C, 0x61, 0xA2,
0xE8, 0x20, 0x0E, 0x7A, 0xD5, 0x72, 0xAF, 0xF4, 0xBC, 0xB3, 0x6F, 0xFE, 0xB3, 0x78, 0x6A, 0x59,
0x73, 0xBD, 0x97, 0xBE, 0x44, 0xA4, 0x9B, 0x71, 0x11, 0x45, 0x37, 0xFE, 0xB3, 0x71, 0xEF, 0x1E,
0x3A, 0x2B, 0x58, 0x07, 0xF6, 0x01, 0x1C, 0x73, 0x28, 0x11, 0xA8, 0x15, 0xA2, 0x58, 0x32, 0x2E,
0x7D, 0x35, 0x9C, 0xE4, 0x98, 0x7F, 0x9C, 0x81, 0x32, 0xAA, 0xC4, 0x87, 0x16, 0x26, 0x23, 0x95,
0x57, 0xC9, 0xD4, 0x34, 0xCE, 0x63, 0x78, 0x7E, 0xD4, 0x3C, 0x16, 0x1D, 0x80, 0xC0, 0x55, 0xBF,
0xB5, 0xD6, 0x0C, 0xA5, 0xB9, 0x0A, 0x14, 0x5B, 0x4D, 0x52, 0xF2, 0xA9, 0x7A, 0x08, 0x67, 0x8E,
0xEB, 0x67, 0x34, 0x7F, 0x7A, 0x35, 0xAF, 0xD9, 0x07, 0x52, 0x30, 0x38, 0x70, 0xC9, 0x41, 0xF8,
0x36, 0x61, 0x32, 0x72, 0xA4, 0x7A, 0xEA, 0x21, 0xB4, 0xBF, 0xAA, 0xCF, 0x93, 0x4F, 0xE1, 0x5C,
0xA0, 0xFB, 0xD0, 0x2B, 0xA3, 0x82, 0x2E, 0x69, 0x7D, 0xB7, 0x76, 0x88, 0xF7, 0x5C, 0xF3, 0x82,
0xC6, 0x6D, 0x49, 0x92, 0x64, 0x88, 0x9A, 0x43, 0xEE, 0xE9, 0x93, 0xC3, 0x70, 0x50, 0x22, 0xF1,
0xD3, 0x2B, 0xCF, 0xA9, 0xE5, 0x69, 0x22, 0xF9, 0xBF, 0x78, 0x9A, 0xA4, 0x5A, 0x3D, 0x2E, 0x2A,
0x23, 0xE3, 0x51, 0x8F, 0x1A, 0xC1, 0xAF, 0x47, 0x9C, 0x14, 0xCE, 0xB9, 0xCD, 0xD0, 0x02, 0xB7,
0xB8, 0x81, 0xCC, 0x44, 0xE7, 0xA2, 0x6F, 0x32, 0x8C, 0x78, 0x79, 0x10, 0xF3, 0xE1, 0xB0, 0x7C,
0xAB, 0x40, 0xDB, 0xF9, 0x99, 0xE7, 0x27, 0x30, 0x53, 0x67, 0x00, 0xE8, 0x33, 0x6D, 0xFC, 0x4D,
0xDC, 0xB0, 0xFC, 0x3D, 0xEF, 0x8D, 0x43, 0xAF, 0x7E, 0x41, 0x69, 0xDA, 0xFD, 0xDF, 0x2F, 0xF8,
0xEC, 0xFB, 0x6A, 0x65, 0xE7, 0xEC, 0xC7, 0x53, 0x1B, 0x14, 0xDF, 0xBD, 0x0C, 0x54, 0x57, 0xD2,
0x56, 0x15, 0xF4, 0x34, 0xE2, 0xFB, 0x12, 0xA0, 0xA2, 0xDE, 0x82, 0xF5, 0x04, 0x81, 0x9B, 0x08,
0xB6, 0x8C, 0x7B, 0xE0, 0xAA, 0xDF, 0xC9, 0x92, 0x9D, 0x5F, 0x2D, 0xF7, 0x4A, 0x0B, 0xFF, 0xA5,
0xAA, 0xDC, 0xD6, 0x3F, 0x56, 0xB2, 0x6A, 0x3C, 0x6F, 0xAA, 0xAC, 0x84, 0xAC, 0x3F, 0x3D, 0x05,
0x96, 0x12, 0x44, 0x39, 0x1C, 0xD1, 0xFA, 0xBE, 0x6B, 0x1A, 0xCD, 0x31, 0x29, 0x41, 0x31, 0xA3,
0xA8, 0x0D, 0x87, 0xEB, 0x96, 0x21, 0x39, 0xD6, 0x3B, 0x11, 0x50, 0xB5, 0xFE, 0x44, 0x0E, 0x74,
0x31, 0x12, 0xA1, 0x66, 0x49, 0xFD, 0x2D, 0x75, 0x72, 0xF9, 0xC8, 0xD9, 0x6C, 0xC9, 0x11, 0x74,
0x2E, 0xEB, 0x20, 0x33, 0x3D, 0x2C, 0x5E, 0xEA, 0x39, 0x31, 0x88, 0xC7, 0xD1, 0x93, 0x95, 0xD8,
0x9E, 0x87, 0x93, 0xBC, 0x09, 0x17, 0xC9, 0xA2, 0x59, 0x18, 0x51, 0x8F, 0xBF, 0x55, 0x45, 0x81,
0x8D, 0xFD, 0xAF, 0xB2, 0x21, 0xB7, 0xD8, 0xA8, 0x00, 0x2E, 0x70, 0x73, 0x2F, 0x74, 0xBC, 0x61,
0x0A, 0x8E, 0xE3, 0x0A, 0x92, 0x82, 0xD2, 0x82, 0xBA, 0xE4, 0x3E, 0x8E, 0xBB, 0xC7, 0xA2, 0x8F,
0x68, 0xE1, 0x29, 0x34, 0x7C, 0xB4, 0x22, 0xCF, 0x36, 0x8F, 0x9D, 0x63, 0x9D, 0x04, 0x8F, 0x4A,
0xFB, 0x84, 0xBB, 0x6B, 0x97, 0x2C, 0x15, 0xC9, 0x37, 0x4F, 0x40, 0xD7, 0x47, 0x50, 0x39, 0x97
};
/*****************************************************************************/
/**
* @brief Packing Service message
*
* @param instPtr pointer to linklayer instance
* type message type.
* dstId destination node address.
*
* @return EPARAM
* SUCCESS
*
******************************************************************************/
static int32_t Service_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dstId)
{
#ifndef DATALINK_ENABLE_BERTEST
ASSERT(instPtr != NULL);
int32_t Status;
uint32_t dataChunk;
uint8_t *buff = instPtr->sendPktData;
// Common section of link layer package
dataChunk = L2_GetNextFrameNum(instPtr);
L2_FrameInsertChunk(buff, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &dataChunk);
dataChunk = L2_GetNextSlotNum(instPtr);
L2_FrameInsertChunk(buff, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &dataChunk);
dataChunk = L2_GetNodeId(instPtr);
L2_FrameInsertChunk(buff, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &dataChunk);
dataChunk = dstId;
L2_FrameInsertChunk(buff, L2_MSG_DST_ID, L2_MSG_DST_ID_LEN, &dataChunk);
switch (type)
{
case L2_SVC_FRAME:
{
dataChunk = L2_SVC_FRAME;
L2_FrameInsertChunk(buff, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &dataChunk);
SysMonitor_GetSysinfo(&(instPtr->sysInfo));
// insert position and speed info
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_POSX, L2_MSG_SVC_SRC_POSX_LEN, &(instPtr->sysInfo.posX));
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_POSY, L2_MSG_SVC_SRC_POSY_LEN, &(instPtr->sysInfo.posY));
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_POSZ, L2_MSG_SVC_SRC_POSZ_LEN, &(instPtr->sysInfo.posZ));
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_SPEEDX, L2_MSG_SVC_SRC_SPEEDX_LEN, &(instPtr->sysInfo.vX));
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_SPEEDY, L2_MSG_SVC_SRC_SPEEDY_LEN, &(instPtr->sysInfo.vY));
L2_FrameInsertChunk(buff, L2_MSG_SVC_SRC_SPEEDZ, L2_MSG_SVC_SRC_SPEEDZ_LEN, &(instPtr->sysInfo.vZ));
uint32_t dataId;
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
{
SysMonitor_GetSendPayload(buff + L2_MSG_SVC_PAYLOAD, &dataId, PAYLOAD_LEN_FLJ_TX);
}
else
{
SysMonitor_GetSendPayload(buff + L2_MSG_SVC_PAYLOAD, &dataId, PAYLOAD_LEN_LJ_TX);
}
L2_FrameInsertChunk(buff, L2_MSG_SVC_PAYLOAD_ID, L2_MSG_SVC_PAYLOAD_ID_LEN, &dataId);
if (dataId == DATA_ID_NONE)
{
L2_FrameInsertChunk(buff, L2_MSG_SVC_PAYLOAD, L2_MSG_SVC_PAYLOAD_LEN, testData);
}
Status = L2_CrcAppend(buff, L2_SVC_PACK_LEN - L2_MSG_SVC_CRC_LEN, L2_MSG_SVC_CRC, L2_CRC16_1021);
if (Status != SUCCESS)
{
DBG_ERROR("Fail to append CRC...\n");
return Status;
}
memcpy(instPtr->log.txLog.data, buff, L2_SVC_PACK_LEN);
instPtr->log.txLog.dataId = dataId;
break;
}
default:
{
DBG_ERROR("Unexpected frame type: %" PRIu8 ".\n", type);
return EPARAM;
break;
}
}
return SUCCESS;
#else
DBG_ERROR("Unexpected call of Service_Packing in BER test mode.\n");
return EUNEXP;
#endif
}
/*****************************************************************************/
/**
* @brief Handle service received packet. Send data up to MPC
*
* @param msg A point32_ter the the message frame.
*
* @return SUCCESS message has been successfully handled.
* other error occurred.
*
******************************************************************************/
int32_t L2_Service_PktHandler(L2_INST *instPtr, uint8_t *msg)
{
ASSERT(instPtr != NULL);
ASSERT(msg != NULL);
int32_t Status;
#ifndef DATALINK_ENABLE_BERTEST
uint8_t srcId = L2_NONE_ID;
uint8_t dstId = L2_NONE_ID;
L2_FRAME_TYPE frameType = L2_NONE_FRAME;
L2_FrameGetChunk(msg, L2_MSG_SRC_ID, L2_MSG_SRC_ID_LEN, &srcId);
L2_FrameGetChunk(msg, L2_MSG_DST_ID, L2_MSG_DST_ID_LEN, &dstId);
if(dstId != L2_GetNodeId(instPtr)) {
DBG_WARNING("Drop frame not addressed to me (%u->%u)", srcId, dstId);
return SUCCESS;
}
L2_FrameGetChunk(msg, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &frameType);
switch (frameType)
{
case L2_SVC_FRAME:
{
NODE_ENTRY *node;
node = L2_GetNodeById(instPtr->nodeList, srcId);
if (node == NULL)
{
DBG_WARNING("Unrecognized node (%u).", srcId);
Status = FAILURE;
break;
}
// Update node info.
float nodePos;
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_POSX, L2_MSG_SVC_SRC_POSX_LEN, &nodePos);
node->nodeInfo.pos.x = (double)nodePos;
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_POSY, L2_MSG_SVC_SRC_POSY_LEN, &nodePos);
node->nodeInfo.pos.y = (double)nodePos;
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_POSZ, L2_MSG_SVC_SRC_POSZ_LEN, &nodePos);
node->nodeInfo.pos.z = (double)nodePos;
float nodeSpeed;
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_SPEEDX, L2_MSG_SVC_SRC_SPEEDX_LEN, &nodeSpeed);
node->nodeInfo.speed.x = (double)nodePos;
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_SPEEDY, L2_MSG_SVC_SRC_SPEEDY_LEN, &nodeSpeed);
node->nodeInfo.speed.y = (double)nodePos;
L2_FrameGetChunk(msg, L2_MSG_SVC_SRC_SPEEDZ, L2_MSG_SVC_SRC_SPEEDZ_LEN, &nodeSpeed);
node->nodeInfo.speed.z = (double)nodePos;
// Reset node ttl
node->ttlCnt = 0;
// Calculate time deviation
uint32_t frameNum, slotNum = 0;
L2_FrameGetChunk(msg, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &frameNum);
L2_FrameGetChunk(msg, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &slotNum);
Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev));
if (Status != SUCCESS)
{
DBG_ERROR("Failed to compute time deviation.\n");
break;
}
uint32_t dataId;
L2_FrameGetChunk(msg, L2_MSG_SVC_PAYLOAD_ID, L2_MSG_SVC_PAYLOAD_ID_LEN, &dataId);
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
{
SysMonitor_UpdateRecvPayload(msg + L2_MSG_SVC_PAYLOAD, dataId, PAYLOAD_LEN_FLJ_RX);
}
else
{
SysMonitor_UpdateRecvPayload(msg + L2_MSG_SVC_PAYLOAD, dataId, PAYLOAD_LEN_LJ_RX);
}
// Logging
memcpy(instPtr->log.rxLog.data, msg, L2_SVC_PACK_LEN);
instPtr->log.rxLog.dataId = dataId;
instPtr->serviceFSM->rxdCnt++;
#ifdef DATALINK_ENABLE_AUTOTIMESYNC
// Implement a auto time sync.
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
{
// Time sync.
L2_TimeAdjust(instPtr, &(instPtr->log.timeDev));
}
#endif
break;
}
default:
DBG_ERROR("Unsupported frame type: %" PRIu8 ".\n", frameType);
break;
}
return Status;
#else
uint32_t errorBits = 0;
for (int i = 0; i < L2_SVC_PACK_LEN; i++)
{
errorBits += count_ones(msg[i] ^ testData[i]);
}
instPtr->serviceFSM->bitError += errorBits;
instPtr->serviceFSM->bitTotal += L2_SVC_PACK_LEN * 8;
// Calculate time deviation
uint32_t frameNum, slotNum = 0;
L2_FrameGetChunk(msg, L2_MSG_FRAME_NUM, L2_MSG_FRAME_NUM_LEN, &frameNum);
L2_FrameGetChunk(msg, L2_MSG_SLOT_NUM, L2_MSG_SLOT_NUM_LEN, &slotNum);
Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev));
if (Status != SUCCESS)
{
DBG_ERROR("Failed to compute time deviation.\n")
return Status;
}
// Implement a auto time sync.
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD)
{
// Time sync.
L2_TimeAdjust(instPtr, &(instPtr->log.timeDev));
}
return SUCCESS;
#endif
}
/*****************************************************************************/
/**
* @brief Initialize service net FSM
*
* @param serviceFSM A pointer to service FSM instance.
*
* @return SUCCESS Initialize successfully.
* Other Initialize failed.
*
******************************************************************************/
int32_t L2_Service_Init(L2_SVC_FSM **svcFSMPtr)
{
ASSERT(svcFSMPtr != NULL);
*svcFSMPtr = (L2_SVC_FSM *)malloc(sizeof(L2_SVC_FSM));
if (*svcFSMPtr == NULL)
{
return ENOMEM;
}
L2_Service_Reset(*svcFSMPtr);
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Reset ServiceNet FSM
*
* @param scanFsmPtr a pointer to service net finite state machine
*
* @return NONE
*
******************************************************************************/
void L2_Service_Reset(L2_SVC_FSM *svcFSMPtr)
{
ASSERT(svcFSMPtr != NULL);
svcFSMPtr->txCnt = 0;
svcFSMPtr->rxCnt = 0;
svcFSMPtr->rxdCnt = 0;
#ifdef DATALINK_ENABLE_BERTEST
svcFSMPtr->bitTotal = 0;
svcFSMPtr->bitError = 0;
svcFSMPtr->lossRate = 0;
svcFSMPtr->errorRate = 0;
#endif
}
/*****************************************************************************/
/**
* @brief Destroy ServiceNet FSM, free memory
*
* @param scanFsmPtr a pointer to service net finite state machine
*
* @return NONE
*
******************************************************************************/
void L2_Service_Destroy(L2_SVC_FSM *serviceFSM)
{
free(serviceFSM);
}
/*****************************************************************************/
/**
* @brief Service FSM Routine.
*
* @param instPtr
* @param schedEntry
*
* @return Slot has been used.
*
******************************************************************************/
int32_t L2_Service_Routine(L2_INST *instPtr, const L2_RTNE_TABLE_ENTRY *rtneEntry)
{
ASSERT(instPtr != NULL);
DBG_INFO("-------- ServiceNet Routine --------\n");
if (rtneEntry->slotSeq != 0)
{
return SUCCESS; // skip
}
PHY_INST *phyRef = instPtr->config.phyInstPtr;
L2_SVC_FSM *svcFSMPtr = instPtr->serviceFSM;
L2_TOR_TYPE torState;
const NODE_ENTRY *commNode;
if (rtneEntry->src == L2_GetNodeId(instPtr))
{
torState = L2_TOR_TX;
commNode = L2_GetNodeById(instPtr->nodeList, rtneEntry->dst);
}
else if (rtneEntry->dst == L2_GetNodeId(instPtr))
{
torState = L2_TOR_RX;
commNode = L2_GetNodeById(instPtr->nodeList, rtneEntry->src);
}
else
{
torState = L2_TOR_SUSPEND;
}
// Setup antenna beam
if (L2_GetNodeType(instPtr) != L2_NODE_HEAD && commNode != NULL)
{
Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_16);
Phy_SetBeamNo(phyRef, commNode->nodeInfo.beamNo, PHY_ANT_BEAM_16);
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_16;
}
else
{
Phy_SetBeamWidth(phyRef, PHY_ANT_BEAM_120);
instPtr->log.lastBeamWidth = PHY_ANT_BEAM_120;
}
switch (rtneEntry->slotType)
{
case L2_SLOT_SERVICE:
if (torState == L2_TOR_TX)
{
svcFSMPtr->txCnt++;
#ifndef DATALINK_ENABLE_BERTEST
// Packing service data
Service_Packing(instPtr, L2_SVC_FRAME, rtneEntry->dst);
#else
memcpy(instPtr->sendPktData, testData, L2_SVC_PACK_LEN);
#endif
}
else
{
svcFSMPtr->rxCnt++;
}
L2_SetupNextSlot(instPtr, torState, L2_SVC_FRAME);
break;
default:
DBG_ERROR("UNKNOWN slot type [%" PRIu8 "].\n", rtneEntry->slotType);
return FAILURE;
}
#ifdef DATALINK_ENABLE_BERTEST
uint32_t pktLoss;
pktLoss = svcFSMPtr->rxCnt - svcFSMPtr->rxdCnt;
svcFSMPtr->lossRate = (svcFSMPtr->rxCnt == 0) ? 0 : (double)pktLoss / (double)svcFSMPtr->rxCnt;
svcFSMPtr->errorRate = (svcFSMPtr->bitTotal == 0) ? 0 : (double)svcFSMPtr->bitError / (double)svcFSMPtr->bitTotal;
DBG_PRINT("Packet Loss Rate -- Total: %lu, Loss: %lu.\n", instPtr->log.svcRxCnt, pktLoss);
DBG_PRINT("Bit Error Rate -- Total:%lu, Error:%lu.\n", svcFSMPtr->bitTotal, svcFSMPtr->bitError);
#endif
return SUCCESS;
}
/** @} LinkLayer_Service*/
/** @} LinkLayer*/
+105
View File
@@ -0,0 +1,105 @@
/*****************************************************************************/
/**
* @file time_sync.c
* @author FanHao ([email protected])
* @brief DF Linklayer time sync implementation file.
* @version 0.0
* @date 2023-05-06
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup LinkLayer
* @{
*/
/**
* @addtogroup LinkLayer_TimeSync
* @{
*/
/***************************** Include Files *********************************/
#include <string.h>
#include <stdlib.h>
#include "link_layer.h"
#include "../phy_layer/phy_layer.h"
#include "error.h"
#include "common.h"
/************************** Constant Definitions *****************************/
/***************** Macros (Inline Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
/************************** Variable Definitions *****************************/
/************************** Function Prototypes ******************************/
/*****************************************************************************/
/**
* @brief Get time deviation to the specified frame and slot number.
*
* @param instPtr a pointer to linklayer layer instance
* @param frameNum
* @param slotNum
* @param relative
* @param timeDev
*
* @return SUCCESS
* EIGNORE there is no received frame
*
******************************************************************************/
int32_t L2_GetTimeDeviation(L2_INST *instPtr, uint32_t frameNum, uint32_t slotNum, bool relative, int64_t *timeDev)
{
ASSERT(instPtr != NULL);
ASSERT(timeDev != NULL);
L1_FRAME_TYPE lastRecvdFrame;
PHY_INST *phyRef = instPtr->config.phyInstPtr;
lastRecvdFrame = Phy_GetLastRecvFrameType(phyRef);
if (lastRecvdFrame == L1_NONE_FRAME)
{
DBG_ERROR("Invalid TimeAlign operation, no frame was received.");
return EIGNORE;
}
DBG_INFO("Starting TimeAlign operation...\n");
// read nextSendTime from physical layer
uint64_t currTime, expectTime;
TIME_WORD timeStamp;
expectTime = ((uint64_t)(frameNum * L2_SLOTS_PER_FRAME + slotNum)) * TIME_FRAC_MAX;
expectTime += Phy_GetTimeComp(lastRecvdFrame);
if (relative)
{
expectTime += (uint64_t)instPtr->netStartTime * L2_SLOTS_PER_FRAME * TIME_FRAC_MAX;
}
Phy_GetLastReceivedFrameSyncTimeStamp(phyRef, &timeStamp);
currTime = (uint64_t)timeStamp.frac_part;
currTime += ((uint64_t)timeStamp.int_part) * TIME_FRAC_MAX;
*timeDev = (int64_t)(expectTime - currTime);
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Implement time adjustment by applying time deviation.
*
* @param instPtr a pointer to linklayer layer instance
* @param timeDev
*
* @return NONE
*
******************************************************************************/
void L2_TimeAdjust(L2_INST *instPtr, const int64_t *timeDev)
{
ASSERT(instPtr != NULL);
ASSERT(timeDev != NULL);
TIME_WORD slotTimerAdjmet;
slotTimerAdjmet.int_part = (uint32_t)(*timeDev / TIME_FRAC_MAX);
slotTimerAdjmet.frac_part = (uint32_t)(*timeDev % TIME_FRAC_MAX);
TimeCtrl_TimeAdjust(instPtr->config.tmcInstPtr, &slotTimerAdjmet, TM_ADJ_ADD);
}
/** @} LinkLayer_TimeSync*/
/** @} LinkLayer*/
+428
View File
@@ -0,0 +1,428 @@
/*****************************************************************************/
/**
* @file phy_antenna.h
* @author FanHao ([email protected])
* @brief Physical layer control antenna configuration functions.
* @version 0.0
* @date 2023-04-24
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @addtogroup PhysicalLayer
* @{
*/
/**
* @addtogroup PhysicalLayer_AntennaControl
* @{
*/
#include <string.h>
#include <stdint.h>
#include <math.h>
#include "error.h"
#include "phy_layer.h"
/**
* @name PhysicalLayer_AntennaConfig_Constants
* @{
*/
#define ANT_PI 3.14159265358979323846
#define ANT_COINFO_HEAD 0xAA
#define ANT_COINFO_TAIL 0xCC
#define CTRL_WORD_DEFAULT 0x00
#define ANT_MODE_BEAM_MASK 0xF0
#define ANT_BEAM_NARROR 0x00 // 8
#define ANT_BEAM_SUBNARROR_0 0x10 // 25
#define ANT_BEAM_SUBNARROR_1 0x20 // 60
#define ANT_BEAM_WIDE 0x30 // 120
#define ANT_MODE_POWER_MASK 0x0F
#define ANT_POWER_FULL 0x00
#define ANT_POWER_LOW 0x04
#define ANT_POWER_STANDBY 0x0F
#define ATN_MODE_SILENT (ANT_BEAM_SUBNARROR_0 | ANT_POWER_STANDBY)
#define ATN_MODE_LOWPOWER (ANT_BEAM_SUBNARROR_0 | ANT_POWER_LOW)
#define ATN_MODE_FULLPOWER (ANT_BEAM_SUBNARROR_0 | ANT_POWER_FULL)
#define ATN_MODE_DEFAULT ATN_MODE_SILENT
#define DEFAULT_CENTRTAL_FREQ 0x06D7 // 26.25GHz
#define RXTXMODE_RX 0x00
#define RXTXMODE_TX 0x01
#define RXTXMODE_DEFAULT 0x00
#define CALIBRMODE_NORMAL 0x00
#define CALIBRMODE_SINGLE_TR_CAL 0x01
#define RF_CTRL_DEFAULT 0x00
// Pair by regex
// Regex: (([0-9]+, ){8})
const uint16_t freqTable[L1_FRAME_MAX_HOPS] =
{
1084, 1097, 1110, 1123, 1136, 1149, 1162, 1175,
1188, 1201, 1214, 1227, 1240, 1253, 1266, 1279,
1292, 1305, 1318, 1331, 1344, 1357, 1370, 1383,
1396, 1409, 1422, 1435, 1448, 1461, 1474, 1487,
1500, 1513, 1526, 1539, 1552, 1565, 1578, 1591,
1604, 1617, 1630, 1643, 1656, 1669, 1682, 1695,
1708, 1721, 1734, 1747, 1760, 1773, 1786, 1799,
1812, 1825, 1838, 1851, 1864, 1877, 1890, 1903,
1916, 1929, 1942, 1955, 1968, 1981, 1994, 2007,
2020, 2033, 2046, 2059, 2072, 2085, 2098, 2111,
2124
};
const uint16_t antCalTable[L1_FRAME_MAX_HOPS][L1_ANT_NUM_CH] =
//Antenna-JG01
{
{ 0, 406, -10530, -8223}, { 0, 697, -9933, -7988},
{ 0, 296, -10497, -8272}, { 0, 515, -10264, -8093},
{ 0, 689, -10212, -8064}, { 0, 40, -10960, -8572},
{ 0, 722, -10878, -8518}, { 0, 59, -10987, -8962},
{ 0, 56, -11264, -8770}, { 0, -464, -11341, -9159},
{ 0, 19, -10924, -8887}, { 0, -669, -10927, -8679},
{ 0, -701, -11154, -8712}, { 0, -255, -10739, -8009},
{ 0, -192, -10509, -8242}, { 0, -1057, -11183, -9007},
{ 0, -57, -10606, -8350}, { 0, -719, -10949, -8880},
{ 0, -760, -11084, -8660}, { 0, -457, -10735, -8833},
{ 0, -188, -10623, -9119}, { 0, -628, -12609, -10119},
{ 0, -434, -12714, -10225}, { 0, -727, -13074, -10685},
{ 0, -12, -12408, -10190}, { 0, 33, -12790, -10624},
{ 0, 93, -13235, -10819}, { 0, -363, -13301, -11183},
{ 0, -514, -13955, -11557}, { 0, -458, -13878, -11722},
{ 0, 93, -13086, -11726}, { 0, -663, -13597, -11868},
{ 0, 174, -12814, -11295}, { 0, 121, -12278, -11150},
{ 0, 425, -11255, -10363}, { 0, 430, -11645, -10189},
{ 0, 277, -11844, -9499}, { 0, -132, -12241, -9420},
{ 0, 448, -11934, -9612}, { 0, 200, -11778, -9582},
{ 0, -40, -12069, -9336}, { 0, 1692, -11315, -9085},
{ 0, -1753, -11445, -9482}, { 0, -2520, -12620, -10068},
{ 0, -1976, -12674, -10218}, { 0, -1984, -12525, -10354},
{ 0, -2272, -13476, -10932}, { 0, -2123, -13918, -11095},
{ 0, -2883, -14447, -11659}, { 0, -2826, -13946, -11563},
{ 0, -2697, -13680, -11328}, { 0, -3068, -13393, -11614},
{ 0, -2935, -13074, -11882}, { 0, -3017, -13038, -11163},
{ 0, -2490, -12379, -11288}, { 0, -2463, -12286, -10726},
{ 0, -2686, -12167, -10673}, { 0, -2428, -12077, -10555},
{ 0, -2282, -12564, -10388}, { 0, -2017, -12303, -10844},
{ 0, -2329, -12637, -11250}, { 0, -2703, -13362, -11807},
{ 0, -1820, -12605, -11733}, { 0, 596, -10833, -9852},
{ 0, 9, -11140, -9776}, { 0, 41, -11168, -9478},
{ 0, -261, -11368, -9752}, { 0, 226, -11282, -9879},
{ 0, -68, -11454, -10148}, { 0, -314, -12278, -10716},
{ 0, -66, -11998, -10762}, { 0, -58, -11469, -10664},
{ 0, 319, -10759, -10212}, { 0, 122, -11041, -9901},
{ 0, -269, -11085, -10008}, { 0, 637, -10569, -9674},
{ 0, 1185, -10632, -9521}, { 0, 902, -11053, -9681},
{ 0, 560, -11408, -9588}, { 0, 1162, -11079, -9371},
{ 0, 1780, -10547, -9133},
};
const uint8_t hopPattern_2KBPS_20MS[L1_FRAME_2KBPS_20MS_HOPS] =
{
0
};
const uint8_t hopPattern_2KBPS_100MS[L1_FRAME_2KBPS_100MS_HOPS] =
{
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79,
80
};
const uint8_t hopPattern_10KBPS_10MS[L1_FRAME_10KBPS_10MS_HOPS] =
{
80
};
const uint8_t hopPattern_10KBPS_20MS[L1_FRAME_10KBPS_20MS_HOPS] =
{
80, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10
};
const uint8_t hopPattern_40KBPS_10MS[L1_FRAME_40KBPS_10MS_HOPS] =
{
0, 1, 2, 3, 4, 5, 6, 7,
8,
};
const uint8_t hopPattern_40KBPS_20MS[L1_FRAME_40KBPS_20MS_HOPS] =
{
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18
};
const uint8_t hopPattern_200KBPS_5MS[L1_FRAME_200KBPS_5MS_HOPS] =
{
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19
};
const uint8_t hopPattern_1M2BPS_5MS[L1_FRAME_1M2BPS_5MS_HOPS] =
{
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19
};
/** @} PhysicalLayer_AntennaConfig_Constants*/
/*****************************************************************************/
/**
* @brief Initialize antenna configurations (load preset values)
*
* @param antConfig pointer to antenna configure
*
* @return None.
*
******************************************************************************/
void Phy_AntConfigInit(PHY_ANT_CONFIG *antConfig)
{
ASSERT(antConfig != NULL);
antConfig->ctrlWord = CTRL_WORD_DEFAULT;
antConfig->antMode = ATN_MODE_DEFAULT;
// FIXME: Dummy default value.
// off axis angle setting
antConfig->oaxis[0] = 0;
antConfig->oaxis[1] = 0;
// round axis angle setting
antConfig->raxis[0] = 0;
antConfig->raxis[1] = 0;
// ***********************
antConfig->antFreq[0] = (uint8_t)(DEFAULT_CENTRTAL_FREQ);
antConfig->antFreq[1] = (uint8_t)(DEFAULT_CENTRTAL_FREQ >> 8);
// FIXME: Dummy default value.
// trSelect
antConfig->trSlect = 0;
// Antenna attenuation setting
antConfig->antAtt = 0;
// phase setting
antConfig->phase = 0;
// ***********************
antConfig->rxtxMode = RXTXMODE_DEFAULT;
antConfig->calibrMode = CALIBRMODE_NORMAL;
antConfig->antReserved = 0x00;
// FIXME: Dummy default value.
// RF mode control
antConfig->rfCtrl = RF_CTRL_DEFAULT;
// RF frequency
antConfig->rfFreq[0] = (uint8_t)(DEFAULT_CENTRTAL_FREQ);
antConfig->rfFreq[1] = (uint8_t)(DEFAULT_CENTRTAL_FREQ >> 8);
// RF MGC control
antConfig->rfTxMgc = 0;
// RF channel 1&2 calibration mgc
antConfig->rf12CalMgc = 0;
// RF channel 2&3 calibration mgc
antConfig->rf34CalMgc = 0;
// Receive channel 1-4 MGC
antConfig->rcvMgc = 0;
antConfig->rfReserved0 = 0x00;
antConfig->rfReserved1 = 0x00;
// ***********************
}
/*****************************************************************************/
/**
* @brief Update antenna power mode setting
*
* @param instPtr pointer to physical layer instance
* @param mode new antenna mode
*
* @return None.
*
******************************************************************************/
void Phy_AntConfigMode(PHY_INST *instPtr, PHY_ANT_MODE mode)
{
ASSERT(instPtr != NULL);
uint8_t config = instPtr->antConfig.antMode & ANT_MODE_BEAM_MASK;
switch (mode)
{
case PHY_ANT_MODE_STANDBY:
config |= ANT_POWER_STANDBY;
break;
case PHY_ANT_MODE_POWER_LOW:
config |= ANT_POWER_LOW;
break;
case PHY_ANT_MODE_POWER_FULL:
config |= ANT_POWER_FULL;
break;
default:
DBG_ERROR("Unknown antenna mode: %" PRIu8 ", remain previous mode.\n", mode);
return;
}
instPtr->phyLog.antMode = mode;
instPtr->antConfig.antMode = config;
// Sync logs to system monitor
SysMonitor_UpdatePhysicalLayerLog(&(instPtr->phyLog));
}
/*****************************************************************************/
/**
* @brief Update antenna beam table
*
* @param instPtr pointer to physical layer instance
* @param table new beam table
* @param offset table offset
*
* @return None
*
******************************************************************************/
void Phy_SetBeamTable(PHY_INST *instPtr, PHY_ANT_ANGLE *table, uint32_t offset)
{
ASSERT(instPtr != NULL);
ASSERT(table != NULL);
for (int i = 0; i < L1_NUM_ANT_NRRW_PATTERN; i++)
{
instPtr->antNrrwPattern[i] = table[(i + offset) % L1_NUM_ANT_NRRW_PATTERN];
}
memcpy((uint32_t *)instPtr->antInfoAddr, instPtr->antNrrwPattern,
NORMALIZE_SIZE(L1_NUM_ANT_NRRW_PATTERN * sizeof(PHY_ANT_ANGLE)));
}
/*****************************************************************************/
/**
* @brief Update antenna point direction using predefined beam table
*
* @param instPtr pointer to physical layer instance
* @param beamNo new beam index
*
* @return SUCCESS.
* FAILURE beamNo exceeds the table size
*
******************************************************************************/
int32_t Phy_SetBeamNo(PHY_INST *instPtr, int32_t beamNo, PHY_ANT_BEAM_WIDTH beamWidth)
{
ASSERT(instPtr != NULL);
if (beamWidth == PHY_ANT_BEAM_16)
{
if (beamNo >= L1_NUM_ANT_NRRW_PATTERN)
{
return FAILURE;
}
else
{
instPtr->beamNo.next = beamNo;
instPtr->antConfig.oaxis[0] = (uint8_t)(instPtr->antNrrwPattern[beamNo].oaxis >> 8);
instPtr->antConfig.oaxis[1] = (uint8_t)(instPtr->antNrrwPattern[beamNo].oaxis);
instPtr->antConfig.raxis[0] = (uint8_t)(instPtr->antNrrwPattern[beamNo].raxis >> 8);
instPtr->antConfig.raxis[1] = (uint8_t)(instPtr->antNrrwPattern[beamNo].raxis);
return SUCCESS;
}
}
else
{
// Beam number assign not support.
// Assign default angle (0,0)
instPtr->beamNo.next = 0;
instPtr->antConfig.oaxis[0] = 0;
instPtr->antConfig.oaxis[1] = 0;
instPtr->antConfig.raxis[0] = 0;
instPtr->antConfig.raxis[1] = 0;
DBG_WARNING("Using default beam number...\n");
return SUCCESS;
}
}
/*****************************************************************************/
/**
* @brief Update antenna beam width setting
*
* @param instPtr pointer to physical layer instance
* @param beamWidth new beam width
*
* @return SUCCESS.
* EPARAM
*
******************************************************************************/
int32_t Phy_SetBeamWidth(PHY_INST *instPtr, PHY_ANT_BEAM_WIDTH beamWidth)
{
ASSERT(instPtr != NULL);
uint8_t beamConfig = instPtr->antConfig.antMode & (~ANT_MODE_BEAM_MASK);
switch (beamWidth)
{
case PHY_ANT_BEAM_120:
beamConfig |= ANT_BEAM_WIDE;
break;
case PHY_ANT_BEAM_60:
beamConfig |= ANT_BEAM_SUBNARROR_1;
break;
case PHY_ANT_BEAM_25:
beamConfig |= ANT_BEAM_SUBNARROR_0;
break;
case PHY_ANT_BEAM_16:
beamConfig |= ANT_BEAM_NARROR;
break;
default:
DBG_ERROR("Beam width code: 0x%08X is illegal.\n\r", beamWidth);
return EPARAM;
}
instPtr->antConfig.antMode = beamConfig;
instPtr->beamWd.next = beamWidth;
return SUCCESS;
}
/*****************************************************************************/
/**
* @brief Set antenna to a specific direction
*
* @param instPtr pointer to physical layer instance
* @param offAx elevation angle
* @param rndAx azimuth angle
*
* @return SUCCESS.
* EPARAM - the direction is exceeds predefined range
*
******************************************************************************/
int32_t Phy_SetBeamAngle(PHY_INST *instPtr, double offAx, double rndAx)
{
ASSERT(instPtr != NULL);
uint16_t offAxDeg = 0;
uint16_t rndAxDeg = 0;
offAxDeg = (offAx >= 0) ? (((int32_t)(offAx * 180 / ANT_PI)) % 360) : (((int32_t)(offAx * 180 / ANT_PI)) % 360 + 360);
rndAxDeg = (rndAx >= 0) ? (((int32_t)(rndAx * 180 / ANT_PI)) % 360) : (((int32_t)(rndAx * 180 / ANT_PI)) % 360 + 360);
if (offAxDeg > 60)
{
DBG_ERROR("Angle out of range, off axis angle: %" PRIu16 " (should be 0~60), round axis angle: %" PRIu16 " (should be 0~360).\n",
offAxDeg, rndAxDeg);
return EPARAM;
}
offAxDeg = offAxDeg * 10;
rndAxDeg = rndAxDeg * 10;
instPtr->antConfig.oaxis[0] = (uint8_t)(offAxDeg >> 8);
instPtr->antConfig.oaxis[1] = (uint8_t)offAxDeg;
instPtr->antConfig.raxis[0] = (uint8_t)(rndAxDeg >> 8);
instPtr->antConfig.raxis[1] = (uint8_t)rndAxDeg;
return SUCCESS;
}
/** @} PhysicalLayer_AntennaControl*/
/** @} PhysicalLayer*/
File diff suppressed because it is too large Load Diff
+315
View File
@@ -0,0 +1,315 @@
/*****************************************************************************/
/**
* @file phy_layer.c
* @author FanHao ([email protected])
* @brief Physical layer control header file.
* @version 0.0
* @date 2023-04-24
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @defgroup PhysicalLayer
* @{
*/
#ifndef PHY_CTRL_H_
#define PHY_CTRL_H_
/***************************** Include Files *********************************/
#include <stdint.h>
#include "common.h"
#ifndef EMULATION
#include "xbram.h"
#include "xsysmon.h"
#include "../config/app_config.h"
#endif
#include "../../system_monitor.h"
#include "../../time_ctrl/time_ctrl.h"
/************************** Constant Definitions *****************************/
/**
* @name PhysicalLayer_Common_Constant
* @{
*/
#define L1_NUM_ANT_NRRW_PATTERN 37
#define L1_INIT_BEAM_NO 0
#define L1_INIT_ANT_WD PHY_ANT_BEAM_120
#define L1_ANT_NUM_CH 4
#define L1_FRAME_NONE_LEN UINT32_MAX // byte
#define L1_FRAME_NONE_COMP UINT32_MAX // *10ns(Timer_L)
#define L1_FRAME_NONE_HOPS UINT32_MAX
#define L1_FRAME_MAX_HOPS 81
#define L1_FRAME_2KBPS_20MS_HOPS 1
#define L1_FRAME_2KBPS_100MS_HOPS 81
#define L1_FRAME_10KBPS_10MS_HOPS 1
#define L1_FRAME_10KBPS_20MS_HOPS 11
#define L1_FRAME_40KBPS_20MS_HOPS 19
#define L1_FRAME_40KBPS_10MS_HOPS 9
#define L1_FRAME_200KBPS_5MS_HOPS 20
#define L1_FRAME_1M2BPS_5MS_HOPS 20
#define PHY_LOG_EXPIRE 40 // 50*5ms
/** @} */
/***************** Macros (Inline Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
/**
* @enum L1_FRAME_TYPE
*/
typedef enum
{
L1_NONE_FRAME = 0,
L1_2KBPS_20MS_FRAME = 1,
L1_2KBPS_100MS_FRAME = 2,
L1_10KBPS_10MS_FRAME = 3,
L1_10KBPS_20MS_FRAME = 4,
L1_40KBPS_20MS_FRAME = 5,
L1_40KBPS_10MS_FRAME = 6,
L1_200KBPS_5MS_FRAME = 7,
L1_1M2BPS_5MS_FRAME = 8
} L1_FRAME_TYPE;
/**
* @struct PHY_ANT_CONFIG
* @brief PhysicalLayer antenna config
*/
typedef struct
{
/*** Ant Control ***/
uint8_t ctrlWord; ///< Antenna control frame head 0xAA\n
/// default 0, reserved for further use
uint8_t antMode; ///< high 4 bits specified beam mode.\n
/// low 4 bits specified power control
uint8_t oaxis[2]; ///< off-axis angle range is 0~60 \n
/// 0.1 degree each LSB
uint8_t raxis[2]; ///< round-axis angle range is 0~360, \n
/// 0.1 degree each LSB
uint8_t antFreq[2]; ///< 0~3500Mhz, step 1MHz
uint8_t trSlect; ///< in single tr mode, 0~63 specified tr channel \n
/// in single subarray mode, 0~3 specified the subarray
/// ! Only in debug mode!
uint8_t antAtt; ///< Antenna attenuation 0~31, 0.5dB each LSB, Only in debug mode
uint8_t phase; ///< 0~63, 5.625 degree each LSB, Only in debug mode
uint8_t rxtxMode; ///< Only for debug \n
/// default 0x00
uint8_t calibrMode; ///< 0x00 Normal, 0x01 single tr calibration
uint8_t antReserved; ///< reserved for further use
/*** RF Control ***/
uint8_t rfCtrl; ///< [7:4]RF enable: 0-On, 1-Off(Default); [3:0]Work mode: 0(default)
uint8_t rfFreq[2]; ///< 0~3500Mhz, step 1MHz
uint8_t rfTxMgc; ///< RF MGC control: 0~31, 1dB each LSB
uint8_t rf12CalMgc; ///< RF channel 1&2 calibration mgc\n
/// [7:4] Channle1 - max 15db, 1dB each LSB \n
/// [3:0] Channle2 - max 15db, 1dB each LSB
uint8_t rf34CalMgc; ///< RF channel 3&4 calibration mgc\n
/// [7:4] Channle3 - max 15db, 1dB each LSB
/// [3:0] Channle4 - max 15db, 1dB each LSB
uint8_t rcvMgc; ///< Receive channel 1-4 MGC: 0~31, 1dB each LSB
uint8_t rfMonitor; ///< Receive monitor, 0-normal, 1-switch to monitor port
uint8_t rfReserved0; ///< reserved for further use
uint8_t rfReserved1; ///< reserved for further use
uint8_t ch0Cal[2];
uint8_t ch1Cal[2];
uint8_t ch2Cal[2];
uint8_t ch3Cal[2];
} PHY_ANT_CONFIG;
/**
* @struct PHY_ANT_ANGLE
* @brief Describe the PhysicalLayer antenna angle
*/
typedef struct
{
uint16_t oaxis; ///< off-axis angle range is 0~60
/// 0.1 degree each LSB
uint16_t raxis; ///< round-axis angle range is 0~360
/// 0.1 degree each LSB
} PHY_ANT_ANGLE;
/**
* @enum PHY_TIME_WORD_TYPE
*/
typedef enum
{
PHY_TIME_WORD_NONE = 0,
PHY_TIME_WORD_POLL = 1,
PHY_TIME_WORD_LISTEN_TIMEOUT = 2
} PHY_TIME_WORD_TYPE;
/**
* @enum PHY_ANT_BEAM_WIDTH
*/
typedef enum
{
PHY_ANT_BEAM_NONE = 0,
PHY_ANT_BEAM_120 = 1,
PHY_ANT_BEAM_60 = 2,
PHY_ANT_BEAM_25 = 3,
PHY_ANT_BEAM_16 = 4
} PHY_ANT_BEAM_WIDTH;
/**
* @enum PHY_TOR_TYPE
*/
typedef enum
{
PHY_TOR_SUSPEND = 0,
PHY_TOR_TX = 1,
PHY_TOR_RX = 2
} PHY_TOR_TYPE;
/**
* @enum PHY_MODE
*/
typedef enum
{
PHY_MODE_NONE = 0,
PHY_MODE_LISTEN = 1,
PHY_MODE_SCHEDULE = 2,
PHY_MODE_PULL = 3
} PHY_MODE;
/**
* @enum PHY_ANT_MODE
*/
typedef enum
{
PHY_ANT_MODE_NONE = 0,
PHY_ANT_MODE_STANDBY = 1,
PHY_ANT_MODE_POWER_LOW = 2,
PHY_ANT_MODE_POWER_FULL = 3,
} PHY_ANT_MODE;
/**
* @struct PHY_RCD
* @brief Physical Layer recode buffer
*/
typedef struct
{
int32_t last;
int32_t curr;
int32_t next;
} PHY_RCD;
/**
* @struct PHY_CONFIG
* @brief struct holds all physical layer initialization parameters
*/
typedef struct
{
uint32_t devId; ///< device ID
uint32_t txBramId; ///< tx bram ID
uint32_t rxBramId; ///< rx bram ID
uint32_t antBramId; ///< antenna config bram ID
uint32_t antInfoBramId; ///< antenna beam info bram ID
uint32_t hwSysmonId; ///< hardware xadc device ID
uintptr_t baseAddr; ///< Physical layer controller base address
#ifndef EMULATION
uint8_t (*get_clk_state)(void); ///< function handle returns hardware clock state
uint8_t (*get_ad_lock_state)(void); ///< function handle returns adc lock state
int8_t (*get_ad0_temp)(void); ///< function handle returns adc0 temperature state
int8_t (*get_ad1_temp)(void); ///< function handle returns adc1 temperature state
#endif
} PHY_CONFIG;
/**
* @struct PHY_INST
* @brief Physical Layer operating instance
*/
typedef struct
{
PHY_CONFIG phyCofig; ///< physical layer configuration parameters
uintptr_t recvDataAddr; ///< receive data bram address
uintptr_t sendDataAddr; ///< send data bram address
uintptr_t antConfigAddr; ///< antenna config data bram address
uintptr_t antInfoAddr; ///< antenna beam info data bram address
bool isPhyEn; ///< indicates if physical layer running
bool isAcq; ///< indicates if last reception acquisition success
bool isFrameSync; ///< indicates if last reception frame sync success
bool isDecode; ///< indicates if last reception decode success
bool isValid; ///< indicates if last reception frame data valid (crc check pass)
TIME_WORD recvSlotTime; ///< last slot start time stamp
TIME_WORD recvFsTime; ///< last frame sync time stamp
PHY_RCD beamNo; ///< beam number record
PHY_RCD beamWd; ///< beam width record
PHY_RCD tor; ///< tx rx state record
PHY_RCD frameType; ///< frame type record
uint32_t sendDataOffset; ///< antenna configuration bram offset (to implement ping-pong data flow)
uint32_t antConfigOffset; ///< antenna configuration bram offset (to implement ping-pong data flow)
PHY_ANT_CONFIG antConfig; ///< antenna configuration pointer
#ifndef EMULATION
XSysMon sysMon; ///< System monitor
#endif
PHY_ANT_ANGLE antNrrwPattern[L1_NUM_ANT_NRRW_PATTERN]; ///< antenna beam scan pattern
HWSTATE hwSate; ///< hardware state log
PHYLOG phyLog; ///< physical state log
uint32_t lastLogTime; /// physical state log time stamp
} PHY_INST;
/************************** Function Prototypes ******************************/
/**
* @defgroup PhysicalLayer_Main
* @{
*/
int32_t Phy_Init(PHY_INST **instPtr, PHY_CONFIG *phyConfig);
void Phy_Destroy(PHY_INST *instPtr);
void Phy_Start(PHY_INST *instPtr);
void Phy_Halt(PHY_INST *instPtr);
int32_t Phy_SetMode(PHY_INST *instPtr, PHY_MODE modeCod);
int32_t Phy_SetTimeWord(PHY_INST *instPtr, const TIME_WORD *tmWord, PHY_TIME_WORD_TYPE tmType);
int32_t Phy_SetupNextSlot(PHY_INST *instPtr, PHY_TOR_TYPE txrxMode, L1_FRAME_TYPE frameType, uint8_t *dataBuff);
void Phy_UpdateState(PHY_INST *instPtr);
void Phy_PeekRecvData(PHY_INST *instPtr, uint8_t *dataBuff);
void Phy_RetrieveRecvData(PHY_INST *instPtr, uint8_t *dataBuff);
void Phy_UpdateLogging(PHY_INST *instPtr);
void Phy_RefreshHwSate(PHY_INST *instPtr);
/** @} PhysicalLayer_Main*/
/**
* @defgroup PhysicalLayer_Utility
* @{
*/
bool Phy_IsFrameDetected(PHY_INST *instPtr);
bool Phy_IsFrameReceived(PHY_INST *instPtr);
bool Phy_IsFrameValid(PHY_INST *instPtr);
uint32_t Phy_GetFrameLen(L1_FRAME_TYPE frameType);
uint32_t Phy_GetHopLength(L1_FRAME_TYPE frameType);
uint32_t Phy_GetTimeComp(L1_FRAME_TYPE frameType);
L1_FRAME_TYPE Phy_GetLastRecvFrameType(PHY_INST *instPtr);
L1_FRAME_TYPE Phy_GetLastSendFrameType(PHY_INST *instPtr);
/** @} PhysicalLayer_Utility*/
/**
* @defgroup PhysicalLayer_Receive_Estimations
* @{
*/
uint8_t Phy_LastScanBeamNo(PHY_INST *instPtr);
double Phy_GetFreqEst(PHY_INST *instPtr);
double Phy_GetCoarseFreqEst(PHY_INST *instPtr);
double Phy_GetFineFreqEst(PHY_INST *instPtr);
void Phy_GetFrameSyncTimeStamp(PHY_INST *instPtr, TIME_WORD *frameSyncT);
void Phy_GetLastReceivedFrameSyncTimeStamp(PHY_INST *instPtr, TIME_WORD *frameSyncT);
void Phy_GetSlotStartTimeStamp(PHY_INST *instPtr, TIME_WORD *slotStart);
void Phy_GetLastReceivedSlotStartTimeStamp(PHY_INST *instPtr, TIME_WORD *slotStart);
/** @} PhysicalLayer_Receive_Estimations*/
/**
* @defgroup PhysicalLayer_AntennaControl
* @{
*/
void Phy_AntConfigInit(PHY_ANT_CONFIG *antConfig);
void Phy_AntConfigMode(PHY_INST *instPtr, PHY_ANT_MODE mode);
void Phy_SetBeamTable(PHY_INST *instPtr, PHY_ANT_ANGLE *table, uint32_t offset);
int32_t Phy_SetBeamWidth(PHY_INST *instPtr, PHY_ANT_BEAM_WIDTH beamWidth);
int32_t Phy_SetBeamNo(PHY_INST *instPtr, int32_t beamNo, PHY_ANT_BEAM_WIDTH beamWidth);
int32_t Phy_SetBeamAngle(PHY_INST *phyInstPtr, double offAx, double rndAx);
/** @} PhysicalLayer_AntennaControl*/
#endif // PHY_CTRL_H_
/** @} PhysicalLayer*/
+497
View File
@@ -0,0 +1,497 @@
/*****************************************************************************/
/**
* @file phy_layer.h
* @author FanHao ([email protected])
* @brief Physical layer controller register definition
* @version 0.0
* @date 2023-04-24
*
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
* Lab of Communication and Network
*
******************************************************************************/
/**
* @defgroup PhysicalLayer
* @{
*/
/**
* @name PhysicalLayer_REG_Constants
* @{
*/
#ifndef PHY_REG_H_
#define PHY_REG_H_
/***************************** Include Files *********************************/
#include "util.h"
/***************** Macros (Inline Functions) Definitions *********************/
#define PhyRead(instPtr, addr) IO_In32((instPtr)->phyCofig.baseAddr + addr)
#define PhyWrite(instPtr, addr, value) IO_Out32((instPtr)->phyCofig.baseAddr + addr, value)
/************************** Constant Definitions *****************************/
/**
* Register: PHY_MAIN_CTRL
*/
#define PHY_MAIN_CTRL 0x00000000U
#define PHY_MAIN_CTRL_EN_SHIFT 0
#define PHY_MAIN_CTRL_EN_WIDTH 1
#define PHY_MAIN_CTRL_EN_MASK 0x00000001U
#define PHY_MAIN_CTRL_MODE_SHIFT 8
#define PHY_MAIN_CTRL_MODE_WIDTH 8
#define PHY_MAIN_CTRL_MODE_MASK 0x0000FF00U
#define PHY_MAIN_CTRL_NSCAN_SHIFT 16
#define PHY_MAIN_CTRL_NSCAN_WIDTH 8
#define PHY_MAIN_CTRL_NSCAN_MASK 0x00FF0000U
#define PHY_MAIN_CTRL_EN_EN 0x00000001U
#define PHY_MAIN_CTRL_EN_DSBL 0x00000000U
#define PHY_MAIN_CTRL_MODE_NONE 0x00000000U
#define PHY_MAIN_CTRL_MODE_LISTEN 0x00000100U
#define PHY_MAIN_CTRL_MODE_SCHEDULE 0x00000200U
#define PHY_MAIN_CTRL_MODE_PULL 0x00000300U
/**
* Register: TXRX_CTRL
*/
#define PHY_MODE_CTRL 0x00000004U
#define PHY_MODE_CTRL_TOR_SHIFT 0
#define PHY_MODE_CTRL_TOR_WIDTH 8
#define PHY_MODE_CTRL_TOR_MASK 0x000000FFU
#define PHY_MODE_CTRL_FRAME_SHIFT 8
#define PHY_MODE_CTRL_FRAME_WIDTH 8
#define PHY_MODE_CTRL_FRAME_MASK 0x0000FF00U
#define PHY_MODE_CTRL_CRC_SHIFT 8
#define PHY_MODE_CTRL_CRC_WIDTH 16
#define PHY_MODE_CTRL_CRC_MASK 0x00FF0000U
#define PHY_MODE_CTRL_TOR_SUSPEND 0x00000000U
#define PHY_MODE_CTRL_TOR_TX 0x00000001U
#define PHY_MODE_CTRL_TOR_RX 0x00000002U
#define PHY_MODE_CTRL_FRAME_NONE 0x00000000U
#define PHY_MODE_CTRL_FRAME_2KBPS_20MS 0x00000100U
#define PHY_MODE_CTRL_FRAME_2KBPS_100MS 0x00000200U
#define PHY_MODE_CTRL_FRAME_10KBPS_10MS 0x00000300U // Initial Scan Frame
#define PHY_MODE_CTRL_FRAME_10KBPS_20MS 0x00000400U // Benchmark Frame
#define PHY_MODE_CTRL_FRAME_40KBPS_20MS 0x00000500U
#define PHY_MODE_CTRL_FRAME_40KBPS_10MS 0x00000600U
#define PHY_MODE_CTRL_FRAME_200KBPS_5MS 0x00000700U // 2-Way ACQ Frame, Management Frame, Service Frame
#define PHY_MODE_CTRL_FRAME_1M2BPS_5MS 0x00000800U // Bistatic Synthetic Aperture Radar Frame
#define PHY_MODE_CTRL_CRC_EN 0x00010000U
#define PHY_MODE_CTRL_CRC_DSBL 0x00000000U
/**
* Register: POLLTIME_L
*/
#define POLLTIME_L 0x00000008U
#define POLLTIME_L_SHIFT 0
#define POLLTIME_L_WIDTH 32
#define POLLTIME_L_MASK 0xFFFFFFFFU
/**
* Register: POLLTIME_H
*/
#define POLLTIME_H 0x0000000CU
#define POLLTIME_H_SHIFT 0
#define POLLTIME_H_WIDTH 32
#define POLLTIME_H_MASK 0xFFFFFFFFU
/**
* Register: TIMEOUT_L
*/
#define LISTENTIMEOUT_L 0x00000010U
#define LISTENTIMEOUT_L_SHIFT 0
#define LISTENTIMEOUT_L_WIDTH 32
#define LISTENTIMEOUT_L_MASK 0xFFFFFFFFU
/**
* Register: TIMEOUT_H
*/
#define LISTENTIMEOUT_H 0x00000014U
#define LISTENTIMEOUT_H_SHIFT 0
#define LISTENTIMEOUT_H_WIDTH 32
#define LISTENTIMEOUT_H_MASK 0xFFFFFFFFU
/**
* Register: ANT_CTRL
*/
#define ANT_CONFIG 0x00000018U
#define ANT_CONFIG_OFFSET_SHIFT 0
#define ANT_CONFIG_OFFSET_WIDTH 16
#define ANT_CONFIG_OFFSET_MASK 0x0000FFFFU
#define ANT_CONFIG_LEN_SHIFT 16
#define ANT_CONFIG_LEN_WIDTH 8
#define ANT_CONFIG_LEN_MASK 0x00FF0000U
#define ANT_CONFIG_NUM_SHIFT 24
#define ANT_CONFIG_NUM_WIDTH 8
#define ANT_CONFIG_NUM_MASK 0xFF000000U
/**
* Register: SEND_DATA_CMD
*/
#define SEND_DATA_CMD 0x0000001CU
#define SEND_DATA_CMD_SHIFT 0
#define SEND_DATA_CMD_WIDTH 32
#define SEND_DATA_CMD_MASK 0xFFFFFFFFU
#define SEND_DATA_CMD_LEN_SHIFT 0
#define SEND_DATA_CMD_LEN_WIDTH 16
#define SEND_DATA_CMD_LEN_MASK 0x0000FFFFU
#define SEND_DATA_CMD_OFFSET_SHIFT 16
#define SEND_DATA_CMD_OFFSET_WIDTH 16
#define SEND_DATA_CMD_OFFSET_MASK 0xFFFF0000U
/**
* Register: SLOT_CONFIG_CMD
*/
#define SLOT_CMD 0x00000020U
#define SLOT_CMD_SHIFT 0
#define SLOT_CMD_WIDTH 32
#define SLOT_CMD_MASK 0xFFFFFFFFU
#define SLOT_CMD_KEY 0x434D442EU
/**
* Register: TXRX_STATE
*/
#define TXRX_STATE 0x00000024U
#define TXRX_STATE_ACQ_SHIFT 0
#define TXRX_STATE_ACQ_WIDTH 8
#define TXRX_STATE_ACQ_MASK 0x000000FFU
#define TXRX_STATE_ACQ_SUCCESS 0x00000001U
#define TXRX_STATE_ACQ_FAIL 0x00000002U
#define TXRX_STATE_FSYNC_SHIFT 8
#define TXRX_STATE_FSYNC_WIDTH 8
#define TXRX_STATE_FSYNC_MASK 0x0000FF00U
#define TXRX_STATE_FSYNC_SUCCESS 0x00000100U
#define TXRX_STATE_FSYNC_FAIL 0x00000200U
#define TXRX_STATE_DECODE_SHIFT 16
#define TXRX_STATE_DECODE_WIDTH 8
#define TXRX_STATE_DECODE_MASK 0x00FF0000U
#define TXRX_STATE_DECODE_SUCCESS 0x00010000U
#define TXRX_STATE_DECODE_FAIL 0x00020000U
#define TXRX_STATE_CRC_SHIFT 24
#define TXRX_STATE_CRC_WIDTH 8
#define TXRX_STATE_CRC_MASK 0xFF000000U
#define TXRX_STATE_CRC_OK 0x01000000U
#define TXRX_STATE_CRC_ERROR 0x02000000U
/**
* Register: RECVDATA_STATE
*/
#define RECVDATA_STATE 0x00000028U
#define RECVDATA_STATE_LEN_SHIFT 0
#define RECVDATA_STATE_LEN_WIDTH 16
#define RECVDATA_STATE_LEN_MASK 0x0000FFFFU
#define RECVDATA_STATE_OFFSET_SHIFT 16
#define RECVDATA_STATE_OFFSET_WIDTH 16
#define RECVDATA_STATE_OFFSET_MASK 0xFFFF0000U
/**
* Register: FSTIME_L
*/
#define FSTIME_L 0x0000002CU
#define FSTIME_L_SHIFT 0
#define FSTIME_L_WIDTH 32
#define FSTIME_L_MASK 0xFFFFFFFFU
/**
* Register: FSTIME_INT1
*/
#define FSTIME_H 0x00000030U
#define FSTIME_H_SHIFT 0
#define FSTIME_H_WIDTH 32
#define FSTIME_H_MASK 0xFFFFFFFFU
/**
* Register: TM_TARGET_L
*/
#define TM_TARGET_L 0x00000064U
#define TM_TARGET_L_SHIFT 0
#define TM_TARGET_L_WIDTH 32
#define TM_TARGET_L_MASK 0xFFFFFFFFU
/**
* Register: TM_TARGET_H
*/
#define TM_TARGET_H 0x00000038U
#define TM_TARGET_H_SHIFT 0
#define TM_TARGET_H_WIDTH 32
#define TM_TARGET_H_MASK 0xFFFFFFFFU
/**
* Register: COASEFREQEST
*/
#define COASE_FREQEST 0x0000003CU
#define COASE_FREQEST_ACQ_SHIFT 0
#define COASE_FREQEST_ACQ_WIDTH 8
#define COASE_FREQEST_ACQ_MASK 0x000000FFU
#define COASE_FREQEST_SYNC_SHIFT 8
#define COASE_FREQEST_SYNC_WIDTH 8
#define COASE_FREQEST_SYNC_MASK 0x0000FF00U
#define COASE_TYPE_SHIFT 16
#define COASE_TYPE_WIDTH 8
#define COASE_TYPE_MASK 0x00FF0000U
#define COASE_TYPE_2KBPS_20MS 0x00010000U
#define COASE_TYPE_2KBPS_100MS 0x00020000U
#define COASE_TYPE_10KBPS_10MS 0x00030000U
#define COASE_TYPE_10KBPS_20MS 0x00040000U
#define COASE_TYPE_40KBPS_20MS 0x00050000U
#define COASE_TYPE_40KBPS_10MS 0x00060000U
#define COASE_TYPE_200KBPS_5MS 0x00070000U
#define COASE_TYPE_1M2BPS_5MS 0x00080000U
/**
* Register: FINE_FREQEST
*/
#define FINE_FREQEST 0x00000040U
#define FINE_FREQEST_VAL_SHIFT 0
#define FINE_FREQEST_VAL_WIDTH 24
#define FINE_FREQEST_VAL_MASK 0x00FFFFFFU
#define FINE_FREQEST_SIGN_SHIFT 24
#define FINE_FREQEST_SIGN_WIDTH 8
#define FINE_FREQEST_SIGN_MASK 0xFF000000U
#define FINE_FREQEST_SIGN_POS 0x00000000U
#define FINE_FREQEST_SIGN_NEG 0x01000000U
/**
* Register: BEAM_SELECT
*/
#define BEAM_SELECT_INDEX 0x00000044U
#define BEAM_SELECT_INDEX_SHIFT 0
#define BEAM_SELECT_INDEX_WIDTH 32
#define BEAM_SELECT_INDEX_MASK 0xFFFFFFFFU
/**
* Register: BEAM_AXIS
*/
#define BEAM_AXIS 0x00000044U
#define BEAM_AXIS_EL_SHIFT 0
#define BEAM_AXIS_EL_WIDTH 16
#define BEAM_AXIS_EL_MASK 0x0000FFFFU
#define BEAM_AXIS_AZ_SHIFT 16
#define BEAM_AXIS_AZ_WIDTH 16
#define BEAM_AXIS_AZ_MASK 0xFFFF0000U
/**
* Register: ANT_STATUS
*/
#define ANT_STATUS 0x00000100U
#define ANT_STATUS_ANT_VOLT_SHIFT 0
#define ANT_STATUS_ANT_VOLT_WIDTH 8
#define ANT_STATUS_ANT_VOLT_MASK 0x000000FFU
#define ANT_STATUS_ANT_VOLT_OK 0x00000001U
#define ANT_STATUS_RF_VOLT_SHIFT 8
#define ANT_STATUS_RF_VOLT_WIDTH 8
#define ANT_STATUS_RF_VOLT_MASK 0x0000FF00U
#define ANT_STATUS_RF_VOLT_OK 0x00000100U
#define ANT_STATUS_NIL_VOLT_SHIFT 16
#define ANT_STATUS_NIL_VOLT_WIDTH 8
#define ANT_STATUS_NIL_VOLT_MASK 0x00FF0000U
#define ANT_STATUS_NIL_VOLT_OK 0x00010000U
#define ANT_STATUS_CODE_SHIFT 24
#define ANT_STATUS_CODE_WIDTH 8
#define ANT_STATUS_CODE_MASK 0xFF000000U
#define ANT_STATUS_CODE_OK 0x00000000U
/**
* Register: ANT_FRAME_CNT
*/
#define ANT_FRAME_CNT 0x00000104U
#define ANT_FRAME_CNT_SHIFT 0
#define ANT_FRAME_CNT_WIDTH 32
#define ANT_FRAME_CNT_MASK 0xFFFFFFFFU
/**
* Register: ANT_RF_STATUS
*/
#define ANT_RF_STATUS 0x00000108U
#define ANT_RF_STATUS_TEMP_SHIFT 0
#define ANT_RF_STATUS_TEMP_WIDTH 8
#define ANT_RF_STATUS_TEMP_MASK 0x000000FFU
#define ANT_RF_STATUS_BBLOCK_SHIFT 8
#define ANT_RF_STATUS_BBLOCK_WIDTH 8
#define ANT_RF_STATUS_BBLOCK_MASK 0x0000FF00U
#define ANT_RF_STATUS_BBLOCK_OK 0x00000100U
#define ANT_RF_STATUS_PLLA_SHIFT 16
#define ANT_RF_STATUS_PLLA_WIDTH 8
#define ANT_RF_STATUS_PLLA_MASK 0x00FF0000U
#define ANT_RF_STATUS_PLLA_OK 0x00010000U
#define ANT_RF_STATUS_PLLB_SHIFT 24
#define ANT_RF_STATUS_PLLB_WIDTH 8
#define ANT_RF_STATUS_PLLB_MASK 0xFF000000U
#define ANT_RF_STATUS_PLLB_OK 0x01000000U
/**
* Register: ANT_RF_MGC
*/
#define ANT_RF_MGC 0x0000010CU
#define ANT_RF_MGC_CH1_SHIFT 0
#define ANT_RF_MGC_CH1_WIDTH 4
#define ANT_RF_MGC_CH1_MASK 0x0000000FU
#define ANT_RF_MGC_CH2_SHIFT 8
#define ANT_RF_MGC_CH2_WIDTH 4
#define ANT_RF_MGC_CH2_MASK 0x00000F00U
#define ANT_RF_MGC_CH3_SHIFT 16
#define ANT_RF_MGC_CH3_WIDTH 4
#define ANT_RF_MGC_CH3_MASK 0x000F0000U
#define ANT_RF_MGC_CH4_SHIFT 24
#define ANT_RF_MGC_CH4_WIDTH 4
#define ANT_RF_MGC_CH4_MASK 0x0F000000U
/**
* Register: ANT_RF_FRAME_CNT
*/
#define ANT_RF_FRAME_CNT 0x00000110U
#define ANT_RF_FRAME_CNT_SHIFT 0
#define ANT_RF_FRAME_CNT_WIDTH 32
#define ANT_RF_FRAME_CNT_MASK 0xFFFFFFFFU
/**
* Register: PHY_ACQ_CNT
*/
#define PHY_ACQ_CNT 0x00000114U
#define PHY_ACQ_CNT_SHIFT 0
#define PHY_ACQ_CNT_WIDTH 32
#define PHY_ACQ_CNT_MASK 0xFFFFFFFFU
/**
* Register: PHY_FRAME_SYNC_CNT
*/
#define PHY_FRAME_SYNC_CNT 0x00000118U
#define PHY_FRAME_SYNC_CNT_SHIFT 0
#define PHY_FRAME_SYNC_CNT_WIDTH 32
#define PHY_FRAME_SYNC_CNT_MASK 0xFFFFFFFFU
/**
* Register: PHY_DECODE_CNT
*/
#define PHY_DECODE_CNT 0x0000011CU
#define PHY_DECODE_CNT_SHIFT 0
#define PHY_DECODE_CNT_WIDTH 32
#define PHY_DECODE_CNT_MASK 0xFFFFFFFFU
/**
* Register: PHY_CRC_OK_CNT
*/
#define PHY_CRC_OK_CNT 0x00000120U
#define PHY_CRC_OK_CNT_SHIFT 0
#define PHY_CRC_OK_CNT_WIDTH 32
#define PHY_CRC_OK_CNT_MASK 0xFFFFFFFFU
/**
* Register: PHY_ACQ_PEAK_H
*/
#define PHY_ACQ_PEAK_H 0x00000124U
#define PHY_ACQ_PEAK_H_SHIFT 0
#define PHY_ACQ_PEAK_H_WIDTH 32
#define PHY_ACQ_PEAK_H_MASK 0xFFFFFFFFU
/**
* Register: PHY_ACQ_PEAK_L
*/
#define PHY_ACQ_PEAK_L 0x00000128U
#define PHY_ACQ_PEAK_L_SHIFT 0
#define PHY_ACQ_PEAK_L_WIDTH 32
#define PHY_ACQ_PEAK_L_MASK 0xFFFFFFFFU
/**
* Register: PHY_ACQ_MEAN_H
*/
#define PHY_ACQ_MEAN_H 0x0000012CU
#define PHY_ACQ_MEAN_H_SHIFT 0
#define PHY_ACQ_MEAN_H_WIDTH 32
#define PHY_ACQ_MEAN_H_MASK 0xFFFFFFFFU
/**
* Register: PHY_ACQ_MEAN_L
*/
#define PHY_ACQ_MEAN_L 0x00000130U
#define PHY_ACQ_MEAN_L_SHIFT 0
#define PHY_ACQ_MEAN_L_WIDTH 32
#define PHY_ACQ_MEAN_L_MASK 0xFFFFFFFFU
/**
* Register: PHY_ACQ_FREQEST
*/
#define PHY_ACQ_FREQEST 0x00000134U
#define PHY_ACQ_FREQEST_SHIFT 0
#define PHY_ACQ_FREQEST_WIDTH 32
#define PHY_ACQ_FREQEST_MASK 0xFFFFFFFFU
#define PHY_ACQ_FREQEST_PHASE_SHIFT 0
#define PHY_ACQ_FREQEST_PHASE_WIDTH 8
#define PHY_ACQ_FREQEST_PHASE_MASK 0x000000FFU
#define PHY_ACQ_FREQEST_CHANNEL_SHIFT 8
#define PHY_ACQ_FREQEST_CHANNEL_WIDTH 8
#define PHY_ACQ_FREQEST_CHANNEL_MASK 0x0000FF00U
/**
* Register: PHY_FRAME_SYNC_PEAK_H
*/
#define PHY_FRAME_SYNC_PEAK_H 0x00000138U
#define PHY_FRAME_SYNC_PEAK_H_SHIFT 0
#define PHY_FRAME_SYNC_PEAK_H_WIDTH 32
#define PHY_FRAME_SYNC_PEAK_H_MASK 0xFFFFFFFFU
/**
* Register: PHY_FRAME_SYNC_PEAK_L
*/
#define PHY_FRAME_SYNC_PEAK_L 0x0000013CU
#define PHY_FRAME_SYNC_PEAK_L_SHIFT 0
#define PHY_FRAME_SYNC_PEAK_L_WIDTH 32
#define PHY_FRAME_SYNC_PEAK_L_MASK 0xFFFFFFFFU
/**
* Register: PHY_FRAME_SYNC_MEAN_H
*/
#define PHY_FRAME_SYNC_MEAN_H 0x00000140U
#define PHY_FRAME_SYNC_MEAN_H_SHIFT 0
#define PHY_FRAME_SYNC_MEAN_H_WIDTH 32
#define PHY_FRAME_SYNC_MEAN_H_MASK 0xFFFFFFFFU
/**
* Register: PHY_FRAME_SYNC_MEAN_L
*/
#define PHY_FRAME_SYNC_MEAN_L 0x00000144U
#define PHY_FRAME_SYNC_MEAN_L_SHIFT 0
#define PHY_FRAME_SYNC_MEAN_L_WIDTH 32
#define PHY_FRAME_SYNC_MEAN_L_MASK 0xFFFFFFFFU
/**
* Register: PHY_FRAME_SYNC_FREQEST
*/
#define PHY_FRAME_SYNC_FREQEST 0x00000148U
#define PHY_FRAME_SYNC_FREQEST_SHIFT 0
#define PHY_FRAME_SYNC_FREQEST_WIDTH 32
#define PHY_FRAME_SYNC_FREQEST_MASK 0xFFFFFFFFU
#define PHY_FRAME_SYNC_FREQEST_CHANNEL_SHIFT 0
#define PHY_FRAME_SYNC_FREQEST_CHANNEL_WIDTH 8
#define PHY_FRAME_SYNC_FREQEST_CHANNEL_MASK 0x000000FFU
/**
* Register: PHY_DEINTLV_AMPEST
*/
#define PHY_DEINTLV_AMPEST 0x0000014CU
#define PHY_DEINTLV_AMPEST_SHIFT 0
#define PHY_DEINTLV_AMPEST_WIDTH 16
#define PHY_DEINTLV_AMPEST_MASK 0x0000FFFFU
#endif /* PHY_REG_H_ */
/** @} PhysicalLayer_REG_Constants*/
/** @} PhysicalLayer*/