/* * MIT License * * Copyright (c) 2020 DigitalConfections * * 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: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * 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 * */ #include "linkbus.h" #include "defs.h" #if COMPILE_FOR_ATMELSTUDIO7 #include #include #endif /* COMPILE_FOR_ATMELSTUDIO7 */ /* Global Variables */ static volatile BOOL g_bus_disabled = TRUE; static const char crlf[] = "\n"; static char lineTerm[8] = "\n"; static const char textPrompt[] = "> "; 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", " SPD - ID code speed\n", " STA - Start tones\n", " TEM - Temperature\n", " VER - S/W version\n" }; static char g_tempMsgBuff[LINKBUS_MAX_MSG_LENGTH]; /* Local function prototypes */ BOOL linkbus_start_tx(void); BOOL linkbus_send_text(char* text); /* 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< LINKBUS_MAX_TX_MSG_LENGTH) { return( TRUE); } strncpy(g_tempMsgBuff, str, LINKBUS_MAX_TX_MSG_LENGTH); if(wait) { while((err = linkbus_send_text(g_tempMsgBuff))) { ; } while(!err && linkbusTxInProgress()) { ; } } else { err = linkbus_send_text(g_tempMsgBuff); } return( err); } 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(); }