obcsim/msp_obc_link.c
struct msp_response msp_recv_header_frame(msp_link_t *lnk)
{
	int code;
	struct msp_response r;
	struct msp_obc_frame frame;
	unsigned long len;

	if (lnk == NULL || lnk->buffer == NULL)
		return msp_response_error(MSP_OBC_ERR_NULL_POINTER);

	if (lnk->next_action != MSP_LINK_ACTION_RX_HEADER) {
		lnk->corrupt_frame_count += 1;
		return msp_response_error(MSP_OBC_ERR_INVALID_ACTION);
	}

	code = msp_i2c_read(lnk->slave_address, lnk->buffer, 9);
	if (code) {
		lnk->corrupt_frame_count += 1;
		return msp_response_error(MSP_OBC_ERR_I2C_ERROR);
	}

	frame = msp_obc_decode_frame(lnk, lnk->buffer, 9);
	if (frame.type != MSP_OBC_FRAME_HEADER) {
		lnk->corrupt_frame_count += 1;
		msp_debug("Expected header frame, got data frame or FCS mismatch");
		return msp_response_error(MSP_OBC_ERR_INVALID_FRAME);
	}

	if (frame.opcode == MSP_OP_NULL) {
		/* NULL frame always resets transaction */
		r = msp_response_aborted(lnk);
		msp_set_as_ready(lnk);
		msp_debug_hex("Aborting transaction with opcode: ", r.opcode);
		return r;
	}

	/* Take no further action if the experiment is busy */
	if (frame.opcode == MSP_OP_EXP_BUSY)
		return msp_response_busy();

	switch (lnk->state) {
	case MSP_LINK_STATE_SEND_TX_HEADER:
	case MSP_LINK_STATE_SEND_TX_DATA:
		/* We should get an ACK here */
		if (frame.opcode == MSP_OP_T_ACK) {
			/* Transaction Complete */
			msp_seqflags_set(&lnk->flags, lnk->opcode, lnk->transaction_id);
			if (lnk->processed_length == lnk->total_length) {
				r = msp_response_successful(lnk);
				msp_set_as_ready(lnk);
			} else {
				r = msp_response_error(MSP_OBC_ERR_DATA_NOT_SENT);
				msp_set_as_ready(lnk);
			}
		} else if (frame.opcode == MSP_OP_F_ACK) {
			/* Treat the F_ACK differently depending on the state */
			len = msp_next_data_length(lnk);
			if (lnk->state == MSP_LINK_STATE_SEND_TX_HEADER) {
				/* Acknowledged, prepare for the first data frame */
				lnk->state = MSP_LINK_STATE_SEND_TX_DATA;
				lnk->next_action = MSP_LINK_ACTION_TX_DATA;
				lnk->frame_id = frame.id ^ 1;
				r = msp_response_ok();
			} else if (len < (lnk->total_length - lnk->processed_length)) {
				/* Acknowledged, setup data next frame */
				lnk->next_action = MSP_LINK_ACTION_TX_DATA;
				lnk->frame_id = frame.id ^ 1;
				r = msp_response_ok();
			} else {
				/* We should've gotten a T_ACK here! */
				lnk->corrupt_frame_count += 1;
				msp_debug("Got an F_ACK when we should have gotten a T_ACK");
				r = msp_response_error(MSP_OBC_ERR_INVALID_FRAME);
			}
		} else {
			/* The only frames that we should received when sending data are
			 * ACK frames. */
			lnk->corrupt_frame_count += 1;
			msp_debug("Did not get an ACK frame when sending data");
			r = msp_response_error(MSP_OBC_ERR_INVALID_FRAME);
		}
		break;
	case MSP_LINK_STATE_REQ_RX_RESPONSE:
		/* The only header with should get in a request transaction is a
		 * response header. */
		if (frame.opcode == MSP_OP_EXP_SEND) {
			lnk->state = MSP_LINK_STATE_REQ_RX_DATA;
			lnk->next_action = MSP_LINK_ACTION_TX_HEADER;
			lnk->transaction_id = frame.id;
			lnk->frame_id = frame.id;
			lnk->processed_length = 0;
			/* first check if this is a duplicate transaction */
			if (msp_seqflags_is_set(&lnk->flags, lnk->opcode, frame.id)) {
				/* Just pretend that the experiment is sending 0 data if this
				 * is a duplicate transaction */
				lnk->total_length = 0;
			} else {
				lnk->total_length = frame.dl;
			}
			r = msp_response_ok();
		} else {
			/* Something went wrong... */
			lnk->corrupt_frame_count += 1;
			r = msp_response_error(MSP_OBC_ERR_INVALID_FRAME);
		}
		break;
	default:
		r = msp_response_error(MSP_OBC_ERR_INVALID_STATE);
		break;
	}
	
	return r;
}
/*
 * Blocking (read over I2C)
 *
 * Receives a header frame from the experiment.
 *
 * This function will also update the state of the link.
 *
 * If the link is in an incorrect state or if any of the inputs are invalid
 * then no I2C transmission will be made and an error will be returned.
 */
Blocking (read over I2C)

Receives a header frame from the experiment.

This function will also update the state of the link.

If the link is in an incorrect state or if any of the inputs are invalid
then no I2C transmission will be made and an error will be returned.
Blocking ( read over I2C ) Receives a header frame from the experiment . This function will also update the state of the link . If the link is in an incorrect state or if any of the inputs are invalid then no I2C transmission will be made and an error will be returned .
struct msp_response msp_recv_header_frame(msp_link_t *lnk)
{
	int code;
	struct msp_response r;
	struct msp_obc_frame frame;
	unsigned long len;
	if (lnk == NULL || lnk->buffer == NULL)
		return msp_response_error(MSP_OBC_ERR_NULL_POINTER);
	if (lnk->next_action != MSP_LINK_ACTION_RX_HEADER) {
		lnk->corrupt_frame_count += 1;
		return msp_response_error(MSP_OBC_ERR_INVALID_ACTION);
	}
	code = msp_i2c_read(lnk->slave_address, lnk->buffer, 9);
	if (code) {
		lnk->corrupt_frame_count += 1;
		return msp_response_error(MSP_OBC_ERR_I2C_ERROR);
	}
	frame = msp_obc_decode_frame(lnk, lnk->buffer, 9);
	if (frame.type != MSP_OBC_FRAME_HEADER) {
		lnk->corrupt_frame_count += 1;
		msp_debug("Expected header frame, got data frame or FCS mismatch");
		return msp_response_error(MSP_OBC_ERR_INVALID_FRAME);
	}
	if (frame.opcode == MSP_OP_NULL) {
		r = msp_response_aborted(lnk);
		msp_set_as_ready(lnk);
		msp_debug_hex("Aborting transaction with opcode: ", r.opcode);
		return r;
	}
	if (frame.opcode == MSP_OP_EXP_BUSY)
		return msp_response_busy();
	switch (lnk->state) {
	case MSP_LINK_STATE_SEND_TX_HEADER:
	case MSP_LINK_STATE_SEND_TX_DATA:
		if (frame.opcode == MSP_OP_T_ACK) {
			msp_seqflags_set(&lnk->flags, lnk->opcode, lnk->transaction_id);
			if (lnk->processed_length == lnk->total_length) {
				r = msp_response_successful(lnk);
				msp_set_as_ready(lnk);
			} else {
				r = msp_response_error(MSP_OBC_ERR_DATA_NOT_SENT);
				msp_set_as_ready(lnk);
			}
		} else if (frame.opcode == MSP_OP_F_ACK) {
			len = msp_next_data_length(lnk);
			if (lnk->state == MSP_LINK_STATE_SEND_TX_HEADER) {
				lnk->state = MSP_LINK_STATE_SEND_TX_DATA;
				lnk->next_action = MSP_LINK_ACTION_TX_DATA;
				lnk->frame_id = frame.id ^ 1;
				r = msp_response_ok();
			} else if (len < (lnk->total_length - lnk->processed_length)) {
				lnk->next_action = MSP_LINK_ACTION_TX_DATA;
				lnk->frame_id = frame.id ^ 1;
				r = msp_response_ok();
			} else {
				lnk->corrupt_frame_count += 1;
				msp_debug("Got an F_ACK when we should have gotten a T_ACK");
				r = msp_response_error(MSP_OBC_ERR_INVALID_FRAME);
			}
		} else {
			lnk->corrupt_frame_count += 1;
			msp_debug("Did not get an ACK frame when sending data");
			r = msp_response_error(MSP_OBC_ERR_INVALID_FRAME);
		}
		break;
	case MSP_LINK_STATE_REQ_RX_RESPONSE:
		if (frame.opcode == MSP_OP_EXP_SEND) {
			lnk->state = MSP_LINK_STATE_REQ_RX_DATA;
			lnk->next_action = MSP_LINK_ACTION_TX_HEADER;
			lnk->transaction_id = frame.id;
			lnk->frame_id = frame.id;
			lnk->processed_length = 0;
			if (msp_seqflags_is_set(&lnk->flags, lnk->opcode, frame.id)) {
				lnk->total_length = 0;
			} else {
				lnk->total_length = frame.dl;
			}
			r = msp_response_ok();
		} else {
			lnk->corrupt_frame_count += 1;
			r = msp_response_error(MSP_OBC_ERR_INVALID_FRAME);
		}
		break;
	default:
		r = msp_response_error(MSP_OBC_ERR_INVALID_STATE);
		break;
	}
	return r;
}
struct msp_response msp_recv_header_frame ( msp_link_t * lnk ) { int code ; struct msp_response r ; struct msp_obc_frame frame ; unsigned long len ; if ( lnk == NULL || lnk -> buffer == NULL ) return msp_response_error ( MSP_OBC_ERR_NULL_POINTER ) ; if ( lnk -> next_action != MSP_LINK_ACTION_RX_HEADER ) { lnk -> corrupt_frame_count += 1 ; return msp_response_error ( MSP_OBC_ERR_INVALID_ACTION ) ; } code = msp_i2c_read ( lnk -> slave_address , lnk -> buffer , 9 ) ; if ( code ) { lnk -> corrupt_frame_count += 1 ; return msp_response_error ( MSP_OBC_ERR_I2C_ERROR ) ; } frame = msp_obc_decode_frame ( lnk , lnk -> buffer , 9 ) ; if ( frame . type != MSP_OBC_FRAME_HEADER ) { lnk -> corrupt_frame_count += 1 ; msp_debug ( " " ) ; return msp_response_error ( MSP_OBC_ERR_INVALID_FRAME ) ; } if ( frame . opcode == MSP_OP_NULL ) { r = msp_response_aborted ( lnk ) ; msp_set_as_ready ( lnk ) ; msp_debug_hex ( " " , r . opcode ) ; return r ; } if ( frame . opcode == MSP_OP_EXP_BUSY ) return msp_response_busy ( ) ; switch ( lnk -> state ) { case MSP_LINK_STATE_SEND_TX_HEADER : case MSP_LINK_STATE_SEND_TX_DATA : if ( frame . opcode == MSP_OP_T_ACK ) { msp_seqflags_set ( & lnk -> flags , lnk -> opcode , lnk -> transaction_id ) ; if ( lnk -> processed_length == lnk -> total_length ) { r = msp_response_successful ( lnk ) ; msp_set_as_ready ( lnk ) ; } else { r = msp_response_error ( MSP_OBC_ERR_DATA_NOT_SENT ) ; msp_set_as_ready ( lnk ) ; } } else if ( frame . opcode == MSP_OP_F_ACK ) { len = msp_next_data_length ( lnk ) ; if ( lnk -> state == MSP_LINK_STATE_SEND_TX_HEADER ) { lnk -> state = MSP_LINK_STATE_SEND_TX_DATA ; lnk -> next_action = MSP_LINK_ACTION_TX_DATA ; lnk -> frame_id = frame . id ^ 1 ; r = msp_response_ok ( ) ; } else if ( len < ( lnk -> total_length - lnk -> processed_length ) ) { lnk -> next_action = MSP_LINK_ACTION_TX_DATA ; lnk -> frame_id = frame . id ^ 1 ; r = msp_response_ok ( ) ; } else { lnk -> corrupt_frame_count += 1 ; msp_debug ( " " ) ; r = msp_response_error ( MSP_OBC_ERR_INVALID_FRAME ) ; } } else { lnk -> corrupt_frame_count += 1 ; msp_debug ( " " ) ; r = msp_response_error ( MSP_OBC_ERR_INVALID_FRAME ) ; } break ; case MSP_LINK_STATE_REQ_RX_RESPONSE : if ( frame . opcode == MSP_OP_EXP_SEND ) { lnk -> state = MSP_LINK_STATE_REQ_RX_DATA ; lnk -> next_action = MSP_LINK_ACTION_TX_HEADER ; lnk -> transaction_id = frame . id ; lnk -> frame_id = frame . id ; lnk -> processed_length = 0 ; if ( msp_seqflags_is_set ( & lnk -> flags , lnk -> opcode , frame . id ) ) { lnk -> total_length = 0 ; } else { lnk -> total_length = frame . dl ; } r = msp_response_ok ( ) ; } else { lnk -> corrupt_frame_count += 1 ; r = msp_response_error ( MSP_OBC_ERR_INVALID_FRAME ) ; } break ; default : r = msp_response_error ( MSP_OBC_ERR_INVALID_STATE ) ; break ; } return r ; }
Blocking (read over I2C)
Blocking ( read over I2C )
/* NULL frame always resets transaction */ /* Take no further action if the experiment is busy */ /* We should get an ACK here */ /* Transaction Complete */ /* Treat the F_ACK differently depending on the state */ /* Acknowledged, prepare for the first data frame */ /* Acknowledged, setup data next frame */ /* We should've gotten a T_ACK here! */ /* The only frames that we should received when sending data are
			 * ACK frames. */ /* The only header with should get in a request transaction is a
		 * response header. */ /* first check if this is a duplicate transaction */ /* Just pretend that the experiment is sending 0 data if this
				 * is a duplicate transaction */ /* Something went wrong... */