/*
This project 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.
Multiprotocol 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 Multiprotocol. If not, see .
*/
//**************************
// Telemetry serial code *
//**************************
#if defined TELEMETRY
uint8_t RetrySequence ;
#if ( defined(MULTI_TELEMETRY) || defined(MULTI_STATUS) )
#define MULTI_TIME 500 //in ms
#define INPUT_SYNC_TIME 100 //in ms
#define INPUT_ADDITIONAL_DELAY 100 // in 10µs, 100 => 1000 µs
uint32_t lastMulti = 0;
#endif // MULTI_TELEMETRY/MULTI_STATUS
#if defined SPORT_TELEMETRY
#define SPORT_TIME 12000 //12ms
#define FRSKY_SPORT_PACKET_SIZE 8
#define FX_BUFFERS 4
uint32_t last = 0;
uint8_t sport_counter=0;
uint8_t RxBt = 0;
uint8_t sport = 0;
uint8_t pktx1[FRSKY_SPORT_PACKET_SIZE*FX_BUFFERS];
// Store for out of sequence packet
uint8_t FrskyxRxTelemetryValidSequence ;
struct t_fx_rx_frame
{
uint8_t valid ;
uint8_t count ;
uint8_t payload[6] ;
} ;
// Store for FrskyX telemetry
struct t_fx_rx_frame FrskyxRxFrames[4] ;
uint8_t NextFxFrameToForward ;
#ifdef SPORT_POLLING
uint8_t sport_rx_index[28] ;
uint8_t ukindex ;
uint8_t kindex ;
uint8_t TxData[2];
uint8_t SportIndexPolling;
uint8_t RxData[16] ;
volatile uint8_t RxIndex=0 ;
uint8_t sport_bytes=0;
uint8_t skipped_id;
uint8_t rx_counter=0;
#endif
#endif // SPORT_TELEMETRY
#if defined HUB_TELEMETRY
#define USER_MAX_BYTES 6
uint8_t prev_index;
#endif // HUB_TELEMETRY
#define START_STOP 0x7e
#define BYTESTUFF 0x7d
#define STUFF_MASK 0x20
#define MAX_PKTX 10
uint8_t pktx[MAX_PKTX];
uint8_t indx;
uint8_t frame[18];
#if ( defined(MULTI_TELEMETRY) || defined(MULTI_STATUS) )
static void multi_send_header(uint8_t type, uint8_t len)
{
Serial_write('M');
#ifdef MULTI_TELEMETRY
Serial_write('P');
Serial_write(type);
#else
(void)type;
#endif
Serial_write(len);
}
static void multi_send_status()
{
#ifdef SPORT_POLLING
rx_pause();
#endif
multi_send_header(MULTI_TELEMETRY_STATUS, 5);
// Build flags
uint8_t flags=0;
if (IS_INPUT_SIGNAL_on)
flags |= 0x01;
if (mode_select==MODE_SERIAL)
flags |= 0x02;
if (remote_callback != 0)
{
flags |= 0x04;
if (IS_WAIT_BIND_on)
flags |= 0x10;
else
if (!IS_BIND_DONE_on)
flags |= 0x08;
}
Serial_write(flags);
// Version number example: 1.1.6.1
Serial_write(VERSION_MAJOR);
Serial_write(VERSION_MINOR);
Serial_write(VERSION_REVISION);
Serial_write(VERSION_PATCH_LEVEL);
}
#endif
#ifdef DSM_TELEMETRY
#ifdef MULTI_TELEMETRY
void DSM_frame()
{
if (pkt[0] == 0x80)
{
multi_send_header(MULTI_TELEMETRY_DSMBIND, 10);
for (uint8_t i = 1; i < 11; i++) // 10 bytes of DSM bind response
Serial_write(pkt[i]);
}
else
{
multi_send_header(MULTI_TELEMETRY_DSM, 17);
for (uint8_t i = 0; i < 17; i++) // RSSI value followed by 16 bytes of telemetry data
Serial_write(pkt[i]);
}
}
#else
void DSM_frame()
{
Serial_write(0xAA); // Telemetry packet
for (uint8_t i = 0; i < 17; i++) // RSSI value followed by 16 bytes of telemetry data
Serial_write(pkt[i]);
}
#endif
#endif
#ifdef AFHDS2A_FW_TELEMETRY
void AFHDSA_short_frame()
{
#if defined MULTI_TELEMETRY
multi_send_header(MULTI_TELEMETRY_AFHDS2A, 29);
#else
Serial_write(0xAA); // Telemetry packet
#endif
for (uint8_t i = 0; i < 29; i++) // RSSI value followed by 4*7 bytes of telemetry data
Serial_write(pkt[i]);
}
#endif
#ifdef MULTI_TELEMETRY
static void multi_send_frskyhub()
{
multi_send_header(MULTI_TELEMETRY_HUB, 9);
for (uint8_t i = 0; i < 9; i++)
Serial_write(frame[i]);
}
#endif
void frskySendStuffed()
{
Serial_write(START_STOP);
for (uint8_t i = 0; i < 9; i++)
{
if ((frame[i] == START_STOP) || (frame[i] == BYTESTUFF))
{
Serial_write(BYTESTUFF);
frame[i] ^= STUFF_MASK;
}
Serial_write(frame[i]);
}
Serial_write(START_STOP);
}
void frsky_check_telemetry(uint8_t *pkt,uint8_t len)
{
uint8_t clen = pkt[0] + 3 ;
if(pkt[1] == rx_tx_addr[3] && pkt[2] == rx_tx_addr[2] && len == clen )
{
telemetry_link|=1; // Telemetry data is available
TX_RSSI = pkt[len-2];
if(TX_RSSI >=128)
TX_RSSI -= 128;
else
TX_RSSI += 128;
TX_LQI = pkt[len-1]&0x7F;
for (uint8_t i=3;i0 && pktt[6]<=10)
{
if (protocol==MODE_FRSKYD)
{
if ( ( pktt[7] & 0x1F ) == (telemetry_counter & 0x1F) )
{
uint8_t topBit = 0 ;
if ( telemetry_counter & 0x80 )
if ( ( telemetry_counter & 0x1F ) != RetrySequence )
topBit = 0x80 ;
telemetry_counter = ( (telemetry_counter+1)%32 ) | topBit ; // Request next telemetry frame
}
else
{
// incorrect sequence
RetrySequence = pktt[7] & 0x1F ;
telemetry_counter |= 0x80 ;
pktt[6]=0 ; // Discard current packet and wait for retransmit
}
}
}
else
pktt[6]=0; // Discard packet
//
#if defined SPORT_TELEMETRY && defined FRSKYX_CC2500_INO
telemetry_lost=0;
if (protocol==MODE_FRSKYX)
{
uint16_t lcrc = frskyX_crc_x(&pkt[3], len-7 ) ;
if ( ( (lcrc >> 8) == pkt[len-4]) && ( (lcrc & 0x00FF ) == pkt[len-3]) )
{
// Check if in sequence
if ( (pkt[5] & 0x0F) == 0x08 )
{
FrX_receive_seq = 0x08 ;
NextFxFrameToForward = 0 ;
FrskyxRxFrames[0].valid = 0 ;
FrskyxRxFrames[1].valid = 0 ;
FrskyxRxFrames[2].valid = 0 ;
FrskyxRxFrames[3].valid = 0 ;
}
else if ( (pkt[5] & 0x03) == (FrX_receive_seq & 0x03 ) )
{
// OK to process
struct t_fx_rx_frame *p ;
uint8_t count ;
p = &FrskyxRxFrames[FrX_receive_seq & 3] ;
count = pkt[6] ;
if ( count <= 6 )
{
p->count = count ;
for ( uint8_t i = 0 ; i < count ; i += 1 )
p->payload[i] = pkt[i+7] ;
}
else
p->count = 0 ;
p->valid = 1 ;
FrX_receive_seq = ( FrX_receive_seq + 1 ) & 0x03 ;
if ( FrskyxRxTelemetryValidSequence & 0x80 )
{
FrX_receive_seq = ( FrskyxRxTelemetryValidSequence + 1 ) & 3 ;
FrskyxRxTelemetryValidSequence &= 0x7F ;
}
}
else
{
// Save and request correct packet
struct t_fx_rx_frame *q ;
uint8_t count ;
// pkt[4] RSSI
// pkt[5] sequence control
// pkt[6] payload count
// pkt[7-12] payload
pktt[6] = 0 ; // Don't process
if ( (pkt[5] & 0x03) == ( ( FrX_receive_seq +1 ) & 3 ) )
{
q = &FrskyxRxFrames[(pkt[5] & 0x03)] ;
count = pkt[6] ;
if ( count <= 6 )
{
q->count = count ;
for ( uint8_t i = 0 ; i < count ; i += 1 )
{
q->payload[i] = pkt[i+7] ;
}
}
else
q->count = 0 ;
q->valid = 1 ;
FrskyxRxTelemetryValidSequence = 0x80 | ( pkt[5] & 0x03 ) ;
}
FrX_receive_seq = ( FrX_receive_seq & 0x03 ) | 0x04 ; // Request re-transmission
}
if (((pktt[5] >> 4) & 0x0f) == 0x08)
FrX_send_seq = 0 ;
}
}
#endif
}
}
void init_frskyd_link_telemetry()
{
telemetry_link=0;
telemetry_counter=0;
v_lipo1=0;
v_lipo2=0;
RX_RSSI=0;
TX_RSSI=0;
RX_LQI=0;
TX_LQI=0;
}
void frsky_link_frame()
{
frame[0] = 0xFE; // Link frame
if (protocol==MODE_FRSKYD)
{
frame[1] = pktt[3]; // A1
frame[2] = pktt[4]; // A2
frame[3] = pktt[5]; // RX_RSSI
telemetry_link &= ~1 ; // Sent
telemetry_link |= 2 ; // Send hub if available
}
else
if (protocol==MODE_HUBSAN||protocol==MODE_AFHDS2A||protocol==MODE_BAYANG||protocol==MODE_CABELL)
{
frame[1] = v_lipo1;
frame[2] = v_lipo2;
frame[3] = RX_RSSI;
telemetry_link=0;
}
frame[4] = TX_RSSI;
frame[5] = RX_LQI;
frame[6] = TX_LQI;
frame[7] = frame[8] = 0;
#if defined MULTI_TELEMETRY
multi_send_frskyhub();
#else
frskySendStuffed();
#endif
}
#if defined HUB_TELEMETRY
void frsky_user_frame()
{
if(pktt[6])
{//only send valid hub frames
frame[0] = 0xFD; // user frame
if(pktt[6]>USER_MAX_BYTES)
{
frame[1]=USER_MAX_BYTES; // packet size
pktt[6]-=USER_MAX_BYTES;
telemetry_link |= 2 ; // 2 packets need to be sent
}
else
{
frame[1]=pktt[6]; // packet size
telemetry_link=0; // only 1 packet or processing second packet
}
frame[2] = pktt[7];
for(uint8_t i=0;i0)
{
crc_s += p[i]; //0-1FF
crc_s += crc_s >> 8; //0-100
crc_s &= 0x00ff;
}
}
}
#else
void sportSend(uint8_t *p)
{
uint16_t crc_s = 0;
Serial_write(START_STOP);//+9
Serial_write(p[0]) ;
for (uint8_t i = 1; i < 9; i++)
{
if (i == 8)
p[i] = 0xff - crc_s;
if ((p[i] == START_STOP) || (p[i] == BYTESTUFF))
{
Serial_write(BYTESTUFF);//stuff again
Serial_write(STUFF_MASK ^ p[i]);
}
else
Serial_write(p[i]);
if (i>0)
{
crc_s += p[i]; //0-1FF
crc_s += crc_s >> 8; //0-100
crc_s &= 0x00ff;
}
}
}
#endif
#if defined SPORT_POLLING
uint8_t nextID()
{
uint8_t i ;
uint8_t poll_idx ;
if (phase)
{
poll_idx = 99 ;
for ( i = 0 ; i < 28 ; i++ )
{
if ( sport_rx_index[kindex] )
{
poll_idx = kindex ;
}
kindex++ ;
if ( kindex>= 28 )
{
kindex = 0 ;
phase = 0 ;
break ;
}
if ( poll_idx != 99 )
{
break ;
}
}
if ( poll_idx != 99 )
{
return poll_idx ;
}
}
if ( phase == 0 )
{
for ( i = 0 ; i < 28 ; i++ )
{
if ( sport_rx_index[ukindex] == 0 )
{
poll_idx = ukindex ;
phase = 1 ;
}
ukindex++;
if (ukindex >= 28 )
{
ukindex = 0 ;
}
if ( poll_idx != 99 )
{
return poll_idx ;
}
}
if ( poll_idx == 99 )
{
phase = 1 ;
return 0 ;
}
}
return poll_idx ;
}
void pollSport()
{
uint8_t pindex = nextID() ;
TxData[0] = START_STOP;
TxData[1] = pgm_read_byte_near(&Indices[pindex]) ;
if(!telemetry_lost && ((TxData[1] &0x1F)== skipped_id ||TxData[1]==0x98))
{//98 ID(RSSI/RxBat and SWR ) and ID's from sport telemetry
pindex = nextID() ;
TxData[1] = pgm_read_byte_near(&Indices[pindex]);
}
SportIndexPolling = pindex ;
RxIndex = 0;
Serial_write(TxData[0]);
Serial_write(TxData[1]);
}
bool checkSportPacket()
{
uint8_t *packet = RxData ;
uint16_t crc = 0 ;
if ( RxIndex < 8 )
return 0 ;
for ( uint8_t i = 0 ; i<8 ; i += 1 )
{
crc += packet[i];
crc += crc >> 8;
crc &= 0x00ff;
}
return (crc == 0x00ff) ;
}
uint8_t unstuff()
{
uint8_t i ;
uint8_t j ;
j = 0 ;
for ( i = 0 ; i < RxIndex ; i += 1 )
{
if ( RxData[i] == BYTESTUFF )
{
i += 1 ;
RxData[j] = RxData[i] ^ STUFF_MASK ; ;
}
else
RxData[j] = RxData[i] ;
j += 1 ;
}
return j ;
}
void processSportData(uint8_t *p)
{
RxIndex = unstuff() ;
uint8_t x=checkSportPacket() ;
if (x)
{
SportData[sport_idx]=0x7E;
sport_idx =(sport_idx+1) & (MAX_SPORT_BUFFER-1);
SportData[sport_idx]=TxData[1]&0x1F;
sport_idx =(sport_idx+1) & (MAX_SPORT_BUFFER-1);
for(uint8_t i=0;i<(RxIndex-1);i++)
{//no crc
if(p[i]==START_STOP || p[i]==BYTESTUFF)
{//stuff back
SportData[sport_idx]=BYTESTUFF;
sport_idx =(sport_idx+1) & (MAX_SPORT_BUFFER-1);
SportData[sport_idx]=p[i]^STUFF_MASK;
}
else
SportData[sport_idx]=p[i];
sport_idx =(sport_idx+1) & (MAX_SPORT_BUFFER-1);
}
sport_rx_index[SportIndexPolling] = 1 ;
ok_to_send=true;
RxIndex =0 ;
}
}
inline void rx_pause()
{
USART3_BASE->CR1 &= ~ USART_CR1_RXNEIE; //disable rx interrupt on USART3
}
inline void rx_resume()
{
USART3_BASE->CR1 |= USART_CR1_RXNEIE; //enable rx interrupt on USART3
}
#endif//end SPORT_POLLING
void sportIdle()
{
#if !defined MULTI_TELEMETRY
Serial_write(START_STOP);
#endif
}
void sportSendFrame()
{
#if defined SPORT_POLLING
rx_pause();
#endif
uint8_t i;
sport_counter = (sport_counter + 1) %36;
if(telemetry_lost)
{
#ifdef SPORT_POLLING
pollSport();
#else
sportIdle();
#endif
return;
}
if(sport_counter<6)
{
frame[0] = 0x98;
frame[1] = 0x10;
for (i=5;i<8;i++)
frame[i]=0;
}
switch (sport_counter)
{
case 0:
frame[2] = 0x05;
frame[3] = 0xf1;
frame[4] = 0x02 ;//dummy values if swr 20230f00
frame[5] = 0x23;
frame[6] = 0x0F;
break;
case 2: // RSSI
frame[2] = 0x01;
frame[3] = 0xf1;
frame[4] = RX_RSSI;
frame[5] = TX_RSSI;
frame[6] = RX_LQI;
frame[7] = TX_LQI;
break;
case 4: //BATT
frame[2] = 0x04;
frame[3] = 0xf1;
frame[4] = RxBt;//a1;
break;
default:
if(sport)
{
for (i=0;i= FRSKY_SPORT_PACKET_SIZE)
{//8 bytes no crc
if ( sport < FX_BUFFERS )
{
uint8_t dest = sport * FRSKY_SPORT_PACKET_SIZE ;
uint8_t i ;
for ( i = 0 ; i < FRSKY_SPORT_PACKET_SIZE ; i += 1 )
pktx1[dest++] = pktx[i] ; // Triple buffer
sport += 1 ;//ok to send
}
// else
// {
// // Overrun
// }
pass = 0;//reset
}
}
#endif
void TelemetryUpdate()
{
// check for space in tx buffer
#ifdef BASH_SERIAL
uint8_t h ;
uint8_t t ;
h = SerialControl.head ;
t = SerialControl.tail ;
if ( h >= t )
t += TXBUFFER_SIZE - h ;
else
t -= h ;
if ( t < 64 )
{
return ;
}
#else
uint8_t h ;
uint8_t t ;
h = tx_head ;
t = tx_tail ;
if ( h >= t )
t += TXBUFFER_SIZE - h ;
else
t -= h ;
if ( t < 32 )
{
return ;
}
#endif
#if ( defined(MULTI_TELEMETRY) || defined(MULTI_STATUS) )
{
uint32_t now = millis();
if ((now - lastMulti) > MULTI_TIME)
{
multi_send_status();
lastMulti = now;
return;
}
}
#endif
#if defined SPORT_TELEMETRY
if (protocol==MODE_FRSKYX)
{ // FrSkyX
for(;;)
{
struct t_fx_rx_frame *p ;
uint8_t count ;
p = &FrskyxRxFrames[NextFxFrameToForward] ;
if ( p->valid )
{
count = p->count ;
for (uint8_t i=0; i < count ; i++)
proces_sport_data(p->payload[i]) ;
p->valid = 0 ; // Sent on
NextFxFrameToForward = ( NextFxFrameToForward + 1 ) & 3 ;
}
else
{
break ;
}
}
if(telemetry_link)
{
if(pktt[4] & 0x80)
RX_RSSI=pktt[4] & 0x7F ;
else
RxBt = (pktt[4]<<1) + 1 ;
telemetry_link=0;
}
uint32_t now = micros();
if ((now - last) > SPORT_TIME)
{
#if defined SPORT_POLLING
processSportData(RxData); //process arrived data before polling
#endif
sportSendFrame();
#ifdef STM32_BOARD
last=now;
#else
last += SPORT_TIME ;
#endif
}
}
#endif // SPORT_TELEMETRY
#if defined DSM_TELEMETRY
if(telemetry_link && protocol == MODE_DSM)
{ // DSM
DSM_frame();
telemetry_link=0;
return;
}
#endif
#if defined AFHDS2A_FW_TELEMETRY
if(telemetry_link == 2 && protocol == MODE_AFHDS2A)
{
AFHDSA_short_frame();
telemetry_link=0;
return;
}
#endif
if((telemetry_link & 1 )&& protocol != MODE_FRSKYX)
{ // FrSkyD + Hubsan + AFHDS2A + Bayang + Cabell
frsky_link_frame();
return;
}
#if defined HUB_TELEMETRY
if((telemetry_link & 2) && protocol == MODE_FRSKYD)
{ // FrSkyD
frsky_user_frame();
return;
}
#endif
}
/**************************/
/**************************/
/** Serial TX routines **/
/**************************/
/**************************/
#ifndef BASH_SERIAL
// Routines for normal serial output
void Serial_write(uint8_t data)
{
uint8_t nextHead ;
nextHead = tx_head + 1 ;
if ( nextHead >= TXBUFFER_SIZE )
nextHead = 0 ;
tx_buff[nextHead]=data;
tx_head = nextHead ;
tx_resume();
}
void initTXSerial( uint8_t speed)
{
#ifdef ENABLE_PPM
if(speed==SPEED_9600)
{ // 9600
#ifdef ORANGE_TX
USARTC0.BAUDCTRLA = 207 ;
USARTC0.BAUDCTRLB = 0 ;
USARTC0.CTRLB = 0x18 ;
USARTC0.CTRLA = (USARTC0.CTRLA & 0xCF) | 0x10 ;
USARTC0.CTRLC = 0x03 ;
#else
#ifdef STM32_BOARD
usart3_begin(9600,SERIAL_8N1); //USART3
USART3_BASE->CR1 &= ~ USART_CR1_RE; //disable RX leave TX enabled
#else
UBRR0H = 0x00;
UBRR0L = 0x67;
UCSR0A = 0 ; // Clear X2 bit
//Set frame format to 8 data bits, none, 1 stop bit
UCSR0C = (1<CR1 &= ~ USART_CR1_RE; //disable RX leave TX enabled
#else
UBRR0H = 0x00;
UBRR0L = 0x22;
UCSR0A = 0x02 ; // Set X2 bit
//Set frame format to 8 data bits, none, 1 stop bit
UCSR0C = (1<CR1 &= ~ USART_CR1_RE; //disable RX leave TX enabled
#else
UBRR0H = 0x00;
UBRR0L = 0x07;
UCSR0A = 0x00 ; // Clear X2 bit
//Set frame format to 8 data bits, none, 1 stop bit
UCSR0C = (1<SR & USART_SR_RXNE)
{
USART3_BASE->SR &= ~USART_SR_RXNE;
if (RxIndex < 16 )
{
if(RxData[0]==TxData[0] && RxData[1]==TxData[1])
RxIndex=0;
RxData[RxIndex++] = USART3_BASE->DR & 0xFF ;
}
}
#endif
if(USART3_BASE->SR & USART_SR_TXE)
{
USART3_BASE->SR &= ~USART_SR_TXE;
#endif
if(tx_head!=tx_tail)
{
if(++tx_tail>=TXBUFFER_SIZE)//head
tx_tail=0;
#ifdef STM32_BOARD
USART3_BASE->DR=tx_buff[tx_tail];//clears TXE bit
#else
UDR0=tx_buff[tx_tail];
#endif
}
if (tx_tail == tx_head)
{
tx_pause(); // Check if all data is transmitted . if yes disable transmitter UDRE interrupt
#ifdef SPORT_POLLING
rx_resume();
#endif
}
#ifdef STM32_BOARD
}
#endif
}
#ifdef STM32_BOARD
void usart2_begin(uint32_t baud,uint32_t config )
{
usart_init(USART2);
usart_config_gpios_async(USART2,GPIOA,PIN_MAP[PA3].gpio_bit,GPIOA,PIN_MAP[PA2].gpio_bit,config);
usart_set_baud_rate(USART2, STM32_PCLK1, baud);
usart_enable(USART2);
}
void usart3_begin(uint32_t baud,uint32_t config )
{
usart_init(USART3);
usart_config_gpios_async(USART3,GPIOB,PIN_MAP[PB11].gpio_bit,GPIOB,PIN_MAP[PB10].gpio_bit,config);
usart_set_baud_rate(USART3, STM32_PCLK1, baud);
usart_enable(USART3);
}
#endif
#else //BASH_SERIAL
// Routines for bit-bashed serial output
// Speed is 0 for 100K and 1 for 9600
void initTXSerial( uint8_t speed)
{
TIMSK0 = 0 ; // Stop all timer 0 interrupts
#ifdef INVERT_SERIAL
SERIAL_TX_off;
#else
SERIAL_TX_on;
#endif
UCSR0B &= ~(1<>= 7 ; // Top bit
if ( SerialControl.speed == SPEED_100K )
{
#ifdef INVERT_SERIAL
byteLo |= 0x02 ; // Parity bit
#else
byteLo |= 0xFC ; // Stop bits
#endif
// calc parity
temp = byte ;
temp >>= 4 ;
temp = byte ^ temp ;
temp1 = temp ;
temp1 >>= 2 ;
temp = temp ^ temp1 ;
temp1 = temp ;
temp1 <<= 1 ;
temp ^= temp1 ;
temp &= 0x02 ;
#ifdef INVERT_SERIAL
byteLo ^= temp ;
#else
byteLo |= temp ;
#endif
}
else
{
byteLo |= 0xFE ; // Stop bit
}
byte <<= 1 ;
#ifdef INVERT_SERIAL
byte |= 1 ; // Start bit
#endif
uint8_t next = SerialControl.head + 2;
if(next>=TXBUFFER_SIZE)
next=0;
if ( next != SerialControl.tail )
{
SerialControl.data[SerialControl.head] = byte ;
SerialControl.data[SerialControl.head+1] = byteLo ;
SerialControl.head = next ;
}
if(!IS_TX_PAUSE_on)
tx_resume();
}
void resumeBashSerial()
{
cli() ;
if ( SerialControl.busy == 0 )
{
sei() ;
// Start the transmission here
#ifdef INVERT_SERIAL
GPIOR2 = 0 ;
#else
GPIOR2 = 0x01 ;
#endif
if ( SerialControl.speed == SPEED_100K )
{
GPIOR1 = 1 ;
OCR0B = TCNT0 + 40 ;
OCR0A = OCR0B + 210 ;
TIFR0 = (1<>= 1
GPIOR0 = byte ;
if ( --GPIOR1 == 0 )
{
TIMSK0 &= ~(1<>= 1
GPIOR2 = byte ;
if ( --GPIOR1 == 0 )
{
if ( IS_TX_PAUSE_on )
{
SerialControl.busy = 0 ;
TIMSK0 &= ~(1<head != ptr->tail )
{
GPIOR0 = ptr->data[ptr->tail] ;
GPIOR2 = ptr->data[ptr->tail+1] ;
uint8_t nextTail = ptr->tail + 2 ;
if ( nextTail >= TXBUFFER_SIZE )
nextTail = 0 ;
ptr->tail = nextTail ;
GPIOR1 = 8 ;
OCR0A = OCR0B + 40 ;
OCR0B = OCR0A + 8 * 20 ;
TIMSK0 |= (1< 2 )
byte = GPIOR0 ;
else
byte = GPIOR2 ;
if ( byte & 0x01 )
SERIAL_TX_on;
else
SERIAL_TX_off;
byte /= 2 ; // Generates shorter code than byte >>= 1
if ( GPIOR1 > 2 )
GPIOR0 = byte ;
else
GPIOR2 = byte ;
if ( --GPIOR1 == 0 )
{ // prepare next byte
volatile struct t_serial_bash *ptr = &SerialControl ;
if ( ptr->head != ptr->tail )
{
GPIOR0 = ptr->data[ptr->tail] ;
GPIOR2 = ptr->data[ptr->tail+1] ;
uint8_t nextTail = ptr->tail + 2 ;
if ( nextTail >= TXBUFFER_SIZE )
nextTail = 0 ;
ptr->tail = nextTail ;
GPIOR1 = 10 ;
}
else
{
SerialControl.busy = 0 ;
TIMSK0 &= ~(1<