int aecp_controller_state_machine::proc_resp(void *& notification_id, struct jdksavdecc_frame * cmd_frame)
{
    uint16_t seq_id = jdksavdecc_aecpdu_common_get_sequence_id(cmd_frame->payload, ETHER_HDR_SIZE);
    uint32_t status = jdksavdecc_common_control_header_get_status(cmd_frame->payload, ETHER_HDR_SIZE);
    uint32_t notification_flag = 0;

    std::vector<inflight>::iterator j =
        std::find_if(inflight_cmds.begin(), inflight_cmds.end(), SeqIdComp(seq_id));

    if (j != inflight_cmds.end()) // found?
    {
        notification_id = j->cmd_notification_id;
        notification_flag = j->notification_flag();
        callback(notification_id, notification_flag, cmd_frame->payload);

        // Restart the timer if response is indicating the operation is still in progress so that it won't be timed out
        if (status == AEM_STATUS_IN_PROGRESS)
        {
            j->restart_timer();
        }
        else
        {
            inflight_cmds.erase(j);
        }

        return 1;
    }

    return -1;
}
    int aecp_controller_state_machine::proc_resp(void *&notification_id, struct jdksavdecc_frame *cmd_frame)
    {
        uint16_t seq_id = jdksavdecc_aecpdu_common_get_sequence_id(cmd_frame->payload, ETHER_HDR_SIZE);
        uint32_t notification_flag = 0;

        std::vector<inflight>::iterator j =
            std::find_if(inflight_cmds.begin(), inflight_cmds.end(), SeqIdComp(seq_id));

        if(j != inflight_cmds.end()) // found?
        {
            notification_id = j->cmd_notification_id;
            notification_flag = j->notification_flag();
            callback(notification_id, notification_flag, cmd_frame->payload);
            inflight_cmds.erase(j);
            return 1;
        }

        return -1;
    }
    int aecp_controller_state_machine::tx_cmd(void *notification_id, uint32_t notification_flag, struct jdksavdecc_frame *cmd_frame, bool resend)
    {
        int send_frame_returned;

        if (!resend)
        {
            uint16_t current_seq_id = aecp_seq_id;

            jdksavdecc_aecpdu_common_set_sequence_id(aecp_seq_id++, cmd_frame->payload, ETHER_HDR_SIZE);
            inflight in_flight = inflight(cmd_frame,
                                          current_seq_id,
                                          notification_id,
                                          notification_flag,
                                          AVDECC_MSG_TIMEOUT_MS);
            in_flight.start_timer();
            inflight_cmds.push_back(in_flight);
        }
        else
        {
            uint16_t resend_with_seq_id = jdksavdecc_aecpdu_common_get_sequence_id(cmd_frame->payload, ETHER_HDR_SIZE);
            std::vector<inflight>::iterator j =
            std::find_if(inflight_cmds.begin(), inflight_cmds.end(), SeqIdComp(resend_with_seq_id));

            if(j != inflight_cmds.end()) // found?
            {
                j->start_timer();
            }
        }

        send_frame_returned = net_interface_ref->send_frame(cmd_frame->payload, cmd_frame->length);
        if(send_frame_returned < 0)
        {
            log_imp_ref->post_log_msg(LOGGING_LEVEL_ERROR, "netif_send_frame error");
            assert(send_frame_returned >= 0);
        }

        callback(notification_id, notification_flag, cmd_frame->payload);

        return 0;
    }
    int aecp_controller_state_machine::callback(void *notification_id, uint32_t notification_flag, uint8_t *frame)
    {
        uint32_t msg_type = jdksavdecc_common_control_header_get_control_data(frame, ETHER_HDR_SIZE);

        uint16_t cmd_type = jdksavdecc_aecpdu_aem_get_command_type(frame, ETHER_HDR_SIZE);
        cmd_type &= 0x7FFF;
        uint32_t status = jdksavdecc_common_control_header_get_status(frame, ETHER_HDR_SIZE);
        uint16_t desc_type = 0;
        uint16_t desc_index = 0;

        switch(cmd_type)
        {
        case JDKSAVDECC_AEM_COMMAND_ACQUIRE_ENTITY:
            desc_type = jdksavdecc_aem_command_acquire_entity_response_get_descriptor_type(frame, ETHER_HDR_SIZE);
            desc_index = jdksavdecc_aem_command_acquire_entity_response_get_descriptor_index(frame, ETHER_HDR_SIZE);
            break;

        case JDKSAVDECC_AEM_COMMAND_LOCK_ENTITY:
            desc_type = jdksavdecc_aem_command_lock_entity_get_descriptor_type(frame, ETHER_HDR_SIZE);
            desc_index = jdksavdecc_aem_command_lock_entity_get_descriptor_index(frame, ETHER_HDR_SIZE);
            break;

        case JDKSAVDECC_AEM_COMMAND_ENTITY_AVAILABLE:
            break;

        case JDKSAVDECC_AEM_COMMAND_CONTROLLER_AVAILABLE:
            break;

        case JDKSAVDECC_AEM_COMMAND_READ_DESCRIPTOR:
            desc_type = jdksavdecc_aem_command_read_descriptor_get_descriptor_type(frame, ETHER_HDR_SIZE);
            desc_index = jdksavdecc_aem_command_read_descriptor_get_descriptor_index(frame, ETHER_HDR_SIZE);
            break;

        case JDKSAVDECC_AEM_COMMAND_SET_STREAM_FORMAT:
            desc_type = jdksavdecc_aem_command_set_stream_format_response_get_descriptor_type(frame, ETHER_HDR_SIZE);
            desc_index = jdksavdecc_aem_command_set_stream_format_response_get_descriptor_index(frame, ETHER_HDR_SIZE);
            break;

        case JDKSAVDECC_AEM_COMMAND_GET_STREAM_FORMAT:
            desc_type = jdksavdecc_aem_command_get_stream_format_response_get_descriptor_type(frame, ETHER_HDR_SIZE);
            desc_index = jdksavdecc_aem_command_get_stream_format_response_get_descriptor_index(frame, ETHER_HDR_SIZE);
            break;

        case JDKSAVDECC_AEM_COMMAND_SET_STREAM_INFO:
            desc_type = jdksavdecc_aem_command_set_stream_info_response_get_descriptor_type(frame, ETHER_HDR_SIZE);
            desc_index = jdksavdecc_aem_command_set_stream_info_response_get_descriptor_index(frame, ETHER_HDR_SIZE);
            break;

        case JDKSAVDECC_AEM_COMMAND_GET_STREAM_INFO:
            desc_type = jdksavdecc_aem_command_get_stream_info_response_get_descriptor_type(frame, ETHER_HDR_SIZE);
            desc_index = jdksavdecc_aem_command_get_stream_info_response_get_descriptor_index(frame, ETHER_HDR_SIZE);
            break;

        case JDKSAVDECC_AEM_COMMAND_SET_NAME:
            desc_type = jdksavdecc_aem_command_set_name_response_get_descriptor_type(frame, ETHER_HDR_SIZE);
            desc_index = jdksavdecc_aem_command_set_name_response_get_descriptor_index(frame, ETHER_HDR_SIZE);
            break;

        case JDKSAVDECC_AEM_COMMAND_GET_NAME:
            desc_type = jdksavdecc_aem_command_get_name_response_get_descriptor_type(frame, ETHER_HDR_SIZE);
            desc_index = jdksavdecc_aem_command_get_name_response_get_descriptor_index(frame, ETHER_HDR_SIZE);
            break;

        case JDKSAVDECC_AEM_COMMAND_SET_SAMPLING_RATE:
            desc_type = jdksavdecc_aem_command_set_sampling_rate_response_get_descriptor_type(frame, ETHER_HDR_SIZE);
            desc_index = jdksavdecc_aem_command_set_sampling_rate_response_get_descriptor_index(frame, ETHER_HDR_SIZE);
            break;

        case JDKSAVDECC_AEM_COMMAND_GET_SAMPLING_RATE:
            desc_type = jdksavdecc_aem_command_get_sampling_rate_response_get_descriptor_type(frame, ETHER_HDR_SIZE);
            desc_index = jdksavdecc_aem_command_get_sampling_rate_response_get_descriptor_index(frame, ETHER_HDR_SIZE);
            break;

        case JDKSAVDECC_AEM_COMMAND_SET_CLOCK_SOURCE:
            desc_type = jdksavdecc_aem_command_set_clock_source_response_get_descriptor_type(frame, ETHER_HDR_SIZE);
            desc_index = jdksavdecc_aem_command_set_clock_source_response_get_descriptor_index(frame, ETHER_HDR_SIZE);
            break;

        case JDKSAVDECC_AEM_COMMAND_GET_CLOCK_SOURCE:
            desc_type = jdksavdecc_aem_command_get_clock_source_response_get_descriptor_type(frame, ETHER_HDR_SIZE);
            desc_index = jdksavdecc_aem_command_get_clock_source_response_get_descriptor_index(frame, ETHER_HDR_SIZE);
            break;

        case JDKSAVDECC_AEM_COMMAND_START_STREAMING:
            desc_type = jdksavdecc_aem_command_start_streaming_response_get_descriptor_type(frame, ETHER_HDR_SIZE);
            desc_index = jdksavdecc_aem_command_start_streaming_response_get_descriptor_index(frame, ETHER_HDR_SIZE);
            break;

        case JDKSAVDECC_AEM_COMMAND_STOP_STREAMING:
            desc_type = jdksavdecc_aem_command_stop_streaming_response_get_descriptor_type(frame, ETHER_HDR_SIZE);
            desc_index = jdksavdecc_aem_command_stop_streaming_response_get_descriptor_index(frame, ETHER_HDR_SIZE);
            break;
        
        case JDKSAVDECC_AEM_COMMAND_GET_COUNTERS:
            desc_type = jdksavdecc_aem_command_get_counters_response_get_descriptor_type(frame, ETHER_HDR_SIZE);
            desc_index = jdksavdecc_aem_command_get_counters_response_get_descriptor_index(frame, ETHER_HDR_SIZE);
            break;
        
        case JDKSAVDECC_AEM_COMMAND_REGISTER_UNSOLICITED_NOTIFICATION:
            break;

        default:
            log_imp_ref->post_log_msg(LOGGING_LEVEL_DEBUG, "NO_MATCH_FOUND for %s", utility::aem_cmd_value_to_name(cmd_type));
            break;
        }

        jdksavdecc_eui64 id = jdksavdecc_common_control_header_get_stream_id(frame, ETHER_HDR_SIZE);
        if((notification_flag == CMD_WITH_NOTIFICATION) &&
            ((msg_type == JDKSAVDECC_AECP_MESSAGE_TYPE_AEM_RESPONSE) ||
            (msg_type == JDKSAVDECC_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_RESPONSE)))
        {
            notification_imp_ref->post_notification_msg(RESPONSE_RECEIVED,
                                                        jdksavdecc_uint64_get(&id, 0),
                                                        cmd_type,
                                                        desc_type,
                                                        desc_index,
                                                        status,
                                                        notification_id);

            if(status != AEM_STATUS_SUCCESS)
            {
                log_imp_ref->post_log_msg(LOGGING_LEVEL_ERROR,
                                          "RESPONSE_RECEIVED, 0x%llx, %s, %s, %d, %d, %s",
                                          jdksavdecc_uint64_get(&id, 0),
                                          utility::aem_cmd_value_to_name(cmd_type),
                                          utility::aem_desc_value_to_name(desc_type),
                                          desc_index,
                                          jdksavdecc_aecpdu_common_get_sequence_id(frame, ETHER_HDR_SIZE),
                                          utility::aem_cmd_status_value_to_name(status));
            }
        }
        else if(((notification_flag == CMD_WITH_NOTIFICATION) || (notification_flag == CMD_WITHOUT_NOTIFICATION)) &&
                ((msg_type == JDKSAVDECC_AECP_MESSAGE_TYPE_AEM_COMMAND) || (msg_type == JDKSAVDECC_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_COMMAND)))
        {
            log_imp_ref->post_log_msg(LOGGING_LEVEL_DEBUG,
                                      "COMMAND_SENT, 0x%llx, %s, %s, %d, %d",
                                      jdksavdecc_uint64_get(&id, 0),
                                      utility::aem_cmd_value_to_name(cmd_type),
                                      utility::aem_desc_value_to_name(desc_type),
                                      desc_index,
                                      jdksavdecc_aecpdu_common_get_sequence_id(frame, ETHER_HDR_SIZE));
        }
        else if((notification_flag == CMD_WITHOUT_NOTIFICATION) &&
                ((msg_type == JDKSAVDECC_AECP_MESSAGE_TYPE_AEM_RESPONSE) ||
                (msg_type == JDKSAVDECC_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_RESPONSE)))
        {
            if(status == AEM_STATUS_SUCCESS)
            {
                log_imp_ref->post_log_msg(LOGGING_LEVEL_DEBUG,
                                          "RESPONSE_RECEIVED, 0x%llx, %s, %s, %d, %d, %s",
                                          jdksavdecc_uint64_get(&id, 0),
                                          utility::aem_cmd_value_to_name(cmd_type),
                                          utility::aem_desc_value_to_name(desc_type),
                                          desc_index,
                                          jdksavdecc_aecpdu_common_get_sequence_id(frame, ETHER_HDR_SIZE),
                                          utility::aem_cmd_status_value_to_name(status));
            }
            else
            {
                log_imp_ref->post_log_msg(LOGGING_LEVEL_ERROR,
                                          "RESPONSE_RECEIVED, 0x%llx, %s, %s, %d, %d, %s",
                                          jdksavdecc_uint64_get(&id, 0),
                                          utility::aem_cmd_value_to_name(cmd_type),
                                          utility::aem_desc_value_to_name(desc_type),
                                          desc_index,
                                          jdksavdecc_aecpdu_common_get_sequence_id(frame, ETHER_HDR_SIZE),
                                          utility::aem_cmd_status_value_to_name(status));
            }
        }

        return 0;
    }