2010-09-25 11:20:38 +02:00
|
|
|
/**
|
|
|
|
******************************************************************************
|
|
|
|
* @addtogroup AHRS AHRS
|
|
|
|
* @brief The AHRS Modules perform
|
|
|
|
*
|
|
|
|
* @{
|
|
|
|
* @addtogroup AHRS_ADC AHRS ADC
|
|
|
|
* @brief Specialized ADC code for double buffered DMA for AHRS
|
|
|
|
* @{
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @file ahrs.c
|
|
|
|
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
|
|
|
* @brief INSGPS Test Program
|
|
|
|
* @see The GNU Public License (GPL) Version 3
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
/*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
2010-07-04 04:21:22 +02:00
|
|
|
#include <stdint.h> /* uint*_t */
|
|
|
|
#include <stddef.h> /* NULL */
|
|
|
|
|
|
|
|
#include "ahrs_fsm.h"
|
|
|
|
|
|
|
|
#include "pios_opahrs_proto.h"
|
|
|
|
|
|
|
|
#include "pios.h"
|
|
|
|
|
|
|
|
struct lfsm_context {
|
2010-09-21 21:29:39 +02:00
|
|
|
enum lfsm_state curr_state;
|
|
|
|
enum opahrs_msg_link_state link_state;
|
|
|
|
enum opahrs_msg_type user_payload_type;
|
|
|
|
uint32_t user_payload_len;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
uint32_t errors;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
uint8_t *rx;
|
|
|
|
uint8_t *tx;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
uint8_t *link_rx;
|
|
|
|
uint8_t *link_tx;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
uint8_t *user_rx;
|
|
|
|
uint8_t *user_tx;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
struct lfsm_link_stats stats;
|
2010-07-04 04:21:22 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct lfsm_context context = { 0 };
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void lfsm_update_link_tx(struct lfsm_context *context);
|
|
|
|
static void lfsm_init_rx(struct lfsm_context *context);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Link Finite State Machine
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct lfsm_transition {
|
2010-09-21 21:29:39 +02:00
|
|
|
void (*entry_fn) (struct lfsm_context * context);
|
|
|
|
enum lfsm_state next_state[LFSM_EVENT_NUM_EVENTS];
|
2010-07-04 04:21:22 +02:00
|
|
|
};
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void go_faulted(struct lfsm_context *context);
|
|
|
|
static void go_stopped(struct lfsm_context *context);
|
|
|
|
static void go_stopping(struct lfsm_context *context);
|
|
|
|
static void go_inactive(struct lfsm_context *context);
|
|
|
|
static void go_user_busy(struct lfsm_context *context);
|
|
|
|
static void go_user_busy_rx_pending(struct lfsm_context *context);
|
|
|
|
static void go_user_busy_tx_pending(struct lfsm_context *context);
|
|
|
|
static void go_user_busy_rxtx_pending(struct lfsm_context *context);
|
|
|
|
static void go_user_rx_pending(struct lfsm_context *context);
|
|
|
|
static void go_user_tx_pending(struct lfsm_context *context);
|
|
|
|
static void go_user_rxtx_pending(struct lfsm_context *context);
|
|
|
|
static void go_user_rx_active(struct lfsm_context *context);
|
|
|
|
static void go_user_tx_active(struct lfsm_context *context);
|
|
|
|
static void go_user_rxtx_active(struct lfsm_context *context);
|
|
|
|
|
|
|
|
const static struct lfsm_transition lfsm_transitions[LFSM_STATE_NUM_STATES]
|
|
|
|
= {
|
|
|
|
[LFSM_STATE_FAULTED] = {
|
|
|
|
.entry_fn = go_faulted,
|
|
|
|
},
|
|
|
|
[LFSM_STATE_STOPPED] = {
|
|
|
|
.entry_fn = go_stopped,
|
|
|
|
.next_state = {
|
|
|
|
[LFSM_EVENT_INIT_LINK] =
|
|
|
|
LFSM_STATE_INACTIVE,
|
|
|
|
[LFSM_EVENT_RX_UNKNOWN] =
|
|
|
|
LFSM_STATE_STOPPED,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
[LFSM_STATE_STOPPING] = {
|
|
|
|
.entry_fn = go_stopping,
|
|
|
|
.next_state = {
|
|
|
|
[LFSM_EVENT_RX_LINK] =
|
|
|
|
LFSM_STATE_STOPPED,
|
|
|
|
[LFSM_EVENT_RX_USER] =
|
|
|
|
LFSM_STATE_STOPPED,
|
|
|
|
[LFSM_EVENT_RX_UNKNOWN] =
|
|
|
|
LFSM_STATE_STOPPED,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
[LFSM_STATE_INACTIVE] = {
|
|
|
|
.entry_fn = go_inactive,
|
|
|
|
.next_state = {
|
|
|
|
[LFSM_EVENT_STOP] =
|
|
|
|
LFSM_STATE_STOPPING,
|
|
|
|
[LFSM_EVENT_USER_SET_RX] =
|
|
|
|
LFSM_STATE_USER_BUSY_RX_PENDING,
|
|
|
|
[LFSM_EVENT_USER_SET_TX] =
|
|
|
|
LFSM_STATE_USER_BUSY_TX_PENDING,
|
|
|
|
[LFSM_EVENT_RX_LINK] =
|
|
|
|
LFSM_STATE_INACTIVE,
|
|
|
|
[LFSM_EVENT_RX_USER] =
|
|
|
|
LFSM_STATE_INACTIVE,
|
|
|
|
[LFSM_EVENT_RX_UNKNOWN] =
|
|
|
|
LFSM_STATE_INACTIVE,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
[LFSM_STATE_USER_BUSY] = {
|
|
|
|
.entry_fn = go_user_busy,
|
|
|
|
.next_state = {
|
|
|
|
[LFSM_EVENT_STOP] =
|
|
|
|
LFSM_STATE_STOPPING,
|
|
|
|
[LFSM_EVENT_USER_SET_RX] =
|
|
|
|
LFSM_STATE_USER_BUSY_RX_PENDING,
|
|
|
|
[LFSM_EVENT_USER_SET_TX] =
|
|
|
|
LFSM_STATE_USER_BUSY_TX_PENDING,
|
|
|
|
[LFSM_EVENT_USER_DONE] =
|
|
|
|
LFSM_STATE_INACTIVE,
|
|
|
|
[LFSM_EVENT_RX_LINK] =
|
|
|
|
LFSM_STATE_USER_BUSY,
|
|
|
|
[LFSM_EVENT_RX_USER] =
|
|
|
|
LFSM_STATE_USER_BUSY,
|
|
|
|
[LFSM_EVENT_RX_UNKNOWN] =
|
|
|
|
LFSM_STATE_USER_BUSY,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
[LFSM_STATE_USER_BUSY_RX_PENDING] = {
|
|
|
|
.entry_fn =
|
|
|
|
go_user_busy_rx_pending,
|
|
|
|
.next_state = {
|
|
|
|
[LFSM_EVENT_USER_SET_TX] = LFSM_STATE_USER_BUSY_RXTX_PENDING,
|
|
|
|
[LFSM_EVENT_USER_DONE] = LFSM_STATE_USER_RX_PENDING,
|
|
|
|
[LFSM_EVENT_RX_LINK] = LFSM_STATE_USER_BUSY_RX_PENDING,
|
|
|
|
[LFSM_EVENT_RX_USER] = LFSM_STATE_USER_BUSY_RX_PENDING,
|
|
|
|
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_USER_BUSY_RX_PENDING,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
[LFSM_STATE_USER_BUSY_TX_PENDING] = {
|
|
|
|
.entry_fn =
|
|
|
|
go_user_busy_tx_pending,
|
|
|
|
.next_state = {
|
|
|
|
[LFSM_EVENT_USER_SET_RX] = LFSM_STATE_USER_BUSY_RXTX_PENDING,
|
|
|
|
[LFSM_EVENT_USER_DONE] = LFSM_STATE_USER_TX_PENDING,
|
|
|
|
[LFSM_EVENT_RX_LINK] = LFSM_STATE_USER_BUSY_TX_PENDING,
|
|
|
|
[LFSM_EVENT_RX_USER] = LFSM_STATE_USER_BUSY_TX_PENDING,
|
|
|
|
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_USER_BUSY_TX_PENDING,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
[LFSM_STATE_USER_BUSY_RXTX_PENDING] = {
|
|
|
|
.entry_fn =
|
|
|
|
go_user_busy_rxtx_pending,
|
|
|
|
.next_state = {
|
|
|
|
[LFSM_EVENT_USER_DONE] = LFSM_STATE_USER_RXTX_PENDING,
|
|
|
|
[LFSM_EVENT_RX_LINK] = LFSM_STATE_USER_BUSY_RXTX_PENDING,
|
|
|
|
[LFSM_EVENT_RX_USER] = LFSM_STATE_USER_BUSY_RXTX_PENDING,
|
|
|
|
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_USER_BUSY_RXTX_PENDING,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
[LFSM_STATE_USER_RX_PENDING] = {
|
|
|
|
.entry_fn = go_user_rx_pending,
|
|
|
|
.next_state = {
|
|
|
|
[LFSM_EVENT_RX_LINK]
|
|
|
|
=
|
|
|
|
LFSM_STATE_USER_RX_ACTIVE,
|
|
|
|
[LFSM_EVENT_RX_USER]
|
|
|
|
=
|
|
|
|
LFSM_STATE_USER_RX_ACTIVE,
|
|
|
|
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_USER_RX_ACTIVE,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
[LFSM_STATE_USER_TX_PENDING] = {
|
|
|
|
.entry_fn = go_user_tx_pending,
|
|
|
|
.next_state = {
|
|
|
|
[LFSM_EVENT_RX_LINK]
|
|
|
|
=
|
|
|
|
LFSM_STATE_USER_TX_ACTIVE,
|
|
|
|
[LFSM_EVENT_RX_USER]
|
|
|
|
=
|
|
|
|
LFSM_STATE_USER_TX_ACTIVE,
|
|
|
|
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_USER_TX_ACTIVE,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
[LFSM_STATE_USER_RXTX_PENDING] = {
|
|
|
|
.entry_fn = go_user_rxtx_pending,
|
|
|
|
.next_state = {
|
|
|
|
[LFSM_EVENT_RX_LINK] = LFSM_STATE_USER_RXTX_ACTIVE,
|
|
|
|
[LFSM_EVENT_RX_USER] = LFSM_STATE_USER_RXTX_ACTIVE,
|
|
|
|
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_USER_RXTX_ACTIVE,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
[LFSM_STATE_USER_RX_ACTIVE] = {
|
|
|
|
.entry_fn = go_user_rx_active,
|
|
|
|
.next_state = {
|
|
|
|
[LFSM_EVENT_RX_LINK]
|
|
|
|
=
|
|
|
|
LFSM_STATE_USER_RX_ACTIVE,
|
|
|
|
[LFSM_EVENT_RX_USER]
|
|
|
|
=
|
|
|
|
LFSM_STATE_USER_BUSY,
|
|
|
|
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_USER_RX_ACTIVE,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
[LFSM_STATE_USER_TX_ACTIVE] = {
|
|
|
|
.entry_fn = go_user_tx_active,
|
|
|
|
.next_state = {
|
|
|
|
[LFSM_EVENT_RX_LINK]
|
|
|
|
=
|
|
|
|
LFSM_STATE_INACTIVE,
|
|
|
|
[LFSM_EVENT_RX_USER]
|
|
|
|
=
|
|
|
|
LFSM_STATE_INACTIVE,
|
|
|
|
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_INACTIVE,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
[LFSM_STATE_USER_RXTX_ACTIVE] = {
|
|
|
|
.entry_fn = go_user_rxtx_active,
|
|
|
|
.next_state = {
|
|
|
|
[LFSM_EVENT_RX_LINK] = LFSM_STATE_USER_RX_ACTIVE,
|
|
|
|
[LFSM_EVENT_RX_USER] = LFSM_STATE_USER_BUSY,
|
|
|
|
[LFSM_EVENT_RX_UNKNOWN] = LFSM_STATE_USER_RX_ACTIVE,
|
|
|
|
},
|
|
|
|
},
|
2010-07-04 04:21:22 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FSM State Entry Functions
|
|
|
|
*/
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void go_faulted(struct lfsm_context *context)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
PIOS_DEBUG_Assert(0);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void go_stopped(struct lfsm_context *context)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
|
|
|
#if 0
|
2010-09-21 21:29:39 +02:00
|
|
|
PIOS_SPI_Stop(PIOS_SPI_OP);
|
2010-07-04 04:21:22 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void go_stopping(struct lfsm_context *context)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
context->link_tx = NULL;
|
|
|
|
context->tx = NULL;
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void go_inactive(struct lfsm_context *context)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
context->link_state = OPAHRS_MSG_LINK_STATE_INACTIVE;
|
|
|
|
lfsm_update_link_tx(context);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->user_rx = NULL;
|
|
|
|
context->user_tx = NULL;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->rx = context->link_rx;
|
|
|
|
context->tx = context->link_tx;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_init_rx(context);
|
|
|
|
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
|
|
context->user_payload_len,
|
|
|
|
lfsm_irq_callback);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void go_user_busy(struct lfsm_context *context)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
/* Sanity checks */
|
|
|
|
PIOS_DEBUG_Assert(context->user_rx);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->user_rx = NULL;
|
|
|
|
context->user_tx = NULL;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->link_state = OPAHRS_MSG_LINK_STATE_BUSY;
|
|
|
|
lfsm_update_link_tx(context);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->rx = context->link_rx;
|
|
|
|
context->tx = context->link_tx;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_init_rx(context);
|
|
|
|
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
|
|
context->user_payload_len,
|
|
|
|
lfsm_irq_callback);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void go_user_busy_rx_pending(struct lfsm_context *context)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
/* Sanity checks */
|
|
|
|
PIOS_DEBUG_Assert(context->user_rx);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->link_state = OPAHRS_MSG_LINK_STATE_BUSY;
|
|
|
|
lfsm_update_link_tx(context);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->rx = context->link_rx;
|
|
|
|
context->tx = context->link_tx;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_init_rx(context);
|
|
|
|
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
|
|
context->user_payload_len,
|
|
|
|
lfsm_irq_callback);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void go_user_busy_tx_pending(struct lfsm_context *context)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
/* Sanity checks */
|
|
|
|
PIOS_DEBUG_Assert(context->user_tx);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->link_state = OPAHRS_MSG_LINK_STATE_BUSY;
|
|
|
|
lfsm_update_link_tx(context);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->rx = context->link_rx;
|
|
|
|
context->tx = context->link_tx;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_init_rx(context);
|
|
|
|
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
|
|
context->user_payload_len,
|
|
|
|
lfsm_irq_callback);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void go_user_busy_rxtx_pending(struct lfsm_context *context)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
/* Sanity checks */
|
|
|
|
PIOS_DEBUG_Assert(context->user_rx);
|
|
|
|
PIOS_DEBUG_Assert(context->user_tx);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->link_state = OPAHRS_MSG_LINK_STATE_BUSY;
|
|
|
|
lfsm_update_link_tx(context);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->rx = context->link_rx;
|
|
|
|
context->tx = context->link_tx;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_init_rx(context);
|
|
|
|
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
|
|
context->user_payload_len,
|
|
|
|
lfsm_irq_callback);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void go_user_rx_pending(struct lfsm_context *context)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
/* Sanity checks */
|
|
|
|
PIOS_DEBUG_Assert(context->user_rx);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->link_state = OPAHRS_MSG_LINK_STATE_BUSY;
|
|
|
|
lfsm_update_link_tx(context);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->rx = context->link_rx;
|
|
|
|
context->tx = context->link_tx;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_init_rx(context);
|
|
|
|
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
|
|
context->user_payload_len,
|
|
|
|
lfsm_irq_callback);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void go_user_tx_pending(struct lfsm_context *context)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
/* Sanity checks */
|
|
|
|
PIOS_DEBUG_Assert(context->user_tx);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->link_state = OPAHRS_MSG_LINK_STATE_BUSY;
|
|
|
|
lfsm_update_link_tx(context);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->rx = context->link_rx;
|
|
|
|
context->tx = context->link_tx;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_init_rx(context);
|
|
|
|
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
|
|
context->user_payload_len,
|
|
|
|
lfsm_irq_callback);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void go_user_rxtx_pending(struct lfsm_context *context)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
/* Sanity checks */
|
|
|
|
PIOS_DEBUG_Assert(context->user_rx);
|
|
|
|
PIOS_DEBUG_Assert(context->user_tx);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->link_state = OPAHRS_MSG_LINK_STATE_BUSY;
|
|
|
|
lfsm_update_link_tx(context);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->rx = context->link_rx;
|
|
|
|
context->tx = context->link_tx;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_init_rx(context);
|
|
|
|
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
|
|
context->user_payload_len,
|
|
|
|
lfsm_irq_callback);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void go_user_rx_active(struct lfsm_context *context)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
/* Sanity checks */
|
|
|
|
PIOS_DEBUG_Assert(context->user_rx);
|
|
|
|
|
|
|
|
context->rx = context->user_rx;
|
|
|
|
context->tx = context->link_tx;
|
|
|
|
context->link_state = OPAHRS_MSG_LINK_STATE_READY;
|
|
|
|
|
|
|
|
lfsm_update_link_tx(context);
|
|
|
|
lfsm_init_rx(context);
|
|
|
|
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
|
|
context->user_payload_len,
|
|
|
|
lfsm_irq_callback);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void go_user_tx_active(struct lfsm_context *context)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
/* Sanity checks */
|
|
|
|
PIOS_DEBUG_Assert(context->user_tx);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context->link_state = OPAHRS_MSG_LINK_STATE_BUSY;
|
|
|
|
context->rx = context->link_rx;
|
|
|
|
context->tx = context->user_tx;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_init_rx(context);
|
|
|
|
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
|
|
context->user_payload_len,
|
|
|
|
lfsm_irq_callback);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void go_user_rxtx_active(struct lfsm_context *context)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
/* Sanity checks */
|
|
|
|
PIOS_DEBUG_Assert(context->user_rx);
|
|
|
|
PIOS_DEBUG_Assert(context->user_tx);
|
|
|
|
|
|
|
|
context->link_state = OPAHRS_MSG_LINK_STATE_READY;
|
|
|
|
context->rx = context->user_rx;
|
|
|
|
context->tx = context->user_tx;
|
|
|
|
|
|
|
|
lfsm_init_rx(context);
|
|
|
|
PIOS_SPI_TransferBlock(PIOS_SPI_OP, context->tx, context->rx,
|
|
|
|
context->user_payload_len,
|
|
|
|
lfsm_irq_callback);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Misc Helper Functions
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void lfsm_update_link_tx_v0(struct opahrs_msg_v0 *msg,
|
|
|
|
enum opahrs_msg_link_state state,
|
|
|
|
uint16_t errors)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
opahrs_msg_v0_init_link_tx(msg, OPAHRS_MSG_LINK_TAG_NOP);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
msg->payload.link.state = state;
|
|
|
|
msg->payload.link.errors = errors;
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void lfsm_update_link_tx_v1(struct opahrs_msg_v1 *msg,
|
|
|
|
enum opahrs_msg_link_state state,
|
|
|
|
uint16_t errors)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
opahrs_msg_v1_init_link_tx(msg, OPAHRS_MSG_LINK_TAG_NOP);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
msg->payload.link.state = state;
|
|
|
|
msg->payload.link.errors = errors;
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void lfsm_update_link_tx(struct lfsm_context *context)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
PIOS_DEBUG_Assert(context->link_tx);
|
|
|
|
|
|
|
|
switch (context->user_payload_type) {
|
|
|
|
case OPAHRS_MSG_TYPE_USER_V0:
|
|
|
|
lfsm_update_link_tx_v0((struct opahrs_msg_v0 *)context->
|
|
|
|
link_tx, context->link_state,
|
|
|
|
context->errors);
|
|
|
|
break;
|
|
|
|
case OPAHRS_MSG_TYPE_USER_V1:
|
|
|
|
lfsm_update_link_tx_v1((struct opahrs_msg_v1 *)context->
|
|
|
|
link_tx, context->link_state,
|
|
|
|
context->errors);
|
|
|
|
break;
|
|
|
|
case OPAHRS_MSG_TYPE_LINK:
|
|
|
|
PIOS_DEBUG_Assert(0);
|
|
|
|
}
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
static void lfsm_init_rx(struct lfsm_context *context)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
PIOS_DEBUG_Assert(context->rx);
|
|
|
|
|
|
|
|
switch (context->user_payload_type) {
|
|
|
|
case OPAHRS_MSG_TYPE_USER_V0:
|
|
|
|
opahrs_msg_v0_init_rx((struct opahrs_msg_v0 *)context->rx);
|
|
|
|
break;
|
|
|
|
case OPAHRS_MSG_TYPE_USER_V1:
|
|
|
|
opahrs_msg_v1_init_rx((struct opahrs_msg_v1 *)context->rx);
|
|
|
|
break;
|
|
|
|
case OPAHRS_MSG_TYPE_LINK:
|
|
|
|
PIOS_DEBUG_Assert(0);
|
|
|
|
}
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* External API
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
void lfsm_inject_event(enum lfsm_event event)
|
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
PIOS_IRQ_Disable();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Move to the next state
|
|
|
|
*
|
|
|
|
* This is done prior to calling the new state's entry function to
|
|
|
|
* guarantee that the entry function never depends on the previous
|
|
|
|
* state. This way, it cannot ever know what the previous state was.
|
|
|
|
*/
|
|
|
|
context.curr_state =
|
|
|
|
lfsm_transitions[context.curr_state].next_state[event];
|
|
|
|
|
|
|
|
/* Call the entry function (if any) for the next state. */
|
|
|
|
if (lfsm_transitions[context.curr_state].entry_fn) {
|
|
|
|
lfsm_transitions[context.curr_state].entry_fn(&context);
|
|
|
|
}
|
|
|
|
PIOS_IRQ_Enable();
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void lfsm_init(void)
|
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
context.curr_state = LFSM_STATE_STOPPED;
|
|
|
|
go_stopped(&context);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
void lfsm_set_link_proto_v0(struct opahrs_msg_v0 *link_tx,
|
|
|
|
struct opahrs_msg_v0 *link_rx)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
PIOS_DEBUG_Assert(link_tx);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context.link_tx = (uint8_t *) link_tx;
|
|
|
|
context.link_rx = (uint8_t *) link_rx;
|
|
|
|
context.user_payload_type = OPAHRS_MSG_TYPE_USER_V0;
|
|
|
|
context.user_payload_len = sizeof(*link_tx);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_update_link_tx_v0(link_tx, context.link_state,
|
|
|
|
context.errors);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_inject_event(LFSM_EVENT_INIT_LINK);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
void lfsm_set_link_proto_v1(struct opahrs_msg_v1 *link_tx,
|
|
|
|
struct opahrs_msg_v1 *link_rx)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
PIOS_DEBUG_Assert(link_tx);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context.link_tx = (uint8_t *) link_tx;
|
|
|
|
context.link_rx = (uint8_t *) link_rx;
|
|
|
|
context.user_payload_type = OPAHRS_MSG_TYPE_USER_V1;
|
|
|
|
context.user_payload_len = sizeof(*link_tx);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_update_link_tx_v1(link_tx, context.link_state,
|
|
|
|
context.errors);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_inject_event(LFSM_EVENT_INIT_LINK);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
void lfsm_user_set_tx_v0(struct opahrs_msg_v0 *user_tx)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
PIOS_DEBUG_Assert(user_tx);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
PIOS_DEBUG_Assert(context.user_payload_type ==
|
|
|
|
OPAHRS_MSG_TYPE_USER_V0);
|
|
|
|
context.user_tx = (uint8_t *) user_tx;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_inject_event(LFSM_EVENT_USER_SET_TX);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
void lfsm_user_set_rx_v0(struct opahrs_msg_v0 *user_rx)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
PIOS_DEBUG_Assert(user_rx);
|
|
|
|
PIOS_DEBUG_Assert(context.user_payload_type ==
|
|
|
|
OPAHRS_MSG_TYPE_USER_V0);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context.user_rx = (uint8_t *) user_rx;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_inject_event(LFSM_EVENT_USER_SET_RX);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
void lfsm_user_set_tx_v1(struct opahrs_msg_v1 *user_tx)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
PIOS_DEBUG_Assert(user_tx);
|
|
|
|
PIOS_DEBUG_Assert(context.user_payload_type ==
|
|
|
|
OPAHRS_MSG_TYPE_USER_V1);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context.user_tx = (uint8_t *) user_tx;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_inject_event(LFSM_EVENT_USER_SET_TX);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
void lfsm_user_set_rx_v1(struct opahrs_msg_v1 *user_rx)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
PIOS_DEBUG_Assert(user_rx);
|
|
|
|
PIOS_DEBUG_Assert(context.user_payload_type ==
|
|
|
|
OPAHRS_MSG_TYPE_USER_V1);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
context.user_rx = (uint8_t *) user_rx;
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_inject_event(LFSM_EVENT_USER_SET_RX);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
void lfsm_user_done(void)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_inject_event(LFSM_EVENT_USER_DONE);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
void lfsm_stop(void)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
lfsm_inject_event(LFSM_EVENT_STOP);
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
void lfsm_get_link_stats(struct lfsm_link_stats *stats)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
PIOS_DEBUG_Assert(stats);
|
2010-07-04 04:21:22 +02:00
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
*stats = context.stats;
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
2010-09-21 21:29:39 +02:00
|
|
|
enum lfsm_state lfsm_get_state(void)
|
2010-07-04 04:21:22 +02:00
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
return context.curr_state;
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* ISR Callback
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
void lfsm_irq_callback(uint8_t crc_ok, uint8_t crc_val)
|
|
|
|
{
|
2010-09-21 21:29:39 +02:00
|
|
|
if (!crc_ok) {
|
|
|
|
context.stats.rx_badcrc++;
|
|
|
|
lfsm_inject_event(LFSM_EVENT_RX_UNKNOWN);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!context.rx) {
|
|
|
|
/* No way to know what we just received, assume invalid */
|
|
|
|
lfsm_inject_event(LFSM_EVENT_RX_UNKNOWN);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Recover the head and tail pointers from the message */
|
|
|
|
struct opahrs_msg_link_head *head = NULL;
|
|
|
|
struct opahrs_msg_link_tail *tail = NULL;
|
|
|
|
|
|
|
|
switch (context.user_payload_type) {
|
|
|
|
case OPAHRS_MSG_TYPE_USER_V0:
|
|
|
|
head = &((struct opahrs_msg_v0 *)context.rx)->head;
|
|
|
|
tail = &((struct opahrs_msg_v0 *)context.rx)->tail;
|
|
|
|
break;
|
|
|
|
case OPAHRS_MSG_TYPE_USER_V1:
|
|
|
|
head = &((struct opahrs_msg_v1 *)context.rx)->head;
|
|
|
|
tail = &((struct opahrs_msg_v1 *)context.rx)->tail;
|
|
|
|
break;
|
|
|
|
case OPAHRS_MSG_TYPE_LINK:
|
|
|
|
/* Should never be rx'ing before the link protocol version is known */
|
|
|
|
PIOS_DEBUG_Assert(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for bad magic */
|
|
|
|
if ((head->magic != OPAHRS_MSG_MAGIC_HEAD) ||
|
|
|
|
(tail->magic != OPAHRS_MSG_MAGIC_TAIL)) {
|
|
|
|
if (head->magic != OPAHRS_MSG_MAGIC_HEAD) {
|
|
|
|
context.stats.rx_badmagic_head++;
|
|
|
|
}
|
|
|
|
if (tail->magic != OPAHRS_MSG_MAGIC_TAIL) {
|
|
|
|
context.stats.rx_badmagic_tail++;
|
|
|
|
}
|
|
|
|
lfsm_inject_event(LFSM_EVENT_RX_UNKNOWN);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Good magic, find out what type of payload we've got */
|
|
|
|
switch (head->type) {
|
|
|
|
case OPAHRS_MSG_TYPE_LINK:
|
|
|
|
context.stats.rx_link++;
|
|
|
|
lfsm_inject_event(LFSM_EVENT_RX_LINK);
|
|
|
|
break;
|
|
|
|
case OPAHRS_MSG_TYPE_USER_V0:
|
|
|
|
case OPAHRS_MSG_TYPE_USER_V1:
|
|
|
|
if (head->type == context.user_payload_type) {
|
|
|
|
context.stats.rx_user++;
|
|
|
|
lfsm_inject_event(LFSM_EVENT_RX_USER);
|
|
|
|
} else {
|
|
|
|
/* Mismatched user payload type */
|
|
|
|
context.stats.rx_badver++;
|
|
|
|
lfsm_inject_event(LFSM_EVENT_RX_UNKNOWN);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Unidentifiable payload type */
|
|
|
|
context.stats.rx_badtype++;
|
|
|
|
lfsm_inject_event(LFSM_EVENT_RX_UNKNOWN);
|
|
|
|
}
|
2010-07-04 04:21:22 +02:00
|
|
|
}
|
2010-09-25 11:20:38 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @}
|
|
|
|
* @}
|
|
|
|
*/
|