diff --git a/src/error.rs b/src/error.rs
index 5e9b9b313652540bbd209c17f3f4eba07bc2c8a9..b7e422fbc6608845cd2664cbc6495516c4bc3e24 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -23,12 +23,21 @@ pub enum TransferError<SE: Debug> {
     SpiError(SE),
 }
 
+#[derive(Debug)]
+pub enum TxError<SE: Debug> {
+    // Given slice was bigger than the maximum packet size
+    TooMuchData,
+    SpiError(SE),
+}
+
 pub(crate) trait SpiErrorToOtherError<T, E: Debug> {
     fn re(self) -> Result<T, RfError<E>>
     where
         Self: Sized;
 
     fn te(self) -> Result<T, TransferError<E>>;
+
+    fn txe(self) -> Result<T, TxError<E>>;
 }
 
 impl<T, E: Debug> SpiErrorToOtherError<T, E> for Result<T, E> {
@@ -39,4 +48,8 @@ impl<T, E: Debug> SpiErrorToOtherError<T, E> for Result<T, E> {
     fn te(self) -> Result<T, TransferError<E>> {
         self.map_err(|e| TransferError::SpiError(e))
     }
+
+    fn txe(self) -> Result<T, TxError<E>> {
+        self.map_err(|e| TxError::SpiError(e))
+    }
 }
diff --git a/src/internal_state.rs b/src/internal_state.rs
index 43dab00dfb6a93c4686fc49ae3588b3ffe5c2974..3bdb772f50b7330dd79c4ec4a0823c9342d4c71c 100644
--- a/src/internal_state.rs
+++ b/src/internal_state.rs
@@ -11,5 +11,6 @@ pub enum InternalState<const PACKET_LEN: usize> {
     Tx {
         data: [u8; PACKET_LEN],
         i: usize,
+        len: usize,
     },
 }
diff --git a/src/lib.rs b/src/lib.rs
index afcf228a6d64139e1c8bbbf6a6c399b351126d87..9943a6fb8ac39f1b15bb9aeb9c92e2d0aca05b6a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,6 +5,7 @@ mod consts;
 pub mod error;
 mod internal_radio;
 mod internal_state;
+pub mod rx;
 pub(crate) mod state;
 
 use core::{convert::Infallible, fmt::Debug};
@@ -14,25 +15,26 @@ use embedded_hal::{
 };
 
 use consts::*;
-use error::{RfError, SpiErrorToOtherError, TransferError};
+use error::{RfError, SpiErrorToOtherError, TransferError, TxError};
 use internal_state::InternalState;
+use rx::RxPacket;
 use state::State;
 
 use crate::internal_radio::InternalRadio;
 
-pub struct Rf4463<const PACKET_LEN: usize, Spi, SdnPin, CsPin, Delay> {
+pub struct Rf4463<const MAX_PACKET_LEN: usize, Spi, SdnPin, CsPin, Delay> {
     radio: InternalRadio<Spi, SdnPin, CsPin, Delay>,
-    state: InternalState<PACKET_LEN>,
+    state: InternalState<MAX_PACKET_LEN>,
     rx_forever: bool,
 }
 
 impl<
-        const PACKET_LEN: usize,
+        const MAX_PACKET_LEN: usize,
         Spi: Transfer<u8>,
         SdnPin: OutputPin<Error = Infallible>,
         CsPin: OutputPin<Error = Infallible>,
         Delay: DelayUs<u16>,
-    > Rf4463<PACKET_LEN, Spi, SdnPin, CsPin, Delay>
+    > Rf4463<MAX_PACKET_LEN, Spi, SdnPin, CsPin, Delay>
 where
     Spi::Error: Debug,
 {
@@ -44,7 +46,7 @@ where
         config: &mut [u8],
     ) -> Result<Self, RfError<Spi::Error>> {
         assert!(
-            PACKET_LEN < 8192,
+            MAX_PACKET_LEN < 8192,
             "Packet length cannot be above 8191 bytes"
         );
 
@@ -78,7 +80,7 @@ where
         self.radio.clear_ph_and_modem_interrupts()?;
 
         self.state = InternalState::Rx {
-            data: [0; PACKET_LEN],
+            data: [0; MAX_PACKET_LEN],
             i: 0,
             received: false,
             rssi: None,
@@ -88,8 +90,8 @@ where
             START_RX,
             0,
             0,
-            (PACKET_LEN >> 8).try_into().unwrap(),
-            (PACKET_LEN & 0xff).try_into().unwrap(),
+            (MAX_PACKET_LEN >> 8).try_into().unwrap(),
+            (MAX_PACKET_LEN & 0xff).try_into().unwrap(),
             State::Rx.into(),
             if rx_forever {
                 State::Rx.into()
@@ -104,26 +106,26 @@ where
         Ok(())
     }
 
-    pub fn finish_rx(&mut self) -> Result<Option<([u8; PACKET_LEN], f64)>, Spi::Error> {
+    pub fn finish_rx(&mut self) -> Result<Option<RxPacket<MAX_PACKET_LEN>>, Spi::Error> {
         let pkt = match self.state {
             InternalState::Rx {
                 data,
                 received,
                 i,
                 rssi,
-            } if i == PACKET_LEN && received => {
+            } if received => {
                 let rssi = match rssi {
                     Some(x) => x,
                     None => self.get_rssi()?,
                 };
 
-                let ret = Some((data, rssi));
+                let ret = Some(RxPacket::new(data, i, rssi));
 
                 if self.rx_forever {
                     self.radio.clear_ph_and_modem_interrupts()?;
 
                     self.state = InternalState::Rx {
-                        data: [0; PACKET_LEN],
+                        data: [0; MAX_PACKET_LEN],
                         i: 0,
                         received: false,
                         rssi: None,
@@ -141,31 +143,46 @@ where
         Ok(pkt)
     }
 
-    pub fn start_tx(&mut self, mut data: [u8; PACKET_LEN]) -> Result<(), Spi::Error> {
-        self.radio.clear_fifo()?;
-        self.radio.clear_ph_and_modem_interrupts()?;
+    pub fn start_tx(&mut self, data: &[u8]) -> Result<(), TxError<Spi::Error>> {
+        let len = data.len();
+        if len > MAX_PACKET_LEN {
+            return Err(TxError::TooMuchData);
+        }
+
+        self.radio.clear_fifo().txe()?;
+        self.radio.clear_ph_and_modem_interrupts().txe()?;
 
         // 128-byte TX buffer
         let i = data.len().min(128);
+        let mut segment = [0; 128];
+        segment[..i].copy_from_slice(&data[..i]);
 
         self.radio.with_cs(|s| {
-            s.spi_transfer_byte(WRITE_TX_FIFO)?;
-            s.spi.transfer(&mut data[0..i])?;
+            s.spi_transfer_byte(WRITE_TX_FIFO).txe()?;
+            s.spi.transfer(&mut segment[..i]).txe()?;
 
             Ok(())
         })?;
 
-        self.radio.send_command::<0>(&mut [
-            START_TX,
-            0,
-            u8::from(State::Sleep) << 4,
-            (PACKET_LEN >> 8).try_into().unwrap(),
-            (PACKET_LEN & 0xff).try_into().unwrap(),
-            0,
-            0,
-        ])?;
-
-        self.state = InternalState::Tx { data, i };
+        self.radio
+            .send_command::<0>(&mut [
+                START_TX,
+                0,
+                u8::from(State::Sleep) << 4,
+                (MAX_PACKET_LEN >> 8).try_into().unwrap(),
+                (MAX_PACKET_LEN & 0xff).try_into().unwrap(),
+                0,
+                0,
+            ])
+            .txe()?;
+
+        let mut padded_data = [0; MAX_PACKET_LEN];
+        padded_data[0..len].copy_from_slice(data);
+        self.state = InternalState::Tx {
+            data: padded_data,
+            i,
+            len,
+        };
 
         Ok(())
     }
@@ -219,12 +236,12 @@ where
             _ => return Ok(()),
         };
 
-        let len: usize = self.radio.rx_fifo_len().te()?.into();
-        if len == 0 {
+        let fifo_len: usize = self.radio.rx_fifo_len().te()?.into();
+        if fifo_len == 0 {
             return Ok(());
         }
 
-        if len + *i > PACKET_LEN {
+        if fifo_len + *i > MAX_PACKET_LEN {
             return Err(TransferError::TooMuchData);
         }
 
@@ -232,7 +249,7 @@ where
             return Err(TransferError::FifoOverflow);
         }
 
-        let data = &mut data[*i..(*i + len)];
+        let data = &mut data[*i..(*i + fifo_len)];
         self.radio
             .with_cs(|s| {
                 s.spi_transfer_byte(READ_RX_FIFO)?;
@@ -246,14 +263,14 @@ where
             *rssi = Some(self.radio.get_rssi().te()?)
         }
 
-        *i += len;
+        *i += fifo_len;
 
         Ok(())
     }
 
     fn tx_step(&mut self) -> Result<(), TransferError<Spi::Error>> {
         let (data, i) = match &mut self.state {
-            InternalState::Tx { data, i, .. } => (data, i),
+            InternalState::Tx { data, i, len } => (&mut data[0..*len], i),
             _ => return Ok(()),
         };
 
diff --git a/src/rx.rs b/src/rx.rs
new file mode 100644
index 0000000000000000000000000000000000000000..fc40823a27b160a4f6fe568d8b782070cd822ce6
--- /dev/null
+++ b/src/rx.rs
@@ -0,0 +1,19 @@
+pub struct RxPacket<const N: usize> {
+    data: [u8; N],
+    i: usize,
+    rssi: f64,
+}
+
+impl<const N: usize> RxPacket<N> {
+    pub(crate) fn new(data: [u8; N], i: usize, rssi: f64) -> Self {
+        Self { data, i, rssi }
+    }
+
+    pub fn data(&self) -> &[u8] {
+        &self.data[..self.i]
+    }
+
+    pub fn rssi(&self) -> f64 {
+        self.rssi
+    }
+}