diff --git a/cw/.cproject b/cw/.cproject new file mode 100644 index 00000000..adafe502 --- /dev/null +++ b/cw/.cproject @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cw/.gitignore b/cw/.gitignore new file mode 100644 index 00000000..3df573fe --- /dev/null +++ b/cw/.gitignore @@ -0,0 +1 @@ +/Debug/ diff --git a/cw/.project b/cw/.project new file mode 100644 index 00000000..26855828 --- /dev/null +++ b/cw/.project @@ -0,0 +1,26 @@ + + + chat + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/cw/.settings/language.settings.xml b/cw/.settings/language.settings.xml new file mode 100644 index 00000000..33aecbb9 --- /dev/null +++ b/cw/.settings/language.settings.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cw/.settings/org.eclipse.cdt.managedbuilder.core.prefs b/cw/.settings/org.eclipse.cdt.managedbuilder.core.prefs new file mode 100644 index 00000000..dc262ac2 --- /dev/null +++ b/cw/.settings/org.eclipse.cdt.managedbuilder.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1377630500/CPATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1377630500/CPATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1377630500/C_INCLUDE_PATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1377630500/C_INCLUDE_PATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1377630500/append=true +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1377630500/appendContributed=true +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.1377630500/LIBRARY_PATH/delimiter=; +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.1377630500/LIBRARY_PATH/operation=remove +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.1377630500/append=true +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.1377630500/appendContributed=true diff --git a/cw/cw_main.c b/cw/cw_main.c new file mode 100644 index 00000000..52016210 --- /dev/null +++ b/cw/cw_main.c @@ -0,0 +1,328 @@ +// Copyright (c) 2018 Brandenburg Tech, LLC +// All right reserved. +// +// THIS SOFTWARE IS PROVIDED BY BRANDENBURG TECH, LLC AND CONTRIBUTORS +// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRANDENBURT TECH, LLC +// AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_MESSAGE_LENGTH (197) + +extern uint8_t axradio_rxbuffer[]; + +void *receive(void *arg); +void *transmit(void *arg); +size_t get_message(uint8_t *buffer, size_t avail); + +enum RadioState {UnknownState, RxState, TxState}; +enum RadioState currentState = UnknownState; + +enum ReceiveState {WaitingForNewPacket, WaitingForPacketCounter1, + WaitingForPacketCounter2, WaitingForMessageLength1, + WaitingForMessageLength2, WaitingForMessage, + WaitingForChecksum1, WaitingForChecksum2}; + +int main(void) +{ + uint8_t retVal; + + // Configure SPI bus to AX5043 + setSpiChannel(SPI_CHANNEL); + setSpiSpeed(SPI_SPEED); + initializeSpi(); + + // Initialize the AX5043 + retVal = axradio_init(); + if (retVal == AXRADIO_ERR_NOCHIP) { + fprintf(stderr, "ERROR: No AX5043 RF chip found\n"); + exit(EXIT_FAILURE); + } + if (retVal != AXRADIO_ERR_NOERROR) { + fprintf(stderr, "ERROR: Unable to initialize AX5043\n"); + exit(EXIT_FAILURE); + } + + printf("INFO: Found and initialized AX5043\n"); + + int result; + + sem_t ax5043_sem; + result = sem_init(&ax5043_sem, 0, 1); + if (result != 0) { + fprintf(stderr, "ERROR: Unable to create semaphore with error %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + + pthread_t receive_thread; + result = pthread_create(&receive_thread, NULL, receive, (void *)&ax5043_sem); + if (result != 0) { + fprintf(stderr, "ERROR: Unable to spawn receive thread with error %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + pthread_t transmit_thread; + result = pthread_create(&transmit_thread, NULL, transmit, (void *)&ax5043_sem); + if (result != 0) { + fprintf(stderr, "ERROR: Unable to spawn transmit thread with error %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + + void *transmit_result; + result = pthread_join(transmit_thread, &transmit_result); + if (result != 0) { + fprintf(stderr, "ERROR: Unable to wait for transmit thread to finish with error %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + sem_destroy(&ax5043_sem); + + return 0; +} + +void *receive(void *arg) { + sem_t *sem; + sem = (sem_t *)arg; + + uint8_t retVal; + uint16_t packetNumber; + uint16_t messageLength; + uint16_t checksum; + char ch; + + enum ReceiveState currentReceiveState = WaitingForNewPacket; + + for (;;) { + int result; + + result = sem_wait(sem); + if (result != 0) { + fprintf(stderr, "Failed to wait on semaphore with error %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + + // Enter receive mode only if not already in receive mode + if (currentState != RxState) { + retVal = mode_rx(); + if (retVal != AXRADIO_ERR_NOERROR) { + fprintf(stderr, "ERROR: Unable to enter RX mode\n"); + exit(EXIT_FAILURE); + } + currentState = RxState; + } + + retVal = receive_packet(); + if (retVal > 0) { + uint8_t counter = 0; + while (retVal-- > 0) { + switch(currentReceiveState) { + case WaitingForNewPacket: + printf("Pkt Len: %d ", (int)axradio_rxbuffer[counter++]); + currentReceiveState = WaitingForPacketCounter1; + break; + case WaitingForPacketCounter1: + packetNumber = (int)axradio_rxbuffer[counter++]; + currentReceiveState = WaitingForPacketCounter2; + break; + case WaitingForPacketCounter2: + packetNumber |= (uint16_t)(axradio_rxbuffer[counter++] << 8); + printf("Pkt Num: %d ", (int)packetNumber); + currentReceiveState = WaitingForMessageLength1; + break; + case WaitingForMessageLength1: + messageLength = (int)axradio_rxbuffer[counter++]; + currentReceiveState = WaitingForMessageLength2; + break; + case WaitingForMessageLength2: + messageLength |= (uint16_t)(axradio_rxbuffer[counter++] << 8); + printf("Msg Len: %d ", (int)messageLength); + currentReceiveState = WaitingForMessage; + break; + case WaitingForMessage: + ch = (char)axradio_rxbuffer[counter++]; + if (ch != '\n') { + printf("%c", ch); + } + else { + printf(" "); + currentReceiveState = WaitingForChecksum1; + } + break; + case WaitingForChecksum1: + checksum = (int)axradio_rxbuffer[counter++]; + currentReceiveState = WaitingForChecksum2; + break; + case WaitingForChecksum2: + checksum |= (uint16_t)(axradio_rxbuffer[counter++] << 8); + printf("(Chksum: %d)\n", (int)checksum); + currentReceiveState = WaitingForNewPacket; + break; + default: + fprintf(stderr, "ERROR: Unknown state in receive state machine\n"); + exit(EXIT_FAILURE); + break; + } + } + + fflush(stdout); + + } + + result = sem_post(sem); + if (result != 0) { + fprintf(stderr, "Failed to post on semaphore with error %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + usleep(25000); + } + + return NULL; +} + +void *transmit(void *arg) { + sem_t *sem; + sem = (sem_t *)arg; + + uint8_t retVal; + + for (;;) { + int result; + + // allocate space for the buffer + static uint8_t packet[MAX_MESSAGE_LENGTH + 1]; + uint16_t pkt_counter; + + ++pkt_counter; + + // Calculate the number of reserved bytes at the beginning of the packet + size_t reserved_space = 0; + + // if transmitting a packet counter, reserve two bytes + if (framing_insert_counter) { + reserved_space += 2; + } + + // reserve two bytes for the overall length of the packet including the + // packet counter, if present, and the field containing the length + reserved_space += 2; + + // get a message to transmit. + size_t msg_length = get_message(&packet[reserved_space], (MAX_MESSAGE_LENGTH + 1) - reserved_space); + + // if message consists only of a newline, terminate + if (msg_length <= 1) { + break; + } + + if (framing_insert_counter) { + packet[framing_counter_pos] = (uint8_t)(pkt_counter & 0xFF); + packet[framing_counter_pos+1] = (uint8_t)((pkt_counter>>8) & 0xFF); + + // include the message length + packet[framing_counter_pos+2] = msg_length & 0xFF ; + packet[framing_counter_pos+3] = (msg_length>>8) & 0xFF; + } + else { // only include the message length + packet[framing_counter_pos] = msg_length & 0xFF ; + packet[framing_counter_pos+1] = (msg_length>>8) & 0xFF; + } + + result = sem_wait(sem); + if (result != 0) { + fprintf(stderr, "Failed to wait on semaphore with error %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + // Enter transmit mode only if not already in receive mode + if (currentState != TxState) { + retVal = mode_tx(); + if (retVal != AXRADIO_ERR_NOERROR) { + fprintf(stderr, "ERROR: Unable to enter TX mode\n"); + exit(EXIT_FAILURE); + } + currentState = TxState; + } + + //printf("INFO: Sending another packet...\n"); + //printf("DEBUG: msg_length = %d\n", msg_length); + //printf("DEBUG: reserved_space = %d\n", reserved_space); + retVal = transmit_packet(&remoteaddr_tx, packet, (uint16_t)(msg_length + reserved_space)); + if (retVal != AXRADIO_ERR_NOERROR) { + fprintf(stderr, "ERROR: Unable to transmit a packet\n"); + exit(EXIT_FAILURE); + } + + result = sem_post(sem); + if (result != 0) { + fprintf(stderr, "Failed to post on semaphore with error %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + usleep(200000); + } + + return NULL; +} + +size_t get_message(uint8_t *buffer, size_t avail) { + + static int instructionsPrinted = 0; + + // obtain a line of text. We state the message is limited to avail-2 to + // leave space for the newline and the null terminator + if (!instructionsPrinted) { + printf("Please enter your message, up to %d characters\n (empty message to terminate the program):\n", (int)(avail-2)); + instructionsPrinted = 1; + } + fgets((char *)buffer, (int)avail, stdin); + + // check for end-of-file (for redirecting stdin) + if (feof(stdin)) { + buffer[0] = '\n'; + buffer[1] = 0; + } + + // If the newline isn't present, the message is too long + + //printf("DEBUG: ***%s***\n", buffer); + + if (buffer[strlen((char *)buffer) - 1] != '\n') { + buffer[strlen((char *)buffer) - 1] = '\n'; + printf("WARNING: message too long. It will be truncated to\n%s", (char *)buffer); + + // If the newline isn't in the buffer, read characters from the keyboard buffer to the newline + int c; + do { + c = getchar(); + } while (c != '\n' && c != EOF); + } + + //printf("DEBUG: ***%s***\n", buffer); + + return strlen((char *)buffer); +}