Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into dest-handler-acked-mode
Browse files Browse the repository at this point in the history
  • Loading branch information
robamu committed Oct 30, 2023
2 parents f75d566 + 5400e7f commit 4480bc4
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 5 deletions.
199 changes: 199 additions & 0 deletions tests/cfdp/test_dest_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,205 @@ def _generic_verify_transfer_completion(
fsm_res = self.dest_handler.state_machine()
if self.expected_mode == TransmissionMode.UNACKNOWLEDGED:
self._state_checker(fsm_res, 0, CfdpState.IDLE, TransactionStep.IDLE)
eof_pdu = EofPdu(
file_size=file_size,
file_checksum=crc32,
pdu_conf=self.src_pdu_conf,
)
self.dest_handler.insert_packet(eof_pdu)
fsm_res = self.dest_handler.state_machine()
self._state_checker(fsm_res, False, CfdpState.IDLE, TransactionStep.IDLE)
self._check_eof_recv_indication(fsm_res)
self._check_finished_recv_indication_success(fsm_res)

def test_small_file_reception_with_closure(self):
self.closure_requested = True
data = "Hello World\n".encode()
with open(self.src_file_path, "wb") as of:
of.write(data)
crc32_func = mkPredefinedCrcFun("crc32")
crc32 = struct.pack("!I", crc32_func(data))
file_size = self.src_file_path.stat().st_size
self._source_simulator_transfer_init_with_metadata(
checksum=ChecksumType.CRC_32,
file_size=file_size,
file_path=self.src_file_path.as_posix(),
)
with open(self.src_file_path, "rb") as rf:
read_data = rf.read()
fd_params = FileDataParams(file_data=read_data, offset=0)
file_data_pdu = FileDataPdu(params=fd_params, pdu_conf=self.src_pdu_conf)
self.dest_handler.insert_packet(file_data_pdu)
fsm_res = self.dest_handler.state_machine()
self._state_checker(
fsm_res,
False,
CfdpState.BUSY_CLASS_1_NACKED,
TransactionStep.RECEIVING_FILE_DATA,
)
eof_pdu = EofPdu(
file_size=file_size,
file_checksum=crc32,
pdu_conf=self.src_pdu_conf,
)
self.dest_handler.insert_packet(eof_pdu)
fsm_res = self.dest_handler.state_machine()
self._state_checker(
fsm_res,
True,
CfdpState.BUSY_CLASS_1_NACKED,
TransactionStep.SENDING_FINISHED_PDU,
)
self._check_eof_recv_indication(fsm_res)
self._check_finished_recv_indication_success(fsm_res)
self._assert_generic_no_error_finished_pdu(fsm_res)
fsm_res = self.dest_handler.state_machine()
self._state_checker(
fsm_res,
False,
CfdpState.IDLE,
TransactionStep.IDLE,
)

def test_larger_file_reception(self):
# This tests generates two file data PDUs, but the second one does not have a
# full segment length
file_info = self.random_data_two_file_segments()
self._state_checker(None, False, CfdpState.IDLE, TransactionStep.IDLE)
self._source_simulator_transfer_init_with_metadata(
checksum=ChecksumType.CRC_32,
file_size=file_info.file_size,
file_path=self.src_file_path.as_posix(),
)
fsm_res = self.pass_file_segment(
file_info.rand_data[0 : self.file_segment_len], 0
)
self._state_checker(
fsm_res,
False,
CfdpState.BUSY_CLASS_1_NACKED,
TransactionStep.RECEIVING_FILE_DATA,
)
self.cfdp_user.file_segment_recv_indication.assert_called()
self.assertEqual(self.cfdp_user.file_segment_recv_indication.call_count, 1)
seg_recv_params = cast(
FileSegmentRecvdParams,
self.cfdp_user.file_segment_recv_indication.call_args.args[0],
)
self.assertEqual(seg_recv_params.transaction_id, self.transaction_id)
fd_params = FileDataParams(
file_data=file_info.rand_data[self.file_segment_len :],
offset=self.file_segment_len,
)
file_data_pdu = FileDataPdu(params=fd_params, pdu_conf=self.src_pdu_conf)
self.dest_handler.insert_packet(file_data_pdu)
fsm_res = self.dest_handler.state_machine()
self._state_checker(
fsm_res,
False,
CfdpState.BUSY_CLASS_1_NACKED,
TransactionStep.RECEIVING_FILE_DATA,
)
eof_pdu = EofPdu(
file_size=file_info.file_size,
file_checksum=file_info.crc32,
pdu_conf=self.src_pdu_conf,
)
self.dest_handler.insert_packet(eof_pdu)
fsm_res = self.dest_handler.state_machine()
self._state_checker(fsm_res, False, CfdpState.IDLE, TransactionStep.IDLE)
self._check_eof_recv_indication(fsm_res)
self._check_finished_recv_indication_success(fsm_res)

def _generic_check_limit_test(self, file_data: bytes):
with open(self.src_file_path, "wb") as of:
of.write(file_data)
crc32_func = mkPredefinedCrcFun("crc32")
crc32 = struct.pack("!I", crc32_func(file_data))
file_size = self.src_file_path.stat().st_size
self._source_simulator_transfer_init_with_metadata(
checksum=ChecksumType.CRC_32,
file_size=file_size,
file_path=self.src_file_path.as_posix(),
)
eof_pdu = EofPdu(
file_size=file_size,
file_checksum=crc32,
pdu_conf=self.src_pdu_conf,
)
self.dest_handler.insert_packet(eof_pdu)
fsm_res = self.dest_handler.state_machine()
self._state_checker(
fsm_res,
False,
CfdpState.BUSY_CLASS_1_NACKED,
TransactionStep.RECV_FILE_DATA_WITH_CHECK_LIMIT_HANDLING,
)
self._check_eof_recv_indication(fsm_res)

def test_check_timer_mechanism(self):
data = "Hello World\n".encode()
self._generic_check_limit_test(data)
fd_params = FileDataParams(
file_data=data,
offset=0,
)
file_data_pdu = FileDataPdu(params=fd_params, pdu_conf=self.src_pdu_conf)
self.dest_handler.insert_packet(file_data_pdu)
fsm_res = self.dest_handler.state_machine()
self._state_checker(
fsm_res,
False,
CfdpState.BUSY_CLASS_1_NACKED,
TransactionStep.RECV_FILE_DATA_WITH_CHECK_LIMIT_HANDLING,
)
self.assertFalse(self.dest_handler.packets_ready)
time.sleep(self.timeout_check_limit_handling_ms * 1.15 / 1000.0)
fsm_res = self.dest_handler.state_machine()
self._state_checker(
fsm_res,
False,
CfdpState.IDLE,
TransactionStep.IDLE,
)

def test_check_limit_reached(self):
data = "Hello World\n".encode()
self._generic_check_limit_test(data)
# Check counter should be incremented by one.
time.sleep(self.timeout_check_limit_handling_ms * 1.15 / 1000.0)
fsm_res = self.dest_handler.state_machine()
self._state_checker(
fsm_res,
False,
CfdpState.BUSY_CLASS_1_NACKED,
TransactionStep.RECV_FILE_DATA_WITH_CHECK_LIMIT_HANDLING,
)
self.assertEqual(self.dest_handler.current_check_counter, 1)
# Check counter reaches 2, check limit fault should be declared
time.sleep(self.timeout_check_limit_handling_ms * 1.15 / 1000.0)
fsm_res = self.dest_handler.state_machine()
self._state_checker(
fsm_res,
False,
CfdpState.BUSY_CLASS_1_NACKED,
TransactionStep.RECV_FILE_DATA_WITH_CHECK_LIMIT_HANDLING,
)
self.assertEqual(self.dest_handler.current_check_counter, 2)
# Check counter has maximum value, check limit fault should be declared
time.sleep(self.timeout_check_limit_handling_ms * 1.15 / 1000.0)
fsm_res = self.dest_handler.state_machine()
self._state_checker(
fsm_res,
False,
CfdpState.IDLE,
TransactionStep.IDLE,
)

def random_data_two_file_segments(self):
if sys.version_info >= (3, 9):
rand_data = random.randbytes(round(self.file_segment_len * 1.3))
>>>>>>> origin/main
else:
self._state_checker(
fsm_res, 0, CfdpState.BUSY, TransactionStep.WAITING_FOR_FINISHED_ACK
Expand Down
2 changes: 1 addition & 1 deletion tmtccmd/cfdp/handler/dest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1068,10 +1068,10 @@ def _check_limit_handling(self):
if self._checksum_verify():
self._file_transfer_complete_transition()
return
self._params.current_check_count += 1
if self._params.current_check_count == self._params.remote_cfg.check_limit:
self._declare_fault(ConditionCode.CHECK_LIMIT_REACHED)
else:
self._params.current_check_count += 1
self._params.check_timer.reset()

def _declare_fault(self, cond: ConditionCode) -> FaultHandlerCode:
Expand Down
9 changes: 5 additions & 4 deletions tmtccmd/cfdp/mib.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ class RemoteEntityCfg:
be used for positive acknowledgement procedures as specified in CFDP chapter 4.7. The sending
entity will start the timer for any PDUs where an acknowledgment is required (e.g. EOF PDU).
Once the expected ACK response has not been received for that interval, as counter will be
incremented and the timer will be reset. Once the counter reached the
incremented and the timer will be reset. Once the counter exceeds the
``positive_ack_timer_expiration_limit``, a Positive ACK Limit Reached fault will be declared.
**Notes on Deferred Lost Segment Procedures**
Expand Down Expand Up @@ -222,13 +222,14 @@ class RemoteEntityCfg:
check_limit
this timer determines the expiry period for incrementing a check counter after an EOF PDU
is received for an incomplete file transfer. This allows out-of-order reception of file
data PDUs and EOF PDUs. Also see 4.6.3.3 of the CFDP standard. Defaults to 2.
data PDUs and EOF PDUs. Also see 4.6.3.3 of the CFDP standard. Defaults to 2, so the
check limit timer may expire twice.
positive_ack_timer_interval_seconds
See the notes on the Positive Acknowledgment Procedures inside the class documentation.
Expected as floating point seconds. Defaults to 10 seconds.
positive_ack_timer_expiration_limit
See the notes on the Positive Acknowledgment Procedures inside the class documentation.
Defaults to 2.
Defaults to 2, so the timer may expire twice.
immediate_nak_mode:
Specifies whether a NAK sequence should be issued immediately when a file data gap or
lost metadata is detected in the acknowledged mode. Defaults to True.
Expand All @@ -237,7 +238,7 @@ class RemoteEntityCfg:
Expected as floating point seconds. Defaults to 10 seconds.
nak_timer_expiration_limit:
See the notes on the Deferred Lost Segment Procedure inside the class documentation.
Defaults to 3.
Defaults to 3, so the timer may expire three times.
"""

Expand Down

0 comments on commit 4480bc4

Please sign in to comment.