/****************************************************************************** * * Freescale Semiconductor Inc. * (c) Copyright 2008-2015 Freescale Semiconductor, Inc. * ALL RIGHTS RESERVED. * ******************************************************************************/ /**************************************************************************//** * @addtogroup commontl_api_group * @{ ******************************************************************************/ /**************************************************************************//** * * @file lin_commontl_api.c * * @author FPT Software * * @brief Common LIN transport layer and configuration functions * ******************************************************************************/ /****************************************************************************** * * History: * * 20090409 v1.0 First version * 20111005 v1.1 Added 3 functions: ld_save_configuration, ld_read_configuration, ld_set_configuration * *****************************************************************************/ #include "lin_commontl_api.h" #if (_TL_FRAME_SUPPORT_ == _TL_MULTI_FRAME_) #include "lin_commontl_proto.h" #endif /* End (_TL_FRAME_SUPPORT_ == _TL_MULTI_FRAME_) */ /** @} */ #if LIN_MODE == _MASTER_MODE_ /********------------- Code supports SINGLE interface ----------------**********/ #if (_TL_FRAME_SUPPORT_ == _TL_MULTI_FRAME_) /* Multi timer selection */ #ifdef MULTI_TIMER_MODE extern const l_u16 max_tl_timeout_counter[LIN_NUM_OF_IFCS]; #endif /* End MULTI_TIMER_MODE */ /** @addtogroup initialization_group * @{ */ void ld_init (l_ifc_handle iii) { static lin_configuration *conf; static lin_tl_descriptor *tl_conf; static lin_transport_layer_queue *tl_queue; /* Get current configuration */ conf = (lin_configuration *) &lin_ifc_configuration[iii]; /* Get TL configuration */ tl_conf = conf->tl_desc; /* init transmit queue */ /* Get TL tx queue */ tl_queue = tl_conf->tl_tx_queue; tl_queue->queue_header = 0; tl_queue->queue_tail = 0; tl_queue->queue_status = LD_QUEUE_EMPTY; tl_queue->queue_current_size = 0; /* init receive queue */ /* Get TL rx queue */ tl_queue = tl_conf->tl_rx_queue; tl_queue->queue_header = 0; tl_queue->queue_tail = 0; tl_queue->queue_status = LD_NO_DATA; tl_queue->queue_current_size = 0; /* Init transmit message */ tl_conf->tl_rx_msg_status = LD_COMPLETED; tl_conf->tl_rx_msg_index = 0; tl_conf->tl_rx_msg_size = 0; tl_conf->tl_receive_msg_status = LD_NO_MSG; /* Init receive message */ tl_conf->tl_tx_msg_status = LD_COMPLETED; tl_conf->tl_tx_msg_index = 0; tl_conf->tl_tx_msg_size = 0; tl_conf->tl_last_cfg_result = LD_SUCCESS; tl_conf->tl_last_RSID = 0; tl_conf->tl_ld_error_code = 0; tl_conf->tl_frame_counter = 0; tl_conf->tl_no_of_pdu = 0; tl_conf->tl_slaveresp_cnt = 0; tl_conf->tl_check_timeout_type = LD_NO_CHECK_TIMEOUT; #ifdef MULTI_TIMER_MODE tl_conf->tl_check_timeout = max_tl_timeout_counter[iii]; #else tl_conf->tl_check_timeout = N_MAX_TIMEOUT_CNT; #endif /* End MULTI_TIMER_MODE */ *conf->tl_diag_state = LD_DIAG_IDLE; *conf->tl_service_status = LD_SERVICE_IDLE; *conf->diagnostic_mode = DIAG_NONE; *conf->tl_diag_interleave_state = DIAG_NOT_START; tl_conf->tl_interleave_timeout_counter = 0; } /** @} */ /** @addtogroup raw_api_group * @{ */ void ld_put_raw( /* [IN] interface name */ l_ifc_handle iii, /* [IN] buffer for the data to be transmitted */ const l_u8* const data) { lin_configuration *conf; lin_tl_descriptor *tl_conf; lin_transport_layer_queue *tl_queue; /* Get current configuration */ conf = (lin_configuration *) &lin_ifc_configuration[iii]; /* Get TL configuration */ tl_conf = conf->tl_desc; /* Get transmit queue */ tl_queue = tl_conf->tl_tx_queue; tl_put_raw(data, tl_queue, TRANSMISSION); tl_conf->tl_slaveresp_cnt++; } void ld_get_raw( /* [IN] interface name */ l_ifc_handle iii, /* [OUT] buffer for store data received */ l_u8* const data) { lin_configuration *conf; lin_tl_descriptor *tl_conf; lin_transport_layer_queue *tl_queue; /* Get current configuration */ conf = (lin_configuration *) &lin_ifc_configuration[iii]; /* Get TL configuration */ tl_conf = conf->tl_desc; /* Get transmit queue */ tl_queue = tl_conf->tl_rx_queue; tl_get_raw(data, tl_queue, RECEIVING); } l_u8 ld_raw_tx_status( /* [IN] interface name */ l_ifc_handle iii) { lin_configuration *conf; lin_tl_descriptor *tl_conf; lin_transport_layer_queue *tl_queue; /* Get current configuration */ conf = (lin_configuration *) &lin_ifc_configuration[iii]; /* Get TL configuration */ tl_conf = conf->tl_desc; /* Get transmit queue */ tl_queue = tl_conf->tl_tx_queue; return (l_u8) (tl_queue->queue_status); } l_u8 ld_raw_rx_status( /* [IN] interface name */ l_ifc_handle iii) { lin_configuration *conf; lin_tl_descriptor *tl_conf; lin_transport_layer_queue *tl_queue; /* Get current configuration */ conf = (lin_configuration *) &lin_ifc_configuration[iii]; /* Get TL configuration */ tl_conf = conf->tl_desc; /* Get transmit queue */ tl_queue = tl_conf->tl_rx_queue; return (l_u8) (tl_queue->queue_status); } /** @} */ /** @addtogroup cooked_api_group * @{ */ void ld_send_message( /* [IN] interface name */ l_ifc_handle iii, /* [IN] length of data to send */ l_u16 length, /* [IN] Node address of slave node */ l_u8 NAD, /* [IN] data to be sent */ const l_u8* const data) { lin_configuration *conf; lin_tl_descriptor *tl_conf; lin_transport_layer_queue *tl_queue; lin_tl_pdu_data pdu; l_u8 i; l_u8 message_size; l_u16 data_index = 0; l_u16 tmp_length = length; l_u16 frame_counter = 0; /* Get current configuration */ conf = (lin_configuration *) &lin_ifc_configuration[iii]; /* Get TL configuration */ tl_conf = conf->tl_desc; /* Get transmit queue */ tl_queue = tl_conf->tl_tx_queue; /* check message status in queue */ if (LD_COMPLETED == tl_conf->tl_tx_msg_status) { /* calculate number of PDU for this message */ if (length <= 6) { message_size = 1; } else { if ((length - 5) % 6 == 0) { message_size = ((length - 5) / 6) + 1; } else { message_size = ((length - 5) / 6) + 2; } } if (message_size <= (tl_queue->queue_max_size - tl_queue->queue_current_size)) { /* update information of message in queue */ tl_conf->tl_tx_msg_index = tl_queue->queue_tail; tl_conf->tl_tx_msg_size = message_size; tl_conf->tl_tx_msg_status = LD_IN_PROGRESS; *conf->tl_service_status = LD_SERVICE_BUSY; /* package data */ if (length <= 6) { /* package single frame */ /* ____________________________________________ */ /* | NAD | PCI | SID | D1 | D2 | D3 | D4 | D5 | */ /* |_____|_____|_____|____|____|____|____|____| */ if (_MASTER_ == conf->function) { pdu[0] = NAD; } else { pdu[0] = conf->node_attribute->configured_NAD; } pdu[1] = (l_u8) length; pdu[2] = data[0]; /* SID / RSID */ for (i = 1; i < length; i++) { pdu[i + 2] = data[i]; /* used data */ } for (i = (l_u8) length; i < 6; i++) { pdu[i + 2] = 0xFF; /* unused data */ } ld_put_raw(iii, pdu); } else { /* package first frame */ /* ____________________________________________ */ /* | NAD | PCI | LEN |SID | D2 | D3 | D4 | D5 | */ /* |_____|_____|_____|____|____|____|____|____| */ if (_MASTER_ == conf->function) { pdu[0] = NAD; } else { pdu[0] = conf->node_attribute->configured_NAD; } pdu[1] = ((length / 256) & 0x0F) | 0x10; /* PCI */ pdu[2] = length % 256; /* length */ pdu[3] = data[0]; /* SID / RSID */ for (i = 1; i < 5; i++) { /* data */ pdu[i + 3] = data[i]; } data_index += 5; tmp_length -= 5; ld_put_raw(iii, pdu); /* package consecutive frame */ /* ___________________________________________ */ /* | NAD | PCI | D1 | D2 | D3 | D4 | D5 | D6 | */ /* |_____|_____|____|____|____|____|____|____| */ message_size--; if (_MASTER_ == conf->function) { pdu[0] = NAD; } else { pdu[0] = conf->node_attribute->configured_NAD; } while (message_size > 0) { frame_counter++; pdu[1] = 0x20 | (frame_counter & 0x0F); if (tmp_length < 6) { /* last PDU */ /* used data */ for (i = 0; i < tmp_length; i++) { pdu[i + 2] = data[data_index++]; } /* unused data */ for (i = (l_u8) tmp_length; i < 6; i++) { pdu[i + 2] = 0xFF; } } else { for (i = 2; i < 8; i++) { pdu[i] = data[data_index++]; } tmp_length -= 6; } /* end of (tmp < 6 ) */ message_size--; ld_put_raw(iii, pdu); } /* end of (message > 0) */ } /* end of (length < 6) */ /* For Master nodes, set Diagnostic Interleaved mode */ if (_MASTER_ == conf->function) { *conf->previous_schedule_id = *conf->active_schedule_id; *conf->active_schedule_id = conf->schedule_start + 2; conf->schedule_start_entry[*conf->active_schedule_id] = 0; /* Start send message */ *conf->diagnostic_mode = DIAG_INTER_LEAVE_MODE; } /* For slave nodes, start checking N_As_timeout*/ else { /* Set check N_As timeout */ tl_conf->tl_check_timeout = N_MAX_TIMEOUT_CNT; tl_conf->tl_check_timeout_type = LD_CHECK_N_AS_TIMEOUT; } } /* end of check message size */ } /* end of (LD_COMPLETED == tl_conf->tl_message_status) */ } /* end of ld_send_message */ void ld_receive_message( /* [IN] interface name */ l_ifc_handle iii, /* [OUT] length of data to receive */ l_u16* const length, /* [OUT] Node address of slave node */ l_u8* const NAD, /* [OUT] data to be sent */ l_u8* const data ) { lin_configuration *conf; lin_tl_descriptor *tl_conf; lin_message_status *_tl_receive_msg_status; lin_transport_layer_queue *tl_queue; lin_tl_pdu_data *queue_data; lin_tl_pdu_data pdu; l_u8 i; l_u16 data_index = 0; l_u16 tmp_length = 0; l_u16 frame_counter; l_u8 PCI_type; /* Get current configuration */ conf = (lin_configuration *) &lin_ifc_configuration[iii]; /* Get TL configuration */ tl_conf = conf->tl_desc; /* Get message status */ _tl_receive_msg_status = &(tl_conf->tl_receive_msg_status); /* Get transmit queue */ tl_queue = tl_conf->tl_rx_queue; queue_data = tl_queue->tl_pdu; /* set status of receive message */ tl_conf->tl_rx_msg_status = LD_IN_PROGRESS; /* wait message is received completely */ while (LD_COMPLETED != *_tl_receive_msg_status) { /* check message error */ if ((LD_FAILED == *_tl_receive_msg_status) || (LD_WRONG_SN == *_tl_receive_msg_status) || (LD_N_CR_TIMEOUT == *_tl_receive_msg_status)) { tl_conf->tl_rx_msg_status = *_tl_receive_msg_status; return; } } /* Message is received completely */ /* get data from receive queue */ ld_get_raw(iii, pdu); /* Analyze data */ if (_MASTER_ == conf->function) { *NAD = pdu[0]; } /* Check type of pdu */ PCI_type = (pdu[1] & 0xF0) >> 4; switch (PCI_type) { /* Single frame */ case SF: tmp_length = pdu[1] & 0x0f; *length = tmp_length; data[0] = pdu[2]; for (i = 1; i < tmp_length; i++) { data[i] = pdu[i + 2]; } break; /* First frame */ case FF: tmp_length = (pdu[1] & 0x0F) * 256 + pdu[2]; *length = tmp_length; data[0] = pdu[3]; for (i = 1; i < 5; i++) { data[i] = pdu[i + 3]; } tmp_length -= 5; data_index += 5; /* Consecutive frame */ case CF: while (tmp_length > 6) { /* get PDU */ ld_get_raw(iii, pdu); frame_counter = pdu[1] & 0x0F; for (i = 2; i < 8; i++) { data[data_index++] = pdu[i]; } tmp_length -= 6; } /* Last frame */ if (tmp_length > 0) { /* get PDU */ ld_get_raw(iii, pdu); frame_counter = pdu[1] & 0x0F; for (i = 0; i < tmp_length; i++) { data[data_index++] = pdu[i + 2]; } } break; default: break; } /* end of switch */ *_tl_receive_msg_status = LD_NO_MSG; tl_conf->tl_rx_msg_status = LD_COMPLETED; } l_u8 ld_tx_status( /* [IN] interface name */ l_ifc_handle iii) { lin_configuration *conf; lin_tl_descriptor *tl_conf; /* Get current configuration */ conf = (lin_configuration *) &lin_ifc_configuration[iii]; /* Get TL configuration */ tl_conf = conf->tl_desc; return (l_u8) (tl_conf->tl_tx_msg_status); } l_u8 ld_rx_status( /* [IN] interface name */ l_ifc_handle iii) { lin_configuration *conf; lin_tl_descriptor *tl_conf; /* Get current configuration */ conf = (lin_configuration *) &lin_ifc_configuration[iii]; /* Get TL configuration */ tl_conf = conf->tl_desc; return (l_u8) (tl_conf->tl_rx_msg_status); } /** @} */ #endif /* End (_TL_FRAME_SUPPORT_ == _TL_MULTI_FRAME_) */ /** @addtogroup node_configuration_group * @{ */ void ld_assign_NAD( /* [IN] interface name */ l_ifc_handle iii, /* [IN] initial node address of the target node */ l_u8 initial_NAD, /* [IN] supplier ID of the target node */ l_u16 supplier_id, /* [IN] function identifier of the target node */ l_u16 function_id, /* [IN] new node address */ l_u8 new_NAD) { /* Multi frame support */ #if (_TL_FRAME_SUPPORT_ == _TL_MULTI_FRAME_) l_u8 data[6]; lin_configuration *conf; /* Get current configuration */ conf = (lin_configuration *) &lin_ifc_configuration[iii]; /* This function is only for Master nodes*/ if (conf->function == _MASTER_) { /* check service is busy? */ if (*conf->tl_service_status != LD_SERVICE_BUSY) { data[0] = 0xB0; data[1] = supplier_id & 0x00FF; data[2] = (supplier_id >> 8) & 0x00FF; data[3] = function_id & 0x00FF; data[4] = (function_id >> 8) & 0x00FF; data[5] = new_NAD; /* put data into TX_QUEUE */ ld_send_message(iii, 6, initial_NAD, data); /* set node config status to busy */ *conf->tl_service_status = LD_SERVICE_BUSY; } /* End of checking service status */ } #else /* Single frame support */ lin_tl_pdu_data *lin_tl_pdu; lin_configuration *conf; lin_tl_descriptor *tl_conf; /* Get current configuration */ conf = (lin_configuration *)&lin_ifc_configuration[iii]; /* This function is only for Master nodes*/ if (conf->function == _MASTER_) { /* Get TL configuration */ tl_conf = conf->tl_desc; /* Get pointer to TX single frame PDU */ lin_tl_pdu = (lin_tl_pdu_data *)tl_conf->tl_tx_single_pdu; /* check service is busy? */ if (LD_SERVICE_BUSY != tl_conf->tl_service_status) { /* Create data for Assign NAD command */ (*lin_tl_pdu)[0] = initial_NAD; (*lin_tl_pdu)[1] = 0x06; (*lin_tl_pdu)[2] = 0xB0; (*lin_tl_pdu)[3] = supplier_id &0x00FF; (*lin_tl_pdu)[4] = (supplier_id >> 8) & 0x00FF; (*lin_tl_pdu)[5] = function_id &0x00FF; (*lin_tl_pdu)[6] = (function_id >> 8) & 0x00FF; (*lin_tl_pdu)[7] = new_NAD; /* Set state of service is BUSY */ tl_conf->tl_service_status = LD_SERVICE_BUSY; /* Notify to Master task sending frame */ tl_conf->tl_cnt_to_send = 1; /* Switch to master request schedule table */ *conf->previous_schedule_id = *conf->active_schedule_id; *conf->active_schedule_id = conf->schedule_start + 2; conf->schedule_start_entry[*conf->active_schedule_id] = 0; } /* End of checking service status */ } #endif /* End (_TL_FRAME_SUPPORT_ == _TL_MULTI_FRAME_) */ } void ld_conditional_change_NAD( /* [IN] interface name */ l_ifc_handle iii, /* [IN] current NAD value of the target node */ l_u8 NAD, /* [IN] property ID of the target node */ l_u8 id, /* [IN] byte location of property value to be read from the target node */ l_u8 byte_data, /* [IN] value for masking the read property byte */ l_u8 mask, /* [IN] value for excluding the read property byte */ l_u8 invert, /* [IN] new NAD value to be assigned when the condition is met */ l_u8 new_NAD) { /* Multi frame support */ #if (_TL_FRAME_SUPPORT_ == _TL_MULTI_FRAME_) l_u8 data[6]; lin_configuration *conf; /* Get current configuration */ conf = (lin_configuration *) &lin_ifc_configuration[iii]; /* This function is only for Master nodes*/ if (conf->function == _MASTER_) { /* check service is busy? */ if (*conf->tl_service_status != LD_SERVICE_BUSY) { data[0] = 0xB3; data[1] = id; data[2] = byte_data; data[3] = mask; data[4] = invert; data[5] = new_NAD; /* put data into TX_QUEUE */ ld_send_message(iii, 6, NAD, data); /* set node config status to busy */ *conf->tl_service_status = LD_SERVICE_BUSY; }/* End of checking service status */ } #else /* Single frame support */ lin_tl_pdu_data *lin_tl_pdu; lin_configuration *conf; lin_tl_descriptor *tl_conf; /* Get current configuration */ conf = (lin_configuration *)&lin_ifc_configuration[iii]; /* This function is only for Master nodes*/ if (conf->function == _MASTER_) { /* Get TL configuration */ tl_conf = conf->tl_desc; /* Get pointer to TX single frame PDU */ lin_tl_pdu = (lin_tl_pdu_data *)tl_conf->tl_tx_single_pdu; /* check service is busy? */ if (LD_SERVICE_BUSY != tl_conf->tl_service_status) { /* Create data for Conditional change NAD command */ (*lin_tl_pdu)[0] = NAD; (*lin_tl_pdu)[1] = 0x06; (*lin_tl_pdu)[2] = 0xB3; (*lin_tl_pdu)[3] = id; (*lin_tl_pdu)[4] = byte_data; (*lin_tl_pdu)[5] = mask; (*lin_tl_pdu)[6] = invert; (*lin_tl_pdu)[7] = new_NAD; /* Set state of service is BUSY */ tl_conf->tl_service_status = LD_SERVICE_BUSY; /* Notify to Master task sending frame */ tl_conf->tl_cnt_to_send = 1; /* Switch to master request schedule table */ *conf->previous_schedule_id = *conf->active_schedule_id; *conf->active_schedule_id = conf->schedule_start + 2; conf->schedule_start_entry[*conf->active_schedule_id] = 0; } /* End of checking service status */ } #endif /* End (_TL_FRAME_SUPPORT_ == _TL_MULTI_FRAME_) */ } /** @} */ /** @addtogroup node_identification_group * @{ */ void ld_read_by_id( /* [IN] interface name */ l_ifc_handle iii, /* [IN] value of the target node */ l_u8 NAD, /* [IN] supplier ID of the target node */ l_u16 supplier_id, /* [IN] function ID of the target node */ l_u16 function_id, /* [IN] ID of the target node */ l_u8 id, /* [OUT] buffer for saving the data read from the node */ l_u8* const data) { /* Multi frame support */ #if (_TL_FRAME_SUPPORT_ == _TL_MULTI_FRAME_) l_u8 buff[6]; lin_configuration *conf; lin_tl_descriptor *tl_conf; /* Get current configuration */ conf = (lin_configuration *) &lin_ifc_configuration[iii]; /* This function is only for Master nodes*/ if (conf->function == _MASTER_) { tl_conf = conf->tl_desc; /* check service is busy? */ if (*conf->tl_service_status != LD_SERVICE_BUSY) { /* Create data for Read by Identifier command */ buff[0] = 0xB2; buff[1] = id; buff[2] = supplier_id & 0x00FF; buff[3] = (supplier_id >> 8) & 0x00FF; buff[4] = function_id & 0x00FF; buff[5] = (function_id >> 8) & 0x00FF; /* Store address of RAM data which contain response infor */ tl_conf->tl_ident_data = data; /* put data into TX_QUEUE */ ld_send_message(iii, 6, NAD, buff); /* set node config status to busy */ *conf->tl_service_status = LD_SERVICE_BUSY; } /* End of checking service status */ } #else /* Single frame support */ lin_tl_pdu_data *lin_tl_pdu; lin_configuration *conf; lin_tl_descriptor *tl_conf; /* Get current configuration */ conf = (lin_configuration *)&lin_ifc_configuration[iii]; /* This function is only for Master nodes*/ if (conf->function == _MASTER_) { /* Get TL configuration */ tl_conf = conf->tl_desc; /* Get pointer to TX single frame PDU */ lin_tl_pdu = (lin_tl_pdu_data *)tl_conf->tl_tx_single_pdu; /* check service is busy? */ if (LD_SERVICE_BUSY != tl_conf->tl_service_status) { /* Create data for Read by Identifier command */ (*lin_tl_pdu)[0] = NAD; (*lin_tl_pdu)[1] = 0x06; (*lin_tl_pdu)[2] = 0xB2; (*lin_tl_pdu)[3] = id; (*lin_tl_pdu)[4] = supplier_id &0x00FF; (*lin_tl_pdu)[5] = (supplier_id >> 8) & 0x00FF; (*lin_tl_pdu)[6] = function_id &0x00FF; (*lin_tl_pdu)[7] = (function_id >> 8) & 0x00FF; /* Store address of RAM data which contain response infor */ tl_conf->tl_ident_data = data; /* Set state of service is BUSY */ tl_conf->tl_service_status = LD_SERVICE_BUSY; /* Notify to Master task sending frame */ tl_conf->tl_cnt_to_send = 1; /* Switch to master request schedule table */ *conf->previous_schedule_id = *conf->active_schedule_id; *conf->active_schedule_id = conf->schedule_start + 2; conf->schedule_start_entry[*conf->active_schedule_id] = 0; } /* End of checking service status */ } #endif /* End (_TL_FRAME_SUPPORT_ == _TL_MULTI_FRAME_) */ } void ld_save_configuration( /* [IN] interface name */ l_ifc_handle iii, /* [IN] node address of the target node */ l_u8 NAD ) { /* Multi frame support */ #if (_TL_FRAME_SUPPORT_ == _TL_MULTI_FRAME_) l_u8 data[6]; lin_configuration *conf; /* Get current configuration */ conf = (lin_configuration *) &lin_ifc_configuration[iii]; /* This function is only for Master nodes*/ if (conf->function == _MASTER_) { /* check service is busy? */ if (*conf->tl_service_status != LD_SERVICE_BUSY) { data[0] = SERVICE_SAVE_CONFIGURATION; data[1] = 0xFF; data[2] = 0xFF; data[3] = 0xFF; data[4] = 0xFF; data[5] = 0xFF; /* put data into TX_QUEUE */ ld_send_message(iii, PCI_SAVE_CONFIGURATION, NAD, data); /* set node config status to busy */ *conf->tl_service_status = LD_SERVICE_BUSY; } /* End of checking service status */ } #else /* Single frame support */ lin_tl_pdu_data *lin_tl_pdu; lin_configuration *conf; lin_tl_descriptor *tl_conf; /* Get current configuration */ conf = (lin_configuration *)&lin_ifc_configuration[iii]; /* This function is only for Master nodes*/ if (conf->function == _MASTER_) { /* Get TL configuration */ tl_conf = conf->tl_desc; /* Get pointer to TX single frame PDU */ lin_tl_pdu = (lin_tl_pdu_data *)tl_conf->tl_tx_single_pdu; /* check service is busy? */ if (LD_SERVICE_BUSY != tl_conf->tl_service_status) { /* Create data for Assign NAD command */ (*lin_tl_pdu)[0] = NAD; (*lin_tl_pdu)[1] = PCI_SAVE_CONFIGURATION; (*lin_tl_pdu)[2] = SERVICE_SAVE_CONFIGURATION; (*lin_tl_pdu)[3] = 0xFF; (*lin_tl_pdu)[4] = 0xFF; (*lin_tl_pdu)[5] = 0xFF; (*lin_tl_pdu)[6] = 0xFF; (*lin_tl_pdu)[7] = 0xFF; /* Set state of service is BUSY */ tl_conf->tl_service_status = LD_SERVICE_BUSY; /* Notify to Master task sending frame */ tl_conf->tl_cnt_to_send = 1; /* Switch to master request schedule table */ *conf->previous_schedule_id = *conf->active_schedule_id; *conf->active_schedule_id = conf->schedule_start + 2; conf->schedule_start_entry[*conf->active_schedule_id] = 0; } /* End of checking service status */ } #endif /* End (_TL_FRAME_SUPPORT_ == _TL_MULTI_FRAME_) */ } l_u8 ld_read_configuration ( /* [IN] interface name */ l_ifc_handle iii, /* [IN] data area to save configuration */ l_u8* const data, /* [IN] length of data area */ l_u8* const length ) { l_u8 i, temp; /* Set the default returned value to LD_READ_OK */ l_u8 retval = (l_u8)LD_READ_OK; /** Set the expected length value to * EXP = NN + NF, where : * NN = the number of NAD. * NF = the number of configurable frames; * Moreover: * Not taken PID's diagnostics frame: 3C, 3D */ l_u8 expected_length; lin_configuration const *conf; lin_node_attribute *node_att; /* Get current configuration */ conf = &lin_ifc_configuration[iii]; expected_length = (l_u8) (conf->num_of_frames - 1); /* Check if slave node */ if (_SLAVE_ == conf->function) { temp = *length; /* Get node attibute */ node_att = conf->node_attribute; if (temp < expected_length) { /* The 'data' size is not enough to store NAD+PIDs */ retval = (l_u8)LD_LENGTH_TOO_SHORT; } else { /* The 'data' size is enough to store NAD+PIDs, so proceed to store them */ /* Copy actual NAD to 'data' */ data[0] = node_att ->configured_NAD; /* Copy protected IDs to 'data' */ for (i = 1U; i < expected_length; ++i) { data[i] = conf->configuration_RAM[i]; } /* Set the length parameter to the actual size of the configuration */ *length = expected_length; } } return retval; } /* End ld_read_configuration() */ l_u8 ld_set_configuration ( /* [IN] interface name */ l_ifc_handle iii, /* [IN] data area to set configuration */ const l_u8* const data, /* [IN] length of data area */ l_u16 length ) { l_u8 i; /* Set the default returned value to LD_DATA_ERROR */ l_u8 retval = LD_DATA_ERROR; /** Set the expected length value to * EXP = NN + NF, where : * NN = the number of NAD. * NF = the number of configurable frames; * Moreover: * Not taken PID's diagnostics frame: 3C, 3D */ l_u16 expected_length; lin_configuration const *conf; lin_node_attribute *node_att; /* Get current configuration */ conf = &lin_ifc_configuration[iii]; expected_length = (l_u16) (conf->num_of_frames - 1); /* Check if slave node */ if (_SLAVE_ == conf->function) { /* Get node attibute */ node_att = conf->node_attribute; if (length < expected_length) { /* The 'data' size is not enough to contain NAD+PIDs */ retval = LD_LENGTH_NOT_CORRECT; } else { /* The 'data' size is enough to contain NAD+PIDs, so proceed to read from 'data' */ /* Read actual NAD from 'data' */ node_att ->configured_NAD = data[0]; /* Copy protected IDs in 'data' to RAM configuration */ for (i = 1U; i < expected_length; ++i) { conf->configuration_RAM[i] = data[i]; } /* No error, return OK */ retval = LD_SET_OK; } } return retval; } /* End ld_set_configuration() */ /** @} */ #endif /* End LIN_MODE == _MASTER_MODE_ */ /* -------------------------------------------------------------------- */ #if LIN_MODE == _SLAVE_MODE_ /* Unuse for GPIO */ #if (_LIN_GPIO_ == 0) && !defined(_MC9S08SC4_H) /* Multi frame support */ #if (_TL_FRAME_SUPPORT_ == _TL_MULTI_FRAME_) /* INITIALIZATION */ /** @addtogroup initialization_group * @{ */ void ld_init(void) { /* init transmit queue */ lin_tl_tx_queue.queue_header = 0; lin_tl_tx_queue.queue_tail = 0; lin_tl_tx_queue.queue_status = LD_QUEUE_EMPTY; lin_tl_tx_queue.queue_current_size = 0; /* init receive queue */ lin_tl_rx_queue.queue_header = 0; lin_tl_rx_queue.queue_tail = 0; lin_tl_rx_queue.queue_status = LD_NO_DATA; lin_tl_rx_queue.queue_current_size = 0; /* Init transmit message */ tl_rx_msg_status = LD_COMPLETED; tl_rx_msg_index = 0; tl_rx_msg_size = 0; tl_receive_msg_status = LD_NO_MSG; /* Init receive message */ tl_tx_msg_status = LD_COMPLETED; tl_tx_msg_index = 0; tl_tx_msg_size = 0; tl_last_cfg_result = LD_SUCCESS; tl_last_RSID = 0; tl_ld_error_code = 0; tl_frame_counter = 0; tl_no_of_pdu = 0; tl_slaveresp_cnt = 0; tl_check_timeout_type = LD_NO_CHECK_TIMEOUT; tl_check_timeout = N_MAX_TIMEOUT_CNT; tl_diag_state = LD_DIAG_IDLE; tl_service_status = LD_SERVICE_IDLE; } /** @} */ /* RAW APIs */ /** @addtogroup raw_api_group * @{ */ void ld_put_raw(const l_u8* const data) { tl_put_raw(data, &lin_tl_tx_queue, TRANSMISSION); tl_slaveresp_cnt++; } void ld_get_raw(l_u8* const data) { tl_get_raw(data, &lin_tl_rx_queue, RECEIVING); } l_u8 ld_raw_tx_status(void) { return (l_u8)lin_tl_tx_queue.queue_status; } l_u8 ld_raw_rx_status(void) { return (l_u8)lin_tl_rx_queue.queue_status; } /** @} */ /* COOKED APIs */ /** @addtogroup cooked_api_group * @{ */ void ld_send_message(l_u16 length, const l_u8* const data) { lin_tl_pdu_data pdu; l_u8 i; l_u8 message_size; l_u16 data_index = 0; l_u16 tmp_length = length; l_u16 frame_counter = 1; /* check message status in queue */ if (LD_COMPLETED == tl_tx_msg_status) { /* calculate number of PDU for this message */ if (length <= 6) { message_size = 1; } else { if ((length-5)%6 == 0) { message_size = ((length - 5) / 6) + 1; } else { message_size = ((length - 5) / 6) + 2; } } if (message_size <= (lin_tl_tx_queue.queue_max_size - lin_tl_tx_queue.queue_current_size)) { /* update information of message in queue */ tl_tx_msg_index = lin_tl_tx_queue.queue_tail; tl_tx_msg_size = message_size; tl_tx_msg_status = LD_IN_PROGRESS; tl_service_status = LD_SERVICE_BUSY; /* package data */ if (length <= 6) { /* package single frame */ /* ____________________________________________ */ /* | NAD | PCI | SID | D1 | D2 | D3 | D4 | D5 | */ /* |_____|_____|_____|____|____|____|____|____| */ pdu[0] = lin_configured_NAD; pdu[1] = (l_u8) length; pdu[2] = data[0]; /* SID / RSID */ for (i = 1; i < length; i++) { pdu[i + 2] = data[i]; /* used data */ } for (i = (l_u8) length; i < 6; i++) { pdu[i + 2] = 0xFF; /* unused data */ } ld_put_raw(pdu); } else { /* package first frame */ /* ____________________________________________ */ /* | NAD | PCI | LEN |SID | D2 | D3 | D4 | D5 | */ /* |_____|_____|_____|____|____|____|____|____| */ pdu[0] = lin_configured_NAD; pdu[1] = ((length / 256) & 0x0F) | 0x10; /* PCI */ pdu[2] = length % 256; /* length */ pdu[3] = data[0]; /* SID / RSID */ for (i = 1; i < 5; i++) { /* data */ pdu[i + 3] = data[i]; } data_index += 5; tmp_length -= 5; ld_put_raw(pdu); /* package consecutive frame */ /* ___________________________________________ */ /* | NAD | PCI | D1 | D2 | D3 | D4 | D5 | D6 | */ /* |_____|_____|____|____|____|____|____|____| */ message_size--; pdu[0] = lin_configured_NAD; while (message_size > 0) { pdu[1] = 0x20 | (frame_counter & 0x0F); frame_counter++; if (frame_counter > 15) { frame_counter = 0; } if (tmp_length < 6) { /* last PDU */ /* used data */ for (i = 0; i < tmp_length; i++) { pdu[i + 2] = data[data_index++]; } /* unused data */ for (i = (l_u8) tmp_length; i < 6; i++) { pdu[i + 2] = 0xFF; } } else { for (i = 2; i < 8; i++) { pdu[i] = data[data_index++]; } tmp_length -= 6; } /* end of (tmp < 6 ) */ message_size--; ld_put_raw(pdu); } /* end of (message > 0) */ } /* end of (length < 6) */ /* Set check N_As timeout */ tl_check_timeout = N_MAX_TIMEOUT_CNT; tl_check_timeout_type = LD_CHECK_N_AS_TIMEOUT; } /* end of check message size */ } /* end of (LD_COMPLETED == tl_conf->tl_message_status) */ } void ld_receive_message(l_u16* const length, l_u8* const data) { lin_tl_pdu_data pdu; l_u8 i; l_u16 data_index = 0; l_u16 tmp_length; l_u16 frame_counter; l_u8 PCI_type; /* set status of receive message */ tl_rx_msg_status = LD_IN_PROGRESS; /* wait message is received completely */ while (LD_COMPLETED != tl_receive_msg_status) { /* check message error */ if ((LD_FAILED == tl_receive_msg_status) || (LD_WRONG_SN == tl_receive_msg_status) || (LD_N_CR_TIMEOUT == tl_receive_msg_status)) { tl_rx_msg_status = tl_receive_msg_status; return; } } /* Message is received completely */ /* get data from receive queue */ ld_get_raw(pdu); /* Check type of pdu */ PCI_type = (pdu[1] & 0xF0) >> 4; switch (PCI_type) { /* Single frame */ case SF: tmp_length = pdu[1] & 0x0f; *length = tmp_length; data[0] = pdu[2]; for (i = 1; i < tmp_length; i++) { data[i] = pdu[i + 2]; } break; /* First frame */ case FF: tmp_length = (pdu[1] & 0x0F) * 256 + pdu[2]; *length = tmp_length; data[0] = pdu[3]; for (i = 1; i < 5; i++) { data[i] = pdu[i + 3]; } tmp_length -= 5; data_index += 5; /* Consecutive frame */ case CF: while (tmp_length > 6) { /* get PDU */ ld_get_raw(pdu); frame_counter = pdu[1] & 0x0F; for (i = 2; i < 8; i++) { data[data_index++] = pdu[i]; } tmp_length -= 6; } /* Last frame */ if (tmp_length > 0) { /* get PDU */ ld_get_raw(pdu); frame_counter = pdu[1] & 0x0F; for (i = 0; i < tmp_length; i++) { data[data_index++] = pdu[i + 2]; } } break; default: break; } /* end of switch */ tl_receive_msg_status = LD_NO_MSG; tl_rx_msg_status = LD_COMPLETED; } l_u8 ld_tx_status(void) { return (l_u8)tl_tx_msg_status; } l_u8 ld_rx_status(void) { return (l_u8)tl_rx_msg_status; } /** @} */ #endif /* End (_TL_FRAME_SUPPORT_ == _TL_MULTI_FRAME_) */ l_u8 ld_read_configuration ( /* [IN] data area to save configuration */ l_u8* const data, /* [IN] length of data area */ l_u8* const length ) { l_u8 i, temp; /* Set the default returned value to LD_READ_OK */ l_u8 retval = (l_u8)LD_READ_OK; /** Set the expected length value to * EXP = NN + NF, where : * NN = the number of NAD. * NF = the number of configurable frames; * Moreover: * Not taken PID's diagnostics frame: 3C, 3D */ l_u8 expected_length = (l_u8)(LIN_NUM_OF_FRMS - 1U); temp = *length; if (temp < expected_length) { /* The 'data' size is not enough to store NAD+PIDs */ retval = (l_u8)LD_LENGTH_TOO_SHORT; } else { /* The 'data' size is enough to store NAD+PIDs, so proceed to store them */ /* Copy actual NAD to 'data' */ data[0] = lin_configured_NAD; /* Copy protected IDs to 'data' */ for (i = 1U; i < expected_length; ++i) { data[i] = lin_configuration_RAM[i]; } /* Set the length parameter to the actual size of the configuration */ *length = expected_length; } return retval; } /* End ld_read_configuration() */ l_u8 ld_set_configuration ( /* [IN] data area to set configuration */ const l_u8* const data, /* [IN] length of data area */ l_u16 length ) { l_u8 i; /* Set the default returned value to LD_DATA_ERROR */ l_u8 retval = LD_DATA_ERROR; /** Set the expected length value to * EXP = NN + NF, where : * NN = the number of NAD. * NF = the number of configurable frames; * Moreover: * Not taken PID's diagnostics frame: 3C, 3D */ l_u16 expected_length = (l_u8)(LIN_NUM_OF_FRMS - 1U); if (length < expected_length) { /* The 'data' size is not enough to contain NAD+PIDs */ retval = LD_LENGTH_NOT_CORRECT; } else { /* The 'data' size is enough to contain NAD+PIDs, so proceed to read from 'data' */ /* Read actual NAD from 'data' */ lin_configured_NAD = data[0]; /* Copy protected IDs in 'data' to RAM configuration */ for (i = 1U; i < expected_length; ++i) { lin_configuration_RAM[i] = data[i]; } /* No error, return OK */ retval = LD_SET_OK; } return retval; } /* End ld_set_configuration() */ #endif /* End (_LIN_GPIO_ == 0) && !defined(_MC9S08SC4_H) */ #endif /* End LIN_MODE == _SLAVE_MODE_ */ /** * @} */