diff --git a/src/control.rs b/src/control.rs
index 407d1a8daeb216e029c33c012d7697ff273e4982..59762fb220cac952af6a61d64036f5a6cd144fb7 100644
--- a/src/control.rs
+++ b/src/control.rs
@@ -79,22 +79,25 @@ impl Controller {
     }
 
     // manages our transceiver
-    // TODO currently very hacky, because we're going to rip
-    // most of this out when we stop using a lobotomized NPR-70
-    // and move to just accessing the RF4463 directly over SPI
     fn tx_thread(image_rx: Receiver<FecPacket>, telem_rx: Receiver<Packet>) {
-        let mut radio = UartRadio::new("/dev/ttyACM0");
+        let mut radio = UartRadio::new("/dev/ttyAMA0").expect("Could not initialize radio");
 
         let mut text_msg_id = 0;
         loop {
             while let Ok(tm) = telem_rx.try_recv() {
                 let tm = tm.into_raw(&mut text_msg_id).into();
 
-                radio.send_packet(&tm);
+                if let Err(e) = radio.send_packet(&tm) {
+                    eprintln!("Could not send packet: {}", e);
+                }
             }
 
             if let Ok(img) = image_rx.try_recv() {
-                radio.send_packet(&img);
+                println!("start send packet");
+                if let Err(e) = radio.send_packet(&img) {
+                    eprintln!("Could not send packet: {}", e);
+                }
+                println!("end send packet");
             } else {
                 thread::sleep(Duration::from_millis(5));
             }
diff --git a/src/packet.rs b/src/packet.rs
index 9a5a91aa2633bdef0f47a0b4005d8502cad2ba1d..6a40ca3aee985273a37c7b8c36debfab61eaaa3c 100644
--- a/src/packet.rs
+++ b/src/packet.rs
@@ -3,6 +3,7 @@ use crc::{Crc, CRC_16_IBM_3740};
 use crate::ldpc::ldpc_encode;
 
 const TEXT_MESSAGE_LEN: usize = 252;
+const FEC_PACKET_LEN: usize = 256 + 2 + 65;
 
 pub enum Packet {
     TextMessage(u8, [u8; TEXT_MESSAGE_LEN]),
@@ -55,7 +56,7 @@ impl Packet {
 
 pub struct RawPacket(pub [u8; 256]);
 
-pub struct FecPacket(pub [u8; 256 + 2 + 65]);
+pub struct FecPacket(pub [u8; FEC_PACKET_LEN]);
 
 impl From<RawPacket> for FecPacket {
     fn from(value: RawPacket) -> Self {
diff --git a/src/radio.rs b/src/radio.rs
index c05d167de559bc6eb4b2923498943095bc6b7beb..3d6174844e7d9a29c09502d81c6326a6ecbab882 100644
--- a/src/radio.rs
+++ b/src/radio.rs
@@ -1,6 +1,7 @@
 use serial::{unix::TTYPort, BaudRate::BaudOther, SerialPort};
 use std::{
     io::{Read, Write},
+    thread::sleep,
     time::Duration,
 };
 
@@ -8,33 +9,36 @@ use crate::packet::FecPacket;
 
 // Used for talking to an RF4463 via a microcontroller
 // The microcontroller takes in packet data over UART and sends it to the RF4463
-// Note that this is a little hacky. It's only intended to be used
-// for debugging, and not for an actual balloon flight
 pub struct UartRadio {
     uart: TTYPort,
 }
 
 impl UartRadio {
-    pub fn new(uart: &str) -> Self {
-        let mut uart = serial::open(uart).unwrap();
-        uart.reconfigure(&|settings| settings.set_baud_rate(BaudOther(921600)))
-            .unwrap();
-        uart.set_timeout(Duration::from_millis(5)).unwrap();
+    pub fn new(uart: &str) -> anyhow::Result<Self> {
+        let mut uart = serial::open(uart)?;
+        uart.reconfigure(&|settings| settings.set_baud_rate(BaudOther(921_600)))?;
 
-        Self { uart }
+        Ok(Self { uart })
     }
 
-    pub fn send_packet(&mut self, packet: &FecPacket) {
-        self.uart.write_all(&packet.0).unwrap();
-        let mut buf = [0; 1];
-        if let Ok(1) = self.uart.read(&mut buf) {
-            if buf[0] == b'F' {
-                // uC is full. Need to wait until we receive
-                // the empty signal
-                while buf[0] != b'E' {
-                    let _ = self.uart.read(&mut buf);
-                }
+    pub fn send_packet(&mut self, packet: &FecPacket) -> anyhow::Result<()> {
+        loop {
+            self.uart.write_all(&[0x00])?;
+            self.uart.flush()?;
+
+            let mut buf = [0; 1];
+            self.uart.read_exact(&mut buf)?;
+
+            if buf == [0x02] {
+                break; // enough space for packet
+            } else {
+                sleep(Duration::from_millis(10));
             }
         }
+
+        self.uart.write_all(&[0x01])?;
+        self.uart.write_all(&packet.0)?;
+
+        Ok(())
     }
 }