Browse Source

got every nearly working except carrier sense

curiousmuch 4 years ago
parent
commit
4e1a9839fc

+ 3 - 3
components/aprs/afsk_modulator.c

@@ -19,20 +19,20 @@
 /* Local Global Variables */
 static float delta_phi, delta_phi_1, delta_phi_2;		// phase deltas for two tones used in AFSK modulation
 static float phase = 0;					// current phase as AFSK modulator must be phase continous
-static int32_t phase_i = 0;				// integer of phase which is used by LUT
+static uint8_t phase_i = 0;				// integer of phase which is used by LUT
 static DRAM_ATTR int8_t LUT[LUT_SIZE];		// look up table used for tone generation
 
 /* Private Functions */
 // Returns the phase for the LUT based on the current symbol being
 // sent
-static int32_t IRAM_ATTR afsk_get_phase(uint8_t tone)
+static uint8_t IRAM_ATTR afsk_get_phase(uint8_t tone)
 {
 	if ( tone )
 		delta_phi = delta_phi_1;
 	else
 		delta_phi = delta_phi_2;
 
-    phase_i = (int32_t)phase;        // get integer part of our phase
+    phase_i = (uint8_t)phase;        // get integer part of our phase
 
     phase += delta_phi;              // increment phase
 

+ 2 - 0
components/aprs/aprs_encoder.c

@@ -37,6 +37,7 @@ void ax25_encoder_reset(void)
 	enc_var.prev_bit = 0;
 	enc_var.nrzi_bit = 0;
 	enc_var.byte = 0;
+	enc_var.flag_count = 0;
 
 	// reset state machine state
 	enc_var.state = PREAMBLE;
@@ -123,6 +124,7 @@ uint8_t ax25_encoder_get_bit(void)
 					enc_var.state = FRAME;
 					enc_var.bit_index = 0;
 					enc_var.index = 0;
+					enc_var.flag_count = 0;
 				}
 
 			}

+ 1 - 1
components/kiss/include/kiss.h

@@ -9,7 +9,7 @@
 #define MAIN_KISS_H_
 
 // Logging Tag
-#define TNC_TAG "KISS"
+#define TNC_TAG "kiss"
 
 // Frame Buffer
 #define FRAME_BUFFER_SIZE 1024

+ 2 - 0
components/kiss/kiss.c

@@ -115,6 +115,8 @@ void kiss_process_frame(void)
     // confirm packet is for this device
     if (tnc_number == kiss_settings.tnc_number)
     	kiss_settings.rx_callback(rx_buffer.buf, rx_buffer.index);
+
+    kiss_clear_buffer();
 }
 
 

+ 6 - 1
components/radio/include/radio.h

@@ -24,13 +24,17 @@ typedef enum {
 	RADIO_RX,
 } radio_status_t;
 
+// internal radio data structure
 typedef struct {
 	radio_config_t type;
 	radio_status_t status;
 	void (*rx_cb)(uint8_t *, uint32_t);
-	void (*tx_cb)(uint8_t *, uint32_t);
+	void (*tx_cb)(void);
 } radio_param_t;
 
+// holds all the settings for AX25
+// style communications used typically
+// on 2M band
 typedef struct {
 	uint8_t tx_delay;
 	uint8_t tx_tail;
@@ -40,6 +44,7 @@ typedef struct {
 	uint8_t *rx_buf;
 	uint32_t rx_buf_len;
 	void (*rx_cb)(uint8_t *, uint32_t);
+	void (*tx_cb)(void);
 	uint8_t cpu_core;
 } ax25_param_t;
 

+ 223 - 103
components/radio/radio.c

@@ -28,16 +28,32 @@
 #include "aprs_encoder.h"
 
 /* Debugging Tag */
-#define RADIO_TAG "Radio"
+#define RADIO_TAG "radio"
+
+/* Data Structures */
+typedef enum {
+	RADIO_TIMER_NO_CONFIG = 0,
+	RADIO_TIMER_TX,
+	RADIO_TIMER_RX,
+} timer_radio_semaphore_t;
 
 /* Local Global Variables */
 static radio_param_t radio_param;				// radio configuraiton
-static SemaphoreHandle_t xRadioSemaphore;		// semphore for sample timing
+//static SemaphoreHandle_t xRadioSemaphore;		// semphore for sample timing
+static SemaphoreHandle_t xRadioTXSemaphore;
+static SemaphoreHandle_t xRadioRXSemaphore;
+static SemaphoreHandle_t xRadioMutex;
+static timer_radio_semaphore_t radio_semaphore;
+
+#define DEBUG_0 			16
+#define DEBUG_1				4
+#define DEBUG_2				32
+#define DEBUG_3				33
 
 /* Private Functions */
 void IRAM_ATTR radio_timer_isr(void *param)
 {
-    //GPIO.out_w1ts = (1 << DEBUG_0);
+    GPIO.out_w1ts = (1 << DEBUG_0);
 
 	int timer_idx = (int) param; 	// cast to int for timer index
 	TIMERG0.int_clr_timers.t0 = 1; 	// clear interrupt
@@ -45,13 +61,28 @@ void IRAM_ATTR radio_timer_isr(void *param)
 
 	// provide unblocking semaphore
 	static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
-	xSemaphoreGiveFromISR(xRadioSemaphore, &xHigherPriorityTaskWoken);
+	switch(radio_semaphore) {
+		case RADIO_TIMER_NO_CONFIG:
+			//ESP_LOGE(RADIO_TAG, "no configuration");
+			break;
+		case RADIO_TIMER_RX:
+			xSemaphoreGiveFromISR(xRadioRXSemaphore, &xHigherPriorityTaskWoken);
+			break;
+		case RADIO_TIMER_TX:
+			xSemaphoreGiveFromISR(xRadioTXSemaphore, &xHigherPriorityTaskWoken);
+			break;
+		default:
+			//ESP_LOGE(RADIO_TAG, "invalid configuration");
+			break;
+	}
+
+	// wake higher priority task if woken
 	if (xHigherPriorityTaskWoken == pdTRUE)
 	{
 		portYIELD_FROM_ISR();
 	}
 
-	//GPIO.out_w1tc = (1 << DEBUG_0);
+	GPIO.out_w1tc = (1 << DEBUG_0);
 }
 
 #define RADIO_TIMER_GROUP TIMER_GROUP_0
@@ -59,6 +90,7 @@ void IRAM_ATTR radio_timer_isr(void *param)
 
 void timer_radio_init(uint32_t sample_rate, void *timer_isr)
 {
+	// setup timer settings
 	timer_config_t timer_config;
 
 	timer_config.divider = 2;
@@ -68,21 +100,28 @@ void timer_radio_init(uint32_t sample_rate, void *timer_isr)
 	timer_config.intr_type = TIMER_INTR_LEVEL;
 	timer_config.auto_reload = TIMER_AUTORELOAD_EN;
 
-
+	// calculate value for timer alarm
+	// TODO: confirm timer alarm value calculation
 	uint32_t timer_alarm;
 	timer_alarm = (uint32_t)(40000000 / sample_rate);
 
-	// TODO: confirm timer_alarm calculation
-
+	// load timer settings
     timer_init(RADIO_TIMER_GROUP, RADIO_TIMER, &timer_config);
     timer_set_counter_value(RADIO_TIMER_GROUP, RADIO_TIMER, 0x00000000ULL);
     timer_set_alarm_value(RADIO_TIMER_GROUP, RADIO_TIMER, 3030);
     timer_isr_register(RADIO_TIMER_GROUP, RADIO_TIMER, timer_isr,
     		(void *) RADIO_TIMER, ESP_INTR_FLAG_IRAM, NULL);
+
+    // setup timer ISR semaphore type
+    radio_semaphore = RADIO_TIMER_NO_CONFIG;
 }
 
-void timer_radio_start(void)
+void timer_radio_start(timer_radio_semaphore_t type)
 {
+	// setup timer ISR semaphore type
+	radio_semaphore = type;
+
+	// start timer
 	timer_enable_intr(RADIO_TIMER_GROUP, RADIO_TIMER);
     timer_set_counter_value(RADIO_TIMER_GROUP, RADIO_TIMER, 0x00000000ULL);
     timer_start(RADIO_TIMER_GROUP, RADIO_TIMER);
@@ -90,6 +129,10 @@ void timer_radio_start(void)
 
 void timer_radio_stop(void)
 {
+	// setup timer ISR semaphore type
+	radio_semaphore = RADIO_TIMER_NO_CONFIG;
+
+	// stop timer
     timer_disable_intr(RADIO_TIMER_GROUP, RADIO_TIMER);
 	timer_pause(RADIO_TIMER_GROUP, RADIO_TIMER);
 }
@@ -136,120 +179,131 @@ int8_t radio_get_cs()
 		return ax25_decoder_get_cs();
 }
 
-void radio_init(radio_config_t type, void *settings)
-{
-	switch(type)
-	{
-		case AX25: {
-			ESP_LOGI("Radio", "APRS Mode");
-			radio_param.type = AX25;
-
-			// cast setting struct
-			ax25_param_t *p = (ax25_param_t *)settings;
 
-			// setup LUT for AFSK demodulator
-			afsk_mod_init(p->sample_rate, p->symbol0_freq, p->symbol1_freq);
 
-			// setup frequency detectors for AFSK demodulator
-			afsk_demod_init(p->sample_rate, p->symbol0_freq, p->symbol1_freq);
 
-			// setup encoder for ax25
-			ax25_encoder_init(p->tx_delay, p->tx_tail);
-
-			// setup ax25 decoder
-			ax25_decoder_init(p->rx_buf, p->rx_buf_len);
-			radio_param.rx_cb = p->rx_cb;
-
-			// setup timer for TX / RX
-			timer_radio_init(p->sample_rate, radio_timer_isr);
+void radio_packet_tx(uint8_t *data, int32_t len, void *settings)
+{
 
-			// configure CC1200
-			cc1200_radio_init(AX25_SETTINGS, sizeof(AX25_SETTINGS)/sizeof(cc1200_reg_settings_t));
 
-			// put chip to idle
-			radio_idle();
+	// configure radio for TX
+	switch (radio_param.type) {
+		case AX25: {
+			ESP_LOGI(RADIO_TAG, "transmitting AX25 packet");
 
-			// task communication
-			xRadioSemaphore = xSemaphoreCreateBinary();
+			// load ax25 encoder state machine
+			ax25_encoder_encode(data, len);
 
-			// create task for sampling
-			// TODO: Reduce stack requirements?
-			xTaskCreatePinnedToCore(radio_rx_task, "radio rx", 1024*4, 0, 1, NULL, p->cpu_core);
-			//vTaskSuspend(radio_rx_task);
+			// configure radio to send CW
+			xSemaphoreTake( xRadioMutex, portMAX_DELAY );	// lock radio
+			radio_tx();
+			xSemaphoreGive( xRadioMutex );					// unlock radio
 
+			// start sampling timer
+			timer_radio_start(RADIO_TIMER_TX);
 			break;
 		}
 		default: {
 			ESP_LOGE(RADIO_TAG, "invalid configuration");
-			radio_param.type = NOT_CONFIGURED;
-			//TODO: Add assert to stop functionality
 			break;
 		}
 	}
+
 }
 
-// this function will block and configure
-// the cc1200 for tx using the protocol setup by "radio_init"
-// the buffer holding the packet isn't copied and therefore must be held until
-// the function returns
-// TODO: Should this be non-blocking and start up a task / wait for an interrupt
-// then fire a callback function?
-void radio_packet_tx(uint8_t *data, int32_t len, void *settings)
+void radio_tx_task(void *para)
 {
-	switch(radio_param.type)
-	{
-		case AX25: {
-			ESP_LOGV(RADIO_TAG, "transmitting AX25 packet");
+	// variables for transmission
+	uint32_t sample_count = 0;
+	uint8_t nrzi_bit = 0;
+	int8_t amplitude = 0;
 
-			// load ax25 encoder state machine
-			ax25_encoder_encode(data, len);
+	// metrics
+	uint32_t tx_count = 0;
 
-			// variables for symbol timing (11 samples per symbol)
-			uint32_t sample_count = 0; int8_t tone;
-			uint8_t bit = ax25_encoder_get_bit();
+	while(1)
+	{
 
-			// configure radio to send CW
-			radio_tx();
+		// block until sampling timer is running
+		if (xSemaphoreTake(xRadioTXSemaphore, portMAX_DELAY) == pdTRUE)
+		{
+			if (ax25_encoder_get_status() == READY)
+			{
+				// reset sample count used per RF symbol
+				sample_count = 0;
 
-			// start sampling timer
-			timer_radio_start();
+				// setup first amplitude for tone
+				nrzi_bit = ax25_encoder_get_bit();
+				amplitude = afsk_get_amplitude(nrzi_bit);
+			}
+			else
+			{
+				// process error
+			}
+		}
 
-			while(ax25_encoder_get_status() == READY)
+		// run until packet is finished
+		while(ax25_encoder_get_status() == READY)
+		{
+			// block until semaphore is given or there has been a timing error
+			if (xSemaphoreTake(xRadioTXSemaphore, portMAX_DELAY) == pdTRUE)
 			{
-				// TODO: Do we need to feed the WDT here?
+				// update carrier for AFSK
+				xSemaphoreTake( xRadioMutex, portMAX_DELAY );	// lock radio
 
-				// get amplitude for AFSK
-				tone = afsk_get_amplitude(bit);
+				cc1200_radio_write_CFM(amplitude);
 
-				// pause for semphore
-				if (xSemaphoreTake(xRadioSemaphore, portMAX_DELAY) == pdTRUE)
-				{
-					// update carrier for AFSK
-					cc1200_radio_write_CFM(tone);
-
-					// inc symbol count
-					sample_count++;
-					if (sample_count > 11)
-					{
-						bit = ax25_encoder_get_bit();
-						sample_count = 0;
-					}
-				}
-				else
+				xSemaphoreGive( xRadioMutex );	// unlock radio
+
+				// increment symbol count
+				sample_count++;
+				if (sample_count >= 11)
 				{
-					ESP_LOGE(RADIO_TAG, "sampling timeout error");
-					break;
+				    GPIO.out_w1ts = (1 << DEBUG_1);
+
+					nrzi_bit = ax25_encoder_get_bit();
+					sample_count = 0;
+
+				    GPIO.out_w1tc = (1 << DEBUG_1);
+
 				}
 
+				// get amplitude for next nrzi bit
+				amplitude = afsk_get_amplitude(nrzi_bit);
+			}
+			else
+			{
+				ESP_LOGE(RADIO_TAG, "timing error");
+				ESP_LOGI(RADIO_TAG, "canceling transmission");
+				break;
 			}
-			radio_idle();
-			ESP_LOGV(RADIO_TAG, "transmit complete");
-			break;
 		}
-		default: {
-			ESP_LOGE(RADIO_TAG, "invalid configuration");
-			break;
+
+		// stop sampling timer
+		timer_radio_stop();
+
+		// confirm if TX failed or not
+		// ax25_encoder will not reach DONE if their is a timing failure
+		switch(ax25_encoder_get_status()) {
+			case STOP:
+				ESP_LOGI(RADIO_TAG, "transmission complete: [%d]", tx_count++);
+				break;
+			case READY:
+				ESP_LOGE(RADIO_TAG, "transmission failed");
+				break;
+			case ERROR:
+				ESP_LOGE(RADIO_TAG, "encoder error");
+				break;
+			default:
+				ESP_LOGE(RADIO_TAG, "unknown encoder error");
+		}
+
+		// active callback function
+		if (radio_param.tx_cb != NULL)
+		{
+			radio_param.tx_cb();
 		}
+
 	}
 }
 
@@ -265,11 +319,9 @@ void radio_rx_task(void *para)
 	int32_t d_pll=0, dpll_error=0, err_div=0;
 
 	// TODO: The following group should be made user setable fed via the settings
-	const int32_t SAMPLE_FREQUENCY = 132000;
+	const int32_t SAMPLE_FREQUENCY = 13200;
 	const int32_t BAUD_RATE = 1200;
 	const int32_t SAMPLES_BIT = SAMPLE_FREQUENCY / BAUD_RATE;
-
-
 	const int32_t D_PLL_INC = (SAMPLES_BIT * 1);
 	const int32_t D_PLL_MAX = (D_PLL_INC * SAMPLES_BIT * 1);
 	const int32_t D_PLL_MARGIN = 1;
@@ -281,10 +333,12 @@ void radio_rx_task(void *para)
 	while(1)
 	{
 		// block until semphore is given or there has been a timing error
-		if (xSemaphoreTake(xRadioSemaphore, portMAX_DELAY) == pdTRUE)
+		if (xSemaphoreTake(xRadioRXSemaphore, portMAX_DELAY) == pdTRUE)
 		{
 			// read register analog value from radio
+			xSemaphoreTake( xRadioMutex, portMAX_DELAY );	// lock radio
 			cfm_value = cc1200_radio_read_CFM();
+			xSemaphoreGive( xRadioMutex );					// unlock radio
 
 			// afsk demod
 			raw_bit = afsk_demod_add_sample(cfm_value);
@@ -318,7 +372,7 @@ void radio_rx_task(void *para)
 					case NORMAL:
 						break;
 					case FRAME_DECODED:
-						ESP_LOGI("APRS RX", "AX.25 Frame Received [%d]", success++);
+						ESP_LOGI("radio", "AX25 transmission received: [%d]", success++);
 						// send via KISS TNC to over BLE SPP
 						//ESP_LOG_BUFFER_HEXDUMP("APRS RX", aprs_buf, 100, ESP_LOG_INFO);
 						//kiss_transmit(KISS_DATAFRAME, v.frame_buffer, v.frame_len);
@@ -326,7 +380,7 @@ void radio_rx_task(void *para)
 							radio_param.rx_cb(ax25_decoder_get_frame(), ax25_decoder_get_frame_len());
 						break;
 					case ERROR_FCS_MISMATCH:
-						ESP_LOGV("APRS RX", "AX.25 FCS Error\n");
+						ESP_LOGV("radio", "AX25 fcs error");
 						break;
 					default:
 						//printf("Weird Error\n");
@@ -338,7 +392,7 @@ void radio_rx_task(void *para)
 		}
 		else
 		{
-			ESP_LOGE(RADIO_TAG, "sampling timeout error");
+			ESP_LOGE(RADIO_TAG, "rx timing error");
 		}
 	}
 }
@@ -351,14 +405,15 @@ void radio_packet_rx(void *settings)
 	{
 		case AX25: {
 			// setup radio
+			xSemaphoreTake( xRadioMutex, portMAX_DELAY );	// lock radio
 			radio_rx();
-
+			xSemaphoreGive( xRadioMutex );					// unlock radio
 			// setup sampling timer
-			timer_radio_start();
-
+			// TODO: This may cause a race condition as this will start a task which requires the
+			// token to start.
+			timer_radio_start(RADIO_TIMER_RX);
 			// unsuspend task
-			vTaskResume(radio_rx_task); //??????? should this be top or bottom
-
+			//vTaskResume(radio_rx_task); //??????? should this be top or bottom
 			break;
 		}
 		default: {
@@ -367,4 +422,69 @@ void radio_packet_rx(void *settings)
 		}
 
 	}
+
+}
+
+void radio_init(radio_config_t type, void *settings)
+{
+	// create mutux so SPI transactions will be multi-thread safe
+	// TODO: fix so mutex is only created one to avoid memory leak
+	xRadioMutex = xSemaphoreCreateMutex();
+
+	// lock radio
+	xSemaphoreTake( xRadioMutex, portMAX_DELAY );
+
+	switch(type)
+	{
+		case AX25: {
+			ESP_LOGI("Radio", "APRS Mode");
+			radio_param.type = AX25;
+
+			// cast setting struct
+			ax25_param_t *p = (ax25_param_t *)settings;
+
+			// setup LUT for AFSK demodulator
+			afsk_mod_init(p->sample_rate, p->symbol0_freq, p->symbol1_freq);
+
+			// setup frequency detectors for AFSK demodulator
+			afsk_demod_init(p->sample_rate, p->symbol0_freq, p->symbol1_freq);
+
+			// setup encoder for ax25
+			ax25_encoder_init(p->tx_delay, p->tx_tail);
+
+			// setup ax25 decoder
+			ax25_decoder_init(p->rx_buf, p->rx_buf_len);
+			radio_param.rx_cb = p->rx_cb;
+			radio_param.tx_cb = p->tx_cb;
+
+			// setup timer for TX / RX
+			timer_radio_init(p->sample_rate, radio_timer_isr);
+
+			// configure CC1200
+			cc1200_radio_init(AX25_SETTINGS, sizeof(AX25_SETTINGS)/sizeof(cc1200_reg_settings_t));
+
+			// put chip to idle
+			radio_idle();
+
+			// task communication
+			xRadioRXSemaphore = xSemaphoreCreateBinary();
+			xRadioTXSemaphore = xSemaphoreCreateBinary();
+
+			// create task for sampling
+			// TODO: Reduce stack requirements?
+			xTaskCreatePinnedToCore(radio_rx_task, "radio rx", 1024*4, 0, 1, NULL, p->cpu_core);
+			xTaskCreatePinnedToCore(radio_tx_task, "radio tx", 1024*4, 0, 2, NULL, p->cpu_core);
+			//vTaskSuspend(radio_rx_task);
+			break;
+		}
+		default: {
+			ESP_LOGE(RADIO_TAG, "invalid configuration");
+			radio_param.type = NOT_CONFIGURED;
+			//TODO: Add assert to stop functionality
+			break;
+		}
+	}
+
+	// unlock radio
+	xSemaphoreGive( xRadioMutex );
 }

+ 60 - 31
main/main.c

@@ -44,29 +44,35 @@ typedef struct {
 } tnc_settings_t;
 
 /* Public Variables */
-tnc_settings_t tnc_settings;
+static tnc_settings_t tnc_settings;
+static SemaphoreHandle_t xRadioTXSemaphore;
 
 uint8_t ax25_rx_buf[1024];
 RingbufHandle_t ax25_tx_buf;
 
-/* Functions and Main */
-
 /* Radio Callback Functions */
-// callback function for when radio rx'd AX25 packet
-// unblocks task on other core and packet to another buffer
-// so we can continue processing
+
 void radio_rx_ax25_cb(uint8_t *frame, uint32_t len)
 {
-	ESP_LOGV("AX25 CB", "We Here");
-	// unblock receive task on CPU0
+	// TODO: move kiss processing to other core
+	kiss_transmit(KISS_DATAFRAME, frame, len);
+}
 
+void radio_tx_ax25_cb(void)
+{
+	// unlock scheduling task to allow next packet to be sent
+	xSemaphoreGive(xRadioTXSemaphore);
 }
 
 /* KISS callback Functions */
+
 void kiss_tx_cb(uint8_t *frame, uint32_t len)
 {
-	// send data to UART / via bluetooth
+	// TODO: move function to other core
+	// TODO: Add functionality which indicates if BLE connection is present or not
+	// send data to UART via bluetooth
 	bt_spp_tx(frame, len);
+	ESP_LOGI("tnc", "kiss packet sent");
 }
 
 void kiss_rx_cb(uint8_t *frame, uint32_t len)
@@ -77,44 +83,50 @@ void kiss_rx_cb(uint8_t *frame, uint32_t len)
 	// process dataframe
 	if (data_byte == KISS_DATAFRAME)
 	{
+
+		ESP_LOGI("tnc", "kiss packet received");
+
 		// feed packet to ring buffer
 		uint32_t fcs = fcs_calc(&frame[1], len-1);
 		frame[len] = fcs & 0xFF;
 		frame[len+1] = fcs>>8 & 0xFF;
-		xRingbufferSend(ax25_tx_buf, &frame[1], ((len+1)*sizeof(uint8_t)),10/portTICK_PERIOD_MS);
+		if (xRingbufferSend(ax25_tx_buf, &frame[1], ((len+1)*sizeof(uint8_t)),10/portTICK_PERIOD_MS) == pdFALSE)
+		{
+			ESP_LOGE("tnc", "packet buffer overflow");
+		}
 	}
 	else // assume command
 	{
 		switch(data_byte)
 		{
 			case KISS_CMD_TXDELAY:
-				ESP_LOGI("TNC", "updated tx delay");
+				ESP_LOGI("tnc", "updated tx delay");
 				tnc_settings.tx_delay = frame[1];
 				break;
 			case KISS_CMD_P:
-				ESP_LOGI("TNC", "updated persistance");
+				ESP_LOGI("tnc", "updated persistance");
 				tnc_settings.P = frame[1];
 				break;
 			case KISS_CMD_SLOTTIME:
-				ESP_LOGI("TNC", "updated slot time");
+				ESP_LOGI("tnc", "updated slot time");
 				tnc_settings.slot_time = frame[1];
 				break;
 			case KISS_CMD_TXTAIL:
-				ESP_LOGI("TNC", "updated tx tail");
+				ESP_LOGI("tnc", "updated tx tail");
 				tnc_settings.tx_tail = frame[1];
 				break;
 			case KISS_CMD_FULLDUPLEX:
-				ESP_LOGI("TNC", "updated duplex setting");
+				ESP_LOGI("tnc", "updated duplex setting");
 				tnc_settings.full_duplex = frame[1];
 				break;
 			case KISS_CMD_SETHARDWARE:
-				ESP_LOGI("TNC", "updated hardware settings");
+				ESP_LOGI("tnc", "updated hardware settings");
 				break;
 			case KISS_CMD_RETURN:
-				ESP_LOGI("TNC", "wtf is return");
+				ESP_LOGI("tnc", "wtf is return");
 				break;
 			default:
-				ESP_LOGE("KISS", "unknown data byte");
+				ESP_LOGE("tnc", "unknown data byte for KISS protocol");
 		}
 
 		// reload for parameter changes to take effect
@@ -122,15 +134,15 @@ void kiss_rx_cb(uint8_t *frame, uint32_t len)
 }
 
 /* TNC Tasks */
-// schedules transmissions based on p-persistance
-// settings and carrier sense from radio a
-// TODO: Latch CS during slot time?
 
 void tnc_task(void *para)
 {
-	radio_packet_rx(NULL);
 	uint8_t *packet;
 	size_t packet_size;
+	uint8_t P;
+
+	radio_packet_rx(NULL);
+
 	while(1)
 	{
 		// indicate RX
@@ -139,14 +151,16 @@ void tnc_task(void *para)
 
 		// check ring buffer for packet
 		packet = xRingbufferReceive(ax25_tx_buf, &packet_size, portMAX_DELAY);
+		ESP_LOGI("tnc", "scheduling transmission");
 
 		if (packet != NULL)
 		{
-			uint8_t P;
 			// wait based on persistance algorithm
 			while (1)
 			{
-				if (!radio_get_cs())
+				// TODO: carrier detect is causing a crash somehow when it gets locked on
+				// to high. I'm confused as the unit should continue to run despite this...
+				//if (!radio_get_cs())
 				{
 					P = (uint8_t) esp_random();
 					if (P <= tnc_settings.P)
@@ -158,24 +172,32 @@ void tnc_task(void *para)
 						vTaskDelay(tnc_settings.slot_time * 10 / portTICK_PERIOD_MS);
 					}
 				}
-				taskYIELD(); // make sure to yield for RX'ing task
 			}
 
+			ESP_LOGI("tnc", "transmission scheduled");
+
 			// indicate TX
 			enable_red_led();
 			disable_green_led();
 
+			// TODO: modify code so the full TX DELAY isn't used when multiple packets are sent.
 			// dump all the packets in the buffer
 			while(packet != NULL)
 			{
+				// setup packet to be transmitted
 				radio_packet_tx(packet, packet_size, NULL);
+
+				// sleep until packet is finished being sent
+				xSemaphoreTake(xRadioTXSemaphore, portMAX_DELAY);
+
+				// remove packet from ring buffer and load next one if it exists
 				vRingbufferReturnItem(ax25_tx_buf, (void *)packet);
 				packet = xRingbufferReceive(ax25_tx_buf, &packet_size, 0);
 			}
 		}
 		else
 		{
-			printf("Why we here \n");
+			ESP_LOGE("tnc", "buffer error");
 		}
 		// setup again for reception
 		radio_packet_rx(NULL);
@@ -184,6 +206,10 @@ void tnc_task(void *para)
 
 void IRAM_ATTR app_main()
 {
+	// Inter-Task Communication
+	ax25_tx_buf = xRingbufferCreate(1028, RINGBUF_TYPE_NOSPLIT);
+	xRadioTXSemaphore = xSemaphoreCreateBinary();
+
 	// Initialize Flash
 	esp_err_t ret = nvs_flash_init();
 	if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
@@ -198,15 +224,16 @@ void IRAM_ATTR app_main()
 	// Load Settings from Flash
 
 
-	// Radio Task Initialize
+	// Radio Initialize
 	ax25_param_t ax25_param;
 
 	ax25_param.tx_tail = 10;
-	ax25_param.tx_delay = 10;
+	ax25_param.tx_delay = 100;
 	ax25_param.sample_rate = 13200;
 	ax25_param.symbol0_freq = 1200;
 	ax25_param.symbol1_freq = 2200;
 	ax25_param.rx_cb = radio_rx_ax25_cb;
+	ax25_param.tx_cb = radio_tx_ax25_cb;
 	ax25_param.rx_buf = ax25_rx_buf;
 	ax25_param.rx_buf_len = sizeof(ax25_rx_buf) / sizeof(ax25_rx_buf[0]);
 	ax25_param.cpu_core = 1;
@@ -216,12 +243,14 @@ void IRAM_ATTR app_main()
 	// Kiss Decoder and Encoder
 	kiss_init(0, kiss_tx_cb, kiss_rx_cb);
 
-
 	// BLE and SPP
 	bt_spp_init();
 
-	// Inter-Task Communication
-	ax25_tx_buf = xRingbufferCreate(1028, RINGBUF_TYPE_NOSPLIT);
+	// TNC Settings
+	tnc_settings.slot_time = 10;
+	tnc_settings.P = 63;
+	tnc_settings.tnc_number = 0;
+
 
 	// Tasks
 	xTaskCreatePinnedToCore(tnc_task, "tnc task", 1024*4, 0, 2, NULL, 1);