2012-03-18 18:22:05 +01:00
/******************************************************************************
2011-01-13 09:45:18 +01:00
*
* @ file packet_handler . c
2012-03-18 18:22:05 +01:00
* @ author The OpenPilot Team , http : //www.openpilot.org Copyright (C) 2010.
* @ brief Modem packet handling routines
2011-01-13 09:45:18 +01:00
* @ 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
*/
2012-03-18 18:22:05 +01:00
// ********
// We use 128-bit AES CBC encryption if encryption is enabled
// encrypted packet format
// 16-byte CBC .. 1st byte must not be zero
// 4-byte source id
// 4-byte destination id
// 1-byte packet type
// 1-byte tx sequence value
// 1-byte rx sequence value
// 1-byte data size
// 4-byte crc of entire packet not including CBC bytes
// unencrypted packet format
// 1-byte null byte .. set to zero to indicate packet is not encrypted
// 4-byte source id
// 4-byte destination id
// 1-byte packet type
// 1-byte tx sequence value
// 1-byte rx sequence value
// 1-byte data size
// 4-byte crc of entire packet not including the null byte
// ********
# include <string.h> // memmove
# include "main.h"
# include "rfm22b.h"
# include "fifo_buffer.h"
2011-01-13 09:45:18 +01:00
# include "aes.h"
# include "crc.h"
2012-03-18 18:22:05 +01:00
# include "saved_settings.h"
# include "packet_handler.h"
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
# if defined(PIOS_COM_DEBUG)
// #define PACKET_DEBUG
# endif
// *****************************************************************************
# define PH_FIFO_BUFFER_SIZE 2048 // FIFO buffer size
// *****************************************************************************
# define AES_BLOCK_SIZE 16 // AES encryption does it in 16-byte blocks ONLY
// default aes 128-bit encryption key
const uint8_t default_aes_key [ AES_BLOCK_SIZE ] = { 0x65 , 0x3b , 0x71 , 0x89 , 0x4a , 0xf4 , 0xc8 , 0xcb , 0x18 , 0xd4 , 0x9b , 0x4d , 0x4a , 0xbe , 0xc8 , 0x37 } ;
// *****************************************************************************
# define RETRY_RECONNECT_COUNT 60 // if transmission retries this many times then reset the link to the remote modem
# define PACKET_TYPE_DATA_COMP_BIT 0x80 // data compressed bit. if set then the data in the packet is compressed
# define PACKET_TYPE_MASK 0x7f // packet type mask
enum {
PACKET_TYPE_NONE = 0 ,
PACKET_TYPE_CONNECT , // for requesting a connection
PACKET_TYPE_CONNECT_ACK , // ack
PACKET_TYPE_DISCONNECT , // to tell the other modem they cannot connect to us
PACKET_TYPE_DATA , // data packet (packet contains user data)
PACKET_TYPE_DATA_ACK , // ack
PACKET_TYPE_READY , // tells the other modem we are ready to accept more data
PACKET_TYPE_READY_ACK , // ack
PACKET_TYPE_NOTREADY , // tells the other modem we're not ready to accept more data - we can also send user data in this packet type
PACKET_TYPE_NOTREADY_ACK , // ack
PACKET_TYPE_DATARATE , // for changing the RF data rate
PACKET_TYPE_DATARATE_ACK , // ack
PACKET_TYPE_PING , // used to check link is still up
PACKET_TYPE_PONG , // ack
PACKET_TYPE_ADJUST_TX_PWR , // used to ask the other modem to adjust it's tx power
PACKET_TYPE_ADJUST_TX_PWR_ACK // ack
} ;
# define BROADCAST_ADDR 0xffffffff
//#pragma pack(push)
//#pragma pack(1)
typedef struct
{
uint32_t source_id ;
uint32_t destination_id ;
uint8_t type ;
uint8_t tx_seq ;
uint8_t rx_seq ;
uint8_t data_size ;
uint32_t crc ;
} __attribute__ ( ( __packed__ ) ) t_packet_header ;
// this structure must be a multiple of 'AES_BLOCK_SIZE' bytes in size and no more than 255 bytes in size
typedef struct
{
uint8_t cbc [ AES_BLOCK_SIZE ] ; // AES encryption Cipher-Block-Chaining key .. 1st byte must not be zero - to indicate the packet is encrypted
t_packet_header header ;
uint8_t data [ 240 - sizeof ( t_packet_header ) - AES_BLOCK_SIZE ] ;
} __attribute__ ( ( __packed__ ) ) t_encrypted_packet ;
// this structure must be no more than 255 bytes in size (255 = the maximum packet size)
typedef struct
2011-03-03 17:32:43 +01:00
{
2012-03-18 18:22:05 +01:00
uint8_t null_byte ; // this must be set to zero - to indicate the packet is unencrypted
t_packet_header header ;
uint8_t data [ 255 - sizeof ( t_packet_header ) - 1 ] ;
} __attribute__ ( ( __packed__ ) ) t_unencrypted_packet ;
//#pragma pack(pop)
// *****************************************************************************
// link state for each remote connection
enum {
LINK_DISCONNECTED = 0 ,
LINK_CONNECTING ,
LINK_CONNECTED
} ;
typedef struct
{
uint32_t serial_number ; // their serial number
uint8_t tx_buffer [ PH_FIFO_BUFFER_SIZE ] __attribute__ ( ( aligned ( 4 ) ) ) ;
t_fifo_buffer tx_fifo_buffer ; // holds the data to be transmitted to the other modem
uint8_t rx_buffer [ PH_FIFO_BUFFER_SIZE ] __attribute__ ( ( aligned ( 4 ) ) ) ;
t_fifo_buffer rx_fifo_buffer ; // holds the data received from the other modem
uint8_t link_state ; // holds our current RF link state
uint8_t tx_sequence ; // incremented with each data packet transmitted, sent in every packet transmitted
uint8_t tx_sequence_data_size ; // the size of data we sent in our last packet
uint8_t rx_sequence ; // incremented with each data packet received contain data, sent in every packet transmitted
volatile uint16_t tx_packet_timer ; // ms .. used for packet timing
uint16_t tx_retry_time_slots ; // add's some random packet transmission timing - to try to prevent transmission collisions
uint16_t tx_retry_time_slot_len ; // ms .. " " "
uint16_t tx_retry_time ; // ms .. " " "
uint16_t tx_retry_counter ; // incremented on each transmission, reset back to '0' when we receive an ack to our transmission
volatile uint16_t data_speed_timer ; // used for calculating the transmit/receive data rate
volatile uint32_t tx_data_speed_count ; // incremented with the number of data bits we send in our transmit packets
volatile uint32_t tx_data_speed ; // holds the number of data bits we have sent each second
volatile uint32_t rx_data_speed_count ; // incremented with the number of data bits we send in our transmit packets
volatile uint32_t rx_data_speed ; // holds the number of data bits we have received each second
uint16_t ping_time ; // ping timer
uint16_t fast_ping_time ; // ping timer
bool pinging ; // TRUE if we are doing a ping test with the other modem - to check if it is still present
bool rx_not_ready_mode ; // TRUE if we have told the other modem we cannot receive data (due to buffer filling up).
// we set it back to FALSE when our received buffer starts to empty
volatile int16_t ready_to_send_timer ; // ms .. used to hold off packet transmission to wait a bit for data to mount up for transmission (improves data thru-put speed)
volatile int32_t not_ready_timer ; // ms .. >= 0 while we have been asked not to send anymore data to the other modem, -1 when we are allowed to send data
bool send_encrypted ; // TRUE if we are to AES encrypt in every packet we transmit
int16_t rx_rssi_dBm ; // the strength of the received packet
int32_t rx_afc_Hz ; // the frequency offset of the received packet
} t_connection ;
// *****************************************************************************
uint32_t our_serial_number = 0 ; // our serial number
t_connection connection [ PH_MAX_CONNECTIONS ] ; // holds each connection state
uint8_t aes_key [ AES_BLOCK_SIZE ] __attribute__ ( ( aligned ( 4 ) ) ) ; // holds the aes encryption key - the same for ALL connections
uint8_t dec_aes_key [ AES_BLOCK_SIZE ] __attribute__ ( ( aligned ( 4 ) ) ) ; // holds the pre-calculated decryption key
uint8_t enc_cbc [ AES_BLOCK_SIZE ] __attribute__ ( ( aligned ( 4 ) ) ) ; // holds the tx aes cbc bytes
uint8_t ph_tx_buffer [ 256 ] __attribute__ ( ( aligned ( 4 ) ) ) ; // holds the transmit packet
uint8_t ph_rx_buffer [ 256 ] __attribute__ ( ( aligned ( 4 ) ) ) ; // holds the received packet
int16_t rx_rssi_dBm ;
int32_t rx_afc_Hz ;
bool fast_ping ;
// *****************************************************************************
// return TRUE if we are connected to the remote modem
bool ph_connected ( const int connection_index )
{
if ( connection_index < 0 | | connection_index > = PH_MAX_CONNECTIONS )
return FALSE ;
t_connection * conn = & connection [ connection_index ] ;
return ( conn - > link_state = = LINK_CONNECTED ) ;
2011-03-04 09:34:44 +01:00
}
2012-03-18 18:22:05 +01:00
// *****************************************************************************
// public tx buffer functions
uint16_t ph_putData_free ( const int connection_index )
{ // return the free space size
if ( connection_index < 0 | | connection_index > = PH_MAX_CONNECTIONS )
return 0 ;
return fifoBuf_getFree ( & connection [ connection_index ] . tx_fifo_buffer ) ;
}
uint16_t ph_putData ( const int connection_index , const void * data , uint16_t len )
{ // add data to our tx buffer to be sent
if ( connection_index < 0 | | connection_index > = PH_MAX_CONNECTIONS )
return 0 ;
return fifoBuf_putData ( & connection [ connection_index ] . tx_fifo_buffer , data , len ) ;
}
// *****************************************************************************
// public rx buffer functions
uint16_t ph_getData_used ( const int connection_index )
{ // return the number of bytes available in the rx buffer
if ( connection_index < 0 | | connection_index > = PH_MAX_CONNECTIONS )
return 0 ;
return fifoBuf_getUsed ( & connection [ connection_index ] . rx_fifo_buffer ) ;
}
uint16_t ph_getData ( const int connection_index , void * data , uint16_t len )
{ // get data from our rx buffer
if ( connection_index < 0 | | connection_index > = PH_MAX_CONNECTIONS )
return 0 ;
return fifoBuf_getData ( & connection [ connection_index ] . rx_fifo_buffer , data , len ) ;
}
// *****************************************************************************
// start a connection to another modem
int ph_startConnect ( int connection_index , uint32_t sn )
2011-03-04 09:34:44 +01:00
{
2012-03-18 18:22:05 +01:00
random32 = updateCRC32 ( random32 , 0xff ) ;
if ( connection_index < 0 | | connection_index > = PH_MAX_CONNECTIONS )
return - 1 ;
t_connection * conn = & connection [ connection_index ] ;
conn - > link_state = LINK_DISCONNECTED ;
LINK_LED_OFF ;
conn - > serial_number = sn ;
conn - > tx_sequence = 0 ;
conn - > tx_sequence_data_size = 0 ;
conn - > rx_sequence = 0 ;
// fifoBuf_init(&conn->tx_fifo_buffer, conn->tx_buffer, PH_FIFO_BUFFER_SIZE);
// fifoBuf_init(&conn->rx_fifo_buffer, conn->rx_buffer, PH_FIFO_BUFFER_SIZE);
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_time_slots = 5 ;
uint32_t ms = 1280000ul / rfm22_getDatarate ( ) ;
if ( ms < 10 ) ms = 10 ;
else
if ( ms > 32000 ) ms = 32000 ;
conn - > tx_retry_time_slot_len = ms ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len * 4 + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len * 4 ;
conn - > tx_retry_counter = 0 ;
conn - > data_speed_timer = 0 ;
conn - > tx_data_speed_count = 0 ;
conn - > tx_data_speed = 0 ;
conn - > rx_data_speed_count = 0 ;
conn - > rx_data_speed = 0 ;
conn - > ping_time = 8000 + ( random32 % 100 ) * 10 ;
conn - > fast_ping_time = 600 + ( random32 % 50 ) * 10 ;
conn - > pinging = false ;
conn - > rx_not_ready_mode = false ;
conn - > ready_to_send_timer = - 1 ;
conn - > not_ready_timer = - 1 ;
// conn->send_encrypted = true;
// conn->send_encrypted = false;
conn - > rx_rssi_dBm = - 200 ;
conn - > rx_afc_Hz = 0 ;
if ( sn ! = 0 & & sn = = our_serial_number )
return - 2 ; // same as our own
if ( sn = = BROADCAST_ADDR )
{
return - 3 ;
}
if ( conn - > serial_number ! = 0 )
conn - > link_state = LINK_CONNECTING ;
return connection_index ;
2011-03-03 17:32:43 +01:00
}
2012-03-18 18:22:05 +01:00
// *****************************************************************************
// return a byte for the tx packet transmission.
//
// return value < 0 if no more bytes available, otherwise return byte to be sent
int16_t ph_TxDataByteCallback ( void )
{
return - 1 ;
}
// *************************************************************
// we are being given a block of received bytes
//
// return TRUE to continue current packet receive, otherwise return FALSE to halt current packet reception
bool ph_RxDataCallback ( void * data , uint8_t len )
{
return true ;
}
// *****************************************************************************
// transmit a packet
bool ph_sendPacket ( int connection_index , bool encrypt , uint8_t packet_type , bool send_immediately )
2011-01-13 09:45:18 +01:00
{
2012-03-18 18:22:05 +01:00
uint8_t key [ AES_BLOCK_SIZE ] ;
t_connection * conn = NULL ;
// ***********
t_encrypted_packet * encrypted_packet = ( t_encrypted_packet * ) & ph_tx_buffer ; // point to the tx buffer
t_unencrypted_packet * unencrypted_packet = ( t_unencrypted_packet * ) & ph_tx_buffer ; // point to the tx buffer
t_packet_header * header ;
uint8_t * data ;
uint16_t max_data_size ;
if ( encrypt )
{
header = ( t_packet_header * ) & encrypted_packet - > header ;
data = ( uint8_t * ) & encrypted_packet - > data ;
max_data_size = sizeof ( encrypted_packet - > data ) ;
}
else
{
header = ( t_packet_header * ) & unencrypted_packet - > header ;
data = ( uint8_t * ) & unencrypted_packet - > data ;
max_data_size = sizeof ( unencrypted_packet - > data ) ;
}
// ***********
if ( ! rfm22_txReady ( ) )
return false ;
if ( ( packet_type & PACKET_TYPE_MASK ) = = PACKET_TYPE_NONE )
return false ;
if ( connection_index > = PH_MAX_CONNECTIONS )
return false ;
if ( connection_index > = 0 )
conn = ( t_connection * ) & connection [ connection_index ] ;
else
return false ;
// ******************
// stuff
uint8_t pack_type = packet_type & PACKET_TYPE_MASK ;
bool data_packet = ( pack_type = = PACKET_TYPE_DATA | | pack_type = = PACKET_TYPE_NOTREADY ) ;
// ******************
// calculate how many user data bytes we are going to add to the packet
uint16_t data_size = 0 ;
if ( data_packet & & conn )
{ // we're adding user data to the packet
data_size = fifoBuf_getUsed ( & connection [ connection_index ] . tx_fifo_buffer ) ; // the number of data bytes waiting to be sent
if ( data_size > max_data_size )
data_size = max_data_size ;
if ( conn - > tx_sequence_data_size > 0 )
{ // we are re-sending data the same data
if ( data_size > conn - > tx_sequence_data_size )
data_size = conn - > tx_sequence_data_size ;
}
}
// ******************
// calculate the total packet size (including null data bytes if we have to add null data byte in AES encrypted packets)
uint32_t packet_size ;
if ( encrypt )
{
packet_size = AES_BLOCK_SIZE + sizeof ( t_packet_header ) + data_size ;
// total packet size must be a multiple of 'AES_BLOCK_SIZE' bytes - aes encryption works on 16-byte blocks
packet_size = ( packet_size + ( AES_BLOCK_SIZE - 1 ) ) & ~ ( AES_BLOCK_SIZE - 1 ) ;
}
else
{
packet_size = 1 + sizeof ( t_packet_header ) + data_size ;
}
// ******************
// construct the packets entire header
if ( encrypt )
{
memmove ( key , aes_key , sizeof ( key ) ) ; // fetch the encryption key
aes_encrypt_cbc_128 ( enc_cbc , key , NULL ) ; // help randomize the CBC bytes
// ensure the 1st byte is not zero - to indicate this packet is encrypted
while ( enc_cbc [ 0 ] = = 0 )
{
random32 = updateCRC32 ( random32 , 0xff ) ;
enc_cbc [ 0 ] ^ = random32 ;
}
memmove ( encrypted_packet - > cbc , enc_cbc , AES_BLOCK_SIZE ) ; // copy the AES CBC bytes into the packet
}
else
unencrypted_packet - > null_byte = 0 ; // packet is not encrypted
header - > source_id = our_serial_number ; // our serial number
// header->destination_id = BROADCAST_ADDR; // broadcast packet
header - > destination_id = conn - > serial_number ; // the other modems serial number
header - > type = packet_type ; // packet type
header - > tx_seq = conn - > tx_sequence ; // our TX sequence number
header - > rx_seq = conn - > rx_sequence ; // our RX sequence number
header - > data_size = data_size ; // the number of user data bytes in the packet
header - > crc = 0 ; // the CRC of the header and user data bytes
// ******************
// add the user data to the packet
if ( data_packet )
{ // we're adding user data to the packet
fifoBuf_getDataPeek ( & connection [ connection_index ] . tx_fifo_buffer , data , data_size ) ;
if ( encrypt )
{ // zero unused bytes
if ( data_size < max_data_size )
memset ( data + data_size , 0 , max_data_size - data_size ) ;
}
conn - > tx_sequence_data_size = data_size ; // remember how much data we are sending in this packet
}
// ******************
// complete the packet header by adding the CRC
if ( encrypt )
header - > crc = updateCRC32Data ( 0xffffffff , header , packet_size - AES_BLOCK_SIZE ) ;
else
header - > crc = updateCRC32Data ( 0xffffffff , header , packet_size - 1 ) ;
// ******************
// encrypt the packet
if ( encrypt )
{ // encrypt the packet .. 'AES_BLOCK_SIZE' bytes at a time
uint8_t * p = ( uint8_t * ) encrypted_packet ;
// encrypt the cbc
memmove ( key , aes_key , sizeof ( key ) ) ; // fetch the encryption key
aes_encrypt_cbc_128 ( p , key , NULL ) ; // encrypt block of data (the CBC bytes)
p + = AES_BLOCK_SIZE ;
// encrypt the rest of the packet
for ( uint16_t i = AES_BLOCK_SIZE ; i < packet_size ; i + = AES_BLOCK_SIZE )
{
memmove ( key , aes_key , sizeof ( key ) ) ; // fetch the encryption key
aes_encrypt_cbc_128 ( p , key , enc_cbc ) ; // encrypt block of data
p + = AES_BLOCK_SIZE ;
}
}
// ******************
// send the packet
int32_t res = rfm22_sendData ( & ph_tx_buffer , packet_size , send_immediately ) ;
// ******************
if ( data_size > 0 & & conn - > tx_retry_counter = = 0 )
conn - > tx_data_speed_count + = data_size * 8 ; // + the number of data bits we just sent .. used for calculating the transmit data rate
// ******************
// debug stuff
# if defined(PACKET_DEBUG)
DEBUG_PRINTF ( " T-PACK " ) ;
switch ( pack_type )
{
case PACKET_TYPE_NONE : DEBUG_PRINTF ( " none " ) ; break ;
case PACKET_TYPE_CONNECT : DEBUG_PRINTF ( " connect " ) ; break ;
case PACKET_TYPE_CONNECT_ACK : DEBUG_PRINTF ( " connect_ack " ) ; break ;
case PACKET_TYPE_DISCONNECT : DEBUG_PRINTF ( " disconnect " ) ; break ;
case PACKET_TYPE_DATA : DEBUG_PRINTF ( " data " ) ; break ;
case PACKET_TYPE_DATA_ACK : DEBUG_PRINTF ( " data_ack " ) ; break ;
case PACKET_TYPE_READY : DEBUG_PRINTF ( " ready " ) ; break ;
case PACKET_TYPE_READY_ACK : DEBUG_PRINTF ( " ready_ack " ) ; break ;
case PACKET_TYPE_NOTREADY : DEBUG_PRINTF ( " notready " ) ; break ;
case PACKET_TYPE_NOTREADY_ACK : DEBUG_PRINTF ( " notready_ack " ) ; break ;
case PACKET_TYPE_DATARATE : DEBUG_PRINTF ( " datarate " ) ; break ;
case PACKET_TYPE_DATARATE_ACK : DEBUG_PRINTF ( " datarate_ack " ) ; break ;
case PACKET_TYPE_PING : DEBUG_PRINTF ( " ping " ) ; break ;
case PACKET_TYPE_PONG : DEBUG_PRINTF ( " pong " ) ; break ;
case PACKET_TYPE_ADJUST_TX_PWR : DEBUG_PRINTF ( " PACKET_TYPE_ADJUST_TX_PWR " ) ; break ;
case PACKET_TYPE_ADJUST_TX_PWR_ACK : DEBUG_PRINTF ( " PACKET_TYPE_ADJUST_TX_PWR_ACK " ) ; break ;
default : DEBUG_PRINTF ( " UNKNOWN [%d] " , pack_type ) ; break ;
}
DEBUG_PRINTF ( " tseq:%d rseq:%d " , conn - > tx_sequence , conn - > rx_sequence ) ;
DEBUG_PRINTF ( " drate:%dbps " , conn - > tx_data_speed ) ;
if ( data_size > 0 ) DEBUG_PRINTF ( " data_size:%d " , data_size ) ;
if ( conn - > tx_retry_counter > 0 ) DEBUG_PRINTF ( " retry:%d " , conn - > tx_retry_counter ) ;
DEBUG_PRINTF ( " \r \n " ) ;
# endif
// ******************
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
switch ( pack_type )
{
case PACKET_TYPE_CONNECT :
case PACKET_TYPE_DISCONNECT :
case PACKET_TYPE_DATA :
case PACKET_TYPE_READY :
case PACKET_TYPE_NOTREADY :
case PACKET_TYPE_DATARATE :
case PACKET_TYPE_PING :
case PACKET_TYPE_ADJUST_TX_PWR :
if ( conn - > tx_retry_counter < 0xffff )
conn - > tx_retry_counter + + ;
break ;
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
case PACKET_TYPE_CONNECT_ACK :
case PACKET_TYPE_DATA_ACK :
case PACKET_TYPE_READY_ACK :
case PACKET_TYPE_NOTREADY_ACK :
case PACKET_TYPE_DATARATE_ACK :
case PACKET_TYPE_PONG :
case PACKET_TYPE_ADJUST_TX_PWR_ACK :
break ;
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
case PACKET_TYPE_NONE :
break ;
}
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
return ( res > = packet_size ) ;
}
// *****************************************************************************
void ph_processPacket2 ( bool was_encrypted , t_packet_header * header , uint8_t * data )
{ // process the received decrypted error-free packet
USB_LED_TOGGLE ; // TEST ONLY
// ***********
// fetch the data compressed bit
bool compressed_data = ( header - > type & PACKET_TYPE_DATA_COMP_BIT ) ! = 0 ;
// fetch the packet type
uint8_t packet_type = header - > type & PACKET_TYPE_MASK ;
// fetch the number of data bytes in the packet
uint16_t data_size = header - > data_size ;
// update the ramdon number
random32 = updateCRC32 ( random32 , 0xff ) ;
// *********************
// debug stuff
/*
# if defined(PACKET_DEBUG)
if ( data_size > 0 )
{
DEBUG_PRINTF ( " rx packet: " ) ;
for ( uint16_t i = 0 ; i < data_size ; i + + )
DEBUG_PRINTF ( " %u " , data [ i ] ) ;
DEBUG_PRINTF ( " \r \n " ) ;
2011-01-13 09:45:18 +01:00
}
2012-03-18 18:22:05 +01:00
# endif
*/
// ***********
// debug stuff
# if defined(PACKET_DEBUG)
DEBUG_PRINTF ( " R-PACK " ) ;
switch ( packet_type )
{
case PACKET_TYPE_NONE : DEBUG_PRINTF ( " none " ) ; break ;
case PACKET_TYPE_CONNECT : DEBUG_PRINTF ( " connect " ) ; break ;
case PACKET_TYPE_CONNECT_ACK : DEBUG_PRINTF ( " connect_ack " ) ; break ;
case PACKET_TYPE_DISCONNECT : DEBUG_PRINTF ( " disconnect " ) ; break ;
case PACKET_TYPE_DATA : DEBUG_PRINTF ( " data " ) ; break ;
case PACKET_TYPE_DATA_ACK : DEBUG_PRINTF ( " data_ack " ) ; break ;
case PACKET_TYPE_READY : DEBUG_PRINTF ( " ready " ) ; break ;
case PACKET_TYPE_READY_ACK : DEBUG_PRINTF ( " ready_ack " ) ; break ;
case PACKET_TYPE_NOTREADY : DEBUG_PRINTF ( " notready " ) ; break ;
case PACKET_TYPE_NOTREADY_ACK : DEBUG_PRINTF ( " notready_ack " ) ; break ;
case PACKET_TYPE_DATARATE : DEBUG_PRINTF ( " datarate " ) ; break ;
case PACKET_TYPE_DATARATE_ACK : DEBUG_PRINTF ( " datarate_ack " ) ; break ;
case PACKET_TYPE_PING : DEBUG_PRINTF ( " ping " ) ; break ;
case PACKET_TYPE_PONG : DEBUG_PRINTF ( " pong " ) ; break ;
case PACKET_TYPE_ADJUST_TX_PWR : DEBUG_PRINTF ( " PACKET_TYPE_ADJUST_TX_PWR " ) ; break ;
case PACKET_TYPE_ADJUST_TX_PWR_ACK : DEBUG_PRINTF ( " PACKET_TYPE_ADJUST_TX_PWR_ACK " ) ; break ;
default : DEBUG_PRINTF ( " UNKNOWN [%d] " , packet_type ) ; break ;
}
DEBUG_PRINTF ( " tseq-%d rseq-%d " , header - > tx_seq , header - > rx_seq ) ;
// DEBUG_PRINTF(" drate:%dbps", conn->rx_data_speed);
if ( data_size > 0 ) DEBUG_PRINTF ( " data_size:%d " , data_size ) ;
DEBUG_PRINTF ( " %ddBm " , rx_rssi_dBm ) ;
DEBUG_PRINTF ( " %dHz " , rx_afc_Hz ) ;
DEBUG_PRINTF ( " \r \n " ) ;
# endif
// *********************
if ( header - > source_id = = our_serial_number )
return ; // it's our own packet .. ignore it
if ( header - > destination_id = = BROADCAST_ADDR )
{ // it's a broadcast packet
// todo:
return ;
}
if ( header - > destination_id ! = our_serial_number )
return ; // the packet is not meant for us
// *********************
// find out which remote connection this packet is from
int connection_index = 0 ;
while ( connection_index < PH_MAX_CONNECTIONS )
{
uint32_t sn = connection [ connection_index ] . serial_number ;
if ( sn ! = 0 )
{ // connection used
if ( header - > source_id = = sn )
break ; // found it
}
connection_index + + ;
}
if ( connection_index > = PH_MAX_CONNECTIONS )
{ // the packet is from an unknown source ID (unknown modem)
if ( packet_type ! = PACKET_TYPE_NONE )
{ // send a disconnect packet back to them
// ph_sendPacket(-1, was_encrypted, PACKET_TYPE_DISCONNECT, true);
}
return ;
}
t_connection * conn = & connection [ connection_index ] ;
// ***********
conn - > rx_rssi_dBm = rx_rssi_dBm ; // remember the packets signal strength
conn - > rx_afc_Hz = rx_afc_Hz ; // remember the packets frequency offset
// ***********
// decompress the data
if ( compressed_data & & data_size > 0 )
{
// todo:
}
// ***********
if ( packet_type = = PACKET_TYPE_NONE )
return ;
if ( packet_type = = PACKET_TYPE_DISCONNECT )
{
conn - > link_state = LINK_DISCONNECTED ;
LINK_LED_OFF ;
return ;
}
if ( packet_type = = PACKET_TYPE_CONNECT )
{
LINK_LED_ON ;
// fifoBuf_init(&conn->tx_fifo_buffer, conn->tx_buffer, PH_FIFO_BUFFER_SIZE);
// fifoBuf_init(&conn->rx_fifo_buffer, conn->rx_buffer, PH_FIFO_BUFFER_SIZE);
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_counter = 0 ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len ;
conn - > rx_sequence = header - > tx_seq ;
conn - > tx_sequence = 0 ;
conn - > tx_sequence_data_size = 0 ;
conn - > data_speed_timer = 0 ;
conn - > tx_data_speed_count = 0 ;
conn - > tx_data_speed = 0 ;
conn - > rx_data_speed_count = 0 ;
conn - > rx_data_speed = 0 ;
conn - > ping_time = 8000 + ( random32 % 100 ) * 10 ;
conn - > fast_ping_time = 600 + ( random32 % 50 ) * 10 ;
conn - > pinging = false ;
conn - > rx_not_ready_mode = false ;
conn - > ready_to_send_timer = - 1 ;
conn - > not_ready_timer = - 1 ;
conn - > link_state = LINK_CONNECTED ;
// send an ack back
if ( ph_sendPacket ( connection_index , conn - > send_encrypted , PACKET_TYPE_CONNECT_ACK , true ) )
{
conn - > tx_packet_timer = 0 ;
}
return ;
}
if ( packet_type = = PACKET_TYPE_CONNECT_ACK )
{
LINK_LED_ON ;
if ( conn - > link_state ! = LINK_CONNECTING )
{ // reset the link
ph_set_remote_serial_number ( connection_index , conn - > serial_number ) ;
return ;
}
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_counter = 0 ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len ;
conn - > rx_sequence = header - > tx_seq ;
conn - > tx_sequence = 0 ;
conn - > tx_sequence_data_size = 0 ;
conn - > data_speed_timer = 0 ;
conn - > tx_data_speed_count = 0 ;
conn - > tx_data_speed = 0 ;
conn - > rx_data_speed_count = 0 ;
conn - > rx_data_speed = 0 ;
conn - > ping_time = 8000 + ( random32 % 100 ) * 10 ;
conn - > fast_ping_time = 600 + ( random32 % 50 ) * 10 ;
conn - > pinging = false ;
conn - > rx_not_ready_mode = false ;
conn - > ready_to_send_timer = - 1 ;
conn - > not_ready_timer = - 1 ;
conn - > link_state = LINK_CONNECTED ;
return ;
}
if ( conn - > link_state = = LINK_CONNECTING )
{ // we are trying to connect to them .. reply with a connect request packet
if ( ph_sendPacket ( connection_index , conn - > send_encrypted , PACKET_TYPE_CONNECT , true ) )
{
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len * 4 + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len * 4 ;
}
return ;
}
if ( conn - > link_state ! = LINK_CONNECTED )
{ // they have sent us a packet when we are not in a connected state - start a connection
ph_startConnect ( connection_index , conn - > serial_number ) ;
return ;
}
// check to make sure it's a wanted packet type
switch ( packet_type )
{
case PACKET_TYPE_DATA :
case PACKET_TYPE_DATA_ACK :
case PACKET_TYPE_READY :
case PACKET_TYPE_READY_ACK :
case PACKET_TYPE_NOTREADY :
case PACKET_TYPE_NOTREADY_ACK :
case PACKET_TYPE_DATARATE :
case PACKET_TYPE_DATARATE_ACK :
case PACKET_TYPE_PING :
case PACKET_TYPE_PONG :
case PACKET_TYPE_ADJUST_TX_PWR :
case PACKET_TYPE_ADJUST_TX_PWR_ACK :
break ;
default :
return ;
}
if ( ( conn - > tx_sequence_data_size > 0 ) & & ( header - > rx_seq = = ( uint8_t ) ( conn - > tx_sequence + 1 ) ) )
{ // they received our last data packet
// remove the data we have sent and they have acked
fifoBuf_removeData ( & conn - > tx_fifo_buffer , conn - > tx_sequence_data_size ) ;
conn - > tx_sequence + + ;
conn - > tx_retry_counter = 0 ;
conn - > tx_sequence_data_size = 0 ;
conn - > not_ready_timer = - 1 ; // stop timer
}
uint16_t size = fifoBuf_getUsed ( & conn - > tx_fifo_buffer ) ; // the size of data waiting to be sent
if ( packet_type = = PACKET_TYPE_DATA | | packet_type = = PACKET_TYPE_DATA_ACK )
{
if ( packet_type = = PACKET_TYPE_DATA & & header - > tx_seq = = conn - > rx_sequence )
{ // the packet number is what we expected
if ( data_size > 0 )
{ // save the data
conn - > rx_data_speed_count + = data_size * 8 ; // + the number of data bits we just received
uint16_t num = fifoBuf_getFree ( & conn - > rx_fifo_buffer ) ;
if ( num < data_size )
{ // error .. we don't have enough space left in our fifo buffer to save the data .. discard it and tell them to hold off a sec
// conn->rx_not_ready_mode = true;
}
else
{ // save the received data into our fifo buffer
fifoBuf_putData ( & conn - > rx_fifo_buffer , data , data_size ) ;
conn - > rx_sequence + + ;
conn - > rx_not_ready_mode = false ;
}
}
}
if ( size > = 200 | | ( conn - > ready_to_send_timer > = 10 & & size > 0 ) | | ( conn - > tx_sequence_data_size > 0 & & size > 0 ) )
{ // send data
uint8_t pack_type = PACKET_TYPE_DATA ;
if ( conn - > rx_not_ready_mode )
pack_type = PACKET_TYPE_NOTREADY ;
if ( ph_sendPacket ( connection_index , conn - > send_encrypted , pack_type , true ) )
{
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len ;
return ;
}
}
if ( packet_type = = PACKET_TYPE_DATA )
{ // send an ack back
uint8_t pack_type = PACKET_TYPE_DATA_ACK ;
if ( conn - > rx_not_ready_mode )
pack_type = PACKET_TYPE_NOTREADY_ACK ;
if ( ph_sendPacket ( connection_index , conn - > send_encrypted , pack_type , true ) )
{
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len ;
return ;
}
}
return ;
}
if ( packet_type = = PACKET_TYPE_READY )
{
conn - > not_ready_timer = - 1 ; // stop timer
// send an ack back
if ( ph_sendPacket ( connection_index , conn - > send_encrypted , PACKET_TYPE_READY_ACK , true ) )
{
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len * 4 + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len * 4 ;
return ;
}
return ;
}
if ( packet_type = = PACKET_TYPE_READY_ACK )
{
conn - > rx_not_ready_mode = false ;
return ;
}
if ( packet_type = = PACKET_TYPE_NOTREADY )
{
// conn->not_ready_timer = 0; // start timer
if ( header - > tx_seq = = conn - > rx_sequence )
{ // the packet number is what we expected
if ( data_size > 0 )
{ // save the data
conn - > rx_data_speed_count + = data_size * 8 ; // + the number of data bits we just received
uint16_t num = fifoBuf_getFree ( & conn - > rx_fifo_buffer ) ;
if ( num < data_size )
{ // error .. we don't have enough space left in our fifo buffer to save the data .. discard it and tell them to hold off a sec
// conn->rx_not_ready_mode = true;
}
else
{ // save the received data into our fifo buffer
fifoBuf_putData ( & conn - > rx_fifo_buffer , data , data_size ) ;
conn - > rx_sequence + + ;
conn - > rx_not_ready_mode = false ;
}
}
}
// send an ack back
if ( ph_sendPacket ( connection_index , conn - > send_encrypted , PACKET_TYPE_NOTREADY_ACK , true ) )
{
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len * 4 + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len * 4 ;
return ;
}
return ;
}
if ( packet_type = = PACKET_TYPE_NOTREADY_ACK )
{
return ;
}
if ( packet_type = = PACKET_TYPE_PING )
{ // send a pong back
if ( ph_sendPacket ( connection_index , conn - > send_encrypted , PACKET_TYPE_PONG , true ) )
{
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len ;
}
return ;
}
if ( packet_type = = PACKET_TYPE_PONG )
{
if ( conn - > pinging )
{
conn - > pinging = false ;
conn - > tx_retry_counter = 0 ;
}
return ;
}
if ( packet_type = = PACKET_TYPE_DATARATE )
{
// send an ack back
if ( ph_sendPacket ( connection_index , conn - > send_encrypted , PACKET_TYPE_DATARATE_ACK , true ) )
{
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len ;
}
return ;
}
if ( packet_type = = PACKET_TYPE_DATARATE_ACK )
{
return ;
}
if ( packet_type = = PACKET_TYPE_ADJUST_TX_PWR )
{
// send an ack back
if ( ph_sendPacket ( connection_index , conn - > send_encrypted , PACKET_TYPE_ADJUST_TX_PWR_ACK , true ) )
{
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len ;
}
return ;
}
if ( packet_type = = PACKET_TYPE_ADJUST_TX_PWR_ACK )
{
return ;
}
// *********************
2011-01-13 09:45:18 +01:00
}
2012-03-18 18:22:05 +01:00
void ph_processRxPacket ( void )
2011-01-13 09:45:18 +01:00
{
2012-03-18 18:22:05 +01:00
uint32_t crc1 , crc2 ;
uint8_t key [ AES_BLOCK_SIZE ] ;
register uint8_t * p ;
// ***********
// fetch the received packet
uint16_t packet_size = rfm22_receivedLength ( ) ;
if ( packet_size = = 0 )
return ; // nothing received
if ( packet_size > sizeof ( ph_rx_buffer ) )
{ // packet too big .. discard it
rfm22_receivedDone ( ) ;
return ;
}
rx_rssi_dBm = rfm22_receivedRSSI ( ) ; // fetch the packets signal stength
rx_afc_Hz = rfm22_receivedAFCHz ( ) ; // fetch the packets frequency offset
// copy the received packet into our own buffer
memmove ( ph_rx_buffer , rfm22_receivedPointer ( ) , packet_size ) ;
rfm22_receivedDone ( ) ; // the received packet has been saved
// *********************
// if the 1st byte in the packet is not zero, then the packet is encrypted
bool encrypted = ( ph_rx_buffer [ 0 ] ! = 0 ) ;
// ***********
t_encrypted_packet * encrypted_packet = ( t_encrypted_packet * ) & ph_rx_buffer ; // point to the rx buffer
t_unencrypted_packet * unencrypted_packet = ( t_unencrypted_packet * ) & ph_rx_buffer ; // point to the rx buffer
t_packet_header * header ;
uint8_t * data ;
uint16_t min_packet_size ;
uint16_t max_data_size ;
if ( encrypted )
{
header = ( t_packet_header * ) & encrypted_packet - > header ;
data = ( uint8_t * ) & encrypted_packet - > data ;
min_packet_size = AES_BLOCK_SIZE + sizeof ( t_packet_header ) ;
max_data_size = sizeof ( encrypted_packet - > data ) ;
}
else
{
header = ( t_packet_header * ) & unencrypted_packet - > header ;
data = ( uint8_t * ) & unencrypted_packet - > data ;
min_packet_size = 1 + sizeof ( t_packet_header ) ;
max_data_size = sizeof ( unencrypted_packet - > data ) ;
}
if ( packet_size < min_packet_size )
{ // packet too small .. discard it
return ;
}
random32 = updateCRC32 ( random32 ^ header - > crc , 0xff ) ; // help randomize the random number
// *********************
// help to randomize the tx aes cbc bytes by using the received packet
p = ( uint8_t * ) & ph_rx_buffer ;
for ( uint16_t i = 0 ; i < packet_size ; i + = AES_BLOCK_SIZE )
{
for ( int j = AES_BLOCK_SIZE - 1 ; j > = 0 ; j - - )
enc_cbc [ j ] ^ = * p + + ;
}
// *********************
// check the packet size
if ( encrypted )
{
if ( ( packet_size & ( AES_BLOCK_SIZE - 1 ) ) ! = 0 )
return ; // packet must be a multiple of 'AES_BLOCK_SIZE' bytes in length - for the aes decryption
}
// *********************
// decrypt the packet
if ( encrypted )
{
p = ( uint8_t * ) encrypted_packet ; // point to the received packet
// decrypt the cbc
memmove ( key , ( void * ) dec_aes_key , sizeof ( key ) ) ; // fetch the decryption key
aes_decrypt_cbc_128 ( p , key , NULL ) ; // decrypt the cbc bytes
p + = AES_BLOCK_SIZE ;
// decrypt the rest of the packet
for ( uint16_t i = AES_BLOCK_SIZE ; i < packet_size ; i + = AES_BLOCK_SIZE )
{
memmove ( key , ( void * ) dec_aes_key , sizeof ( key ) ) ; // fetch the decryption key
aes_decrypt_cbc_128 ( p , key , ( void * ) encrypted_packet - > cbc ) ;
p + = AES_BLOCK_SIZE ;
}
}
// *********************
# if defined(PACKET_DEBUG)
DEBUG_PRINTF ( " rx packet: " ) ;
DEBUG_PRINTF ( " %s " , encrypted ? " encrypted " : " unencrypted " ) ;
if ( encrypted )
{
for ( int i = 0 ; i < AES_BLOCK_SIZE ; i + + )
DEBUG_PRINTF ( " %02X " , encrypted_packet - > cbc [ i ] ) ;
}
DEBUG_PRINTF ( " %08X %08X %u %u %u %u %08X \r \n " ,
header - > source_id ,
header - > destination_id ,
header - > type ,
header - > tx_seq ,
header - > rx_seq ,
header - > data_size ,
header - > crc ) ;
if ( header - > data_size > 0 )
{
DEBUG_PRINTF ( " rx packet [%u]: " , header - > data_size ) ;
for ( int i = 0 ; i < header - > data_size ; i + + )
DEBUG_PRINTF ( " %02X " , data [ i ] ) ;
DEBUG_PRINTF ( " \r \n " ) ;
}
# endif
// *********************
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
uint32_t data_size = header - > data_size ;
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
if ( packet_size < ( min_packet_size + data_size ) )
return ; // packet too small
# if defined(PACKET_DEBUG)
// DEBUG_PRINTF("rx packet size: %d\r\n", packet_size);
# endif
// *********************
// check the packet is error free
crc1 = header - > crc ;
header - > crc = 0 ;
if ( encrypted )
crc2 = updateCRC32Data ( 0xffffffff , header , packet_size - AES_BLOCK_SIZE ) ;
else
crc2 = updateCRC32Data ( 0xffffffff , header , packet_size - 1 ) ;
if ( crc1 ! = crc2 )
{ // corrupt packet
# if defined(PACKET_DEBUG)
if ( encrypted )
DEBUG_PRINTF ( " ENC-R-PACK corrupt %08X %08X \r \n " , crc1 , crc2 ) ;
else
DEBUG_PRINTF ( " R-PACK corrupt %08X %08X \r \n " , crc1 , crc2 ) ;
# endif
return ;
}
// *********************
// process the data
ph_processPacket2 ( encrypted , header , data ) ;
// *********************
2011-01-13 09:45:18 +01:00
}
2012-03-18 18:22:05 +01:00
// *****************************************************************************
// do all the link/packet handling stuff - request connection/disconnection, send data, acks etc
void ph_processLinks ( int connection_index )
2011-01-13 09:45:18 +01:00
{
2012-03-18 18:22:05 +01:00
if ( connection_index < 0 | | connection_index > = PH_MAX_CONNECTIONS )
return ;
random32 = updateCRC32 ( random32 , 0xff ) ;
t_connection * conn = & connection [ connection_index ] ;
bool canTx = ( ! rfm22_transmitting ( ) & & rfm22_channelIsClear ( ) ) ; // TRUE is we can transmit
bool timeToRetry = ( rfm22_txReady ( ) & & conn - > tx_packet_timer > = conn - > tx_retry_time ) ;
bool tomanyRetries = ( conn - > tx_retry_counter > = RETRY_RECONNECT_COUNT ) ;
if ( conn - > tx_retry_counter > 3 )
conn - > rx_rssi_dBm = - 200 ;
switch ( conn - > link_state )
{
case LINK_DISCONNECTED :
if ( ! canTx )
{
conn - > tx_packet_timer = 0 ;
break ;
}
if ( ! rfm22_txReady ( ) | | conn - > tx_packet_timer < 60000 )
break ;
if ( our_serial_number ! = 0 & & conn - > serial_number ! = 0 )
{ // try to reconnect with the remote modem
ph_startConnect ( connection_index , conn - > serial_number ) ;
break ;
}
break ;
case LINK_CONNECTING :
if ( ! canTx )
{
conn - > tx_packet_timer = 0 ;
break ;
}
if ( ! timeToRetry )
break ;
if ( ph_sendPacket ( connection_index , conn - > send_encrypted , PACKET_TYPE_CONNECT , false ) )
{
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len * 4 + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len * 4 ;
break ;
}
break ;
case LINK_CONNECTED :
if ( ! canTx )
{
conn - > tx_packet_timer = 0 ;
break ;
}
if ( ! timeToRetry )
break ;
if ( tomanyRetries )
{ // reset the link if we have sent tomany retries
ph_startConnect ( connection_index , conn - > serial_number ) ;
break ;
}
if ( conn - > pinging )
{ // we are trying to ping them
if ( ph_sendPacket ( connection_index , conn - > send_encrypted , PACKET_TYPE_PING , false ) )
{
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len * 4 + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len * 4 ;
}
break ;
}
uint16_t ping_time = conn - > ping_time ;
if ( fast_ping ) ping_time = conn - > fast_ping_time ;
if ( conn - > tx_packet_timer > = ping_time )
{ // start pinging
if ( ph_sendPacket ( connection_index , conn - > send_encrypted , PACKET_TYPE_PING , false ) )
{
conn - > ping_time = 8000 + ( random32 % 100 ) * 10 ;
conn - > fast_ping_time = 600 + ( random32 % 50 ) * 10 ;
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len * 4 + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len * 4 ;
conn - > pinging = true ;
}
break ;
}
// ***********
// exit rx not ready mode if we have space in our rx buffer for more data
/*
if ( conn - > rx_not_ready_mode )
{
uint16_t size = fifoBuf_getFree ( & conn - > rx_fifo_buffer ) ;
if ( size > = conn - > rx_fifo_buffer . buf_size / 6 )
{ // leave 'rx not ready' mode
if ( ph_sendPacket ( connection_index , conn - > send_encrypted , PACKET_TYPE_READY , false ) )
{
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len ;
break ;
}
}
}
*/
// ***********
// send data packets
// if (conn->not_ready_timer < 0)
{
uint16_t size = fifoBuf_getUsed ( & conn - > tx_fifo_buffer ) ;
if ( size = = 0 )
conn - > ready_to_send_timer = - 1 ; // no data to send
else
if ( conn - > ready_to_send_timer < 0 )
conn - > ready_to_send_timer = 0 ; // start timer
if ( size > = 200 | | ( conn - > ready_to_send_timer > = saved_settings . rts_time & & size > 0 ) | | ( conn - > tx_sequence_data_size > 0 & & size > 0 ) )
{ // send data
uint8_t pack_type = PACKET_TYPE_DATA ;
if ( conn - > rx_not_ready_mode )
pack_type = PACKET_TYPE_NOTREADY ;
if ( ph_sendPacket ( connection_index , conn - > send_encrypted , pack_type , false ) )
{
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len ;
}
break ;
}
}
// ***********
break ;
default : // we should never end up here - maybe we should do a reboot?
conn - > link_state = LINK_DISCONNECTED ;
/*
// disable all interrupts
PIOS_IRQ_Disable ( ) ;
// turn off all leds
USB_LED_OFF ;
LINK_LED_OFF ;
RX_LED_OFF ;
TX_LED_OFF ;
PIOS_SYS_Reset ( ) ;
while ( 1 ) ;
*/
break ;
}
2011-01-13 09:45:18 +01:00
}
2012-03-18 18:22:05 +01:00
// *****************************************************************************
void ph_setFastPing ( bool fast )
2011-01-13 09:45:18 +01:00
{
2012-03-18 18:22:05 +01:00
fast_ping = fast ;
}
// *****************************************************************************
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
uint8_t ph_getCurrentLinkState ( const int connection_index )
{
if ( connection_index < 0 | | connection_index > = PH_MAX_CONNECTIONS )
return 0 ;
return connection [ connection_index ] . link_state ;
}
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
// *****************************************************************************
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
uint16_t ph_getRetries ( const int connection_index )
{
if ( connection_index < 0 | | connection_index > = PH_MAX_CONNECTIONS )
return 0 ;
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
return connection [ connection_index ] . tx_retry_counter ;
2011-01-13 09:45:18 +01:00
}
2012-03-18 18:22:05 +01:00
// *****************************************************************************
int16_t ph_getLastRSSI ( const int connection_index )
2011-02-02 12:44:23 +01:00
{
2012-03-18 18:22:05 +01:00
if ( connection_index < 0 | | connection_index > = PH_MAX_CONNECTIONS )
return 0 ;
2011-02-03 14:12:30 +01:00
2012-03-18 18:22:05 +01:00
return connection [ connection_index ] . rx_rssi_dBm ;
2011-02-02 12:44:23 +01:00
}
2012-03-18 18:22:05 +01:00
int32_t ph_getLastAFC ( const int connection_index )
{
if ( connection_index < 0 | | connection_index > = PH_MAX_CONNECTIONS )
return 0 ;
return connection [ connection_index ] . rx_afc_Hz ;
}
// *****************************************************************************
// set/get the carrier frequency
void ph_setNominalCarrierFrequency ( uint32_t frequency_hz )
{
rfm22_setNominalCarrierFrequency ( frequency_hz ) ;
}
uint32_t ph_getNominalCarrierFrequency ( void )
{
return rfm22_getNominalCarrierFrequency ( ) ;
}
// *****************************************************************************
// set/get the RF datarate
void ph_setDatarate ( uint32_t datarate_bps )
{
rfm22_setDatarate ( datarate_bps , TRUE ) ;
uint32_t ms = 1280000ul / rfm22_getDatarate ( ) ;
if ( ms < 10 ) ms = 10 ;
else
if ( ms > 32000 ) ms = 32000 ;
for ( int i = 0 ; i < PH_MAX_CONNECTIONS ; i + + )
connection [ i ] . tx_retry_time_slot_len = ms ;
}
uint32_t ph_getDatarate ( void )
{
return rfm22_getDatarate ( ) ;
}
// *****************************************************************************
void ph_setTxPower ( uint8_t tx_power )
{
rfm22_setTxPower ( tx_power ) ;
}
uint8_t ph_getTxPower ( void )
{
return rfm22_getTxPower ( ) ;
}
// *****************************************************************************
// set the AES encryption key
void ph_set_AES128_key ( const void * key )
{
if ( ! key )
return ;
memmove ( aes_key , key , sizeof ( aes_key ) ) ;
// create the AES decryption key
aes_decrypt_key_128_create ( aes_key , ( void * ) & dec_aes_key ) ;
}
// *****************************************************************************
int ph_set_remote_serial_number ( int connection_index , uint32_t sn )
{
random32 = updateCRC32 ( random32 , 0xff ) ;
if ( ph_startConnect ( connection_index , sn ) > = 0 )
{
t_connection * conn = & connection [ connection_index ] ;
// wipe any user data present in the buffers
fifoBuf_init ( & conn - > tx_fifo_buffer , conn - > tx_buffer , PH_FIFO_BUFFER_SIZE ) ;
fifoBuf_init ( & conn - > rx_fifo_buffer , conn - > rx_buffer , PH_FIFO_BUFFER_SIZE ) ;
return connection_index ;
}
return - 4 ;
}
void ph_set_remote_encryption ( int connection_index , bool enabled , const void * key )
{
if ( connection_index < 0 | | connection_index > = PH_MAX_CONNECTIONS )
return ;
ph_set_AES128_key ( key ) ;
connection [ connection_index ] . send_encrypted = enabled ;
}
// *****************************************************************************
// can be called from an interrupt if you wish.
// call this once every ms
void ph_1ms_tick ( void )
2011-02-06 11:55:08 +01:00
{
2012-03-18 18:22:05 +01:00
if ( booting ) return ;
if ( saved_settings . mode = = MODE_NORMAL )
{
// help randomize the encryptor cbc bytes
register uint32_t * cbc = ( uint32_t * ) & enc_cbc ;
for ( int i = 0 ; i < sizeof ( enc_cbc ) / 4 ; i + + )
{
random32 = updateCRC32 ( random32 , 0xff ) ;
* cbc + + ^ = random32 ;
}
for ( int i = 0 ; i < PH_MAX_CONNECTIONS ; i + + )
{
t_connection * conn = & connection [ i ] ;
if ( conn - > tx_packet_timer < 0xffff )
conn - > tx_packet_timer + + ;
2011-02-06 11:55:08 +01:00
2012-03-18 18:22:05 +01:00
if ( conn - > link_state = = LINK_CONNECTED )
{ // we are connected
2011-02-06 11:55:08 +01:00
2012-03-18 18:22:05 +01:00
if ( conn - > ready_to_send_timer > = 0 & & conn - > ready_to_send_timer < 0x7fff )
conn - > ready_to_send_timer + + ;
2011-02-06 11:55:08 +01:00
2012-03-18 18:22:05 +01:00
if ( conn - > not_ready_timer > = 0 & & conn - > not_ready_timer < 0x7fffffff )
conn - > not_ready_timer + + ;
2011-02-06 11:55:08 +01:00
2012-03-18 18:22:05 +01:00
if ( conn - > data_speed_timer < 0xffff )
{
if ( + + conn - > data_speed_timer > = 1000 )
{ // 1 second gone by
conn - > data_speed_timer = 0 ;
conn - > tx_data_speed = ( conn - > tx_data_speed + conn - > tx_data_speed_count ) > > 1 ;
conn - > tx_data_speed_count = 0 ;
conn - > rx_data_speed = ( conn - > rx_data_speed + conn - > rx_data_speed_count ) > > 1 ;
conn - > rx_data_speed_count = 0 ;
}
}
}
else
{ // we are not connected
if ( conn - > data_speed_timer ) conn - > data_speed_timer = 0 ;
if ( conn - > tx_data_speed_count ) conn - > tx_data_speed_count = 0 ;
if ( conn - > tx_data_speed ) conn - > tx_data_speed = 0 ;
if ( conn - > rx_data_speed_count ) conn - > rx_data_speed_count = 0 ;
if ( conn - > rx_data_speed ) conn - > rx_data_speed = 0 ;
}
}
}
}
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
// *****************************************************************************
// call this as often as possible - not from an interrupt
void ph_process ( void )
{
if ( booting ) return ;
2011-03-04 09:34:44 +01:00
2012-03-18 18:22:05 +01:00
if ( saved_settings . mode = = MODE_NORMAL )
{
ph_processRxPacket ( ) ;
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
for ( int i = 0 ; i < PH_MAX_CONNECTIONS ; i + + )
ph_processLinks ( i ) ;
2011-02-06 11:55:08 +01:00
}
2012-03-18 18:22:05 +01:00
else
{
2011-02-06 11:55:08 +01:00
2012-03-18 18:22:05 +01:00
}
2011-01-13 09:45:18 +01:00
}
2012-03-18 18:22:05 +01:00
// *****************************************************************************
void ph_disconnectAll ( void )
2011-01-13 09:45:18 +01:00
{
2012-03-18 18:22:05 +01:00
for ( int i = 0 ; i < PH_MAX_CONNECTIONS ; i + + )
{
random32 = updateCRC32 ( random32 , 0xff ) ;
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
t_connection * conn = & connection [ i ] ;
2011-02-03 12:31:34 +01:00
2012-03-18 18:22:05 +01:00
conn - > serial_number = 0 ;
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
conn - > tx_sequence = 0 ;
conn - > tx_sequence_data_size = 0 ;
conn - > rx_sequence = 0 ;
fifoBuf_init ( & conn - > tx_fifo_buffer , conn - > tx_buffer , PH_FIFO_BUFFER_SIZE ) ;
fifoBuf_init ( & conn - > rx_fifo_buffer , conn - > rx_buffer , PH_FIFO_BUFFER_SIZE ) ;
conn - > link_state = LINK_DISCONNECTED ;
conn - > tx_packet_timer = 0 ;
conn - > tx_retry_time_slots = 5 ;
conn - > tx_retry_time_slot_len = 40 ;
conn - > tx_retry_time = conn - > tx_retry_time_slot_len * 4 + ( random32 % conn - > tx_retry_time_slots ) * conn - > tx_retry_time_slot_len * 4 ;
conn - > tx_retry_counter = 0 ;
conn - > data_speed_timer = 0 ;
conn - > tx_data_speed_count = 0 ;
conn - > tx_data_speed = 0 ;
conn - > rx_data_speed_count = 0 ;
conn - > rx_data_speed = 0 ;
conn - > ping_time = 8000 + ( random32 % 100 ) * 10 ;
conn - > fast_ping_time = 600 + ( random32 % 50 ) * 10 ;
conn - > pinging = false ;
conn - > rx_not_ready_mode = false ;
conn - > ready_to_send_timer = - 1 ;
conn - > not_ready_timer = - 1 ;
conn - > send_encrypted = false ;
conn - > rx_rssi_dBm = - 200 ;
conn - > rx_afc_Hz = 0 ;
}
2011-03-06 19:52:18 +01:00
}
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
// *****************************************************************************
void ph_deinit ( void )
{
ph_disconnectAll ( ) ;
}
void ph_init ( uint32_t our_sn )
2011-03-06 19:52:18 +01:00
{
2012-03-18 18:22:05 +01:00
our_serial_number = our_sn ; // remember our own serial number
2011-01-13 09:45:18 +01:00
2012-03-18 18:22:05 +01:00
fast_ping = false ;
2011-03-06 19:52:18 +01:00
2012-03-18 18:22:05 +01:00
ph_disconnectAll ( ) ;
// set the AES encryption key using the default AES key
ph_set_AES128_key ( default_aes_key ) ;
// try too randomise the tx AES CBC bytes
for ( uint32_t j = 0 , k = 0 ; j < 123 + ( random32 & 1023 ) ; j + + )
{
random32 = updateCRC32 ( random32 , 0xff ) ;
enc_cbc [ k ] ^ = random32 > > 3 ;
if ( + + k > = sizeof ( enc_cbc ) ) k = 0 ;
}
2011-03-04 09:34:44 +01:00
2012-03-18 18:22:05 +01:00
// ******
rfm22_init_normal ( saved_settings . min_frequency_Hz , saved_settings . max_frequency_Hz , rfm22_freqHopSize ( ) ) ;
rfm22_TxDataByte_SetCallback ( ph_TxDataByteCallback ) ;
rfm22_RxData_SetCallback ( ph_RxDataCallback ) ;
rfm22_setFreqCalibration ( saved_settings . rf_xtal_cap ) ;
ph_setNominalCarrierFrequency ( saved_settings . frequency_Hz ) ;
ph_setDatarate ( saved_settings . max_rf_bandwidth ) ;
ph_setTxPower ( saved_settings . max_tx_power ) ;
ph_set_remote_encryption ( 0 , saved_settings . aes_enable , ( const void * ) saved_settings . aes_key ) ;
ph_set_remote_serial_number ( 0 , saved_settings . destination_id ) ;
// ******
2011-01-13 09:45:18 +01:00
}
2012-03-18 18:22:05 +01:00
// *****************************************************************************