@@ -693,4 +693,115 @@ TEST(TINY_FD_ABM, ABM_UIFrameReceiveDisconnected)
693693 CHECK (s_ui_received);
694694 CHECK_EQUAL (1 , s_ui_len);
695695 CHECK_EQUAL (0x42 , s_ui_data[0 ]);
696+ }
697+
698+ // ==========================================================================
699+ // SREJ (Selective Reject) Tests
700+ // ==========================================================================
701+
702+ TEST (TINY_FD_ABM, ABM_SREJRetransmitsSingleFrame)
703+ {
704+ establishConnection ();
705+ // Queue one I-frame
706+ int result = tiny_fd_send_packet_to (handle, TINY_FD_PRIMARY_ADDR, (const void *)" \xAA " , 1 , 1000 );
707+ CHECK_EQUAL (TINY_SUCCESS, result);
708+ // Send the I-frame out
709+ int len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
710+ CHECK (len > 0 );
711+ uint8_t sent_control = outBuffer[2 ];
712+ CHECK_EQUAL (0x00 , sent_control & 0x01 ); // I-frame (bit 0 = 0)
713+ CHECK_EQUAL (0x00 , (sent_control >> 1 ) & 0x07 ); // N(S) = 0
714+
715+ // Peer sends SREJ for frame 0: address=0x03 (command), control=0x0D (SREJ, N(R)=0)
716+ auto read_result = tiny_fd_on_rx_data (handle, (uint8_t *)" \x7E\x03\x0D\x7E " , 4 );
717+ CHECK_EQUAL (TINY_SUCCESS, read_result);
718+
719+ // Should retransmit frame 0
720+ len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
721+ CHECK (len > 0 );
722+ CHECK_EQUAL (0x00 , outBuffer[2 ] & 0x01 ); // I-frame
723+ CHECK_EQUAL (0x00 , (outBuffer[2 ] >> 1 ) & 0x07 ); // N(S) = 0 (retransmitted)
724+ CHECK_EQUAL (0xAA , outBuffer[3 ]); // Original payload preserved
725+ }
726+
727+ TEST (TINY_FD_ABM, ABM_SREJRetransmitsOnlyRequestedFrame)
728+ {
729+ establishConnection ();
730+ // Queue two I-frames
731+ int result = tiny_fd_send_packet_to (handle, TINY_FD_PRIMARY_ADDR, (const void *)" \xAA " , 1 , 1000 );
732+ CHECK_EQUAL (TINY_SUCCESS, result);
733+ result = tiny_fd_send_packet_to (handle, TINY_FD_PRIMARY_ADDR, (const void *)" \xBB " , 1 , 1000 );
734+ CHECK_EQUAL (TINY_SUCCESS, result);
735+
736+ // Send both I-frames out
737+ int len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
738+ CHECK (len > 0 );
739+ int len2 = tiny_fd_get_tx_data (handle, outBuffer.data () + len, outBuffer.size () - len, 100 );
740+ CHECK (len2 > 0 );
741+
742+ // Peer sends SREJ for frame 0 only: control=0x0D (SREJ, N(R)=0)
743+ auto read_result = tiny_fd_on_rx_data (handle, (uint8_t *)" \x7E\x03\x0D\x7E " , 4 );
744+ CHECK_EQUAL (TINY_SUCCESS, read_result);
745+
746+ // Get retransmitted frame - should be only frame 0
747+ len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
748+ CHECK (len > 0 );
749+ CHECK_EQUAL (0x00 , (outBuffer[2 ] >> 1 ) & 0x07 ); // N(S) = 0
750+
751+ // No more frames should be available (frame 1 was NOT retransmitted)
752+ len2 = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
753+ CHECK_EQUAL (0 , len2); // Nothing else to send
754+ }
755+
756+ TEST (TINY_FD_ABM, ABM_SREJForSecondFrame)
757+ {
758+ establishConnection ();
759+ // Queue two I-frames
760+ int result = tiny_fd_send_packet_to (handle, TINY_FD_PRIMARY_ADDR, (const void *)" \xAA " , 1 , 1000 );
761+ CHECK_EQUAL (TINY_SUCCESS, result);
762+ result = tiny_fd_send_packet_to (handle, TINY_FD_PRIMARY_ADDR, (const void *)" \xBB " , 1 , 1000 );
763+ CHECK_EQUAL (TINY_SUCCESS, result);
764+
765+ // Send both I-frames out
766+ int len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
767+ len += tiny_fd_get_tx_data (handle, outBuffer.data () + len, outBuffer.size () - len, 100 );
768+
769+ // Peer acks frame 0, sends SREJ for frame 1: control=0x2D (SREJ, N(R)=1)
770+ // N(R)=1 means: confirmed frame 0, please retransmit frame 1
771+ auto read_result = tiny_fd_on_rx_data (handle, (uint8_t *)" \x7E\x03\x2D\x7E " , 4 );
772+ CHECK_EQUAL (TINY_SUCCESS, read_result);
773+
774+ // Get retransmitted frame - should be frame 1 with payload 0xBB
775+ len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
776+ CHECK (len > 0 );
777+ CHECK_EQUAL (0x01 , (outBuffer[2 ] >> 1 ) & 0x07 ); // N(S) = 1
778+ CHECK_EQUAL (0xBB , outBuffer[3 ]); // Frame 1 payload
779+ }
780+
781+ TEST (TINY_FD_ABM, ABM_REJRetransmitsAllFromNR)
782+ {
783+ // Compare with REJ behavior: REJ retransmits ALL frames from N(R) onward
784+ establishConnection ();
785+ // Queue two I-frames
786+ int result = tiny_fd_send_packet_to (handle, TINY_FD_PRIMARY_ADDR, (const void *)" \xAA " , 1 , 1000 );
787+ CHECK_EQUAL (TINY_SUCCESS, result);
788+ result = tiny_fd_send_packet_to (handle, TINY_FD_PRIMARY_ADDR, (const void *)" \xBB " , 1 , 1000 );
789+ CHECK_EQUAL (TINY_SUCCESS, result);
790+
791+ // Send both I-frames out
792+ int len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
793+ len += tiny_fd_get_tx_data (handle, outBuffer.data () + len, outBuffer.size () - len, 100 );
794+
795+ // Peer sends REJ for frame 0: control=0x09 (REJ, N(R)=0)
796+ auto read_result = tiny_fd_on_rx_data (handle, (uint8_t *)" \x7E\x03\x09\x7E " , 4 );
797+ CHECK_EQUAL (TINY_SUCCESS, read_result);
798+
799+ // REJ should retransmit BOTH frames: frame 0 and frame 1
800+ len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
801+ CHECK (len > 0 );
802+ CHECK_EQUAL (0x00 , (outBuffer[2 ] >> 1 ) & 0x07 ); // N(S) = 0 (first retransmit)
803+
804+ int len2 = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
805+ CHECK (len2 > 0 );
806+ CHECK_EQUAL (0x01 , (outBuffer[2 ] >> 1 ) & 0x07 ); // N(S) = 1 (second retransmit)
696807}
0 commit comments