@@ -238,17 +238,17 @@ TEST(TINY_FD_ABM, ABM_RecieveOutOfOrderIFrames)
238238 CHECK_EQUAL (0x7E , outBuffer[7 ]); // Flag
239239}
240240
241- TEST (TINY_FD_ABM, ABM_SendSABMOnIFrameIfDisconnected )
241+ TEST (TINY_FD_ABM, ABM_SendDMOnIFrameIfDisconnected )
242242{
243- // If we are disconnected, we should send SABM frame on I-frame
243+ // Per HDLC ABM spec, if we are disconnected and receive I-frame, send DM (Disconnect Mode)
244244 auto read_result = tiny_fd_on_rx_data (handle, (uint8_t *)" \x7E\x03\x00\x11\x7E " , 5 ); // I-frame in order
245245 CHECK_EQUAL (TINY_SUCCESS, read_result);
246246 auto len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
247247 CHECK_EQUAL (4 , len);
248- // Check SABM frame
248+ // DM control = (0x0C | 0x03) | P_BIT = 0x0F | 0x10 = 0x1F
249249 CHECK_EQUAL (0x7E , outBuffer[0 ]); // Flag
250- CHECK_EQUAL (0x03 , outBuffer[1 ]); // Address field - CR bit must be cleared
251- CHECK_EQUAL (0x3F , outBuffer[2 ]); // SABM packet
250+ CHECK_EQUAL (0x01 , outBuffer[1 ]); // Address field - CR bit cleared (response)
251+ CHECK_EQUAL (0x1F , outBuffer[2 ]); // DM packet with P/F bit
252252 CHECK_EQUAL (0x7E , outBuffer[3 ]); // Flag
253253}
254254
@@ -419,4 +419,97 @@ TEST(TINY_FD_ABM, ABM_CheckReceiveReadyWithCommandBitCleared)
419419 CHECK_EQUAL (TINY_SUCCESS, read_result);
420420 int len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
421421 CHECK_EQUAL (0 , len); // We should have sent RR frame
422+ }
423+
424+ TEST (TINY_FD_ABM, ABM_SendDMOnSFrameIfDisconnected)
425+ {
426+ // Per HDLC ABM spec, if we are disconnected and receive S-frame, send DM
427+ // RR frame with N(R)=0: control = 0x01
428+ auto read_result = tiny_fd_on_rx_data (handle, (uint8_t *)" \x7E\x03\x01\x7E " , 4 ); // RR S-frame
429+ CHECK_EQUAL (TINY_SUCCESS, read_result);
430+ auto len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
431+ CHECK_EQUAL (4 , len);
432+ // DM control = (0x0C | 0x03) | P_BIT = 0x0F | 0x10 = 0x1F
433+ CHECK_EQUAL (0x7E , outBuffer[0 ]); // Flag
434+ CHECK_EQUAL (0x01 , outBuffer[1 ]); // Address field - CR bit cleared (response)
435+ CHECK_EQUAL (0x1F , outBuffer[2 ]); // DM packet with P/F bit
436+ CHECK_EQUAL (0x7E , outBuffer[3 ]); // Flag
437+ }
438+
439+ TEST (TINY_FD_ABM, ABM_FRMRReceiveTriggersReconnect)
440+ {
441+ // FRMR should trigger disconnection and SABM reconnection attempt
442+ establishConnection ();
443+ CHECK (connected);
444+ // Send FRMR frame: control = HDLC_U_FRAME_TYPE_FRMR | HDLC_U_FRAME_BITS = 0x84 | 0x03 = 0x87
445+ auto read_result = tiny_fd_on_rx_data (handle, (uint8_t *)" \x7E\x01\x87\x00\x00\x7E " , 6 ); // FRMR with 2 info bytes
446+ CHECK_EQUAL (TINY_SUCCESS, read_result);
447+ CHECK (!connected); // Should have disconnected
448+ // Should get SABM reconnection attempt
449+ auto len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
450+ CHECK_EQUAL (4 , len);
451+ CHECK_EQUAL (0x7E , outBuffer[0 ]); // Flag
452+ CHECK_EQUAL (0x03 , outBuffer[1 ]); // Address field - CR bit set (command)
453+ CHECK_EQUAL (0x3F , outBuffer[2 ]); // SABM packet (0x2C | 0x13 with P bit = 0x2F | 0x10 = 0x3F)
454+ CHECK_EQUAL (0x7E , outBuffer[3 ]); // Flag
455+ }
456+
457+ TEST (TINY_FD_ABM, ABM_RSETResetsSequenceNumbers)
458+ {
459+ establishConnection ();
460+ // Send some I-frames to advance sequence numbers
461+ auto read_result = tiny_fd_on_rx_data (handle, (uint8_t *)" \x7E\x03\x00\x11\x7E " , 5 ); // I-frame N(S)=0
462+ CHECK_EQUAL (TINY_SUCCESS, read_result);
463+ // Drain RR response
464+ int len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
465+ CHECK (len > 0 );
466+ // Now send RSET: control = HDLC_U_FRAME_TYPE_RSET | HDLC_U_FRAME_BITS = 0x8C | 0x03 = 0x8F
467+ read_result = tiny_fd_on_rx_data (handle, (uint8_t *)" \x7E\x03\x8F\x7E " , 4 ); // RSET frame
468+ CHECK_EQUAL (TINY_SUCCESS, read_result);
469+ // Should respond with UA
470+ len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
471+ CHECK_EQUAL (4 , len);
472+ CHECK_EQUAL (0x7E , outBuffer[0 ]); // Flag
473+ CHECK_EQUAL (0x01 , outBuffer[1 ]); // Address field - CR bit cleared (response)
474+ CHECK_EQUAL (0x73 , outBuffer[2 ]); // UA packet
475+ CHECK_EQUAL (0x7E , outBuffer[3 ]); // Flag
476+ // After RSET, send I-frame N(S)=0 again — should succeed since V(R) was reset to 0
477+ read_result = tiny_fd_on_rx_data (handle, (uint8_t *)" \x7E\x03\x00\x22\x7E " , 5 ); // I-frame N(S)=0
478+ CHECK_EQUAL (TINY_SUCCESS, read_result);
479+ len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
480+ CHECK (len > 0 );
481+ // Should get RR with N(R)=1 confirming the frame was accepted
482+ CHECK_EQUAL (0x7E , outBuffer[0 ]); // Flag
483+ CHECK_EQUAL (0x01 , outBuffer[1 ]); // Address field
484+ CHECK_EQUAL (0x31 , outBuffer[2 ]); // RR with N(R)=1
485+ CHECK_EQUAL (0x7E , outBuffer[3 ]); // Flag
486+ }
487+
488+ TEST (TINY_FD_ABM, ABM_RNRPausesTransmission)
489+ {
490+ establishConnection ();
491+ // Send I-frame first to advance sequence
492+ auto read_result = tiny_fd_on_rx_data (handle, (uint8_t *)" \x7E\x03\x00\x11\x7E " , 5 ); // I-frame
493+ CHECK_EQUAL (TINY_SUCCESS, read_result);
494+ // Drain RR
495+ int len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
496+ CHECK (len > 0 );
497+ // Send RNR S-frame: control = HDLC_S_FRAME_BITS | HDLC_S_FRAME_TYPE_RNR | (N(R)<<5)
498+ // = 0x01 | 0x04 | (1<<5) = 0x25
499+ read_result = tiny_fd_on_rx_data (handle, (uint8_t *)" \x7E\x03\x25\x7E " , 4 ); // RNR with N(R)=1
500+ CHECK_EQUAL (TINY_SUCCESS, read_result);
501+ // RNR should be accepted without error (confirms N(R)=1)
502+ // No response frame should be generated (RNR doesn't have CR bit set as command here)
503+ len = tiny_fd_get_tx_data (handle, outBuffer.data (), outBuffer.size (), 100 );
504+ CHECK_EQUAL (0 , len);
505+ }
506+
507+ TEST (TINY_FD_ABM, ABM_DMReceiveDisconnects)
508+ {
509+ establishConnection ();
510+ CHECK (connected);
511+ // Receive DM from peer: control = HDLC_U_FRAME_TYPE_DM | HDLC_U_FRAME_BITS = 0x0C | 0x03 = 0x0F
512+ auto read_result = tiny_fd_on_rx_data (handle, (uint8_t *)" \x7E\x01\x0F\x7E " , 4 ); // DM frame
513+ CHECK_EQUAL (TINY_SUCCESS, read_result);
514+ CHECK (!connected); // Should have disconnected
422515}
0 commit comments