2020-05-30 13:48:04 +00:00
|
|
|
/*
|
|
|
|
* MIT License
|
2020-05-26 12:50:47 +00:00
|
|
|
*
|
2020-05-30 13:48:04 +00:00
|
|
|
* Copyright (c) 2020 DigitalConfections
|
2020-05-26 12:50:47 +00:00
|
|
|
*
|
2020-05-30 13:48:04 +00:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
2020-05-26 12:50:47 +00:00
|
|
|
*
|
2020-05-30 13:48:04 +00:00
|
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
|
|
* copies or substantial portions of the Software.
|
2020-05-26 12:50:47 +00:00
|
|
|
*
|
2020-05-30 13:48:04 +00:00
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
* SOFTWARE.
|
|
|
|
*/
|
|
|
|
/* linkbus.c
|
2020-05-26 12:50:47 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "linkbus.h"
|
|
|
|
#include "defs.h"
|
2020-05-29 02:53:02 +00:00
|
|
|
|
|
|
|
#ifdef COMPILE_FOR_ATMELSTUDIO7
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#endif /* COMPILE_FOR_ATMELSTUDIO7 */
|
2020-05-26 12:50:47 +00:00
|
|
|
|
|
|
|
/* Global Variables */
|
|
|
|
static volatile BOOL g_bus_disabled = TRUE;
|
|
|
|
static const char crlf[] = "\n";
|
|
|
|
static char lineTerm[8] = "\n";
|
|
|
|
static const char textPrompt[] = "> ";
|
|
|
|
|
2020-05-29 02:53:02 +00:00
|
|
|
static const char textHelp[][23] = { "\nCommands:\n",
|
|
|
|
" CAL - Calibrate\n",
|
|
|
|
" DIP - Override DIP\n",
|
|
|
|
" FAC - Factory reset\n",
|
|
|
|
" GO - Sync clock\n",
|
|
|
|
" ID - Set callsign\n",
|
|
|
|
" LED - LED on/off\n",
|
|
|
|
" RST - Reset\n",
|
2020-06-04 19:32:08 +00:00
|
|
|
" SPD - ID code speed\n",
|
|
|
|
" STA - Start tones\n",
|
2020-05-29 02:53:02 +00:00
|
|
|
" TEM - Temperature\n",
|
|
|
|
" VER - S/W version\n" };
|
2020-05-26 12:50:47 +00:00
|
|
|
|
|
|
|
static char g_tempMsgBuff[LINKBUS_MAX_MSG_LENGTH];
|
|
|
|
|
|
|
|
/* Local function prototypes */
|
|
|
|
BOOL linkbus_start_tx(void);
|
2020-05-29 17:12:30 +00:00
|
|
|
BOOL linkbus_send_text(char* text);
|
|
|
|
|
2020-05-26 12:50:47 +00:00
|
|
|
|
|
|
|
/* Module global variables */
|
|
|
|
static volatile BOOL linkbus_tx_active = FALSE; /* volatile is required to ensure optimizer handles this properly */
|
|
|
|
static LinkbusTxBuffer tx_buffer[LINKBUS_NUMBER_OF_TX_MSG_BUFFERS];
|
|
|
|
static LinkbusRxBuffer rx_buffer[LINKBUS_NUMBER_OF_RX_MSG_BUFFERS];
|
|
|
|
|
|
|
|
LinkbusTxBuffer* nextFullTxBuffer(void)
|
|
|
|
{
|
|
|
|
BOOL found = TRUE;
|
|
|
|
static uint8_t bufferIndex = 0;
|
|
|
|
uint8_t count = 0;
|
|
|
|
|
|
|
|
while(tx_buffer[bufferIndex][0] == '\0')
|
|
|
|
{
|
|
|
|
if(++count >= LINKBUS_NUMBER_OF_TX_MSG_BUFFERS)
|
|
|
|
{
|
|
|
|
found = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bufferIndex++;
|
|
|
|
if(bufferIndex >= LINKBUS_NUMBER_OF_TX_MSG_BUFFERS)
|
|
|
|
{
|
|
|
|
bufferIndex = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(found)
|
|
|
|
{
|
|
|
|
return( &tx_buffer[bufferIndex]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
LinkbusTxBuffer* nextEmptyTxBuffer(void)
|
|
|
|
{
|
|
|
|
BOOL found = TRUE;
|
|
|
|
static uint8_t bufferIndex = 0;
|
|
|
|
uint8_t count = 0;
|
|
|
|
|
|
|
|
while(tx_buffer[bufferIndex][0] != '\0')
|
|
|
|
{
|
|
|
|
if(++count >= LINKBUS_NUMBER_OF_TX_MSG_BUFFERS)
|
|
|
|
{
|
|
|
|
found = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bufferIndex++;
|
|
|
|
if(bufferIndex >= LINKBUS_NUMBER_OF_TX_MSG_BUFFERS)
|
|
|
|
{
|
|
|
|
bufferIndex = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(found)
|
|
|
|
{
|
|
|
|
return( &tx_buffer[bufferIndex]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
LinkbusRxBuffer* nextEmptyRxBuffer(void)
|
|
|
|
{
|
|
|
|
BOOL found = TRUE;
|
|
|
|
static uint8_t bufferIndex = 0;
|
|
|
|
uint8_t count = 0;
|
|
|
|
|
|
|
|
while(rx_buffer[bufferIndex].id != MESSAGE_EMPTY)
|
|
|
|
{
|
|
|
|
if(++count >= LINKBUS_NUMBER_OF_RX_MSG_BUFFERS)
|
|
|
|
{
|
|
|
|
found = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bufferIndex++;
|
|
|
|
if(bufferIndex >= LINKBUS_NUMBER_OF_RX_MSG_BUFFERS)
|
|
|
|
{
|
|
|
|
bufferIndex = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(found)
|
|
|
|
{
|
|
|
|
return( &rx_buffer[bufferIndex]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
LinkbusRxBuffer* nextFullRxBuffer(void)
|
|
|
|
{
|
|
|
|
BOOL found = TRUE;
|
|
|
|
static uint8_t bufferIndex = 0;
|
|
|
|
uint8_t count = 0;
|
|
|
|
|
|
|
|
while(rx_buffer[bufferIndex].id == MESSAGE_EMPTY)
|
|
|
|
{
|
|
|
|
if(++count >= LINKBUS_NUMBER_OF_RX_MSG_BUFFERS)
|
|
|
|
{
|
|
|
|
found = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bufferIndex++;
|
|
|
|
if(bufferIndex >= LINKBUS_NUMBER_OF_RX_MSG_BUFFERS)
|
|
|
|
{
|
|
|
|
bufferIndex = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(found)
|
|
|
|
{
|
|
|
|
return( &rx_buffer[bufferIndex]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* linkbusTxInProgress(void)
|
|
|
|
************************************************************************/
|
|
|
|
BOOL linkbusTxInProgress(void)
|
|
|
|
{
|
|
|
|
return(linkbus_tx_active);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL linkbus_start_tx(void)
|
|
|
|
{
|
|
|
|
BOOL success = !linkbus_tx_active;
|
|
|
|
|
|
|
|
if(success) /* message will be lost if transmit is busy */
|
|
|
|
{
|
|
|
|
linkbus_tx_active = TRUE;
|
|
|
|
UCSR0B |= (1 << UDRIE0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(success);
|
|
|
|
}
|
|
|
|
|
|
|
|
void linkbus_end_tx(void)
|
|
|
|
{
|
|
|
|
if(linkbus_tx_active)
|
|
|
|
{
|
|
|
|
UCSR0B &= ~(1 << UDRIE0);
|
|
|
|
linkbus_tx_active = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void linkbus_reset_rx(void)
|
|
|
|
{
|
|
|
|
if(UCSR0B & (1 << RXEN0)) /* perform only if rx is currently enabled */
|
|
|
|
{
|
|
|
|
UCSR0B &= ~(1 << RXEN0);
|
|
|
|
/* uint16_t s = sizeof(rx_buffer); // test */
|
|
|
|
memset(rx_buffer, 0, sizeof(rx_buffer));
|
|
|
|
/* if(s) s = 0; // test */
|
|
|
|
UCSR0B |= (1 << RXEN0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void linkbus_init(uint32_t baud)
|
|
|
|
{
|
|
|
|
memset(rx_buffer, 0, sizeof(rx_buffer));
|
|
|
|
|
|
|
|
for(int bufferIndex = 0; bufferIndex < LINKBUS_NUMBER_OF_TX_MSG_BUFFERS; bufferIndex++)
|
|
|
|
{
|
|
|
|
tx_buffer[bufferIndex][0] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
/*Set baud rate */
|
|
|
|
uint16_t myubrr = MYUBRR(baud);
|
|
|
|
UBRR0H = (uint8_t)(myubrr >> 8);
|
|
|
|
UBRR0L = (uint8_t)myubrr;
|
|
|
|
/* Enable receiver and transmitter and related interrupts */
|
|
|
|
UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);
|
|
|
|
/* UCSR0B = (1<<RXEN0) | (1<<TXEN0);
|
|
|
|
* Set frame format: 8data, 2stop bit */
|
|
|
|
UCSR0C = (1 << USBS0) | (3 << UCSZ00);
|
|
|
|
g_bus_disabled = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void linkbus_disable(void)
|
|
|
|
{
|
|
|
|
uint8_t bufferIndex;
|
|
|
|
|
|
|
|
g_bus_disabled = TRUE;
|
|
|
|
UCSR0B = 0;
|
|
|
|
linkbus_end_tx();
|
|
|
|
memset(rx_buffer, 0, sizeof(rx_buffer));
|
|
|
|
|
|
|
|
for(bufferIndex = 0; bufferIndex < LINKBUS_NUMBER_OF_TX_MSG_BUFFERS; bufferIndex++)
|
|
|
|
{
|
|
|
|
tx_buffer[bufferIndex][0] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void linkbus_enable(void)
|
|
|
|
{
|
|
|
|
uint8_t bufferIndex;
|
|
|
|
|
|
|
|
g_bus_disabled = FALSE;
|
|
|
|
UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);
|
|
|
|
|
|
|
|
memset(rx_buffer, 0, sizeof(rx_buffer));
|
|
|
|
|
|
|
|
for(bufferIndex = 0; bufferIndex < LINKBUS_NUMBER_OF_TX_MSG_BUFFERS; bufferIndex++)
|
|
|
|
{
|
|
|
|
tx_buffer[bufferIndex][0] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL linkbus_send_text(char* text)
|
|
|
|
{
|
|
|
|
BOOL err = TRUE;
|
|
|
|
uint16_t tries = 200;
|
|
|
|
|
|
|
|
if(g_bus_disabled)
|
|
|
|
{
|
|
|
|
return( err);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(text)
|
|
|
|
{
|
|
|
|
LinkbusTxBuffer* buff = nextEmptyTxBuffer();
|
|
|
|
|
|
|
|
while(!buff && tries)
|
|
|
|
{
|
|
|
|
while(linkbusTxInProgress() && tries)
|
|
|
|
{
|
|
|
|
if(tries)
|
|
|
|
{
|
|
|
|
tries--; /* wait until transmit finishes */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
buff = nextEmptyTxBuffer();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(buff)
|
|
|
|
{
|
|
|
|
sprintf(*buff, text);
|
|
|
|
|
|
|
|
linkbus_start_tx();
|
|
|
|
err = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************************
|
|
|
|
* Support for creating and sending various Terminal Mode Linkbus messages is provided below.
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
void lb_send_NewPrompt(void)
|
|
|
|
{
|
2020-05-29 02:53:02 +00:00
|
|
|
while(linkbus_send_text((char*)textPrompt))
|
|
|
|
{
|
|
|
|
;
|
|
|
|
}
|
2020-05-26 12:50:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lb_send_NewLine(void)
|
|
|
|
{
|
|
|
|
linkbus_send_text((char*)crlf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void lb_echo_char(uint8_t c)
|
|
|
|
{
|
|
|
|
g_tempMsgBuff[0] = c;
|
|
|
|
g_tempMsgBuff[1] = '\0';
|
|
|
|
linkbus_send_text(g_tempMsgBuff);
|
|
|
|
}
|
|
|
|
|
2020-05-29 02:53:02 +00:00
|
|
|
BOOL lb_send_string(char* str, BOOL wait)
|
2020-05-26 12:50:47 +00:00
|
|
|
{
|
2020-05-29 17:12:30 +00:00
|
|
|
BOOL err = FALSE;
|
2020-05-29 02:53:02 +00:00
|
|
|
|
2020-05-26 12:50:47 +00:00
|
|
|
if(str == NULL)
|
|
|
|
{
|
|
|
|
return( TRUE);
|
|
|
|
}
|
2020-05-30 13:48:04 +00:00
|
|
|
|
2020-05-29 02:53:02 +00:00
|
|
|
if(strlen(str) > LINKBUS_MAX_TX_MSG_LENGTH)
|
2020-05-26 12:50:47 +00:00
|
|
|
{
|
|
|
|
return( TRUE);
|
|
|
|
}
|
2020-05-30 13:48:04 +00:00
|
|
|
|
2020-05-29 02:53:02 +00:00
|
|
|
strncpy(g_tempMsgBuff, str, LINKBUS_MAX_TX_MSG_LENGTH);
|
|
|
|
|
|
|
|
if(wait)
|
|
|
|
{
|
2020-05-29 17:12:30 +00:00
|
|
|
while((err = linkbus_send_text(g_tempMsgBuff)))
|
2020-05-29 02:53:02 +00:00
|
|
|
{
|
|
|
|
;
|
|
|
|
}
|
2020-05-29 17:12:30 +00:00
|
|
|
while(!err && linkbusTxInProgress())
|
2020-05-29 02:53:02 +00:00
|
|
|
{
|
|
|
|
;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
err = linkbus_send_text(g_tempMsgBuff);
|
|
|
|
}
|
|
|
|
|
|
|
|
return( err);
|
2020-05-26 12:50:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lb_send_value(uint16_t value, char* label)
|
|
|
|
{
|
|
|
|
sprintf(g_tempMsgBuff, "> %s=%d%s", label, value, lineTerm);
|
|
|
|
linkbus_send_text(g_tempMsgBuff);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* lb_send_Help(void)
|
|
|
|
************************************************************************/
|
|
|
|
void lb_send_Help(void)
|
|
|
|
{
|
|
|
|
if(g_bus_disabled)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(g_tempMsgBuff, "\n*** %s Ver. %s ***", PRODUCT_NAME_LONG, SW_REVISION);
|
|
|
|
|
|
|
|
while(linkbus_send_text(g_tempMsgBuff))
|
|
|
|
{
|
|
|
|
;
|
|
|
|
}
|
|
|
|
while(linkbusTxInProgress())
|
|
|
|
{
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t n = sizeof(textHelp) / sizeof(textHelp[0]);
|
|
|
|
for(uint8_t i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
while(linkbus_send_text((char*)textHelp[i]))
|
|
|
|
{
|
|
|
|
;
|
|
|
|
}
|
|
|
|
while(linkbusTxInProgress())
|
|
|
|
{
|
|
|
|
;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lb_send_NewLine();
|
|
|
|
}
|
|
|
|
|